pagination
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
|||||||
GridColDef,
|
GridColDef,
|
||||||
GridActionsCellItem,
|
GridActionsCellItem,
|
||||||
GridRenderCellParams,
|
GridRenderCellParams,
|
||||||
|
GridPaginationModel,
|
||||||
} from '@mui/x-data-grid';
|
} from '@mui/x-data-grid';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
@@ -34,6 +35,10 @@ import { ResourceConfig } from '../types/config';
|
|||||||
interface EnhancedTableProps {
|
interface EnhancedTableProps {
|
||||||
config: ResourceConfig;
|
config: ResourceConfig;
|
||||||
data: any[];
|
data: any[];
|
||||||
|
total?: number;
|
||||||
|
paginationModel?: GridPaginationModel;
|
||||||
|
onPaginationModelChange?: (model: GridPaginationModel) => void;
|
||||||
|
loading?: boolean;
|
||||||
onEdit: (item: any) => void;
|
onEdit: (item: any) => void;
|
||||||
onDelete: (id: string) => void;
|
onDelete: (id: string) => void;
|
||||||
onCreate: () => void;
|
onCreate: () => void;
|
||||||
@@ -43,6 +48,10 @@ interface EnhancedTableProps {
|
|||||||
export default function EnhancedTable({
|
export default function EnhancedTable({
|
||||||
config,
|
config,
|
||||||
data,
|
data,
|
||||||
|
total,
|
||||||
|
paginationModel,
|
||||||
|
onPaginationModelChange,
|
||||||
|
loading = false,
|
||||||
onEdit,
|
onEdit,
|
||||||
onDelete,
|
onDelete,
|
||||||
onCreate,
|
onCreate,
|
||||||
@@ -152,6 +161,23 @@ export default function EnhancedTable({
|
|||||||
rows={data || []}
|
rows={data || []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
autoHeight
|
autoHeight
|
||||||
|
paginationMode={config.pagination ? 'server' : 'client'}
|
||||||
|
rowCount={(() => {
|
||||||
|
if (!config.pagination) return data.length;
|
||||||
|
if (total !== undefined) return total;
|
||||||
|
|
||||||
|
// Graceful fallback for missing total count
|
||||||
|
const page = paginationModel?.page || 0;
|
||||||
|
const pageSize = paginationModel?.pageSize || 10;
|
||||||
|
if (data.length < pageSize) {
|
||||||
|
return page * pageSize + data.length;
|
||||||
|
}
|
||||||
|
// Enable 'Next' button by pretending there's at least one more page
|
||||||
|
return (page + 2) * pageSize;
|
||||||
|
})()}
|
||||||
|
loading={loading}
|
||||||
|
paginationModel={paginationModel || { page: 0, pageSize: 10 }}
|
||||||
|
onPaginationModelChange={onPaginationModelChange}
|
||||||
getRowId={(row) => {
|
getRowId={(row) => {
|
||||||
const pk = config.primaryKey;
|
const pk = config.primaryKey;
|
||||||
if (row[pk] !== undefined && row[pk] !== null) return row[pk];
|
if (row[pk] !== undefined && row[pk] !== null) return row[pk];
|
||||||
@@ -162,11 +188,6 @@ export default function EnhancedTable({
|
|||||||
return `temp-id-${data.indexOf(row)}`;
|
return `temp-id-${data.indexOf(row)}`;
|
||||||
}}
|
}}
|
||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
initialState={{
|
|
||||||
pagination: {
|
|
||||||
paginationModel: { page: 0, pageSize: 10 },
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
pageSizeOptions={[10, 25, 50]}
|
pageSizeOptions={[10, 25, 50]}
|
||||||
sx={{
|
sx={{
|
||||||
border: 'none',
|
border: 'none',
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ interface ResourceViewProps {
|
|||||||
onNavigateToResource?: (resourceName: string, id: string) => void;
|
onNavigateToResource?: (resourceName: string, id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { GridPaginationModel } from '@mui/x-data-grid';
|
||||||
|
|
||||||
export default function ResourceView({ config, onNavigateToResource }: ResourceViewProps) {
|
export default function ResourceView({ config, onNavigateToResource }: ResourceViewProps) {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -21,11 +23,26 @@ export default function ResourceView({ config, onNavigateToResource }: ResourceV
|
|||||||
const isView = !!id && !isEdit;
|
const isView = !!id && !isEdit;
|
||||||
const isList = !id && !isCreate;
|
const isList = !id && !isCreate;
|
||||||
|
|
||||||
|
const [paginationModel, setPaginationModel] = React.useState<GridPaginationModel>({
|
||||||
|
page: 0,
|
||||||
|
pageSize: 10,
|
||||||
|
});
|
||||||
|
|
||||||
const { useList, useRead, useCreate, useUpdate, useDelete } = useResource(config);
|
const { useList, useRead, useCreate, useUpdate, useDelete } = useResource(config);
|
||||||
|
|
||||||
const listQuery = useList();
|
// Determine query parameters based on pagination config
|
||||||
|
const queryParams = React.useMemo(() => {
|
||||||
|
if (!config.pagination) return {};
|
||||||
|
return {
|
||||||
|
skip: paginationModel.page * paginationModel.pageSize,
|
||||||
|
limit: paginationModel.pageSize,
|
||||||
|
};
|
||||||
|
}, [config.pagination, paginationModel]);
|
||||||
|
|
||||||
|
const listQuery = useList(queryParams);
|
||||||
const itemQuery = useRead(id || "");
|
const itemQuery = useRead(id || "");
|
||||||
|
|
||||||
|
const paginatedData = listQuery.data || { data: [], total: undefined };
|
||||||
const createMutation = useCreate();
|
const createMutation = useCreate();
|
||||||
const updateMutation = useUpdate();
|
const updateMutation = useUpdate();
|
||||||
const deleteMutation = useDelete();
|
const deleteMutation = useDelete();
|
||||||
@@ -65,7 +82,11 @@ export default function ResourceView({ config, onNavigateToResource }: ResourceV
|
|||||||
{isList ? (
|
{isList ? (
|
||||||
<EnhancedTable
|
<EnhancedTable
|
||||||
config={config}
|
config={config}
|
||||||
data={listQuery.data || []}
|
data={paginatedData.data || []}
|
||||||
|
total={paginatedData.total}
|
||||||
|
paginationModel={paginationModel}
|
||||||
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
loading={listQuery.isFetching}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onCreate={handleCreate}
|
onCreate={handleCreate}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export const configuration: Record<string, ResourceOverride> = {
|
|||||||
display: false
|
display: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
pagination: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ export function useResource<T = any>(config: ResourceConfig) {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const res = await api.get<T[]>(endpoint, { params });
|
const res = await api.get<T[]>(endpoint, { params });
|
||||||
return res.data;
|
const total = res.headers ? parseInt(res.headers['x-total-count'] || res.headers['X-Total-Count']) : undefined;
|
||||||
|
return {
|
||||||
|
data: res.data,
|
||||||
|
total: isNaN(total as any) ? undefined : total
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,7 +81,11 @@ export function useResource<T = any>(config: ResourceConfig) {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const res = await api.get<T[]>(endpoint, { params });
|
const res = await api.get<T[]>(endpoint, { params });
|
||||||
return res.data;
|
const total = res.headers ? parseInt(res.headers['x-total-count'] || res.headers['X-Total-Count']) : undefined;
|
||||||
|
return {
|
||||||
|
data: res.data,
|
||||||
|
total: isNaN(total as any) ? undefined : total
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export interface ResourceConfig {
|
|||||||
endpoint: string;
|
endpoint: string;
|
||||||
primaryKey: string;
|
primaryKey: string;
|
||||||
fields: Record<string, ResourceField>;
|
fields: Record<string, ResourceField>;
|
||||||
|
pagination?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppConfig {
|
export interface AppConfig {
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ export interface FieldOverride {
|
|||||||
|
|
||||||
export interface ResourceOverride {
|
export interface ResourceOverride {
|
||||||
fields?: Record<string, FieldOverride>;
|
fields?: Record<string, FieldOverride>;
|
||||||
|
pagination?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user