UX: switch dashboard to be the new dashboard
Also: - add pageviews - add problems and version sections
This commit is contained in:
parent
d6316ac4b9
commit
6332d5040d
|
@ -1,7 +1,11 @@
|
|||
import { setting } from 'discourse/lib/computed';
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import AdminDashboardNext from "admin/models/admin-dashboard-next";
|
||||
import Report from "admin/models/report";
|
||||
import VersionCheck from 'admin/models/version-check';
|
||||
|
||||
const PROBLEMS_CHECK_MINUTES = 1;
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
queryParams: ["period"],
|
||||
|
@ -9,10 +13,28 @@ export default Ember.Controller.extend({
|
|||
isLoading: false,
|
||||
dashboardFetchedAt: null,
|
||||
exceptionController: Ember.inject.controller("exception"),
|
||||
showVersionChecks: setting('version_checks'),
|
||||
diskSpace: Ember.computed.alias("model.attributes.disk_space"),
|
||||
|
||||
availablePeriods: ["yearly", "quarterly", "monthly", "weekly"],
|
||||
|
||||
@computed('problems.length')
|
||||
foundProblems(problemsLength) {
|
||||
return this.currentUser.get('admin') && (problemsLength || 0) > 0;
|
||||
},
|
||||
|
||||
|
||||
@computed('foundProblems')
|
||||
thereWereProblems(foundProblems) {
|
||||
if (!this.currentUser.get('admin')) { return false; }
|
||||
|
||||
if (foundProblems) {
|
||||
this.set('hadProblems', true);
|
||||
return true;
|
||||
} else {
|
||||
return this.get('hadProblems') || false;
|
||||
}
|
||||
},
|
||||
|
||||
fetchDashboard() {
|
||||
if (this.get("isLoading")) return;
|
||||
|
@ -20,7 +42,14 @@ export default Ember.Controller.extend({
|
|||
if (!this.get("dashboardFetchedAt") || moment().subtract(30, "minutes").toDate() > this.get("dashboardFetchedAt")) {
|
||||
this.set("isLoading", true);
|
||||
|
||||
const versionChecks = this.siteSettings.version_checks;
|
||||
|
||||
AdminDashboardNext.find().then(adminDashboardNextModel => {
|
||||
|
||||
if (versionChecks) {
|
||||
this.set('versionCheck', VersionCheck.create(adminDashboardNextModel.version_check));
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
dashboardFetchedAt: new Date(),
|
||||
model: adminDashboardNextModel,
|
||||
|
@ -33,6 +62,25 @@ export default Ember.Controller.extend({
|
|||
this.set("isLoading", false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.get('problemsFetchedAt') || moment().subtract(PROBLEMS_CHECK_MINUTES, 'minutes').toDate() > this.get('problemsFetchedAt')) {
|
||||
this.loadProblems();
|
||||
}
|
||||
},
|
||||
|
||||
loadProblems() {
|
||||
this.set('loadingProblems', true);
|
||||
this.set('problemsFetchedAt', new Date());
|
||||
AdminDashboardNext.fetchProblems().then(d => {
|
||||
this.set('problems', d.problems);
|
||||
}).finally(() => {
|
||||
this.set('loadingProblems', false);
|
||||
});
|
||||
},
|
||||
|
||||
@computed('problemsFetchedAt')
|
||||
problemsTimestamp(problemsFetchedAt) {
|
||||
return moment(problemsFetchedAt).format('LLL');
|
||||
},
|
||||
|
||||
@computed("period")
|
||||
|
@ -80,7 +128,10 @@ export default Ember.Controller.extend({
|
|||
actions: {
|
||||
changePeriod(period) {
|
||||
DiscourseURL.routeTo(this._reportsForPeriodURL(period));
|
||||
}
|
||||
},
|
||||
refreshProblems() {
|
||||
this.loadProblems();
|
||||
},
|
||||
},
|
||||
|
||||
_reportsForPeriodURL(period) {
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { setting } from 'discourse/lib/computed';
|
||||
import AdminDashboard from 'admin/models/admin-dashboard';
|
||||
import VersionCheck from 'admin/models/version-check';
|
||||
import Report from 'admin/models/report';
|
||||
import AdminUser from 'admin/models/admin-user';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
const PROBLEMS_CHECK_MINUTES = 1;
|
||||
|
||||
const ATTRIBUTES = [ 'disk_space','admins', 'moderators', 'silenced', 'suspended', 'top_traffic_sources',
|
||||
'top_referred_topics', 'updated_at'];
|
||||
|
@ -18,35 +15,13 @@ export default Ember.Controller.extend({
|
|||
loading: null,
|
||||
versionCheck: null,
|
||||
dashboardFetchedAt: null,
|
||||
showVersionChecks: setting('version_checks'),
|
||||
exceptionController: Ember.inject.controller('exception'),
|
||||
|
||||
@computed('problems.length')
|
||||
foundProblems(problemsLength) {
|
||||
return this.currentUser.get('admin') && (problemsLength || 0) > 0;
|
||||
},
|
||||
|
||||
@computed('foundProblems')
|
||||
thereWereProblems(foundProblems) {
|
||||
if (!this.currentUser.get('admin')) { return false; }
|
||||
|
||||
if (foundProblems) {
|
||||
this.set('hadProblems', true);
|
||||
return true;
|
||||
} else {
|
||||
return this.get('hadProblems') || false;
|
||||
}
|
||||
},
|
||||
|
||||
fetchDashboard() {
|
||||
if (!this.get('dashboardFetchedAt') || moment().subtract(30, 'minutes').toDate() > this.get('dashboardFetchedAt')) {
|
||||
this.set('loading', true);
|
||||
const versionChecks = this.siteSettings.version_checks;
|
||||
AdminDashboard.find().then(d => {
|
||||
this.set('dashboardFetchedAt', new Date());
|
||||
if (versionChecks) {
|
||||
this.set('versionCheck', VersionCheck.create(d.version_check));
|
||||
}
|
||||
|
||||
REPORTS.forEach(name => this.set(name, d[name].map(r => Report.create(r))));
|
||||
|
||||
|
@ -64,26 +39,8 @@ export default Ember.Controller.extend({
|
|||
this.set('loading', false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.get('problemsFetchedAt') || moment().subtract(PROBLEMS_CHECK_MINUTES, 'minutes').toDate() > this.get('problemsFetchedAt')) {
|
||||
this.loadProblems();
|
||||
}
|
||||
},
|
||||
|
||||
loadProblems() {
|
||||
this.set('loadingProblems', true);
|
||||
this.set('problemsFetchedAt', new Date());
|
||||
AdminDashboard.fetchProblems().then(d => {
|
||||
this.set('problems', d.problems);
|
||||
}).finally(() => {
|
||||
this.set('loadingProblems', false);
|
||||
});
|
||||
},
|
||||
|
||||
@computed('problemsFetchedAt')
|
||||
problemsTimestamp(problemsFetchedAt) {
|
||||
return moment(problemsFetchedAt).format('LLL');
|
||||
},
|
||||
|
||||
@computed('updated_at')
|
||||
updatedTimestamp(updatedAt) {
|
||||
|
@ -91,9 +48,6 @@ export default Ember.Controller.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
refreshProblems() {
|
||||
this.loadProblems();
|
||||
},
|
||||
showTrafficReport() {
|
||||
this.set("showTrafficReport", true);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,13 @@ AdminDashboardNext.reopenClass({
|
|||
@return {jqXHR} a jQuery Promise object
|
||||
**/
|
||||
find() {
|
||||
|
||||
return ajax("/admin/dashboard-next.json").then(function(json) {
|
||||
|
||||
var model = AdminDashboardNext.create();
|
||||
|
||||
model.set("reports", json.reports);
|
||||
model.set("version_check", json.version_check);
|
||||
|
||||
const attributes = {};
|
||||
ATTRIBUTES.forEach(a => attributes[a] = json[a]);
|
||||
|
@ -24,6 +27,25 @@ AdminDashboardNext.reopenClass({
|
|||
|
||||
model.set("loaded", true);
|
||||
|
||||
return model;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
Only fetch the list of problems that should be rendered on the dashboard.
|
||||
The model will only have its "problems" attribute set.
|
||||
|
||||
@method fetchProblems
|
||||
@return {jqXHR} a jQuery Promise object
|
||||
**/
|
||||
fetchProblems: function() {
|
||||
return ajax("/admin/dashboard/problems.json", {
|
||||
type: 'GET',
|
||||
dataType: 'json'
|
||||
}).then(function(json) {
|
||||
var model = AdminDashboardNext.create(json);
|
||||
model.set('loaded', true);
|
||||
return model;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,23 +19,6 @@ AdminDashboard.reopenClass({
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
Only fetch the list of problems that should be rendered on the dashboard.
|
||||
The model will only have its "problems" attribute set.
|
||||
|
||||
@method fetchProblems
|
||||
@return {jqXHR} a jQuery Promise object
|
||||
**/
|
||||
fetchProblems: function() {
|
||||
return ajax("/admin/dashboard/problems.json", {
|
||||
type: 'GET',
|
||||
dataType: 'json'
|
||||
}).then(function(json) {
|
||||
var model = AdminDashboard.create(json);
|
||||
model.set('loaded', true);
|
||||
return model;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default AdminDashboard;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export default function() {
|
||||
this.route('admin', { resetNamespace: true }, function() {
|
||||
this.route('dashboard', { path: '/' });
|
||||
this.route('dashboardNext', { path: '/dashboard-next' });
|
||||
this.route('dashboard', { path: '/dashboard-old' });
|
||||
this.route('dashboardNext', { path: '/' });
|
||||
this.route('adminSiteSettings', { path: '/site_settings', resetNamespace: true }, function() {
|
||||
this.route('adminSiteSettingsCategory', { path: 'category/:category_id', resetNamespace: true} );
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="full-width">
|
||||
|
||||
<ul class="nav nav-pills">
|
||||
{{nav-item route='admin.dashboard' label='admin.dashboard.title'}}
|
||||
{{nav-item route='admin.dashboardNext' label='admin.dashboard.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{nav-item route='adminSiteSettings' label='admin.site_settings.title'}}
|
||||
{{/if}}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
{{#if foundProblems}}
|
||||
<div class="dashboard-stats detected-problems">
|
||||
<div class="look-here">{{d-icon "exclamation-triangle"}}</div>
|
||||
<div class="problem-messages">
|
||||
{{#conditional-loading-spinner condition=loadingProblems}}
|
||||
<p>
|
||||
{{i18n 'admin.dashboard.problems_found'}}
|
||||
<ul class="{{if loadingProblems 'invisible'}}">
|
||||
{{#each problems as |problem|}}
|
||||
<li>{{{problem}}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</p>
|
||||
<p class="actions">
|
||||
<small>{{i18n 'admin.dashboard.last_checked'}}: {{problemsTimestamp}}</small>
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
{{/conditional-loading-spinner}}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if thereWereProblems}}
|
||||
<div class="dashboard-stats detected-problems">
|
||||
<div class="look-here"> </div>
|
||||
<div class="problem-messages">
|
||||
<p>
|
||||
{{i18n 'admin.dashboard.no_problems'}}
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
|
@ -1,11 +1,5 @@
|
|||
{{plugin-outlet name="admin-dashboard-top"}}
|
||||
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
<div class="dashboard-left">
|
||||
{{#if showVersionChecks}}
|
||||
{{partial 'admin/templates/version-checks'}}
|
||||
{{/if}}
|
||||
|
||||
<div class="dashboard-stats trust-levels">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
|
@ -174,42 +168,6 @@
|
|||
</div>
|
||||
|
||||
<div class="dashboard-right">
|
||||
{{#if foundProblems}}
|
||||
<div class="dashboard-stats detected-problems">
|
||||
<div class="look-here">{{d-icon "exclamation-triangle"}}</div>
|
||||
<div class="problem-messages">
|
||||
{{#conditional-loading-spinner condition=loadingProblems}}
|
||||
<p>
|
||||
{{i18n 'admin.dashboard.problems_found'}}
|
||||
<ul class="{{if loadingProblems 'invisible'}}">
|
||||
{{#each problems as |problem|}}
|
||||
<li>{{{problem}}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</p>
|
||||
<p class="actions">
|
||||
<small>{{i18n 'admin.dashboard.last_checked'}}: {{problemsTimestamp}}</small>
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
{{/conditional-loading-spinner}}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if thereWereProblems}}
|
||||
<div class="dashboard-stats detected-problems">
|
||||
<div class="look-here"> </div>
|
||||
<div class="problem-messages">
|
||||
<p>
|
||||
{{i18n 'admin.dashboard.no_problems'}}
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<div class="dashboard-stats">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
{{plugin-outlet name="admin-dashboard-top"}}
|
||||
{{plugin-outlet name="admin-dashboard-top"}}
|
||||
|
||||
<div class="section-top">
|
||||
{{#if showVersionChecks}}
|
||||
<div class="dashboard-left">
|
||||
{{partial 'admin/templates/version-checks'}}
|
||||
</div>
|
||||
<div class="dashboard-right">
|
||||
{{partial 'admin/templates/dashboard-problems'}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
|
||||
<div class="community-health section">
|
||||
<div class="section-title">
|
||||
|
@ -105,6 +117,12 @@
|
|||
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
{{i18n 'admin.dashboard.find_old'}} {{#link-to 'admin.dashboard'}}{{i18n "admin.dashboard.old_link"}}{{/link-to}}
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p class="last-dashboard-update">
|
||||
{{i18n "admin.dashboard.last_updated"}} {{updatedTimestamp}}
|
||||
</p>
|
||||
|
|
|
@ -3,7 +3,6 @@ class Admin::DashboardController < Admin::AdminController
|
|||
def index
|
||||
dashboard_data = AdminDashboardData.fetch_cached_stats || Jobs::DashboardStats.new.execute({})
|
||||
dashboard_data.merge!(version_check: DiscourseUpdates.check_version.as_json) if SiteSetting.version_checks?
|
||||
|
||||
dashboard_data[:disk_space] = DiskSpace.cached_stats
|
||||
render json: dashboard_data
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ require 'disk_space'
|
|||
class Admin::DashboardNextController < Admin::AdminController
|
||||
def index
|
||||
dashboard_data = AdminDashboardNextData.fetch_cached_stats
|
||||
dashboard_data.merge!(version_check: DiscourseUpdates.check_version.as_json) if SiteSetting.version_checks?
|
||||
dashboard_data[:disk_space] = DiskSpace.cached_stats
|
||||
render json: dashboard_data
|
||||
end
|
||||
|
|
|
@ -15,8 +15,8 @@ module Jobs
|
|||
end
|
||||
|
||||
# TODO: decide if we want to keep caching this every 30 minutes
|
||||
AdminDashboardData.refresh_stats
|
||||
AdminDashboardNextData.refresh_stats
|
||||
AdminDashboardData.refresh_stats
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class AdminDashboardNextData
|
||||
include StatsCacheable
|
||||
|
||||
REPORTS = [ "visits", "posts", "time_to_first_response", "likes", "flags" ]
|
||||
REPORTS = ["page_view_total_reqs", "visits", "posts", "time_to_first_response", "likes", "flags" ]
|
||||
|
||||
def initialize(opts = {})
|
||||
@opts = opts
|
||||
|
|
|
@ -2713,6 +2713,8 @@ en:
|
|||
dashboard:
|
||||
title: "Dashboard"
|
||||
last_updated: "Dashboard last updated:"
|
||||
find_old: "Looking for the old dashboard?"
|
||||
old_link: "visit it here"
|
||||
version: "Version"
|
||||
up_to_date: "You're up to date!"
|
||||
critical_available: "A critical update is available."
|
||||
|
|
|
@ -972,7 +972,7 @@ en:
|
|||
xaxis: "Day"
|
||||
yaxis: "Web Crawler Pageviews"
|
||||
page_view_total_reqs:
|
||||
title: "Total"
|
||||
title: "Pageviews"
|
||||
xaxis: "Day"
|
||||
yaxis: "Total Pageviews"
|
||||
page_view_logged_in_mobile_reqs:
|
||||
|
|
Loading…
Reference in New Issue