Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/diagram-block
@blocknote/mantine
@blocknote/math-block
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
@blocknote/xl-typst-exporter
commit: |
|
YousefED
added this pull request to stack #3169
October 8, 2026 04:22
YousefED
commented
Oct 8, 2026
| // "After": each user applies their change on its own clone; the clones are | ||
| // merged into `afterDoc` via the CRDT — exactly like the gallery's merge. | ||
| const afterDoc = cloneWithId(beforeDoc, 2); | ||
| // Kept without garbage collection, as stored history and the gallery are. |
Collaborator
Author
There was a problem hiding this comment.
shouldn't we change cloneWithId instead?
3 of 4 tasks
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 8, 2026 14:25
e9ea6c5 to
32ccc8f
Compare
YousefED
removed this pull request from stack #3169
October 8, 2026 14:26
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 8, 2026 14:28
32ccc8f to
18605c5
Compare
YousefED
changed the base branch from
feat/versioning-sidebar-ux-b
to
fix/legacy-version-diff-structure
October 8, 2026 14:28
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 8, 2026 14:30
18605c5 to
b180866
Compare
YousefED
added this pull request to stack #3174
October 8, 2026 14:30
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 8, 2026 20:38
b180866 to
38624d6
Compare
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 9, 2026 09:54
38624d6 to
7550f28
Compare
…experimental) Behind `experimental.lostContentAttribution` in the collaboration options; it only changes what a version diff shows. With it, versions are decoded keeping deleted content, so content lost with a concurrently deleted block, or with a moved block's lost copy, shows as deleted without an author instead of being credited to the deleter or the mover. Content inserted and deleted between the two versions stays hidden. Also, on by default: a change without a known author shows "Deleted" or "Inserted" when hovered, and a change to only a block's id isn't shown.
The Diff in Versioning mode is off by default, as in the editor; a checkbox per flag (kept in the URL) turns it on. A note can depend on the flags, so the sidebar and the notes show the severity for the current flags. The versioning snapshot records each scenario with the flags off and all on.
…s mark With gc: false, each piece of content deleted with its block kept its own delete mark, so hovering it showed a second, identical tooltip. Content whose deletion matches its parent's now renders inside the parent's deletion, as before. Content deleted by someone else, or without an author, keeps its own mark.
A lost move's original was shown without an author, to not credit the mover. But someone else may have deleted it too, knowingly: deleting its parent, for example. Only the movers are left out now.
`experimental.versionDiffFixes` takes one value, each including the fixes before it, so only combinations that make sense can be set. The first is "implicitDeleteAttribution". The gallery offers it as one choice.
…tal) Behind `experimental.blockCopyDiffs` in the collaboration options; it only changes what a version diff shows. A type change or a move stores a copy of the block, so the diff showed it as a deleted and an inserted block, with the copied content credited to whoever made the change. Pair each copy with its original (by block id) and show it once: - a type change between text blocks as a formatting change; - a move, including an indent, as "Moved"; - a copy in the same place (its children changed) as unchanged. Copied content keeps its authors. Content the earlier version had that no copy kept still shows as deleted.
…ier version A block copied twice between two versions (indented, then outdented; retyped twice) leaves an intermediate copy that is deleted too. The pairing could pick that copy as the original, and credit the final copy to whoever made the intermediate one. It now pairs with the block of the earlier version; without one, several candidates aren't paired. Also from the stack review: the version diff never writes to the document (checked for each value of the option), the moved-text highlight shares the inserted-text rules, and Remove a column has its own note.
A block re-created more than once between two versions (retyped, then indented; moved twice) is a chain of copies, each deleted by the update that inserts the next. Follow the chain back by those updates' users and times, so text typed into an intermediate copy keeps its writer. Content added to the original after the earlier version is credited to whoever added it, not shown as unchanged. Also: the pairing no longer recomputes reading order or scans all removed items for each copy.
YousefED
force-pushed
the
fix/version-diff-cascade-attribution
branch
from
October 9, 2026 11:55
7550f28 to
ef5e48a
Compare
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #3173. This PR now also contains #3172, which is closed.
Summary
Two experimental fixes for how a version diff shows changes. Both are behind one option. The option changes only what a version diff shows. It does not change the stored document. Without the option, the diff is as before.
Option
Each value includes the fixes of the values before it. Thus, only combinations that work can be set.
versionDiffFixesIncludedgives the fixes of each value.Problem 1: implicit deletes
Alice deletes a block. At the same time, Bob adds text or blocks inside that block. Yjs then deletes Bob's content together with the block. Nobody deleted this content: it is an implicit delete. A move or a type change also deletes the original block, so the same problem occurs for these edits.
YHub already attributes deletions correctly: it attributes a deletion only to the content that the update itself deleted. The incorrect attribution came from our preview. We decoded snapshots with garbage collection on, so the preview read the children of the deleted block again from the baseline document, and rendered them under the "deleted by" mark of the block.
Changes
snapshotCodec.ts: decode snapshots withgc: false. Nested deleted content keeps its own attribution: if Alice deleted it, it shows her name; if Yjs deleted it with its parent, it shows no name.snapshotPreview.ts,SnapshotDiffRenderer:DiffRendererhides this content only after garbage collection. Without this,gc: falseshows "ghost" deletions.deleteAt), because no mark shows them.snapshotPreview.ts,withoutLostMovers: a move (indent, drag, type change) deletes the block and inserts a copy with the same block id. When no copy is left, the diff shows only the deletion of the original block, which names the mover. But the mover did not delete the block: the copy was deleted with a concurrently deleted parent, or a different user deleted it later. Thus, the movers are removed from the deletion of the original block. Other users that deleted it keep the credit. When no user is left, the block shows without an author.Problem 2: re-created blocks
In Yjs, the type of a node cannot change. Thus, a type change or a move re-creates the block: it stores a copy of the block (with the same block id) and deletes the original. The diff showed the original as deleted and the copy as inserted, and credited all the copied content to the user who made the change.
Changes
When the diff is rendered, we pair each copy with its original (by block id). Then we show the pair once:
Copied content keeps its original authors, character by character. This also applies when you compare with the first version.
A block can be re-created more than once between two versions: for example, retyped and then indented, or moved twice. The copies then form a chain. Each copy is deleted by the update that inserts the next copy. We follow the chain back by the users and times of these updates. Thus:
We do not pair a copy with its original when the copy lost content (for example, a concurrent edit deleted text from the original). Then the diff shows a delete and an insert, as before. A type change between a text block and a block without inline content (for example, paragraph to image) is not paired.
Display:
Block.cssgives the text element the highlight of inserted text. In a code block, the highlight uses the dark variant of inserted code. A moved block without inline content (image, file, table, divider) gets the card of a formatting change.movedattribute. The tooltip shows "Moved" for both.Gallery
One choice for the option ("Default", "Implicit delete attribution", "+ re-created blocks"), kept in the URL. A note can apply only with or without a fix. The sidebar shows the severity without fixes, and in parentheses the severity with all fixes (green: no problem left).
Moved to #3090
Two changes that this PR had are now in #3090, because they are on by default and do not depend on the option:
idattribute of a block is not shown.Not covered
deleteAt) of the mover. No mark or tooltip shows the time.Tests
The tests are in #3090. On #3090, 16 tests have the comment "To be fixed by #3166" and are marked
it.fails. This PR changes them to normal tests:versionDiffAttribution.test.ts:nestingChanges.test.ts: an indent and an unindent show as one moved block.This PR removes the test "attributes a move to the mover": with the re-created blocks fix, an indent shows as moved and not as deleted.
Other tests:
versionDiffFlags.test.ts: each value of the option, for 4 scenarios. Each value stores the same updates, and showing a diff never writes to the document (no update, and the same bytes before and after).tests/src/end-to-end/y-prosemirror/__snapshots__/versioning.test.tsx.snap): each scenario shows once without the option and once with it ("(experimental)"). Without the option, all scenarios are the same as on feat!: rebuild version history and customize snapshot actions #3090. With "Implicit delete attribution", 2 scenarios change. With "+ re-created blocks", 15 scenarios change. Each changed scenario has a note for the option in the gallery.