feat: add per-user raw Markdown editing (#3570)#8898
Conversation
Add an "Edit Markdown source" toggle that switches the current user into a detached plain-text editor showing the document's raw Markdown. Other collaborators are unaffected: the collaborative rich editor stays mounted and connected in the background, so the shared document never sees the plain-text schema. On return, the edited source is applied to the live document. If the document drifted in the meantime (concurrent edits from other users), the existing CollisionResolveDialog is reused so the user can keep their raw version or the remote one instead of silently clobbering either. - useRawEditing: enter/exit state machine with drift detection - RawMarkdownEditor: detached plain editor (no Collaboration extension) - RawEditingToggle: overflow-menu entry, gated to rich Markdown editing (hidden when rich_editing_enabled is off, i.e. the whole instance is raw) - suppress autosave while detached; warn on unload with unsaved raw edits - unit tests for the state machine and Cypress e2e covering the round-trip, discard, and both conflict-resolution branches Signed-off-by: Gordon Myers <soapergem@gmail.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Hi @soapergem Thanks for your contribution. I like the general approach of a per session single user switch. That seems useful also for inspecting the markdown. I'm unsure about adding another scenario that runs into a conflict resolution screen. We've observer that it's overwhelming in particular with large files as we currently have no indication of what changed. We want to improve upon that - but we are not there yet. Technically we could also implement the same approach without a conflict screen and leave the resolution to yjs. We'd need to keep a copy of the ydoc at the start of the editing session. Then compute an yjs update that transforms the ydoc into one that corresponds to the document after the editing session. This update could be applied to the main editing session just like any other yjs update. In cases of small edits that create no actual conflicts this would be ideal. However if people are editing the same section it may lead to counterintuitive results. I'd be curious what @marcoambrosini thinks from a design point of view. I also have not looked at the code changes yet at all. |
📝 Summary
Adds a per-user "Edit Markdown source" toggle that lets a user switch the current document into a raw Markdown editor on the fly, without disrupting other collaborators.
Why the per-user, detached approach. The rich editor and the plain editor bind to the same shared yjs document but use incompatible ProseMirror schemas (rich node tree vs. a single plain-text document). Two users on different schemas against one shared document would corrupt each other — which is exactly the concern raised in the issue discussion. So raw editing runs on a detached plain-text editor (no
Collaborationextension): the collaborative rich editor stays mounted and connected in the background, so the shared document never sees the plain-text schema and other participants are unaffected.Round-trip and conflicts. On leaving raw mode the edited source is applied back to the live document. If the document drifted in the meantime (concurrent edits from other users), the existing
CollisionResolveDialogis reused so the user can keep their raw version or the remote one, instead of silently clobbering either. If the user made no changes, or the document did not drift, the edits are applied directly with no prompt.Interplay with
rich_editing_enabled. The toggle is gated on rich Markdown editing being active, so when an admin has setrich_editing_enabled=0(the whole instance already edits raw) the toggle simply does not appear — no "raw within raw", no schema mixing. The mode is ephemeral per-user view state and is not persisted, which deliberately sidesteps the open "user vs. file vs. instance setting" question from the issue.What's included
useRawEditingcomposable — enter/exit state machine with drift detectionRawMarkdownEditor— detached plain-text editor seeded with the serialized MarkdownRawEditingToggle— overflow-menu entry, gated to rich Markdown editing🖼️ Screenshots
1. Toggle in the ⋯ overflow menu
2. Editing the raw Markdown source
The current user is switched to a detached plain-text editor showing the document's raw Markdown. Rich text returns to the WYSIWYG view.
3. Conflict resolution when the document changed concurrently
If another collaborator changed the document while it was being edited raw, the existing collision dialog is reused to keep either the local (raw) version or the remote one.
🚧 TODO
🏁 Checklist
npm run lintpasses;tscclean under TypeScript 6)Testing notes
src/tests/composables/useRawEditing.spec.ts, 7 cases): enter/gating, direct apply when there is no drift, conflict raised on drift, no-op when unchanged, discard, and conflict clearing.cypress/e2e/RawEditing.spec.js, 5 cases): toggling into the source view, applying raw edits back to the rich editor, discarding, and both branches of the conflict dialog when the document changed concurrently. All passing against a local Nextcloud instance.🤖 AI (if applicable)