Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions e2e/query-explorer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}) => {
Expand Down Expand Up @@ -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', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/features/query-explorer/components/history-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function HistoryPanel({
</Select>
<p className='text-[11px] leading-snug text-muted-foreground'>
{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.'}
Expand All @@ -83,7 +83,7 @@ export function HistoryPanel({
if (runHistory.length === 0) {
return (
<div className={cn('flex min-h-0 flex-1 flex-col', className)}>
<div className='px-3 py-4'>
<div className='flex flex-1 px-3 py-4'>
<p className='text-xs text-muted-foreground'>
Run a query to see history here.
</p>
Expand Down
24 changes: 18 additions & 6 deletions src/store/slices/query-explorer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})
Expand All @@ -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 }', '{}')
Expand All @@ -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', () => {
Expand Down
4 changes: 4 additions & 0 deletions src/store/slices/query-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Loading