UX: refactoring/refining tables of new dashboard

This commit is contained in:
Joffrey JAFFEUX 2018-05-22 16:47:23 +02:00 committed by GitHub
parent 7285e7fbba
commit 508b65b76a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 184 additions and 126 deletions

View File

@ -1,32 +1,13 @@
import { ajax } from "discourse/lib/ajax";
import Report from "admin/models/report";
import AsyncReport from "admin/mixins/async-report";
export default Ember.Component.extend(AsyncReport, {
classNames: ["dashboard-table", "dashboard-inline-table", "fixed"],
help: null,
helpPage: null,
loadReport(report_json) {
return Report.create(report_json);
},
classNames: ["dashboard-inline-table"],
fetchReport() {
this._super();
let payload = { data: { cache: true, facets: ["total", "prev30Days"] } };
if (this.get("startDate")) {
payload.data.start_date = this.get("startDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ");
}
if (this.get("endDate")) {
payload.data.end_date = this.get("endDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ");
}
if (this.get("limit")) {
payload.data.limit = this.get("limit");
}
let payload = this.buildPayload(["total", "prev30Days"]);
return Ember.RSVP.Promise.all(this.get("dataSources").map(dataSource => {
return ajax(dataSource, payload)

View File

@ -52,17 +52,7 @@ export default Ember.Component.extend(AsyncReport, {
fetchReport() {
this._super();
let payload = {
data: { cache: true, facets: ["prev_period"] }
};
if (this.get("startDate")) {
payload.data.start_date = this.get("startDate").locale('en').format('YYYY-MM-DD[T]HH:mm:ss.SSSZZ');
}
if (this.get("endDate")) {
payload.data.end_date = this.get("endDate").locale('en').format('YYYY-MM-DD[T]HH:mm:ss.SSSZZ');
}
let payload = this.buildPayload(["prev_period"]);
if (this._chart) {
this._chart.destroy();

View File

@ -0,0 +1,19 @@
import { ajax } from "discourse/lib/ajax";
import AsyncReport from "admin/mixins/async-report";
export default Ember.Component.extend(AsyncReport, {
classNames: ["dashboard-table"],
fetchReport() {
this._super();
let payload = this.buildPayload(["total", "prev30Days"]);
return Ember.RSVP.Promise.all(this.get("dataSources").map(dataSource => {
return ajax(dataSource, payload)
.then(response => {
this.get("reports").pushObject(this.loadReport(response.report));
});
}));
}
});

View File

@ -1,4 +1,5 @@
import computed from "ember-addons/ember-computed-decorators";
import Report from "admin/models/report";
export default Ember.Mixin.create({
classNameBindings: ["isLoading", "dataSourceNames"],
@ -17,6 +18,24 @@ export default Ember.Mixin.create({
return dataSourceNames.split(",").map(source => `/admin/reports/${source}`);
},
buildPayload(facets) {
let payload = { data: { cache: true, facets } };
if (this.get("startDate")) {
payload.data.start_date = this.get("startDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ");
}
if (this.get("endDate")) {
payload.data.end_date = this.get("endDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ");
}
if (this.get("limit")) {
payload.data.limit = this.get("limit");
}
return payload;
},
@computed("reports.[]", "startDate", "endDate", "dataSourceNames")
reportsForPeriod(reports, startDate, endDate, dataSourceNames) {
// on a slow network fetchReport could be called multiple times between
@ -69,7 +88,9 @@ export default Ember.Mixin.create({
this.set("isLoading", false);
},
loadReport() {},
loadReport(jsonReport) {
return Report.create(jsonReport);
},
fetchReport() {
this.set("reports", []);

View File

@ -1,40 +1,31 @@
{{#conditional-loading-section isLoading=isLoading}}
<div class="table-title">
<h3>{{title}}</h3>
{{#if help}}
<a href="{{helpPage}}">{{i18n help}}</a>
{{/if}}
</div>
{{#each reportsForPeriod as |report|}}
<div class="table-container">
<table>
<thead>
<tr>
{{#if report.labels}}
{{#each report.labels as |label|}}
<th>{{label}}</th>
{{/each}}
{{else}}
{{#each report.data as |data|}}
<th>{{data.x}}</th>
{{/each}}
{{/if}}
</tr>
</thead>
<tbody>
{{#unless hasBlock}}
{{#each report.data as |data|}}
<tr>
<td>{{number data.y}}</td>
</tr>
{{/each}}
{{else}}
{{yield (hash report=report)}}
{{/unless}}
</tbody>
</table>
{{#unless hasBlock}}
{{#each report.data as |data|}}
<div class="table-cell">
<span class="label">
{{#if data.icon}}
{{d-icon data.icon}}
{{/if}}
{{data.x}}:
</span>
<span class="value">
{{#if data.url}}
<a href="{{data.url}}">{{number data.y}}</a>
{{else}}
{{number data.y}}
{{/if}}
</span>
</div>
{{/each}}
{{else}}
{{yield (hash report=report)}}
{{/unless}}
</div>
{{/each}}
{{/conditional-loading-section}}

View File

@ -0,0 +1,36 @@
{{#conditional-loading-section isLoading=isLoading}}
<div class="table-title">
<h3>{{title}}</h3>
</div>
{{#each reportsForPeriod as |report|}}
<div class="table-container">
<table>
<thead>
<tr>
{{#if report.labels}}
{{#each report.labels as |label|}}
<th>{{label}}</th>
{{/each}}
{{else}}
{{#each report.data as |data|}}
<th>{{data.x}}</th>
{{/each}}
{{/if}}
</tr>
</thead>
<tbody>
{{#unless hasBlock}}
{{#each report.data as |data|}}
<tr>
<td>{{number data.y}}</td>
</tr>
{{/each}}
{{else}}
{{yield (hash report=report)}}
{{/unless}}
</tbody>
</table>
</div>
{{/each}}
{{/conditional-loading-section}}

View File

@ -80,17 +80,9 @@
{{/conditional-loading-section}}
</div>
{{#dashboard-inline-table dataSourceNames="users_by_type,users_by_trust_level" lastRefreshedAt=lastRefreshedAt as |context|}}
<tr>
{{#each context.report.data as |data|}}
<td>
<a href="/admin/users/list/{{data.key}}">
{{number data.y}}
</a>
</td>
{{/each}}
</tr>
{{/dashboard-inline-table}}
{{dashboard-inline-table dataSourceNames="users_by_type" lastRefreshedAt=lastRefreshedAt}}
{{dashboard-inline-table dataSourceNames="users_by_trust_level" lastRefreshedAt=lastRefreshedAt}}
{{#conditional-loading-section isLoading=isLoading title=(i18n "admin.dashboard.backups")}}
<div class="misc">
@ -116,7 +108,6 @@
</div>
</div>
<div class="last-dashboard-update">
<div>
<h4>{{i18n "admin.dashboard.last_updated"}} </h4>
@ -128,58 +119,57 @@
</div>
</div>
<p>
{{i18n 'admin.dashboard.find_old'}} {{#link-to 'admin.dashboard'}}{{i18n "admin.dashboard.old_link"}}{{/link-to}}
</p>
<p>
{{i18n 'admin.dashboard.find_old'}} {{#link-to 'admin.dashboard'}}{{i18n "admin.dashboard.old_link"}}{{/link-to}}
</p>
{{/conditional-loading-section}}
</div>
<div class="section-column">
<div class="top-referred-topics">
{{#dashboard-inline-table
dataSourceNames="top_referred_topics"
lastRefreshedAt=lastRefreshedAt
limit=8
as |context|}}
{{#each context.report.data as |data|}}
<tr>
<td class='left'>
<a href="{{data.topic_url}}">
{{data.topic_title}}
</a>
</td>
<td>
{{data.num_clicks}}
</td>
</tr>
{{/each}}
{{/dashboard-inline-table}}
{{#dashboard-table
dataSourceNames="top_referred_topics"
lastRefreshedAt=lastRefreshedAt
limit=8
as |context|}}
{{#each context.report.data as |data|}}
<tr>
<td class='left'>
<a href="{{data.topic_url}}">
{{data.topic_title}}
</a>
</td>
<td>
{{data.num_clicks}}
</td>
</tr>
{{/each}}
{{/dashboard-table}}
</div>
<div class="trending-search">
{{#dashboard-inline-table
limit=8
dataSourceNames="trending_search"
isEnabled=logSearchQueriesEnabled
disabledLabel="admin.dashboard.reports.trending_search.disabled"
startDate=lastWeek
endDate=endDate as |context|}}
{{#each context.report.data as |data|}}
<tr>
<td class='left'>
{{data.term}}
</td>
<td>
{{number data.unique_searches}}
</td>
<td>
{{data.ctr}}
</td>
</tr>
{{/each}}
{{/dashboard-inline-table}}
{{#dashboard-table
limit=8
dataSourceNames="trending_search"
isEnabled=logSearchQueriesEnabled
disabledLabel="admin.dashboard.reports.trending_search.disabled"
startDate=lastWeek
endDate=endDate as |context|}}
{{#each context.report.data as |data|}}
<tr>
<td class='left'>
{{data.term}}
</td>
<td>
{{number data.unique_searches}}
</td>
<td>
{{data.ctr}}
</td>
</tr>
{{/each}}
{{/dashboard-table}}
{{{i18n "admin.dashboard.reports.trending_search.more"}}}
</div>
</div>
</div>
</div>

View File

@ -370,6 +370,32 @@
}
}
.dashboard-inline-table {
margin-bottom: 1em;
.table-title {
border-bottom: 1px solid $primary-low;
margin-bottom: 1em;
padding-bottom: .5em;
}
.table-container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.table-cell {
margin-right: .5em;
display: flex;
.label {
font-weight: 700;
margin-right: .5em;
}
}
}
.dashboard-table.activity-metrics {
table {
@media screen and (min-width: 400px) {
@ -381,7 +407,7 @@
.d-icon {
color: $primary-low-mid;
min-width: 14px;
text-align: center;
text-align: center;
}
@media screen and (max-width: 400px) {
.d-icon { display: none; }

View File

@ -341,8 +341,11 @@ class Report
def self.report_users_by_trust_level(report)
report.data = []
User.real.group('trust_level').count.sort.each do |level, count|
report.data << { key: TrustLevel.levels[level.to_i], x: level.to_i, y: count }
key = TrustLevel.levels[level.to_i]
url = Proc.new { |key| "/admin/users/list/#{key}" }
report.data << { url: url.call(key), key: key, x: level.to_i, y: count }
end
end
@ -416,19 +419,20 @@ class Report
def self.report_users_by_type(report)
report.data = []
label = Proc.new { |key| I18n.t("reports.users_by_type.xaxis_labels.#{key}") }
label = Proc.new { |x| I18n.t("reports.users_by_type.xaxis_labels.#{x}") }
url = Proc.new { |key| "/admin/users/list/#{key}" }
admins = User.real.admins.count
report.data << { key: "admins", x: label.call("admin"), y: admins } if admins > 0
report.data << { url: url.call("admins"), icon: "shield", key: "admins", x: label.call("admin"), y: admins } if admins > 0
moderators = User.real.moderators.count
report.data << { key: "moderators", x: label.call("moderator"), y: moderators } if moderators > 0
report.data << { url: url.call("moderators"), icon: "shield", key: "moderators", x: label.call("moderator"), y: moderators } if moderators > 0
suspended = User.real.suspended.count
report.data << { key: "suspended", x: label.call("suspended"), y: suspended } if suspended > 0
report.data << { url: url.call("suspended"), icon: "ban", key: "suspended", x: label.call("suspended"), y: suspended } if suspended > 0
silenced = User.real.silenced.count
report.data << { key: "silenced", x: label.call("silenced"), y: silenced } if silenced > 0
report.data << { url: url.call("silenced"), icon: "ban", key: "silenced", x: label.call("silenced"), y: silenced } if silenced > 0
end
def self.report_top_referred_topics(report)