Skip to content

[codex] Enable Enter on destructive alert dialogs#2995

Merged
Kitenite merged 3 commits into
mainfrom
update-alert-dialogs-to-be-triggerable-by-enter-ke
Mar 29, 2026
Merged

[codex] Enable Enter on destructive alert dialogs#2995
Kitenite merged 3 commits into
mainfrom
update-alert-dialogs-to-be-triggerable-by-enter-ke

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Mar 29, 2026

Summary

  • add an opt-in EnterEnabledAlertDialogContent in packages/ui that focuses the dialog's AlertDialogAction when the dialog opens
  • extend AlertDialogAction to carry the shared action slot and support button variant and size props
  • apply it to the desktop discard and close dialogs so pressing Enter activates the destructive AlertDialogAction immediately

Why

The discard and close confirmation dialogs did not consistently route Enter to the intended destructive action. The behavior was being handled locally instead of through the shared alert-dialog primitives.

Impact

Desktop discard and close confirmations now respond to Enter by activating the primary destructive AlertDialogAction without changing unrelated alert dialogs globally.

Validation

  • bun test packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/DeleteWorkspaceDialog/DeleteWorkspaceDialog.test.ts
  • bun run --cwd packages/ui typecheck
  • bunx biome check --write packages/ui/src/components/ui/alert-dialog.tsx packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.ts packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/UnsavedChangesDialog.tsx apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/components/DiscardConfirmDialog/DiscardConfirmDialog.tsx apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/CloseProjectDialog.tsx apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx

Summary by CodeRabbit

  • Improvements
    • Improved keyboard behavior in confirmation dialogs so Enter focuses and activates the primary action (faster keyboard confirmations).
    • Better focus management when dialogs open, enhancing accessibility for keyboard-only users across project close, unsaved changes, and discard confirmations.
  • Tests
    • Added tests covering the Enter-to-focus-and-activate dialog behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

An Enter-enabled alert-dialog flow was added: a new EnterEnabledAlertDialogContent component invokes a focus utility on open-auto-focus events to focus enabled primary actions. AlertDialogContent styling was consolidated; AlertDialogAction gained variant/size props and a data-slot="alert-dialog-action" attribute. Several dialogs were switched to the new content component.

Changes

Cohort / File(s) Summary
Core Alert Dialog Components
packages/ui/src/components/ui/alert-dialog.tsx, packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.ts
Added EnterEnabledAlertDialogContent; extracted alertDialogContentClassName; added alertDialogPrimaryActionSelector and focusEnterEnabledAlertDialogPrimaryAction. Updated AlertDialogAction typing to accept variant/size and set data-slot="alert-dialog-action".
Alert Dialog Utility Tests
packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts
New tests covering focus/preventDefault behavior for presence/absence/of already-prevented open-auto-focus events.
Dialog Screen Updates
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/CloseProjectDialog.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/UnsavedChangesDialog.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/components/DiscardConfirmDialog/DiscardConfirmDialog.tsx
Switched dialog wrappers from AlertDialogContent to EnterEnabledAlertDialogContent. Primary destructive actions changed from plain Button to AlertDialogAction (now exposed via data-slot="alert-dialog-action") and handlers no longer manually call the dialog close prior to invoking confirm/discard logic.

Sequence Diagram

sequenceDiagram
    participant User
    participant Dialog as EnterEnabledAlertDialogContent
    participant Utility as focusEnterEnabledAlertDialogPrimaryAction
    participant DOM as DOM Query
    participant Button as Primary Action Button

    User->>Dialog: Dialog opens (onOpenAutoFocus triggered)
    Dialog->>Utility: invoke onOpenAutoFocus handler with event
    Utility->>Utility: if event.defaultPrevented? (exit if true)
    Utility->>DOM: query currentTarget for [data-slot='alert-dialog-action']:not([disabled])
    alt Primary action found
        DOM-->>Utility: return button element
        Utility->>Utility: call event.preventDefault()
        Utility->>Button: call focus()
    else No primary action found
        DOM-->>Utility: return null
    end
    Utility-->>Dialog: done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped in to see dialogs brighten and zoom,

Primary buttons flagged to leap from the gloom,
Enter wakes focus, a small magical start,
Dialogs now listen and play their part,
A rabbit's soft cheer for this focused bloom. 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: enabling Enter key functionality on destructive alert dialogs across the desktop application.
Description check ✅ Passed The description is comprehensive and follows the template structure with Summary, Why, Impact, and Validation sections clearly addressing all key aspects of the change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch update-alert-dialogs-to-be-triggerable-by-enter-ke
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch update-alert-dialogs-to-be-triggerable-by-enter-ke

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 7 files

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts (1)

36-50: Consider adding a disabled-primary regression test.

Since the selector explicitly excludes disabled actions, a test with a marked-but-disabled button would lock in that contract.

🧪 Suggested test addition
 describe("focusEnterEnabledAlertDialogPrimaryAction", () => {
+	test("does nothing when only a disabled primary action exists", () => {
+		let prevented = false;
+		let focused = false;
+
+		focusEnterEnabledAlertDialogPrimaryAction({
+			currentTarget: {
+				querySelector: (selector: string) => {
+					expect(selector).toBe(alertDialogPrimaryActionSelector);
+					return null; // simulates selector excluding disabled primary
+				},
+			},
+			defaultPrevented: false,
+			preventDefault: () => {
+				prevented = true;
+			},
+		});
+
+		expect(prevented).toBe(false);
+		expect(focused).toBe(false);
+	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts`
around lines 36 - 50, Add a regression test in
focus-enter-enabled-alert-dialog-primary-action.test.ts that verifies a
marked-but-disabled primary action does not trigger or prevent default: call
focusEnterEnabledAlertDialogPrimaryAction with an event whose
currentTarget.querySelector returns an element that matches the primary-action
marker used in the implementation (e.g., an element with the same data attribute
or class the function searches for) but has the disabled property true, and
assert that the event.preventDefault() was not called (prevented remains false);
this ensures the function's exclusion of disabled buttons is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts`:
- Around line 36-50: Add a regression test in
focus-enter-enabled-alert-dialog-primary-action.test.ts that verifies a
marked-but-disabled primary action does not trigger or prevent default: call
focusEnterEnabledAlertDialogPrimaryAction with an event whose
currentTarget.querySelector returns an element that matches the primary-action
marker used in the implementation (e.g., an element with the same data attribute
or class the function searches for) but has the disabled property true, and
assert that the event.preventDefault() was not called (prevented remains false);
this ensures the function's exclusion of disabled buttons is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a90d725-5bfe-4255-ab2d-465a5b43ae00

📥 Commits

Reviewing files that changed from the base of the PR and between 8dc5c38 and ae58a24.

📒 Files selected for processing (7)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/CloseProjectDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/UnsavedChangesDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/components/DiscardConfirmDialog/DiscardConfirmDialog.tsx
  • packages/ui/src/components/ui/alert-dialog.tsx
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/ui/src/components/ui/alert-dialog.tsx (2)

7-7: Co-locate the focus helper with this component.

Line 7 pulls an alert-dialog-specific helper from packages/ui/src/lib, which makes the selector and the consuming markup easier to evolve separately. Keeping it next to alert-dialog.tsx would better match the ownership boundary here.

As per coding guidelines, "**/components/**/*.{ts,tsx}: Co-locate utils, hooks, constants, config, tests, and stories next to the file using them`."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/ui/alert-dialog.tsx` at line 7, Move the
alert-dialog-specific helper focusEnterEnabledAlertDialogPrimaryAction out of
packages/ui/src/lib and co-locate it with alert-dialog.tsx (e.g., create a
sibling file like focus-enter-enabled-alert-dialog-primary-action.ts or inline
it), update the import in alert-dialog.tsx to the new relative path, and remove
or refactor the original exported helper from the lib area (or re-export it from
the new location) so the selector and consuming markup remain owned by the
component; ensure any other consumers update their imports to the new module.

144-155: Expose an explicit Enter target instead of matching every action.

Line 153 makes every AlertDialogAction eligible for the helper selector, and focusEnterEnabledAlertDialogPrimaryAction currently takes the first enabled match. That is fine for single-action dialogs, but reusable dialogs with two confirm actions would end up relying on DOM order instead of an explicit primary target.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/ui/alert-dialog.tsx` around lines 144 - 155, The
helper currently matches every AlertDialogAction and picks the first enabled
one; update AlertDialogAction to accept an explicit enter-target prop (e.g.,
enterTarget?: boolean or enterKeyTarget?: 'primary') and when set render a
distinct data attribute (e.g., data-enter-target="primary") on the
AlertDialogPrimitive.Action element; then change the helper selector
focusEnterEnabledAlertDialogPrimaryAction to prefer elements with that attribute
([data-enter-target="primary"]) so dialogs with multiple confirm actions can opt
one explicit primary enter target instead of relying on DOM order.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/ui/src/components/ui/alert-dialog.tsx`:
- Line 7: Move the alert-dialog-specific helper
focusEnterEnabledAlertDialogPrimaryAction out of packages/ui/src/lib and
co-locate it with alert-dialog.tsx (e.g., create a sibling file like
focus-enter-enabled-alert-dialog-primary-action.ts or inline it), update the
import in alert-dialog.tsx to the new relative path, and remove or refactor the
original exported helper from the lib area (or re-export it from the new
location) so the selector and consuming markup remain owned by the component;
ensure any other consumers update their imports to the new module.
- Around line 144-155: The helper currently matches every AlertDialogAction and
picks the first enabled one; update AlertDialogAction to accept an explicit
enter-target prop (e.g., enterTarget?: boolean or enterKeyTarget?: 'primary')
and when set render a distinct data attribute (e.g.,
data-enter-target="primary") on the AlertDialogPrimitive.Action element; then
change the helper selector focusEnterEnabledAlertDialogPrimaryAction to prefer
elements with that attribute ([data-enter-target="primary"]) so dialogs with
multiple confirm actions can opt one explicit primary enter target instead of
relying on DOM order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6c3b95bd-638c-4120-8f0d-b659935fee74

📥 Commits

Reviewing files that changed from the base of the PR and between ae58a24 and 9603c27.

📒 Files selected for processing (7)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/CloseProjectDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/UnsavedChangesDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/components/DiscardConfirmDialog/DiscardConfirmDialog.tsx
  • packages/ui/src/components/ui/alert-dialog.tsx
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/UnsavedChangesDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/components/DiscardConfirmDialog/DiscardConfirmDialog.tsx
  • packages/ui/src/lib/focus-enter-enabled-alert-dialog-primary-action.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx

…to-be-triggerable-by-enter-ke

# Conflicts:
#	apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/ChangesView/ChangesView.tsx
@Kitenite Kitenite merged commit bd61cc1 into main Mar 29, 2026
14 checks passed
@Kitenite Kitenite deleted the update-alert-dialogs-to-be-triggerable-by-enter-ke branch March 29, 2026 22:46
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 29, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

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.

1 participant