FIX: quality/bugfix dashboard/reports pass (#6283)

This commit is contained in:
Joffrey JAFFEUX 2018-08-17 16:19:25 +02:00 committed by GitHub
parent 010fe479cb
commit 37d4f27c44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 733 additions and 660 deletions

View File

@ -1,5 +1,4 @@
import computed from "ember-addons/ember-computed-decorators";
import { registerTooltip, unregisterTooltip } from "discourse/lib/tooltip";
const PAGES_LIMIT = 8;
@ -11,19 +10,6 @@ export default Ember.Component.extend({
perPage: Ember.computed.alias("options.perPage"),
page: 0,
didRender() {
this._super(...arguments);
unregisterTooltip($(".text[data-tooltip]"));
registerTooltip($(".text[data-tooltip]"));
},
willDestroyElement() {
this._super(...arguments);
unregisterTooltip($(".text[data-tooltip]"));
},
@computed("model.computedLabels.length")
twoColumns(labelsLength) {
return labelsLength === 2;
@ -52,7 +38,12 @@ export default Ember.Component.extend({
@computed("totalsForSampleRow", "model.computedLabels")
totalsForSample(row, labels) {
return labels.map(label => label.compute(row));
return labels.map(label => {
const computedLabel = label.compute(row);
computedLabel.type = label.type;
computedLabel.property = label.mainProperty;
return computedLabel;
});
},
@computed("model.data", "model.computedLabels")
@ -119,7 +110,7 @@ export default Ember.Component.extend({
return {
page: v + 1,
index: v,
class: v === page ? "current" : null
class: v === page ? "is-current" : null
};
});

View File

@ -4,7 +4,10 @@ import { outputExportResult } from "discourse/lib/export-result";
import { ajax } from "discourse/lib/ajax";
import { SCHEMA_VERSION, default as Report } from "admin/models/report";
import computed from "ember-addons/ember-computed-decorators";
import { registerTooltip, unregisterTooltip } from "discourse/lib/tooltip";
import {
registerHoverTooltip,
unregisterHoverTooltip
} from "discourse/lib/tooltip";
const TABLE_OPTIONS = {
perPage: 8,
@ -35,12 +38,7 @@ function collapseWeekly(data, average) {
}
export default Ember.Component.extend({
classNameBindings: [
"isEnabled",
"isLoading",
"dasherizedDataSourceName",
"currentMode"
],
classNameBindings: ["isEnabled", "isLoading", "dasherizedDataSourceName"],
classNames: ["admin-report"],
isEnabled: true,
disabledLabel: "admin.dashboard.disabled",
@ -69,6 +67,7 @@ export default Ember.Component.extend({
"showDatesOptions",
"showGroupOptions"
),
shouldDisplayTrend: Ember.computed.and("showTrend", "model.prev_period"),
init() {
this._super(...arguments);
@ -80,6 +79,7 @@ export default Ember.Component.extend({
this._super(...arguments);
const state = this.get("filters") || {};
this.setProperties({
category: Category.findById(state.categoryId),
groupId: state.groupId,
@ -101,14 +101,13 @@ export default Ember.Component.extend({
didRender() {
this._super(...arguments);
unregisterTooltip($(".info[data-tooltip]"));
registerTooltip($(".info[data-tooltip]"));
registerHoverTooltip($(".info[data-tooltip]"));
},
willDestroyElement() {
this._super(...arguments);
unregisterTooltip($(".info[data-tooltip]"));
unregisterHoverTooltip($(".info[data-tooltip]"));
},
showError: Ember.computed.or("showTimeoutError", "showExceptionError"),
@ -140,8 +139,8 @@ export default Ember.Component.extend({
const modes = forcedModes ? forcedModes.split(",") : reportModes;
return Ember.makeArray(modes).map(mode => {
const base = `mode-button ${mode}`;
const cssClass = currentMode === mode ? `${base} current` : base;
const base = `mode-btn ${mode}`;
const cssClass = currentMode === mode ? `${base} is-current` : base;
return {
mode,
@ -157,7 +156,7 @@ export default Ember.Component.extend({
{ name: I18n.t("admin.dashboard.reports.groups"), value: "all" }
];
return arr.concat(
this.site.groups.map(i => {
(this.site.groups || []).map(i => {
return { name: i["name"], value: i["id"] };
})
);
@ -171,15 +170,25 @@ export default Ember.Component.extend({
@computed("startDate")
normalizedStartDate(startDate) {
return startDate && typeof startDate.isValid === "function"
? startDate.format("YYYYMMDD")
: startDate;
? moment
.utc(startDate.toISOString())
.locale("en")
.format("YYYYMMDD")
: moment(startDate)
.locale("en")
.format("YYYYMMDD");
},
@computed("endDate")
normalizedEndDate(endDate) {
return endDate && typeof endDate.isValid === "function"
? endDate.format("YYYYMMDD")
: endDate;
? moment
.utc(endDate.toISOString())
.locale("en")
.format("YYYYMMDD")
: moment(endDate)
.locale("en")
.format("YYYYMMDD");
},
@computed(
@ -317,16 +326,15 @@ export default Ember.Component.extend({
let payload = { data: { cache: true, facets } };
if (this.get("startDate")) {
payload.data.start_date = moment(
this.get("startDate"),
"YYYY-MM-DD"
).format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ");
payload.data.start_date = moment
.utc(this.get("startDate"), "YYYY-MM-DD")
.toISOString();
}
if (this.get("endDate")) {
payload.data.end_date = moment(this.get("endDate"), "YYYY-MM-DD").format(
"YYYY-MM-DD[T]HH:mm:ss.SSSZZ"
);
payload.data.end_date = moment
.utc(this.get("endDate"), "YYYY-MM-DD")
.toISOString();
}
if (this.get("groupId") && this.get("groupId") !== "all") {

View File

@ -285,7 +285,7 @@ const Report = Discourse.Model.extend({
value,
type,
property: mainProperty,
formatedValue: value ? escapeExpression(value) : "-"
formatedValue: value ? escapeExpression(value) : ""
};
}
};
@ -318,7 +318,7 @@ const Report = Discourse.Model.extend({
return {
value: username,
formatedValue: username ? formatedValue(username) : "-"
formatedValue: username ? formatedValue(username) : ""
};
},
@ -333,7 +333,7 @@ const Report = Discourse.Model.extend({
return {
value: topicTitle,
formatedValue: topicTitle ? formatedValue() : "-"
formatedValue: topicTitle ? formatedValue() : ""
};
},
@ -360,7 +360,7 @@ const Report = Discourse.Model.extend({
_percentLabel(value) {
return {
value,
formatedValue: value ? `${value}%` : "-"
formatedValue: value ? `${value}%` : ""
};
},
@ -373,14 +373,14 @@ const Report = Discourse.Model.extend({
return {
value,
formatedValue: value ? formatedValue() : "-"
formatedValue: value ? formatedValue() : ""
};
},
_dateLabel(value, date) {
return {
value,
formatedValue: value ? date.format("LL") : "-"
formatedValue: value ? date.format("LL") : ""
};
},
@ -389,7 +389,7 @@ const Report = Discourse.Model.extend({
return {
value,
formatedValue: value ? escaped : "-"
formatedValue: value ? escaped : ""
};
},
@ -404,7 +404,7 @@ const Report = Discourse.Model.extend({
return {
value,
formatedValue: value ? formatedValue(value, row[properties[1]]) : "-"
formatedValue: value ? formatedValue(value, row[properties[1]]) : ""
};
},

View File

@ -5,14 +5,23 @@ export default Discourse.Route.extend({
if (!controller.get("start_date")) {
controller.set(
"start_date",
moment()
.subtract("30", "day")
moment
.utc()
.subtract(1, "day")
.subtract(1, "month")
.startOf("day")
.format("YYYY-MM-DD")
);
}
if (!controller.get("end_date")) {
controller.set("end_date", moment().format("YYYY-MM-DD"));
controller.set(
"end_date",
moment()
.utc()
.endOf("day")
.format("YYYY-MM-DD")
);
}
}
});

View File

@ -1,5 +1,5 @@
{{#if showSortingUI}}
{{d-button action=sortByLabel icon=sortIcon class="sort-button"}}
{{d-button action=sortByLabel icon=sortIcon class="sort-btn"}}
{{/if}}
<span>{{label.title}}</span>
<span class="title">{{label.title}}</span>

View File

@ -1,4 +1,4 @@
<table class="report-table">
<table class="table">
<thead>
<tr>
{{#if model.computedLabels}}
@ -30,7 +30,7 @@
</tr>
<tr class="admin-report-table-row">
{{#each totalsForSample as |total|}}
<td class="{{total.type}} {{total.property}}">
<td class="admin-report-table-cell {{total.type}} {{total.property}}">
{{total.formatedValue}}
</td>
{{/each}}
@ -44,8 +44,8 @@
</td>
</tr>
<tr class="admin-report-table-row">
<td class="date x">-</td>
<td class="number y">{{number model.total}}</td>
<td class="admin-report-table-cell date x">—</td>
<td class="admin-report-table-cell number y">{{number model.total}}</td>
</tr>
{{/if}}
</tbody>

View File

@ -1,50 +1,99 @@
{{#if isEnabled}}
{{#conditional-loading-section isLoading=isLoading}}
{{#if showHeader}}
<div class="report-header">
{{#if showTitle}}
<div class="report-title">
<h3 class="title">
{{#if showAllReportsLink}}
{{#link-to "adminReports" class="all-report-link"}}
{{i18n "admin.dashboard.all_reports"}}
{{/link-to}}
<span class="separator">|</span>
{{/if}}
{{#conditional-loading-section isLoading=isLoading}}
{{#if showHeader}}
<div class="header">
{{#if showTitle}}
<ul class="breadcrumb">
{{#if showAllReportsLink}}
<li class="item all-reports">
{{#link-to "adminReports" class="report-url"}}
{{i18n "admin.dashboard.all_reports"}}
{{/link-to}}
</li>
<li class="item separator">|</li>
{{/if}}
<a href="{{model.reportUrl}}" class="report-link">
{{model.title}}
</a>
</h3>
<li class="item report">
<a href="{{model.reportUrl}}" class="report-url">
{{model.title}}
</a>
{{#if model.description}}
<span class="info" data-tooltip="{{model.description}}">
{{d-icon "question-circle"}}
</span>
{{/if}}
</div>
{{/if}}
</li>
</ul>
{{/if}}
{{#if showTrend}}
{{#if model.prev_period}}
<div class="trend {{model.trend}}">
<span class="trend-value" title="{{model.trendTitle}}">
{{#if model.average}}
{{number model.currentAverage}}{{#if model.percent}}%{{/if}}
{{else}}
{{number model.currentTotal noTitle="true"}}{{#if model.percent}}%{{/if}}
{{/if}}
</span>
{{#if shouldDisplayTrend}}
<div class="trend {{model.trend}}">
<span class="value" title="{{model.trendTitle}}">
{{#if model.average}}
{{number model.currentAverage}}{{#if model.percent}}%{{/if}}
{{else}}
{{number model.currentTotal noTitle="true"}}{{#if model.percent}}%{{/if}}
{{/if}}
</span>
{{#if model.trendIcon}}
{{d-icon model.trendIcon class="trend-icon"}}
{{#if model.trendIcon}}
{{d-icon model.trendIcon class="icon"}}
{{/if}}
</div>
{{/if}}
</div>
{{/if}}
<div class="body">
<div class="main">
{{#unless showError}}
{{#if hasData}}
{{#if currentMode}}
{{component modeComponent model=model options=options}}
{{#if model.relatedReport}}
{{admin-report showFilteringUI=false dataSourceName=model.relatedReport.type}}
{{/if}}
{{/if}}
{{else}}
<div class="alert alert-info report-alert no-data">
{{d-icon "pie-chart"}}
{{#if model.reportUrl}}
<a href="{{model.reportUrl}}" class="report-url">
<span>
{{#if model.title}}
{{model.title}}
{{/if}}
{{i18n "admin.dashboard.reports.no_data"}}
</span>
</a>
{{else}}
<span>{{i18n "admin.dashboard.reports.no_data"}}</span>
{{/if}}
</div>
{{/if}}
{{else}}
{{#if showTimeoutError}}
<div class="alert alert-error report-alert timeout">
{{d-icon "exclamation-triangle"}}
<span>{{i18n "admin.dashboard.timeout_error"}}</span>
</div>
{{/if}}
{{#if showExceptionError}}
<div class="alert alert-error report-alert exception">
{{d-icon "exclamation-triangle"}}
<span>{{i18n "admin.dashboard.exception_error"}}</span>
</div>
{{/if}}
{{/unless}}
</div>
{{#if showFilteringUI}}
<div class="filters">
{{#if showModes}}
<ul class="mode-switch">
<ul class="modes">
{{#each displayedModes as |displayedMode|}}
<li class="mode">
{{d-button
@ -56,118 +105,84 @@
{{/each}}
</ul>
{{/if}}
{{#if showDatesOptions}}
<div class="control">
<span class="label">
{{i18n 'admin.dashboard.reports.start_date'}}
</span>
<div class="input">
{{date-picker-past
value=startDate
defaultDate=startDate}}
</div>
</div>
<div class="control">
<span class="label">
{{i18n 'admin.dashboard.reports.end_date'}}
</span>
<div class="input">
{{date-picker-past
value=endDate
defaultDate=endDate}}
</div>
</div>
{{/if}}
{{#if showCategoryOptions}}
<div class="control">
<div class="input">
{{search-advanced-category-chooser
filterable=true
value=category
castInteger=true}}
</div>
</div>
{{/if}}
{{#if showGroupOptions}}
<div class="control">
<div class="input">
{{combo-box
castInteger=true
filterable=true
valueAttribute="value"
content=groupOptions
value=groupId}}
</div>
</div>
{{/if}}
{{#if showExport}}
<div class="control">
<div class="input">
{{d-button
class="export-csv-btn"
action="exportCsv"
label="admin.export_csv.button_text"
icon="download"}}
</div>
</div>
{{/if}}
{{#if showRefresh}}
<div class="control">
<div class="input">
{{d-button
class="refresh-report-btn btn-primary"
action="refreshReport"
label="admin.dashboard.reports.refresh_report"
icon="refresh"}}
</div>
</div>
{{/if}}
</div>
{{/if}}
<div class="report-body">
{{#unless showError}}
{{#if hasData}}
{{#if currentMode}}
{{component modeComponent model=model options=options}}
{{/if}}
{{else}}
<div class="alert alert-info no-data">
{{d-icon "pie-chart"}}
<span>{{i18n "admin.dashboard.reports.no_data"}}</span>
</div>
{{/if}}
{{else}}
{{#if showTimeoutError}}
<div class="alert alert-error report-error timeout">
<span>{{i18n "admin.dashboard.timeout_error"}}</span>
</div>
{{/if}}
{{#if showExceptionError}}
<div class="alert alert-error report-error exception">
{{i18n "admin.dashboard.exception_error"}}
</div>
{{/if}}
{{/unless}}
{{#if showFilteringUI}}
<div class="report-filters">
{{#if showDatesOptions}}
<div class="filtering-control">
<span class="filtering-label">
{{i18n 'admin.dashboard.reports.start_date'}}
</span>
<div class="filtering-input">
{{date-picker-past
value=startDate
defaultDate=startDate}}
</div>
</div>
<div class="filtering-control">
<span class="filtering-label">
{{i18n 'admin.dashboard.reports.end_date'}}
</span>
<div class="filtering-input">
{{date-picker-past
value=endDate
defaultDate=endDate}}
</div>
</div>
{{/if}}
{{#if showCategoryOptions}}
<div class="filtering-control">
<div class="filtering-input">
{{search-advanced-category-chooser
filterable=true
value=category
castInteger=true}}
</div>
</div>
{{/if}}
{{#if showGroupOptions}}
<div class="filtering-control">
<div class="filtering-input">
{{combo-box
castInteger=true
filterable=true
valueAttribute="value"
content=groupOptions
value=groupId}}
</div>
</div>
{{/if}}
{{#if showExport}}
<div class="filtering-control">
<div class="filtering-input">
{{d-button
class="export-csv-btn"
action="exportCsv"
label="admin.export_csv.button_text"
icon="download"}}
</div>
</div>
{{/if}}
{{#if showRefresh}}
<div class="filtering-control">
<div class="filtering-input">
{{d-button
class="refresh-report-btn btn-primary"
action="refreshReport"
label="admin.dashboard.reports.refresh_report"
icon="refresh"}}
</div>
</div>
{{/if}}
</div>
{{/if}}
</div>
{{#if model.relatedReport}}
{{admin-report dataSourceName=model.relatedReport.type}}
{{/if}}
{{/conditional-loading-section}}
</div>
{{/conditional-loading-section}}
{{else}}
<div class="alert alert-info">
{{{i18n disabledLabel}}}

View File

@ -57,23 +57,23 @@
<div class="section-columns">
<div class="section-column">
<div class="admin-report activity-metrics">
<div class="report-header">
<div class="report-title">
<h3 class="title">
{{#link-to "adminReports" class="report-link"}}
<div class="header">
<ul class="breadcrumb">
<li class="item report">
{{#link-to "adminReports" class="report-url"}}
{{i18n "admin.dashboard.activity_metrics"}}
{{/link-to}}
</h3>
</div>
</li>
</ul>
</div>
<div class="report-body">
<div class="admin-report-counters-list">
<div class="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 class="counters-cell"></div>
<div class="counters-cell">{{i18n 'admin.dashboard.reports.today'}}</div>
<div class="counters-cell">{{i18n 'admin.dashboard.reports.yesterday'}}</div>
<div class="counters-cell">{{i18n 'admin.dashboard.reports.last_7_days'}}</div>
<div class="counters-cell">{{i18n 'admin.dashboard.reports.last_30_days'}}</div>
</div>
{{#each activityMetrics as |metric|}}
@ -84,10 +84,11 @@
{{/each}}
</div>
</div>
{{#link-to "adminReports"}}
{{i18n "admin.dashboard.all_reports"}}
{{/link-to}}
</div>
{{#link-to "adminReports"}}
{{i18n "admin.dashboard.all_reports"}}
{{/link-to}}
<div class="user-metrics">
{{#conditional-loading-section isLoading=isLoading}}

View File

@ -1,8 +1,9 @@
import { escapeExpression } from "discourse/lib/utilities";
const fadeSpeed = 300;
const tooltipID = "#discourse-tooltip";
export function showTooltip() {
const fadeSpeed = 300;
const tooltipID = "#discourse-tooltip";
const $this = $(this);
const $parent = $this.offsetParent();
const content = escapeExpression($this.attr("data-tooltip"));
@ -16,9 +17,7 @@ export function showTooltip() {
pos.top -= delta.top;
pos.left -= delta.left;
$(tooltipID)
.fadeOut(fadeSpeed)
.remove();
hideTooltip(tooltipID);
$(this).after(`
<div id="discourse-tooltip" ${retina}>
@ -67,9 +66,24 @@ export function showTooltip() {
return false;
}
export function hideTooltip() {
$(tooltipID)
.fadeOut(fadeSpeed)
.remove();
}
export function registerTooltip(jqueryContext) {
if (jqueryContext.length) {
jqueryContext.on("click", showTooltip);
jqueryContext.off("click").on("click", showTooltip);
}
}
export function registerHoverTooltip(jqueryContext) {
if (jqueryContext.length) {
jqueryContext
.off("mouseenter mouseleave click")
.on("mouseenter click", showTooltip)
.on("mouseleave", hideTooltip);
}
}
@ -78,3 +92,9 @@ export function unregisterTooltip(jqueryContext) {
jqueryContext.off("click");
}
}
export function unregisterHoverTooltip(jqueryContext) {
if (jqueryContext.length) {
jqueryContext.off("mouseenter mouseleave click");
}
}

View File

@ -1,70 +1,36 @@
.admin-report {
.report-error,
.no-data {
width: 100%;
width: 100%;
align-self: flex-start;
text-align: center;
padding: 3em;
margin-bottom: 1.5em;
box-sizing: border-box;
}
+ .table {
margin-top: 1.5em;
}
.report-error {
color: $danger;
border: 1px solid $danger;
}
.no-data {
background: $secondary;
border: 1px solid $primary-low;
color: $primary-low-mid;
.d-icon-pie-chart {
color: currentColor;
margin-bottom: 0.25em;
font-size: $font-up-5;
display: block;
.conditional-loading-section {
&.is-loading {
margin: 0;
}
}
.conditional-loading-section {
flex: 1;
margin: 0;
.header {
display: flex;
align-items: center;
border-bottom: 1px solid $primary-low;
margin-bottom: 0.5em;
padding-bottom: 0.5em;
}
.report-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 0.5em;
margin-bottom: 0.5em;
.header .breadcrumb {
margin: 0;
list-style: none;
.report-title {
align-items: center;
display: flex;
justify-content: space-between;
.item {
display: inline;
font-size: $font-up-1;
}
.title {
margin: 0;
padding: 0;
border: 0;
font-size: $font-up-1;
.separator {
font-weight: normal;
}
.all-reports .report-url {
font-weight: 700;
}
.report-link {
color: $primary;
}
.report {
font-weight: 700;
.separator + .report-link {
font-weight: normal;
}
.report-url {
color: $primary;
}
.info {
@ -77,167 +43,134 @@
}
}
}
}
.trend {
align-items: center;
&.trending-down,
&.high-trending-down {
color: $danger;
}
&.trending-up,
&.high-trending-up {
color: $success;
}
&.no-change {
color: $primary-medium;
}
.trend-value {
font-size: $font-up-1;
}
.trend-icon {
font-size: $font-up-1;
font-weight: 700;
}
.header .trend {
margin-left: auto;
&.trending-down,
&.high-trending-down {
color: $danger;
}
.mode-switch {
&.trending-up,
&.high-trending-up {
color: $success;
}
&.no-change {
color: $primary-medium;
}
.value {
font-size: $font-up-1;
}
.icon {
font-size: $font-up-1;
font-weight: 700;
}
}
.body {
display: flex;
}
.main {
flex: 1;
}
.main .report-alert {
margin: 0;
text-align: center;
padding: 3em;
border: 1px solid transparent;
a {
color: $primary-medium;
}
.d-icon {
color: currentColor;
margin-bottom: 0.25em;
font-size: $font-up-5;
display: block;
}
&.no-data {
background: $secondary;
border-color: $primary-low;
color: $primary-low-mid;
}
&.timeout,
&.exception {
border-color: $danger-low;
color: $danger;
}
}
.filters {
display: flex;
margin-left: 1em;
flex-direction: column;
width: 220px;
.modes {
margin: 0 0 1em 0;
padding: 0;
list-style: none;
display: flex;
margin: 0;
.mode {
display: inline;
display: inline-flex;
flex: 1;
.mode-button.current {
.mode-btn.is-current {
color: $tertiary;
}
}
}
}
.report-body {
display: flex;
justify-content: space-between;
.control {
margin-bottom: 1em;
}
.admin-report-table,
.admin-report-chart {
.control .label {
font-weight: 700;
width: 100%;
}
.report-filters {
margin-left: 1em;
min-width: 250px;
display: flex;
flex-direction: column;
.control .input,
.control .select-kit {
width: 100%;
.filtering-control {
display: flex;
flex-direction: column;
margin-bottom: 1em;
}
.filtering-label {
}
.filtering-input {
.export-csv-btn {
width: 100%;
}
.date-picker-wrapper,
.combo-box,
.export-csv-btn,
.refresh-report-btn {
.refresh-report-btn {
width: 100%;
}
.date-picker-wrapper {
width: 100%;
.date-picker {
box-sizing: border-box;
width: 100%;
}
.date-picker-wrapper {
.date-picker {
width: 100%;
box-sizing: border-box;
margin: 0;
}
margin: 0;
}
}
}
.report-filters:only-child {
margin-left: auto;
}
}
}
.admin-report.activity-metrics {
table {
table-layout: auto;
}
}
.admin-report.users-by-type {
margin-top: 1.5em;
}
.admin-report.users-by-type,
.admin-report.users-by-trust-level {
margin-bottom: 1.5em;
flex: 1;
.report-header {
border-bottom: 1px solid $primary-medium;
padding-bottom: 0.25em;
border-bottom: 1px solid #e9e9e9;
}
}
.admin-report.moderators-activity {
tbody tr td.username,
thead tr th.username {
text-align: left;
}
}
.admin-report.trending-search {
tbody tr td.term,
thead tr th.term {
text-align: left;
}
}
.admin-report.top-traffic-sources {
tbody tr td.domain,
thead tr th.domain {
text-align: left;
}
}
.admin-report.post-edits {
.report-table {
table-layout: auto;
tbody tr td,
thead tr th {
text-align: left;
}
thead tr th.edit_reason,
tbody tr td.edit_reason {
width: 100%;
}
}
}
.admin-report.flags-status {
.admin-report-table {
table-layout: auto;
tbody tr td,
thead tr th {
text-align: left;
}
tbody tr td.response_time,
thead tr th.response_time {
text-align: center;
}
.rtl .admin-report {
.filters {
margin-left: 0;
margin-right: 1em;
}
.trend {
margin-left: unset;
margin-right: auto;
}
}

View File

@ -1,67 +1,21 @@
.admin-report-counters-list {
display: flex;
flex: 1;
flex-direction: column;
border-bottom: 1px solid $primary-low;
.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 {
.admin-report {
.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;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
.d-icon {
color: $primary-low-mid;
@ -75,13 +29,8 @@
}
@media screen and (max-width: 400px) {
&.title {
padding: 8px 0 8px 4px;
font-size: $font-down-1;
.d-icon {
display: none;
}
&.title .d-icon {
display: none;
}
}
@ -99,27 +48,18 @@
}
}
}
}
.no-data {
margin: 0;
padding: 8px;
display: flex;
flex-direction: row;
align-items: center;
font-size: $font-0;
border-bottom: 0;
color: $primary-medium;
.d-icon {
font-size: $font-up-1;
margin: 0 0.25em 0 0;
color: $primary-low-mid;
.rtl .counters-list .counters-header .counters-cell {
text-align: left;
}
.rtl .counters-list {
.cell {
text-align: left;
&.title {
text-align: right;
}
}
.alert-error {
text-align: left;
padding: 0.5em;
margin: 0;
border: 0;
}
}

View File

@ -1,9 +1,74 @@
.admin-report-table {
@media screen and (max-width: 650px) {
table {
tbody tr td {
font-size: $font-down-1;
&.two-columns {
.table .admin-report-table-cell:first-child,
.table .admin-report-table-header:first-child {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-align: left;
width: 80%;
}
.table .admin-report-table-cell:last-child,
.table .admin-report-table-header:last-child {
display: inline-block;
width: 80%;
text-align: right;
}
}
.table {
margin: 0;
border: 1px solid $primary-low;
table-layout: fixed;
tbody {
border-top: 0;
}
}
.table .admin-report-table-header {
.sort-btn {
outline: none;
background: none;
padding: 3px 8px;
overflow: hidden;
text-overflow: ellipsis;
}
&.is-current-sort {
.d-icon {
color: $tertiary;
}
.sort-btn:hover {
color: $primary-medium;
background: $primary-low;
}
}
&:not(.is-current-sort) .sort-btn {
background: none;
&:hover {
color: $primary-medium;
background: $primary-low;
}
}
}
.admin-report-table-cell {
&.user .username {
margin-left: 0.25em;
}
}
.total-row {
background: $primary-very-low;
td {
font-weight: 700;
text-align: left;
}
}
@ -15,98 +80,114 @@
button {
margin-left: 0.5em;
&.current {
&.is-current {
color: $tertiary;
}
}
}
}
&.two-columns {
.report-table tbody tr td:first-child,
.report-table thead tr th:first-child {
text-align: left;
.admin-report.top-referred-topics {
.admin-report-table-header.topic_title {
width: 80%;
}
}
.admin-report.trending-search {
.admin-report-table-header.ctr,
.admin-report-table-header.unique_searches,
.admin-report-table-cell.ctr,
.admin-report-table-cell.unique_searches {
text-align: center;
width: 20%;
}
.admin-report-table-cell.term {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.admin-report.moderators-activity {
.admin-report-table-header.seconds,
.admin-report-table-header.number,
.admin-report-table-cell.seconds,
.admin-report-table-cell.number {
text-align: center;
}
.admin-report-table-header.user {
width: 20%;
}
}
.admin-report.post-edits {
.admin-report-table-header.user {
width: 20%;
}
.admin-report-table-cell.post,
.admin-report-table-cell.edit_reason {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.admin-report.flags-status {
.admin-report-table-header.response_time,
.admin-report-table-cell.response_time {
text-align: center;
}
}
.rtl {
.admin-report-table {
&.two-columns {
.table .admin-report-table-cell:first-child,
.table .admin-report-table-header:first-child {
text-align: right;
}
.table .admin-report-table-cell:last-child,
.table .admin-report-table-header:last-child {
text-align: left;
}
}
.report-table {
table-layout: auto;
.total-row {
td {
text-align: right;
}
}
}
.report-table {
table-layout: fixed;
border: 1px solid $primary-low;
margin-top: 0;
tbody {
border: none;
.total-row {
td {
font-weight: 700;
text-align: left;
}
}
tr {
td {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-align: center;
padding: 8px;
&.user {
text-align: left;
.username {
margin-left: 3px;
}
}
}
}
.admin-report-table-cell {
&.user .username {
margin-left: 0;
margin-right: 0.25em;
}
}
thead {
border: 1px solid $primary-low;
.admin-report.trending-search {
.admin-report-table-header.term,
.admin-report-table-cell.term {
text-align: right;
}
}
.admin-report-table-header {
.sort-button {
outline: none;
background: none;
padding: 3px 7px;
overflow: hidden;
text-overflow: ellipsis;
}
.pagination {
button {
margin-left: 0;
margin-right: 0.5em;
}
}
&.is-current-sort {
.d-icon {
color: $tertiary;
}
.sort-button:hover {
color: $primary-medium;
background: $primary-low;
}
}
&:not(.is-current-sort) .sort-button {
background: none;
&:hover {
color: $primary-medium;
background: $primary-low;
}
}
}
tr {
th {
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.admin-report.moderators-activity {
.admin-report-table-header.user,
.admin-report-table-cell.user {
text-align: right;
}
}
}

View File

@ -62,11 +62,11 @@
max-width: 100%;
&:last-child {
margin-left: 1em;
margin-left: 0.5em;
}
&:first-child {
margin-right: 1em;
margin-right: 0.5em;
}
@include breakpoint(medium) {
@ -119,22 +119,25 @@
}
}
.charts {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.admin-report .header {
border: 0;
padding: 0;
margin-bottom: 1em;
}
.chart {
max-width: calc(100% * 1 / 3.2);
width: 100%;
flex-grow: 1;
flex-basis: 100%;
display: flex;
.charts {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-column-gap: 1em;
grid-row-gap: 1em;
.admin-report {
grid-column: span 4;
}
@include breakpoint(medium) {
.chart {
max-width: 100%;
.admin-report {
grid-column: span 12;
}
}
@ -209,6 +212,10 @@
}
}
.top-referred-topics {
margin-bottom: 1.5em;
}
.top-referred-topics,
.trending-search {
th:first-of-type {
@ -216,12 +223,6 @@
}
}
.top-referred-topics {
.dashboard-table table {
table-layout: auto;
}
}
.section {
.period-chooser .period-chooser-header {
.selected-name,
@ -248,27 +249,82 @@
}
}
.admin-report-table {
&.is-disabled {
background: $primary-low;
padding: 1em;
.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;
font-weight: 700;
text-align: right;
align-items: center;
padding: 0.65em 0.25em;
}
@media screen and (max-width: 650px) {
table {
tbody tr td {
font-size: $font-down-1;
}
.admin-report .main {
border: 1px solid $primary-low;
&:hover {
background-color: $primary-very-low;
}
}
&.is-loading {
height: 150px;
.admin-report:not(:last-child) {
.main {
border-bottom: 0;
}
.conditional-loading-section.is-loading {
border-bottom: 0;
}
}
.admin-report .conditional-loading-section.is-loading {
display: flex;
flex-direction: row;
padding: 0.5em 0.25em;
align-items: flex-start;
justify-content: flex-start;
border: 1px solid $primary-low;
.title {
font-size: $font-0;
}
.spinner {
margin: 0;
width: 8px;
height: 8px;
margin-left: 0.5em;
}
}
.admin-report .main .report-alert {
display: flex;
flex-direction: row;
padding: 0.5em 0.25em;
align-items: center;
border: 0;
&:hover {
background-color: $primary-very-low;
}
.d-icon {
font-size: $font-up-1;
margin: 0 0.25em 0 0;
color: $primary-low-mid;
}
}
}
.activity-metrics {
margin-bottom: 0.25em;
margin-bottom: 1.5em;
}
.user-metrics {
@ -368,21 +424,32 @@
}
}
.community-health.section {
margin-bottom: 1em;
.users-by-trust-level,
.users-by-type {
margin-bottom: 1.5em;
}
.dashboard-next.moderation {
.community-health.section {
margin-bottom: 1.5em;
}
.dashboard-next-moderation {
.admin-dashboard-moderation-top {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-column-gap: 1em;
grid-row-gap: 1em;
}
.section-body {
margin-bottom: 1em;
}
.main-section {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-column-gap: 1em;
grid-row-gap: 1em;
> * {
grid-column: span 12;
@ -392,6 +459,7 @@
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-column-gap: 1em;
grid-row-gap: 1em;
}
}

View File

@ -22,9 +22,11 @@
@import "mobile/ring";
@import "mobile/group";
@import "mobile/groups";
@import "mobile/dashboard_next";
@import "mobile/admin_reports";
@import "mobile/admin_report";
@import "mobile/admin_report_table";
@import "mobile/admin_report_counters";
// Import all component-specific files
@import "mobile/components/*";

View File

@ -9,27 +9,9 @@
}
}
.admin-report.top-referred-topics {
.admin-report-table {
.report-table {
table-layout: fixed;
thead tr th.topic_title,
tbody tr td.topic_title {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 80%;
}
}
}
}
.admin-report.trending-search {
.admin-report-table {
.report-table {
table-layout: fixed;
thead tr th.term,
tbody tr td.term {
width: 50%;

View File

@ -0,0 +1,5 @@
.counters-list {
.counters-header .counters-cell {
font-weight: normal;
}
}

View File

@ -1,14 +1,28 @@
.admin-report-table {
.report-table {
table-layout: fixed;
.table {
font-size: $font-down-1;
}
thead tr th {
font-weight: normal;
font-size: $font-down-2;
white-space: unset;
.sort-button {
display: none;
}
.table .admin-report-table-header {
font-weight: 500;
border-right: 1px solid $primary-low;
padding: auto;
.title {
writing-mode: vertical-rl;
text-orientation: mixed;
text-align: right;
transform: rotate(180deg);
}
.sort-btn {
display: none;
}
}
.table tbody tr td {
&.user .username {
display: none;
}
}
}

View File

@ -1,24 +1,24 @@
.admin-reports {
.admin-report {
.report-body {
.body {
flex-direction: column;
.report-filters {
.filters {
order: 0;
margin: 0;
width: 100%;
}
.alert {
.main {
order: 2;
}
.report-alert {
margin: 0;
order: 1;
flex: 1;
padding: 1em;
}
.admin-report-table,
.admin-report-chart {
order: 2;
}
}
}
}

View File

@ -0,0 +1,5 @@
.dashboard-next {
.activity-metrics .counters-list {
font-size: $font-down-1;
}
}

View File

@ -23,8 +23,8 @@ class Admin::ReportsController < Admin::AdminController
raise Discourse::NotFound unless report_type =~ /^[a-z0-9\_]+$/
start_date = (params[:start_date].present? ? params[:start_date].to_date : 30.days.ago).beginning_of_day
end_date = (params[:end_date].present? ? params[:end_date].to_date : start_date + 30.days).end_of_day
start_date = (params[:start_date].present? ? Time.parse(params[:start_date]).to_date : 1.days.ago).beginning_of_day
end_date = (params[:end_date].present? ? Time.parse(params[:end_date]).to_date : start_date + 30.days).end_of_day
if params.has_key?(:category_id) && params[:category_id].to_i > 0
category_id = params[:category_id].to_i

View File

@ -18,8 +18,8 @@ class Report
def initialize(type)
@type = type
@start_date ||= Report.default_days.days.ago.beginning_of_day
@end_date ||= Time.now.end_of_day
@start_date ||= Report.default_days.days.ago.utc.beginning_of_day
@end_date ||= Time.now.utc.end_of_day
@prev_end_date = @start_date
@average = false
@percent = false

View File

@ -10,12 +10,10 @@ componentTest("default", {
async test(assert) {
assert.ok(exists(".admin-report.signups"));
assert.ok(
exists(".admin-report.table.signups", "it defaults to table mode")
);
assert.ok(exists(".admin-report.signups", "it defaults to table mode"));
assert.equal(
find(".report-header .title")
find(".header .item.report")
.text()
.trim(),
"Signups",
@ -23,13 +21,13 @@ componentTest("default", {
);
assert.equal(
find(".report-header .info").attr("data-tooltip"),
find(".header .info").attr("data-tooltip"),
"New account registrations for this period",
"it has a description"
);
assert.equal(
find(".report-body .report-table thead tr th:first-child")
find(".admin-report-table thead tr th:first-child .title")
.text()
.trim(),
"Day",
@ -37,7 +35,7 @@ componentTest("default", {
);
assert.equal(
find(".report-body .report-table thead tr th:nth-child(2)")
find(".admin-report-table thead tr th:nth-child(2) .title")
.text()
.trim(),
"Count",
@ -45,7 +43,7 @@ componentTest("default", {
);
assert.equal(
find(".report-body .report-table tbody tr:nth-child(1) td:nth-child(1)")
find(".admin-report-table tbody tr:nth-child(1) td:nth-child(1)")
.text()
.trim(),
"June 16, 2018",
@ -53,7 +51,7 @@ componentTest("default", {
);
assert.equal(
find(".report-body .report-table tbody tr:nth-child(1) td:nth-child(2)")
find(".admin-report-table tbody tr:nth-child(1) td:nth-child(2)")
.text()
.trim(),
"12",
@ -62,9 +60,10 @@ componentTest("default", {
assert.ok(exists(".total-row"), "it has totals");
await click(".admin-report-table-header.y .sort-button");
await click(".admin-report-table-header.y .sort-btn");
assert.equal(
find(".report-body .report-table tbody tr:nth-child(1) td:nth-child(2)")
find(".admin-report-table tbody tr:nth-child(1) td:nth-child(2)")
.text()
.trim(),
"7",
@ -98,13 +97,13 @@ componentTest("options", {
});
componentTest("switch modes", {
template: "{{admin-report dataSourceName='signups'}}",
template: "{{admin-report dataSourceName='signups' showFilteringUI=true}}",
async test(assert) {
await click(".mode-button.chart");
await click(".mode-btn.chart");
assert.notOk(exists(".admin-report.table.signups"), "it removes the table");
assert.ok(exists(".admin-report.chart.signups"), "it shows the chart");
assert.notOk(exists(".admin-report-table"), "it removes the table");
assert.ok(exists(".admin-report-chart"), "it shows the chart");
}
});