UX: improve new dashboard

- top referred topics
- limit search logs to 8 results
This commit is contained in:
Sam 2018-05-15 15:08:23 +10:00
parent 8d6a9eb511
commit 193b6d5651
12 changed files with 126 additions and 144 deletions

View File

@ -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);

View File

@ -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"]
});

View File

@ -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);
};
});
}
});

View File

@ -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")

View File

@ -17,15 +17,15 @@
</tr>
</thead>
<tbody>
<tr>
{{#unless hasBlock}}
{{#each values as |value|}}
{{#unless hasBlock}}
{{#each values as |value|}}
<tr>
<td>{{number value}}</td>
{{/each}}
{{else}}
{{yield (hash report=report)}}
{{/unless}}
</tr>
</tr>
{{/each}}
{{else}}
{{yield (hash report=report)}}
{{/unless}}
</tbody>
</table>
</div>

View File

@ -1,37 +0,0 @@
{{#if isDisabled}}
{{{i18n disabledLabel}}}
{{else}}
{{#conditional-loading-section isLoading=isLoading title=report.title}}
<div class="table-title">
<h3>{{report.title}}</h3>
{{#if help}}
<a href="{{helpPage}}">{{i18n help}}</a>
{{/if}}
</div>
<div class="table-container">
<table>
<thead>
<tr>
{{#each labels as |label|}}
<th>{{label}}</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each values as |value|}}
<tr>
{{#each value as |v|}}
<td>{{v}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
{{yield}}
</div>
{{/conditional-loading-section}}
{{/if}}

View File

@ -87,6 +87,7 @@
</div>
{{#dashboard-inline-table dataSourceName="users_by_type" lastRefreshedAt=lastRefreshedAt as |context|}}
<tr>
{{#each context.report.data as |data|}}
<td>
<a href="/admin/users/list/{{data.key}}">
@ -94,9 +95,11 @@
</a>
</td>
{{/each}}
</tr>
{{/dashboard-inline-table}}
{{#dashboard-inline-table dataSourceName="users_by_trust_level" lastRefreshedAt=lastRefreshedAt as |context|}}
<tr>
{{#each context.report.data as |data|}}
<td>
<a href="/admin/users/list/{{data.key}}">
@ -104,6 +107,7 @@
</a>
</td>
{{/each}}
</tr>
{{/dashboard-inline-table}}
{{#conditional-loading-section isLoading=isLoading title=(i18n "admin.dashboard.backups")}}
@ -148,13 +152,47 @@
</div>
<div class="section-column">
{{#dashboard-table-trending-search
{{#dashboard-inline-table
dataSourceName="top_referred_topics"
lastRefreshedAt=lastRefreshedAt
limit=8
as |context|}}
{{#each context.report.data as |data|}}
<tr>
<td class='left'>
<a href="{{data.topic_url}}">
{{data.topic_title}}
</a>
</td>
<td>
{{data.num_clicks}}
</td>
</tr>
{{/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|}}
<tr>
<td class='left'>
{{data.term}}
</td>
<td>
{{number data.unique_searches}}
</td>
<td>
{{data.ctr}}
</td>
</tr>
{{/each}}
{{{i18n "admin.dashboard.reports.trending_search.more"}}}
{{/dashboard-table-trending-search}}
</div>
{{/dashboard-inline-table}}
</div>
</div>

View File

@ -120,6 +120,9 @@
border: 1px solid $primary-low;
text-align: center;
}
td.left {
text-align: left;
}
td.value {
i {

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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