diff --git a/crates/channel/src/channel_chat.rs b/crates/channel/src/channel_chat.rs index 1877f7c0d2..b6212d378f 100644 --- a/crates/channel/src/channel_chat.rs +++ b/crates/channel/src/channel_chat.rs @@ -370,6 +370,18 @@ impl ChannelChat { cursor.item().unwrap() } + pub fn rendered_message(&self, id: ChannelMessageId) { + let ChannelMessageId::Saved(id) = id else { + return; + }; + self.rpc + .send(proto::AckChannelMessage { + channel_id: self.channel.id, + message_id: id, + }) + .ok(); + } + pub fn messages_in_range(&self, range: Range) -> impl Iterator { let mut cursor = self.messages.cursor::(); cursor.seek(&Count(range.start), Bias::Right, &()); diff --git a/crates/collab/src/db/queries/channels.rs b/crates/collab/src/db/queries/channels.rs index 60ccff2614..4ee7625afd 100644 --- a/crates/collab/src/db/queries/channels.rs +++ b/crates/collab/src/db/queries/channels.rs @@ -386,7 +386,7 @@ impl Database { } Ok(self - .respond_to_notification( + .mark_notification_as_read_with_response( user_id, &rpc::Notification::ChannelInvitation { channel_id: channel_id.to_proto(), diff --git a/crates/collab/src/db/queries/contacts.rs b/crates/collab/src/db/queries/contacts.rs index 841f9faa20..f31f1addbd 100644 --- a/crates/collab/src/db/queries/contacts.rs +++ b/crates/collab/src/db/queries/contacts.rs @@ -321,7 +321,7 @@ impl Database { let mut notifications = Vec::new(); notifications.extend( - self.respond_to_notification( + self.mark_notification_as_read_with_response( responder_id, &rpc::Notification::ContactRequest { sender_id: requester_id.to_proto(), diff --git a/crates/collab/src/db/queries/messages.rs b/crates/collab/src/db/queries/messages.rs index ca364c5596..d406cbb091 100644 --- a/crates/collab/src/db/queries/messages.rs +++ b/crates/collab/src/db/queries/messages.rs @@ -1,5 +1,6 @@ use super::*; use futures::Stream; +use rpc::Notification; use sea_orm::TryInsertResult; use time::OffsetDateTime; @@ -326,11 +327,24 @@ impl Database { channel_id: ChannelId, user_id: UserId, message_id: MessageId, - ) -> Result<()> { + ) -> Result { self.transaction(|tx| async move { self.observe_channel_message_internal(channel_id, user_id, message_id, &*tx) .await?; - Ok(()) + let mut batch = NotificationBatch::default(); + batch.extend( + self.mark_notification_as_read( + user_id, + &Notification::ChannelMessageMention { + message_id: message_id.to_proto(), + sender_id: Default::default(), + channel_id: Default::default(), + }, + &*tx, + ) + .await?, + ); + Ok(batch) }) .await } diff --git a/crates/collab/src/db/queries/notifications.rs b/crates/collab/src/db/queries/notifications.rs index 893bedb72b..718e41de58 100644 --- a/crates/collab/src/db/queries/notifications.rs +++ b/crates/collab/src/db/queries/notifications.rs @@ -129,22 +129,47 @@ impl Database { /// Populate the response for the notification with the given kind and /// entity id. - pub async fn respond_to_notification( + pub async fn mark_notification_as_read_with_response( &self, recipient_id: UserId, notification: &Notification, response: bool, tx: &DatabaseTransaction, + ) -> Result> { + self.mark_notification_as_read_internal(recipient_id, notification, Some(response), tx) + .await + } + + pub async fn mark_notification_as_read( + &self, + recipient_id: UserId, + notification: &Notification, + tx: &DatabaseTransaction, + ) -> Result> { + self.mark_notification_as_read_internal(recipient_id, notification, None, tx) + .await + } + + async fn mark_notification_as_read_internal( + &self, + recipient_id: UserId, + notification: &Notification, + response: Option, + tx: &DatabaseTransaction, ) -> Result> { if let Some(id) = self - .find_notification(recipient_id, notification, tx) + .find_notification(recipient_id, notification, &*tx) .await? { let row = notification::Entity::update(notification::ActiveModel { id: ActiveValue::Unchanged(id), recipient_id: ActiveValue::Unchanged(recipient_id), - response: ActiveValue::Set(Some(response)), is_read: ActiveValue::Set(true), + response: if let Some(response) = response { + ActiveValue::Set(Some(response)) + } else { + ActiveValue::NotSet + }, ..Default::default() }) .exec(tx) diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index adb7ff50ff..eb4f9394e3 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -3061,11 +3061,16 @@ async fn acknowledge_channel_message( ) -> Result<()> { let channel_id = ChannelId::from_proto(request.channel_id); let message_id = MessageId::from_proto(request.message_id); - session + let notifications = session .db() .await .observe_channel_message(channel_id, session.user_id, message_id) .await?; + send_notifications( + &*session.connection_pool().await, + &session.peer, + notifications, + ); Ok(()) } diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index 814cadb4fb..3661d1ae0e 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -357,8 +357,16 @@ impl ChatPanel { let is_continuation = last_message.id != this_message.id && this_message.sender.id == last_message.sender.id; + if this_message + .mentions + .iter() + .any(|(_, user_id)| Some(*user_id) == self.client.user_id()) + { + active_chat.rendered_message(this_message.id); + } + ( - active_chat.message(ix).clone(), + this_message.clone(), is_continuation, active_chat.message_count() == ix + 1, is_admin,