FEATURE: add mention count to threads (#29739)

Previously we only counted mentions that were made within channels, however for threads this was never implemented.

This change adds a mention count to the ThreadUnreadsQuery, which is used for channel thread lists and the user thread list. We are also expanding channel mentions count to include mentions within threads.

The goal is to have a more consistent urgent badge across chat, in places such as channel lists and the chat header.
This commit is contained in:
David Battersby 2024-11-14 14:10:12 +04:00 committed by GitHub
parent cd6d2ffaa4
commit 5ce4af1aa6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 137 additions and 5 deletions

View File

@ -46,7 +46,6 @@ module Chat
AND notifications.notification_type = :notification_type_mention
AND (data::json->>'chat_message_id')::bigint > COALESCE(user_chat_channel_memberships.last_read_message_id, 0)
AND (data::json->>'chat_channel_id')::bigint = memberships.chat_channel_id
AND (chat_messages.thread_id IS NULL OR chat_messages.id = chat_threads.original_message_id)
) AS mention_count,
(
SELECT COUNT(*) AS watched_threads_unread_count

View File

@ -59,7 +59,22 @@ module Chat
AND user_chat_channel_memberships.muted = false
AND user_chat_channel_memberships.user_id = :user_id
) AS unread_count,
0 as mention_count,
(
SELECT COUNT(*) AS mention_count
FROM notifications
INNER JOIN chat_messages ON chat_messages.id = (data::json->>'chat_message_id')::bigint
INNER JOIN chat_channels ON chat_channels.id = chat_messages.chat_channel_id
INNER JOIN user_chat_channel_memberships ON user_chat_channel_memberships.chat_channel_id = chat_messages.chat_channel_id
LEFT JOIN chat_threads ON chat_threads.id = chat_messages.thread_id
WHERE NOT read
AND notifications.user_id = :user_id
AND notifications.notification_type = :notification_type_mention
AND user_chat_channel_memberships.user_id = :user_id
AND chat_channels.threading_enabled
AND chat_messages.deleted_at IS NULL
AND chat_messages.thread_id = memberships.thread_id
AND NOT user_chat_channel_memberships.muted
) AS mention_count,
(
SELECT COUNT(*) AS watched_threads_unread_count
FROM chat_messages
@ -122,6 +137,7 @@ module Chat
limit: MAX_THREADS,
tracking_level: ::Chat::UserChatThreadMembership.notification_levels[:tracking],
watching_level: ::Chat::UserChatThreadMembership.notification_levels[:watching],
notification_type_mention: ::Notification.types[:chat_mention],
)
end
end

View File

@ -11,6 +11,7 @@ export default class ChatChannelUnreadIndicator extends Component {
get showUnreadIndicator() {
return (
this.args.channel.tracking.unreadCount > 0 ||
this.args.channel.tracking.mentionCount > 0 ||
this.args.channel.unreadThreadsCountSinceLastViewed > 0
);
}

View File

@ -8,7 +8,10 @@ export default class ChatThreadUnreadIndicator extends Component {
}
get urgentCount() {
return this.args.thread.tracking.watchedThreadsUnreadCount;
return (
this.args.thread.tracking.mentionCount +
this.args.thread.tracking.watchedThreadsUnreadCount
);
}
get showUnreadIndicator() {

View File

@ -225,14 +225,14 @@ describe Chat::ChannelUnreadsQuery do
)
end
it "does not include other thread messages in the mention count" do
it "includes thread messages with mentions in the channel mention count" do
thread_message_1 = Fabricate(:chat_message, chat_channel: channel_1, thread: thread)
thread_message_2 = Fabricate(:chat_message, chat_channel: channel_1, thread: thread)
create_mention(thread_message_1, channel_1)
create_mention(thread_message_2, channel_1)
expect(query.first).to eq(
{
mention_count: 0,
mention_count: 2,
unread_count: 1,
watched_threads_unread_count: 0,
channel_id: channel_1.id,

View File

@ -36,6 +36,24 @@ describe Chat::ThreadUnreadsQuery do
thread_4.add(current_user)
end
def create_mention(message, channel, thread)
notification =
Notification.create!(
notification_type: Notification.types[:chat_mention],
user_id: current_user.id,
data: {
chat_message_id: message.id,
chat_channel_id: channel.id,
thread_id: thread.id,
}.to_json,
)
Chat::UserMention.create!(
notifications: [notification],
user: current_user,
chat_message: message,
)
end
context "with unread messages across multiple threads" do
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1, thread: thread_1) }
fab!(:message_2) { Fabricate(:chat_message, chat_channel: channel_2, thread: thread_3) }
@ -188,6 +206,87 @@ describe Chat::ThreadUnreadsQuery do
)
end
end
context "with mentions" do
let!(:message) { create_mention(message_1, channel_1, thread_1) }
it "counts both unread messages and mentions separately" do
expect(query.map(&:to_h)).to eq(
[
{
channel_id: channel_1.id,
thread_id: thread_1.id,
mention_count: 1,
unread_count: 1,
watched_threads_unread_count: 0,
},
{
channel_id: channel_1.id,
thread_id: thread_2.id,
mention_count: 0,
unread_count: 0,
watched_threads_unread_count: 0,
},
{
channel_id: channel_2.id,
thread_id: thread_3.id,
mention_count: 0,
unread_count: 1,
watched_threads_unread_count: 0,
},
{
channel_id: channel_2.id,
thread_id: thread_4.id,
mention_count: 0,
unread_count: 1,
watched_threads_unread_count: 0,
},
],
)
end
it "does not count mentions in muted channels" do
channel_1.membership_for(current_user).update!(muted: true)
expect(query.map(&:to_h).find { |tracking| tracking[:thread_id] == thread_1.id }).to eq(
{
thread_id: thread_1.id,
channel_id: channel_1.id,
unread_count: 0,
mention_count: 0,
watched_threads_unread_count: 0,
},
)
end
it "does not count mentions in threads when channel has threading_enabled = false" do
channel_1.update!(threading_enabled: false)
expect(query.map(&:to_h).find { |tracking| tracking[:thread_id] == thread_1.id }).to eq(
{
thread_id: thread_1.id,
channel_id: channel_1.id,
unread_count: 0,
mention_count: 0,
watched_threads_unread_count: 0,
},
)
end
it "does not count mentions in threads when the message is deleted" do
message_1.trash!
expect(query.map(&:to_h).find { |tracking| tracking[:thread_id] == thread_1.id }).to eq(
{
thread_id: thread_1.id,
channel_id: channel_1.id,
unread_count: 0,
mention_count: 0,
watched_threads_unread_count: 0,
},
)
end
end
end
context "when only the thread_ids are provided" do
@ -254,6 +353,20 @@ describe Chat::ThreadUnreadsQuery do
},
)
end
it "counts mentions but not unreads" do
create_mention(message_1, channel_1, thread_1)
expect(query.map(&:to_h)).to include(
{
channel_id: channel_1.id,
mention_count: 1,
thread_id: thread_1.id,
unread_count: 0,
watched_threads_unread_count: 0,
},
)
end
end
context "when the user is not a member of a thread" do