mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 00:17:44 +00:00
fix(grid): preserve row selection during infinite-scroll append
This commit is contained in:
@@ -141,7 +141,7 @@ import { isCancelSearchShortcut, isCopyCurrentRowShortcut, isDeleteCurrentRowSho
|
||||
import { dataGridHeaderContentWidth, scrollbarGutterWidth } from "@/lib/dataGrid/dataGridScrollGutter";
|
||||
import { canFetchNextDataGridSegment, canGoNextDataGridPage, dataGridTotalRowCountLabelKey, hasCompleteLocalDataGridResult, resolveDataGridPaginationTotal, type DataGridInexactTotalRowCountMode } from "@/lib/dataGrid/dataGridPagination";
|
||||
import { dataGridCountQueryOptions } from "@/lib/dataGrid/dataGridQueryOptions";
|
||||
import { dataGridBottomScrollTop, dataGridScrollPosition, isDataGridAtScrollBottom, isDataGridNearScrollBottom, shouldCheckInfiniteScrollAfterScroll, type DataGridScrollPosition } from "@/lib/dataGrid/dataGridInfiniteScroll";
|
||||
import { dataGridBottomScrollTop, dataGridScrollPosition, isDataGridAtScrollBottom, isDataGridNearScrollBottom, isDataGridPrefixAppend, shouldCheckInfiniteScrollAfterScroll, type DataGridScrollPosition } from "@/lib/dataGrid/dataGridInfiniteScroll";
|
||||
import { CANVAS_DATA_GRID_ROW_HEIGHT, canvasDataGridActionOverlayWidth, canvasDataGridActionReservedWidth, dataGridSearchMatchKey, drawCanvasDataGrid, type CanvasDevicePixelSize } from "@/lib/dataGrid/canvasDataGridRenderer";
|
||||
import { DATA_GRID_DARK_STRIPED_ROW_BG, DATA_GRID_LIGHT_STRIPED_ROW_BG, dataGridActiveRowBackground } from "@/lib/dataGrid/dataGridPaintTheme";
|
||||
import { createRowLowerTextCache } from "@/lib/dataGrid/dataGridRowLowerText";
|
||||
@@ -7112,9 +7112,10 @@ watch(isTransposeMode, (active) => {
|
||||
|
||||
watch(
|
||||
() => props.result,
|
||||
() => {
|
||||
(result, previousResult) => {
|
||||
const shouldPreserveTranspose = preserveTransposeOnNextResult.value;
|
||||
preserveTransposeOnNextResult.value = false;
|
||||
if (isDataGridPrefixAppend(previousResult, result)) return;
|
||||
if (getResetScrollAfterResult()) {
|
||||
clearResetScrollAfterResult();
|
||||
resetGridVerticalScroll();
|
||||
|
||||
@@ -9,6 +9,11 @@ export interface DataGridScrollMetrics {
|
||||
clientHeight: number;
|
||||
}
|
||||
|
||||
export interface DataGridAppendResult {
|
||||
rows: readonly unknown[];
|
||||
appended_from_row_count?: number;
|
||||
}
|
||||
|
||||
export function dataGridScrollPosition(top: number, left: number): DataGridScrollPosition {
|
||||
return {
|
||||
top: Math.max(0, top),
|
||||
@@ -30,6 +35,11 @@ export function isDataGridNearScrollBottom(metrics: DataGridScrollMetrics, thres
|
||||
return metrics.scrollHeight - metrics.scrollTop - metrics.clientHeight < threshold;
|
||||
}
|
||||
|
||||
export function isDataGridPrefixAppend(previous: DataGridAppendResult | undefined, next: DataGridAppendResult): boolean {
|
||||
if (!previous || next.appended_from_row_count !== previous.rows.length || next.rows.length < previous.rows.length) return false;
|
||||
return previous.rows.every((row, index) => row === next.rows[index]);
|
||||
}
|
||||
|
||||
export function isDataGridAtScrollBottom(metrics: DataGridScrollMetrics, tolerance = 1): boolean {
|
||||
const maxScrollTop = Math.max(0, metrics.scrollHeight - metrics.clientHeight);
|
||||
return maxScrollTop - metrics.scrollTop <= tolerance;
|
||||
|
||||
+16
-1
@@ -1,7 +1,7 @@
|
||||
import { strict as assert } from "node:assert";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { test } from "vitest";
|
||||
import { dataGridScrollPosition, isDataGridNearScrollBottom, shouldCheckInfiniteScrollAfterScroll } from "../../apps/desktop/src/lib/dataGrid/dataGridInfiniteScroll.ts";
|
||||
import { dataGridScrollPosition, isDataGridNearScrollBottom, isDataGridPrefixAppend, shouldCheckInfiniteScrollAfterScroll } from "../../apps/desktop/src/lib/dataGrid/dataGridInfiniteScroll.ts";
|
||||
|
||||
test("horizontal-only scroll does not check infinite scroll", () => {
|
||||
assert.equal(shouldCheckInfiniteScrollAfterScroll(dataGridScrollPosition(240, 0), dataGridScrollPosition(240, 180)), false);
|
||||
@@ -25,6 +25,21 @@ test("near-bottom check matches the grid threshold", () => {
|
||||
assert.equal(isDataGridNearScrollBottom({ scrollTop: 800, scrollHeight: 1000, clientHeight: 100 }), false);
|
||||
});
|
||||
|
||||
test("prefix-only append preserves the existing result identity", () => {
|
||||
const first = [1, "Ada"];
|
||||
const second = [2, "Linus"];
|
||||
const previous = { rows: [first, second] };
|
||||
assert.equal(isDataGridPrefixAppend(previous, { rows: [first, second, [3, "Grace"]], appended_from_row_count: 2 }), true);
|
||||
});
|
||||
|
||||
test("append marker does not preserve state when an existing row was replaced", () => {
|
||||
const first = [1, "Ada"];
|
||||
const second = [2, "Linus"];
|
||||
const previous = { rows: [first, second] };
|
||||
assert.equal(isDataGridPrefixAppend(previous, { rows: [first, [...second], [3, "Grace"]], appended_from_row_count: 2 }), false);
|
||||
assert.equal(isDataGridPrefixAppend(previous, { rows: [first, second, [3, "Grace"]] }), false);
|
||||
});
|
||||
|
||||
test("infinite scroll requests only the next bounded segment", () => {
|
||||
const source = readFileSync("apps/desktop/src/components/grid/DataGrid.vue", "utf8");
|
||||
assert.match(source, /function infiniteScrollNextPage\(\) \{[\s\S]*?if \(!canFetchNextInfiniteScrollSegment\.value\) \{[\s\S]*?infiniteScrollAllLoaded = true;[\s\S]*?return;[\s\S]*?\}/);
|
||||
|
||||
Reference in New Issue
Block a user