discourse/app/services/admin_dashboard_section_configuration.rb
Natalie Tay 37e13f0afc
FEATURE: Allow admins to configure sections in the experimental admin dashboard (#39964)
Allow admins to configure which sections they want to see.

A few tasks in this commit:
- rename the "Customise" menu to "Configure" and removes the calendar
icon from the Custom date range option
- implements the Configure menu:
  - toggle section visibility
  - drag-and-drop reorder on desktop, up/down arrows on mobile
  - empty state when all sections are off
- persists configuration site-wide on menu close via
`admin_dashboard_sections` site setting
  - admins and moderators can view, but admins write and moderators read
- `AdminDashboardSectionConfiguration` owns configuration, so storage
can change later if we move to per-user
- `PUT /admin/dashboard/configuration.json` is admin-only (mentioned
above)
  - audit log (`SiteSetting.set_and_log`)
- the backend filters `sections` payload to only the visible-and-ordered
list, so mods render the layout admins set without seeing the
configuration meta
    - hidden sections skip their server-side data computation
2026-05-13 18:03:39 +08:00

31 lines
988 B
Ruby
Vendored

# frozen_string_literal: true
class AdminDashboardSectionConfiguration
KNOWN_SECTIONS = %w[highlights reports traffic engagement].freeze
def self.visible_section_ids
raw = SiteSetting.admin_dashboard_sections.to_s
return [] if raw.empty?
ids = raw.split("|").map(&:strip).uniq.select { |id| KNOWN_SECTIONS.include?(id) }
ids.empty? ? KNOWN_SECTIONS.dup : ids
end
def self.sections
visible = visible_section_ids
hidden = KNOWN_SECTIONS - visible
visible.map { |id| { id: id, visible: true } } + hidden.map { |id| { id: id, visible: false } }
end
def self.update(input_sections, actor:)
visible_ids =
Array(input_sections)
.select { |s| ActiveModel::Type::Boolean.new.cast(s[:visible] || s["visible"]) }
.map { |s| (s[:id] || s["id"]).to_s }
.uniq
.select { |id| KNOWN_SECTIONS.include?(id) }
SiteSetting.set_and_log("admin_dashboard_sections", visible_ids.join("|"), actor)
sections
end
end