Skip to content

fix(ui-react): surface swallowed errors in ConfirmDialog delete flows#6168

Open
luizhf42 wants to merge 5 commits intomasterfrom
fix/ui-react/confirm-dialog-suppressed-errors
Open

fix(ui-react): surface swallowed errors in ConfirmDialog delete flows#6168
luizhf42 wants to merge 5 commits intomasterfrom
fix/ui-react/confirm-dialog-suppressed-errors

Conversation

@luizhf42
Copy link
Copy Markdown
Member

What

Five confirm-dialog delete flows in the console silently swallowed mutation errors on failure, leaving the dialog stuck open with no explanation. Each now catches the rejection, keeps the dialog open, and renders a human-readable error inline.

Why

ConfirmDialog intentionally swallows exceptions from onConfirm and expects consumers to pre-catch and manage their own error state (the component's comment points at KeyDeleteDialog as the reference implementation). Three pages listed in #6165 — firewall rules, public keys, API keys — violated that contract with an uncaught await mutateAsync inside onConfirm. A grep of apps/console/src/pages surfaced two more with the same pattern: team members and web endpoints.

Closes #6165

Changes

  • firewall-rules, public-keys, api-keys, members, web-endpoints: mirrored the KeyDeleteDialog shape — local deleteError state, closeDelete handler that resets both the target and the error, confirmDelete handler that wraps mutateAsync in try/catch and falls back to "Failed to delete …" when the rejection isn't an Error. Success-path side effects (page decrement, dialog close) only run on success.
  • tests: added vitest coverage for the three pages named in the issue (firewall rules, public keys, API keys). Each file mocks the data hook, the mutation hook, and flattens ConfirmDialog — matching the existing pattern used by DeleteNamespaceDialog.test.tsx and KeyDeleteDialog.test.tsx. Coverage asserts: the raw Error.message is shown, the generic fallback is shown for non-Error rejections, the dialog closes on success, and stale error text clears on cancel+reopen.

Testing

The large line count on WebEndpoints.tsx is the project formatter normalizing the whole file on first edit — the intended change is the new state + handlers plus the ConfirmDialog wiring (same shape as the other four pages). Review that file's diff with whitespace ignored to see the real change.

Reviewers can exercise the error path manually by opening any of the five pages with the API unreachable (or returning 4xx/5xx), clicking a destructive action, and confirming: the dialog should stay open, the confirm button should re-enable, and a red error message should appear below the description.

The confirm dialog swallowed any error from the delete mutation, leaving
the user with a stuck dialog and no explanation. Track the error locally
and render it via ConfirmDialog's children so the dialog stays open with
a visible message on failure.
Same swallowed-error bug as the firewall rules page — catch the mutation
rejection, keep the dialog open, and render the message via ConfirmDialog
children.
Same swallowed-error bug as the other confirm dialogs — catch the
mutation rejection, keep the dialog open, and render the message via
ConfirmDialog children.
Same swallowed-error bug as the other confirm dialogs — catch the
mutation rejection, keep the dialog open, and render the message via
ConfirmDialog children.
Same swallowed-error bug as the other confirm dialogs — catch the
mutation rejection, keep the dialog open, and render the message via
ConfirmDialog children.

The large diff is from the formatter normalizing the whole file; the
intended change is the new deleteError state plus the closeDelete /
confirmDelete handlers wired to ConfirmDialog.

Fixes: #6165
@luizhf42 luizhf42 requested a review from a team as a code owner April 13, 2026 20:54
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 13, 2026

Claude finished @luizhf42's task in 4m 17s —— View job


Code Review Complete

Reviewed 8 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. The code looks good as-is.

All five pages correctly mirror the KeyDeleteDialog reference pattern: local deleteError/removeError state, try/catch around mutateAsync, closeDelete handler that resets both error and target, error rendered via ConfirmDialog children slot. The ConfirmDialog contract (swallows exceptions, expects pre-caught onConfirm) is properly satisfied. The three new test files are well-structured with correct ConfirmDialog mocks and good assertion coverage.


If you push additional changes and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 self-assigned this Apr 13, 2026
@luizhf42 luizhf42 added kind/bug Something isn't working area/ui labels Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ui kind/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui-react: delete confirm dialogs silently swallow mutation errors

1 participant