mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: Export any type of report supporting table mode. (#7662)
This commit is contained in:
parent
847f2943e8
commit
b2eb0f4ad6
@ -55,7 +55,7 @@ export default Ember.Component.extend({
|
|||||||
showTitle: true,
|
showTitle: true,
|
||||||
showFilteringUI: false,
|
showFilteringUI: false,
|
||||||
showDatesOptions: Ember.computed.alias("model.dates_filtering"),
|
showDatesOptions: Ember.computed.alias("model.dates_filtering"),
|
||||||
showExport: Ember.computed.not("model.onlyTable"),
|
showExport: Ember.computed.not("model.isTable"),
|
||||||
showRefresh: Ember.computed.or(
|
showRefresh: Ember.computed.or(
|
||||||
"showDatesOptions",
|
"showDatesOptions",
|
||||||
"model.available_filters.length"
|
"model.available_filters.length"
|
||||||
@ -170,8 +170,9 @@ export default Ember.Component.extend({
|
|||||||
"[:prev_period]",
|
"[:prev_period]",
|
||||||
this.get("reportOptions.table.limit"),
|
this.get("reportOptions.table.limit"),
|
||||||
customFilters
|
customFilters
|
||||||
? JSON.stringify(customFilters, (key, value) =>
|
? JSON.stringify(
|
||||||
isNumeric(value) ? value.toString() : value
|
customFilters,
|
||||||
|
(key, value) => (isNumeric(value) ? value.toString() : value)
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
SCHEMA_VERSION
|
SCHEMA_VERSION
|
||||||
|
@ -16,8 +16,8 @@ const Report = Discourse.Model.extend({
|
|||||||
higher_is_better: true,
|
higher_is_better: true,
|
||||||
|
|
||||||
@computed("modes")
|
@computed("modes")
|
||||||
onlyTable(modes) {
|
isTable(modes) {
|
||||||
return modes.length === 1 && modes[0] === "table";
|
return modes.some(mode => mode === "table");
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("type", "start_date", "end_date")
|
@computed("type", "start_date", "end_date")
|
||||||
|
@ -55,7 +55,7 @@ module Jobs
|
|||||||
|
|
||||||
# write to CSV file
|
# write to CSV file
|
||||||
CSV.open(absolute_path, "w") do |csv|
|
CSV.open(absolute_path, "w") do |csv|
|
||||||
csv << get_header
|
csv << get_header if @entity != "report"
|
||||||
public_send(export_method).each { |d| csv << d }
|
public_send(export_method).each { |d| csv << d }
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -186,14 +186,23 @@ module Jobs
|
|||||||
@extra[:category_id] = @extra[:category_id].present? ? @extra[:category_id].to_i : nil
|
@extra[:category_id] = @extra[:category_id].present? ? @extra[:category_id].to_i : nil
|
||||||
@extra[:group_id] = @extra[:group_id].present? ? @extra[:group_id].to_i : nil
|
@extra[:group_id] = @extra[:group_id].present? ? @extra[:group_id].to_i : nil
|
||||||
|
|
||||||
report_hash = {}
|
report = Report.find(@extra[:name], @extra)
|
||||||
Report.find(@extra[:name], @extra).data.each do |row|
|
|
||||||
report_hash[row[:x].to_s] = row[:y].to_s
|
header = []
|
||||||
|
titles = {}
|
||||||
|
|
||||||
|
report.labels.each do |label|
|
||||||
|
if label[:type] == :user
|
||||||
|
titles[label[:properties][:username]] = label[:title]
|
||||||
|
header << label[:properties][:username]
|
||||||
|
else
|
||||||
|
titles[label[:property]] = label[:title]
|
||||||
|
header << label[:property]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
(@extra[:start_date].to_date..@extra[:end_date].to_date).each do |date|
|
yield header.map { |k| titles[k] || k }
|
||||||
yield [date.to_s(:db), report_hash.fetch(date.to_s, 0)]
|
report.data.each { |row| yield row.values_at(*header).map(&:to_s) }
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_header
|
def get_header
|
||||||
|
@ -17,6 +17,21 @@ class Report
|
|||||||
30
|
30
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.default_labels
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: :date,
|
||||||
|
property: :x,
|
||||||
|
title: I18n.t("reports.default.labels.day")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: :number,
|
||||||
|
property: :y,
|
||||||
|
title: I18n.t("reports.default.labels.count")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(type)
|
def initialize(type)
|
||||||
@type = type
|
@type = type
|
||||||
@start_date ||= Report.default_days.days.ago.utc.beginning_of_day
|
@start_date ||= Report.default_days.days.ago.utc.beginning_of_day
|
||||||
@ -102,18 +117,7 @@ class Report
|
|||||||
primary_color: self.primary_color,
|
primary_color: self.primary_color,
|
||||||
secondary_color: self.secondary_color,
|
secondary_color: self.secondary_color,
|
||||||
available_filters: self.available_filters.map { |k, v| { id: k }.merge(v) },
|
available_filters: self.available_filters.map { |k, v| { id: k }.merge(v) },
|
||||||
labels: labels || [
|
labels: labels || Report.default_labels,
|
||||||
{
|
|
||||||
type: :date,
|
|
||||||
property: :x,
|
|
||||||
title: I18n.t("reports.default.labels.day")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: :number,
|
|
||||||
property: :y,
|
|
||||||
title: I18n.t("reports.default.labels.count")
|
|
||||||
},
|
|
||||||
],
|
|
||||||
average: self.average,
|
average: self.average,
|
||||||
percent: self.percent,
|
percent: self.percent,
|
||||||
higher_is_better: self.higher_is_better,
|
higher_is_better: self.higher_is_better,
|
||||||
|
@ -42,6 +42,43 @@ describe Jobs::ExportCsvFile do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context '.report_export' do
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:admin) }
|
||||||
|
|
||||||
|
let(:exporter) do
|
||||||
|
exporter = Jobs::ExportCsvFile.new
|
||||||
|
exporter.instance_variable_set(:@entity, 'report')
|
||||||
|
exporter.instance_variable_set(:@extra, HashWithIndifferentAccess.new(start_date: '2010-01-01', end_date: '2011-01-01'))
|
||||||
|
exporter.instance_variable_set(:@current_user, User.find_by(id: user.id))
|
||||||
|
exporter
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works with single-column reports' do
|
||||||
|
user.user_visits.create!(visited_at: '2010-01-01', posts_read: 42)
|
||||||
|
Fabricate(:user).user_visits.create!(visited_at: '2010-01-03', posts_read: 420)
|
||||||
|
|
||||||
|
exporter.instance_variable_get(:@extra)['name'] = 'dau_by_mau'
|
||||||
|
report = exporter.report_export.to_a
|
||||||
|
|
||||||
|
expect(report.first).to contain_exactly("Day", "Percent")
|
||||||
|
expect(report.second).to contain_exactly("2010-01-01", "100.0")
|
||||||
|
expect(report.third).to contain_exactly("2010-01-03", "50.0")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works with multi-columns reports' do
|
||||||
|
DiscourseIpInfo.stubs(:get).with("1.1.1.1").returns(location: "Earth")
|
||||||
|
user.user_auth_token_logs.create!(action: "login", client_ip: "1.1.1.1", created_at: '2010-01-01')
|
||||||
|
|
||||||
|
exporter.instance_variable_get(:@extra)['name'] = 'staff_logins'
|
||||||
|
report = exporter.report_export.to_a
|
||||||
|
|
||||||
|
expect(report.first).to contain_exactly("User", "Location", "Login at")
|
||||||
|
expect(report.second).to contain_exactly(user.username, "Earth", "2010-01-01 00:00:00 UTC")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
let(:user_list_header) {
|
let(:user_list_header) {
|
||||||
%w{
|
%w{
|
||||||
id name username email title created_at last_seen_at last_posted_at
|
id name username email title created_at last_seen_at last_posted_at
|
||||||
|
Loading…
Reference in New Issue
Block a user