Dashboard: success snackbar on layout save - #78072
Conversation
Wraps the dashboard route's onLayoutChange handler so it dispatches a success notice on @wordpress/notices after persisting. The user gets a "Layout saved." snackbar on Done, matching the feedback pattern used by other admin surfaces (e.g., experimental features toggles).
|
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: 0 B Total Size: 7.93 MB ℹ️ View Unchanged
|
|
Flaky tests detected in 3ac859d. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25678360226
|
d6eef0d to
cfa391b
Compare
3ac859d to
a29c168
Compare
50bf18c
into
update/dashboard-staging-layout
* add staging layer to WidgetDashboard WidgetDashboardProvider now keeps an internal staging copy of the layout. In-progress mutations (drag, resize, insert, setAttributes) mutate staging only; the consumer's onLayoutChange fires once on commit. Adds hasUncommittedChanges (deep-equal between committed and staging via fast-deep-equal) plus commitLayout and cancelLayout actions. Auto-flips edit mode on when the layout becomes empty. Existing tests are updated to follow the staged commit flow (insert or setAttributes followed by Done) and the actions harness now uses a non-empty layout so the auto-edit effect does not interfere. * wire Done and Cancel to commit and cancel actions Replaces the placeholder console.log handlers in the dashboard toolbar with the staging-layer commit and cancel actions. Done publishes the staged layout to the consumer; Cancel discards it and exits edit mode without firing onLayoutChange. * fix icon property type: IconType * switch useDashboardLayout to a named export Aligns the hook with the rest of the route's named-export convention (the local barrel and stage.tsx already imported it as named via re-export). Drops the now-stale test under the shared hooks/test directory; the test moves next to the source in a follow-up. * colocate useDashboardLayout test with its source Moves the unit test alongside the hook implementation under hooks/use-dashboard-layout/test/, so each hook owns its tests and the shared hooks/test/ directory disappears. * ignore placement.order in uncommitted-changes diff The grid model assigns explicit `order: 0, 1, …` to each item after the first drag. A swap followed by an undo restores the visible arrangement but leaves explicit orders in staging, while the committed layout never had any. Deep-equal flagged this as dirty and the toolbar treated it as a pending change. Canonicalize both layouts before comparison: sort by `placement.order` (falling back to the array index when omitted), then strip `order` since the array position now encodes it. Adds a regression test that simulates a swap and its undo. * disable Done when there are no uncommitted changes The Done button now reads `hasUncommittedChanges` from the dashboard context and renders disabled when staging matches committed. Avoids the no-op confirmation path when the user enters Customize and exits without touching the layout. Replaces the toggle-on-click test with a Customize-only assertion plus an explicit "Done is disabled when there are no staging changes" check. * clarify onLayoutChange documentation The block doc for WidgetDashboardProps and the field doc for onLayoutChange were stale: the former mentioned a "reset replaces the committed layout from outside" path that does not flow through this callback, and the latter still described "every layout mutation". With the staging layer in place, onLayoutChange only fires from commitLayout (the Done action). Documents the actual contract. * canonicalize layout before publishing on commit commitLayout was publishing the raw stagingLayout, while hasUncommittedChanges already compared canonicalized copies. The persisted payload accumulated redundant placement.order values that the comparison treated as implicit; the publish form and the compare form had drifted. Pipe the staged layout through canonicalize() before invoking the consumer's onLayoutChange so the persisted shape is sorted by order with `order` stripped, matching the canonical comparison form. Updates the canonicalize doc to describe the dual use and adds a test that pins the publish payload. * Dashboard: success snackbar on layout save (#78072) * show success snackbar when the dashboard layout is saved Wraps the dashboard route's onLayoutChange handler so it dispatches a success notice on @wordpress/notices after persisting. The user gets a "Layout saved." snackbar on Done, matching the feedback pattern used by other admin surfaces (e.g., experimental features toggles). * Reword saving dashboard message * udpate npm lock file
What?
The dashboard route now dispatches a
'Layout saved.'snackbar via@wordpress/noticesafter the layout is committed. Same feedback pattern that the experimental-features toggle uses ('Other settings updated.'), built on the same store.Part of #77616 #78035
Why?
The staging-layer change in #78071 makes Done the explicit save action, but right now the click is silent. The user has no confirmation that anything happened beyond the toolbar collapsing. A snackbar gives the same low-cost reassurance that other admin surfaces give for similar actions (settings toggles, post saves).
How?
routes/dashboard/stage.tsxwraps the existingsetLayouthandler in ahandleLayoutChangethat firessetLayout(next)and then dispatchescreateSuccessNotice( 'Layout saved.', { type: 'snackbar' } )viauseDispatch( noticesStore ). The notice action isvoid-ed since we don't need the returned id and the dispatch returns a thunk. Adds@wordpress/noticesto the route's dependencies.The notice fires only on commit (Done), because the staging layer in #78071 already ensures
onLayoutChangeis the commit-only path. Reset has its own visual feedback (the confirmation dialog closes) and is not noticed for now; we can revisit when there's a clearer UX call for it.Where the notice should live longer-term
For now it lives in the consumer (
stage.tsx). TheWidgetDashboardprovider is kept as a pure state machine with no opinion on UX. If a second consumer ofWidgetDashboardlands and we want consistent feedback across surfaces, the notice can move into the provider'scommitLayout(or be exposed as an opt-in prop). Doing it in the consumer first lets each surface customize the message or skip it.Stacked PR
Built on top of #78071 (staging layer). The commit-only semantics that this notice depends on come from that PR; merging this one before #78071 would mean the notice fires on every drag and resize, which is exactly the spammy behavior we wanted to avoid.
Testing
'Layout saved.'snackbar appears at the bottom.Screen.Recording.2026-05-07.at.7.02.34.PM.mov
Follow-ups
WidgetDashboardprovider (or behind an opt-in prop) once a second consumer lands and we want shared feedback semantics.