feat(grid): add first-page and last-page pagination buttons

Add « and » buttons to the pagination bar. First-page jumps to page 1.
Last-page runs a COUNT(*) query to calculate total pages, then jumps
to the final page.
This commit is contained in:
t8y2 2026-05-12 17:09:20 +08:00
parent 62a79ab611
commit 4f48ddc823
1 changed files with 44 additions and 1 deletions

View File

@ -16,6 +16,8 @@ import {
Save,
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
Search,
Inbox,
SearchX,
@ -60,7 +62,12 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
import DangerConfirmDialog from "@/components/editor/DangerConfirmDialog.vue";
import type { QueryResult, ColumnInfo, DatabaseType } from "@/types/database";
import * as api from "@/lib/api";
import { buildTableSelectSql, quoteTableIdentifier } from "@/lib/tableSelectSql";
import {
buildTableSelectSql,
qualifiedTableName,
normalizeWhereInput,
quoteTableIdentifier,
} from "@/lib/tableSelectSql";
import { isHiddenGridColumn, usesSyntheticRowIdKey } from "@/lib/tableEditing";
import { formatGridSqlLiteral } from "@/lib/dataGridSql";
import { matchesRowStatusFilter, type RowStatus, type RowStatusFilter } from "@/lib/gridRowStatus";
@ -810,6 +817,12 @@ function currentOrderBy(): string | undefined {
);
}
function firstPage() {
if (currentPage.value <= 1) return;
currentPage.value = 1;
resetGridVerticalScroll(true);
emit("paginate", 0, pageSize.value, currentWhereInput(), currentOrderBy());
}
function prevPage() {
if (currentPage.value <= 1) return;
currentPage.value--;
@ -829,6 +842,30 @@ function changePageSize(size: number) {
emit("paginate", 0, size, currentWhereInput(), currentOrderBy());
}
async function lastPage() {
if (!props.connectionId || !props.tableMeta) return;
const table = qualifiedTableName({
databaseType: props.databaseType,
schema: props.tableMeta.schema,
tableName: props.tableMeta.tableName,
});
const predicate = normalizeWhereInput(currentWhereInput());
const where = predicate ? ` WHERE (${predicate})` : "";
const sql = `SELECT COUNT(*) AS cnt FROM ${table}${where}`;
try {
const result = await api.executeQuery(props.connectionId, props.database ?? "", sql, props.tableMeta.schema);
const total = Number(result.rows?.[0]?.[0] ?? 0);
if (total <= 0) return;
const lastPageNum = Math.ceil(total / pageSize.value);
if (lastPageNum <= currentPage.value) return;
currentPage.value = lastPageNum;
resetGridVerticalScroll(true);
emit("paginate", (lastPageNum - 1) * pageSize.value, pageSize.value, currentWhereInput(), currentOrderBy());
} catch {
// COUNT query failed ignore silently
}
}
// --- Editing (composable) ---
interface RowItem {
@ -2585,6 +2622,9 @@ defineExpose({
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Button variant="ghost" size="icon" class="h-5 w-5" :disabled="currentPage <= 1" @click="firstPage">
<ChevronsLeft class="h-3 w-3" />
</Button>
<Button variant="ghost" size="icon" class="h-5 w-5" :disabled="currentPage <= 1" @click="prevPage">
<ChevronLeft class="h-3 w-3" />
</Button>
@ -2592,6 +2632,9 @@ defineExpose({
<Button variant="ghost" size="icon" class="h-5 w-5" :disabled="!isFullPage" @click="nextPage">
<ChevronRight class="h-3 w-3" />
</Button>
<Button variant="ghost" size="icon" class="h-5 w-5" :disabled="!isFullPage" @click="lastPage">
<ChevronsRight class="h-3 w-3" />
</Button>
</span>
<DropdownMenu>