From 3bec5091df6ef1237d357afc0b9117b9c1c1c791 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 21 Aug 2026 17:32:11 +0000 Subject: [PATCH] fix(grid): use table-open page size for documents Closes #6903 --- .../components/document/DocumentBrowser.vue | 3 +- .../DocumentBrowserInfiniteScroll.spec.ts | 30 ++++++++++++++----- apps/desktop/src/components/grid/DataGrid.vue | 12 ++++---- .../dataGridPageSizePreference.spec.ts | 30 +++++++++++++++++++ .../dataGrid/dataGridPageSizePreference.ts | 23 ++++++++++++++ 5 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 apps/desktop/src/lib/__tests__/dataGrid/dataGridPageSizePreference.spec.ts create mode 100644 apps/desktop/src/lib/dataGrid/dataGridPageSizePreference.ts diff --git a/apps/desktop/src/components/document/DocumentBrowser.vue b/apps/desktop/src/components/document/DocumentBrowser.vue index 2e0fb6ab18..730b549160 100644 --- a/apps/desktop/src/components/document/DocumentBrowser.vue +++ b/apps/desktop/src/components/document/DocumentBrowser.vue @@ -134,7 +134,7 @@ const documentLoadExecutionId = ref(""); const documentLoadCancelling = ref(false); const documentLoadingElapsedSeconds = ref("0.0"); const page = ref(0); -const pageSize = ref(normalizeResultPageSize(settingsStore.editorSettings.pageSize)); +const pageSize = ref(normalizeResultPageSize(settingsStore.editorSettings.tableOpenPageSize)); const selectedIdx = ref(null); const editJson = ref(""); const isEditing = ref(false); @@ -2300,6 +2300,7 @@ defineExpose({ focusSearch }); :table-meta="props.tableMeta" :column-layout-scope-key="documentColumnLayoutScopeKey" context="results" + page-size-preference="table-open" :database-type="props.databaseType" :mongo-update-target="mongoUpdateTarget" :editable="documentStoreEditable" diff --git a/apps/desktop/src/components/document/__tests__/DocumentBrowserInfiniteScroll.spec.ts b/apps/desktop/src/components/document/__tests__/DocumentBrowserInfiniteScroll.spec.ts index c5e602e6ba..0c4123d177 100644 --- a/apps/desktop/src/components/document/__tests__/DocumentBrowserInfiniteScroll.spec.ts +++ b/apps/desktop/src/components/document/__tests__/DocumentBrowserInfiniteScroll.spec.ts @@ -25,6 +25,7 @@ const dataGrid = vi.hoisted(() => ({ appendedFromRowCount: undefined as number | undefined, pageOffset: undefined as number | undefined, pageLimit: undefined as number | undefined, + pageSizePreference: undefined as string | undefined, selectionActive: false, editActive: false, fullReplaceCount: 0, @@ -33,6 +34,7 @@ const dataGrid = vi.hoisted(() => ({ const settings = vi.hoisted(() => ({ editorSettings: { pageSize: 2, + tableOpenPageSize: 5, infiniteScroll: true, mongoViewMode: "table" as "document" | "table", columnWidthDensity: "standard" as "compact" | "standard" | "comfortable", @@ -87,6 +89,7 @@ vi.mock("@/components/grid/DataGrid.vue", async () => { customSaveHandler: { type: Object, required: false }, pageOffset: { type: Number, required: false }, pageLimit: { type: Number, required: false }, + pageSizePreference: { type: String, required: false }, }, setup(props, { attrs, expose }) { dataGrid.paginate = attrs.onPaginate as typeof dataGrid.paginate; @@ -127,6 +130,7 @@ vi.mock("@/components/grid/DataGrid.vue", async () => { dataGrid.appendedFromRowCount = result.appended_from_row_count; dataGrid.pageOffset = props.pageOffset; dataGrid.pageLimit = props.pageLimit; + dataGrid.pageSizePreference = props.pageSizePreference; return h("div", { "data-testid": "data-grid" }); }; }, @@ -182,12 +186,12 @@ async function flushUi() { } } -async function mountBrowser() { +async function mountBrowser(databaseType: "mongodb" | "elasticsearch" = "mongodb") { app = createApp(DocumentBrowser, { connectionId: "mongo-1", database: "test", collection: "docs", - databaseType: "mongodb", + databaseType, }); app.mount(root!); await flushUi(); @@ -230,10 +234,12 @@ beforeEach(async () => { dataGrid.appendedFromRowCount = undefined; dataGrid.pageOffset = undefined; dataGrid.pageLimit = undefined; + dataGrid.pageSizePreference = undefined; dataGrid.selectionActive = false; dataGrid.editActive = false; dataGrid.fullReplaceCount = 0; settings.editorSettings.pageSize = 2; + settings.editorSettings.tableOpenPageSize = 5; settings.editorSettings.infiniteScroll = true; root = document.createElement("div"); @@ -249,6 +255,16 @@ afterEach(() => { }); describe("DocumentBrowser infinite scroll (issue #6455)", () => { + it.each(["mongodb", "elasticsearch"] as const)("uses the table-open page-size preference for %s", async (databaseType) => { + backend.documentFindDocuments.mockResolvedValueOnce(documentResult(1, 5, 5)); + + await mountBrowser(databaseType); + + expect(backend.documentFindDocuments.mock.calls[0]!.slice(0, 5)).toEqual(["mongo-1", "test", "docs", 0, 5]); + expect(dataGrid.pageLimit).toBe(5); + expect(dataGrid.pageSizePreference).toBe("table-open"); + }); + it("preserves existing row identity and DataGrid selection/edit state for same-column appends", async () => { backend.documentFindDocuments.mockResolvedValueOnce(documentResult(1, 2, 4)).mockResolvedValueOnce(documentResult(3, 2, 4)); @@ -310,11 +326,11 @@ describe("DocumentBrowser infinite scroll (issue #6455)", () => { await dataGrid.reload!(); await flushUi(); - expect(backend.documentFindDocuments.mock.calls[3]!.slice(0, 5)).toEqual(["mongo-1", "test", "docs", 0, 2]); + expect(backend.documentFindDocuments.mock.calls[3]!.slice(0, 5)).toEqual(["mongo-1", "test", "docs", 0, 5]); expect(dataGrid.rows).toHaveLength(2); expect(dataGrid.appendedFromRowCount).toBeUndefined(); expect(dataGrid.pageOffset).toBe(0); - expect(dataGrid.pageLimit).toBe(2); + expect(dataGrid.pageLimit).toBe(5); expect(dataGrid.resetInfiniteScrollState).toHaveBeenCalledTimes(1); }); @@ -341,16 +357,16 @@ describe("DocumentBrowser infinite scroll (issue #6455)", () => { await flushUi(); expect(backend.documentUpdateDocument).toHaveBeenCalledTimes(1); - expect(backend.documentFindDocuments.mock.calls[3]!.slice(0, 5)).toEqual(["mongo-1", "test", "docs", 0, 2]); + expect(backend.documentFindDocuments.mock.calls[3]!.slice(0, 5)).toEqual(["mongo-1", "test", "docs", 0, 5]); expect(dataGrid.rows).toHaveLength(2); expect(dataGrid.appendedFromRowCount).toBeUndefined(); expect(dataGrid.pageOffset).toBe(0); - expect(dataGrid.pageLimit).toBe(2); + expect(dataGrid.pageLimit).toBe(5); expect(dataGrid.resetInfiniteScrollState).toHaveBeenCalledTimes(1); }); it("keeps the configured page size when the final capped segment has a smaller limit", async () => { - settings.editorSettings.pageSize = 3; + settings.editorSettings.tableOpenPageSize = 3; backend.documentFindDocuments .mockResolvedValueOnce(documentResult(1, 3, 11)) .mockResolvedValueOnce(documentResult(4, 3, 11)) diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index 394ff0b690..3526045fcb 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -84,7 +84,6 @@ import { dataGridCellDisplayText, dataGridCellEditorText } from "@/lib/dataGrid/ import { createColumnDrafts } from "@/lib/table/tableStructureEditorState"; import type { BuildSingleColumnAlterSqlOptions } from "@/lib/table/tableStructureEditorSql"; import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql"; -import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit"; import { uuid } from "@/lib/common/utils"; import { generateCellValues, type CellValueGenerationKind } from "@/lib/dataGrid/cellValueGeneration"; import { compactHeaderColumnType, isNumericColumnType, resolveDataGridTypeVisualKind, resolveHeaderColumnType, resolveResultColumnType } from "@/lib/dataGrid/dataGridColumnType"; @@ -219,6 +218,7 @@ import { replaceColumnValueFilterCondition, } from "@/lib/dataGrid/dataGridColumnFilter"; import { normalizeResultPageSize, resultPageSizeMenuOptions } from "@/lib/dataGrid/paginationPageSize"; +import { dataGridPageSizeSettingsPatch, preferredDataGridPageSize, resolveDataGridPageSizePreference, type DataGridPageSizePreference } from "@/lib/dataGrid/dataGridPageSizePreference"; import { continuousQueryResultMaxRows, effectiveQueryResultMaxRows } from "@/lib/dataGrid/queryResultRowLimit"; import { allNullColumnIndexes } from "@/lib/dataGrid/dataGridColumnVisibility"; import { buildDataGridColumnLookupItems, dataGridColumnCommentFor, filterDataGridColumnLookupItems } from "@/lib/dataGrid/dataGridColumnLookup"; @@ -385,6 +385,7 @@ interface DataGridProps { schema?: string; columnLayoutScopeKey?: string; context?: "results" | "table-data"; + pageSizePreference?: DataGridPageSizePreference; autoTransposeSingleRow?: boolean; sourceColumns?: Array; readonlyColumnIndexes?: number[]; @@ -3076,7 +3077,8 @@ watch( ); // --- Pagination --- -const pageSize = ref(normalizeResultPageSize(props.context === "table-data" ? (props.pageLimit ?? tableOpenPageLimit(settingsStore.editorSettings.tableOpenPageSize)) : settingsStore.editorSettings.pageSize)); +const pageSizePreference = computed(() => resolveDataGridPageSizePreference(props.context, props.pageSizePreference)); +const pageSize = ref(preferredDataGridPageSize(settingsStore.editorSettings, pageSizePreference.value, props.pageLimit)); const currentPage = ref(1); const pageSizeOptions = computed(() => resultPageSizeMenuOptions(pageSize.value)); const customPageSizeInput = ref(String(pageSize.value)); @@ -3097,8 +3099,8 @@ watch(pageSize, (value) => { watch( () => settingsStore.editorSettings.pageSize, (value) => { - // Table-data segments keep their own pagination state instead of following SQL result settings. - if (props.context === "table-data") return; + // Table-open grids keep their own pagination state instead of following SQL result settings. + if (pageSizePreference.value !== "results") return; pageSize.value = normalizeResultPageSize(value, pageSize.value); }, ); @@ -3440,7 +3442,7 @@ function checkInfiniteScroll(scroller: HTMLElement) { function changePageSize(size: number) { const normalizedSize = normalizeResultPageSize(size); pageSize.value = normalizedSize; - settingsStore.updateEditorSettings(props.context === "table-data" ? { tableOpenPageSize: normalizedSize } : { pageSize: normalizedSize }); + settingsStore.updateEditorSettings(dataGridPageSizeSettingsPatch(pageSizePreference.value, normalizedSize)); currentPage.value = 1; lastInfiniteScrollPage = 0; infiniteScrollAllLoaded = false; diff --git a/apps/desktop/src/lib/__tests__/dataGrid/dataGridPageSizePreference.spec.ts b/apps/desktop/src/lib/__tests__/dataGrid/dataGridPageSizePreference.spec.ts new file mode 100644 index 0000000000..bf6af761ce --- /dev/null +++ b/apps/desktop/src/lib/__tests__/dataGrid/dataGridPageSizePreference.spec.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import { dataGridPageSizeSettingsPatch, preferredDataGridPageSize, resolveDataGridPageSizePreference } from "@/lib/dataGrid/dataGridPageSizePreference"; + +describe("DataGrid page-size preference", () => { + it("keeps the context-derived defaults for regular result and table-data grids", () => { + expect(resolveDataGridPageSizePreference("results")).toBe("results"); + expect(resolveDataGridPageSizePreference(undefined)).toBe("results"); + expect(resolveDataGridPageSizePreference("table-data")).toBe("table-open"); + }); + + it("allows a result-context grid to explicitly use the table-open preference", () => { + expect(resolveDataGridPageSizePreference("results", "table-open")).toBe("table-open"); + }); + + it("reads the selected preference and preserves an explicit table-data page limit", () => { + const settings = { pageSize: 25, tableOpenPageSize: 500 }; + + expect(preferredDataGridPageSize(settings, "results")).toBe(25); + expect(preferredDataGridPageSize(settings, "table-open")).toBe(500); + expect(preferredDataGridPageSize(settings, "table-open", 75)).toBe(75); + expect(preferredDataGridPageSize({ pageSize: 0, tableOpenPageSize: Number.NaN }, "results")).toBe(100); + expect(preferredDataGridPageSize({ pageSize: 0, tableOpenPageSize: Number.NaN }, "table-open")).toBe(100); + }); + + it("writes only the selected normalized setting", () => { + expect(dataGridPageSizeSettingsPatch("results", 250.9)).toEqual({ pageSize: 250 }); + expect(dataGridPageSizeSettingsPatch("table-open", 750.9)).toEqual({ tableOpenPageSize: 750 }); + expect(dataGridPageSizeSettingsPatch("table-open", 0)).toEqual({ tableOpenPageSize: 100 }); + }); +}); diff --git a/apps/desktop/src/lib/dataGrid/dataGridPageSizePreference.ts b/apps/desktop/src/lib/dataGrid/dataGridPageSizePreference.ts new file mode 100644 index 0000000000..4f29d20342 --- /dev/null +++ b/apps/desktop/src/lib/dataGrid/dataGridPageSizePreference.ts @@ -0,0 +1,23 @@ +import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize"; +import { tableOpenPageLimit } from "@/lib/table/tableOpenPageLimit"; + +export type DataGridPageSizePreference = "results" | "table-open"; + +type DataGridContext = "results" | "table-data" | undefined; +type DataGridPageSizeSettings = { + pageSize: unknown; + tableOpenPageSize: unknown; +}; + +export function resolveDataGridPageSizePreference(context: DataGridContext, preference?: DataGridPageSizePreference): DataGridPageSizePreference { + return preference ?? (context === "table-data" ? "table-open" : "results"); +} + +export function preferredDataGridPageSize(settings: DataGridPageSizeSettings, preference: DataGridPageSizePreference, pageLimit?: number): number { + return preference === "table-open" ? normalizeResultPageSize(pageLimit ?? tableOpenPageLimit(settings.tableOpenPageSize)) : normalizeResultPageSize(settings.pageSize); +} + +export function dataGridPageSizeSettingsPatch(preference: DataGridPageSizePreference, value: unknown): { pageSize: number } | { tableOpenPageSize: number } { + const normalized = normalizeResultPageSize(value); + return preference === "table-open" ? { tableOpenPageSize: normalized } : { pageSize: normalized }; +}