mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
fix(grid): continue load-all loop after jumped page reload
This commit is contained in:
@@ -3554,6 +3554,7 @@ let loadAllRowsLoopActive = false;
|
||||
// Set when a "load all" reloads a jumped-to discrete page from the first row;
|
||||
// the replacing result must still land the view on the last row (#11940).
|
||||
let loadAllRowsReloadPending = false;
|
||||
let loadAllRowsReloadLimit: number | undefined;
|
||||
const loadAllRowsActive = ref(false);
|
||||
// Tracks whether the current loading cycle was triggered by a refresh/rollback
|
||||
// (as opposed to a normal paginate). Used to decide whether to auto-redirect
|
||||
@@ -4103,6 +4104,7 @@ function startLoadAllRows(segment: { offset: number; limit: number }, reloadFrom
|
||||
loadAllRowsActive.value = true;
|
||||
loadAllRowsLoopActive = !reloadFromFirstRow;
|
||||
loadAllRowsReloadPending = reloadFromFirstRow;
|
||||
loadAllRowsReloadLimit = reloadFromFirstRow ? segment.limit : undefined;
|
||||
infiniteScrollAllLoaded = false;
|
||||
// A reload-from-first-row run replaces the page through the normal (non-
|
||||
// append) execution path; the append watcher must not treat it as one of
|
||||
@@ -4195,6 +4197,7 @@ function changePageSize(size: number) {
|
||||
loadAllRowsActive.value = false;
|
||||
loadAllRowsLoopActive = false;
|
||||
loadAllRowsReloadPending = false;
|
||||
loadAllRowsReloadLimit = undefined;
|
||||
infiniteScrollPositions = new WeakMap();
|
||||
resetGridVerticalScroll(true);
|
||||
emit("paginate", 0, normalizedSize, currentWhereInput(), effectiveOrderBy());
|
||||
@@ -5134,6 +5137,7 @@ function resetInfiniteScrollState() {
|
||||
loadAllRowsActive.value = false;
|
||||
loadAllRowsLoopActive = false;
|
||||
loadAllRowsReloadPending = false;
|
||||
loadAllRowsReloadLimit = undefined;
|
||||
infiniteScrollPositions = new WeakMap();
|
||||
resetGridVerticalScroll(true);
|
||||
}
|
||||
@@ -11837,21 +11841,25 @@ watch(
|
||||
filterValueSuggestionLoader.reset({ clearCache: true });
|
||||
// A non-append result replaces the whole data set, so a running "load all" is over.
|
||||
const reloadedFromFirstRow = loadAllRowsReloadPending;
|
||||
const reloadLimit = loadAllRowsReloadLimit ?? infiniteScrollMaxRows.value;
|
||||
loadAllRowsReloadPending = false;
|
||||
loadAllRowsReloadLimit = undefined;
|
||||
loadAllRowsActive.value = false;
|
||||
loadAllRowsLoopActive = false;
|
||||
if (reloadedFromFirstRow) {
|
||||
// A capped/truncated reload must not claim completeness — that would
|
||||
// block the #10752 continuation past the cap; only an uncapped full
|
||||
// reload marks the end (#11940).
|
||||
if (!props.result.truncated && props.result.has_more !== true) {
|
||||
infiniteScrollAllLoaded = true;
|
||||
if (props.result.has_more === true && !props.result.truncated) {
|
||||
loadAllRowsActive.value = true;
|
||||
loadAllRowsLoopActive = true;
|
||||
nextTick(() => {
|
||||
if (loadAllRowsLoopActive && !finishOrContinueLoadAllRun(0, reloadLimit)) selectAndRevealLastLoadedRow();
|
||||
});
|
||||
} else {
|
||||
if (!props.result.truncated && props.result.has_more !== true && (props.result.has_more === false || props.result.rows.length < reloadLimit)) {
|
||||
infiniteScrollAllLoaded = true;
|
||||
}
|
||||
selectAndRevealLastLoadedRow();
|
||||
}
|
||||
selectAndRevealLastLoadedRow();
|
||||
} else {
|
||||
// The replacement also invalidates the all-loaded marker: a filter change or
|
||||
// page jump swaps in a fresh first page whose remaining segments must be
|
||||
// re-derived instead of being silently skipped.
|
||||
infiniteScrollAllLoaded = false;
|
||||
}
|
||||
if (getResetScrollAfterResult()) {
|
||||
@@ -13246,6 +13254,8 @@ onUnmounted(() => {
|
||||
onSqlPreviewResizeEnd();
|
||||
finishCellSelection();
|
||||
loadAllRowsLoopActive = false;
|
||||
loadAllRowsReloadPending = false;
|
||||
loadAllRowsReloadLimit = undefined;
|
||||
clearTimeout(highlightedColumnTimer);
|
||||
stopLoadingElapsedTimer();
|
||||
});
|
||||
|
||||
+99
@@ -567,6 +567,105 @@ describe("DataGrid load-all on a jumped-to discrete page (#11940)", () => {
|
||||
expect(Math.max(...rowNumbers)).toBeLessThanOrEqual(30);
|
||||
expect(Math.min(...rowNumbers)).toBe(1);
|
||||
});
|
||||
|
||||
it("continues chunking past the cap when total row count is unknown and has_more is true (#12418)", async () => {
|
||||
// Jumped to page 9 (offset 80), unknown total, result cap is 5.
|
||||
const { host, paginate, settingsStore, gridState } = mountGrid({ pageOffset: 80 });
|
||||
settingsStore.updateEditorSettings({ dataGridRenderMode: "dom", queryResultMaxRowsEnabled: true, queryResultMaxRows: 5 });
|
||||
gridState.value = {
|
||||
context: "table-data",
|
||||
pageLimit: 10,
|
||||
pageOffset: 80,
|
||||
totalRowCount: undefined,
|
||||
result: { columns: ["id"], rows: [[1]], has_more: true, affected_rows: 0, execution_time_ms: 0 },
|
||||
};
|
||||
await settle();
|
||||
|
||||
host.querySelector<HTMLButtonElement>(`button[aria-label="${i18n.global.t("grid.loadAllAndGoToLastRow")}"]`)!.click();
|
||||
await settle();
|
||||
|
||||
// 1st request: reloads from first row (offset: 0, limit: 5, append: false)
|
||||
expect(paginate).toHaveBeenCalledOnce();
|
||||
expect(paginate.mock.calls[0]?.slice(0, 2)).toEqual([0, 5]);
|
||||
expect(paginate.mock.calls[0]?.[4]).toBe(false);
|
||||
|
||||
// Backend returns 5 rows with has_more: true
|
||||
gridState.value = {
|
||||
context: "table-data",
|
||||
pageLimit: 5,
|
||||
pageOffset: 0,
|
||||
totalRowCount: undefined,
|
||||
result: {
|
||||
columns: ["id"],
|
||||
rows: Array.from({ length: 5 }, (_, index) => [index + 1]),
|
||||
has_more: true,
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 0,
|
||||
},
|
||||
};
|
||||
await settle();
|
||||
|
||||
// 2nd request: continues past the cap via append (offset: 5, limit: 5, append: true)
|
||||
expect(paginate).toHaveBeenCalledTimes(2);
|
||||
expect(paginate.mock.calls[1]?.slice(0, 2)).toEqual([5, 5]);
|
||||
expect(paginate.mock.calls[1]?.[4]).toBe(true);
|
||||
|
||||
// Second chunk lands with 3 rows (tail) and has_more: false
|
||||
gridState.value = {
|
||||
context: "table-data",
|
||||
pageLimit: 5,
|
||||
pageOffset: 0,
|
||||
totalRowCount: undefined,
|
||||
result: {
|
||||
columns: ["id"],
|
||||
rows: Array.from({ length: 8 }, (_, index) => [index + 1]),
|
||||
has_more: false,
|
||||
appended_from_row_count: 5,
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 0,
|
||||
},
|
||||
};
|
||||
await settle();
|
||||
|
||||
// Run terminates after tail chunk
|
||||
expect(paginate).toHaveBeenCalledTimes(2);
|
||||
const footer = host.textContent || "";
|
||||
expect(footer).toMatch(/all loaded/i);
|
||||
});
|
||||
|
||||
it("does not report all loaded if reload lands at cap with unknown total and missing has_more (#12418)", async () => {
|
||||
const { host, settingsStore, gridState } = mountGrid({ pageOffset: 80 });
|
||||
settingsStore.updateEditorSettings({ dataGridRenderMode: "dom", queryResultMaxRowsEnabled: true, queryResultMaxRows: 5 });
|
||||
gridState.value = {
|
||||
context: "table-data",
|
||||
pageLimit: 10,
|
||||
pageOffset: 80,
|
||||
totalRowCount: undefined,
|
||||
result: { columns: ["id"], rows: [[1]], has_more: false, affected_rows: 0, execution_time_ms: 0 },
|
||||
};
|
||||
await settle();
|
||||
host.querySelector<HTMLButtonElement>(`button[aria-label="${i18n.global.t("grid.loadAllAndGoToLastRow")}"]`)!.click();
|
||||
await settle();
|
||||
|
||||
// Reload returned exactly 5 rows (the cap), but has_more is undefined
|
||||
gridState.value = {
|
||||
context: "table-data",
|
||||
pageLimit: 5,
|
||||
pageOffset: 0,
|
||||
totalRowCount: undefined,
|
||||
result: {
|
||||
columns: ["id"],
|
||||
rows: Array.from({ length: 5 }, (_, index) => [index + 1]),
|
||||
has_more: undefined,
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 0,
|
||||
},
|
||||
};
|
||||
await settle();
|
||||
|
||||
const footer = host.textContent || "";
|
||||
expect(footer).not.toMatch(/all loaded/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DataGrid multi-chunk load-all run", () => {
|
||||
|
||||
Reference in New Issue
Block a user