mirror of
https://github.com/discourse/discourse.git
synced 2025-05-31 04:00:49 +08:00
FEATURE: allows to limit visible reports and tabs in dashboard (#9598)
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { makeArray } from "discourse-common/lib/helpers";
|
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 EmberObject, { computed, action } from "@ember/object";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
@ -41,7 +41,12 @@ function collapseWeekly(data, average) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: ["isEnabled", "isLoading", "dasherizedDataSourceName"],
|
classNameBindings: [
|
||||||
|
"isVisible",
|
||||||
|
"isEnabled",
|
||||||
|
"isLoading",
|
||||||
|
"dasherizedDataSourceName"
|
||||||
|
],
|
||||||
classNames: ["admin-report"],
|
classNames: ["admin-report"],
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
disabledLabel: I18n.t("admin.dashboard.disabled"),
|
disabledLabel: I18n.t("admin.dashboard.disabled"),
|
||||||
@ -63,6 +68,7 @@ export default Component.extend({
|
|||||||
showDatesOptions: alias("model.dates_filtering"),
|
showDatesOptions: alias("model.dates_filtering"),
|
||||||
showRefresh: or("showDatesOptions", "model.available_filters.length"),
|
showRefresh: or("showDatesOptions", "model.available_filters.length"),
|
||||||
shouldDisplayTrend: and("showTrend", "model.prev_period"),
|
shouldDisplayTrend: and("showTrend", "model.prev_period"),
|
||||||
|
isVisible: not("isHidden"),
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
@ -70,6 +76,13 @@ export default Component.extend({
|
|||||||
this._reports = [];
|
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() {
|
startDate: computed("filters.startDate", function() {
|
||||||
if (this.filters && isPresent(this.filters.startDate)) {
|
if (this.filters && isPresent(this.filters.startDate)) {
|
||||||
return moment(this.filters.startDate, "YYYY-MM-DD");
|
return moment(this.filters.startDate, "YYYY-MM-DD");
|
||||||
|
@ -23,9 +23,44 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
|
|
||||||
@discourseComputed("siteSettings.dashboard_general_tab_activity_metrics")
|
@discourseComputed("siteSettings.dashboard_general_tab_activity_metrics")
|
||||||
activityMetrics(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
|
@discourseComputed
|
||||||
activityMetricsFilters() {
|
activityMetricsFilters() {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
|
||||||
export default Controller.extend(PeriodComputationMixin, {
|
export default Controller.extend(PeriodComputationMixin, {
|
||||||
@discourseComputed
|
@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
|
@discourseComputed
|
||||||
userFlaggingRatioOptions() {
|
userFlaggingRatioOptions() {
|
||||||
return {
|
return {
|
||||||
|
@ -8,17 +8,27 @@ const { get } = Ember;
|
|||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
filter: null,
|
filter: null,
|
||||||
|
|
||||||
@discourseComputed("model.[]", "filter")
|
@discourseComputed(
|
||||||
|
"model.[]",
|
||||||
|
"filter",
|
||||||
|
"siteSettings.dashboard_hidden_reports"
|
||||||
|
)
|
||||||
filterReports(reports, filter) {
|
filterReports(reports, filter) {
|
||||||
if (filter) {
|
if (filter) {
|
||||||
filter = filter.toLowerCase();
|
filter = filter.toLowerCase();
|
||||||
return reports.filter(report => {
|
reports = reports.filter(report => {
|
||||||
return (
|
return (
|
||||||
(get(report, "title") || "").toLowerCase().indexOf(filter) > -1 ||
|
(get(report, "title") || "").toLowerCase().indexOf(filter) > -1 ||
|
||||||
(get(report, "description") || "").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;
|
return reports;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { inject } from "@ember/controller";
|
import Controller, { inject } from "@ember/controller";
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import { setting } from "discourse/lib/computed";
|
import { setting } from "discourse/lib/computed";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
import AdminDashboard from "admin/models/admin-dashboard";
|
import AdminDashboard from "admin/models/admin-dashboard";
|
||||||
import VersionCheck from "admin/models/version-check";
|
import VersionCheck from "admin/models/version-check";
|
||||||
|
|
||||||
@ -18,6 +18,24 @@ export default Controller.extend({
|
|||||||
return this.currentUser.get("admin") && (problemsLength || 0) > 0;
|
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() {
|
fetchProblems() {
|
||||||
if (this.isLoadingProblems) return;
|
if (this.isLoadingProblems) return;
|
||||||
|
|
||||||
|
@ -1,195 +1,197 @@
|
|||||||
{{#if isEnabled}}
|
{{#unless isHidden}}
|
||||||
{{#conditional-loading-section isLoading=isLoading}}
|
{{#if isEnabled}}
|
||||||
{{#if showHeader}}
|
{{#conditional-loading-section isLoading=isLoading}}
|
||||||
<div class="header">
|
{{#if showHeader}}
|
||||||
{{#if showTitle}}
|
<div class="header">
|
||||||
<ul class="breadcrumb">
|
{{#if showTitle}}
|
||||||
{{#if showAllReportsLink}}
|
<ul class="breadcrumb">
|
||||||
<li class="item all-reports">
|
{{#if showAllReportsLink}}
|
||||||
{{#link-to "admin.dashboardReports" class="report-url"}}
|
<li class="item all-reports">
|
||||||
{{i18n "admin.dashboard.all_reports"}}
|
{{#link-to "admin.dashboardReports" class="report-url"}}
|
||||||
{{/link-to}}
|
{{i18n "admin.dashboard.all_reports"}}
|
||||||
</li>
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{{#unless showNotFoundError}}
|
||||||
|
<li class="item separator">|</li>
|
||||||
|
{{/unless}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#unless showNotFoundError}}
|
{{#unless showNotFoundError}}
|
||||||
<li class="item separator">|</li>
|
<li class="item report">
|
||||||
{{/unless}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#unless showNotFoundError}}
|
|
||||||
<li class="item report">
|
|
||||||
<a href={{model.reportUrl}} class="report-url">
|
|
||||||
{{model.title}}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{{#if model.description}}
|
|
||||||
{{#if model.description_link}}
|
|
||||||
<a target="_blank" rel="noopener noreferrer" href={{model.description_link}} class="info" data-tooltip={{model.description}}>
|
|
||||||
{{d-icon "question-circle"}}
|
|
||||||
</a>
|
|
||||||
{{else}}
|
|
||||||
<span class="info" data-tooltip={{model.description}}>
|
|
||||||
{{d-icon "question-circle"}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</li>
|
|
||||||
{{/unless}}
|
|
||||||
</ul>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if shouldDisplayTrend}}
|
|
||||||
<div class="trend {{model.trend}}">
|
|
||||||
<span class="value" title={{model.trendTitle}}>
|
|
||||||
{{#if model.average}}
|
|
||||||
{{number model.currentAverage}}{{#if model.percent}}%{{/if}}
|
|
||||||
{{else}}
|
|
||||||
{{number model.currentTotal noTitle="true"}}{{#if model.percent}}%{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if model.trendIcon}}
|
|
||||||
{{d-icon model.trendIcon class="icon"}}
|
|
||||||
{{/if}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="body">
|
|
||||||
<div class="main">
|
|
||||||
{{#if showError}}
|
|
||||||
{{#if showTimeoutError}}
|
|
||||||
<div class="alert alert-error report-alert timeout">
|
|
||||||
{{d-icon "exclamation-triangle"}}
|
|
||||||
<span>{{i18n "admin.dashboard.timeout_error"}}</span>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if showExceptionError}}
|
|
||||||
<div class="alert alert-error report-alert exception">
|
|
||||||
{{d-icon "exclamation-triangle"}}
|
|
||||||
<span>{{i18n "admin.dashboard.exception_error"}}</span>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if showNotFoundError}}
|
|
||||||
<div class="alert alert-error report-alert not-found">
|
|
||||||
{{d-icon "exclamation-triangle"}}
|
|
||||||
<span>{{i18n "admin.dashboard.not_found_error"}}</span>
|
|
||||||
</div>
|
|
||||||
{{/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}}
|
|
||||||
<div class="alert alert-error report-alert rate-limited">
|
|
||||||
{{d-icon "thermometer-three-quarters"}}
|
|
||||||
<span>{{rateLimitationString}}</span>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-info report-alert no-data">
|
|
||||||
{{d-icon "chart-pie"}}
|
|
||||||
{{#if model.reportUrl}}
|
|
||||||
<a href={{model.reportUrl}} class="report-url">
|
<a href={{model.reportUrl}} class="report-url">
|
||||||
<span>
|
{{model.title}}
|
||||||
{{#if model.title}}
|
|
||||||
{{model.title}} —
|
|
||||||
{{/if}}
|
|
||||||
{{i18n "admin.dashboard.reports.no_data"}}
|
|
||||||
</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{{#if model.description}}
|
||||||
|
{{#if model.description_link}}
|
||||||
|
<a target="_blank" rel="noopener noreferrer" href={{model.description_link}} class="info" data-tooltip={{model.description}}>
|
||||||
|
{{d-icon "question-circle"}}
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<span class="info" data-tooltip={{model.description}}>
|
||||||
|
{{d-icon "question-circle"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</li>
|
||||||
|
{{/unless}}
|
||||||
|
</ul>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if shouldDisplayTrend}}
|
||||||
|
<div class="trend {{model.trend}}">
|
||||||
|
<span class="value" title={{model.trendTitle}}>
|
||||||
|
{{#if model.average}}
|
||||||
|
{{number model.currentAverage}}{{#if model.percent}}%{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>{{i18n "admin.dashboard.reports.no_data"}}</span>
|
{{number model.currentTotal noTitle="true"}}{{#if model.percent}}%{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if showFilteringUI}}
|
{{#if model.trendIcon}}
|
||||||
<div class="filters">
|
{{d-icon model.trendIcon class="icon"}}
|
||||||
{{#if showModes}}
|
{{/if}}
|
||||||
<div class="modes">
|
|
||||||
{{#each displayedModes as |displayedMode|}}
|
|
||||||
{{d-button
|
|
||||||
action=(action "changeMode")
|
|
||||||
actionParam=displayedMode.mode
|
|
||||||
class=displayedMode.cssClass
|
|
||||||
icon=displayedMode.icon}}
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if showDatesOptions}}
|
|
||||||
<div class="control">
|
|
||||||
<span class="label">
|
|
||||||
{{i18n "admin.dashboard.reports.dates"}}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="input">
|
|
||||||
{{date-time-input-range
|
|
||||||
from=startDate
|
|
||||||
to=endDate
|
|
||||||
onChange=(action "onChangeDateRange")
|
|
||||||
showFromTime=false
|
|
||||||
showToTime=false
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#each model.available_filters as |filter|}}
|
|
||||||
<div class="control">
|
|
||||||
<span class="label">
|
|
||||||
{{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="input">
|
|
||||||
{{component
|
|
||||||
(concat "report-filters/" filter.type)
|
|
||||||
model=model
|
|
||||||
filter=filter
|
|
||||||
applyFilter=(action "applyFilter")}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
<div class="control">
|
|
||||||
<div class="input">
|
|
||||||
{{d-button
|
|
||||||
class="btn-default export-csv-btn"
|
|
||||||
action=(action "exportCsv")
|
|
||||||
label="admin.export_csv.button_text"
|
|
||||||
icon="download"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if showRefresh}}
|
|
||||||
<div class="control">
|
|
||||||
<div class="input">
|
|
||||||
{{d-button
|
|
||||||
class="refresh-report-btn btn-primary"
|
|
||||||
action=(action "refreshReport")
|
|
||||||
label="admin.dashboard.reports.refresh_report"
|
|
||||||
icon="sync"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="body">
|
||||||
|
<div class="main">
|
||||||
|
{{#if showError}}
|
||||||
|
{{#if showTimeoutError}}
|
||||||
|
<div class="alert alert-error report-alert timeout">
|
||||||
|
{{d-icon "exclamation-triangle"}}
|
||||||
|
<span>{{i18n "admin.dashboard.timeout_error"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showExceptionError}}
|
||||||
|
<div class="alert alert-error report-alert exception">
|
||||||
|
{{d-icon "exclamation-triangle"}}
|
||||||
|
<span>{{i18n "admin.dashboard.exception_error"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showNotFoundError}}
|
||||||
|
<div class="alert alert-error report-alert not-found">
|
||||||
|
{{d-icon "exclamation-triangle"}}
|
||||||
|
<span>{{i18n "admin.dashboard.not_found_error"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/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}}
|
||||||
|
<div class="alert alert-error report-alert rate-limited">
|
||||||
|
{{d-icon "thermometer-three-quarters"}}
|
||||||
|
<span>{{rateLimitationString}}</span>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="alert alert-info report-alert no-data">
|
||||||
|
{{d-icon "chart-pie"}}
|
||||||
|
{{#if model.reportUrl}}
|
||||||
|
<a href={{model.reportUrl}} class="report-url">
|
||||||
|
<span>
|
||||||
|
{{#if model.title}}
|
||||||
|
{{model.title}} —
|
||||||
|
{{/if}}
|
||||||
|
{{i18n "admin.dashboard.reports.no_data"}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<span>{{i18n "admin.dashboard.reports.no_data"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if showFilteringUI}}
|
||||||
|
<div class="filters">
|
||||||
|
{{#if showModes}}
|
||||||
|
<div class="modes">
|
||||||
|
{{#each displayedModes as |displayedMode|}}
|
||||||
|
{{d-button
|
||||||
|
action=(action "changeMode")
|
||||||
|
actionParam=displayedMode.mode
|
||||||
|
class=displayedMode.cssClass
|
||||||
|
icon=displayedMode.icon}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showDatesOptions}}
|
||||||
|
<div class="control">
|
||||||
|
<span class="label">
|
||||||
|
{{i18n "admin.dashboard.reports.dates"}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
{{date-time-input-range
|
||||||
|
from=startDate
|
||||||
|
to=endDate
|
||||||
|
onChange=(action "onChangeDateRange")
|
||||||
|
showFromTime=false
|
||||||
|
showToTime=false
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#each model.available_filters as |filter|}}
|
||||||
|
<div class="control">
|
||||||
|
<span class="label">
|
||||||
|
{{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
{{component
|
||||||
|
(concat "report-filters/" filter.type)
|
||||||
|
model=model
|
||||||
|
filter=filter
|
||||||
|
applyFilter=(action "applyFilter")}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
<div class="input">
|
||||||
|
{{d-button
|
||||||
|
class="btn-default export-csv-btn"
|
||||||
|
action=(action "exportCsv")
|
||||||
|
label="admin.export_csv.button_text"
|
||||||
|
icon="download"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if showRefresh}}
|
||||||
|
<div class="control">
|
||||||
|
<div class="input">
|
||||||
|
{{d-button
|
||||||
|
class="refresh-report-btn btn-primary"
|
||||||
|
action=(action "refreshReport")
|
||||||
|
label="admin.dashboard.reports.refresh_report"
|
||||||
|
icon="sync"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/conditional-loading-section}}
|
||||||
|
{{else}}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{{html-safe disabledLabel}}
|
||||||
</div>
|
</div>
|
||||||
{{/conditional-loading-section}}
|
{{/if}}
|
||||||
{{else}}
|
{{/unless}}
|
||||||
<div class="alert alert-info">
|
|
||||||
{{html-safe disabledLabel}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
@ -22,21 +22,30 @@
|
|||||||
{{i18n "admin.dashboard.general_tab"}}
|
{{i18n "admin.dashboard.general_tab"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
<li class="navigation-item moderation">
|
|
||||||
{{#link-to "admin.dashboardModeration" class="navigation-link"}}
|
{{#if isModerationTabVisible}}
|
||||||
{{i18n "admin.dashboard.moderation_tab"}}
|
<li class="navigation-item moderation">
|
||||||
{{/link-to}}
|
{{#link-to "admin.dashboardModeration" class="navigation-link"}}
|
||||||
</li>
|
{{i18n "admin.dashboard.moderation_tab"}}
|
||||||
<li class="navigation-item security">
|
{{/link-to}}
|
||||||
{{#link-to "admin.dashboardSecurity" class="navigation-link"}}
|
</li>
|
||||||
{{i18n "admin.dashboard.security_tab"}}
|
{{/if}}
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
{{#if isSecurityTabVisible}}
|
||||||
<li class="navigation-item reports">
|
<li class="navigation-item security">
|
||||||
{{#link-to "admin.dashboardReports" class="navigation-link"}}
|
{{#link-to "admin.dashboardSecurity" class="navigation-link"}}
|
||||||
{{i18n "admin.dashboard.reports_tab"}}
|
{{i18n "admin.dashboard.security_tab"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isReportsTabVisible}}
|
||||||
|
<li class="navigation-item reports">
|
||||||
|
{{#link-to "admin.dashboardReports" class="navigation-link"}}
|
||||||
|
{{i18n "admin.dashboard.reports_tab"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
@ -1,97 +1,101 @@
|
|||||||
{{#conditional-loading-spinner condition=isLoading}}
|
{{#conditional-loading-spinner condition=isLoading}}
|
||||||
{{plugin-outlet name="admin-dashboard-general-top"}}
|
{{plugin-outlet name="admin-dashboard-general-top"}}
|
||||||
|
|
||||||
<div class="community-health section">
|
{{#if isCommunityHealthVisible}}
|
||||||
<div class="period-section">
|
<div class="community-health section">
|
||||||
<div class="section-title">
|
<div class="period-section">
|
||||||
<h2>
|
<div class="section-title">
|
||||||
<a href={{get-url "/admin/dashboard/reports"}}>
|
<h2>
|
||||||
{{i18n "admin.dashboard.community_health"}}
|
<a href={{get-url "/admin/dashboard/reports"}}>
|
||||||
</a>
|
{{i18n "admin.dashboard.community_health"}}
|
||||||
</h2>
|
</a>
|
||||||
{{period-chooser period=period action=(action "changePeriod") content=availablePeriods fullDay=true}}
|
</h2>
|
||||||
</div>
|
{{period-chooser period=period action=(action "changePeriod") content=availablePeriods fullDay=true}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section-body">
|
<div class="section-body">
|
||||||
<div class="charts">
|
<div class="charts">
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="consolidated_page_views"
|
dataSourceName="consolidated_page_views"
|
||||||
forcedModes="stacked-chart"
|
forcedModes="stacked-chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="signups"
|
dataSourceName="signups"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="topics"
|
dataSourceName="topics"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="posts"
|
dataSourceName="posts"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="dau_by_mau"
|
dataSourceName="dau_by_mau"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="daily_engaged_users"
|
dataSourceName="daily_engaged_users"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="new_contributors"
|
dataSourceName="new_contributors"
|
||||||
showTrend=true
|
showTrend=true
|
||||||
forcedModes="chart"
|
forcedModes="chart"
|
||||||
filters=filters}}
|
filters=filters}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
|
|
||||||
<div class="section-columns">
|
<div class="section-columns">
|
||||||
<div class="section-column">
|
<div class="section-column">
|
||||||
{{#if activityMetrics.length}}
|
{{#if isActivityMetricsVisible}}
|
||||||
<div class="admin-report activity-metrics">
|
{{#if activityMetrics.length}}
|
||||||
<div class="header">
|
<div class="admin-report activity-metrics">
|
||||||
<ul class="breadcrumb">
|
<div class="header">
|
||||||
<li class="item report">
|
<ul class="breadcrumb">
|
||||||
{{#link-to "adminReports" class="report-url"}}
|
<li class="item report">
|
||||||
{{i18n "admin.dashboard.activity_metrics"}}
|
{{#link-to "adminReports" class="report-url"}}
|
||||||
{{/link-to}}
|
{{i18n "admin.dashboard.activity_metrics"}}
|
||||||
</li>
|
{{/link-to}}
|
||||||
</ul>
|
</li>
|
||||||
</div>
|
</ul>
|
||||||
<div class="report-body">
|
</div>
|
||||||
<div class="counters-list">
|
<div class="report-body">
|
||||||
<div class="counters-header">
|
<div class="counters-list">
|
||||||
<div class="counters-cell"></div>
|
<div class="counters-header">
|
||||||
<div class="counters-cell">{{i18n "admin.dashboard.reports.today"}}</div>
|
<div class="counters-cell"></div>
|
||||||
<div class="counters-cell">{{i18n "admin.dashboard.reports.yesterday"}}</div>
|
<div class="counters-cell">{{i18n "admin.dashboard.reports.today"}}</div>
|
||||||
<div class="counters-cell">{{i18n "admin.dashboard.reports.last_7_days"}}</div>
|
<div class="counters-cell">{{i18n "admin.dashboard.reports.yesterday"}}</div>
|
||||||
<div class="counters-cell">{{i18n "admin.dashboard.reports.last_30_days"}}</div>
|
<div class="counters-cell">{{i18n "admin.dashboard.reports.last_7_days"}}</div>
|
||||||
</div>
|
<div class="counters-cell">{{i18n "admin.dashboard.reports.last_30_days"}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#each activityMetrics as |metric|}}
|
{{#each activityMetrics as |metric|}}
|
||||||
{{admin-report
|
{{admin-report
|
||||||
showHeader=false
|
showHeader=false
|
||||||
filters=activityMetricsFilters
|
filters=activityMetricsFilters
|
||||||
forcedModes="counters"
|
forcedModes="counters"
|
||||||
dataSourceName=metric}}
|
dataSourceName=metric}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="user-metrics">
|
<div class="user-metrics">
|
||||||
@ -130,20 +134,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section-column">
|
{{#if isSearchReportsVisible}}
|
||||||
{{admin-report
|
<div class="section-column">
|
||||||
filters=topReferredTopicsFilters
|
{{admin-report
|
||||||
dataSourceName="top_referred_topics"
|
filters=topReferredTopicsFilters
|
||||||
reportOptions=topReferredTopicsOptions}}
|
dataSourceName="top_referred_topics"
|
||||||
|
reportOptions=topReferredTopicsOptions}}
|
||||||
|
|
||||||
{{admin-report
|
{{admin-report
|
||||||
dataSourceName="trending_search"
|
dataSourceName="trending_search"
|
||||||
reportOptions=trendingSearchOptions
|
reportOptions=trendingSearchOptions
|
||||||
filters=trendingSearchFilters
|
filters=trendingSearchFilters
|
||||||
isEnabled=logSearchQueriesEnabled
|
isEnabled=logSearchQueriesEnabled
|
||||||
disabledLabel=trendingSearchDisabledLabel}}
|
disabledLabel=trendingSearchDisabledLabel}}
|
||||||
{{html-safe (i18n "admin.dashboard.reports.trending_search.more" basePath=basePath)}}
|
{{html-safe (i18n "admin.dashboard.reports.trending_search.more" basePath=basePath)}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{plugin-outlet name="admin-dashboard-general-bottom"}}
|
{{plugin-outlet name="admin-dashboard-general-bottom"}}
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
<div class="sections">
|
<div class="sections">
|
||||||
{{plugin-outlet name="admin-dashboard-moderation-top"}}
|
{{plugin-outlet name="admin-dashboard-moderation-top"}}
|
||||||
|
|
||||||
<div class="moderators-activity section">
|
{{#if isModeratorsActivityVisible}}
|
||||||
<div class="section-title">
|
<div class="moderators-activity section">
|
||||||
<h2>
|
<div class="section-title">
|
||||||
<a href={{get-url "/admin/reports/moderators_activity"}}>
|
<h2>
|
||||||
{{i18n "admin.dashboard.moderators_activity"}}
|
<a href={{get-url "/admin/reports/moderators_activity"}}>
|
||||||
</a>
|
{{i18n "admin.dashboard.moderators_activity"}}
|
||||||
</h2>
|
</a>
|
||||||
{{period-chooser
|
</h2>
|
||||||
period=period
|
{{period-chooser
|
||||||
action=(action "changePeriod")
|
period=period
|
||||||
content=availablePeriods
|
action=(action "changePeriod")
|
||||||
fullDay=true}}
|
content=availablePeriods
|
||||||
</div>
|
fullDay=true}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section-body">
|
<div class="section-body">
|
||||||
{{admin-report
|
{{admin-report
|
||||||
filters=filters
|
filters=filters
|
||||||
showHeader=false
|
showHeader=false
|
||||||
dataSourceName="moderators_activity"}}
|
dataSourceName="moderators_activity"}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
|
|
||||||
<div class="main-section">
|
<div class="main-section">
|
||||||
{{admin-report
|
{{admin-report
|
||||||
|
@ -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."
|
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."
|
dashboard_general_tab_activity_metrics: "Choose reports to be displayed as activity metrics on the general tab."
|
||||||
|
|
||||||
gravatar_name: "Name of the Gravatar provider"
|
gravatar_name: "Name of the Gravatar provider"
|
||||||
|
@ -2205,6 +2205,22 @@ tags:
|
|||||||
client: true
|
client: true
|
||||||
|
|
||||||
dashboard:
|
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:
|
dashboard_general_tab_activity_metrics:
|
||||||
client: true
|
client: true
|
||||||
type: list
|
type: list
|
||||||
|
@ -4,6 +4,7 @@ import { acceptance } from "helpers/qunit-helpers";
|
|||||||
acceptance("Dashboard", {
|
acceptance("Dashboard", {
|
||||||
loggedIn: true,
|
loggedIn: true,
|
||||||
settings: {
|
settings: {
|
||||||
|
dashboard_visible_tabs: "moderation|security|reports",
|
||||||
dashboard_general_tab_activity_metrics: "page_view_total_reqs"
|
dashboard_general_tab_activity_metrics: "page_view_total_reqs"
|
||||||
},
|
},
|
||||||
site: {
|
site: {
|
||||||
@ -20,8 +21,9 @@ acceptance("Dashboard", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("Dashboard", async assert => {
|
QUnit.test("default", async assert => {
|
||||||
await visit("/admin");
|
await visit("/admin");
|
||||||
|
|
||||||
assert.ok(exists(".dashboard"), "has dashboard-next class");
|
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");
|
await visit("/admin");
|
||||||
|
|
||||||
assert.ok(exists(".admin-report.page-view-total-reqs .today-count"));
|
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(
|
await visit(
|
||||||
'/admin/reports/signups_with_groups?end_date=2018-07-16&filters=%7B"group"%3A88%7D&start_date=2018-06-16'
|
'/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"
|
"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"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user