FEATURE: allows to display charts by day/week/month (#10325)

This commit is contained in:
Joffrey JAFFEUX 2020-07-28 16:14:41 +02:00 committed by GitHub
parent bc11769118
commit 0c7eaa57b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 148 additions and 8 deletions

View File

@ -8,6 +8,7 @@ export default Component.extend({
classNames: ["admin-report-chart"],
limit: 8,
total: 0,
options: null,
init() {
this._super(...arguments);
@ -49,7 +50,11 @@ export default Component.extend({
if (!chartCanvas) return;
const context = chartCanvas.getContext("2d");
const chartData = makeArray(model.get("chartData") || model.get("data"));
const chartData = this._applyChartGrouping(
model,
makeArray(model.get("chartData") || model.get("data"), "weekly"),
this.options
);
const prevChartData = makeArray(
model.get("prevChartData") || model.get("prev_data")
);
@ -91,11 +96,14 @@ export default Component.extend({
return;
}
this._chart = new window.Chart(context, this._buildChartConfig(data));
this._chart = new window.Chart(
context,
this._buildChartConfig(data, this.options)
);
});
},
_buildChartConfig(data) {
_buildChartConfig(data, options) {
return {
type: "line",
data,
@ -144,7 +152,7 @@ export default Component.extend({
gridLines: { display: false },
type: "time",
time: {
parser: "YYYY-MM-DD"
unit: this._unitForGrouping(options)
},
ticks: {
sampleSize: 5,
@ -163,5 +171,65 @@ export default Component.extend({
this._chart.destroy();
this._chart = null;
}
},
_applyChartGrouping(model, data, options) {
if (!options.chartGrouping || options.chartGrouping === "daily") {
return data;
}
if (
options.chartGrouping === "weekly" ||
options.chartGrouping === "monthly"
) {
const isoKind = options.chartGrouping === "weekly" ? "isoWeek" : "month";
const kind = options.chartGrouping === "weekly" ? "week" : "month";
const startMoment = moment(model.start_date, "YYYY-MM-DD");
let currentIndex = 0;
let currentStart = startMoment.clone().startOf(isoKind);
let currentEnd = startMoment.clone().endOf(isoKind);
const transformedData = [
{
x: currentStart.format("YYYY-MM-DD"),
y: 0
}
];
data.forEach(d => {
let date = moment(d.x, "YYYY-MM-DD");
if (!date.isBetween(currentStart, currentEnd)) {
currentIndex += 1;
currentStart = currentStart.add(1, kind).startOf(isoKind);
currentEnd = currentEnd.add(1, kind).endOf(isoKind);
}
if (transformedData[currentIndex]) {
transformedData[currentIndex].y += d.y;
} else {
transformedData[currentIndex] = {
x: d.x,
y: d.y
};
}
});
return transformedData;
}
// ensure we return something if grouping is unknown
return data;
},
_unitForGrouping(options) {
switch (options.chartGrouping) {
case "monthly":
return "month";
case "weekly":
return "week";
default:
return "day";
}
}
});

View File

@ -131,6 +131,18 @@ export default Component.extend({
return displayedModesLength > 1;
},
@discourseComputed("currentMode")
isChartMode(currentMode) {
return currentMode === "chart";
},
@action
changeGrouping(grouping) {
this.send("refreshReport", {
chartGrouping: grouping
});
},
@discourseComputed("currentMode", "model.modes", "forcedModes")
displayedModes(currentMode, reportModes, forcedModes) {
const modes = forcedModes ? forcedModes.split(",") : reportModes;
@ -184,6 +196,19 @@ export default Component.extend({
return reportKey;
},
@discourseComputed("reportOptions.chartGrouping")
chartGroupings(chartGrouping) {
chartGrouping = chartGrouping || "daily";
return ["daily", "weekly", "monthly"].map(id => {
return {
id,
label: `admin.dashboard.reports.${id}`,
class: `chart-grouping ${chartGrouping === id ? "active" : "inactive"}`
};
});
},
@action
onChangeDateRange(range) {
this.send("refreshReport", {
@ -211,6 +236,7 @@ export default Component.extend({
refreshReport(options = {}) {
this.attrs.onRefresh({
type: this.get("model.type"),
chartGrouping: options.chartGrouping,
startDate:
typeof options.startDate === "undefined"
? this.startDate
@ -243,6 +269,10 @@ export default Component.extend({
@action
changeMode(mode) {
this.set("currentMode", mode);
this.send("refreshReport", {
chartGrouping: null
});
},
_computeReport() {
@ -364,7 +394,9 @@ export default Component.extend({
} else {
const chartOptions = JSON.parse(JSON.stringify(CHART_OPTIONS));
return EmberObject.create(
Object.assign(chartOptions, this.get("reportOptions.chart") || {})
Object.assign(chartOptions, this.get("reportOptions.chart") || {}, {
chartGrouping: this.get("reportOptions.chartGrouping")
})
);
}
},

View File

@ -2,10 +2,11 @@ import discourseComputed from "discourse-common/utils/decorators";
import Controller from "@ember/controller";
export default Controller.extend({
queryParams: ["start_date", "end_date", "filters"],
queryParams: ["start_date", "end_date", "filters", "chart_grouping"],
start_date: null,
end_date: null,
filters: null,
chart_grouping: null,
@discourseComputed("model.type")
reportOptions(type) {
@ -15,6 +16,8 @@ export default Controller.extend({
options.table.limit = 10;
}
options.chartGrouping = this.chart_grouping;
return options;
}
});

View File

@ -4,7 +4,8 @@ export default DiscourseRoute.extend({
queryParams: {
start_date: { refreshModel: true },
end_date: { refreshModel: true },
filters: { refreshModel: true }
filters: { refreshModel: true },
chart_grouping: { refreshModel: true }
},
model(params) {
@ -27,6 +28,9 @@ export default DiscourseRoute.extend({
.format("YYYY-MM-DD");
delete params.end_date;
params.chartGrouping = params.chart_grouping || "daily";
delete params.chart_grouping;
return params;
},
@ -57,6 +61,7 @@ export default DiscourseRoute.extend({
start_date: params.startDate
? params.startDate.toISOString(true).split("T")[0]
: null,
chart_grouping: params.chartGrouping,
filters: params.filters,
end_date: params.endDate
? params.endDate.toISOString(true).split("T")[0]

View File

@ -130,6 +130,18 @@
</div>
{{/if}}
{{#if isChartMode}}
<div class="chart-groupings">
{{#each chartGroupings as |chartGrouping|}}
{{d-button
label=chartGrouping.label
action=(action "changeGrouping" chartGrouping.id)
class=chartGrouping.class
}}
{{/each}}
</div>
{{/if}}
{{#if showDatesOptions}}
<div class="control">
<span class="label">

View File

@ -140,6 +140,18 @@
}
}
.chart-groupings {
display: grid;
grid-template-columns: repeat(auto-fill, 1fr);
grid-gap: 0.5em;
margin-bottom: 1em;
.chart-grouping.active {
background: $tertiary;
color: $secondary;
}
}
.control {
margin-bottom: 1em;
}

View File

@ -1,3 +1,9 @@
.admin-report-chart {
animation: fadein 2s;
.chart-canvas-container {
position: relative;
height: 50vh;
width: 100%;
}
}

View File

@ -3500,6 +3500,9 @@ en:
view_table: "table"
view_graph: "graph"
refresh_report: "Refresh Report"
daily: Daily
monthly: Monthly
weekly: Weekly
dates: "Dates (UTC)"
groups: "All groups"
disabled: "This report is disabled"
@ -3630,7 +3633,6 @@ en:
optional_allowed_parameters: Allowed Parameters (optional)
any_parameter: (any parameter)
web_hooks:
title: "Webhooks"
none: "There are no webhooks right now."