diff --git a/src/components/reusable/Pagination.tsx b/src/components/reusable/Pagination.tsx
index 13914f9..c10580c 100644
--- a/src/components/reusable/Pagination.tsx
+++ b/src/components/reusable/Pagination.tsx
@@ -1,5 +1,5 @@
-import { ChevronLeft, ChevronRight } from 'lucide-react';
-import { Button } from '../buttons/Button';
+import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
+import { useState, useEffect } from 'react';
export interface PaginationProps {
/** 1-based current page. */
@@ -8,38 +8,114 @@ export interface PaginationProps {
/** Total rows across all pages. */
total: number;
onPage: (page: number) => void;
+ onPageSizeChange?: (size: number) => void;
}
/** Pager: "Showing a–b of N" + Prev/Next. Renders nothing when the set fits on
* one page. Shared by the record-view tables. */
-export function Pagination({ page, pageSize, total, onPage }: PaginationProps) {
+export function Pagination({ page, pageSize, total, onPage, onPageSizeChange }: PaginationProps) {
if (total <= 0) return null;
const totalPages = Math.max(1, Math.ceil(total / pageSize));
const safePage = Math.min(Math.max(page, 1), totalPages);
const start = (safePage - 1) * pageSize;
+ const [jumpPage, setJumpPage] = useState(safePage.toString());
+
+ useEffect(() => {
+ setJumpPage(safePage.toString());
+ }, [safePage]);
+
const handlePageChange = (newPage: number) => {
onPage(newPage);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return (
-
-
- Showing {start + 1}–{Math.min(start + pageSize, total)} of {total}
-
-
-
-
- {safePage} / {totalPages}
+
+
+
+
+
+
+
+ PAGE
+ setJumpPage(e.target.value)}
+ onBlur={() => {
+ let p = parseInt(jumpPage, 10);
+ if (isNaN(p)) p = safePage;
+ p = Math.max(1, Math.min(p, totalPages));
+ setJumpPage(p.toString());
+ if (p !== safePage) handlePageChange(p);
+ }}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.currentTarget.blur();
+ }
+ }}
+ className="w-12 h-7 bg-white border border-gray-200 rounded text-center focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 font-bold text-gray-900 p-0 m-0 no-spinners"
+ />
+ / {totalPages}
+
+
+
+
+
+
+
+
+
+ Showing {start + 1} to {Math.min(start + pageSize, total)} of {total.toLocaleString()} Records
-
+
+ {onPageSizeChange && (
+
+ )}
);
diff --git a/src/components/rv/RecordView.tsx b/src/components/rv/RecordView.tsx
index 52b029c..86568c1 100644
--- a/src/components/rv/RecordView.tsx
+++ b/src/components/rv/RecordView.tsx
@@ -69,6 +69,7 @@ export function RecordView({
preset_alias,
}: RecordViewProps) {
const [page, setPage] = useState(1);
+ const [activePageSize, setActivePageSize] = useState(pageSize);
const [search, setSearch] = useState('');
const [debounced, setDebounced] = useState('');
const [activeFilters, setActiveFilters] = useState>({});
@@ -107,7 +108,7 @@ export function RecordView({
setLoading(true);
setError(null);
try {
- const r = await client.recordView(rvUid, { preset_alias, page, limit: pageSize, search: debounced, filters: filtersParam, sortBy, sortDir });
+ const r = await client.recordView(rvUid, { preset_alias, page, limit: activePageSize, search: debounced, filters: filtersParam, sortBy, sortDir });
if (live) setResp(r);
} catch (e) {
if (live) setError((e as { message?: string })?.message ?? 'Failed to load');
@@ -119,7 +120,7 @@ export function RecordView({
return () => {
live = false;
};
- }, [client, rvUid, preset_alias, page, pageSize, debounced, filtersParam, refreshKey, sortBy, sortDir]);
+ }, [client, rvUid, preset_alias, page, activePageSize, debounced, filtersParam, refreshKey, sortBy, sortDir]);
const fields: RecordViewField[] = useMemo(() => {
const all = resp?.config.fields ?? [];
@@ -317,7 +318,16 @@ export function RecordView({
})}
)}
-
+
{
+ setActivePageSize(size);
+ setPage(1); // Reset to page 1 when changing page size
+ }}
+ />
);
}