RTC: Add session activity notifications#75790
RTC: Add session activity notifications#75790shekharnwagh wants to merge 7 commits intoWordPress:fix/sync-stale-crdt-doc-on-savefrom
Conversation
4bf3ffe to
d3119e6
Compare
d3119e6 to
d6646ec
Compare
5b9ff52 to
18e7c87
Compare
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| * @param postId The ID of the post being edited. | ||
| * @param postType The post type of the post being edited. | ||
| */ | ||
| export function useCollaboratorNotifications( |
There was a problem hiding this comment.
We already track entity save events in the Y.Doc state map. We could listen and dispatch notices from PostAwarenessState
There was a problem hiding this comment.
Did you explore this? Run into any issues?
There was a problem hiding this comment.
Do you mean the lastSaveEvent state field we added here in this PR or did we used to have something for this already ?
I find it simpler to have all notifications dispatched from the same hook that detects changes, instead of spreading them out. This also avoids directly accessing the Y.Doc state map in useCollaboratorNotifications hook. Given this do you still think it might be better to do it in useBroadcastSaveEvent hook.
There was a problem hiding this comment.
I'm saying we could access the Y.Doc state map in PostEditorAwareness and dispatch directly from there, no hook needed.
There was a problem hiding this comment.
One of the issues that we encountered last time was that we were mixing UI elements (notices package) into core-data. Since the PostEditorAwareness is located within core-data, the solution should ideally fire the notification from outside core-data. I don't know if we have the convo on a PR on hand, but that's what I recall the last time we explored this.
That said, I do agree that we should re-used the existing keys in the state map that track all this already. We don't need to introduce new ones imo.
There was a problem hiding this comment.
I've pushed a few commits to use the existing keys synced using YDoc. The useCollaboratorNotifications hook which dispatches notifications is in editor package so that should address not doing UI stuff in core-data.
ffe0f12 to
353dee6
Compare
| * @var int | ||
| */ | ||
| const AWARENESS_TIMEOUT = 30; | ||
| const AWARENESS_TIMEOUT = 70; |
There was a problem hiding this comment.
Nothing that this'd need to be backported into 7.0 as a separate PR as well.
There was a problem hiding this comment.
Opened a backport PR and linked in new PR #76065
| * notices if the same event is processed more than once. | ||
| */ | ||
| const NOTIFICATION_TYPE = { | ||
| POST_UPDATED: 'collab-post-updated', |
There was a problem hiding this comment.
I know this was how we kept it in the plugin, but we should match the key with the name.
There was a problem hiding this comment.
Do you mean update the key to COLLAB_POST_UPDATED or update the value to align with key ?
There was a problem hiding this comment.
My point was more to just align them.
The collab prefix was added to make it clear that this notification was to do with RTC mode only. So IMO, I think COLLAB_POST_UPDATED makes more sense than just POST_UPDATED since we don't handle notifications in non-RTC mode.
| continue; | ||
| } | ||
|
|
||
| notify( |
There was a problem hiding this comment.
Could the content be generated from within the notify method? The collaborator id and name could be passed in as arguments, or just the entire collaborator object even.
There was a problem hiding this comment.
Its tricky for post updated notification as that needs additional data like if its first publish and current status to generate notification content - https://github.com/WordPress/gutenberg/pull/75790/changes#diff-ec598d4eb0aacc0ff99f30afd0f8e524f4ac9e242cf69e9045bf6aeaf4c3b291R239-R243. So this seems easier to me for now, but open to being convinced otherwise.
|
|
||
| const notificationsConfig = useMemo( | ||
| () => | ||
| applyFilters( |
There was a problem hiding this comment.
Is this the best way to configure notifications? Is this inline within how Gutenberg does it? I think there'd need to be a UI (similar to their preferences) to turn this on/off and have it follow the same preferences storage system.
Would it be similar to move the notifications config to a separate PR, and have this be focused on introducing it?
There was a problem hiding this comment.
I was going off this comment from the issue -
We've also seen a desire to default some of these to "on" until users turn them off. I don't think we need UI, but perhaps a filter to set the default for an application.
@smithjw1 Any thoughts on dropping the filter and then adding the UI in a follow up PR while keeping all the notifications ON for now ?
There was a problem hiding this comment.
I've removed the filter and made it on by default for all notifications.
| .isCurrentCollaboratorDisconnected; | ||
| } | ||
|
|
||
| export interface PostSaveEvent { |
There was a problem hiding this comment.
Could this go in the types?
There was a problem hiding this comment.
Updated. Not adding commit as that changes on rebases but can check in #76065
| * @param postId The ID of the post. | ||
| * @param postType The type of the post. | ||
| */ | ||
| export function useLastPostSave( |
There was a problem hiding this comment.
This function at the moment isn't called setup on the Awareness instance.
The other functions in this hook go through a single common method usePostEditorAwarenessState that ensures the awareness instance is properly setup, before accessing anything on it. useLastPostSave benefits from being called after useActiveCollaborators which ensures that the PostEditorAwareness state is setup. If that changes, there's going to be a problem because the setUp function on the awareness instance isn't being called in this method.
It'd be worth exploring how this could go through the common shared hook (might require some refactoring) to ensure this is avoided.
There was a problem hiding this comment.
Good catch on the missing setUp(). I've added that call in useLastPostSave now, so it no longer depends on useActiveCollaborators being invoked first. Since setUp() is idempotent, calling it from both hooks is safe.
I looked into routing this through usePostEditorAwarenessState. useLastPostSave subscribes to the Y.Doc state map where markEntityAsSaved writes savedAt/savedBy. The usePostEditorAwarenessState hook is used to subscribe to the awareness, so I'll rather keep them separate.
| // syncs historical state on page load or peer reconnect. | ||
| const setupTime = Date.now(); | ||
|
|
||
| const observer = ( event: Y.YMapEvent< unknown > ) => { |
There was a problem hiding this comment.
There's may be more properties down the line that we might be interested in, it'd be worth exploring how this bit could be redone to make that easier.
There was a problem hiding this comment.
Right now savedAt is the only YDoc state map property we observe, so the observer is straightforward. When we need to watch additional properties, we could revisit this.
Did you have anything specific in mind ?
fdd556a to
0e59564
Compare
Collaborators had no way to know when others joined, left, or saved the post. This adds snackbar notices for all four events, broadcast via a new `lastSaveEvent` field on the Yjs awareness state. Notification types can be toggled via the `editor.collaborationNotifications` WordPress filter.
Replace custom awareness-based save broadcasting with the existing CRDT state map already written by markEntityAsSaved in @wordpress/sync.
The notification always showed "Draft saved by X" because post status was read from the local Redux store, which lags behind the Y.Doc. Fix by reading status from the Y.Doc record map (updated in the same transaction as the save marker) and distinguishing three cases: "Post published", "Post updated", and "Draft saved".
The 30 s awareness timeout matched the background-tab polling interval exactly, causing awareness entries to expire between polls and triggering false "X has left" notifications that resolved on the next poll cycle. Increase to 70 s to comfortably exceed the polling interval. The value accounts for Chrome's intensive throttling which can delay background tab timers to ~60 s
516abab to
ad398fb
Compare
|
Re-opened the PR here - #76065 |
|
@ingeniumed I've addressed or replied to your review comments. FYI the PR was moved here - #76065 |
What?
Closes #75323
Depends on #75975
Adds snackbar notifications for real-time collaboration session activity: when a collaborator joins, leaves, or saves the post.
Why?
Collaborator avatars in the top bar show who's present, but they're easy to miss. There's no active notification when someone joins, leaves, or saves — you'd only notice by watching the avatars constantly.
How?
useCollaboratorNotificationshook that compares the current and previous collaborator lists to detect joins, leaves, and remote saves.lastSaveEventfield on the awareness state.isConnectedproperty transition rather than list removal, so the notification fires when the avatar greys out (not after the 5s cleanup delay).editor.collaborationNotificationsWordPress filter.Testing Instructions
Testing Instructions for Keyboard
No new interactive UI elements are added. Snackbar notifications are announced to screen readers automatically via the existing notice system.
Screenshots or screencast