From 7a257e08d78f3706893067cb6c9ab83660857256 Mon Sep 17 00:00:00 2001 From: Wayne Date: Tue, 31 Mar 2026 13:25:41 +0300 Subject: [PATCH] CLI-1500: Fix history save to work correctly --- e2e/query-explorer.spec.ts | 35 +++++++++++++++++++ .../components/history-panel.tsx | 4 +-- src/store/slices/query-explorer.test.ts | 24 +++++++++---- src/store/slices/query-explorer.ts | 4 +++ 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/e2e/query-explorer.spec.ts b/e2e/query-explorer.spec.ts index a196b7c..7533cdf 100644 --- a/e2e/query-explorer.spec.ts +++ b/e2e/query-explorer.spec.ts @@ -220,6 +220,20 @@ test.describe('History panel', () => { ).toBeVisible() }) + test('empty history view still shows save options footer', async ({ + page, + }) => { + await page.goto('/explorer') + + await page.getByRole('button', { name: 'Show history' }).click() + + await expect(page.getByText('Save history')).toBeVisible() + await expect( + page.getByRole('combobox', { name: 'Where to save query history' }), + ).toBeVisible() + await expect(page.getByText('This browser (until expired)')).toBeVisible() + }) + test('clicking editor toggle from history view returns to Editor', async ({ page, }) => { @@ -308,6 +322,27 @@ test.describe('Query execution', () => { await expect(page.getByRole('button', { name: 'Load' })).toBeVisible() }) + + test('history is not retained when save mode is set to do not save', async ({ + page, + }) => { + await page.goto('/explorer') + await page.getByRole('button', { name: 'Show history' }).click() + + await page + .getByRole('combobox', { name: 'Where to save query history' }) + .click() + await page.getByRole('option', { name: 'Do not save' }).click() + + await page.getByRole('button', { name: 'Show editor' }).click() + await runQueryAndWaitForResult(page) + await page.getByRole('button', { name: 'Show history' }).click() + + await expect( + page.getByText('Run a query to see history here.'), + ).toBeVisible() + await expect(page.getByRole('button', { name: 'Load' })).toHaveCount(0) + }) }) test.describe('History entry interactions', () => { diff --git a/src/features/query-explorer/components/history-panel.tsx b/src/features/query-explorer/components/history-panel.tsx index 69ffbba..ef28f1e 100644 --- a/src/features/query-explorer/components/history-panel.tsx +++ b/src/features/query-explorer/components/history-panel.tsx @@ -72,7 +72,7 @@ export function HistoryPanel({

{historyStorageMode === 'off' - ? 'History is kept in memory for this session only.' + ? 'History is not retained after each run.' : historyStorageMode === 'session' ? 'History clears when you close this tab.' : 'History is stored locally and pruned after the configured retention period.'} @@ -83,7 +83,7 @@ export function HistoryPanel({ if (runHistory.length === 0) { return (

-
+

Run a query to see history here.

diff --git a/src/store/slices/query-explorer.test.ts b/src/store/slices/query-explorer.test.ts index 7c8def9..7c35ac5 100644 --- a/src/store/slices/query-explorer.test.ts +++ b/src/store/slices/query-explorer.test.ts @@ -302,11 +302,12 @@ describe('query-explorer slice', () => { expect(stored[0].query).toBe('query { a }') }) - it('does not persist when history storage mode is off', () => { + it('does not retain or persist history when history storage mode is off', () => { localStorageData[STORAGE_MODE_KEY] = 'off' const s = createTestStore() vi.mocked(localStorage.setItem).mockClear() s.getState().addRunToHistory('query { a }', '{}') + expect(s.getState().runHistory).toEqual([]) expect(localStorageData[RUN_HISTORY_KEY]).toBeUndefined() expect(sessionStorageData[RUN_HISTORY_KEY]).toBeUndefined() }) @@ -330,21 +331,20 @@ describe('query-explorer slice', () => { expect(JSON.parse(sessionStorageData[RUN_HISTORY_KEY])).toHaveLength(1) }) - it('migrates in-memory history to localStorage when switching from off to local', () => { + it('starts with empty localStorage history when switching from off to local', () => { localStorageData[STORAGE_MODE_KEY] = 'off' const s = createTestStore() s.getState().addRunToHistory('query { a }', '{}') - // History exists only in memory while mode is off expect(localStorageData[RUN_HISTORY_KEY]).toBeUndefined() s.getState().setHistoryStorageMode('local') expect(localStorageData[STORAGE_MODE_KEY]).toBe('local') expect(s.getState().historyStorageMode).toBe('local') expect(localStorageData[RUN_HISTORY_KEY]).toBeDefined() - expect(JSON.parse(localStorageData[RUN_HISTORY_KEY])).toHaveLength(1) + expect(JSON.parse(localStorageData[RUN_HISTORY_KEY])).toEqual([]) }) - it('migrates in-memory history to sessionStorage when switching from off to session', () => { + it('starts with empty sessionStorage history when switching from off to session', () => { localStorageData[STORAGE_MODE_KEY] = 'off' const s = createTestStore() s.getState().addRunToHistory('query { a }', '{}') @@ -354,7 +354,19 @@ describe('query-explorer slice', () => { expect(localStorageData[STORAGE_MODE_KEY]).toBe('session') expect(s.getState().historyStorageMode).toBe('session') expect(sessionStorageData[RUN_HISTORY_KEY]).toBeDefined() - expect(JSON.parse(sessionStorageData[RUN_HISTORY_KEY])).toHaveLength(1) + expect(JSON.parse(sessionStorageData[RUN_HISTORY_KEY])).toEqual([]) + }) + + it('clears existing in-memory history when switching to off', () => { + store.getState().addRunToHistory('query { a }', '{}') + expect(store.getState().runHistory).toHaveLength(1) + + store.getState().setHistoryStorageMode('off') + + expect(store.getState().historyStorageMode).toBe('off') + expect(store.getState().runHistory).toEqual([]) + expect(localStorageData[RUN_HISTORY_KEY]).toBeUndefined() + expect(sessionStorageData[RUN_HISTORY_KEY]).toBeUndefined() }) it('prunes stale entries when switching to local mode', () => { diff --git a/src/store/slices/query-explorer.ts b/src/store/slices/query-explorer.ts index 02a340b..30edea0 100644 --- a/src/store/slices/query-explorer.ts +++ b/src/store/slices/query-explorer.ts @@ -236,6 +236,9 @@ export function createQueryExplorerSlice( addRunToHistory: (query, variables) => { const state = get() + if (state.historyStorageMode === 'off') { + return + } const entry: HistoryEntry = { id: crypto.randomUUID(), query, @@ -279,6 +282,7 @@ export function createQueryExplorerSlice( try { if (mode === 'off') { clearHistoryFromBothStorages() + return { historyStorageMode: mode, runHistory: [] } } else if (mode === 'local') { // Prune stale entries before writing to localStorage so entries // that accumulated in memory (e.g. while in session/off mode) don't