diff --git a/app/assets/javascripts/admin/components/dashboard-inline-table.js.es6 b/app/assets/javascripts/admin/components/dashboard-inline-table.js.es6 index 22443906acb..7a1720db3e7 100644 --- a/app/assets/javascripts/admin/components/dashboard-inline-table.js.es6 +++ b/app/assets/javascripts/admin/components/dashboard-inline-table.js.es6 @@ -8,12 +8,31 @@ export default Ember.Component.extend(AsyncReport, { help: null, helpPage: null, + loadReport(report_json) { + this._setPropertiesFromReport(Report.create(report_json)); + }, + fetchReport() { this.set("isLoading", true); - ajax(this.get("dataSource")) + let payload = { data: { async: true } }; + + if (this.get("startDate")) { + payload.data.start_date = this.get("startDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ"); + } + + if (this.get("endDate")) { + payload.data.end_date = this.get("endDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ"); + } + + if (this.get("limit")) { + payload.data.limit = this.get("limit"); + } + + ajax(this.get("dataSource"), payload) .then((response) => { - this._setPropertiesFromReport(Report.create(response.report)); + this.set('reportKey', response.report.report_key); + this.loadReport(response.report); }).finally(() => { if (!Ember.isEmpty(this.get("report.data"))) { this.set("isLoading", false); diff --git a/app/assets/javascripts/admin/components/dashboard-table-trending-search.js.es6 b/app/assets/javascripts/admin/components/dashboard-table-trending-search.js.es6 deleted file mode 100644 index f6523f6841b..00000000000 --- a/app/assets/javascripts/admin/components/dashboard-table-trending-search.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import DashboardTable from "admin/components/dashboard-table"; -import AsyncReport from "admin/mixins/async-report"; - -export default DashboardTable.extend(AsyncReport, { - layoutName: "admin/templates/components/dashboard-table", - - classNames: ["dashboard-table", "dashboard-table-trending-search"] -}); diff --git a/app/assets/javascripts/admin/components/dashboard-table.js.es6 b/app/assets/javascripts/admin/components/dashboard-table.js.es6 deleted file mode 100644 index 6db70f9bb89..00000000000 --- a/app/assets/javascripts/admin/components/dashboard-table.js.es6 +++ /dev/null @@ -1,59 +0,0 @@ -import { ajax } from "discourse/lib/ajax"; -import Report from "admin/models/report"; -import AsyncReport from "admin/mixins/async-report"; -import computed from "ember-addons/ember-computed-decorators"; -import { number } from 'discourse/lib/formatter'; - -export default Ember.Component.extend(AsyncReport, { - classNames: ["dashboard-table"], - classNameBindings : ["isDisabled"], - help: null, - helpPage: null, - isDisabled: Ember.computed.not("siteSettings.log_search_queries"), - disabledLabel: "admin.dashboard.reports.disabled", - - @computed("report") - values(report) { - if (!report) return; - return Ember.makeArray(report.data) - .map(x => { - return [ x[0], number(x[1]), x[2] ]; - }); - }, - - @computed("report") - labels(report) { - if (!report) return; - return Ember.makeArray(report.labels); - }, - - loadReport(report_json) { - this._setPropertiesFromReport(Report.create(report_json)); - }, - - fetchReport() { - if (this.get("isDisabled")) return; - - this.set("isLoading", true); - - let payload = { data: { async: true } }; - - if (this.get("startDate")) { - payload.data.start_date = this.get("startDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ"); - } - - if (this.get("endDate")) { - payload.data.end_date = this.get("endDate").format("YYYY-MM-DD[T]HH:mm:ss.SSSZZ"); - } - - ajax(this.get("dataSource"), payload) - .then((response) => { - this.set('reportKey', response.report.report_key); - this.loadReport(response.report); - }).finally(() => { - if (!Ember.isEmpty(this.get("report.data"))) { - this.set("isLoading", false); - }; - }); - } -}); diff --git a/app/assets/javascripts/admin/mixins/async-report.js.es6 b/app/assets/javascripts/admin/mixins/async-report.js.es6 index c06c01ef141..12b267b059e 100644 --- a/app/assets/javascripts/admin/mixins/async-report.js.es6 +++ b/app/assets/javascripts/admin/mixins/async-report.js.es6 @@ -57,7 +57,11 @@ export default Ember.Mixin.create({ @computed("report") labels(report) { if (!report) return; - return Ember.makeArray(report.data).map(r => r.x); + if (report.labels) { + return Ember.makeArray(report.labels); + } else { + return Ember.makeArray(report.data).map(r => r.x); + } }, @computed("report") diff --git a/app/assets/javascripts/admin/templates/components/dashboard-inline-table.hbs b/app/assets/javascripts/admin/templates/components/dashboard-inline-table.hbs index 9e97de2f469..ce075761a5d 100644 --- a/app/assets/javascripts/admin/templates/components/dashboard-inline-table.hbs +++ b/app/assets/javascripts/admin/templates/components/dashboard-inline-table.hbs @@ -17,15 +17,15 @@ - - {{#unless hasBlock}} - {{#each values as |value|}} + {{#unless hasBlock}} + {{#each values as |value|}} + {{number value}} - {{/each}} - {{else}} - {{yield (hash report=report)}} - {{/unless}} - + + {{/each}} + {{else}} + {{yield (hash report=report)}} + {{/unless}} diff --git a/app/assets/javascripts/admin/templates/components/dashboard-table.hbs b/app/assets/javascripts/admin/templates/components/dashboard-table.hbs deleted file mode 100644 index 5055d04175d..00000000000 --- a/app/assets/javascripts/admin/templates/components/dashboard-table.hbs +++ /dev/null @@ -1,37 +0,0 @@ -{{#if isDisabled}} - {{{i18n disabledLabel}}} -{{else}} - {{#conditional-loading-section isLoading=isLoading title=report.title}} -
-

{{report.title}}

- - {{#if help}} - {{i18n help}} - {{/if}} -
- -
- - - - {{#each labels as |label|}} - - {{/each}} - - - - - {{#each values as |value|}} - - {{#each value as |v|}} - - {{/each}} - - {{/each}} - -
{{label}}
{{v}}
- - {{yield}} -
- {{/conditional-loading-section}} -{{/if}} diff --git a/app/assets/javascripts/admin/templates/dashboard_next.hbs b/app/assets/javascripts/admin/templates/dashboard_next.hbs index d6b0660e55f..d42c25a0417 100644 --- a/app/assets/javascripts/admin/templates/dashboard_next.hbs +++ b/app/assets/javascripts/admin/templates/dashboard_next.hbs @@ -87,6 +87,7 @@ {{#dashboard-inline-table dataSourceName="users_by_type" lastRefreshedAt=lastRefreshedAt as |context|}} + {{#each context.report.data as |data|}} @@ -94,9 +95,11 @@ {{/each}} + {{/dashboard-inline-table}} {{#dashboard-inline-table dataSourceName="users_by_trust_level" lastRefreshedAt=lastRefreshedAt as |context|}} + {{#each context.report.data as |data|}} @@ -104,6 +107,7 @@ {{/each}} + {{/dashboard-inline-table}} {{#conditional-loading-section isLoading=isLoading title=(i18n "admin.dashboard.backups")}} @@ -148,13 +152,47 @@
- {{#dashboard-table-trending-search + {{#dashboard-inline-table + dataSourceName="top_referred_topics" + lastRefreshedAt=lastRefreshedAt + limit=8 + as |context|}} + {{#each context.report.data as |data|}} + + + + {{data.topic_title}} + + + + {{data.num_clicks}} + + + {{/each}} + {{/dashboard-inline-table}} + + {{#dashboard-inline-table + limit=8 dataSourceName="trending_search" isEnabled=logSearchQueriesEnabled disabledLabel="admin.dashboard.reports.trending_search.disabled" startDate=lastWeek - endDate=endDate}} + endDate=endDate as |context|}} + {{#each context.report.data as |data|}} + + + {{data.term}} + + + {{number data.unique_searches}} + + + {{data.ctr}} + + + {{/each}} {{{i18n "admin.dashboard.reports.trending_search.more"}}} - {{/dashboard-table-trending-search}} -
+ {{/dashboard-inline-table}} + + diff --git a/app/assets/stylesheets/common/admin/dashboard_next.scss b/app/assets/stylesheets/common/admin/dashboard_next.scss index afe91b2614f..3e9a9fbcf4f 100644 --- a/app/assets/stylesheets/common/admin/dashboard_next.scss +++ b/app/assets/stylesheets/common/admin/dashboard_next.scss @@ -120,6 +120,9 @@ border: 1px solid $primary-low; text-align: center; } + td.left { + text-align: left; + } td.value { i { diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 2fae3c38d2b..58f3c0454e4 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -27,12 +27,18 @@ class Admin::ReportsController < Admin::AdminController facets = params[:facets].map { |s| s.to_s.to_sym } end + limit = nil + if params.has_key?(:limit) && params[:limit].to_i > 0 + limit = params[:limit].to_i + end + report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id, group_id: group_id, facets: facets, + limit: limit, async: params[:async]) raise Discourse::NotFound if report.blank? diff --git a/app/jobs/regular/retrieve_report.rb b/app/jobs/regular/retrieve_report.rb index 54cac2b8312..2d00ae39838 100644 --- a/app/jobs/regular/retrieve_report.rb +++ b/app/jobs/regular/retrieve_report.rb @@ -14,6 +14,7 @@ module Jobs report.category_id = args['category_id'] if args['category_id'] report.group_id = args['group_id'] if args['group_id'] report.facets = args['facets'].map(&:to_sym) if args['facets'] + report.limit = args['limit'].to_i if args['limit'] Report.send("report_#{type}", report) json = report.as_json diff --git a/app/models/incoming_links_report.rb b/app/models/incoming_links_report.rb index 5e817e18b28..a0d043acfec 100644 --- a/app/models/incoming_links_report.rb +++ b/app/models/incoming_links_report.rb @@ -1,6 +1,6 @@ class IncomingLinksReport - attr_accessor :type, :data, :y_titles + attr_accessor :type, :data, :y_titles, :start_date, :limit def initialize(type) @type = type @@ -14,7 +14,8 @@ class IncomingLinksReport title: I18n.t("reports.#{self.type}.title"), xaxis: I18n.t("reports.#{self.type}.xaxis"), ytitles: self.y_titles, - data: self.data + data: self.data, + start_date: start_date } end @@ -24,6 +25,10 @@ class IncomingLinksReport # Load the report report = IncomingLinksReport.new(type) + + report.start_date = _opts[:start_date] || 30.days.ago + report.limit = _opts[:limit].to_i if _opts[:limit] + send(report_method, report) report end @@ -43,19 +48,19 @@ class IncomingLinksReport report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10] end - def self.per_user + def self.per_user(start_date:) @per_user_query ||= IncomingLink - .where('incoming_links.created_at > ? AND incoming_links.user_id IS NOT NULL', 30.days.ago) + .where('incoming_links.created_at > ? AND incoming_links.user_id IS NOT NULL', start_date) .joins(:user) .group('users.username') end - def self.link_count_per_user - per_user.count + def self.link_count_per_user(start_date:) + per_user(start_date: start_date).count end - def self.topic_count_per_user - per_user.joins(:post).count("DISTINCT posts.topic_id") + def self.topic_count_per_user(start_date:) + per_user(start_date: start_date).joins(:post).count("DISTINCT posts.topic_id") end # Return top 10 domains that brought traffic to the site within the last 30 days @@ -64,7 +69,7 @@ class IncomingLinksReport report.y_titles[:num_topics] = I18n.t("reports.#{report.type}.num_topics") report.y_titles[:num_users] = I18n.t("reports.#{report.type}.num_users") - num_clicks = link_count_per_domain + num_clicks = link_count_per_domain(start_date: start_date) num_topics = topic_count_per_domain(num_clicks.keys) report.data = [] num_clicks.each_key do |domain| @@ -73,8 +78,8 @@ class IncomingLinksReport report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10] end - def self.link_count_per_domain(limit = 10) - IncomingLink.where('incoming_links.created_at > ?', 30.days.ago) + def self.link_count_per_domain(limit: 10, start_date:) + IncomingLink.where('incoming_links.created_at > ?', start_date) .joins(incoming_referer: :incoming_domain) .group('incoming_domains.name') .order('count_all DESC') @@ -95,8 +100,8 @@ class IncomingLinksReport def self.report_top_referred_topics(report) report.y_titles[:num_clicks] = I18n.t("reports.#{report.type}.num_clicks") - num_clicks = link_count_per_topic - num_clicks = num_clicks.to_a.sort_by { |x| x[1] }.last(10).reverse # take the top 10 + num_clicks = link_count_per_topic(start_date: report.start_date) + num_clicks = num_clicks.to_a.sort_by { |x| x[1] }.last(report.limit || 10).reverse report.data = [] topics = Topic.select('id, slug, title').where('id in (?)', num_clicks.map { |z| z[0] }) num_clicks.each do |topic_id, num_clicks_element| @@ -108,9 +113,9 @@ class IncomingLinksReport report.data end - def self.link_count_per_topic + def self.link_count_per_topic(start_date:) IncomingLink.joins(:post) - .where('incoming_links.created_at > ? AND topic_id IS NOT NULL', 30.days.ago) + .where('incoming_links.created_at > ? AND topic_id IS NOT NULL', start_date) .group('topic_id') .count end diff --git a/app/models/report.rb b/app/models/report.rb index 7f87778f232..53e1b1bbb10 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -4,7 +4,7 @@ class Report attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id, :group_id, :labels, :async, - :prev_period, :facets + :prev_period, :facets, :limit def self.default_days 30 @@ -24,7 +24,8 @@ class Report report.start_date.to_date.strftime("%Y%m%d"), report.end_date.to_date.strftime("%Y%m%d"), report.group_id, - report.facets + report.facets, + report.limit ].map(&:to_s).join(':') end @@ -55,6 +56,7 @@ class Report json[:total] = total if total json[:prev_period] = prev_period if prev_period json[:prev30Days] = self.prev30Days if self.prev30Days + json[:limit] = self.limit if self.limit if type == 'page_view_crawler_reqs' json[:related_report] = Report.find('web_crawlers', start_date: start_date, end_date: end_date)&.as_json @@ -77,6 +79,7 @@ class Report report.group_id = opts[:group_id] if opts[:group_id] report.async = opts[:async] || false report.facets = opts[:facets] || [:total, :prev30Days] + report.limit = opts[:limit] if opts[:limit] report_method = :"report_#{type}" if respond_to?(report_method) @@ -405,11 +408,18 @@ class Report report.data << { key: "silenced", x: label.call("silenced"), y: silenced } if silenced > 0 end + def self.report_top_referred_topics(report) + report.labels = [I18n.t("reports.top_referred_topics.xaxis"), + I18n.t("reports.top_referred_topics.num_clicks")] + result = IncomingLinksReport.find(:top_referred_topics, start_date: 7.days.ago, limit: report.limit) + report.data = result.data + end + def self.report_trending_search(report) report.data = [] select_sql = <<~SQL - term, + lower(term) term, COUNT(*) AS searches, SUM(CASE WHEN search_result_id IS NOT NULL THEN 1 @@ -420,9 +430,9 @@ class Report trends = SearchLog.select(select_sql) .where('created_at > ? AND created_at <= ?', report.start_date, report.end_date) - .group(:term) + .group('lower(term)') .order('unique_searches DESC, click_through ASC, term ASC') - .limit(20).to_a + .limit(report.limit || 20).to_a report.labels = [:term, :searches, :click_through].map { |key| I18n.t("reports.trending_search.labels.#{key}") @@ -436,11 +446,11 @@ class Report trend.click_through.to_f / trend.searches.to_f end - report.data << [ - trend.term, - trend.unique_searches, - (ctr * 100).ceil(1).to_s + "%" - ] + report.data << { + term: trend.term, + unique_searches: trend.unique_searches, + ctr: (ctr * 100).ceil(1).to_s + "%" + } end end end