Skip to content

Commit 9c50137

Browse files
authored
feat: warn user before leaving behind an unsaved prompt (#281)
Closes #274 Asks user to confirm when closing the tab or navigating away from a Session and there is a prompt in the textarea, except when navigating to another session.
1 parent a38265b commit 9c50137

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

Diff for: src/i18n/en/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ const en = {
147147
tryingToConnectNotLocalhost:
148148
'If you want to connect to an Ollama server that is not available on {hostname:string} or {ip:string} try',
149149
typicalP: 'Typical P',
150+
unsavedChangesWillBeLost: 'You have unsaved changes that will be lost. Continue?',
150151
useMlock: 'Use MLOCK',
151152
useMmap: 'Use MMAP',
152153
useModelsFromThisServer: 'Use models from this server',

Diff for: src/i18n/i18n-types.ts

+8
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ type RootTranslation = {
593593
* T​y​p​i​c​a​l​ ​P
594594
*/
595595
typicalP: string
596+
/**
597+
* Y​o​u​ ​h​a​v​e​ ​u​n​s​a​v​e​d​ ​c​h​a​n​g​e​s​ ​t​h​a​t​ ​w​i​l​l​ ​b​e​ ​l​o​s​t​.​ ​C​o​n​t​i​n​u​e​?
598+
*/
599+
unsavedChangesWillBeLost: string
596600
/**
597601
* U​s​e​ ​M​L​O​C​K
598602
*/
@@ -1205,6 +1209,10 @@ The completion in progress will stop
12051209
* Typical P
12061210
*/
12071211
typicalP: () => LocalizedString
1212+
/**
1213+
* You have unsaved changes that will be lost. Continue?
1214+
*/
1215+
unsavedChangesWillBeLost: () => LocalizedString
12081216
/**
12091217
* Use MLOCK
12101218
*/

Diff for: src/routes/sessions/[id]/+page.svelte

+19-5
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,27 @@
7676
});
7777
7878
beforeNavigate((navigation) => {
79-
if (!editor.isCompletionInProgress) return;
80-
const userConfirmed = confirm($LL.areYouSureYouWantToLeave());
81-
if (userConfirmed) {
82-
stopCompletion();
79+
if (editor.isCompletionInProgress) {
80+
const userConfirmed = confirm($LL.areYouSureYouWantToLeave());
81+
if (userConfirmed) {
82+
stopCompletion();
83+
return;
84+
}
85+
navigation.cancel();
8386
return;
8487
}
85-
navigation.cancel();
88+
89+
// Only show confirmation when navigating outside of /sessions/ path
90+
if (
91+
editor.prompt &&
92+
editor.prompt.trim() !== '' &&
93+
!navigation.to?.url.pathname.startsWith('/sessions/')
94+
) {
95+
const userConfirmed = confirm($LL.unsavedChangesWillBeLost());
96+
if (!userConfirmed) {
97+
navigation.cancel();
98+
}
99+
}
86100
});
87101
88102
async function handleSessionChange() {

Diff for: tests/session-interaction.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,32 @@ test.describe('Session interaction', () => {
608608
);
609609
});
610610

611+
test('warns when navigating away with unsaved prompt content', async ({ page }) => {
612+
await page.goto('/');
613+
await page.getByText('Sessions', { exact: true }).click();
614+
await page.getByTestId('new-session').click();
615+
616+
// Fill the prompt but don't submit
617+
await chooseModel(page, MOCK_API_TAGS_RESPONSE.models[0].name);
618+
await promptTextarea.fill('This is an unsaved prompt');
619+
620+
// First verify that navigating within /sessions/ doesn't trigger a dialog
621+
await page.getByTestId('new-session').click();
622+
await expect(promptTextarea).toHaveValue('This is an unsaved prompt');
623+
expect(page.url()).toContain('/sessions/');
624+
625+
// Now verify that navigating outside /sessions/ does trigger a dialog
626+
const dialogPromise = page.waitForEvent('dialog');
627+
await page.getByText('Settings', { exact: true }).click();
628+
const dialog = await dialogPromise;
629+
expect(dialog.message()).toContain('You have unsaved changes that will be lost');
630+
await dialog.dismiss();
631+
632+
// Verify we're still on the session page (navigation was canceled)
633+
await expect(promptTextarea).toHaveValue('This is an unsaved prompt');
634+
expect(page.url()).toContain('/sessions/');
635+
});
636+
611637
test('renders math notation correctly using KaTeX', async ({ page }) => {
612638
// Mock a session with LaTeX math content
613639
await page.evaluate(() =>

0 commit comments

Comments
 (0)