UX: show an enveloppe icon when a badge is used in messages

- the badge count now includes messages
- only show the message badges to admins
This commit is contained in:
Régis Hanol 2018-05-14 19:02:00 +02:00
parent 1e132b4599
commit e9abdaebbe
9 changed files with 110 additions and 60 deletions

View File

@ -1,22 +1,23 @@
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Component.extend({ export default Ember.Component.extend({
classNameBindings: [':tag-list', 'categoryClass'], classNameBindings: [':tag-list', 'categoryClass'],
isPrivateMessage: false, isPrivateMessage: false,
sortedTags: Ember.computed.sort('tags', 'sortProperties'), sortedTags: Ember.computed.sort('tags', 'sortProperties'),
title: function() { @computed("titleKey")
if (this.get('titleKey')) { return I18n.t(this.get('titleKey')); } title(titleKey) {
}.property('titleKey'), return titleKey && I18n.t(titleKey);
},
category: function() { @computed("categoryId")
if (this.get('categoryId')) { category(categoryId) {
return Discourse.Category.findById(this.get('categoryId')); return categoryId && Discourse.Category.findById(categoryId);
} },
}.property('categoryId'),
categoryClass: function() { @computed("category.fullSlug")
if (this.get('category')) { categoryClass(slug) {
return "tag-list-" + this.get('category.fullSlug'); return slug && `tag-list-${slug}`;
} }
}.property('category')
}); });

View File

@ -1,7 +1,7 @@
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
sortProperties: ['count:desc', 'id'], sortProperties: ['totalCount:desc', 'id'],
sortedByCount: true, sortedByCount: true,
sortedByName: false, sortedByName: false,
@ -21,7 +21,7 @@ export default Ember.Controller.extend({
actions: { actions: {
sortByCount() { sortByCount() {
this.setProperties({ this.setProperties({
sortProperties: ['count:desc', 'id'], sortProperties: ['totalCount:desc', 'id'],
sortedByCount: true, sortedByCount: true,
sortedByName: false sortedByName: false
}); });

View File

@ -37,7 +37,6 @@ CategoryList.reopenClass({
c.topics = c.topics.map(t => Discourse.Topic.create(t)); c.topics = c.topics.map(t => Discourse.Topic.create(t));
} }
switch(statPeriod) { switch(statPeriod) {
case "week": case "week":
case "month": case "month":

View File

@ -0,0 +1,9 @@
import RestModel from "discourse/models/rest";
import computed from "ember-addons/ember-computed-decorators";
export default RestModel.extend({
@computed("count", "pm_count")
totalCount(count, pmCount) {
return count + pmCount;
}
});

View File

@ -1,6 +1,22 @@
import Tag from "discourse/models/tag";
export default Discourse.Route.extend({ export default Discourse.Route.extend({
model() { model() {
return this.store.findAll('tag'); return this.store.findAll("tag").then(result => {
if (result.extras) {
if (result.extras.categories) {
result.extras.categories.forEach(category => {
category.tags = category.tags.map(t => Tag.create(t));
});
}
if (result.extras.tag_groups) {
result.extras.tag_groups.forEach(tagGroup => {
tagGroup.tags = tagGroup.tags.map(t => Tag.create(t));
});
}
}
return result;
});
}, },
titleToken() { titleToken() {
@ -10,7 +26,7 @@ export default Discourse.Route.extend({
setupController(controller, model) { setupController(controller, model) {
this.controllerFor('tags.index').setProperties({ this.controllerFor('tags.index').setProperties({
model, model,
sortProperties: this.siteSettings.tags_sort_alphabetically ? ['id'] : ['count:desc', 'id'] sortProperties: this.siteSettings.tags_sort_alphabetically ? ['id'] : ['totalCount:desc', 'id']
}); });
}, },

View File

@ -9,11 +9,7 @@
{{/if}} {{/if}}
{{#each sortedTags as |tag|}} {{#each sortedTags as |tag|}}
<div class='tag-box'> <div class='tag-box'>
{{#if tag.count}} {{discourse-tag tag.id isPrivateMessage=isPrivateMessage tagsForUser=tagsForUser}} {{#if tag.pm_count}}{{d-icon "envelope"}}{{/if}}{{#if tag.totalCount}} <span class='tag-count'>x {{tag.totalCount}}</span>{{/if}}
{{discourse-tag tag.id isPrivateMessage=isPrivateMessage tagsForUser=tagsForUser}} <span class='tag-count'>x {{tag.count}}</span>
{{else}}
{{discourse-tag tag.id}}
{{/if}}
</div> </div>
{{/each}} {{/each}}
<div class="clearfix" /> <div class="clearfix" />

View File

@ -33,7 +33,11 @@ class TagsController < ::ApplicationController
format.json do format.json do
ungrouped_tags = Tag.where("tags.id NOT IN (select tag_id from tag_group_memberships)") ungrouped_tags = Tag.where("tags.id NOT IN (select tag_id from tag_group_memberships)")
ungrouped_tags = ungrouped_tags.where("tags.topic_count > 0") unless guardian.can_admin_tags?
# show all the tags to admins
unless guardian.can_admin_tags? && guardian.is_admin?
ungrouped_tags = ungrouped_tags.where("tags.topic_count > 0")
end
if SiteSetting.tags_listed_by_group if SiteSetting.tags_listed_by_group
grouped_tag_counts = TagGroup.allowed(guardian).order('name ASC').includes(:tags).map do |tag_group| grouped_tag_counts = TagGroup.allowed(guardian).order('name ASC').includes(:tags).map do |tag_group|
@ -210,7 +214,7 @@ class TagsController < ::ApplicationController
end end
def self.tag_counts_json(tags) def self.tag_counts_json(tags)
tags.map { |t| { id: t.name, text: t.name, count: t.topic_count } } tags.map { |t| { id: t.name, text: t.name, count: t.topic_count, pm_count: t.pm_topic_count } }
end end
def set_category_from_params def set_category_from_params

View File

@ -20,22 +20,40 @@ class Tag < ActiveRecord::Base
after_commit :trigger_tag_destroyed_event, on: :destroy after_commit :trigger_tag_destroyed_event, on: :destroy
def self.ensure_consistency! def self.ensure_consistency!
update_topic_counts # topic_count counter cache can miscount update_topic_counts
end end
def self.update_topic_counts def self.update_topic_counts
Category.exec_sql <<~SQL Tag.exec_sql <<~SQL
UPDATE tags t UPDATE tags t
SET topic_count = x.topic_count SET topic_count = x.topic_count
FROM ( FROM (
SELECT COUNT(topics.id) AS topic_count, tags.id AS tag_id SELECT COUNT(topics.id) AS topic_count, tags.id AS tag_id
FROM tags FROM tags
LEFT JOIN topic_tags ON tags.id = topic_tags.tag_id LEFT JOIN topic_tags ON tags.id = topic_tags.tag_id
LEFT JOIN topics ON topics.id = topic_tags.topic_id AND topics.deleted_at IS NULL AND topics.archetype != 'private_message' LEFT JOIN topics ON topics.id = topic_tags.topic_id
GROUP BY tags.id AND topics.deleted_at IS NULL
) x AND topics.archetype != 'private_message'
WHERE x.tag_id = t.id GROUP BY tags.id
AND x.topic_count <> t.topic_count ) x
WHERE x.tag_id = t.id
AND x.topic_count <> t.topic_count
SQL
Tag.exec_sql <<~SQL
UPDATE tags t
SET pm_topic_count = x.pm_topic_count
FROM (
SELECT COUNT(topics.id) AS pm_topic_count, tags.id AS tag_id
FROM tags
LEFT JOIN topic_tags ON tags.id = topic_tags.tag_id
LEFT JOIN topics ON topics.id = topic_tags.topic_id
AND topics.deleted_at IS NULL
AND topics.archetype = 'private_message'
GROUP BY tags.id
) x
WHERE x.tag_id = t.id
AND x.pm_topic_count <> t.pm_topic_count
SQL SQL
end end
@ -54,7 +72,7 @@ class Tag < ActiveRecord::Base
tag_names_with_counts = Tag.exec_sql <<~SQL tag_names_with_counts = Tag.exec_sql <<~SQL
SELECT tags.name as tag_name, SUM(stats.topic_count) AS sum_topic_count SELECT tags.name as tag_name, SUM(stats.topic_count) AS sum_topic_count
FROM category_tag_stats stats FROM category_tag_stats stats
INNER JOIN tags ON stats.tag_id = tags.id AND stats.topic_count > 0 JOIN tags ON stats.tag_id = tags.id AND stats.topic_count > 0
WHERE stats.category_id in (#{scope_category_ids.join(',')}) WHERE stats.category_id in (#{scope_category_ids.join(',')})
#{filter_sql} #{filter_sql}
GROUP BY tags.name GROUP BY tags.name
@ -71,23 +89,24 @@ class Tag < ActiveRecord::Base
user_id = allowed_user.id user_id = allowed_user.id
tag_names_with_counts = Tag.exec_sql <<~SQL tag_names_with_counts = Tag.exec_sql <<~SQL
SELECT tags.name, SELECT tags.name, COUNT(topics.id) AS topic_count
COUNT(topics.id) AS topic_count FROM tags
FROM tags JOIN topic_tags ON tags.id = topic_tags.tag_id
INNER JOIN topic_tags ON tags.id = topic_tags.tag_id JOIN topics ON topics.id = topic_tags.topic_id
INNER JOIN topics ON topics.id = topic_tags.topic_id AND topics.deleted_at IS NULL
AND topics.deleted_at IS NULL AND topics.archetype = 'private_message'
AND topics.archetype = 'private_message' WHERE topic_tags.topic_id IN (
WHERE topic_tags.topic_id IN SELECT topic_id
(SELECT topic_id FROM topic_allowed_users
FROM topic_allowed_users WHERE user_id = #{user_id}
WHERE user_id = #{user_id} UNION
UNION ALL SELECT tg.topic_id SELECT tg.topic_id
FROM topic_allowed_groups tg FROM topic_allowed_groups tg
JOIN group_users gu ON gu.user_id = #{user_id} JOIN group_users gu ON gu.user_id = #{user_id}
AND gu.group_id = tg.group_id) AND gu.group_id = tg.group_id
GROUP BY tags.name )
LIMIT #{limit} GROUP BY tags.name
LIMIT #{limit}
SQL SQL
tag_names_with_counts.map { |t| { id: t['name'], text: t['name'], count: t['topic_count'] } } tag_names_with_counts.map { |t| { id: t['name'], text: t['name'], count: t['topic_count'] } }
@ -120,11 +139,12 @@ end
# #
# Table name: tags # Table name: tags
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string not null # name :string not null
# topic_count :integer default(0), not null # topic_count :integer default(0), not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# pm_topic_count :integer default(0), not null
# #
# Indexes # Indexes
# #

View File

@ -0,0 +1,5 @@
class AddPmTopicCountToTags < ActiveRecord::Migration[5.1]
def change
add_column :tags, :pm_topic_count, :integer, null: false, default: 0
end
end