diff --git a/app/assets/javascripts/admin/components/mini-chart.js.es6 b/app/assets/javascripts/admin/components/mini-chart.js.es6 new file mode 100644 index 00000000000..e55e684c734 --- /dev/null +++ b/app/assets/javascripts/admin/components/mini-chart.js.es6 @@ -0,0 +1,129 @@ +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({ + classNames: ["mini-chart"], + + classNameBindings: ["trend", "oneDataPoint"], + + isLoading: false, + total: null, + trend: null, + title: null, + chartData: null, + oneDataPoint: false, + + backgroundColor: "rgba(200,220,240,0.3)", + borderColor: "#08C", + + + didInsertElement() { + this._super(); + + loadScript("/javascripts/Chart.min.js").then(() => { + this.fetchReport.apply(this); + }); + }, + + didUpdateAttrs() { + this._super(); + + this.fetchReport.apply(this); + }, + + @computed("dataSourceName") + dataSource(dataSourceName) { + return `/admin/reports/${dataSourceName}`; + }, + + @computed("trend") + trendIcon(trend) { + if (trend === "stable") { + return null; + } else { + return `angle-${trend}`; + } + }, + + _computeTrend(total, prevTotal) { + const percentChange = ((total - prevTotal) / prevTotal) * 100; + + 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"; + }, + + fetchReport() { + 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(); + } + + this.set("isLoading", true); + + ajax(this.get("dataSource"), payload) + .then((response) => { + const report = response.report; + + this.setProperties({ + oneDataPoint: (this.get("startDate") && this.get("endDate")) && + this.get("startDate").isSame(this.get("endDate"), 'day'), + total: report.total, + title: report.title, + trend: this._computeTrend(report.total, report.prev30Days), + chartData: report.data + }); + }) + .finally(() => { + this.set("isLoading", false); + + Ember.run.schedule("afterRender", () => { + if (!this.get("oneDataPoint")) { + this.drawChart(); + } + }); + }); + }, + + drawChart() { + const ctx = this.$(".chart-canvas")[0].getContext("2d"); + + let data = { + 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") + }] + }; + + const config = { + type: "line", + data: data, + options: { + legend: { display: false }, + responsive: true, + layout: { + padding: { left: 0, top: 0, right: 0, bottom: 0 } + }, + scales: { + yAxes: [{ + display: true, + ticks: { suggestedMin: 0 } + }], + xAxes: [{ display: true }], + } + }, + }; + + this._chart = new window.Chart(ctx, config); + } +}); diff --git a/app/assets/javascripts/admin/components/mini-table.js.es6 b/app/assets/javascripts/admin/components/mini-table.js.es6 new file mode 100644 index 00000000000..8be07314776 --- /dev/null +++ b/app/assets/javascripts/admin/components/mini-table.js.es6 @@ -0,0 +1,43 @@ +import { ajax } from 'discourse/lib/ajax'; +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + classNames: ["mini-table"], + + total: null, + labels: null, + title: null, + chartData: null, + isLoading: false, + help: null, + helpPage: null, + + didInsertElement() { + this._super(); + + this.fetchReport.apply(this); + }, + + @computed("dataSourceName") + dataSource(dataSourceName) { + return `/admin/reports/${dataSourceName}`; + }, + + fetchReport() { + this.set("isLoading", true); + + ajax(this.get("dataSource")).then((response) => { + const report = response.report; + + this.setProperties({ + labels: report.data.map(r => r.x), + dataset: report.data.map(r => r.y), + total: report.total, + title: report.title, + chartData: report.data + }); + }).finally(() => { + this.set("isLoading", false); + }) + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 new file mode 100644 index 00000000000..2d009fe285b --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 @@ -0,0 +1,48 @@ +import DiscourseURL from 'discourse/lib/url'; +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Controller.extend({ + queryParams: ["period"], + + period: "all", + + @computed("period") + startDate(period) { + if (period === "all") return null; + + switch (period) { + case "yearly": + return moment().subtract(1, "year").startOf("day"); + break; + case "quarterly": + return moment().subtract(3, "month").startOf("day"); + break; + case "weekly": + return moment().subtract(1, "week").startOf("day"); + break; + case "monthly": + return moment().subtract(1, "month").startOf("day"); + break; + case "daily": + return moment().startOf("day"); + break; + } + }, + + @computed("period") + endDate(period) { + if (period === "all") return null; + + return moment().endOf("day"); + }, + + actions: { + changePeriod(period) { + DiscourseURL.routeTo(this._reportsForPeriodURL(period)); + } + }, + + _reportsForPeriodURL(period) { + return `/admin/dashboard_next?period=${period}`; + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-dashboard-next.js.es6 b/app/assets/javascripts/admin/routes/admin-dashboard-next.js.es6 new file mode 100644 index 00000000000..55af882f13f --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-dashboard-next.js.es6 @@ -0,0 +1 @@ +export default Discourse.Route.extend({}); diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 index b4926b9a5a1..1a82a9d1f8d 100644 --- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 @@ -1,6 +1,7 @@ export default function() { this.route('admin', { resetNamespace: true }, function() { this.route('dashboard', { path: '/' }); + this.route('dashboard_next', { path: '/dashboard_next' }); this.route('adminSiteSettings', { path: '/site_settings', resetNamespace: true }, function() { this.route('adminSiteSettingsCategory', { path: 'category/:category_id', resetNamespace: true} ); }); diff --git a/app/assets/javascripts/admin/templates/components/mini-chart.hbs b/app/assets/javascripts/admin/templates/components/mini-chart.hbs new file mode 100644 index 00000000000..5b30980bbdd --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/mini-chart.hbs @@ -0,0 +1,25 @@ +{{#conditional-loading-spinner condition=isLoading}} +
{{label}} | + {{/each}} +
---|
{{data}} | + {{/each}} +