diff --git a/app/assets/javascripts/admin/components/admin-report.js b/app/assets/javascripts/admin/components/admin-report.js index 97db7c9df72..757a90a7dbc 100644 --- a/app/assets/javascripts/admin/components/admin-report.js +++ b/app/assets/javascripts/admin/components/admin-report.js @@ -1,6 +1,6 @@ import discourseComputed from "discourse-common/utils/decorators"; import { makeArray } from "discourse-common/lib/helpers"; -import { alias, or, and, equal, notEmpty } from "@ember/object/computed"; +import { alias, or, and, equal, notEmpty, not } from "@ember/object/computed"; import EmberObject, { computed, action } from "@ember/object"; import { next } from "@ember/runloop"; import Component from "@ember/component"; @@ -41,7 +41,12 @@ function collapseWeekly(data, average) { } export default Component.extend({ - classNameBindings: ["isEnabled", "isLoading", "dasherizedDataSourceName"], + classNameBindings: [ + "isVisible", + "isEnabled", + "isLoading", + "dasherizedDataSourceName" + ], classNames: ["admin-report"], isEnabled: true, disabledLabel: I18n.t("admin.dashboard.disabled"), @@ -63,6 +68,7 @@ export default Component.extend({ showDatesOptions: alias("model.dates_filtering"), showRefresh: or("showDatesOptions", "model.available_filters.length"), shouldDisplayTrend: and("showTrend", "model.prev_period"), + isVisible: not("isHidden"), init() { this._super(...arguments); @@ -70,6 +76,13 @@ export default Component.extend({ this._reports = []; }, + isHidden: computed("siteSettings.dashboard_hidden_reports", function() { + return (this.siteSettings.dashboard_hidden_reports || "") + .split("|") + .filter(Boolean) + .includes(this.dataSourceName); + }), + startDate: computed("filters.startDate", function() { if (this.filters && isPresent(this.filters.startDate)) { return moment(this.filters.startDate, "YYYY-MM-DD"); diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js index b77e3e02884..5f2ea86819f 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js @@ -23,9 +23,44 @@ export default Controller.extend(PeriodComputationMixin, { @discourseComputed("siteSettings.dashboard_general_tab_activity_metrics") activityMetrics(metrics) { - return (metrics || "").split("|").filter(m => m); + return (metrics || "").split("|").filter(Boolean); }, + hiddenReports: computed("siteSettings.dashboard_hidden_reports", function() { + return (this.siteSettings.dashboard_hidden_reports || "") + .split("|") + .filter(Boolean); + }), + + isActivityMetricsVisible: computed( + "activityMetrics", + "hiddenReports", + function() { + return ( + this.activityMetrics.length && + this.activityMetrics.some(x => !this.hiddenReports.includes(x)) + ); + } + ), + + isSearchReportsVisible: computed("hiddenReports", function() { + return ["top_referred_topics", "trending_search"].some( + x => !this.hiddenReports.includes(x) + ); + }), + + isCommunityHealthVisible: computed("hiddenReports", function() { + return [ + "consolidated_page_views", + "signups", + "topics", + "posts", + "dau_by_mau", + "daily_engaged_users", + "new_contributors" + ].some(x => !this.hiddenReports.includes(x)); + }), + @discourseComputed activityMetricsFilters() { return { diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js b/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js index 8925825fbad..95f820b598f 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js @@ -1,6 +1,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import Controller from "@ember/controller"; import PeriodComputationMixin from "admin/mixins/period-computation"; +import { computed } from "@ember/object"; export default Controller.extend(PeriodComputationMixin, { @discourseComputed @@ -13,6 +14,16 @@ export default Controller.extend(PeriodComputationMixin, { }; }, + isModeratorsActivityVisible: computed( + "siteSettings.dashboard_hidden_reports", + function() { + return !(this.siteSettings.dashboard_hidden_reports || "") + .split("|") + .filter(Boolean) + .includes("moderators_activity"); + } + ), + @discourseComputed userFlaggingRatioOptions() { return { diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js b/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js index d6e15496f76..c096c3e7638 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js @@ -8,17 +8,27 @@ const { get } = Ember; export default Controller.extend({ filter: null, - @discourseComputed("model.[]", "filter") + @discourseComputed( + "model.[]", + "filter", + "siteSettings.dashboard_hidden_reports" + ) filterReports(reports, filter) { if (filter) { filter = filter.toLowerCase(); - return reports.filter(report => { + reports = reports.filter(report => { return ( (get(report, "title") || "").toLowerCase().indexOf(filter) > -1 || (get(report, "description") || "").toLowerCase().indexOf(filter) > -1 ); }); } + + const hiddenReports = (this.siteSettings.dashboard_hidden_reports || "") + .split("|") + .filter(Boolean); + reports = reports.filter(report => !hiddenReports.includes(report.type)); + return reports; }, diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard.js b/app/assets/javascripts/admin/controllers/admin-dashboard.js index bd8561abc1d..5946a1736d6 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard.js +++ b/app/assets/javascripts/admin/controllers/admin-dashboard.js @@ -1,7 +1,7 @@ import discourseComputed from "discourse-common/utils/decorators"; -import { inject } from "@ember/controller"; -import Controller from "@ember/controller"; +import Controller, { inject } from "@ember/controller"; import { setting } from "discourse/lib/computed"; +import { computed } from "@ember/object"; import AdminDashboard from "admin/models/admin-dashboard"; import VersionCheck from "admin/models/version-check"; @@ -18,6 +18,24 @@ export default Controller.extend({ return this.currentUser.get("admin") && (problemsLength || 0) > 0; }, + visibleTabs: computed("siteSettings.dashboard_visible_tabs", function() { + return (this.siteSettings.dashboard_visible_tabs || "") + .split("|") + .filter(Boolean); + }), + + isModerationTabVisible: computed("visibleTabs", function() { + return this.visibleTabs.includes("moderation"); + }), + + isSecurityTabVisible: computed("visibleTabs", function() { + return this.visibleTabs.includes("security"); + }), + + isReportsTabVisible: computed("visibleTabs", function() { + return this.visibleTabs.includes("reports"); + }), + fetchProblems() { if (this.isLoadingProblems) return; diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs index ee375ac6ff6..be075dbd2d0 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs @@ -1,195 +1,197 @@ -{{#if isEnabled}} - {{#conditional-loading-section isLoading=isLoading}} - {{#if showHeader}} -
- {{#if showTitle}} - + {{/if}} + + {{#if shouldDisplayTrend}} +
+ + {{#if model.average}} + {{number model.currentAverage}}{{#if model.percent}}%{{/if}} {{else}} - {{i18n "admin.dashboard.reports.no_data"}} + {{number model.currentTotal noTitle="true"}}{{#if model.percent}}%{{/if}} {{/if}} -
- {{/if}} - {{/if}} - {{/if}} -
- {{#if showFilteringUI}} -
- {{#if showModes}} -
- {{#each displayedModes as |displayedMode|}} - {{d-button - action=(action "changeMode") - actionParam=displayedMode.mode - class=displayedMode.cssClass - icon=displayedMode.icon}} - {{/each}} -
- {{/if}} - - {{#if showDatesOptions}} -
- - {{i18n "admin.dashboard.reports.dates"}} + {{#if model.trendIcon}} + {{d-icon model.trendIcon class="icon"}} + {{/if}} - -
- {{date-time-input-range - from=startDate - to=endDate - onChange=(action "onChangeDateRange") - showFromTime=false - showToTime=false - }} -
-
- {{/if}} - - {{#each model.available_filters as |filter|}} -
- - {{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}} - - -
- {{component - (concat "report-filters/" filter.type) - model=model - filter=filter - applyFilter=(action "applyFilter")}} -
-
- {{/each}} - -
-
- {{d-button - class="btn-default export-csv-btn" - action=(action "exportCsv") - label="admin.export_csv.button_text" - icon="download"}} -
-
- - {{#if showRefresh}} -
-
- {{d-button - class="refresh-report-btn btn-primary" - action=(action "refreshReport") - label="admin.dashboard.reports.refresh_report" - icon="sync"}} -
{{/if}}
{{/if}} + +
+
+ {{#if showError}} + {{#if showTimeoutError}} +
+ {{d-icon "exclamation-triangle"}} + {{i18n "admin.dashboard.timeout_error"}} +
+ {{/if}} + + {{#if showExceptionError}} +
+ {{d-icon "exclamation-triangle"}} + {{i18n "admin.dashboard.exception_error"}} +
+ {{/if}} + + {{#if showNotFoundError}} +
+ {{d-icon "exclamation-triangle"}} + {{i18n "admin.dashboard.not_found_error"}} +
+ {{/if}} + {{else}} + {{#if hasData}} + {{#if currentMode}} + {{component modeComponent model=model options=options}} + + {{#if model.relatedReport}} + {{admin-report showFilteringUI=false dataSourceName=model.relatedReport.type}} + {{/if}} + {{/if}} + {{else}} + {{#if rateLimitationString}} +
+ {{d-icon "thermometer-three-quarters"}} + {{rateLimitationString}} +
+ {{else}} +
+ {{d-icon "chart-pie"}} + {{#if model.reportUrl}} + + + {{#if model.title}} + {{model.title}} — + {{/if}} + {{i18n "admin.dashboard.reports.no_data"}} + + + {{else}} + {{i18n "admin.dashboard.reports.no_data"}} + {{/if}} +
+ {{/if}} + {{/if}} + {{/if}} +
+ + {{#if showFilteringUI}} +
+ {{#if showModes}} +
+ {{#each displayedModes as |displayedMode|}} + {{d-button + action=(action "changeMode") + actionParam=displayedMode.mode + class=displayedMode.cssClass + icon=displayedMode.icon}} + {{/each}} +
+ {{/if}} + + {{#if showDatesOptions}} +
+ + {{i18n "admin.dashboard.reports.dates"}} + + +
+ {{date-time-input-range + from=startDate + to=endDate + onChange=(action "onChangeDateRange") + showFromTime=false + showToTime=false + }} +
+
+ {{/if}} + + {{#each model.available_filters as |filter|}} +
+ + {{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}} + + +
+ {{component + (concat "report-filters/" filter.type) + model=model + filter=filter + applyFilter=(action "applyFilter")}} +
+
+ {{/each}} + +
+
+ {{d-button + class="btn-default export-csv-btn" + action=(action "exportCsv") + label="admin.export_csv.button_text" + icon="download"}} +
+
+ + {{#if showRefresh}} +
+
+ {{d-button + class="refresh-report-btn btn-primary" + action=(action "refreshReport") + label="admin.dashboard.reports.refresh_report" + icon="sync"}} +
+
+ {{/if}} +
+ {{/if}} +
+ {{/conditional-loading-section}} + {{else}} +
+ {{html-safe disabledLabel}}
- {{/conditional-loading-section}} -{{else}} -
- {{html-safe disabledLabel}} -
-{{/if}} + {{/if}} +{{/unless}} diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index 05296f4d7b3..0e4f4beec26 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -22,21 +22,30 @@ {{i18n "admin.dashboard.general_tab"}} {{/link-to}} - - - + + {{#if isModerationTabVisible}} + + {{/if}} + + {{#if isSecurityTabVisible}} + + {{/if}} + + {{#if isReportsTabVisible}} + + {{/if}} {{outlet}} diff --git a/app/assets/javascripts/admin/templates/dashboard_general.hbs b/app/assets/javascripts/admin/templates/dashboard_general.hbs index 16214a92e3c..5566271a20d 100644 --- a/app/assets/javascripts/admin/templates/dashboard_general.hbs +++ b/app/assets/javascripts/admin/templates/dashboard_general.hbs @@ -1,97 +1,101 @@ {{#conditional-loading-spinner condition=isLoading}} {{plugin-outlet name="admin-dashboard-general-top"}} -
-
-
-

- - {{i18n "admin.dashboard.community_health"}} - -

- {{period-chooser period=period action=(action "changePeriod") content=availablePeriods fullDay=true}} -
+ {{#if isCommunityHealthVisible}} +
+
+
+

+ + {{i18n "admin.dashboard.community_health"}} + +

+ {{period-chooser period=period action=(action "changePeriod") content=availablePeriods fullDay=true}} +
-
-
- {{admin-report - dataSourceName="consolidated_page_views" - forcedModes="stacked-chart" - filters=filters}} +
+
+ {{admin-report + dataSourceName="consolidated_page_views" + forcedModes="stacked-chart" + filters=filters}} - {{admin-report - dataSourceName="signups" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="signups" + showTrend=true + forcedModes="chart" + filters=filters}} - {{admin-report - dataSourceName="topics" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="topics" + showTrend=true + forcedModes="chart" + filters=filters}} - {{admin-report - dataSourceName="posts" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="posts" + showTrend=true + forcedModes="chart" + filters=filters}} - {{admin-report - dataSourceName="dau_by_mau" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="dau_by_mau" + showTrend=true + forcedModes="chart" + filters=filters}} - {{admin-report - dataSourceName="daily_engaged_users" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="daily_engaged_users" + showTrend=true + forcedModes="chart" + filters=filters}} - {{admin-report - dataSourceName="new_contributors" - showTrend=true - forcedModes="chart" - filters=filters}} + {{admin-report + dataSourceName="new_contributors" + showTrend=true + forcedModes="chart" + filters=filters}} +
-
+ {{/if}}
- {{#if activityMetrics.length}} -
-
- -
-
-
-
-
-
{{i18n "admin.dashboard.reports.today"}}
-
{{i18n "admin.dashboard.reports.yesterday"}}
-
{{i18n "admin.dashboard.reports.last_7_days"}}
-
{{i18n "admin.dashboard.reports.last_30_days"}}
-
+ {{#if isActivityMetricsVisible}} + {{#if activityMetrics.length}} +
+
+ +
+
+
+
+
+
{{i18n "admin.dashboard.reports.today"}}
+
{{i18n "admin.dashboard.reports.yesterday"}}
+
{{i18n "admin.dashboard.reports.last_7_days"}}
+
{{i18n "admin.dashboard.reports.last_30_days"}}
+
- {{#each activityMetrics as |metric|}} - {{admin-report - showHeader=false - filters=activityMetricsFilters - forcedModes="counters" - dataSourceName=metric}} - {{/each}} + {{#each activityMetrics as |metric|}} + {{admin-report + showHeader=false + filters=activityMetricsFilters + forcedModes="counters" + dataSourceName=metric}} + {{/each}} +
-
+ {{/if}} {{/if}}
@@ -130,20 +134,22 @@
-
- {{admin-report - filters=topReferredTopicsFilters - dataSourceName="top_referred_topics" - reportOptions=topReferredTopicsOptions}} + {{#if isSearchReportsVisible}} +
+ {{admin-report + filters=topReferredTopicsFilters + dataSourceName="top_referred_topics" + reportOptions=topReferredTopicsOptions}} - {{admin-report - dataSourceName="trending_search" - reportOptions=trendingSearchOptions - filters=trendingSearchFilters - isEnabled=logSearchQueriesEnabled - disabledLabel=trendingSearchDisabledLabel}} - {{html-safe (i18n "admin.dashboard.reports.trending_search.more" basePath=basePath)}} -
+ {{admin-report + dataSourceName="trending_search" + reportOptions=trendingSearchOptions + filters=trendingSearchFilters + isEnabled=logSearchQueriesEnabled + disabledLabel=trendingSearchDisabledLabel}} + {{html-safe (i18n "admin.dashboard.reports.trending_search.more" basePath=basePath)}} +
+ {{/if}}
{{plugin-outlet name="admin-dashboard-general-bottom"}} diff --git a/app/assets/javascripts/admin/templates/dashboard_moderation.hbs b/app/assets/javascripts/admin/templates/dashboard_moderation.hbs index 06ae3567f67..a6566b78e6b 100644 --- a/app/assets/javascripts/admin/templates/dashboard_moderation.hbs +++ b/app/assets/javascripts/admin/templates/dashboard_moderation.hbs @@ -1,27 +1,29 @@
{{plugin-outlet name="admin-dashboard-moderation-top"}} -
-
-

- - {{i18n "admin.dashboard.moderators_activity"}} - -

- {{period-chooser - period=period - action=(action "changePeriod") - content=availablePeriods - fullDay=true}} -
+ {{#if isModeratorsActivityVisible}} +
+
+

+ + {{i18n "admin.dashboard.moderators_activity"}} + +

+ {{period-chooser + period=period + action=(action "changePeriod") + content=availablePeriods + fullDay=true}} +
-
- {{admin-report - filters=filters - showHeader=false - dataSourceName="moderators_activity"}} +
+ {{admin-report + filters=filters + showHeader=false + dataSourceName="moderators_activity"}} +
-
+ {{/if}}
{{admin-report diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 7a0ebe6f4e3..bb7863aa189 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2195,6 +2195,8 @@ en: short_title: "The short title will be used on the user's home screen, launcher, or other places where space may be limited. It should be limited to 12 characters." + dashboard_hidden_reports: "Allow to hide the specified reports from the dashboard." + dashboard_visible_tabs: "Choose which dashboard tabs are visible." dashboard_general_tab_activity_metrics: "Choose reports to be displayed as activity metrics on the general tab." gravatar_name: "Name of the Gravatar provider" diff --git a/config/site_settings.yml b/config/site_settings.yml index ef0fea49980..edda4aa263e 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2205,6 +2205,22 @@ tags: client: true dashboard: + dashboard_hidden_reports: + client: true + type: list + list_type: compact + default: "" + allow_any: true + dashboard_visible_tabs: + client: true + type: list + list_type: compact + default: "moderation|security|reports" + allow_any: false + choices: + - moderation + - security + - reports dashboard_general_tab_activity_metrics: client: true type: list diff --git a/test/javascripts/acceptance/dashboard-test.js b/test/javascripts/acceptance/dashboard-test.js index 09c8d0a0b71..7f7e207765e 100644 --- a/test/javascripts/acceptance/dashboard-test.js +++ b/test/javascripts/acceptance/dashboard-test.js @@ -4,6 +4,7 @@ import { acceptance } from "helpers/qunit-helpers"; acceptance("Dashboard", { loggedIn: true, settings: { + dashboard_visible_tabs: "moderation|security|reports", dashboard_general_tab_activity_metrics: "page_view_total_reqs" }, site: { @@ -20,8 +21,9 @@ acceptance("Dashboard", { } }); -QUnit.test("Dashboard", async assert => { +QUnit.test("default", async assert => { await visit("/admin"); + assert.ok(exists(".dashboard"), "has dashboard-next class"); }); @@ -57,7 +59,7 @@ QUnit.test("general tab", async assert => { ); }); -QUnit.test("general tab - activity metrics", async assert => { +QUnit.test("activity metrics", async assert => { await visit("/admin"); assert.ok(exists(".admin-report.page-view-total-reqs .today-count")); @@ -100,7 +102,7 @@ QUnit.test("reports tab", async assert => { ); }); -QUnit.test("report filters", async assert => { +QUnit.test("reports filters", async assert => { await visit( '/admin/reports/signups_with_groups?end_date=2018-07-16&filters=%7B"group"%3A88%7D&start_date=2018-06-16' ); @@ -113,3 +115,41 @@ QUnit.test("report filters", async assert => { "its set the value of the filter from the query params" ); }); + +acceptance("Dashboard: dashboard_visible_tabs", { + loggedIn: true, + settings: { + dashboard_visible_tabs: "general|security|reports" + } +}); + +QUnit.test("visible tabs", async assert => { + await visit("/admin"); + + assert.ok(exists(".dashboard .navigation-item.general"), "general tab"); + assert.notOk( + exists(".dashboard .navigation-item.moderation"), + "moderation tab" + ); + assert.ok(exists(".dashboard .navigation-item.security"), "security tab"); + assert.ok(exists(".dashboard .navigation-item.reports"), "reports tab"); +}); + +acceptance("Dashboard: dashboard_hidden_reports", { + loggedIn: true, + settings: { + dashboard_visible_tabs: "reports", + dashboard_hidden_reports: "posts|dau_by_mau" + } +}); + +QUnit.test("hidden reports", async assert => { + await visit("/admin"); + + assert.ok(exists(".admin-report.signups.is-visible"), "signups report"); + assert.notOk(exists(".admin-report.is-visible.posts"), "posts report"); + assert.notOk( + exists(".admin-report.is-visible.dau-by-mau"), + "dau-by-mau report" + ); +});