🥂 feat: Toasts on All Save Actions#81
Merged
Merged
Conversation
* feat: success/error toasts on every admin panel save action Wires click-ui's Toast component into every save mutation in the admin panel: config editor (per-field, bulk, YAML import), groups (create / edit / delete), roles (create / edit / delete), users (invite, delete, role / group assignment, user profile create / delete), system grants (EditCapabilitiesDialog), and per-field profile mutations (useProfileMutations). Uses click-ui's official createToast directly; ClickUIProvider already mounts the matching ToastProvider, so the global createToast routes through it. Toasts inherit click-ui brand colours, WCAG contrast, keyboard accessibility, swipe-to-dismiss, close button, ARIA live region, and 5s auto-dismiss from the library. src/utils/toast.ts is a five-line wrapper exposing notifySuccess and notifyError that delegate to click-ui's createToast. Call sites pass the affected resource through mutation variables (not closed-over component state) so the toast renders the correct name even when the confirm dialog has already cleared its target by the time the response lands. Refs AI-1206. * fix: throw instead of silently no-op when target missing in edit mutations EditGroupDialog, EditRoleDialog and EditCapabilitiesDialog mutationFns used to bail with an empty return when their target (group, role, principal) was missing, which React Query treats as success and which caused the new onSuccess handlers to fire a success toast and close the dialog without anything having been persisted. Throw a localised error in the unavailable case so onError fires instead, and add a matching guard at each call site so mutate is never invoked with a missing target in the first place. * fix: capture submitted name in mutation variables for create/edit toasts The five create and edit dialogs used to read the resource name from component state inside onSuccess instead of from the value that was submitted with the mutation. If the user edited the name field while the request was in flight (or the dialog reset before the toast fired), the toast could render an empty or wrong name even though the server saved the original value. Pass the submitted name through the mutation variables, use it for the actual API call, and read it back from the mutation's data or variables argument in onSuccess so the toast always reflects what was persisted.
6 tasks
danny-avila
approved these changes
Jun 18, 2026
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.
Summary
Wires
@clickhouse/click-ui'sToastinto every save mutation in the admin panel so admins get visible feedback on both success and failure. Before this PR most save sites silently swallowed errors toconsole.errorand showed nothing on success.Depends on the Radix
react-dismissable-layerdedupe in #80. Without that dedupe click-ui's toast auto-dismiss timer is killed by the shared-layer-set race as soon as any modal opens or closes.notifySuccess(title)andnotifyError(title)helpers insrc/utils/toast.tsthat delegate to click-ui's exportedcreateToast.ClickUIProvideralready mounts the matchingToastProvider, so no extra wiring is needed at the root.UserDetailDialog, user-profile create/delete, system grants inEditCapabilitiesDialog, and per-field profile values inuseProfileMutations.onSuccess, so the toast still renders the correct name when the confirm dialog has cleared its target by the time the response lands..config-toast*CSS block andToastStatetype left over from the oldConfigPage-local toast portal.com_toast_*for the per-resource success messages (com_toast_group_deleted,com_toast_role_updated, etc.).Change Type
Implementation
src/utils/toast.ts: five-line module exportingnotifySuccessandnotifyErrorovercreateToast({ type: 'success' | 'danger', title }). Toasts inherit click-ui's brand colours, WCAG contrast, dismiss button, swipe-to-dismiss, ARIA live region, keyboard accessibility, and 5s auto-dismiss from the library.GroupsTab,RolesTab,UsersPagedelete-mutationmutationFnnow takes the full target object;UserDetailDialog's add/remove role/group mutations take{ id, name };EditCapabilitiesDialog's save passes{ name: principalName }. EachonSuccessreads from the mutation'svariablesarg so the toast cannot read an empty string when the confirm dialog has already closed.ConfigPagedrops its localuseState<ToastState>+ portal and instead callsnotifySuccessandnotifyErrordirectly. ThenotifySavingintermediate state is gone since the bulk save flow already shows pending state viaConfirmSaveDialog'ssavingprop and the StickyActionBar's disabled save button.Testing
SESSION_SECRET=12345678901234567890123456789012 bun run test: 675 tests pass across 17 files.bun run lint: clean.SESSION_SECRET=12345678901234567890123456789012 bun run build: production build green.Checklist
Note
Medium Risk
Wide UI-only surface area across admin mutations (including capabilities and access control), but server behavior is largely unchanged aside from clearer client error handling and toast timing dependency on click-ui/Radix dismissable-layer behavior.
Overview
Adds shared
notifySuccess/notifyErrorhelpers that call click-uicreateToast, and uses them across admin save/delete flows so successes and failures are visible instead of inline-only or silent errors.Config drops the local
ToastStateportal and.config-toast*CSS in favor of toasts on save, validation, import, and scope errors; the in-flight “Saving…” toast is removed (pending state stays on the confirm dialog / action bar).Access, users, grants, and profile field edits fire localized
com_toast_*messages on create/update/delete and on role/group assignment changes. Mutations now pass the affected resource (full entity or{ id, name }) throughmutatevariables so toast text stays correct after confirm dialogs close. SeveralonErrorhandlers switch fromsetErrortonotifyError; role delete no longer usesConfirmDialog’serrorprop.Edit save paths throw when group/role/principal is missing instead of no-op returns.
Reviewed by Cursor Bugbot for commit 2fa6042. Bugbot is set up for automated code reviews on this repo. Configure here.