discourse/plugins/discourse-solved/spec/lib/admin_dashboard_highlights_integration_spec.rb
Natalie Tay 728e70f507
FEATURE: Admin dashboard highlights to real data (#39895)
Behind the `dashboard_improvements` setting, the Highlights row is
hardcoded

This commit updates `/admin/dashboard.json` to swap out to a
`sections.highlights`. The endpoint takes optional `start_date` /
`end_date` so the redesigned page passes its picker range. Legacy
dashboard / `AdminDashboard.fetch()` callers get the same response
without the new stuff.

Core ships three KPIs (`new_signups`, `dau_mau`, `new_contributors`).
Plugins register more via a new
`register_admin_dashboard_highlight_kpi(type:, report:, enabled:)`
(discourse-solved for now). Each plugin owns their own KPI stuff.

Caching uses the existing per-report layer (`Report.find_cached`) rather
than wrapping the service in its own cache. Toggling a plugin's
`enabled:` takes effect immediately, the cache is shared with the
Reports tab when an admin drills into a tile, and the cache key isn't
fragmented per admin since the data is admin-agnostic.

The server returns `report_type` + `report_query` instead of a full URL
so routes are stable.

Without solved:

https://github.com/user-attachments/assets/28612829-b425-4664-bfb9-02e8783f5b93

With solved:

https://github.com/user-attachments/assets/3c6b6d6f-44b7-4c61-9b23-0aaaa3f21ddc
2026-05-12 13:15:52 +08:00

110 lines
3.3 KiB
Ruby
Vendored

# frozen_string_literal: true
describe AdminDashboardHighlights do
before do
freeze_time(Time.zone.local(2026, 4, 28, 12, 0, 0))
Discourse.cache.clear
end
context "when solved is enabled" do
before { SiteSetting.solved_enabled = true }
it "omits the KPI when no category enables accepted answers" do
Fabricate(:category)
result = AdminDashboardHighlights.build(start_date: "2026-04-01", end_date: "2026-04-28")
expect(result[:kpis].map { |k| k[:type] }).not_to include(:accepted_solutions)
end
it "includes the KPI when at least one category supports accepted answers" do
category = Fabricate(:category)
category.custom_fields[DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD] = "true"
category.save!
result = AdminDashboardHighlights.build(start_date: "2026-04-01", end_date: "2026-04-28")
kpi = result[:kpis].find { |k| k[:type] == :accepted_solutions }
expect(kpi).to be_present
expect(kpi[:report_type]).to eq("accepted_solutions")
end
end
context "when solved is disabled" do
before { SiteSetting.solved_enabled = false }
it "omits the KPI even if a category enables accepted answers" do
category = Fabricate(:category)
category.custom_fields[DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD] = "true"
category.save!
result = AdminDashboardHighlights.build(start_date: "2026-04-01", end_date: "2026-04-28")
expect(result[:kpis].map { |k| k[:type] }).not_to include(:accepted_solutions)
end
end
describe "accepted_solutions report prev_period facet" do
fab!(:user)
fab!(:topic)
fab!(:post) { Fabricate(:post, topic: topic) }
it "populates prev_period when the facet is requested" do
DiscourseSolved::SolvedTopic.create!(
topic: topic,
answer_post: post,
accepter: user,
created_at: Time.zone.local(2026, 3, 15),
)
report =
Report.find(
"accepted_solutions",
start_date: Time.zone.local(2026, 4, 1),
end_date: Time.zone.local(2026, 4, 28),
facets: %i[prev_period],
)
expect(report.prev_period).to be >= 1
end
it "excludes deleted topics from prev_period" do
DiscourseSolved::SolvedTopic.create!(
topic: topic,
answer_post: post,
accepter: user,
created_at: Time.zone.local(2026, 3, 15),
)
topic.trash!
report =
Report.find(
"accepted_solutions",
start_date: Time.zone.local(2026, 4, 1),
end_date: Time.zone.local(2026, 4, 28),
facets: %i[prev_period],
)
expect(report.prev_period.to_i).to eq(0)
end
it "excludes private message topics from prev_period" do
pm = Fabricate(:private_message_topic)
pm_post = Fabricate(:post, topic: pm)
DiscourseSolved::SolvedTopic.create!(
topic: pm,
answer_post: pm_post,
accepter: user,
created_at: Time.zone.local(2026, 3, 15),
)
report =
Report.find(
"accepted_solutions",
start_date: Time.zone.local(2026, 4, 1),
end_date: Time.zone.local(2026, 4, 28),
facets: %i[prev_period],
)
expect(report.prev_period.to_i).to eq(0)
end
end
end