diff --git a/app/assets/javascripts/admin/addon/components/admin-report-counts.hbs b/app/assets/javascripts/admin/addon/components/admin-report-counts.hbs
deleted file mode 100644
index e0a77431745..00000000000
--- a/app/assets/javascripts/admin/addon/components/admin-report-counts.hbs
+++ /dev/null
@@ -1,36 +0,0 @@
-
@@ -146,7 +147,7 @@
diff --git a/app/assets/javascripts/admin/addon/templates/reports-show.hbs b/app/assets/javascripts/admin/addon/templates/reports-show.hbs
index c7ac2ba9255..4ac65d8b479 100644
--- a/app/assets/javascripts/admin/addon/templates/reports-show.hbs
+++ b/app/assets/javascripts/admin/addon/templates/reports-show.hbs
@@ -6,6 +6,7 @@
@filters={{this.model}}
@reportOptions={{this.reportOptions}}
@showFilteringUI={{true}}
+ @showDescriptionInTooltip={{false}}
@onRefresh={{route-action "onParamsChange"}}
/>
diff --git a/app/assets/javascripts/discourse/app/lib/admin-report-additional-modes.js b/app/assets/javascripts/discourse/app/lib/admin-report-additional-modes.js
new file mode 100644
index 00000000000..950285f1773
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/lib/admin-report-additional-modes.js
@@ -0,0 +1,10 @@
+let additionalReportModes = new Map();
+export function registerReportModeComponent(mode, componentClass) {
+ additionalReportModes.set(mode, componentClass);
+}
+export function resetAdditionalReportModes() {
+ additionalReportModes.clear();
+}
+export function reportModeComponent(mode) {
+ return additionalReportModes.get(mode);
+}
diff --git a/app/assets/javascripts/discourse/app/lib/constants.js b/app/assets/javascripts/discourse/app/lib/constants.js
index e08fcd52947..0aff2a48b0c 100644
--- a/app/assets/javascripts/discourse/app/lib/constants.js
+++ b/app/assets/javascripts/discourse/app/lib/constants.js
@@ -106,3 +106,14 @@ export const USER_FIELD_FLAGS = [
"show_on_user_card",
"searchable",
];
+
+export const REPORT_MODES = {
+ table: "table",
+ chart: "chart",
+ stacked_chart: "stacked_chart",
+ stacked_line_chart: "stacked_line_chart",
+ radar: "radar",
+ counters: "counters",
+ inline_table: "inline_table",
+ storage_stats: "storage_stats",
+};
diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
index faa2f236c77..1fee4b3ff48 100644
--- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
+++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
@@ -3,7 +3,7 @@
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
// using the format described at https://keepachangelog.com/en/1.0.0/.
-export const PLUGIN_API_VERSION = "2.0.0";
+export const PLUGIN_API_VERSION = "2.0.1";
import $ from "jquery";
import { h } from "virtual-dom";
@@ -61,6 +61,7 @@ import {
registerAdminPluginConfigNav,
} from "discourse/lib/admin-plugin-config-nav";
import { registerPluginHeaderActionComponent } from "discourse/lib/admin-plugin-header-actions";
+import { registerReportModeComponent } from "discourse/lib/admin-report-additional-modes";
import classPrepend, {
withPrependsRolledBack,
} from "discourse/lib/class-prepend";
@@ -3375,6 +3376,19 @@ class PluginApi {
registeredTabs.push(tab);
}
+ /**
+ * Registers a report mode and an associated component, which will be rendered
+ * by the AdminReport component. A mode is a different way of displaying the
+ * report data, core modes are things like "table" and "chart". For all core modes
+ * see Admin::Report::MODES.
+ *
+ * @param {String} mode - The identifier of the mode to register
+ * @param {Class} componentClass - The class of the component to render
+ */
+ registerReportModeComponent(mode, componentClass) {
+ registerReportModeComponent(mode, componentClass);
+ }
+
#deprecatedWidgetOverride(widgetName, override) {
// insert here the code to handle widget deprecations, e.g. for the header widgets we used:
// if (DEPRECATED_HEADER_WIDGETS.includes(widgetName)) {
diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
index 4bedff6e52a..7a01a298e2c 100644
--- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
+++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
@@ -36,6 +36,7 @@ import { resetUsernameDecorators } from "discourse/helpers/decorate-username-sel
import { resetBeforeAuthCompleteCallbacks } from "discourse/instance-initializers/auth-complete";
import { resetAdminPluginConfigNav } from "discourse/lib/admin-plugin-config-nav";
import { clearPluginHeaderActionComponents } from "discourse/lib/admin-plugin-header-actions";
+import { resetAdditionalReportModes } from "discourse/lib/admin-report-additional-modes";
import { rollbackAllPrepends } from "discourse/lib/class-prepend";
import { clearPopupMenuOptions } from "discourse/lib/composer/custom-popup-menu-options";
import deprecated from "discourse/lib/deprecated";
@@ -201,6 +202,7 @@ export function testCleanup(container, app) {
User.resetCurrent();
resetMobile();
+ resetAdditionalReportModes();
resetExtraClasses();
clearOutletCache();
clearHTMLCache();
diff --git a/app/assets/javascripts/discourse/tests/integration/components/admin-report-test.js b/app/assets/javascripts/discourse/tests/integration/components/admin-report-test.js
index ce0b783861c..6f1d35664ee 100644
--- a/app/assets/javascripts/discourse/tests/integration/components/admin-report-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/components/admin-report-test.js
@@ -8,7 +8,9 @@ module("Integration | Component | admin-report", function (hooks) {
setupRenderingTest(hooks);
test("default", async function (assert) {
- await render(hbs`
`);
+ await render(
+ hbs`
`
+ );
assert.dom(".admin-report.signups").exists();
assert.dom(".admin-report-table").exists("defaults to table mode");
diff --git a/app/assets/stylesheets/common/admin/admin_report.scss b/app/assets/stylesheets/common/admin/admin_report.scss
index c7e61b59e9b..9c331a7688e 100644
--- a/app/assets/stylesheets/common/admin/admin_report.scss
+++ b/app/assets/stylesheets/common/admin/admin_report.scss
@@ -80,7 +80,6 @@
.body {
display: flex;
flex-direction: row;
- margin-top: var(--space-3);
}
.main {
diff --git a/app/assets/stylesheets/common/admin/dashboard.scss b/app/assets/stylesheets/common/admin/dashboard.scss
index c48f4e56ad4..859c9d227a6 100644
--- a/app/assets/stylesheets/common/admin/dashboard.scss
+++ b/app/assets/stylesheets/common/admin/dashboard.scss
@@ -137,6 +137,19 @@
margin-bottom: 1em;
}
+ .admin-report.description-in-tooltip .header {
+ .d-page-subheader {
+ .d-page-subheader__title-row {
+ margin-bottom: 0;
+ }
+ }
+
+ .fk-d-tooltip__trigger {
+ margin-left: 0.5em;
+ max-width: 20px;
+ }
+ }
+
.charts {
display: grid;
grid-template-columns: repeat(12, 1fr);
@@ -153,7 +166,7 @@
.header {
display: grid;
- grid-template-areas: "title trend" "description description";
+ grid-template-areas: "title tooltip trend" "description description description";
grid-template-columns: auto 1fr;
.d-page-subheader {
diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb
index fb28fabf239..06ef5fd1024 100644
--- a/app/jobs/regular/export_csv_file.rb
+++ b/app/jobs/regular/export_csv_file.rb
@@ -227,7 +227,7 @@ module Jobs
end
end
- if report.modes == [:stacked_chart]
+ if report.modes == [Report::MODES[:stacked_chart]]
header = [:x]
data = {}
diff --git a/app/models/concerns/reports/consolidated_api_requests.rb b/app/models/concerns/reports/consolidated_api_requests.rb
index e50d240c56c..b7e094a7bea 100644
--- a/app/models/concerns/reports/consolidated_api_requests.rb
+++ b/app/models/concerns/reports/consolidated_api_requests.rb
@@ -7,7 +7,7 @@ module Reports::ConsolidatedApiRequests
def report_consolidated_api_requests(report)
filters = %w[api user_api]
- report.modes = [:stacked_chart]
+ report.modes = [Report::MODES[:stacked_chart]]
requests =
filters.map do |filter|
diff --git a/app/models/concerns/reports/consolidated_page_views.rb b/app/models/concerns/reports/consolidated_page_views.rb
index 4d48f18415b..1815ccd9b63 100644
--- a/app/models/concerns/reports/consolidated_page_views.rb
+++ b/app/models/concerns/reports/consolidated_page_views.rb
@@ -11,7 +11,7 @@ module Reports::ConsolidatedPageViews
def report_consolidated_page_views(report)
filters = %w[page_view_logged_in page_view_anon page_view_crawler]
- report.modes = [:stacked_chart]
+ report.modes = [Report::MODES[:stacked_chart]]
requests =
filters.map do |filter|
diff --git a/app/models/concerns/reports/flags_status.rb b/app/models/concerns/reports/flags_status.rb
index 572185ebc53..0219ba90598 100644
--- a/app/models/concerns/reports/flags_status.rb
+++ b/app/models/concerns/reports/flags_status.rb
@@ -5,7 +5,7 @@ module Reports::FlagsStatus
class_methods do
def report_flags_status(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/moderators_activity.rb b/app/models/concerns/reports/moderators_activity.rb
index 6b733e93661..5ab3156a85b 100644
--- a/app/models/concerns/reports/moderators_activity.rb
+++ b/app/models/concerns/reports/moderators_activity.rb
@@ -47,7 +47,7 @@ module Reports::ModeratorsActivity
},
]
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.data = []
query = <<~SQL
diff --git a/app/models/concerns/reports/post_edits.rb b/app/models/concerns/reports/post_edits.rb
index af97ddc19a8..c096e1ffa95 100644
--- a/app/models/concerns/reports/post_edits.rb
+++ b/app/models/concerns/reports/post_edits.rb
@@ -8,7 +8,7 @@ module Reports::PostEdits
category_id, include_subcategories = report.add_category_filter
editor_username = report.filters["editor"]
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/posts.rb b/app/models/concerns/reports/posts.rb
index b2ac5199099..338d962c29c 100644
--- a/app/models/concerns/reports/posts.rb
+++ b/app/models/concerns/reports/posts.rb
@@ -5,8 +5,6 @@ module Reports::Posts
class_methods do
def report_posts(report)
- report.modes = %i[table chart]
-
category_id, include_subcategories = report.add_category_filter
basic_report_about report,
diff --git a/app/models/concerns/reports/site_traffic.rb b/app/models/concerns/reports/site_traffic.rb
index b77c977f0a0..b3b3c658d9c 100644
--- a/app/models/concerns/reports/site_traffic.rb
+++ b/app/models/concerns/reports/site_traffic.rb
@@ -5,7 +5,7 @@ module Reports::SiteTraffic
class_methods do
def report_site_traffic(report)
- report.modes = [:stacked_chart]
+ report.modes = [Report::MODES[:stacked_chart]]
first_browser_pageview_date =
DB.query_single(
diff --git a/app/models/concerns/reports/staff_logins.rb b/app/models/concerns/reports/staff_logins.rb
index d65c2e2df05..bba58aeee24 100644
--- a/app/models/concerns/reports/staff_logins.rb
+++ b/app/models/concerns/reports/staff_logins.rb
@@ -5,7 +5,7 @@ module Reports::StaffLogins
class_methods do
def report_staff_logins(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.data = []
diff --git a/app/models/concerns/reports/suspicious_logins.rb b/app/models/concerns/reports/suspicious_logins.rb
index cd07d427d11..64d7ac65361 100644
--- a/app/models/concerns/reports/suspicious_logins.rb
+++ b/app/models/concerns/reports/suspicious_logins.rb
@@ -5,7 +5,7 @@ module Reports::SuspiciousLogins
class_methods do
def report_suspicious_logins(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/top_ignored_users.rb b/app/models/concerns/reports/top_ignored_users.rb
index 3403de992e7..ebb572d9fdf 100644
--- a/app/models/concerns/reports/top_ignored_users.rb
+++ b/app/models/concerns/reports/top_ignored_users.rb
@@ -5,7 +5,7 @@ module Reports::TopIgnoredUsers
class_methods do
def report_top_ignored_users(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/top_referred_topics.rb b/app/models/concerns/reports/top_referred_topics.rb
index c8cacb79297..c57480dc698 100644
--- a/app/models/concerns/reports/top_referred_topics.rb
+++ b/app/models/concerns/reports/top_referred_topics.rb
@@ -7,7 +7,7 @@ module Reports::TopReferredTopics
def report_top_referred_topics(report)
category_id, include_subcategories = report.add_category_filter
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/top_referrers.rb b/app/models/concerns/reports/top_referrers.rb
index 3454f17632b..e3f3eecc8af 100644
--- a/app/models/concerns/reports/top_referrers.rb
+++ b/app/models/concerns/reports/top_referrers.rb
@@ -5,7 +5,7 @@ module Reports::TopReferrers
class_methods do
def report_top_referrers(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{
diff --git a/app/models/concerns/reports/top_traffic_sources.rb b/app/models/concerns/reports/top_traffic_sources.rb
index a1b313f01f9..d3068c13bff 100644
--- a/app/models/concerns/reports/top_traffic_sources.rb
+++ b/app/models/concerns/reports/top_traffic_sources.rb
@@ -7,7 +7,7 @@ module Reports::TopTrafficSources
def report_top_traffic_sources(report)
category_id, include_subcategories = report.add_category_filter
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.labels = [
{ property: :domain, title: I18n.t("reports.top_traffic_sources.labels.domain") },
diff --git a/app/models/concerns/reports/top_uploads.rb b/app/models/concerns/reports/top_uploads.rb
index b9caaa63fab..1aff15b4873 100644
--- a/app/models/concerns/reports/top_uploads.rb
+++ b/app/models/concerns/reports/top_uploads.rb
@@ -5,7 +5,7 @@ module Reports::TopUploads
class_methods do
def report_top_uploads(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
extension_filter = report.filters.dig(:file_extension)
report.add_filter(
diff --git a/app/models/concerns/reports/top_users_by_likes_received.rb b/app/models/concerns/reports/top_users_by_likes_received.rb
index 2861cbefc51..e0a78a7aefb 100644
--- a/app/models/concerns/reports/top_users_by_likes_received.rb
+++ b/app/models/concerns/reports/top_users_by_likes_received.rb
@@ -8,7 +8,7 @@ module Reports::TopUsersByLikesReceived
report.icon = "heart"
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = true
diff --git a/app/models/concerns/reports/top_users_by_likes_received_from_a_variety_of_people.rb b/app/models/concerns/reports/top_users_by_likes_received_from_a_variety_of_people.rb
index a6a42c72181..2445b244015 100644
--- a/app/models/concerns/reports/top_users_by_likes_received_from_a_variety_of_people.rb
+++ b/app/models/concerns/reports/top_users_by_likes_received_from_a_variety_of_people.rb
@@ -8,7 +8,7 @@ module Reports::TopUsersByLikesReceivedFromAVarietyOfPeople
report.icon = "heart"
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = true
diff --git a/app/models/concerns/reports/top_users_by_likes_received_from_inferior_trust_level.rb b/app/models/concerns/reports/top_users_by_likes_received_from_inferior_trust_level.rb
index 0daad06783f..927a468bf15 100644
--- a/app/models/concerns/reports/top_users_by_likes_received_from_inferior_trust_level.rb
+++ b/app/models/concerns/reports/top_users_by_likes_received_from_inferior_trust_level.rb
@@ -8,7 +8,7 @@ module Reports::TopUsersByLikesReceivedFromInferiorTrustLevel
report.icon = "heart"
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = true
diff --git a/app/models/concerns/reports/topic_view_stats.rb b/app/models/concerns/reports/topic_view_stats.rb
index ce33f30d3ab..d939c2715ab 100644
--- a/app/models/concerns/reports/topic_view_stats.rb
+++ b/app/models/concerns/reports/topic_view_stats.rb
@@ -5,7 +5,7 @@ module Reports::TopicViewStats
class_methods do
def report_topic_view_stats(report)
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
category_id, include_subcategories = report.add_category_filter
diff --git a/app/models/concerns/reports/trending_search.rb b/app/models/concerns/reports/trending_search.rb
index 8d4f5ff38a3..9b447a30d44 100644
--- a/app/models/concerns/reports/trending_search.rb
+++ b/app/models/concerns/reports/trending_search.rb
@@ -21,7 +21,7 @@ module Reports::TrendingSearch
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
trends =
SearchLog.trending_from(report.start_date, end_date: report.end_date, limit: report.limit)
diff --git a/app/models/concerns/reports/trust_level_growth.rb b/app/models/concerns/reports/trust_level_growth.rb
index 3b393426c08..0e0c45850ac 100644
--- a/app/models/concerns/reports/trust_level_growth.rb
+++ b/app/models/concerns/reports/trust_level_growth.rb
@@ -5,7 +5,7 @@ module Reports::TrustLevelGrowth
class_methods do
def report_trust_level_growth(report)
- report.modes = [:stacked_chart]
+ report.modes = [Report::MODES[:stacked_chart]]
filters = %w[tl1_reached tl2_reached tl3_reached tl4_reached]
diff --git a/app/models/concerns/reports/user_flagging_ratio.rb b/app/models/concerns/reports/user_flagging_ratio.rb
index 0147792a8d8..c72474dd4d7 100644
--- a/app/models/concerns/reports/user_flagging_ratio.rb
+++ b/app/models/concerns/reports/user_flagging_ratio.rb
@@ -7,7 +7,7 @@ module Reports::UserFlaggingRatio
def report_user_flagging_ratio(report)
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = true
diff --git a/app/models/concerns/reports/users_by_trust_level.rb b/app/models/concerns/reports/users_by_trust_level.rb
index f0226a90c8a..688574a50ce 100644
--- a/app/models/concerns/reports/users_by_trust_level.rb
+++ b/app/models/concerns/reports/users_by_trust_level.rb
@@ -7,7 +7,7 @@ module Reports::UsersByTrustLevel
def report_users_by_trust_level(report)
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = false
diff --git a/app/models/concerns/reports/users_by_type.rb b/app/models/concerns/reports/users_by_type.rb
index a7c77cc7eb4..6dcf279b8cc 100644
--- a/app/models/concerns/reports/users_by_type.rb
+++ b/app/models/concerns/reports/users_by_type.rb
@@ -7,7 +7,7 @@ module Reports::UsersByType
def report_users_by_type(report)
report.data = []
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.dates_filtering = false
diff --git a/app/models/concerns/reports/web_crawlers.rb b/app/models/concerns/reports/web_crawlers.rb
index cdb731eeab5..298ecd1a179 100644
--- a/app/models/concerns/reports/web_crawlers.rb
+++ b/app/models/concerns/reports/web_crawlers.rb
@@ -18,7 +18,7 @@ module Reports::WebCrawlers
},
]
- report.modes = [:table]
+ report.modes = [Report::MODES[:table]]
report.data =
WebCrawlerRequest
diff --git a/app/models/report.rb b/app/models/report.rb
index 032094cc9af..b52162f7cdc 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -16,6 +16,17 @@ class Report
include_subcategories
]
+ MODES = {
+ table: :table,
+ chart: :chart,
+ stacked_chart: :stacked_chart,
+ stacked_line_chart: :stacked_line_chart,
+ radar: :radar,
+ counters: :counters,
+ inline_table: :inline_table,
+ storage_stats: :storage_stats,
+ }
+
include Reports::Bookmarks
include Reports::ConsolidatedApiRequests
include Reports::ConsolidatedPageViews
@@ -106,7 +117,7 @@ class Report
@average = false
@percent = false
@higher_is_better = true
- @modes = %i[table chart]
+ @modes = [MODES[:chart], MODES[:table]]
@prev_data = nil
@dates_filtering = true
@available_filters = {}
@@ -374,7 +385,7 @@ class Report
end
def self.add_prev_data(report, subject_class, report_method, *args)
- if report.modes.include?(:chart) && report.facets.include?(:prev_period)
+ if report.modes.include?(Report::MODES[:chart]) && report.facets.include?(:prev_period)
prev_data = subject_class.public_send(report_method, *args)
report.prev_data = prev_data.map { |k, v| { x: k, y: v } }
end
diff --git a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md
index ce597732f99..b007e2fdbc4 100644
--- a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md
+++ b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md
@@ -7,6 +7,10 @@ in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [2.0.1] - 2025-01-29
+
+- Added `registerReportModeComponent`. This allows plugins to register different report display modes in addition to the built-in core ones like `chart`, `table`, and so on defined in `Report::MODES`.
+
## [2.0.0] - 2025-01-07
- Removed `decorateTopicTitle`. This has been deprecated for more than a year, and we are not aware of any remaining uses in the ecosystem.
diff --git a/lib/tasks/javascript.rake b/lib/tasks/javascript.rake
index 08ae71850b4..180cea69d61 100644
--- a/lib/tasks/javascript.rake
+++ b/lib/tasks/javascript.rake
@@ -167,6 +167,8 @@ task "javascript:update_constants" => :environment do
export const MAX_UNOPTIMIZED_CATEGORIES = #{CategoryList::MAX_UNOPTIMIZED_CATEGORIES};
export const USER_FIELD_FLAGS = #{UserField::FLAG_ATTRIBUTES};
+
+ export const REPORT_MODES = #{Report::MODES.to_json};
JS
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")