mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-25 22:12:08 +08:00
Makes the redesigned dashboard Site traffic section real for the core
traffic summary.
- In scope: live pageview headline, comparison trend, logged-in share
KPI, and stacked traffic chart.
- Out of scope: top referrers, top countries, and narrative traffic
insights. Those remain placeholder UI for a follow-up.
- Reuses the existing report stacked chart for both the dashboard
section and `/admin/reports/site_traffic`.
- Extends the existing site traffic report data contract instead of
introducing a dashboard-only chart shape.
- Keeps traffic aggregation, KPI calculation, and trend eligibility on
the backend.
- Supports dashboard preset and custom date ranges with inclusive date
windows.
- Ships traffic data in this section payload shape:
```json
{
"id": "traffic",
"data": {
"kpis": {
"browser_pageviews": {
"value": 30,
"percent_change": 900,
"comparison_period": {
"start_date": "2026-04-28",
"end_date": "2026-04-30"
}
},
"logged_in_share": {
"value": 33
}
},
"pageview_series": [
{
"req": "page_view_logged_in_browser",
"label": "Logged in",
"color": "#4B3CE0",
"data": [
{ "x": "2026-05-01", "y": 10 }
]
}
]
}
}
```
107 lines
3 KiB
Ruby
Vendored
107 lines
3 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
class Admin::DashboardController < Admin::StaffController
|
|
def index
|
|
if SiteSetting.dashboard_improvements
|
|
visible_ids = AdminDashboardSectionConfiguration.visible_section_ids
|
|
data = { sections: visible_ids.map { |id| { id: id, data: section_data(id) } } }
|
|
if current_user.admin?
|
|
data[:configuration] = { sections: AdminDashboardSectionConfiguration.sections }
|
|
end
|
|
else
|
|
data = AdminDashboardIndexData.fetch_cached_stats
|
|
|
|
if SiteSetting.version_checks?
|
|
data.merge!(version_check: DiscourseUpdates.check_version.as_json)
|
|
end
|
|
end
|
|
|
|
render json: data
|
|
end
|
|
|
|
def update_configuration
|
|
sections = params.permit(sections: %i[id visible])[:sections] || []
|
|
AdminDashboardSectionConfiguration.update(sections, actor: current_user)
|
|
head :no_content
|
|
end
|
|
|
|
def moderation
|
|
end
|
|
|
|
def security
|
|
end
|
|
|
|
def reports
|
|
end
|
|
|
|
def general
|
|
render json: AdminDashboardGeneralData.fetch_cached_stats
|
|
end
|
|
|
|
def problems
|
|
ProblemCheck.realtime.run_all
|
|
|
|
render json: { problems: serialize_data(AdminNotice.problem.all, AdminNoticeSerializer) }
|
|
end
|
|
|
|
def new_features
|
|
force_refresh = params[:force_refresh] == "true"
|
|
|
|
if force_refresh
|
|
RateLimiter.new(
|
|
current_user,
|
|
"force-refresh-new-features",
|
|
5,
|
|
1.minute,
|
|
apply_limit_to_staff: true,
|
|
).performed!
|
|
end
|
|
|
|
new_features = DiscourseUpdates.new_features(force_refresh:)
|
|
new_features_with_permanent_uc =
|
|
DiscourseUpdates.merge_new_features_with_upcoming_changes(
|
|
new_features&.map { |item| item.symbolize_keys } || [],
|
|
)
|
|
|
|
if current_user.admin? && most_recent = new_features_with_permanent_uc&.first
|
|
DiscourseUpdates.bump_last_viewed_feature_date(current_user.id, most_recent[:created_at])
|
|
end
|
|
|
|
data = {
|
|
new_features: new_features_with_permanent_uc,
|
|
has_unseen_features: DiscourseUpdates.has_unseen_features?(current_user.id),
|
|
release_notes_link: AdminDashboardGeneralData.fetch_cached_stats["release_notes_link"],
|
|
}
|
|
|
|
mark_new_features_as_seen
|
|
|
|
render json: data
|
|
end
|
|
|
|
def toggle_feature
|
|
UpcomingChanges::Toggle.call(service_params) do
|
|
on_success { render(json: success_json) }
|
|
on_failure { render(json: failed_json, status: :unprocessable_entity) }
|
|
on_failed_policy(:current_user_is_admin) { raise Discourse::InvalidAccess }
|
|
on_failed_policy(:setting_is_available) { raise Discourse::InvalidAccess }
|
|
on_failed_contract do |contract|
|
|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: :bad_request)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def section_data(id)
|
|
case id
|
|
when "highlights"
|
|
AdminDashboardHighlights.build(start_date: params[:start_date], end_date: params[:end_date])
|
|
when "traffic"
|
|
AdminDashboardSiteTraffic.build(start_date: params[:start_date], end_date: params[:end_date])
|
|
end
|
|
end
|
|
|
|
def mark_new_features_as_seen
|
|
DiscourseUpdates.mark_new_features_as_seen(current_user.id)
|
|
end
|
|
end
|