FIX: improves reports resilience (#6239)

This commit makes most of the reports now lazy loaded, and making them benefits from graceful failures.
This commit is contained in:
Joffrey JAFFEUX 2018-08-06 16:57:40 -04:00 committed by GitHub
parent ffc8c52bf5
commit 7f2f3b8b22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 246 additions and 163 deletions

View File

@ -0,0 +1,3 @@
export default Ember.Component.extend({
classNames: ["admin-report-counters"]
});

View File

@ -4,18 +4,11 @@ import AdminDashboardNext from "admin/models/admin-dashboard-next";
import Report from "admin/models/report";
import PeriodComputationMixin from "admin/mixins/period-computation";
const ACTIVITY_METRICS_REPORTS = [
"page_view_total_reqs",
"visits",
"time_to_first_response",
"likes",
"flags",
"user_to_user_private_messages_with_replies"
];
function staticReport(reportType) {
return function() {
return this.get("reports").find(x => x.type === reportType);
return Ember.makeArray(this.get("reports")).find(
report => report.type === reportType
);
}.property("reports.[]");
}
@ -35,6 +28,18 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
return { table: { total: false, limit: 8 } };
},
@computed
activityMetrics() {
return [
"page_view_total_reqs",
"visits",
"time_to_first_response",
"likes",
"flags",
"user_to_user_private_messages_with_replies"
];
},
@computed
trendingSearchOptions() {
return { table: { total: false, limit: 8 } };
@ -43,13 +48,6 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
usersByTypeReport: staticReport("users_by_type"),
usersByTrustLevelReport: staticReport("users_by_trust_level"),
@computed("reports.[]")
activityMetricsReports(reports) {
return reports.filter(report =>
ACTIVITY_METRICS_REPORTS.includes(report.type)
);
},
fetchDashboard() {
if (this.get("isLoading")) return;

View File

@ -0,0 +1,20 @@
<div class="cell title">
{{#if model.icon}}
{{d-icon model.icon}}
{{/if}}
<a href="{{model.reportUrl}}">{{model.title}}</a>
</div>
<div class="cell value today-count">{{number model.todayCount}}</div>
<div class="cell value yesterday-count {{model.yesterdayTrend}}" title={{model.yesterdayCountTitle}}>
{{number model.yesterdayCount}} {{d-icon model.yesterdayTrendIcon}}
</div>
<div class="cell value sevendays-count {{model.sevenDaysTrend}}" title={{model.sevenDaysCountTitle}}>
{{number model.lastSevenDaysCount}} {{d-icon model.sevenDaysTrendIcon}}
</div>
<div class="cell value thirty-days-count {{model.thirtyDaysTrend}}" title={{model.thirtyDaysCountTitle}}>
{{number model.lastThirtyDaysCount}} {{d-icon model.thirtyDaysTrendIcon}}
</div>

View File

@ -68,7 +68,7 @@
{{else}}
<div class="alert alert-info no-data">
{{d-icon "pie-chart"}}
<span>{{i18n 'admin.dashboard.reports.no_data'}}</span>
<span>{{i18n "admin.dashboard.reports.no_data"}}</span>
</div>
{{/if}}
{{else}}

View File

@ -57,61 +57,50 @@
<div class="section-columns">
<div class="section-column">
<div class="admin-report activity-metrics">
{{#conditional-loading-section isLoading=isLoading title=(i18n "admin.dashboard.activity_metrics")}}
<div class="report-header">
<div class="report-title">
<h3 class="title">
{{#link-to "adminReports" class="report-link"}}
{{i18n "admin.dashboard.activity_metrics"}}
{{/link-to}}
</h3>
</div>
<div class="report-header">
<div class="report-title">
<h3 class="title">
{{#link-to "adminReports" class="report-link"}}
{{i18n "admin.dashboard.activity_metrics"}}
{{/link-to}}
</h3>
</div>
</div>
<div class="report-body">
<div class="admin-report-counters-list">
<div class="counters-header">
<div class="header"></div>
<div class="header">{{i18n 'admin.dashboard.reports.today'}}</div>
<div class="header">{{i18n 'admin.dashboard.reports.yesterday'}}</div>
<div class="header">{{i18n 'admin.dashboard.reports.last_7_days'}}</div>
<div class="header">{{i18n 'admin.dashboard.reports.last_30_days'}}</div>
</div>
<div class="report-body">
<div class="admin-report-table">
<table class="report-table">
<thead>
<tr>
<th class="admin-report-table-header"></th>
<th class="admin-report-table-header">
{{i18n 'admin.dashboard.reports.today'}}
</th>
<th class="admin-report-table-header">
{{i18n 'admin.dashboard.reports.yesterday'}}
</th>
<th class="admin-report-table-header">
{{i18n 'admin.dashboard.reports.last_7_days'}}
</th>
<th class="admin-report-table-header">
{{i18n 'admin.dashboard.reports.last_30_days'}}
</th>
</tr>
</thead>
<tbody>
{{#each activityMetricsReports as |report|}}
{{admin-report-counts report=report allTime=false class="admin-report-table-row"}}
{{/each}}
</tbody>
</table>
</div>
{{#each activityMetrics as |metric|}}
{{admin-report
showHeader=false
forcedModes="counters"
dataSourceName=metric}}
{{/each}}
</div>
{{/conditional-loading-section}}
</div>
</div>
{{#link-to "adminReports"}}
{{i18n "admin.dashboard.all_reports"}}
{{/link-to}}
<div class="user-metrics">
{{admin-report
forcedModes="inline-table"
report=usersByTypeReport
lastRefreshedAt=lastRefreshedAt}}
{{#conditional-loading-section isLoading=isLoading}}
{{admin-report
forcedModes="inline-table"
report=usersByTypeReport
lastRefreshedAt=lastRefreshedAt}}
{{admin-report
forcedModes="inline-table"
report=usersByTrustLevelReport
lastRefreshedAt=lastRefreshedAt}}
{{admin-report
forcedModes="inline-table"
report=usersByTrustLevelReport
lastRefreshedAt=lastRefreshedAt}}
{{/conditional-loading-section}}
</div>
{{#conditional-loading-section isLoading=isLoading title=(i18n "admin.dashboard.backups")}}

View File

@ -951,6 +951,7 @@ table#user-badges {
@import "common/admin/plugins";
@import "common/admin/admin_reports";
@import "common/admin/admin_report";
@import "common/admin/admin_report_counters";
@import "common/admin/admin_report_chart";
@import "common/admin/admin_report_table";
@import "common/admin/admin_report_inline_table";

View File

@ -27,9 +27,9 @@
}
}
.conditional-loading-section.is-loading {
.conditional-loading-section {
flex: 1;
margin: 0.5em 0;
margin: 0;
}
.report-header {

View File

@ -0,0 +1,122 @@
.admin-report-counters-list {
display: flex;
flex: 1;
flex-direction: column;
.counters-header {
display: grid;
flex: 1;
grid-template-columns: 33% repeat(auto-fit, minmax(20px, 1fr));
border: 1px solid $primary-low;
border-bottom: 0;
padding: 0.25em;
font-weight: 700;
text-align: right;
}
.conditional-loading-section.is-loading {
padding: 0.5em;
margin: 0;
flex-direction: row;
justify-content: flex-start;
.title {
font-weight: normal;
font-size: $font-down-1;
}
.spinner {
margin: 0 0 0 0.5em;
height: 5px;
width: 5px;
}
}
}
.admin-report.counters {
&:last-child .admin-report-counters {
border-bottom: 1px solid $primary-low;
}
.admin-report-counters {
display: grid;
flex: 1;
grid-template-columns: 33% repeat(auto-fit, minmax(20px, 1fr));
grid-template-rows: repeat(auto-fit, minmax(32px, 1fr));
border: 1px solid $primary-low;
align-items: center;
border-bottom: 0;
.cell {
padding: 0.25em;
text-align: right;
white-space: nowrap;
padding: 8px 21px 8px 8px; // accounting for negative right caret margin
&:nth-of-type(2) {
padding: 8px 12px 8px;
}
i {
margin-right: -12px; // align on caret
@media screen and (max-width: 650px) {
margin-right: -9px;
}
}
&.title {
text-align: left;
padding: 8px;
.d-icon {
color: $primary-low-mid;
min-width: 14px;
text-align: center;
}
i {
margin: 0;
}
}
@media screen and (max-width: 400px) {
&.title {
padding: 8px 0 8px 4px;
font-size: $font-down-1;
.d-icon {
display: none;
}
}
}
&.high-trending-up,
&.trending-up {
i {
color: $success;
}
}
&.high-trending-down,
&.trending-down {
i {
color: $danger;
}
}
}
}
.no-data {
margin: 0;
padding: 8px;
display: flex;
flex-direction: row;
align-items: center;
font-size: $font-0;
border: 0;
background: $primary-low;
color: $primary-medium;
.d-icon {
font-size: $font-up-1;
margin: 0 0.25em 0 0;
color: $primary-low-mid;
}
}
}

View File

@ -262,6 +262,10 @@
}
}
.activity-metrics {
margin-bottom: 1em;
}
.user-metrics {
display: flex;
flex-wrap: wrap;
@ -330,85 +334,6 @@
}
}
.admin-report.activity-metrics {
.report-table {
@media screen and (min-width: 400px) {
table-layout: auto;
}
tr th {
text-align: right;
}
.d-icon {
color: $primary-low-mid;
min-width: 14px;
text-align: center;
}
@media screen and (max-width: 400px) {
.d-icon {
display: none;
}
td.title {
padding: 8px 0 8px 4px;
}
}
tr {
td {
text-overflow: unset;
overflow: auto;
white-space: normal;
}
td:first-child {
text-overflow: ellipsis;
overflow: hidden;
white-space: normal;
}
}
td {
text-align: center;
padding: 8px;
}
td.left {
text-align: left;
}
td.title {
text-align: left;
}
td.value {
text-align: right;
white-space: nowrap;
padding: 8px 21px 8px 8px; // accounting for negative right caret margin
&:nth-of-type(2) {
padding: 8px 12px 8px;
}
i {
margin-right: -12px; // align on caret
@media screen and (max-width: 650px) {
margin-right: -9px;
}
}
&.high-trending-up,
&.trending-up {
i {
color: $success;
}
}
&.high-trending-down,
&.trending-down {
i {
color: $danger;
}
}
}
}
}
.rtl .dashboard-next {
.section-column {
&:last-child {
@ -422,17 +347,6 @@
}
}
.dashboard-table table tbody tr {
td.title {
text-align: right;
}
td.value i {
margin-right: 0;
margin-left: -12px;
}
}
.user-metrics .table-cell {
margin: 0 0 5px 10px;
}

View File

@ -11,8 +11,7 @@ class Admin::DashboardNextController < Admin::AdminController
render json: data
end
def moderation
end
def moderation; end
def general
data = AdminDashboardNextGeneralData.fetch_cached_stats

View File

@ -1,12 +1,6 @@
class AdminDashboardNextGeneralData < AdminDashboardNextData
def reports
@reports ||= %w{
page_view_total_reqs
visits
time_to_first_response
likes
flags
user_to_user_private_messages_with_replies
users_by_type
users_by_trust_level
}

View File

@ -107,6 +107,7 @@ class Report
group_filtering: self.group_filtering,
modes: self.modes,
}.tap do |json|
json[:icon] = self.icon if self.icon
json[:error] = self.error if self.error
json[:total] = self.total if self.total
json[:prev_period] = self.prev_period if self.prev_period

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/flags": {
report: {
report_key: "flags"
}
}
};

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/likes": {
report: {
report_key: "likes"
}
}
};

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/page_view_total_reqs": {
report: {
report_key: "page_view_total_reqs"
}
}
};

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/time_to_first_response": {
report: {
report_key: "time_to_first_response"
}
}
};

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/user_to_user_private_messages_with_replies": {
report: {
report_key: "user_to_user_private_messages_with_replies"
}
}
};

View File

@ -0,0 +1,7 @@
export default {
"/admin/reports/visits": {
report: {
report_key: "posts"
}
}
};