diff --git a/apps/desktop/src/components/document/DocumentBrowser.vue b/apps/desktop/src/components/document/DocumentBrowser.vue index 5b5f785a37..9ebcffa22e 100644 --- a/apps/desktop/src/components/document/DocumentBrowser.vue +++ b/apps/desktop/src/components/document/DocumentBrowser.vue @@ -339,7 +339,20 @@ function documentDataSignature(): string | undefined { } } -const documentLocalColumnFilterRestoreKey = computed(() => documentDataSignature()); +// Local value filters describe column values, not the rows that happen to be +// loaded, so paging and page-size changes must not drop them. Only a new query +// (collection, filter or sort) invalidates the snapshot; restored filters are +// mapped back by column name, so a changed column set is handled as well. +function documentLocalColumnFilterSignature(): string | undefined { + try { + return JSON.stringify([documentStoreProvider.value.kind, props.connectionId, props.database, props.collection, currentDocumentFilter() ?? null, currentDocumentSortJson(sortInput.value) ?? null]); + } catch { + // Malformed filter/sort JSON: nothing stable to key filters against. + return undefined; + } +} + +const documentLocalColumnFilterRestoreKey = computed(() => documentLocalColumnFilterSignature()); let loadedDocumentDataSignature: string | undefined; @@ -391,13 +404,11 @@ function handleLocalColumnFiltersChange(filters: SerializedDataGridLocalColumnFi persistDocumentBrowserState({ includeData: true }); } -// Keep these sources in lockstep with documentDataSignature(): every input that -// invalidates held rows (including pageSize and the infinite-scroll setting, which -// can change mid-session at page 0 without moving `page`) must also drop the -// local-filter snapshot, or a tab switch would replay filters the user watched -// DataGrid clear on its own restore-key change. +// Keep these sources in lockstep with documentLocalColumnFilterSignature(): a +// changed query means the local-filter snapshot no longer describes what the +// user is looking at. watch( - [filterInput, sortInput, appliedDocumentFilter, page, pageSize, () => settingsStore.editorSettings.infiniteScroll], + [filterInput, sortInput, appliedDocumentFilter], () => { localColumnFilters.value = {}; localColumnFilterColumns.value = undefined; @@ -405,6 +416,8 @@ watch( }, { deep: true }, ); +// Paging and page-size changes reload rows, but the local value filters stay put. +watch([page, pageSize, () => settingsStore.editorSettings.infiniteScroll], () => persistDocumentBrowserState()); watch(documentFilterRules, () => persistDocumentBrowserState(), { deep: true }); // Seed the grid from the cached page so a tab switch costs no round trip diff --git a/apps/desktop/src/components/document/__tests__/DocumentBrowserTabState.spec.ts b/apps/desktop/src/components/document/__tests__/DocumentBrowserTabState.spec.ts index 940360fd25..c3a43b8b80 100644 --- a/apps/desktop/src/components/document/__tests__/DocumentBrowserTabState.spec.ts +++ b/apps/desktop/src/components/document/__tests__/DocumentBrowserTabState.spec.ts @@ -399,16 +399,17 @@ describe("DocumentBrowser tab state (tab switch persistence)", () => { expect(dataGrid.localColumnFilterColumns).toBeUndefined(); }); - it("clears mongodb local column filters when the page size changes mid-session", async () => { + it("keeps mongodb local column filters when the page size changes mid-session", async () => { await mountBrowser({ stateKey: "tab-local-filters-page-size" }); dataGrid.localFiltersChange!({ "1": ["str:OpenGate"] }); await flushUi(); expect(dataGrid.localColumnFilters).toEqual({ "1": ["str:OpenGate"] }); - // Page stays at 0 for a page-size change, so only the pageSize input invalidates the snapshot. + // A page-size change reloads rows, but the value filter is about columns, not rows. await dataGrid.paginate!(0, 10); await flushUi(); - expect(dataGrid.localColumnFilters).toEqual({}); + expect(dataGrid.localColumnFilters).toEqual({ "1": ["str:OpenGate"] }); + expect(dataGrid.localColumnFilterColumns).toEqual(["_id", "name"]); app!.unmount(); app = null; @@ -416,8 +417,8 @@ describe("DocumentBrowser tab state (tab switch persistence)", () => { await flushUi(); await mountBrowser({ stateKey: "tab-local-filters-page-size" }); - expect(dataGrid.localColumnFilters).toEqual({}); - expect(dataGrid.localColumnFilterColumns).toBeUndefined(); + expect(dataGrid.localColumnFilters).toEqual({ "1": ["str:OpenGate"] }); + expect(dataGrid.localColumnFilterColumns).toEqual(["_id", "name"]); }); it("still forces a real reload from the refresh button after a restore", async () => { diff --git a/docs/screenshots/issue-9061-after.png b/docs/screenshots/issue-9061-after.png new file mode 100644 index 0000000000..d4d45f5ebd Binary files /dev/null and b/docs/screenshots/issue-9061-after.png differ diff --git a/docs/screenshots/issue-9061-before.png b/docs/screenshots/issue-9061-before.png new file mode 100644 index 0000000000..ac90c9762d Binary files /dev/null and b/docs/screenshots/issue-9061-before.png differ