fix(grid): preserve current page on data refresh instead of resetting to page 1
* @
fix(grid): preserve current page on data refresh instead of resetting to page 1
When refreshing table data (toolbar button, Ctrl+R, or auto-refresh), the
offset was hardcoded to 0, causing pagination to always jump back to the
first page. This was frustrating for users viewing later pages.
Use the current page offset (currentPage - 1) * pageSize so the user
stays on the same page after refresh. In infinite-scroll mode, the
offset still evaluates to 0 because resetInfiniteScrollState() sets
currentPage = 1, so behavior is unchanged.
@
* @
fix(grid): auto-redirect to last page when refreshed page no longer exists
Extends the refresh pagination fix with a safety net: when data is deleted
while viewing a later page (e.g. page 5 with only 2 pages remaining), the
grid auto-navigates to the last available page instead of showing an empty
page.
Uses a transient isRefreshingData flag to distinguish refresh/rollback
from normal pagination navigation, avoiding false triggers.
@
* Revert "@"
This reverts commit ff0bf0bb31.
* @
fix(grid): auto-redirect to last page when refreshed page no longer exists
When data is deleted while viewing a later page, the grid now auto-navigates
to the last available page instead of showing an empty page.
Uses a transient isRefreshingData flag to distinguish refresh/rollback
from normal pagination, and a loading-transition watcher (true->false)
placed after displayedTotalRowCount declaration to avoid TDZ errors.
@
* @
test(grid): add pagination offset-preservation and auto-redirect tests
Cover the two new behaviors added to DataGrid.vue:
1. dataGridPagination.test.ts — auto-redirect page calculation:
- page beyond last page after data deletion → triggers redirect
- page still valid → no redirect
- fewer rows than one page → redirects to page 1
- total=0 / total=undefined → guard prevents redirect
2. useDataGridActions.test.ts — offset preserved on reload:
- onReloadData(offset=400) passes offset=400 to build-table-select-sql
- resultPageOffset stored as 400 (not reset to 0)
@
This commit is contained in:
1 parent
2929b1c035
commit
0901f176b0
3 files changed
+126
-2
No files matched your search
@@ -3364,6 +3364,10 @@ const isInfiniteScrollPaginating = ref(false);
|
||||
let lastInfiniteScrollPage = 0;
|
||||
let infiniteScrollCheckScheduled = false;
|
||||
let infiniteScrollAllLoaded = 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
|
||||
// when the current page no longer exists after data was deleted.
|
||||
const isRefreshingData = ref(false);
|
||||
watch(pageSize, (value) => {
|
||||
customPageSizeInput.value = String(value);
|
||||
});
|
||||
@@ -3454,6 +3458,26 @@ const canGoNextPage = computed(() => {
|
||||
const canJumpLastPage = computed(() => canGoNextPage.value && (hasKnownTotalRowCount.value || allRowsLoaded.value || !!props.tableMeta || !!props.countSql));
|
||||
const totalRowCountBusy = computed(() => props.totalRowCountLoading === true || manualTotalRowCountLoading.value);
|
||||
const canCalculateTotalRowCount = computed(() => !isResultsContext.value && !!props.connectionId && (!!props.tableMeta || !!props.countSql));
|
||||
// When a refresh/rollback completes and the current page exceeds the last
|
||||
// available page (e.g. data was deleted while viewing), auto-navigate to the
|
||||
// last available page instead of showing an empty page.
|
||||
watch(
|
||||
() => props.loading,
|
||||
(loading, prevLoading) => {
|
||||
// Only act when loading completes (transitions from true to false)
|
||||
// and the completion was triggered by a refresh/rollback.
|
||||
if (!loading && prevLoading && isRefreshingData.value) {
|
||||
isRefreshingData.value = false;
|
||||
const total = displayedTotalRowCount.value;
|
||||
if (!total || total <= 0) return;
|
||||
const lastPageNum = Math.max(1, Math.ceil(total / pageSize.value));
|
||||
if (currentPage.value <= lastPageNum) return;
|
||||
currentPage.value = lastPageNum;
|
||||
resetGridVerticalScroll(true);
|
||||
emit("paginate", (lastPageNum - 1) * pageSize.value, pageSize.value, currentWhereInput(), currentOrderBy());
|
||||
}
|
||||
},
|
||||
);
|
||||
const showQueryEditReadyBadge = computed(() => isResultsContext.value && hasData.value && !!props.editable && (!!props.tableMeta || !!props.customSaveHandler));
|
||||
const queryEditReadyTargetLabel = computed(() => props.tableMeta?.tableName ?? props.customSaveHandler?.targetLabel ?? "");
|
||||
const showKeylessEditWarning = computed(() => !!props.editable && !!props.tableMeta && canUseKeylessRowPredicate(props.databaseType, props.tableMeta.primaryKeys ?? []));
|
||||
@@ -4034,7 +4058,8 @@ async function onToolbarRefresh() {
|
||||
resetInfiniteScrollState();
|
||||
}
|
||||
preserveTransposeOnNextResult.value = showTranspose.value;
|
||||
emit("reload", props.sql, searchText.value, currentWhereInput(), currentOrderBy(), pageSize.value, 0);
|
||||
isRefreshingData.value = true;
|
||||
emit("reload", props.sql, searchText.value, currentWhereInput(), currentOrderBy(), pageSize.value, (currentPage.value - 1) * pageSize.value);
|
||||
}
|
||||
|
||||
function stopAutoRefreshTimer() {
|
||||
@@ -4078,7 +4103,8 @@ function onToolbarRollback() {
|
||||
if (infiniteScrollEnabled.value) {
|
||||
resetInfiniteScrollState();
|
||||
}
|
||||
emit("reload", props.sql, searchText.value, currentWhereInput(), currentOrderBy(), pageSize.value, 0);
|
||||
isRefreshingData.value = true;
|
||||
emit("reload", props.sql, searchText.value, currentWhereInput(), currentOrderBy(), pageSize.value, (currentPage.value - 1) * pageSize.value);
|
||||
}
|
||||
|
||||
function addRow() {
|
||||
|
||||
Reference in new issue
Block a user