Skip to content

feat(cancel-button): improve UX with loading spinner and success state#774

Merged
aaight merged 2 commits intodevfrom
feature/improve-cancel-button-ux
Mar 13, 2026
Merged

feat(cancel-button): improve UX with loading spinner and success state#774
aaight merged 2 commits intodevfrom
feature/improve-cancel-button-ux

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 13, 2026

Summary

Enhanced the cancel run button in the dashboard with improved UX feedback and better confirmation flow.

Changes Made

  • Loading Spinner: Shows an animated spinner while the cancel mutation is in-flight, replacing the disabled state alone
  • Success Indicator: Displays a CheckCircle icon + "Cancelled" text after successful cancellation, auto-dismissing after 2 seconds
  • AlertDialog: Replaced native window.confirm() with shadcn/ui AlertDialog for consistent UX
  • Better Confirmation Text: Updated dialog from "Cancel this run?" to "This will terminate the worker container. Are you sure?"
  • Improved Error Display: Shows full error message (e.g., "Error: Network timeout") instead of just "Failed"
  • Prevent Double-Cancellation: Button is disabled during success state to prevent accidental resubmission

Acceptance Criteria Met

  • ✅ Cancel button shows loading spinner while mutation is in-flight
  • ✅ Shows success indication with auto-dismiss before query invalidation
  • ✅ Uses descriptive dialog message
  • ✅ Uses shadcn/ui AlertDialog instead of window.confirm()
  • ✅ Shows descriptive error messages
  • ✅ All tests pass, lint and typecheck clean

Testing

  • All 264 test files passed (4537 tests)
  • Lint: No errors or warnings
  • Typecheck: No type errors
  • Web build: Successful with no errors

Files Modified

  • `web/src/components/runs/cancel-run-button.tsx` — Complete UX overhaul with state management for loading, success, and error states

Card: https://trello.com/c/5serjXgw/305-as-a-user-i-want-improved-cancel-button-ux-in-the-dashboard-so-that-i-get-clear-feedback-when-stopping-a-run

- Add loading spinner (Loader2 with animate-spin) during mutation
- Show brief success indicator with auto-dismiss after 2 seconds
- Replace window.confirm() with shadcn AlertDialog
- Update dialog text: 'This will terminate the worker container?'
- Improve error display to show full error message
- Prevent double-cancellation by disabling button during success
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Good UX improvement overall — replacing window.confirm() with AlertDialog and adding loading/success states are solid changes. Two issues worth addressing: dead code in the dialog that can never execute, and a pattern deviation from existing AlertDialog usage.

Code Issues

Should Fix

  • web/src/components/runs/cancel-run-button.tsx:100-108 — The spinner and disabled states inside AlertDialogContent are dead code. Radix UI's AlertDialogAction auto-closes the dialog on click. Since onClick calls cancelMutation.mutate() and then the dialog immediately closes, cancelMutation.isPending will never be true while the dialog is visible. The <Loader2> spinner (line 107), and disabled={cancelMutation.isPending} on AlertDialogCancel (line 100) and AlertDialogAction (line 102) will never have any visible effect. This is misleading — it looks like the dialog stays open during the mutation, but it doesn't. Either remove the dead code from the dialog, or switch AlertDialogAction to a regular <Button> and manage dialog close manually in onSuccess if the intent is to show in-dialog progress.

  • web/src/components/runs/cancel-run-button.tsx:99 — Uses a raw <div> instead of AlertDialogFooter. Every other AlertDialog in the codebase (credentials-table.tsx, projects-table.tsx, agent-configs-table.tsx) uses AlertDialogFooter, which provides responsive layout (flex-col-reverse on mobile, sm:flex-row sm:justify-end). Should use AlertDialogFooter for consistency and better mobile behavior.

- Remove dead `disabled={cancelMutation.isPending}` props from AlertDialogCancel
  and AlertDialogAction — Radix UI auto-closes the dialog on action click, so
  isPending is never true while the dialog is visible
- Remove the unreachable Loader2 spinner inside AlertDialogAction for the same reason
- Replace raw `<div>` footer with `AlertDialogFooter` for consistent responsive
  layout matching credentials-table, projects-table, and agent-configs-table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Clean implementation that correctly replaces window.confirm() with shadcn/ui AlertDialog and adds loading/success/error states. Follows existing codebase patterns (matches projects-table, credentials-table, agent-configs-table AlertDialog usage). No blocking issues.

Minor Observations

Should consider

  • Race condition on success visibility (line 34): onSuccess sets showSuccess(true) and invalidates queries simultaneously. If the query re-fetch resolves quickly (status changes from 'running' to something else), the component returns null before the 2-second success indicator is visible to the user. Consider delaying the invalidateQueries calls to fire after the 2-second success display (e.g., inside the timeout callback) if the success indicator is important for user feedback. This is a UX polish point, not a bug.
  • Minor style inconsistency (line 109): The destructive button uses text-destructive-foreground while projects-table.tsx and credentials-table.tsx use text-white. Both work, but text-destructive-foreground is arguably more correct (semantic token). Just noting the inconsistency — agent-configs-table.tsx already uses the same approach as this PR.

@aaight aaight merged commit 247c48d into dev Mar 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants