diff --git a/web/src/settings/AISettingsPage.module.css b/web/src/settings/AISettingsPage.module.css index 6ca3105..e18f2f3 100644 --- a/web/src/settings/AISettingsPage.module.css +++ b/web/src/settings/AISettingsPage.module.css @@ -305,8 +305,9 @@ resize: none; } -/* A form locked while its save is pending, so no edit is made that the - saved settings would then replace. It lays out as if it were not there. */ +/* A form locked while its save or prompt reset is pending, so no edit is + made that the response would then replace. It lays out as if it were not + there. */ .lock { display: contents; } diff --git a/web/src/settings/AISettingsPage.test.tsx b/web/src/settings/AISettingsPage.test.tsx index 73e68c7..b0803a5 100644 --- a/web/src/settings/AISettingsPage.test.tsx +++ b/web/src/settings/AISettingsPage.test.tsx @@ -431,6 +431,39 @@ describe('AISettingsPage', () => { await waitFor(() => expect(unload()).toBe(false)) }) + it('locks the form while a prompt reset is pending, even with the sheet closed', async () => { + let answer: (response: Response) => void = () => {} + stubAPI({ + 'POST /api/v1/settings/ai/reset-prompt': () => new Promise((resolve) => (answer = resolve)), + }) + await renderPage() + const unload = () => { + const event = new Event('beforeunload', { cancelable: true }) + act(() => void window.dispatchEvent(event)) + return event.defaultPrevented + } + fireEvent.change(slider(), { target: { value: '0.2' } }) + fireEvent.click(screen.getByRole('button', { name: 'Reset' })) + const confirm = screen.getByRole('dialog', { name: 'Reset the system prompt?' }) + fireEvent.click(within(confirm).getByRole('button', { name: 'Reset prompt' })) + expect(await within(confirm).findByRole('button', { name: 'Resetting…' })).toBeDisabled() + fireEvent.click(within(confirm).getByRole('button', { name: 'Cancel' })) + await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument()) + + for (const field of [provider(), model(), slider(), prompt()]) expect(field).toBeDisabled() + expect(screen.getByRole('button', { name: 'Reset' })).toBeDisabled() + expect(save()).toBeDisabled() + expect(unload()).toBe(true) + + answer(jsonResponse(200, { ...AI_SETTINGS, system_prompt: DEFAULT_PROMPT })) + await waitFor(() => expect(prompt()).toBeEnabled()) + expect(prompt()).toHaveValue(DEFAULT_PROMPT) + expect(slider()).toHaveValue('0.2') + expect(unload()).toBe(true) + fireEvent.change(prompt(), { target: { value: 'After the reset.' } }) + expect(prompt()).toHaveValue('After the reset.') + }) + it('keeps 44 px tap targets', async () => { stubAPI() await renderPage() diff --git a/web/src/settings/AISettingsPage.tsx b/web/src/settings/AISettingsPage.tsx index 992bc15..8fe9ec8 100644 --- a/web/src/settings/AISettingsPage.tsx +++ b/web/src/settings/AISettingsPage.tsx @@ -201,7 +201,7 @@ function AISettingsForm({ saved, onDirtyChange }: AISettingsFormProps) { } return ( -
+