mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
* chore: remove dead comment in database page * fix(data-table): manualPagination support * fix(hooks): useServerDataTable for server-side pagination * fix(database): paginated backup and restoration list actions * fix(database): server-paginate backup list * fix(database): server-paginate restoration list * fix(database): switch tabs via History API instead of router.push * fix(logs): load job logs on demand when the modal opens * perf(database): slim metadata poll and drop eager backup/log loading * fix(database): invalidate backups/restorations list keys on mutations for instant refresh * fix(logs): disable log button when row has no logs * fix(logs): fetch logs on button click, open modal already populated * fix: loading log modal --------- Co-authored-by: charles-gauthereau <charles.gauthereau@soluce-technologies.com>
107 lines
3.0 KiB
TypeScript
107 lines
3.0 KiB
TypeScript
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
import type { PaginationState, SortingState } from "@tanstack/react-table";
|
|
import { useEffect, useState } from "react";
|
|
|
|
interface PaginatedResult<TData> {
|
|
data: TData[];
|
|
meta: {
|
|
total: number;
|
|
page: number;
|
|
pageSize: number;
|
|
totalPages: number;
|
|
[key: string]: any;
|
|
};
|
|
}
|
|
|
|
interface UseServerDataTableProps<TData, TParams> {
|
|
fetchAction: any;
|
|
queryKey: any[];
|
|
extraParams?: Partial<TParams>;
|
|
initialPageSize?: number;
|
|
initialSorting?: SortingState;
|
|
enabled?: boolean;
|
|
refetchInterval?: number | false;
|
|
}
|
|
|
|
const EMPTY_ARRAY: any[] = [];
|
|
|
|
export function useServerDataTable<TData, TParams>(
|
|
props: UseServerDataTableProps<TData, TParams>,
|
|
) {
|
|
const {
|
|
fetchAction,
|
|
queryKey,
|
|
extraParams,
|
|
initialPageSize = 20,
|
|
initialSorting = [],
|
|
enabled = true,
|
|
refetchInterval = false,
|
|
} = props;
|
|
|
|
const [pagination, setPagination] = useState<PaginationState>({
|
|
pageIndex: 0,
|
|
pageSize: initialPageSize,
|
|
});
|
|
const [sorting, setSorting] = useState<SortingState>(initialSorting);
|
|
|
|
useEffect(() => {
|
|
setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
}, [sorting]);
|
|
|
|
useEffect(() => {
|
|
setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
}, [JSON.stringify(extraParams)]);
|
|
|
|
const query = useQuery({
|
|
queryKey: [
|
|
...queryKey,
|
|
pagination.pageIndex,
|
|
pagination.pageSize,
|
|
sorting,
|
|
JSON.stringify(extraParams),
|
|
],
|
|
queryFn: async () => {
|
|
const response = await fetchAction({
|
|
page: pagination.pageIndex + 1,
|
|
pageSize: pagination.pageSize,
|
|
sorting,
|
|
...extraParams,
|
|
} as any);
|
|
|
|
const result = response?.data as PaginatedResult<TData> | undefined;
|
|
if (!result || !Array.isArray(result.data)) {
|
|
throw new Error("Failed to fetch paginated data");
|
|
}
|
|
return result;
|
|
},
|
|
placeholderData: keepPreviousData,
|
|
enabled,
|
|
gcTime: 2 * 60 * 1000,
|
|
staleTime: 30 * 1000,
|
|
refetchInterval,
|
|
refetchOnWindowFocus: true,
|
|
retry: 1,
|
|
});
|
|
|
|
return {
|
|
data: (query.data?.data as TData[]) || EMPTY_ARRAY,
|
|
rowCount: query.data?.meta?.total || 0,
|
|
pagination,
|
|
onPaginationChange: setPagination,
|
|
sorting,
|
|
onSortingChange: setSorting,
|
|
tableProps: {
|
|
manualPagination: true as const,
|
|
rowCount: query.data?.meta?.total || 0,
|
|
paginationState: pagination,
|
|
onPaginationChange: setPagination,
|
|
sorting,
|
|
onSortingChange: setSorting,
|
|
},
|
|
meta: query.data?.meta,
|
|
isLoading: query.isPending,
|
|
isFetching: query.isFetching,
|
|
refetch: query.refetch,
|
|
};
|
|
}
|