FEATURE: Show draft count in user menu and activity (#13812)
This commit adds the number of drafts a user has next to the "Draft" label in the user preferences menu and activity tab. The count is updated via MessageBus when a draft is created or destroyed.
This commit is contained in:
parent
d801e33e0b
commit
760c9a5698
|
@ -3,7 +3,7 @@ import I18n from "I18n";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
import bootbox from "bootbox";
|
import bootbox from "bootbox";
|
||||||
import { exportUserArchive } from "discourse/lib/export-csv";
|
import { exportUserArchive } from "discourse/lib/export-csv";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
application: controller(),
|
application: controller(),
|
||||||
|
@ -28,6 +28,13 @@ export default Controller.extend({
|
||||||
this.set("application.showFooter", showFooter);
|
this.set("application.showFooter", showFooter);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("currentUser.draft_count")
|
||||||
|
draftLabel(count) {
|
||||||
|
return count > 0
|
||||||
|
? I18n.t("drafts.label_with_count", { count })
|
||||||
|
: I18n.t("drafts.label");
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
exportUserArchive() {
|
exportUserArchive() {
|
||||||
bootbox.confirm(
|
bootbox.confirm(
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
export default {
|
||||||
|
name: "subscribe-user-changes",
|
||||||
|
after: "message-bus",
|
||||||
|
|
||||||
|
initialize(container) {
|
||||||
|
const user = container.lookup("current-user:main");
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
const bus = container.lookup("message-bus:main");
|
||||||
|
bus.subscribe("/user", (data) => {
|
||||||
|
user.setProperties(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
{{#if user.showDrafts}}
|
{{#if user.showDrafts}}
|
||||||
{{#d-navigation-item route="userActivity.drafts"}}
|
{{#d-navigation-item route="userActivity.drafts"}}
|
||||||
{{i18n "user_action_groups.15"}}
|
{{draftLabel}}
|
||||||
{{/d-navigation-item}}
|
{{/d-navigation-item}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,12 @@ createWidgetFrom(QuickAccessPanel, "quick-access-profile", {
|
||||||
{
|
{
|
||||||
icon: "pencil-alt",
|
icon: "pencil-alt",
|
||||||
href: `${this.attrs.path}/activity/drafts`,
|
href: `${this.attrs.path}/activity/drafts`,
|
||||||
content: I18n.t("user_action_groups.15"),
|
content:
|
||||||
|
this.currentUser.draft_count > 0
|
||||||
|
? I18n.t("drafts.label_with_count", {
|
||||||
|
count: this.currentUser.draft_count,
|
||||||
|
})
|
||||||
|
: I18n.t("drafts.label"),
|
||||||
className: "drafts",
|
className: "drafts",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,8 @@ class Draft < ActiveRecord::Base
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
|
after_commit :update_draft_count, on: [:create, :destroy]
|
||||||
|
|
||||||
class OutOfSequence < StandardError; end
|
class OutOfSequence < StandardError; end
|
||||||
|
|
||||||
def self.set(user, key, sequence, data, owner = nil, force_save: false)
|
def self.set(user, key, sequence, data, owner = nil, force_save: false)
|
||||||
|
@ -92,6 +94,8 @@ class Draft < ActiveRecord::Base
|
||||||
owner = :owner,
|
owner = :owner,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
|
UserStat.update_draft_count(user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
sequence
|
sequence
|
||||||
|
@ -338,6 +342,9 @@ class Draft < ActiveRecord::Base
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_draft_count
|
||||||
|
UserStat.update_draft_count(self.user_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -202,6 +202,21 @@ class UserStat < ActiveRecord::Base
|
||||||
self.class.update_distinct_badge_count(self.user_id)
|
self.class.update_distinct_badge_count(self.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.update_draft_count(user_id)
|
||||||
|
draft_count = DB.query_single <<~SQL, user_id: user_id
|
||||||
|
UPDATE user_stats
|
||||||
|
SET draft_count = (SELECT COUNT(*) FROM drafts WHERE user_id = :user_id)
|
||||||
|
WHERE user_id = :user_id
|
||||||
|
RETURNING draft_count
|
||||||
|
SQL
|
||||||
|
|
||||||
|
MessageBus.publish(
|
||||||
|
'/user',
|
||||||
|
{ draft_count: draft_count.first },
|
||||||
|
user_ids: [user_id]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# topic_reply_count is a count of posts in other users' topics
|
# topic_reply_count is a count of posts in other users' topics
|
||||||
def calc_topic_reply_count!(start_time = nil)
|
def calc_topic_reply_count!(start_time = nil)
|
||||||
sql = <<~SQL
|
sql = <<~SQL
|
||||||
|
@ -292,4 +307,5 @@ end
|
||||||
# distinct_badge_count :integer default(0), not null
|
# distinct_badge_count :integer default(0), not null
|
||||||
# first_unread_pm_at :datetime not null
|
# first_unread_pm_at :datetime not null
|
||||||
# digest_attempted_at :datetime
|
# digest_attempted_at :datetime
|
||||||
|
# draft_count :integer default(0), not null
|
||||||
#
|
#
|
||||||
|
|
|
@ -65,6 +65,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
||||||
:do_not_disturb_until,
|
:do_not_disturb_until,
|
||||||
:has_topic_draft,
|
:has_topic_draft,
|
||||||
:can_review,
|
:can_review,
|
||||||
|
:draft_count,
|
||||||
|
|
||||||
def groups
|
def groups
|
||||||
owned_group_ids = GroupUser.where(user_id: id, owner: true).pluck(:group_id).to_set
|
owned_group_ids = GroupUser.where(user_id: id, owner: true).pluck(:group_id).to_set
|
||||||
|
@ -315,4 +316,8 @@ class CurrentUserSerializer < BasicUserSerializer
|
||||||
def include_has_topic_draft?
|
def include_has_topic_draft?
|
||||||
Draft.has_topic_draft(object)
|
Draft.has_topic_draft(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def draft_count
|
||||||
|
object.user_stat.draft_count
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -332,6 +332,8 @@ en:
|
||||||
copied: "copied!"
|
copied: "copied!"
|
||||||
|
|
||||||
drafts:
|
drafts:
|
||||||
|
label: "Drafts"
|
||||||
|
label_with_count: "Drafts (%{count})"
|
||||||
resume: "Resume"
|
resume: "Resume"
|
||||||
remove: "Remove"
|
remove: "Remove"
|
||||||
remove_confirmation: "Are you sure you want to delete this draft?"
|
remove_confirmation: "Are you sure you want to delete this draft?"
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddDraftCountToUserStat < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :user_stats, :draft_count, :integer, default: 0, null: false
|
||||||
|
|
||||||
|
execute <<~SQL
|
||||||
|
UPDATE user_stats
|
||||||
|
SET draft_count = new_user_stats.draft_count
|
||||||
|
FROM (SELECT user_stats.user_id, COUNT(drafts.id) draft_count
|
||||||
|
FROM user_stats
|
||||||
|
LEFT JOIN drafts ON user_stats.user_id = drafts.user_id
|
||||||
|
GROUP BY user_stats.user_id) new_user_stats
|
||||||
|
WHERE user_stats.user_id = new_user_stats.user_id
|
||||||
|
AND user_stats.draft_count <> new_user_stats.draft_count
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
end
|
|
@ -176,6 +176,20 @@ describe Draft do
|
||||||
expect(Draft.count).to eq 0
|
expect(Draft.count).to eq 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'updates draft count when a draft is created or destroyed' do
|
||||||
|
messages = MessageBus.track_publish("/user") do
|
||||||
|
Draft.set(user, "test", 0, "data")
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(messages.first.data[:draft_count]).to eq(1)
|
||||||
|
|
||||||
|
messages = MessageBus.track_publish("/user") do
|
||||||
|
Draft.where(user: user).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(messages.first.data[:draft_count]).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
describe '#stream' do
|
describe '#stream' do
|
||||||
fab!(:public_post) { Fabricate(:post) }
|
fab!(:public_post) { Fabricate(:post) }
|
||||||
let(:public_topic) { public_post.topic }
|
let(:public_topic) { public_post.topic }
|
||||||
|
|
|
@ -222,4 +222,18 @@ describe UserStat do
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.update_draft_count' do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it 'updates draft_count' do
|
||||||
|
Draft.create!(user: user, draft_key: "topic_1", data: {})
|
||||||
|
Draft.create!(user: user, draft_key: "new_topic", data: {})
|
||||||
|
Draft.create!(user: user, draft_key: "topic_2", data: {})
|
||||||
|
UserStat.update_all(draft_count: 0)
|
||||||
|
|
||||||
|
UserStat.update_draft_count(user.id)
|
||||||
|
expect(user.user_stat.draft_count).to eq(3)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue