mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 11:13:38 +08:00
FEATURE: initial implementation of generic filters for reports
This commit is contained in:
parent
4b455e741e
commit
bcca2b5d73
|
@ -1,7 +1,7 @@
|
|||
import ReportLoader from "discourse/lib/reports-loader";
|
||||
import Category from "discourse/models/category";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { isNumeric } from "discourse/lib/utilities";
|
||||
import { SCHEMA_VERSION, default as Report } from "admin/models/report";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
|
@ -50,21 +50,15 @@ export default Ember.Component.extend({
|
|||
filters: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
category: null,
|
||||
groupId: null,
|
||||
filter: null,
|
||||
showTrend: false,
|
||||
showHeader: true,
|
||||
showTitle: true,
|
||||
showFilteringUI: false,
|
||||
showCategoryOptions: Ember.computed.alias("model.category_filtering"),
|
||||
showDatesOptions: Ember.computed.alias("model.dates_filtering"),
|
||||
showGroupOptions: Ember.computed.alias("model.group_filtering"),
|
||||
showExport: Ember.computed.not("model.onlyTable"),
|
||||
showRefresh: Ember.computed.or(
|
||||
"showCategoryOptions",
|
||||
"showDatesOptions",
|
||||
"showGroupOptions"
|
||||
"model.available_filters.length"
|
||||
),
|
||||
shouldDisplayTrend: Ember.computed.and("showTrend", "model.prev_period"),
|
||||
|
||||
|
@ -74,19 +68,12 @@ export default Ember.Component.extend({
|
|||
this._reports = [];
|
||||
},
|
||||
|
||||
startDate: Ember.computed.alias("filters.startDate"),
|
||||
endDate: Ember.computed.alias("filters.endDate"),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
const state = this.get("filters") || {};
|
||||
|
||||
this.setProperties({
|
||||
category: Category.findById(state.categoryId),
|
||||
groupId: state.groupId,
|
||||
filter: state.filter,
|
||||
startDate: state.startDate,
|
||||
endDate: state.endDate
|
||||
});
|
||||
|
||||
if (this.get("report")) {
|
||||
this._renderReport(
|
||||
this.get("report"),
|
||||
|
@ -125,8 +112,6 @@ export default Ember.Component.extend({
|
|||
return displayedModesLength > 1;
|
||||
},
|
||||
|
||||
categoryId: Ember.computed.alias("category.id"),
|
||||
|
||||
@computed("currentMode", "model.modes", "forcedModes")
|
||||
displayedModes(currentMode, reportModes, forcedModes) {
|
||||
const modes = forcedModes ? forcedModes.split(",") : reportModes;
|
||||
|
@ -143,35 +128,11 @@ export default Ember.Component.extend({
|
|||
});
|
||||
},
|
||||
|
||||
@computed()
|
||||
groupOptions() {
|
||||
const arr = [
|
||||
{ name: I18n.t("admin.dashboard.reports.groups"), value: "all" }
|
||||
];
|
||||
return arr.concat(
|
||||
(this.site.groups || []).map(i => {
|
||||
return { name: i["name"], value: i["id"] };
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
@computed("currentMode")
|
||||
modeComponent(currentMode) {
|
||||
return `admin-report-${currentMode}`;
|
||||
},
|
||||
|
||||
@computed("model.filter_options")
|
||||
filterOptions(options) {
|
||||
if (options) {
|
||||
return options.map(option => {
|
||||
if (option.allowAny) {
|
||||
option.choices.unshift(I18n.t("admin.dashboard.report_filter_any"));
|
||||
}
|
||||
return option;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@computed("startDate")
|
||||
normalizedStartDate(startDate) {
|
||||
return startDate && typeof startDate.isValid === "function"
|
||||
|
@ -198,25 +159,25 @@ export default Ember.Component.extend({
|
|||
|
||||
@computed(
|
||||
"dataSourceName",
|
||||
"categoryId",
|
||||
"groupId",
|
||||
"filter",
|
||||
"normalizedStartDate",
|
||||
"normalizedEndDate"
|
||||
"normalizedEndDate",
|
||||
"filters.customFilters"
|
||||
)
|
||||
reportKey(dataSourceName, categoryId, groupId, filter, startDate, endDate) {
|
||||
reportKey(dataSourceName, startDate, endDate, customFilters) {
|
||||
if (!dataSourceName || !startDate || !endDate) return null;
|
||||
|
||||
let reportKey = "reports:";
|
||||
reportKey += [
|
||||
dataSourceName,
|
||||
categoryId,
|
||||
startDate.replace(/-/g, ""),
|
||||
endDate.replace(/-/g, ""),
|
||||
groupId,
|
||||
filter,
|
||||
"[:prev_period]",
|
||||
this.get("reportOptions.table.limit"),
|
||||
customFilters
|
||||
? JSON.stringify(customFilters, (key, value) =>
|
||||
isNumeric(value) ? value.toString() : value
|
||||
)
|
||||
: null,
|
||||
SCHEMA_VERSION
|
||||
]
|
||||
.filter(x => x)
|
||||
|
@ -227,49 +188,40 @@ export default Ember.Component.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
filter(filterOptionId, value) {
|
||||
let params = [];
|
||||
let paramPairs = {};
|
||||
let newParams = [];
|
||||
applyFilter(id, value) {
|
||||
let customFilters = this.get("filters.customFilters") || {};
|
||||
|
||||
if (this.get("filter")) {
|
||||
const filter = this.get("filter").slice(1, -1);
|
||||
params = filter.split("&") || [];
|
||||
params.map(p => {
|
||||
const pair = p.split("=");
|
||||
paramPairs[pair[0]] = pair[1];
|
||||
});
|
||||
if (typeof value === "undefined") {
|
||||
delete customFilters[id];
|
||||
} else {
|
||||
customFilters[id] = value;
|
||||
}
|
||||
|
||||
paramPairs[filterOptionId] = value;
|
||||
Object.keys(paramPairs).forEach(key => {
|
||||
if (paramPairs[key] !== I18n.t("admin.dashboard.report_filter_any")) {
|
||||
newParams.push(`${key}=${paramPairs[key]}`);
|
||||
}
|
||||
this.attrs.onRefresh({
|
||||
type: this.get("model.type"),
|
||||
startDate: this.get("startDate"),
|
||||
endDate: this.get("endDate"),
|
||||
filters: customFilters
|
||||
});
|
||||
|
||||
this.set("filter", `[${newParams.join("&")}]`);
|
||||
},
|
||||
|
||||
refreshReport() {
|
||||
this.attrs.onRefresh({
|
||||
categoryId: this.get("categoryId"),
|
||||
groupId: this.get("groupId"),
|
||||
filter: this.get("filter"),
|
||||
startDate: this.get("startDate"),
|
||||
endDate: this.get("endDate")
|
||||
endDate: this.get("endDate"),
|
||||
filters: this.get("filters.customFilters")
|
||||
});
|
||||
},
|
||||
|
||||
exportCsv() {
|
||||
const customFilters = this.get("filters.customFilters");
|
||||
|
||||
exportEntity("report", {
|
||||
name: this.get("model.type"),
|
||||
start_date: this.get("startDate"),
|
||||
end_date: this.get("endDate"),
|
||||
category_id:
|
||||
this.get("categoryId") === "all" ? undefined : this.get("categoryId"),
|
||||
group_id:
|
||||
this.get("groupId") === "all" ? undefined : this.get("groupId")
|
||||
startDate: this.get("startDate"),
|
||||
endDate: this.get("endDate"),
|
||||
category_id: customFilters.category,
|
||||
group_id: customFilters.group
|
||||
}).then(outputExportResult);
|
||||
},
|
||||
|
||||
|
@ -383,22 +335,14 @@ export default Ember.Component.extend({
|
|||
.toISOString();
|
||||
}
|
||||
|
||||
if (this.get("groupId") && this.get("groupId") !== "all") {
|
||||
payload.data.group_id = this.get("groupId");
|
||||
}
|
||||
|
||||
if (this.get("categoryId") && this.get("categoryId") !== "all") {
|
||||
payload.data.category_id = this.get("categoryId");
|
||||
}
|
||||
|
||||
if (this.get("filter") && this.get("filter") !== "all") {
|
||||
payload.data.filter = this.get("filter");
|
||||
}
|
||||
|
||||
if (this.get("reportOptions.table.limit")) {
|
||||
payload.data.limit = this.get("reportOptions.table.limit");
|
||||
}
|
||||
|
||||
if (this.get("filters.customFilters")) {
|
||||
payload.data.filters = this.get("filters.customFilters");
|
||||
}
|
||||
|
||||
return payload;
|
||||
},
|
||||
|
||||
|
@ -443,8 +387,8 @@ export default Ember.Component.extend({
|
|||
Report.fillMissingDates(jsonReport, {
|
||||
filledField: "prevChartData",
|
||||
dataField: "prev_data",
|
||||
starDate: jsonReport.prev_start_date,
|
||||
endDate: jsonReport.prev_end_date
|
||||
starDate: jsonReport.prev_startDate,
|
||||
endDate: jsonReport.prev_endDate
|
||||
});
|
||||
|
||||
if (jsonReport.prevChartData && jsonReport.prevChartData.length > 40) {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import Category from "discourse/models/category";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["category-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/category",
|
||||
|
||||
@computed("filter.default")
|
||||
category(categoryId) {
|
||||
return Category.findById(categoryId);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["file-extension-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/file-extension"
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
export default Ember.Component.extend({
|
||||
actions: {
|
||||
onChange(value) {
|
||||
this.applyFilter(this.get("filter.id"), value);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["group-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/group",
|
||||
|
||||
@computed()
|
||||
groupOptions() {
|
||||
return (this.site.groups || []).map(group => {
|
||||
return { name: group["name"], value: group["id"] };
|
||||
});
|
||||
},
|
||||
|
||||
@computed("filter.default")
|
||||
groupId(filterDefault) {
|
||||
return filterDefault ? parseInt(filterDefault, 10) : null;
|
||||
}
|
||||
});
|
|
@ -1,7 +1,10 @@
|
|||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
queryParams: ["start_date", "end_date", "category_id", "group_id", "filter"],
|
||||
queryParams: ["start_date", "end_date", "filters"],
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
filters: null,
|
||||
|
||||
@computed("model.type")
|
||||
reportOptions(type) {
|
||||
|
@ -12,28 +15,5 @@ export default Ember.Controller.extend({
|
|||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
@computed("category_id", "group_id", "start_date", "end_date", "filter")
|
||||
filters(categoryId, groupId, startDate, endDate, filter) {
|
||||
return {
|
||||
categoryId,
|
||||
groupId,
|
||||
filter,
|
||||
startDate,
|
||||
endDate
|
||||
};
|
||||
},
|
||||
|
||||
actions: {
|
||||
onParamsChange(params) {
|
||||
this.setProperties({
|
||||
start_date: params.startDate,
|
||||
filter: params.filter,
|
||||
category_id: params.categoryId,
|
||||
group_id: params.groupId,
|
||||
end_date: params.endDate
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import { renderAvatar } from "discourse/helpers/user-avatar";
|
|||
|
||||
// Change this line each time report format change
|
||||
// and you want to ensure cache is reset
|
||||
export const SCHEMA_VERSION = 3;
|
||||
export const SCHEMA_VERSION = 4;
|
||||
|
||||
const Report = Discourse.Model.extend({
|
||||
average: false,
|
||||
|
|
|
@ -1,27 +1,65 @@
|
|||
export default Discourse.Route.extend({
|
||||
setupController(controller) {
|
||||
this._super(...arguments);
|
||||
queryParams: {
|
||||
start_date: { refreshModel: true },
|
||||
end_date: { refreshModel: true },
|
||||
filters: { refreshModel: true }
|
||||
},
|
||||
|
||||
if (!controller.get("start_date")) {
|
||||
controller.set(
|
||||
"start_date",
|
||||
moment
|
||||
.utc()
|
||||
.subtract(1, "day")
|
||||
.subtract(1, "month")
|
||||
.startOf("day")
|
||||
.format("YYYY-MM-DD")
|
||||
);
|
||||
model(params) {
|
||||
params.customFilters = params.filters;
|
||||
delete params.filters;
|
||||
|
||||
params.startDate =
|
||||
params.start_date ||
|
||||
moment
|
||||
.utc()
|
||||
.subtract(1, "day")
|
||||
.subtract(1, "month")
|
||||
.startOf("day")
|
||||
.format("YYYY-MM-DD");
|
||||
delete params.start_date;
|
||||
|
||||
params.endDate =
|
||||
params.end_date ||
|
||||
moment
|
||||
.utc()
|
||||
.endOf("day")
|
||||
.format("YYYY-MM-DD");
|
||||
delete params.end_date;
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
deserializeQueryParam(value, urlKey, defaultValueType) {
|
||||
if (urlKey === "filters") {
|
||||
return JSON.parse(decodeURIComponent(value));
|
||||
}
|
||||
|
||||
if (!controller.get("end_date")) {
|
||||
controller.set(
|
||||
"end_date",
|
||||
moment()
|
||||
.utc()
|
||||
.endOf("day")
|
||||
.format("YYYY-MM-DD")
|
||||
);
|
||||
return this._super(value, urlKey, defaultValueType);
|
||||
},
|
||||
|
||||
serializeQueryParam(value, urlKey, defaultValueType) {
|
||||
if (urlKey === "filters") {
|
||||
if (value && Object.keys(value).length > 0) {
|
||||
return JSON.stringify(value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this._super(value, urlKey, defaultValueType);
|
||||
},
|
||||
|
||||
actions: {
|
||||
onParamsChange(params) {
|
||||
const queryParams = {
|
||||
type: params.type,
|
||||
start_date: params.startDate,
|
||||
filters: params.filters,
|
||||
end_date: params.endDate
|
||||
};
|
||||
|
||||
this.transitionTo("adminReports.show", { queryParams });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -149,38 +149,17 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showCategoryOptions}}
|
||||
{{#each model.available_filters as |filter|}}
|
||||
<div class="control">
|
||||
<div class="input">
|
||||
{{search-advanced-category-chooser
|
||||
filterable=true
|
||||
value=category
|
||||
castInteger=true}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<span class="label">
|
||||
{{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}}
|
||||
</span>
|
||||
|
||||
{{#if showGroupOptions}}
|
||||
<div class="control">
|
||||
<div class="input">
|
||||
{{combo-box
|
||||
castInteger=true
|
||||
filterable=true
|
||||
valueAttribute="value"
|
||||
content=groupOptions
|
||||
value=groupId}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#each filterOptions as |filterOption|}}
|
||||
<div class="control">
|
||||
<div class="input">
|
||||
{{combo-box content=filterOption.choices
|
||||
filterable=true
|
||||
allowAny=true
|
||||
value=filterOption.selected
|
||||
onSelect=(action "filter" filterOption.id)}}
|
||||
{{component
|
||||
(concat "report-filters/" filter.id)
|
||||
filter=filter
|
||||
applyFilter=(action "applyFilter")}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{{search-advanced-category-chooser
|
||||
filterable=true
|
||||
value=category
|
||||
castInteger=true
|
||||
onSelectNone=(action "onChange")
|
||||
onSelect=(action "onChange")}}
|
|
@ -0,0 +1,8 @@
|
|||
{{combo-box
|
||||
content=filter.choices
|
||||
filterable=true
|
||||
allowAny=filter.allow_any
|
||||
value=filter.default
|
||||
none="admin.dashboard.report_filter_any"
|
||||
onSelectNone=(action "onChange")
|
||||
onSelect=(action "onChange")}}
|
|
@ -0,0 +1,10 @@
|
|||
{{combo-box
|
||||
castInteger=true
|
||||
filterable=true
|
||||
valueAttribute="value"
|
||||
content=groupOptions
|
||||
value=groupId
|
||||
allowAny=filter.allow_any
|
||||
none="admin.dashboard.reports.groups"
|
||||
onSelectNone=(action "onChange")
|
||||
onSelect=(action "onChange")}}
|
|
@ -1,7 +1,7 @@
|
|||
{{admin-report
|
||||
showAllReportsLink=true
|
||||
dataSourceName=model.type
|
||||
filters=filters
|
||||
filters=model
|
||||
reportOptions=reportOptions
|
||||
showFilteringUI=true
|
||||
onRefresh=(action "onParamsChange")}}
|
||||
onRefresh=(route-action "onParamsChange")}}
|
||||
|
|
|
@ -91,18 +91,6 @@ class Admin::ReportsController < Admin::AdminController
|
|||
start_date = (report_params[:start_date].present? ? Time.parse(report_params[:start_date]).to_date : 1.days.ago).beginning_of_day
|
||||
end_date = (report_params[:end_date].present? ? Time.parse(report_params[:end_date]).to_date : start_date + 30.days).end_of_day
|
||||
|
||||
if report_params.has_key?(:category_id) && report_params[:category_id].to_i > 0
|
||||
category_id = report_params[:category_id].to_i
|
||||
else
|
||||
category_id = nil
|
||||
end
|
||||
|
||||
if report_params.has_key?(:group_id) && report_params[:group_id].to_i > 0
|
||||
group_id = report_params[:group_id].to_i
|
||||
else
|
||||
group_id = nil
|
||||
end
|
||||
|
||||
facets = nil
|
||||
if Array === report_params[:facets]
|
||||
facets = report_params[:facets].map { |s| s.to_s.to_sym }
|
||||
|
@ -113,17 +101,15 @@ class Admin::ReportsController < Admin::AdminController
|
|||
limit = report_params[:limit].to_i
|
||||
end
|
||||
|
||||
filter = nil
|
||||
if report_params.has_key?(:filter)
|
||||
filter = report_params[:filter]
|
||||
filters = nil
|
||||
if report_params.has_key?(:filters)
|
||||
filters = report_params[:filters]
|
||||
end
|
||||
|
||||
{
|
||||
start_date: start_date,
|
||||
end_date: end_date,
|
||||
category_id: category_id,
|
||||
group_id: group_id,
|
||||
filter: filter,
|
||||
filters: filters,
|
||||
facets: facets,
|
||||
limit: limit
|
||||
}
|
||||
|
|
|
@ -3,14 +3,13 @@ require_dependency 'topic_subtype'
|
|||
class Report
|
||||
# Change this line each time report format change
|
||||
# and you want to ensure cache is reset
|
||||
SCHEMA_VERSION = 3
|
||||
SCHEMA_VERSION = 4
|
||||
|
||||
attr_accessor :type, :data, :total, :prev30Days, :start_date,
|
||||
:end_date, :category_id, :group_id, :filter,
|
||||
:labels, :async, :prev_period, :facets, :limit, :processing, :average, :percent,
|
||||
:higher_is_better, :icon, :modes, :category_filtering,
|
||||
:group_filtering, :prev_data, :prev_start_date, :prev_end_date,
|
||||
:dates_filtering, :error, :primary_color, :secondary_color, :filter_options
|
||||
:end_date, :labels, :prev_period, :facets, :limit, :average,
|
||||
:percent, :higher_is_better, :icon, :modes, :prev_data,
|
||||
:prev_start_date, :prev_end_date, :dates_filtering, :error,
|
||||
:primary_color, :secondary_color, :filters, :available_filters
|
||||
|
||||
def self.default_days
|
||||
30
|
||||
|
@ -24,13 +23,11 @@ class Report
|
|||
@average = false
|
||||
@percent = false
|
||||
@higher_is_better = true
|
||||
@category_filtering = false
|
||||
@group_filtering = false
|
||||
@modes = [:table, :chart]
|
||||
@prev_data = nil
|
||||
@dates_filtering = true
|
||||
@filter_options = nil
|
||||
@filter = nil
|
||||
@available_filters = {}
|
||||
@filters = {}
|
||||
|
||||
tertiary = ColorScheme.hex_for_name('tertiary') || '0088cc'
|
||||
@primary_color = rgba_color(tertiary)
|
||||
|
@ -41,17 +38,24 @@ class Report
|
|||
(+"reports:") <<
|
||||
[
|
||||
report.type,
|
||||
report.category_id,
|
||||
report.start_date.to_date.strftime("%Y%m%d"),
|
||||
report.end_date.to_date.strftime("%Y%m%d"),
|
||||
report.group_id,
|
||||
report.filter,
|
||||
report.facets,
|
||||
report.limit,
|
||||
report.filters.blank? ? nil : MultiJson.dump(report.filters),
|
||||
SCHEMA_VERSION,
|
||||
].compact.map(&:to_s).join(':')
|
||||
end
|
||||
|
||||
def add_filter(name, options = {})
|
||||
default_filter = { allow_any: false, choices: [], default: nil }
|
||||
available_filters[name] = default_filter.merge(options)
|
||||
end
|
||||
|
||||
def remove_filter(name)
|
||||
available_filters.delete(name)
|
||||
end
|
||||
|
||||
def self.clear_cache(type = nil)
|
||||
pattern = type ? "reports:#{type}:*" : "reports:*"
|
||||
|
||||
|
@ -76,13 +80,6 @@ class Report
|
|||
self.start_date
|
||||
end
|
||||
|
||||
def filter_values
|
||||
if self.filter.present?
|
||||
return self.filter.delete_prefix("[").delete_suffix("]").split("&").map { |param| param.split("=") }.to_h
|
||||
end
|
||||
{}
|
||||
end
|
||||
|
||||
def as_json(options = nil)
|
||||
description = I18n.t("reports.#{type}.description", default: "")
|
||||
{
|
||||
|
@ -97,14 +94,12 @@ class Report
|
|||
prev_data: self.prev_data,
|
||||
prev_start_date: prev_start_date&.iso8601,
|
||||
prev_end_date: prev_end_date&.iso8601,
|
||||
category_id: category_id,
|
||||
group_id: group_id,
|
||||
filter: self.filter,
|
||||
prev30Days: self.prev30Days,
|
||||
dates_filtering: self.dates_filtering,
|
||||
report_key: Report.cache_key(self),
|
||||
primary_color: self.primary_color,
|
||||
secondary_color: self.secondary_color,
|
||||
available_filters: self.available_filters.map { |k, v| { id: k }.merge(v) },
|
||||
labels: labels || [
|
||||
{
|
||||
type: :date,
|
||||
|
@ -117,13 +112,9 @@ class Report
|
|||
title: I18n.t("reports.default.labels.count")
|
||||
},
|
||||
],
|
||||
processing: self.processing,
|
||||
average: self.average,
|
||||
percent: self.percent,
|
||||
higher_is_better: self.higher_is_better,
|
||||
category_filtering: self.category_filtering,
|
||||
group_filtering: self.group_filtering,
|
||||
filter_options: self.filter_options,
|
||||
modes: self.modes,
|
||||
}.tap do |json|
|
||||
json[:icon] = self.icon if self.icon
|
||||
|
@ -150,15 +141,12 @@ class Report
|
|||
report = Report.new(type)
|
||||
report.start_date = opts[:start_date] if opts[:start_date]
|
||||
report.end_date = opts[:end_date] if opts[:end_date]
|
||||
report.category_id = opts[:category_id] if opts[:category_id]
|
||||
report.group_id = opts[:group_id] if opts[:group_id]
|
||||
report.filter = opts[:filter] if opts[:filter]
|
||||
report.facets = opts[:facets] || [:total, :prev30Days]
|
||||
report.limit = opts[:limit] if opts[:limit]
|
||||
report.processing = false
|
||||
report.average = opts[:average] if opts[:average]
|
||||
report.percent = opts[:percent] if opts[:percent]
|
||||
report.higher_is_better = opts[:higher_is_better] if opts[:higher_is_better]
|
||||
report.filters = opts[:filters] if opts[:filters]
|
||||
|
||||
report
|
||||
end
|
||||
|
||||
|
@ -192,7 +180,6 @@ class Report
|
|||
report.error = :timeout
|
||||
end
|
||||
rescue Exception => e
|
||||
|
||||
# In test mode, don't swallow exceptions by default to help debug errors.
|
||||
raise if Rails.env.test? && !opts[:wrap_exceptions_in_test]
|
||||
|
||||
|
@ -288,12 +275,15 @@ class Report
|
|||
end
|
||||
|
||||
def self.post_action_report(report, post_action_type)
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.data = []
|
||||
PostAction.count_per_day_for_type(post_action_type, category_id: report.category_id, start_date: report.start_date, end_date: report.end_date).each do |date, count|
|
||||
PostAction.count_per_day_for_type(post_action_type, category_id: category_filter, start_date: report.start_date, end_date: report.end_date).each do |date, count|
|
||||
report.data << { x: date, y: count }
|
||||
end
|
||||
countable = PostAction.unscoped.where(post_action_type_id: post_action_type)
|
||||
countable = countable.joins(post: :topic).merge(Topic.in_category_and_subcategories(report.category_id)) if report.category_id
|
||||
countable = countable.joins(post: :topic).merge(Topic.in_category_and_subcategories(category_filter)) if category_filter
|
||||
add_counts report, countable, 'post_actions.created_at'
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Report.add_report("bookmarks") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('bookmarks') do |report|
|
||||
report.icon = 'bookmark'
|
||||
|
||||
post_action_report report, PostActionType.types[:bookmark]
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
Report.add_report("flags") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('flags') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.icon = 'flag'
|
||||
report.higher_is_better = false
|
||||
|
||||
|
@ -9,11 +11,14 @@ Report.add_report("flags") do |report|
|
|||
:count_by_date,
|
||||
report.start_date,
|
||||
report.end_date,
|
||||
report.category_id
|
||||
category_filter
|
||||
)
|
||||
|
||||
countable = ReviewableFlaggedPost.scores_with_topics
|
||||
countable.merge!(Topic.in_category_and_subcategories(report.category_id)) if report.category_id
|
||||
|
||||
if category_filter
|
||||
countable.merge!(Topic.in_category_and_subcategories(category_filter))
|
||||
end
|
||||
|
||||
add_counts report, countable, 'reviewable_scores.created_at'
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Report.add_report("likes") do |report|
|
||||
report.category_filtering = true
|
||||
report.icon = 'heart'
|
||||
|
||||
post_action_report report, PostActionType.types[:like]
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
Report.add_report("post_edits") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('post_edits') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.modes = [:table]
|
||||
|
||||
report.labels = [
|
||||
|
@ -77,14 +79,14 @@ Report.add_report("post_edits") do |report|
|
|||
ON u.id = p.user_id
|
||||
SQL
|
||||
|
||||
if report.category_id
|
||||
if category_filter
|
||||
sql += <<~SQL
|
||||
JOIN topics t
|
||||
ON t.id = p.topic_id
|
||||
WHERE t.category_id = ? OR t.category_id IN (SELECT id FROM categories WHERE categories.parent_category_id = ?)
|
||||
SQL
|
||||
end
|
||||
result = report.category_id ? DB.query(sql, report.category_id, report.category_id) : DB.query(sql)
|
||||
result = category_filter ? DB.query(sql, category_filter, category_filter) : DB.query(sql)
|
||||
|
||||
result.each do |r|
|
||||
revision = {}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
Report.add_report("posts") do |report|
|
||||
Report.add_report('posts') do |report|
|
||||
report.modes = [:table, :chart]
|
||||
report.category_filtering = true
|
||||
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date, report.category_id
|
||||
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date, category_filter
|
||||
|
||||
countable = Post.public_posts.where(post_type: Post.types[:regular])
|
||||
if report.category_id
|
||||
countable = countable.joins(:topic).merge(Topic.in_category_and_subcategories(report.category_id))
|
||||
if category_filter
|
||||
countable = countable.joins(:topic).merge(Topic.in_category_and_subcategories(category_filter))
|
||||
end
|
||||
add_counts report, countable, 'posts.created_at'
|
||||
end
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
Report.add_report("profile_views") do |report|
|
||||
report.group_filtering = true
|
||||
Report.add_report('profile_views') do |report|
|
||||
group_filter = report.filters.dig(:group)
|
||||
report.add_filter('group', default: group_filter)
|
||||
|
||||
start_date = report.start_date
|
||||
end_date = report.end_date
|
||||
basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date, report.group_id
|
||||
basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date, group_filter
|
||||
|
||||
report.total = UserProfile.sum(:views)
|
||||
report.prev30Days = UserProfileView.where("viewed_at >= ? AND viewed_at < ?", start_date - 30.days, start_date + 1).count
|
||||
report.prev30Days = UserProfileView.where('viewed_at >= ? AND viewed_at < ?', start_date - 30.days, start_date + 1).count
|
||||
end
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
Report.add_report("signups") do |report|
|
||||
report.group_filtering = true
|
||||
|
||||
Report.add_report('signups') do |report|
|
||||
report.icon = 'user-plus'
|
||||
|
||||
if report.group_id
|
||||
basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, report.group_id
|
||||
group_filter = report.filters.dig(:group)
|
||||
report.add_filter('group', default: group_filter)
|
||||
|
||||
if group_filter
|
||||
basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, group_filter
|
||||
add_counts report, User.real, 'users.created_at'
|
||||
else
|
||||
report_about report, User.real, :count_by_signup_date
|
||||
end
|
||||
|
||||
# add_prev_data report, User.real, :count_by_signup_date, report.prev_start_date, report.prev_end_date
|
||||
end
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
Report.add_report("time_to_first_response") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('time_to_first_response') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.icon = 'reply'
|
||||
report.higher_is_better = false
|
||||
report.data = []
|
||||
Topic.time_to_first_response_per_day(report.start_date, report.end_date, category_id: report.category_id).each do |r|
|
||||
report.data << { x: r["date"], y: r["hours"].to_f.round(2) }
|
||||
|
||||
Topic.time_to_first_response_per_day(report.start_date, report.end_date, category_id: category_filter).each do |r|
|
||||
report.data << { x: r['date'], y: r['hours'].to_f.round(2) }
|
||||
end
|
||||
report.total = Topic.time_to_first_response_total(category_id: report.category_id)
|
||||
report.prev30Days = Topic.time_to_first_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: report.category_id)
|
||||
|
||||
report.total = Topic.time_to_first_response_total(category_id: category_filter)
|
||||
|
||||
report.prev30Days = Topic.time_to_first_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_filter)
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
Report.add_report("top_referred_topics") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('top_referred_topics') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.modes = [:table]
|
||||
|
||||
|
@ -10,12 +11,12 @@ Report.add_report("top_referred_topics") do |report|
|
|||
title: :topic_title,
|
||||
id: :topic_id
|
||||
},
|
||||
title: I18n.t("reports.top_referred_topics.labels.topic")
|
||||
title: I18n.t('reports.top_referred_topics.labels.topic')
|
||||
},
|
||||
{
|
||||
property: :num_clicks,
|
||||
type: :number,
|
||||
title: I18n.t("reports.top_referred_topics.labels.num_clicks")
|
||||
title: I18n.t('reports.top_referred_topics.labels.num_clicks')
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -23,7 +24,7 @@ Report.add_report("top_referred_topics") do |report|
|
|||
end_date: report.end_date,
|
||||
start_date: report.start_date,
|
||||
limit: report.limit || 8,
|
||||
category_id: report.category_id
|
||||
category_id: category_filter
|
||||
}
|
||||
result = nil
|
||||
result = IncomingLinksReport.find(:top_referred_topics, options)
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
Report.add_report("top_traffic_sources") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('top_traffic_sources') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.modes = [:table]
|
||||
|
||||
report.labels = [
|
||||
{
|
||||
property: :domain,
|
||||
title: I18n.t("reports.top_traffic_sources.labels.domain")
|
||||
title: I18n.t('reports.top_traffic_sources.labels.domain')
|
||||
},
|
||||
{
|
||||
property: :num_clicks,
|
||||
type: :number,
|
||||
title: I18n.t("reports.top_traffic_sources.labels.num_clicks")
|
||||
title: I18n.t('reports.top_traffic_sources.labels.num_clicks')
|
||||
},
|
||||
{
|
||||
property: :num_topics,
|
||||
type: :number,
|
||||
title: I18n.t("reports.top_traffic_sources.labels.num_topics")
|
||||
title: I18n.t('reports.top_traffic_sources.labels.num_topics')
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -24,7 +25,7 @@ Report.add_report("top_traffic_sources") do |report|
|
|||
end_date: report.end_date,
|
||||
start_date: report.start_date,
|
||||
limit: report.limit || 8,
|
||||
category_id: report.category_id
|
||||
category_id: category_filter
|
||||
}
|
||||
|
||||
result = IncomingLinksReport.find(:top_traffic_sources, options)
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
Report.add_report("top_uploads") do |report|
|
||||
Report.add_report('top_uploads') do |report|
|
||||
report.modes = [:table]
|
||||
|
||||
report.filter_options = [
|
||||
{
|
||||
id: "file-extension",
|
||||
selected: report.filter_values.fetch("file-extension", "any"),
|
||||
choices: (SiteSetting.authorized_extensions.split("|") + report.filter_values.values).uniq,
|
||||
allowAny: true
|
||||
}
|
||||
]
|
||||
extension_filter = report.filters.dig(:"file-extension")
|
||||
report.add_filter('file-extension',
|
||||
default: extension_filter || 'any',
|
||||
choices: (
|
||||
SiteSetting.authorized_extensions.split('|') + Array(extension_filter)
|
||||
).uniq
|
||||
)
|
||||
|
||||
report.labels = [
|
||||
{
|
||||
|
@ -59,12 +58,15 @@ Report.add_report("top_uploads") do |report|
|
|||
LIMIT #{report.limit || 250}
|
||||
SQL
|
||||
|
||||
extension_filter = report.filter_values["file-extension"]
|
||||
builder = DB.build(sql)
|
||||
builder.where("up.id > :seeded_id_threshold", seeded_id_threshold: Upload::SEEDED_ID_THRESHOLD)
|
||||
builder.where("up.created_at >= :start_date", start_date: report.start_date)
|
||||
builder.where("up.created_at < :end_date", end_date: report.end_date)
|
||||
builder.where("up.extension = :extension", extension: extension_filter) if extension_filter.present?
|
||||
|
||||
if extension_filter
|
||||
builder.where("up.extension = :extension", extension: extension_filter)
|
||||
end
|
||||
|
||||
builder.query.each do |row|
|
||||
data = {}
|
||||
data[:author_id] = row.user_id
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
Report.add_report("topics") do |report|
|
||||
report.category_filtering = true
|
||||
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date, report.category_id
|
||||
Report.add_report('topics') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date, category_filter
|
||||
|
||||
countable = Topic.listable_topics
|
||||
countable = countable.in_category_and_subcategories(report.category_id) if report.category_id
|
||||
if category_filter
|
||||
countable = countable.in_category_and_subcategories(category_filter)
|
||||
end
|
||||
add_counts report, countable, 'topics.created_at'
|
||||
end
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
Report.add_report("topics_with_no_response") do |report|
|
||||
report.category_filtering = true
|
||||
Report.add_report('topics_with_no_response') do |report|
|
||||
category_filter = report.filters.dig(:category)
|
||||
report.add_filter('category', default: category_filter)
|
||||
|
||||
report.data = []
|
||||
Topic.with_no_response_per_day(report.start_date, report.end_date, report.category_id).each do |r|
|
||||
report.data << { x: r["date"], y: r["count"].to_i }
|
||||
Topic.with_no_response_per_day(report.start_date, report.end_date, category_filter).each do |r|
|
||||
report.data << { x: r['date'], y: r['count'].to_i }
|
||||
end
|
||||
report.total = Topic.with_no_response_total(category_id: report.category_id)
|
||||
report.prev30Days = Topic.with_no_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: report.category_id)
|
||||
|
||||
report.total = Topic.with_no_response_total(category_id: category_filter)
|
||||
|
||||
report.prev30Days = Topic.with_no_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_filter)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
Report.add_report("visits") do |report|
|
||||
report.group_filtering = true
|
||||
Report.add_report('visits') do |report|
|
||||
group_filter = report.filters.dig(:group)
|
||||
report.add_filter('group', default: group_filter)
|
||||
|
||||
report.icon = 'user'
|
||||
|
||||
basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date, report.group_id
|
||||
basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date, group_filter
|
||||
add_counts report, UserVisit, 'visited_at'
|
||||
|
||||
report.prev30Days = UserVisit.where("visited_at >= ? and visited_at < ?", report.start_date - 30.days, report.start_date).count
|
||||
report.prev30Days = UserVisit.where('visited_at >= ? and visited_at < ?', report.start_date - 30.days, report.start_date).count
|
||||
end
|
||||
|
|
|
@ -3110,6 +3110,13 @@ en:
|
|||
trending_search:
|
||||
more: '<a href="%{basePath}/admin/logs/search_logs">Search logs</a>'
|
||||
disabled: 'Trending search report is disabled. Enable <a href="%{basePath}/admin/site_settings/category/all_results?filter=log%20search%20queries">log search queries</a> to collect data.'
|
||||
filters:
|
||||
file-extension:
|
||||
label: File extension
|
||||
group:
|
||||
label: Group
|
||||
category:
|
||||
label: Category
|
||||
|
||||
commits:
|
||||
latest_changes: "Latest changes: please update often!"
|
||||
|
|
|
@ -20,7 +20,6 @@ describe Report do
|
|||
end
|
||||
|
||||
shared_examples 'category filtering on subcategories' do
|
||||
|
||||
it 'returns the filtered data' do
|
||||
expect(report.total).to eq(1)
|
||||
end
|
||||
|
@ -753,12 +752,12 @@ describe Report do
|
|||
end
|
||||
|
||||
context "with category filtering" do
|
||||
let(:report) { Report.find('flags', category_id: c1.id) }
|
||||
let(:report) { Report.find('flags', filters: { category: c1.id }) }
|
||||
|
||||
include_examples 'category filtering'
|
||||
|
||||
context "on subcategories" do
|
||||
let(:report) { Report.find('flags', category_id: c0.id) }
|
||||
let(:report) { Report.find('flags', filters: { category: c0.id }) }
|
||||
|
||||
include_examples 'category filtering on subcategories'
|
||||
end
|
||||
|
@ -782,12 +781,12 @@ describe Report do
|
|||
end
|
||||
|
||||
context "with category filtering" do
|
||||
let(:report) { Report.find('topics', category_id: c1.id) }
|
||||
let(:report) { Report.find('topics', filters: { category: c1.id }) }
|
||||
|
||||
include_examples 'category filtering'
|
||||
|
||||
context "on subcategories" do
|
||||
let(:report) { Report.find('topics', category_id: c0.id) }
|
||||
let(:report) { Report.find('topics', filters: { category: c0.id }) }
|
||||
|
||||
include_examples 'category filtering on subcategories'
|
||||
end
|
||||
|
@ -872,12 +871,12 @@ describe Report do
|
|||
end
|
||||
|
||||
context "with category filtering" do
|
||||
let(:report) { Report.find('posts', category_id: c1.id) }
|
||||
let(:report) { Report.find('posts', filters: { category: c1.id }) }
|
||||
|
||||
include_examples 'category filtering'
|
||||
|
||||
context "on subcategories" do
|
||||
let(:report) { Report.find('posts', category_id: c0.id) }
|
||||
let(:report) { Report.find('posts', filters: { category: c0.id }) }
|
||||
|
||||
include_examples 'category filtering on subcategories'
|
||||
end
|
||||
|
@ -903,12 +902,12 @@ describe Report do
|
|||
end
|
||||
|
||||
context "with category filtering" do
|
||||
let(:report) { Report.find('topics_with_no_response', category_id: c1.id) }
|
||||
let(:report) { Report.find('topics_with_no_response', filters: { category: c1.id }) }
|
||||
|
||||
include_examples 'category filtering'
|
||||
|
||||
context "on subcategories" do
|
||||
let(:report) { Report.find('topics_with_no_response', category_id: c0.id) }
|
||||
let(:report) { Report.find('topics_with_no_response', filters: { category: c0.id }) }
|
||||
|
||||
include_examples 'category filtering on subcategories'
|
||||
end
|
||||
|
@ -939,12 +938,12 @@ describe Report do
|
|||
end
|
||||
|
||||
context "with category filtering" do
|
||||
let(:report) { Report.find('likes', category_id: c1.id) }
|
||||
let(:report) { Report.find('likes', filters: { category: c1.id }) }
|
||||
|
||||
include_examples 'category filtering'
|
||||
|
||||
context "on subcategories" do
|
||||
let(:report) { Report.find('likes', category_id: c0.id) }
|
||||
let(:report) { Report.find('likes', filters: { category: c0.id }) }
|
||||
|
||||
include_examples 'category filtering on subcategories'
|
||||
end
|
||||
|
|
|
@ -4,6 +4,18 @@ acceptance("Dashboard", {
|
|||
loggedIn: true,
|
||||
settings: {
|
||||
dashboard_general_tab_activity_metrics: "page_view_total_reqs"
|
||||
},
|
||||
site: {
|
||||
groups: [
|
||||
{
|
||||
id: 88,
|
||||
name: "tl1"
|
||||
},
|
||||
{
|
||||
id: 89,
|
||||
name: "tl2"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -86,3 +98,17 @@ QUnit.test("reports tab", async assert => {
|
|||
"filter is case insensitive"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("report filters", async assert => {
|
||||
await visit(
|
||||
'/admin/reports/signups?end_date=2018-07-16&filters=%7B"group"%3A88%7D&start_date=2018-06-16'
|
||||
);
|
||||
|
||||
const groupFilter = selectKit(".group-filter .combo-box");
|
||||
|
||||
assert.equal(
|
||||
groupFilter.header().value(),
|
||||
88,
|
||||
"its set the value of the filter from the query params"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -57,21 +57,20 @@ let signups = {
|
|||
],
|
||||
prev_start_date: "2018-05-17T00:00:00Z",
|
||||
prev_end_date: "2018-06-17T00:00:00Z",
|
||||
category_id: null,
|
||||
group_id: null,
|
||||
prev30Days: null,
|
||||
dates_filtering: true,
|
||||
report_key: "reports:signups::20180616:20180716::[:prev_period]:",
|
||||
report_key:
|
||||
'reports:signups:20180616:20180716:[:prev_period]:50:{"group":"88"}:4',
|
||||
available_filters: [
|
||||
{ id: "group", allow_any: false, choices: [], default: "88" }
|
||||
],
|
||||
labels: [
|
||||
{ type: "date", properties: ["x"], title: "Day" },
|
||||
{ type: "number", properties: ["y"], title: "Count" }
|
||||
],
|
||||
processing: false,
|
||||
average: false,
|
||||
percent: false,
|
||||
higher_is_better: true,
|
||||
category_filtering: false,
|
||||
group_filtering: true,
|
||||
modes: ["table", "chart"],
|
||||
prev_period: 961
|
||||
};
|
||||
|
@ -158,8 +157,6 @@ const page_view_total_reqs = {
|
|||
prev_data: null,
|
||||
prev_start_date: "2018-06-20T00:00:00Z",
|
||||
prev_end_date: "2018-07-23T00:00:00Z",
|
||||
category_id: null,
|
||||
group_id: null,
|
||||
prev30Days: 58110,
|
||||
dates_filtering: true,
|
||||
report_key: `reports:page_view_total_reqs:${startDate.format(
|
||||
|
@ -169,12 +166,9 @@ const page_view_total_reqs = {
|
|||
{ type: "date", property: "x", title: "Day" },
|
||||
{ type: "number", property: "y", title: "Count" }
|
||||
],
|
||||
processing: false,
|
||||
average: false,
|
||||
percent: false,
|
||||
higher_is_better: true,
|
||||
category_filtering: false,
|
||||
group_filtering: false,
|
||||
modes: ["table", "chart"],
|
||||
icon: "file",
|
||||
total: 921672
|
||||
|
|
Loading…
Reference in New Issue
Block a user