Suggest mode 6b: Capture and apply block-insert-after suggestions (mechanism)#77971
Suggest mode 6b: Capture and apply block-insert-after suggestions (mechanism)#77971adamsilverstein wants to merge 7 commits into
Conversation
Inserts in Suggest mode now flow through the apply-and-tag pipeline: the block stays at its inserted position, the metadata.suggestion = pending-insert marker drives the visual treatment (UI ships in a follow-up), and auto-save persists a block-insert-after operation with anchor + parent context. Apply just clears the marker (the block is already in the tree); Reject runs removeBlock to undo. The interceptor's "new block" branch now captures the previous-tick parent + sibling order to compute anchorClientId (null = first child) and parentClientId (null = root). Descendants of another new block — a Group with nested children fires multiple new-block entries in one tick — are filtered out so only the top-level insertion is tagged; the descendants ride along inside the captured block snapshot. Refs #77434.
|
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. |
|
Size Change: +207 B (0%) Total Size: 7.92 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in 5d8bf4c. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25407196762
|
A `removeBlock` dispatch in Suggest mode runs through the apply-and-tag flow: re-insert the subtree at its previous position, tag the top with `metadata.suggestion = pending-remove`, and write a `block-remove` op into the overlay. The post-handler used to call `snapshot.delete` on the removed clientIds — fine in isolation, but once the new-block branch (this PR) starts tagging unfamiliar blocks as `pending-insert`, any follow-up subscribe fire (a YJS sync echo, an unrelated dispatch, or a follow-up tick drained by React's batching) finds the re-inserted block missing from the snapshot, routes it through that branch, and overwrites both the marker and the persisted structural op with the insert pair. Re-seed `snapshot` from the live attributes instead. The pending- remove marker is in `metadata.suggestion`, which is already a member of `SYSTEM_METADATA_KEYS`, so the re-seeded baseline keeps the marker invisible to subsequent diffs without leaking it into the user-pending overlay. Refs #77434.
The block-insert-after apply branch only cleared the pending-insert marker on the live block, on the assumption that the live block already carried the suggested values. That holds on the suggester's own client — but the suggester's interceptor diverts every post- insertion edit into the overlay and reverts the live attributes, so collaborators (and the suggester after a reload) see the live block in its captured-at-insertion shape: typically an empty paragraph. After Apply, the marker disappears but the block stays empty, which reads as "the inserted block didn't appear." Fold the payload's attribute-set ops into the apply payload along with the marker clear: `applyOperations` produces the merged attributes, `clearSuggestionMarkerAttributes` strips the marker from the result, and the two are spread together for a single `updateBlockAttributes` dispatch. The marker-clear path in `adoptSystemMetadata` keeps the dispatch from looping back through the interceptor. Refs #77434.
…suggest-mode-6b-insert-mechanism
…mechanism # Conflicts: # packages/editor/src/components/suggestion-mode/test/store-interceptor.js
…gging Rejecting a pending-insert suggestion dispatches a `removeBlock` to undo the insert. When that lands on a peer client through sync, batched with the marker-clearing `updateBlockAttributes`, the removal-detection branch was treating the disappearance as a fresh user delete — re-inserting the block and tagging it pending-remove. That re-insert bounced back through sync and undid the reject on the rejecting client a moment after they clicked. Extend the apply-landing check to also recognize `pending-insert` in the previous-tick tree snapshot. The marker presence means the removal is the reject landing; adopt it.
The conflict check compares each attribute-set op's `before` against the
live block's current attribute. For an inserted block the overlay
baseline is `{}`, so every attribute-set op rides on `before: null`.
On the accepting client the inserted block already carries the typed
content, so the comparison reads as a divergence and the apply flow
opens a 'This block has changed' dialog before every Insert apply.
Inserted blocks have no pre-existing attributes to overwrite — the
attribute-set ops describe the new block's content, not concurrent
edits. Short-circuit `hasAttributeConflict` to false when the payload
carries a `block-insert-after` structural op, and add a regression
test.
What
Adds the data-layer mechanism for block-insert-after suggestions (#77434, task 6b). In Suggest mode an inserted block stays at its position but is tagged with
metadata.suggestion = { type: 'pending-insert' }. Auto-save persists the marker as ablock-insert-afteroperation; Apply clears the marker; Reject runsremoveBlockto undo.Visual treatment lands in the next PR (#77973).
How
anchorClientId(null = first child) andparentClientId(null = root).block-insert-after: clears marker. Reject dispatchesremoveBlockwith bypass.Testing
Stack
Refs #77434, #73411.