diff --git a/app/assets/javascripts/admin/components/admin-report.js.es6 b/app/assets/javascripts/admin/components/admin-report.js.es6
index c7f03112084..05babdbdf45 100644
--- a/app/assets/javascripts/admin/components/admin-report.js.es6
+++ b/app/assets/javascripts/admin/components/admin-report.js.es6
@@ -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) {
diff --git a/app/assets/javascripts/admin/components/report-filters/category.js.es6 b/app/assets/javascripts/admin/components/report-filters/category.js.es6
new file mode 100644
index 00000000000..d1c910ad18d
--- /dev/null
+++ b/app/assets/javascripts/admin/components/report-filters/category.js.es6
@@ -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);
+ }
+});
diff --git a/app/assets/javascripts/admin/components/report-filters/file-extension.js.es6 b/app/assets/javascripts/admin/components/report-filters/file-extension.js.es6
new file mode 100644
index 00000000000..d8eb1b5b062
--- /dev/null
+++ b/app/assets/javascripts/admin/components/report-filters/file-extension.js.es6
@@ -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"
+});
diff --git a/app/assets/javascripts/admin/components/report-filters/filter.js.es6 b/app/assets/javascripts/admin/components/report-filters/filter.js.es6
new file mode 100644
index 00000000000..25f2464f951
--- /dev/null
+++ b/app/assets/javascripts/admin/components/report-filters/filter.js.es6
@@ -0,0 +1,7 @@
+export default Ember.Component.extend({
+ actions: {
+ onChange(value) {
+ this.applyFilter(this.get("filter.id"), value);
+ }
+ }
+});
diff --git a/app/assets/javascripts/admin/components/report-filters/group.js.es6 b/app/assets/javascripts/admin/components/report-filters/group.js.es6
new file mode 100644
index 00000000000..54523f9446e
--- /dev/null
+++ b/app/assets/javascripts/admin/components/report-filters/group.js.es6
@@ -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;
+ }
+});
diff --git a/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6
index 8c773181ed9..2a78ece7f41 100644
--- a/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6
@@ -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
- });
- }
}
});
diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6
index 19a1579e5db..0f030b509ba 100644
--- a/app/assets/javascripts/admin/models/report.js.es6
+++ b/app/assets/javascripts/admin/models/report.js.es6
@@ -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,
diff --git a/app/assets/javascripts/admin/routes/admin-reports-show.js.es6 b/app/assets/javascripts/admin/routes/admin-reports-show.js.es6
index 55503091e13..9bf9ff8ebaf 100644
--- a/app/assets/javascripts/admin/routes/admin-reports-show.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-reports-show.js.es6
@@ -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 });
}
}
});
diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs
index 888be8dd22d..7181ac3dd11 100644
--- a/app/assets/javascripts/admin/templates/components/admin-report.hbs
+++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs
@@ -149,38 +149,17 @@
{{/if}}
- {{#if showCategoryOptions}}
+ {{#each model.available_filters as |filter|}}
-
- {{search-advanced-category-chooser
- filterable=true
- value=category
- castInteger=true}}
-
-
- {{/if}}
+
+ {{i18n (concat "admin.dashboard.reports.filters." filter.id ".label")}}
+
- {{#if showGroupOptions}}
-
- {{combo-box
- castInteger=true
- filterable=true
- valueAttribute="value"
- content=groupOptions
- value=groupId}}
-
-
- {{/if}}
-
- {{#each filterOptions as |filterOption|}}
-
-
- {{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")}}
{{/each}}
diff --git a/app/assets/javascripts/admin/templates/components/report-filters/category.hbs b/app/assets/javascripts/admin/templates/components/report-filters/category.hbs
new file mode 100644
index 00000000000..9ad96c6be60
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/components/report-filters/category.hbs
@@ -0,0 +1,6 @@
+{{search-advanced-category-chooser
+ filterable=true
+ value=category
+ castInteger=true
+ onSelectNone=(action "onChange")
+ onSelect=(action "onChange")}}
diff --git a/app/assets/javascripts/admin/templates/components/report-filters/file-extension.hbs b/app/assets/javascripts/admin/templates/components/report-filters/file-extension.hbs
new file mode 100644
index 00000000000..871179d63d6
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/components/report-filters/file-extension.hbs
@@ -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")}}
diff --git a/app/assets/javascripts/admin/templates/components/report-filters/group.hbs b/app/assets/javascripts/admin/templates/components/report-filters/group.hbs
new file mode 100644
index 00000000000..0209c1cb6e8
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/components/report-filters/group.hbs
@@ -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")}}
diff --git a/app/assets/javascripts/admin/templates/reports-show.hbs b/app/assets/javascripts/admin/templates/reports-show.hbs
index 899a8ebd9e7..dac1aa0bbe0 100644
--- a/app/assets/javascripts/admin/templates/reports-show.hbs
+++ b/app/assets/javascripts/admin/templates/reports-show.hbs
@@ -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")}}
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index fa5a6e374df..8143d099f7b 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -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
}
diff --git a/app/models/report.rb b/app/models/report.rb
index 67bcb26d82f..0fb79f2f3e2 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -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
diff --git a/app/models/reports/bookmarks.rb b/app/models/reports/bookmarks.rb
index 1752b560ccb..2a98071c3fa 100644
--- a/app/models/reports/bookmarks.rb
+++ b/app/models/reports/bookmarks.rb
@@ -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
diff --git a/app/models/reports/flags.rb b/app/models/reports/flags.rb
index 8d66da9fd0f..0241089b16f 100644
--- a/app/models/reports/flags.rb
+++ b/app/models/reports/flags.rb
@@ -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
diff --git a/app/models/reports/likes.rb b/app/models/reports/likes.rb
index 0212da61e0d..37f7ea3176e 100644
--- a/app/models/reports/likes.rb
+++ b/app/models/reports/likes.rb
@@ -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
diff --git a/app/models/reports/post_edits.rb b/app/models/reports/post_edits.rb
index a708f4345af..43c039cc0c7 100644
--- a/app/models/reports/post_edits.rb
+++ b/app/models/reports/post_edits.rb
@@ -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 = {}
diff --git a/app/models/reports/posts.rb b/app/models/reports/posts.rb
index 7e7e1f59c0c..51ecdcd8b9a 100644
--- a/app/models/reports/posts.rb
+++ b/app/models/reports/posts.rb
@@ -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
diff --git a/app/models/reports/profile_views.rb b/app/models/reports/profile_views.rb
index a9123da0091..029740d71ec 100644
--- a/app/models/reports/profile_views.rb
+++ b/app/models/reports/profile_views.rb
@@ -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
diff --git a/app/models/reports/signups.rb b/app/models/reports/signups.rb
index e9646cd8c63..0531557325e 100644
--- a/app/models/reports/signups.rb
+++ b/app/models/reports/signups.rb
@@ -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
diff --git a/app/models/reports/time_to_first_response.rb b/app/models/reports/time_to_first_response.rb
index 33342b77b5b..d5c9ebf298a 100644
--- a/app/models/reports/time_to_first_response.rb
+++ b/app/models/reports/time_to_first_response.rb
@@ -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
diff --git a/app/models/reports/top_referred_topics.rb b/app/models/reports/top_referred_topics.rb
index 635aab136ce..a818215ff86 100644
--- a/app/models/reports/top_referred_topics.rb
+++ b/app/models/reports/top_referred_topics.rb
@@ -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)
diff --git a/app/models/reports/top_traffic_sources.rb b/app/models/reports/top_traffic_sources.rb
index 45c0ee91461..90fcb92ce5a 100644
--- a/app/models/reports/top_traffic_sources.rb
+++ b/app/models/reports/top_traffic_sources.rb
@@ -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)
diff --git a/app/models/reports/top_uploads.rb b/app/models/reports/top_uploads.rb
index f52c9e41a50..c27790a3775 100644
--- a/app/models/reports/top_uploads.rb
+++ b/app/models/reports/top_uploads.rb
@@ -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
diff --git a/app/models/reports/topics.rb b/app/models/reports/topics.rb
index 851700f18a8..6994ae0f12b 100644
--- a/app/models/reports/topics.rb
+++ b/app/models/reports/topics.rb
@@ -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
diff --git a/app/models/reports/topics_with_no_response.rb b/app/models/reports/topics_with_no_response.rb
index 2b1d434db83..123da140b0e 100644
--- a/app/models/reports/topics_with_no_response.rb
+++ b/app/models/reports/topics_with_no_response.rb
@@ -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
diff --git a/app/models/reports/visits.rb b/app/models/reports/visits.rb
index 4d95537c194..9e38b032b25 100644
--- a/app/models/reports/visits.rb
+++ b/app/models/reports/visits.rb
@@ -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
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 859b845e850..6d217d85c46 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -3110,6 +3110,13 @@ en:
trending_search:
more: 'Search logs'
disabled: 'Trending search report is disabled. Enable log search queries to collect data.'
+ filters:
+ file-extension:
+ label: File extension
+ group:
+ label: Group
+ category:
+ label: Category
commits:
latest_changes: "Latest changes: please update often!"
diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb
index 4efcbead189..6843ac9af55 100644
--- a/spec/models/report_spec.rb
+++ b/spec/models/report_spec.rb
@@ -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
diff --git a/test/javascripts/acceptance/dashboard-test.js.es6 b/test/javascripts/acceptance/dashboard-test.js.es6
index 3a9f7011746..1a7675dac9a 100644
--- a/test/javascripts/acceptance/dashboard-test.js.es6
+++ b/test/javascripts/acceptance/dashboard-test.js.es6
@@ -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"
+ );
+});
diff --git a/test/javascripts/fixtures/reports_bulk.js.es6 b/test/javascripts/fixtures/reports_bulk.js.es6
index 2e581278e0f..d12eb9377ab 100644
--- a/test/javascripts/fixtures/reports_bulk.js.es6
+++ b/test/javascripts/fixtures/reports_bulk.js.es6
@@ -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