Skip to content

Suggest mode 6/9: review UI (Apply / Reject sidebar and summary) - #80432

Open
adamsilverstein wants to merge 58 commits into
suggest/inline-opsfrom
suggest/review-ui
Open

adamsilverstein wants to merge 58 commits into
suggest/inline-opsfrom
suggest/review-ui

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jul 17, 2026 •

Copy link
Copy Markdown
Member

Part of #73411

What's in this PR

Adds the sidebar review surface: SuggestionActions renders the Accept /
Reject affordance in a note's header, resolves the marked text for inline
suggestions on read, and shows a Docs-style Add / Delete / Format summary
(SuggestionSummary + word-diff). The notes list hides the generic Resolve
button for suggestion notes so the checkmark isn't duplicated, and the note
toolbar's Add-note button stays active while a suggestion is being composed.

Screenshot

Reviewing as the post author. Each suggestion becomes a note with a plain-language summary and Accept / Reject actions, here an attribute change and an inline addition:

All notes sidebar listing a heading level format suggestion and an Add suggestion, each with accept and reject buttons

Testing

This is one layer of the stack. To exercise the whole feature, #78994 bundles every layer into one branch and builds it in Playground:

Test in WordPress Playground

👉 https://playground.wordpress.net/gutenberg.html?pr=78994

Enable Gutenberg > Experiments > Collaboration > Suggestion Mode, then follow the walkthrough in #73411, which also explains how to review the stack layer by layer.


Suggest mode stack

This rebuilds the manually-stacked Suggest mode work (#73411) as a GitHub Stack of 9 small, independently reviewable PRs, each building on the one below it:

  1. #80427 - editor intent (edit/suggest/view) + experiment gate
  2. #80428 - suggestion storage, REST controller, provider
  3. #80429 - block-level capture (attribute + structural)
  4. #80430 - inline marker primitive
  5. #80431 - inline suggestion operations
  6. #80432 - review UI (Apply/Reject sidebar + summary)
  7. #80433 - inline live wiring
  8. #82047 - architecture documentation
  9. #82048 - end-to-end test suite

Each follow up fix now sits in the layer that owns the code it changes, rather than piling onto the top of the stack. The whole feature can be exercised end-to-end via the combined testing branch #78994 (Playground). Behind the "Suggestion Mode" experiment (Gutenberg > Experiments).


AI Use

Code and description both written with 🤖 Claude Code. I will review and test.

Adds the sidebar review surface: SuggestionActions renders the Accept /
Reject affordance in a note's header, resolves the marked text for inline
suggestions on read, and shows a Docs-style Add / Delete / Format summary
(SuggestionSummary + word-diff). The notes list hides the generic Resolve
button for suggestion notes so the checkmark isn't duplicated, and the note
toolbar's Add-note button stays active while a suggestion is being composed.
@github-actions

github-actions Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Size Change: +5.08 kB (+0.06%)

Total Size: 7.93 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 596 kB +4.39 kB (+0.74%)
build/styles/editor/style-rtl.css 31.8 kB +193 B (+0.61%)
build/styles/editor/style-rtl.min.css 27.2 kB +155 B (+0.57%)
build/styles/editor/style.css 31.8 kB +184 B (+0.58%)
build/styles/editor/style.min.css 27.2 kB +154 B (+0.57%)

compressed-size-action

# Conflicts:
#	packages/editor/src/components/collab-sidebar/format.js
#	tools/eslint/suppressions.json
@adamsilverstein
adamsilverstein marked this pull request as ready for review August 5, 2026 22:24
@github-actions

github-actions Bot commented Aug 5, 2026 •

Copy link
Copy Markdown

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 props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: aduth <aduth@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

Flaky tests detected in ec52201.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/33117692745
📝 Reported tests:

refuses the drop and uploads nothing in /test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js, passed after 1 failed attempt.
Error: expect(received).toHaveLength(expected)

Expected length: 0
Received length: 2
Received array:  [{"_links": {"about": [{"href": "http://localhost:8889/wp-json/wp/v2/types/attachment"}], "author": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/users/1"}], "collection": [{"href": "http://localhost:8889/wp-json/wp/v2/media"}], "curies": [{"href": "https://api.w.org/{rel}", "name": "wp", "templated": true}], "replies": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/comments?post=106"}], "self": [{"href": "http://localhost:8889/wp-json/wp/v2/media/106", "targetHints": {"allow": ["GET", "POST", "PUT", "PATCH", "DELETE"]}}], "wp:attached-to": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/posts/104", "id": 104, "post_type": "post"}]}, "alt_text": "", "author": 1, "caption": {"rendered": ""}, "class_list": ["post-106", "attachment", "type-attachment", "status-inherit", "hentry", "entry"], "comment_status": "open", "date": "2026-08-27T21:33:22", "date_gmt": "2026-08-27T21:33:22", "description": {"rendered": "<p class=\"attachment\"><a href='http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png'><img loading=\"lazy\" decoding=\"async\" width=\"10\" height=\"10\" src=\"http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png\" class=\"attachment-medium size-medium\" alt=\"\" style=\"width:100%;height:100%;max-width:10px;\" /></a></p>
"}, "featured_media": 0, "filename": "10x10_e2e_test_image_z9T8jK-1.png", "filesize": 80, "guid": {"rendered": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png"}, "id": 106, "link": "http://localhost:8889/?attachment_id=106", "media_details": {"file": "2026/08/10x10_e2e_test_image_z9T8jK-1.png", "filesize": 80, "height": 10, "image_meta": {"alt": "", "aperture": "0", "camera": "", "caption": "", "copyright": "", "created_timestamp": "0", "credit": "", "focal_length": "0", "iso": "0", "keywords": [], "orientation": "0", "shutter_speed": "0", "title": ""}, "sizes": {}, "width": 10}, "media_type": "image", "meta": [], "mime_type": "image/png", "modified": "2026-08-27T21:33:22", "modified_gmt": "2026-08-27T21:33:22", "ping_status": "closed", "post": 104, "slug": "10x10_e2e_test_image_z9t8jk-2", "source_url": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK-1.png", "status": "inherit", "template": "", "title": {"rendered": "10x10_e2e_test_image_z9T8jK"}, "type": "attachment"}, {"_links": {"about": [{"href": "http://localhost:8889/wp-json/wp/v2/types/attachment"}], "author": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/users/1"}], "collection": [{"href": "http://localhost:8889/wp-json/wp/v2/media"}], "curies": [{"href": "https://api.w.org/{rel}", "name": "wp", "templated": true}], "replies": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/comments?post=105"}], "self": [{"href": "http://localhost:8889/wp-json/wp/v2/media/105", "targetHints": {"allow": ["GET", "POST", "PUT", "PATCH", "DELETE"]}}], "wp:attached-to": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/posts/104", "id": 104, "post_type": "post"}]}, "alt_text": "", "author": 1, "caption": {"rendered": ""}, "class_list": ["post-105", "attachment", "type-attachment", "status-inherit", "hentry", "entry"], "comment_status": "open", "date": "2026-08-27T21:33:22", "date_gmt": "2026-08-27T21:33:22", "description": {"rendered": "<p class=\"attachment\"><a href='http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png'><img loading=\"lazy\" decoding=\"async\" width=\"10\" height=\"10\" src=\"http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png\" class=\"attachment-medium size-medium\" alt=\"\" style=\"width:100%;height:100%;max-width:10px;\" /></a></p>
"}, "featured_media": 0, "filename": "10x10_e2e_test_image_z9T8jK.png", "filesize": 80, "guid": {"rendered": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png"}, "id": 105, "link": "http://localhost:8889/?attachment_id=105", "media_details": {"file": "2026/08/10x10_e2e_test_image_z9T8jK.png", "filesize": 80, "height": 10, "image_meta": {"alt": "", "aperture": "0", "camera": "", "caption": "", "copyright": "", "created_timestamp": "0", "credit": "", "focal_length": "0", "iso": "0", "keywords": [], "orientation": "0", "shutter_speed": "0", "title": ""}, "sizes": {}, "width": 10}, "media_type": "image", "meta": [], "mime_type": "image/png", "modified": "2026-08-27T21:33:22", "modified_gmt": "2026-08-27T21:33:22", "ping_status": "closed", "post": 104, "slug": "10x10_e2e_test_image_z9t8jk", "source_url": "http://localhost:8889/wp-content/uploads/2026/08/10x10_e2e_test_image_z9T8jK.png", "status": "inherit", "template": "", "title": {"rendered": "10x10_e2e_test_image_z9T8jK"}, "type": "attachment"}]
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js:71:45

# Conflicts:
#	tools/eslint/suppressions.json
Rename the files this PR adds from .js to .ts/.tsx and add types so the
strict type check covers them: the word diff exports a WordDiffSegment
interface and the summary/actions components carry typed props. No behavior
changes; eslint suppression paths follow the renames.
# Conflicts:
#	packages/components/CHANGELOG.md
# Conflicts:
#	packages/editor/src/components/collab-sidebar/note.jsx
Changing an existing link's href keeps the same anchor tag and visible
text, so the summary fell back to a bare "Change: text" and a reviewer
could accept a new URL without ever seeing it. Compare link targets on
their own and report "Change link: old → new".

Claude-Session: https://claude.ai/code/session_01EmSXGAGtuLnk3UEe5kXPSU
@adamsilverstein

Copy link
Copy Markdown
Member Author

Claude picked up the review note on link summaries:

Fixed in 5c5169c. When the format diff finds no added or removed tags, the summary now compares link targets on their own. A retargeted link reads Change link: https://old.example → https://new.example instead of Change: text. It covers both attribute-set and inline format suggestions, with a test for each.

@mirka mirka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

button icons

Why are the check and remove button icons weird? Doesn't seem to match the design spec in the original issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not add legacy components in new code 🙂

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and the suppression is gone.

Claude checked what is left on the legacy side:

Text moved to @wordpress/ui in 99fa69d, which removed the suppressions entry. The file still imports Button and ConfirmDialog from @wordpress/components: their @wordpress/ui counterparts, IconButton and AlertDialog, are on the use-with-caution list in the use-recommended-components rule, so switching would need a new suppression and would mix the two systems in a header that already uses the legacy Button for Resolve. Happy to switch once those two are promoted.

adamsilverstein and others added 11 commits September 29, 2026 12:37
New code should not pull in legacy components. The summary and the
status lines under a suggestion used __experimentalText, which the
use-recommended-components rule flags, so both files needed lint
suppressions to land.

Switch to Text from @wordpress/ui (body-md for the 13px summary lines,
body-sm for the 12px status lines) and drop the two suppressions. The
ui Text has no muted variant, so the status lines get a small class
that applies the neutral-weak foreground token instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmgVCwTwC7cJaY1UYMBjpS
The header check and close icons looked mismatched. @wordpress/icons
now draws both as 1.5px stroked, non-scaling paths, but the header
still carried overrides written for the old filled glyphs: it blew
both icons up to 32px and forced a 1px stroke onto the check only. The
result was a thin, oversized check next to a heavier close icon, which
is not what the mockup in #73411 shows.

Render both as plain small icon buttons, the same size as the note's
Resolve and actions menu buttons, and drop the size and stroke
overrides. The two glyphs now share one weight and sit in the header
the way the design has them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmgVCwTwC7cJaY1UYMBjpS
…/review-ui

# Conflicts:
#	packages/editor/src/components/collab-sidebar/note.jsx
ResolvedSuggestionSummary's selector mapped fresh op objects on every
store change, so every suggestion note re-rendered and re-ran its word
diff per keystroke. Select only the marker strings and build the ops in
a memo. Note now calls useSuggestionDecision once and hands the result
to both the header buttons and the body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHz7zkCC2S8crriSWsYPDk
.editor-collab-sidebar-panel__suggestion-summary {
em {
font-style: italic;
color: $gray-700;

@aduth aduth Sep 30, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're using design system tokens elsewhere (e.g. --wpds-color-foreground-content-neutral-weak a few lines below), and I imagine we could do similar here to avoid mixing the two systems.

Opportunity for the design system: There might be an opportunity to clarify how agents think to work with shared variables between the base styles and design tokens.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapped in a0fd2a8: both colors now read --wpds-color-foreground-content-neutral-weak and the base-styles import is gone.

Comment thread packages/editor/src/components/collab-sidebar/suggestion-actions.tsx Outdated
adamsilverstein and others added 2 commits September 30, 2026 15:59
…ns.tsx

Co-authored-by: Andrew Duthie <1779930+aduth@users.noreply.github.com>
The suggestion summary stylesheet already reads its muted status color
from a design system token but set the quoted-text color from the
base-styles palette, mixing the two systems in one file. Read both from
the same foreground token and drop the base-styles import.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnVknLuyvKfR9DsM4H3SrX
@adamsilverstein

Copy link
Copy Markdown
Member Author

The mismatched icons were my doing, not the icon set's. Fixed in 5479ffc.

Claude went back over the icon styling and reports:

Both glyphs in @wordpress/icons are already drawn as matching 1.5px stroked paths. The header stylesheet was still carrying overrides written for the old filled glyphs: it scaled both buttons up to 32px and layered an extra 1px stroke on the check only, which is what produced the thin, oversized check next to the heavier close icon.

The overrides are gone. Accept and Reject now render as plain small icon buttons, the same size and weight as the note's Resolve button beside them, which matches the mockup in #73411.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Editor /packages/editor [Type] Feature New feature to highlight in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants