Unread notifications for child messages
Each new child message in Thread message feed will make the parent message unread again. The notification will look exactly the same as if the parent message has just been created.
TODO:
-
understand how the unread information is stored and how it is represented to a user -
how announcement works? the distribution should be broken (typo) -
how to make sure all child messages from unread notifications are in message map? -
how to keep parent message highlighted? -
should we take mentions
from child message and use them for the parent message unread notification?
Email notifications
-
How is the "Last 3 messages" part of the email going to look like with thread messages?
Multiple messages in different TMFs
Example (unread messages marked with ⊙):
.
├── parent1
│ ├── child1
│ ├── child2⊙
│ └── child3⊙
├── parent2
│ ├── child4
│ └── child5⊙
└── parent3⊙
├── child6⊙
├── child7⊙
└── child8⊙
In this scenario, the user returned to a room and there is a combination of parent and child unread messages. There are several options on how to handle this unread scenario:
Option A:
Only mark parent messages as unread, the moment the user sees parent message, mark it and all its child messages as read.
Pros:
- simple implementation
Cons:
- it's going to be easy to scroll through parent message and miss that there are new child messages
Option B:
Mark parent message unread and keep it unread till user opens the TMF and then mark the child messages unread. Only when the user saw the unread child messages, mark parent message read.
Pros:
- User won't miss an unread message
Cons:
- Persistent unread indicator (till user clicks on the parent, it's going to be highlighted as unread)
- Harder to implement
Unread messages storage and usage
New unread message
(The dashed line shows how messages are marked as unread, the full line shows how rooms are marked as having unread messages)
graph TD
A[chatService.newChatMessageToTroupe] --> B[unreadItemService.createChatUnreadItems]
B --> C[create distribution]
C --> D[engine.newItemWithMentions]
D --> E[ redis:unread:email_notify, redis:unread:chat:<userId>:<troupeId>, redis:ub:<userId> ]
E -.-> F[engine.getUnreadItems]
F -.-> G[unreadItemService.getUnreadItems]
G -.-> H[UnreadItemStrategy.preload]
H -.-> I[ChatStrategy.preload - and map]
I -.-> J[restful.serializeChatsForTroupe]
J -.-> K[chat-internal.renderChat]
E --> S[engine.getRoomsMentioningUser]
S --> T[unreadItemService.getRoomIdsMentioningUser]
T --> U[roomService.findAllRoomsIdsForUserIncludingMentions]
U --> V[restful.serializeTroupesForUser]
V --> W[mixin-vue-left-menu-data.mixinHbsDataForVueLeftMenu]
Note: Chat messages are serialized with unread information by default
Marking messages as read
public/js/components/unread-items-client.js
graph TD
A[unreadItemsClient.syncCollections] --> B[unreadItemsClient._windowScroll]
B --> C[unreadItemsStore.markItemRead]
C -- event itemMarkedRead --> D[ReadItemSender._onItemMarkedRead]
D --> E[ReadItemSender._send - limited to 1000ms]
E --> F[ReadItemSender._sendForRoom]
F -.-> G[api/v1/user/unread-items.js create]
G --> H[unreadItemService.markItemsRead]
H --> I[engine.markItemsRead]
Email notification is stored in a format redis.call("HSETNX", email_hash_key, troupe_id..':'..user_id, time_now)
127.0.0.1:6379> HGETALL unread:email_notify
1) "5d07443a17d82eff1cc8265e:5cf4ccf564fbea9f3d9bf489"
2) "1569845637000"
3) "5d07443a17d82eff1cc8265e:5cdc2417572f607a5bc8a428"
4) "1569845637000"
Unread messages are stored in a format keys.push('unread:chat:' + userId + ':' + troupeId);
127.0.0.1:6379> SMEMBERS unread:chat:5cf4ccf564fbea9f3d9bf489:5d07443a17d82eff1cc8265e
1) "5d91f185196440216c07d2df"
User badge is stored in a format keys.push('ub:' + userId);
127.0.0.1:6379> ZRANGE ub:5cdc2417572f607a5bc8a428 0 -1
1) "5d07443a17d82eff1cc8265e"
And mentions are stored in similar format:
var mentionKey = 'm:' + userId;
mentionKeys.push(mentionKey + ':' + troupeId);
mentionKeys.push(mentionKey);
127.0.0.1:6379> SMEMBERS m:5cdc2417572f607a5bc8a428
1) "5d07443a17d82eff1cc8265e"
127.0.0.1:6379> SMEMBERS m:5cdc2417572f607a5bc8a428:5d07443a17d82eff1cc8265e
1) "5d92d935196440216c07d306"
Distribution is an object that says what users and in what way (announcement, mentions) https://gitlab.com/gitlab-org/gitter/webapp/blob/baf37c43103cd1632c53f9d26c94eb66e0b10bbc/modules/unread-items/lib/create-distribution.js#L173
// distribution
{
membersWithFlags: parsedMentions.membersWithFlags,
mentions: parsedMentions.mentions,
nonMemberMentions: parsedMentions.nonMemberMentions,
announcement: mentionInfo.announcement
}