fix(mongo): stabilize estimated-total pagination
This commit is contained in:
1 parent
96038d2b8a
commit
8f3fd0ebfb
23 files changed
+462
-124
No files matched your search
@@ -4,7 +4,7 @@ import { computed, nextTick, ref } from "vue";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { DATA_GRID_COL_AUTO_FIT_MAX_WIDTH, DATA_GRID_COL_MIN_WIDTH } from "@/lib/dataGrid/dataGridColumnWidth";
|
||||
import { clearDataGridColumnWidthStates, createDataGridColumnMeasurementSignature, createDataGridColumnStructureSignature, DATA_GRID_COLUMN_WIDTH_STATE_LIMIT, dataGridColumnWidthStateCount, loadDataGridColumnWidthState, saveDataGridColumnWidthState } from "@/lib/dataGrid/dataGridColumnWidthState";
|
||||
import { DATA_GRID_ROW_NUM_WIDTH, resizeDataGridColumnWidth, useDataGridColumnResize } from "@/composables/useDataGridColumnResize";
|
||||
import { DATA_GRID_ROW_NUM_WIDTH, dataGridRowNumberColumnWidth, resizeDataGridColumnWidth, resolveDataGridMaxRowNumber, useDataGridColumnResize } from "@/composables/useDataGridColumnResize";
|
||||
|
||||
function createResizeState(options: { columns: string[]; rows: Array<Array<string | number | boolean | null>>; columnIndexes?: number[]; columnTypes?: string[]; cacheKey?: string; density?: "compact" | "standard" | "comfortable"; compactColumnHeaderActions?: boolean; headerTextWidth?: number }) {
|
||||
const compact = ref(options.compactColumnHeaderActions ?? true);
|
||||
@@ -301,3 +301,19 @@ describe("useDataGridColumnResize", () => {
|
||||
expect(comf.columnWidths.value[0]).toBeGreaterThanOrEqual(std.columnWidths.value[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("dataGridRowNumberColumnWidth", () => {
|
||||
it("keeps the default width for small page indexes", () => {
|
||||
expect(dataGridRowNumberColumnWidth(999)).toBe(DATA_GRID_ROW_NUM_WIDTH);
|
||||
expect(dataGridRowNumberColumnWidth(9999)).toBe(DATA_GRID_ROW_NUM_WIDTH);
|
||||
});
|
||||
|
||||
it("widens the gutter for multi-million row numbers", () => {
|
||||
expect(dataGridRowNumberColumnWidth(4_215_101)).toBeGreaterThan(DATA_GRID_ROW_NUM_WIDTH);
|
||||
expect(dataGridRowNumberColumnWidth(4_215_101)).toBe(dataGridRowNumberColumnWidth(9_999_999));
|
||||
});
|
||||
|
||||
it("prefers measured text width when provided", () => {
|
||||
expect(dataGridRowNumberColumnWidth(99, 12, () => 40)).toBe(56);
|
||||
});
|
||||
});
|
||||
@@ -405,7 +405,7 @@ export function useDataGridColumnLayout(options: {
|
||||
renderedColumnWidths: MaybeRefOrGetter<readonly number[]>;
|
||||
scrollLeft: MaybeRefOrGetter<number>;
|
||||
viewportWidth: MaybeRefOrGetter<number>;
|
||||
rowNumberWidth: number;
|
||||
rowNumberWidth: MaybeRefOrGetter<number>;
|
||||
bufferPx?: number;
|
||||
headerRef?: MaybeRefOrGetter<HTMLElement | null | undefined>;
|
||||
orderedColumnIndexes?: MaybeRefOrGetter<readonly number[]>;
|
||||
@@ -427,7 +427,7 @@ export function useDataGridColumnLayout(options: {
|
||||
columnCount: toValue(options.visibleColumnIndexes).length,
|
||||
scrollLeft: toValue(options.scrollLeft),
|
||||
viewportWidth: toValue(options.viewportWidth),
|
||||
rowNumberWidth: options.rowNumberWidth,
|
||||
rowNumberWidth: toValue(options.rowNumberWidth),
|
||||
bufferPx: options.bufferPx ?? 900,
|
||||
}),
|
||||
);
|
||||
@@ -478,7 +478,7 @@ export function useDataGridColumnLayout(options: {
|
||||
}
|
||||
|
||||
function columnContentOffsetLeft(visibleColIdx: number): number {
|
||||
return options.rowNumberWidth + (renderedColumnOffsets.value[visibleColIdx] ?? 0);
|
||||
return toValue(options.rowNumberWidth) + (renderedColumnOffsets.value[visibleColIdx] ?? 0);
|
||||
}
|
||||
|
||||
const columnHeaderDragState = ref<ColumnHeaderDragState | null>(null);
|
||||
|
||||
@@ -5,8 +5,27 @@ import type { ColumnWidthDensity } from "@/stores/settingsStore";
|
||||
|
||||
type CellValue = string | number | boolean | null;
|
||||
|
||||
/** Minimum row-number gutter; fits ~4 digits with px-2 padding. */
|
||||
export const DATA_GRID_ROW_NUM_WIDTH = 48;
|
||||
|
||||
/** Largest absolute row number that may appear in the gutter for the current page/window. */
|
||||
export function resolveDataGridMaxRowNumber(options: { infiniteScroll: boolean; allRowsLoaded: boolean; currentPage: number; pageSize: number; rowCount: number }): number {
|
||||
if (options.infiniteScroll || options.allRowsLoaded) {
|
||||
return Math.max(1, options.rowCount);
|
||||
}
|
||||
const pageSize = Math.max(1, options.pageSize);
|
||||
return Math.max(1, Math.max(0, options.currentPage - 1) * pageSize + Math.max(options.rowCount, 1));
|
||||
}
|
||||
|
||||
/** Grow the sticky # column so multi-million row indexes are not clipped or spilled into data cells. */
|
||||
export function dataGridRowNumberColumnWidth(maxRowNumber: number, fontSize = 12, measureTextWidth?: (text: string) => number | undefined): number {
|
||||
const text = String(Math.max(1, Math.floor(Math.max(0, maxRowNumber))));
|
||||
const measured = measureTextWidth?.(text);
|
||||
const contentWidth = typeof measured === "number" && Number.isFinite(measured) && measured > 0 ? measured : text.length * Math.max(8, Math.ceil(fontSize * 0.65));
|
||||
// Keep ~4 digits in the default 48px gutter; measured text gets the same 16px padding as px-2.
|
||||
return Math.max(DATA_GRID_ROW_NUM_WIDTH, Math.ceil(contentWidth) + 16);
|
||||
}
|
||||
|
||||
export function resizeDataGridColumnWidth(startWidth: number, deltaX: number): number {
|
||||
return Math.max(DATA_GRID_COL_MIN_WIDTH, startWidth + deltaX);
|
||||
}
|
||||
@@ -21,6 +40,7 @@ export interface UseDataGridColumnResizeOptions {
|
||||
columnStructureSignature: ComputedRef<string>;
|
||||
measureHeaderText?: (text: string) => number | undefined;
|
||||
headerMeasurementKey?: Ref<unknown>;
|
||||
rowNumberWidth?: Ref<number> | ComputedRef<number>;
|
||||
}
|
||||
|
||||
export function useDataGridColumnResize(options: UseDataGridColumnResizeOptions) {
|
||||
@@ -143,14 +163,16 @@ export function useDataGridColumnResize(options: UseDataGridColumnResizeOptions)
|
||||
|
||||
const renderedColumnWidths = computed(() => columnWidths.value.slice());
|
||||
|
||||
const totalWidth = computed(() => renderedColumnWidths.value.reduce((a, b) => a + b, 0) + DATA_GRID_ROW_NUM_WIDTH);
|
||||
const resolvedRowNumberWidth = computed(() => options.rowNumberWidth?.value ?? DATA_GRID_ROW_NUM_WIDTH);
|
||||
|
||||
const totalWidth = computed(() => renderedColumnWidths.value.reduce((a, b) => a + b, 0) + resolvedRowNumberWidth.value);
|
||||
|
||||
const columnVars = computed(() => {
|
||||
const vars: Record<string, string> = {};
|
||||
renderedColumnWidths.value.forEach((w, i) => {
|
||||
vars[`--col-w-${i}`] = `${w}px`;
|
||||
});
|
||||
vars["--row-num-w"] = `${DATA_GRID_ROW_NUM_WIDTH}px`;
|
||||
vars["--row-num-w"] = `${resolvedRowNumberWidth.value}px`;
|
||||
vars["--total-w"] = `${totalWidth.value}px`;
|
||||
return vars;
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user