From f44ff67ff4e14cc0baaa6b8cba43c44294dcfdda Mon Sep 17 00:00:00 2001 From: arnestrickmann <115920878+arnestrickmann@users.noreply.github.com> Date: Mon, 2 Nov 2026 13:48:26 -0800 Subject: [PATCH 1/3] submit confirmation dialogs with enter --- .../src/components/confirm-dialog.test.tsx | 52 +++++++++++++++++++ .../web/src/components/confirm-dialog.tsx | 43 ++++++++------- 2 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 packages/web/src/components/confirm-dialog.test.tsx diff --git a/packages/web/src/components/confirm-dialog.test.tsx b/packages/web/src/components/confirm-dialog.test.tsx new file mode 100644 index 00000000..1a040676 --- /dev/null +++ b/packages/web/src/components/confirm-dialog.test.tsx @@ -0,0 +1,52 @@ +/// + +import {afterEach, describe, expect, mock, test} from 'bun:test'; +import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; +import {ConfirmDialog} from '@/components/confirm-dialog'; + +afterEach(() => { + cleanup(); +}); + +function renderDialog({destructive = false}: {destructive?: boolean} = {}) { + const onClose = mock(); + const onConfirm = mock(); + render( + , + ); + return {onClose, onConfirm}; +} + +describe('ConfirmDialog', () => { + test('uses the confirmation as the default action when it is safe', async () => { + const {onClose, onConfirm} = renderDialog(); + const confirm = screen.getByRole('button', {name: 'Share'}); + + await waitFor(() => expect(document.activeElement).toBe(confirm)); + expect(confirm.getAttribute('type')).toBe('submit'); + fireEvent.click(confirm); + + expect(onConfirm).toHaveBeenCalledTimes(1); + expect(onClose).toHaveBeenCalledTimes(1); + }); + + test('uses cancel as the default action when confirmation is destructive', async () => { + const {onClose, onConfirm} = renderDialog({destructive: true}); + const cancel = screen.getByRole('button', {name: 'Cancel'}); + + await waitFor(() => expect(document.activeElement).toBe(cancel)); + expect(cancel.getAttribute('type')).toBe('button'); + fireEvent.click(cancel); + + expect(onConfirm).not.toHaveBeenCalled(); + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/web/src/components/confirm-dialog.tsx b/packages/web/src/components/confirm-dialog.tsx index 49cc1fca..75c6824e 100644 --- a/packages/web/src/components/confirm-dialog.tsx +++ b/packages/web/src/components/confirm-dialog.tsx @@ -39,24 +39,31 @@ export function ConfirmDialog({ }} > - - {title} - {description} - - - - - +
{ + event.preventDefault(); + onConfirm(); + onClose(); + }} + > + + {title} + {description} + + + + + +
); From 5b64f57c1609508dd7278a97a10b7522f775aeed Mon Sep 17 00:00:00 2001 From: arnestrickmann <115920878+arnestrickmann@users.noreply.github.com> Date: Mon, 2 Nov 2026 13:53:44 -0800 Subject: [PATCH 2/3] support command-enter in confirmation dialogs --- .../src/components/confirm-dialog.test.tsx | 4 ++- .../web/src/components/confirm-dialog.tsx | 4 +++ .../src/components/persona-dialog.test.tsx | 27 +++++++++++++++++++ .../web/src/components/persona-dialog.tsx | 3 +++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 packages/web/src/components/persona-dialog.test.tsx diff --git a/packages/web/src/components/confirm-dialog.test.tsx b/packages/web/src/components/confirm-dialog.test.tsx index 1a040676..a4e19166 100644 --- a/packages/web/src/components/confirm-dialog.test.tsx +++ b/packages/web/src/components/confirm-dialog.test.tsx @@ -32,7 +32,7 @@ describe('ConfirmDialog', () => { await waitFor(() => expect(document.activeElement).toBe(confirm)); expect(confirm.getAttribute('type')).toBe('submit'); - fireEvent.click(confirm); + fireEvent.keyDown(window, {key: 'Enter', metaKey: true}); expect(onConfirm).toHaveBeenCalledTimes(1); expect(onClose).toHaveBeenCalledTimes(1); @@ -44,6 +44,8 @@ describe('ConfirmDialog', () => { await waitFor(() => expect(document.activeElement).toBe(cancel)); expect(cancel.getAttribute('type')).toBe('button'); + fireEvent.keyDown(window, {key: 'Enter', metaKey: true}); + expect(onConfirm).not.toHaveBeenCalled(); fireEvent.click(cancel); expect(onConfirm).not.toHaveBeenCalled(); diff --git a/packages/web/src/components/confirm-dialog.tsx b/packages/web/src/components/confirm-dialog.tsx index 75c6824e..87f9888f 100644 --- a/packages/web/src/components/confirm-dialog.tsx +++ b/packages/web/src/components/confirm-dialog.tsx @@ -8,6 +8,7 @@ import { DialogHeader, DialogTitle, } from '@proxy/ui/components/dialog'; +import {useCommandEnterSubmit} from '@/hooks/use-command-enter'; type Props = { open: boolean; @@ -28,6 +29,8 @@ export function ConfirmDialog({ onClose, onConfirm, }: Props) { + const form = useCommandEnterSubmit(!destructive); + return (
{ event.preventDefault(); diff --git a/packages/web/src/components/persona-dialog.test.tsx b/packages/web/src/components/persona-dialog.test.tsx new file mode 100644 index 00000000..ff984a90 --- /dev/null +++ b/packages/web/src/components/persona-dialog.test.tsx @@ -0,0 +1,27 @@ +/// + +import {afterEach, describe, expect, mock, test} from 'bun:test'; +import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; + +mock.module('@/components/head', () => ({LiveHead: () => null})); + +const {PersonaDialog} = await import('@/components/persona-dialog'); + +afterEach(() => { + cleanup(); +}); + +describe('PersonaDialog', () => { + test('creates an agent with Command+Enter', async () => { + const onClose = mock(); + const onSave = mock(async () => null); + render(); + + fireEvent.change(screen.getByLabelText('Name'), {target: {value: 'Finance'}}); + fireEvent.keyDown(window, {key: 'Enter', metaKey: true}); + + await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1)); + expect(onSave).toHaveBeenCalledWith(expect.objectContaining({name: 'Finance'})); + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/web/src/components/persona-dialog.tsx b/packages/web/src/components/persona-dialog.tsx index 6c4e3ee9..c9907bb8 100644 --- a/packages/web/src/components/persona-dialog.tsx +++ b/packages/web/src/components/persona-dialog.tsx @@ -16,6 +16,7 @@ import { import {Input} from '@proxy/ui/components/input'; import {Label} from '@proxy/ui/components/label'; import {cn} from '@proxy/ui/lib/utils'; +import {useCommandEnterSubmit} from '@/hooks/use-command-enter'; type Props = { open: boolean; @@ -62,6 +63,7 @@ export function PersonaDialog({open, initial, onClose, onSave, onDelete}: Props) const [error, setError] = useState(null); const [busy, setBusy] = useState(false); const ready = persona.name.trim() !== ''; + const form = useCommandEnterSubmit(ready && !busy); const finish = (failed: string | null) => { setBusy(false); @@ -83,6 +85,7 @@ export function PersonaDialog({open, initial, onClose, onSave, onDelete}: Props) > { event.preventDefault(); From ddbba9aa87e2bb4b6cda8c6b38a145fc03ffdc82 Mon Sep 17 00:00:00 2001 From: arnestrickmann <115920878+arnestrickmann@users.noreply.github.com> Date: Mon, 2 Nov 2026 13:58:30 -0800 Subject: [PATCH 3/3] limit dialog shortcuts to open dialogs --- packages/web/src/components/confirm-dialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/components/confirm-dialog.tsx b/packages/web/src/components/confirm-dialog.tsx index 87f9888f..5c5f451a 100644 --- a/packages/web/src/components/confirm-dialog.tsx +++ b/packages/web/src/components/confirm-dialog.tsx @@ -29,7 +29,7 @@ export function ConfirmDialog({ onClose, onConfirm, }: Props) { - const form = useCommandEnterSubmit(!destructive); + const form = useCommandEnterSubmit(open && !destructive); return (