From c1dce209027ab0792b649d43e38122c4cb2c957e Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Fri, 4 Sep 2026 17:33:01 +0200 Subject: [PATCH] fix cmd+enter submit shortcut on modals #1238 --- e2e/time.spec.ts | 41 +++++++++++++++++++ .../Common/Client/ClientCreateModal.vue | 2 +- .../Common/Client/ClientEditModal.vue | 2 +- .../Common/Member/MemberEditModal.vue | 2 +- .../Common/Member/MemberInviteModal.vue | 2 +- .../Common/Project/ProjectEditModal.vue | 2 +- .../ProjectMemberCreateModal.vue | 2 +- .../ProjectMember/ProjectMemberEditModal.vue | 2 +- .../Common/Report/ReportCreateModal.vue | 2 +- .../Common/Report/ReportEditModal.vue | 2 +- .../js/Components/Common/Tag/TagEditModal.vue | 2 +- .../Common/Task/TaskCreateModal.vue | 2 +- .../Components/Common/Task/TaskEditModal.vue | 2 +- .../Timesheet/BreakPlacementModal.vue | 2 +- resources/js/packages/ui/src/DialogModal.vue | 9 +++- resources/js/packages/ui/src/Modal.vue | 25 +++++++++-- .../ui/src/Project/ProjectCreateModal.vue | 2 +- .../js/packages/ui/src/Tag/TagCreateModal.vue | 2 +- .../ui/src/TimeEntry/BreakCreateModal.vue | 2 +- .../ui/src/TimeEntry/TimeEntryCreateModal.vue | 2 +- .../ui/src/TimeEntry/TimeEntryEditModal.vue | 2 +- .../TimeEntry/TimeEntryMassUpdateModal.vue | 2 +- 22 files changed, 89 insertions(+), 24 deletions(-) diff --git a/e2e/time.spec.ts b/e2e/time.spec.ts index 486f1c88..f3fc8910 100644 --- a/e2e/time.spec.ts +++ b/e2e/time.spec.ts @@ -1579,6 +1579,47 @@ test('test that project selection works in create modal', async ({ page, ctx }) expect(createBody.data.project_id).not.toBeNull(); }); +test('test that ctrl+enter submits the create modal after selecting a project via keyboard', async ({ + page, + ctx, +}) => { + // Regression test for https://github.com/solidtime-io/solidtime/issues/1238 + const projectName = 'Keyboard Submit Project ' + Math.floor(1 + Math.random() * 10000); + await createProjectViaApi(ctx, { name: projectName }); + + await goToTimeOverview(page); + + await page.getByRole('button', { name: 'Time entry actions' }).click(); + await page.getByRole('menuitem', { name: 'Manual time entry' }).click(); + await expect(page.getByRole('dialog')).toBeVisible(); + + // Fill the description, then move to the project dropdown and select a project purely via keyboard + const description = page.getByRole('dialog').getByRole('textbox', { name: 'Description' }); + await description.fill('Keyboard submit test'); + await description.press('Tab'); + await expect( + page.getByRole('dialog').getByRole('button', { name: 'No Project' }) + ).toBeFocused(); + await page.keyboard.press('Enter'); + await page.getByTestId('client_dropdown_search').fill(projectName); + await expect(page.getByRole('option', { name: projectName })).toBeVisible(); + await page.keyboard.press('Enter'); + await expect(page.getByRole('dialog').getByRole('button', { name: projectName })).toBeVisible(); + + // Ctrl+Enter must submit even though focus is no longer on the description input + const [createResponse] = await Promise.all([ + page.waitForResponse( + (response) => response.url().includes('/time-entries') && response.status() === 201 + ), + page.keyboard.press('Control+Enter'), + ]); + const createBody = await createResponse.json(); + expect(createBody.data.description).toBe('Keyboard submit test'); + expect(createBody.data.project_id).not.toBeNull(); + await expect(page.getByRole('dialog')).toBeHidden(); + await expect(page.getByText('Keyboard submit test')).toBeVisible(); +}); + test('test that tag selection works in create modal', async ({ page }) => { await goToTimeOverview(page); diff --git a/resources/js/Components/Common/Client/ClientCreateModal.vue b/resources/js/Components/Common/Client/ClientCreateModal.vue index 6ce70036..5e71f273 100644 --- a/resources/js/Components/Common/Client/ClientCreateModal.vue +++ b/resources/js/Components/Common/Client/ClientCreateModal.vue @@ -28,7 +28,7 @@ useFocus(clientNameInput, { initialValue: true });