From 50562be76fa170bf2dd5bdb55f8d2686a68914d3 Mon Sep 17 00:00:00 2001 From: sanwalsulehri Date: Sat, 20 Sep 2025 17:21:49 +0500 Subject: [PATCH] fix(ui): Fix pagination for documents #320 solved --- .../documents/(manage)/page.tsx | 39 +++++++++++++------ .../components/chat/ChatInputGroup.tsx | 17 +++++++- .../components/chat/DocumentsDataTable.tsx | 36 ++++++++++------- surfsense_web/hooks/use-documents.ts | 13 +++++-- 4 files changed, 74 insertions(+), 31 deletions(-) diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx index 4a69a7533..8387ad9b4 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx @@ -26,10 +26,8 @@ export default function DocumentsTable() { const params = useParams(); const searchSpaceId = Number(params.search_space_id); - const { documents, loading, error, refreshDocuments, deleteDocument } = - useDocuments(searchSpaceId); - - const [data, setData] = useState([]); + const [pageIndex, setPageIndex] = useState(0); + const [pageSize, setPageSize] = useState(100); // Increased page size for better performance const [search, setSearch] = useState(""); const debouncedSearch = useDebounced(search, 250); const [activeTypes, setActiveTypes] = useState([]); @@ -39,16 +37,28 @@ export default function DocumentsTable() { content: true, created_at: true, }); - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); const [sortKey, setSortKey] = useState("title"); const [sortDesc, setSortDesc] = useState(false); const [selectedIds, setSelectedIds] = useState>(new Set()); + // Calculate skip value for pagination + const skip = pageIndex * pageSize; + + const { documents, loading, error, refreshDocuments, deleteDocument } = useDocuments( + searchSpaceId, + false, + skip, + pageSize + ); + + const [data, setData] = useState([]); + useEffect(() => { if (documents) setData(documents as Document[]); }, [documents]); + // For server-side pagination, we apply client-side filtering to the current page data + // Note: This is a simplified approach. For production, you might want to implement server-side filtering const filtered = useMemo(() => { let result = data; if (debouncedSearch.trim()) { @@ -61,16 +71,21 @@ export default function DocumentsTable() { return result; }, [data, debouncedSearch, activeTypes]); - const total = filtered.length; - const pageStart = pageIndex * pageSize; - const pageEnd = Math.min(pageStart + pageSize, total); - const pageDocs = filtered.slice(pageStart, pageEnd); + // For server-side pagination, we show the filtered results from current page + // Total count is estimated based on current page size (this could be improved with a count endpoint) + const pageDocs = filtered; + const total = pageSize * (pageIndex + 1); // Estimated total, could be improved with actual count const onToggleType = (type: string, checked: boolean) => { setActiveTypes((prev) => (checked ? [...prev, type] : prev.filter((t) => t !== type))); setPageIndex(0); }; + // Reset to first page when search changes + useEffect(() => { + setPageIndex(0); + }, [debouncedSearch]); + const onToggleColumn = (id: keyof ColumnVisibility, checked: boolean) => { setColumnVisibility((prev) => ({ ...prev, [id]: checked })); }; @@ -157,10 +172,10 @@ export default function DocumentsTable() { }} onFirst={() => setPageIndex(0)} onPrev={() => setPageIndex((i) => Math.max(0, i - 1))} - onNext={() => setPageIndex((i) => (pageEnd < total ? i + 1 : i))} + onNext={() => setPageIndex((i) => i + 1)} onLast={() => setPageIndex(Math.max(0, Math.ceil(total / pageSize) - 1))} canPrev={pageIndex > 0} - canNext={pageEnd < total} + canNext={pageDocs.length === pageSize} // Show next if current page is full id={id} /> diff --git a/surfsense_web/components/chat/ChatInputGroup.tsx b/surfsense_web/components/chat/ChatInputGroup.tsx index 1f5cc6d31..56d924a78 100644 --- a/surfsense_web/components/chat/ChatInputGroup.tsx +++ b/surfsense_web/components/chat/ChatInputGroup.tsx @@ -39,10 +39,17 @@ const DocumentSelector = React.memo( }) => { const { search_space_id } = useParams(); const [isOpen, setIsOpen] = useState(false); + const [pageIndex, setPageIndex] = useState(0); + const [pageSize, setPageSize] = useState(100); // Larger page size for document selector + + // Calculate skip value for pagination + const skip = pageIndex * pageSize; const { documents, loading, isLoaded, fetchDocuments } = useDocuments( Number(search_space_id), - true + true, + skip, + pageSize ); const handleOpenChange = useCallback( @@ -104,6 +111,14 @@ const DocumentSelector = React.memo( onSelectionChange={handleSelectionChange} onDone={handleDone} initialSelectedDocuments={selectedDocuments} + pageIndex={pageIndex} + pageSize={pageSize} + onPageIndexChange={setPageIndex} + onPageSizeChange={(newSize) => { + setPageSize(newSize); + setPageIndex(0); + }} + canNext={documents.length === pageSize} /> ) : null} diff --git a/surfsense_web/components/chat/DocumentsDataTable.tsx b/surfsense_web/components/chat/DocumentsDataTable.tsx index 79b6216b3..7d6006c3c 100644 --- a/surfsense_web/components/chat/DocumentsDataTable.tsx +++ b/surfsense_web/components/chat/DocumentsDataTable.tsx @@ -41,6 +41,11 @@ interface DocumentsDataTableProps { onSelectionChange: (documents: Document[]) => void; onDone: () => void; initialSelectedDocuments?: Document[]; + pageIndex?: number; + pageSize?: number; + onPageIndexChange?: (pageIndex: number) => void; + onPageSizeChange?: (pageSize: number) => void; + canNext?: boolean; } // Combine EnumConnectorName with additional document types @@ -181,6 +186,11 @@ export function DocumentsDataTable({ onSelectionChange, onDone, initialSelectedDocuments = [], + pageIndex = 0, + pageSize = 100, + onPageIndexChange, + onPageSizeChange, + canNext = false, }: DocumentsDataTableProps) { const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); @@ -400,35 +410,33 @@ export function DocumentsDataTable({ {/* Footer Pagination */}
- Showing {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}{" "} - to{" "} - {Math.min( - (table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize, - table.getFilteredRowModel().rows.length - )}{" "} - of {table.getFilteredRowModel().rows.length} documents + Showing {pageIndex * pageSize + 1} to{" "} + {Math.min((pageIndex + 1) * pageSize, pageIndex * pageSize + documents.length)} of{" "} + {canNext + ? `${(pageIndex + 1) * pageSize}+` + : `${pageIndex * pageSize + documents.length}`}{" "} + documents
Page - {table.getState().pagination.pageIndex + 1} - of - {table.getPageCount()} + {pageIndex + 1} + {canNext && +}