Realtime Editing Session

Last modified by Marius Dumitru Florea on 2025/03/31 15:44

Description

Requirements

  • [R1] See who's editing
  • [R2] Leave the realtime session and continue editing alone
  • [R3] Join the realtime session after editing alone
  • [R4] Attribution: know which users have contributed to a page revision auto-saved during realtime editing
  • [R5] Identify the page revisions auto-saved during realtime editing
  • [R6] Leave the realtime session to view mode
  • [R7] Know if the realtime session has unsaved changes
  • [R8] Know if the user is offline
  • [R9] Create milestone page revisions with detailed summary
  • [R10] Mark a milestone page revision as minor / major
  • [R11] Edit the milestone revision summary in realtime
  • [R12] Don't ask for accidental page leave confirmation
  • [R13] Discard all changes made during the realtime session

See who's editing

This can be understood in 2 ways:

  • the users that have joined the realtime editing session
  • the users that are currently editing a particular field (e.g. the page content)

In other words, we can have a list per session and per field. The latter doesn't make sense for small fields whose content always fits in the view port. But it can make sense for large fields. Take for instance a large text field edited with a WYSIWYG editor. Even if the WYSIWYG editor shows the caret / selection of each of the editing users, those may not be always visible if the content is large enough to require a scroll bar. In such cases it's useful to have an overview of the users currently editing this particular field (otherwise the user will have to scroll through all the content to get this information). This overview can also be used as a shortcut that takes you to the place where a given user is editing (inside that field). The same can be achieved with the per-session list, with the mention that:

  • for small fields the shortcut would just scroll to / highlight the field where that user has the focus
  • the click would be ignored if the target user doesn't have the focus in none of the fields (e.g. if the target user has switched to a different browser tab)

The list of users could be shown:

  • on each editor toolbar (per field)
    • Con: Makes sense only for large text fields
    • Con: the editor toolbar may be already crowded
    • Pro: relatively easy to implement (just show on the same line as the other WYSIWYG editor toolbar buttons, instead of using a separate line, and drop the technical lag information)
    • Pro: visible when the page is scrolled down (at least for the in-place edit mode the WYSIWYG editor toolbar is floating)
  • near the page action buttons / menu (per session)
    • Con: not visible when the page is scrolled down; changing this is not trivial
    • Con: some change is needed to keep track of the field that the user is currently editing (to know which field to highlight on click)
  • on the form actions toolbar (per session)
    • Pro: visible when the page is scrolled down
    • Con: some change is needed to keep track of the field that the user is currently editing (to know which field to highlight on click)

In any case, the list length should be limited, as proposed by Thiago in RealtimeSession.

Given that a user can join the same realtime editing session multiple times (i.e. in different browser tabs) it means a user avatar can appear multiple times in the list. This is an edge use case (I don't see why a user would do this unless for testing) so we can:

  • either leave with it
  • or mark each occurrence of an avatar differently (e.g. with a different border color, matching the color used to show the user caret / selection inside the edited content)
  • or group occurrences of the same user, but then it would be more difficult to have a shortcut on the user avatar for the place where the user is editing (because the user is editing in two places)

Leave / Join the realtime session

 [R2] Leave the realtime session and continue editing alone
 [R3] Join the realtime session after editing alone

Not all documents are meant to be edited in realtime. It works well when writing meeting notes, or gathering brainstorming ideas, but it might not be a good fit for documents that have to go through a validation workflow for instance, where each change needs to be well documented and tracked. For such cases we may need a way to disable realtime editing per document, at least by default. A simple solution would be to mark those documents with some metadata (xobject). For the rest, that are going to be edited in realtime (by default) does it make sense to allow the user to leave the realtime session (after they joined) and continue editing alone? Technically we need to support this because for the WYSIWYG editor, switching to Source disconnects the user from the realtime session and switching back reconnects the user if the changes done to the Source can be merged.

Leaving (to edit alone) and joining back could be implemented with:

  • A checkbox on the form actions toolbar (the current implementation)
    • Con: feels strange to use a checkbox as a trigger for an action
    • Con: takes more space (checkbox plus the long label)
  • A button on the form actions toolbar ("Leave" / "Leave Collaboration" / "Edit Alone", "Join" / "Join Collaboration" / "Edit Together")
  • A button near the page action buttons
    • Con: currently not visible when the page is scrolled down
    • Con: crowded area already, and it may cause confusion when seen near the Edit button that we can't remove because the user can use it to switch the edit mode

Auto-saved page revisions

 [R4] Attribution: know which users have contributed to a page revision auto-saved during realtime editing
 [R5] Identify the page revisions auto-saved during realtime editing

Realtime editing requires auto-save. The save needs to be synchronized between the editing users in order to avoid the merge conflicts that occur when multiple users save the same document at the same time. A realtime auto-save will often include changes from multiple users that are editing at the same time. This poses two problems:

  • knowing which users have contributed changes to a document revision that was auto-saved
  • knowing what changes each author has done in a document revision that was auto-saved

The first problem could be solved by saving the list of authors somewhere in the document revision. Given that a document revision currently has a single author, we could:

  • change the author field to support multiple values (with some migration of the existing document revisions)
  • add a new revision field to list "contributors" (this means that we'll have a single author that has created the revision, but the revision can have changes from multiple contributors)
  • simply list the contributors in the revision summary: "Auto saved changes by mflorea, vmassol, ..."

The second problem is harder to solve. We'd have to save the chain of operational transformations along with their authors instead of the actual content in the document revision. Definitely not trivial.

Realtime editing will generate a lot of document revisions with its auto-save, which in turn will make the document history harder to read with its current UI. There are two problems to fix:

  • Make the history UI scale with large number of revisions. Using a live data would help a lot, e.g. allowing the user to filter / search for specific revisions (by author, date, summary).
  • Identify, and ideally group, all revisions associated with a realtime editing session.
    • One difficulty is that the document can be saved also outside the realtime editing session, which makes it difficult to group and still preserve the chronology of the revisions.
    • Using a draft instead of saving directly could help in this case because merging the draft into the original document would lead to a single revision (but we'd lose the draft history, which is probably not that important, as long as we keep the list of contributors, similar to a squash when merging pull requests).
    • The simplest solution is to use a special revision summary when auto-saving from a realtime editing session (e.g. "Auto saved changes by mflorea, vmassol, ...").

Leave the realtime session to view mode

Realtime editing comes with auto-save which means the user doesn't need the Save buttons anymore. The "Save" and "Save & View" buttons could be replaced by a single "Done" / "Close" / "View" button that:

  • saves the content or waits for the changes to be propagated to the other editors
  • takes the user to view mode

This button could be:

  • kept on the form actions toolbar (we would basically rename the "Save & View" button and hide the "Save" button)
  • moved to the page action buttons / menu
    • Con: currently not visible when the page is scrolled down
    • Con: we can't replace the edit button because the user can switch the edit mode, so it would mean an additional button so a more crowded area

Know if the realtime session has unsaved changes

The auto-save is triggered from time to time, so the latest changes are not saved instantly. Moreover, the save could fail, or the user could go offline. The notification message shown on save at the bottom of the page is not enough because it disappears quickly. We could display a status message:

  • either on the form actions toolbar
  • or near the page action buttons / menu
    • Con: currently not visible when the page is scrolled down

The status message should simply indicate if the content is saved or not. The last save date could be shown on hover (e.g. "Last saved 2 minutes ago.").

Know if the user is offline

We currently don't support offline mode, meaning that the WYSIWYG editor is put in read-only mode while the user is disconnected from the realtime session. It's still useful though to indicate this more explicitly to the user. We could replace for instance the list of users [R1] with a special icon to indicate that the user is offline. Of course, we need to distinguish between being alone in the realtime editing session and being offline.

Milestone revisions

 [R9] Create milestone page revisions with detailed summary
 [R10] Mark a milestone page revision as minor / major
 [R11] Edit the milestone revision summary in realtime

When editing alone you can "annotate" (explain) your changes using the version summary field. This doesn't work when editing in realtime because you don't control when the auto-save is triggered, and thus you don't control what changes are included. But you may still want to create some "milestone" revisions with detailed summary for the changes done so far in the realtime session. This could work like this:

  • Alice makes some changes (that might be auto-saved) then opens the "Changes Summary" UI (modal) to explain what she did.
  • Bob makes some changes at the same time (that might be auto-saved) then opens the "Changes Summary" UI (modal) to explain what he did, editing the summary in realtime with Alice
  • Carol decides a new milestone revision is needed and triggers an explicit save with the change summary written by Alice and Bob

Of course this requires some synchronization between the editing users, so I'm not sure how feasible it is. All this could be replaced with the draft merge UI if we decide to auto-save as draft instead of updating directly the edited document.

Don't ask for accidental page leave confirmation

When editing alone the user can leave the edit mode by mistake, e.g. by clicking on a link or by closing the browser tab, losing unsaved changes. For this reason we ask the user to confirm the page leave when there are unsaved changes. This doesn't make sense (all the time) when editing collaboratively:

  • as long as your changes were propagated to the realtime session, other users editing at the same time will save your changes (automatically)
  • a remote auto-save (done from another user) should mark the content as clean (if there are no additional changes)
  • leaving the page could simply trigger an auto-save

Discard all changes made during the realtime session

Auto-save makes the Cancel button (with its current implementation) useless because it can only discard the changes since the last auto-save, which in practice means very little changes if the auto-save is triggered often. We should remove the Cancel button as a consequence, but I think some users will miss a way to revert the changes from the edit mode, without going to the page history. This is highly dependent on how we save the changes done during the realtime editing session:

  • If we save directly (the current approach) then we'll probably need a way to discard all the changes by reverting to the revision before the realtime editing session started. We could do this by storing the initial revision number when starting a realtime session and propagating this to all the users joining the session. The problem is that we may revert changes done outside the realtime editing session (i.e. revisions created while we were editing).
  • if we save the realtime changes as a draft then we need a way to discard that draft

Either way, we need a button / menu entry for this, on the form actions toolbar or near the page action buttons / menu.

Save directly vs. save as draft

There seems to be two main approaches when saving the changes done in a realtime editing session:

  • Update the edited document directly (Notion)
    • Pro: the edited content is pretty much the content you saw in view mode before starting to edit (this is especially important for the in-place edit mode)
    • Pro: we're already doing this so no change is needed
    • Pro: the history is complete: you can see the intermediate auto-saved revisions and thus determine more precisely when a change was done and by whom
    • Pro: if the edited content has scripts that rely on the current page reference they will work as expected
    • Con: we have to deal with merge conflicts when the edited document is saved outside the realtime session
    • Con: we can't group the revisions auto-saved from realtime because we could have revisions created outside the realtime session, interleaved
    • Con: discarding the changes done during realtime edit could revert as well changes done (at the same time) outside the realtime session
    • Con: The auto-saved content can be in an unfinished state that prevents it from being properly rendered. This is less of a problem for the WYSIWYG editor, but it's a big problem for the realtime Wiki editor, where partial wiki syntax can be auto-saved that breaks the rendering of the document for those that look at the page in view mode.
    • Con: the users accessing the page in view mode will see partial content (even if the partial content is properly rendered)
  • Create a draft that can be later merged with the original document (Confluence)
    • Pro: no merge conflicts to deal with (from saves done outside the realtime session), because the draft is owned by the realtime session
    • Pro: A change summary can be specified when merging (like when we merge a pull request by squash), leading to a more clean history on the original document. The user can also see at this point all the changes made during the realtime edit (the diff), reducing the risk of accidental / unwanted changes, especially if we remove the Cancel button from the realtime edit.
    • Pro: no need to group or identify the auto-saved revisions on the original document history
    • Pro: the draft can be easily discarded at any moment without affecting the original document
    • Pro: the user looking at the page in view mode is seeing a final / polished version of the content
    • Con: more complex to implement
    • Con: The draft has to be persisted beyond the life of the realtime session. Starting a new realtime editing session should resume the edit of the previous draft. This can cause confusion if the content of the draft is very different from what the user had seen in view mode before editing.
    • Con: the draft can diverge from the original document significantly, making it more difficult to merge (if the original document is updated during the realtime session)
    • Con: the history of the original document may be incomplete if we chose to merge the draft by squashing its revisions
    • Con: we'd have to persist the script level of the realtime session on the draft document so that when realtime edit is resumed the script level is not reset (until after the draft is merged)
    • Con: scripts that rely on the current document reference might not work as expected (the draft is not the same as the original document)
    • Con: overlaps in functionality with Change Request application

Proposal

See https://forum.xwiki.org/t/realtime-session-toolbar/16726 .


 

Get Connected