2018-04-16 04:42:06 -04:00
|
|
|
import { ajax } from 'discourse/lib/ajax';
|
|
|
|
import computed from 'ember-addons/ember-computed-decorators';
|
|
|
|
import loadScript from 'discourse/lib/load-script';
|
|
|
|
|
|
|
|
export default Ember.Component.extend({
|
2018-04-16 06:00:49 -04:00
|
|
|
classNames: ["dashboard-mini-chart"],
|
2018-04-16 04:42:06 -04:00
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
classNameBindings: ["trend", "oneDataPoint", "isLoading"],
|
2018-04-16 04:42:06 -04:00
|
|
|
|
|
|
|
isLoading: false,
|
|
|
|
total: null,
|
|
|
|
trend: null,
|
|
|
|
title: null,
|
|
|
|
chartData: null,
|
|
|
|
oneDataPoint: false,
|
|
|
|
backgroundColor: "rgba(200,220,240,0.3)",
|
|
|
|
borderColor: "#08C",
|
|
|
|
|
2018-04-18 15:30:41 -04:00
|
|
|
didUpdateAttrs() {
|
2018-04-16 04:42:06 -04:00
|
|
|
this._super();
|
|
|
|
|
|
|
|
loadScript("/javascripts/Chart.min.js").then(() => {
|
2018-04-18 15:30:41 -04:00
|
|
|
if (this.get("model") && !this.get("chartData")) {
|
|
|
|
this._setPropertiesFromModel(this.get("model"));
|
|
|
|
this._drawChart();
|
|
|
|
} else if (this.get("dataSource")) {
|
|
|
|
this._fetchReport();
|
|
|
|
}
|
2018-04-16 04:42:06 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
@computed("dataSourceName")
|
|
|
|
dataSource(dataSourceName) {
|
2018-04-18 15:30:41 -04:00
|
|
|
if (dataSourceName) {
|
|
|
|
return `/admin/reports/${dataSourceName}`;
|
|
|
|
}
|
2018-04-16 04:42:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
@computed("trend")
|
|
|
|
trendIcon(trend) {
|
|
|
|
if (trend === "stable") {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return `angle-${trend}`;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-18 15:30:41 -04:00
|
|
|
_fetchReport() {
|
2018-04-17 05:01:06 -04:00
|
|
|
if (this.get("isLoading")) return;
|
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
this.set("isLoading", true);
|
|
|
|
|
2018-04-16 04:42:06 -04:00
|
|
|
let payload = {data: {}};
|
|
|
|
|
|
|
|
if (this.get("startDate")) {
|
|
|
|
payload.data.start_date = this.get("startDate").toISOString();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.get("endDate")) {
|
|
|
|
payload.data.end_date = this.get("endDate").toISOString();
|
|
|
|
}
|
|
|
|
|
|
|
|
ajax(this.get("dataSource"), payload)
|
|
|
|
.then((response) => {
|
2018-04-18 15:30:41 -04:00
|
|
|
this._setPropertiesFromModel(response.report);
|
2018-04-16 04:42:06 -04:00
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
this.set("isLoading", false);
|
|
|
|
|
|
|
|
Ember.run.schedule("afterRender", () => {
|
|
|
|
if (!this.get("oneDataPoint")) {
|
2018-04-18 15:30:41 -04:00
|
|
|
this._drawChart();
|
2018-04-16 04:42:06 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2018-04-18 15:30:41 -04:00
|
|
|
_drawChart() {
|
2018-04-16 10:01:29 -04:00
|
|
|
const context = this.$(".chart-canvas")[0].getContext("2d");
|
2018-04-16 04:42:06 -04:00
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
const data = {
|
2018-04-16 04:42:06 -04:00
|
|
|
labels: this.get("chartData").map(r => r.x),
|
|
|
|
datasets: [{
|
|
|
|
data: this.get("chartData").map(r => r.y),
|
|
|
|
backgroundColor: this.get("backgroundColor"),
|
|
|
|
borderColor: this.get("borderColor")
|
|
|
|
}]
|
|
|
|
};
|
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
this._chart = new window.Chart(context, this._buildChartConfig(data));
|
|
|
|
},
|
|
|
|
|
2018-04-18 15:30:41 -04:00
|
|
|
_setPropertiesFromModel(model) {
|
|
|
|
this.setProperties({
|
|
|
|
oneDataPoint: (this.get("startDate") && this.get("endDate")) &&
|
|
|
|
this.get("startDate").isSame(this.get("endDate"), 'day'),
|
|
|
|
total: model.total,
|
|
|
|
title: model.title,
|
|
|
|
trend: this._computeTrend(model.total, model.prev30Days),
|
|
|
|
chartData: model.data
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
_buildChartConfig(data) {
|
2018-04-17 05:01:06 -04:00
|
|
|
const values = this.get("chartData").map(d => d.y);
|
|
|
|
const max = Math.max(...values);
|
|
|
|
const min = Math.min(...values);
|
|
|
|
const stepSize = Math.max(...[Math.ceil((max - min)/5), 20]);
|
|
|
|
|
|
|
|
const startDate = this.get("startDate") || moment();
|
|
|
|
const endDate = this.get("endDate") || moment();
|
|
|
|
const datesDifference = startDate.diff(endDate, "days");
|
|
|
|
let unit = "day";
|
|
|
|
if (datesDifference >= 366) {
|
|
|
|
unit = "quarter";
|
|
|
|
} else if (datesDifference >= 61) {
|
|
|
|
unit = "month";
|
|
|
|
} else if (datesDifference >= 14) {
|
|
|
|
unit = "week";
|
|
|
|
}
|
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
return {
|
2018-04-16 04:42:06 -04:00
|
|
|
type: "line",
|
2018-04-16 10:01:29 -04:00
|
|
|
data,
|
2018-04-16 04:42:06 -04:00
|
|
|
options: {
|
|
|
|
legend: { display: false },
|
|
|
|
responsive: true,
|
2018-04-16 10:01:29 -04:00
|
|
|
layout: { padding: { left: 0, top: 0, right: 0, bottom: 0 } },
|
2018-04-16 04:42:06 -04:00
|
|
|
scales: {
|
2018-04-17 05:01:06 -04:00
|
|
|
yAxes: [
|
|
|
|
{
|
|
|
|
display: true,
|
|
|
|
ticks: { suggestedMin: 0, stepSize, suggestedMax: max + stepSize }
|
|
|
|
}
|
|
|
|
],
|
|
|
|
xAxes: [
|
|
|
|
{
|
|
|
|
display: true,
|
|
|
|
type: "time",
|
|
|
|
time: {
|
|
|
|
parser: "YYYY-MM-DD",
|
|
|
|
unit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
2018-04-16 04:42:06 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
2018-04-16 10:01:29 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_computeTrend(total, prevTotal) {
|
|
|
|
const percentChange = ((total - prevTotal) / prevTotal) * 100;
|
2018-04-16 04:42:06 -04:00
|
|
|
|
2018-04-16 10:01:29 -04:00
|
|
|
if (percentChange > 50) return "double-up";
|
|
|
|
if (percentChange > 0) return "up";
|
|
|
|
if (percentChange === 0) return "stable";
|
|
|
|
if (percentChange < 50) return "double-down";
|
|
|
|
if (percentChange < 0) return "down";
|
|
|
|
},
|
2018-04-16 04:42:06 -04:00
|
|
|
});
|