Repository navigation
RTC: Fix Yjs undo manager to update UI state when undo stack changes #78864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7985ed0
a065a76
0069b18
e201585
518905a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1646,12 +1646,20 @@ export function __unstableMarkLastChangeAsPersistent() { | |
| } | ||
|
|
||
| /** | ||
| * Action that signals that the next block change should be marked explicitly as not persistent. | ||
| * Action that signals that the next block change should be marked explicitly | ||
| * as not persistent. | ||
| * | ||
| * By default, non-persistent changes may still merge into undo history. Use | ||
| * `history: 'ignore'` for derived changes that should never be captured by undo. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm having a hard time understanding the difference between "non persistent" change and a change that is ignored from history. My memory might be failing me a bit.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question, I think the terminology is confusing. My apologies in advance for the wall of text. "Non-persistent" is the block-editor distinction between sending a block-editor change through However, these "non-persistent" markers are used with different purposes. Edit from the PR description:
In other uses of Before this PR, both typing and template sync reach the undo layer with the same shape, non-persistent or Yjs works differently. It observes CRDT transactions as they happen and modifies the local undo stack outside of the editor. We have tools to That is why this template still case can be fixed with the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok I'm going to ping @ellatrix here just for awareness. This feels a bit complex and I just to want make sure we're not shooting ourselves in the foot by this extra complexity. |
||
| * | ||
| * @param {Object} options Options object. | ||
| * @param {string} options.history How the change should interact with history. | ||
| * @return {Object} Action object. | ||
| */ | ||
| export function __unstableMarkNextChangeAsNotPersistent() { | ||
| return { type: 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT' }; | ||
| export function __unstableMarkNextChangeAsNotPersistent( { | ||
| history = 'merge', | ||
| } = {} ) { | ||
| return { type: 'MARK_NEXT_CHANGE_AS_NOT_PERSISTENT', history }; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why there are changes to the block-editor package and how they relate to the current PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, I didn't explain the flow.
useBlockSyncis the place where block-editor changes are converted into theonInput/onChangecallbacks that eventually calleditEntityRecord. This is part of the plumbing into core data. Here's the flow:We insert an async template and don't want it to create an undo item. The "ignore history in this undo" starts in
useInnerBlockTemplateSync, which calls__unstableMarkNextChangeAsNotPersistent( { history: 'ignore' } );.The block-editor store records that as the next block change’s history mode, and exposes it through a selector.
For the line you commented on above,
useBlockSyncbridges from block-editor to the core-dataonInputcallback. It reads the history mode and addsundoIgnore: truewhen the mode ishistory: 'ignore'to theonInputcallback.useEntityBlockEditor.onInputforwards those options intoeditEntityRecord.editEntityRecordunderstandsundoIgnore, and merges into the CRDT withLOCAL_UNDO_IGNORED_ORIGIN, so the Yjs document still receives the template change but the Yjs undo manager does not capture it.The
undoIgnoreflag plumbing is used communicate to core-data to treat the template insertion differently than a normal cached block edit and have it avoid creating an undo item.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the confusion, I was not pointing that line specifically, It's just that in my mind, the bug that I highlighted before has nothing to do with block-editor store, it was a core-data selector, so I don't understand how the changes to block-editor are related to that bug fix.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. In my mind, the connection to the original comment you left is this:
In dependent PR #78756, we made a small timing adjustment to CRDT updates which caused
hasUndoandhasRedoto update in-time with the actual Yjs undo stack, which it was not doing before. This revealed that Yjs was incorrectly adding an undo stack item, but it wasn't reflected in the UI for the test because "core-data is probably changing at the same time" wasn't actually happening. Once we started correctly reflecting the undo state in the UI, the test promptly failed because we weren't supposed to be creating an undo item. The behavior was always wrong, but we didn't see it because undo stack UI updates weren't being dispatched. That's the problem you described.This PR address both your comment and the break:
We're now ensuring that stack updates, regardless of timing, actually update UI state instead of relying on "probably changing" second-order effects.
One of the consequences of correct undo stack UI display is the failure of the
inner-blocks-templates.spec.jstest because of an incorrectly-created undo item. The rest of the changes in this PR are to address the underlying issue to allow Yjs to correctly skip an undo item for this particular case.The changes are largely in the block editor as the originator of the
__unstableMarkNextChangeAsNotPersistentsignal, and the place where we can understand the intended meaning of that signal.