mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-07-14 01:00:05 +08:00
use pre and next cursor check from the server
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardBody,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
@@ -47,6 +45,8 @@ export type DataTableProps<T> = {
|
||||
onNextClick?: () => void;
|
||||
onPreviousClick?: () => void;
|
||||
onFilterChange?: (items: FilterItem[]) => void;
|
||||
disableNext?: boolean;
|
||||
disablePrevious?: boolean;
|
||||
};
|
||||
|
||||
export const DataTable = <T,>({
|
||||
@@ -57,6 +57,8 @@ export const DataTable = <T,>({
|
||||
onNextClick,
|
||||
onPreviousClick,
|
||||
onFilterChange,
|
||||
disableNext,
|
||||
disablePrevious,
|
||||
}: DataTableProps<T>) => {
|
||||
const { getHeaderGroups, getRowModel } = useReactTable<T>({
|
||||
data,
|
||||
@@ -75,49 +77,51 @@ export const DataTable = <T,>({
|
||||
onFilterChange(newValues);
|
||||
};
|
||||
return (
|
||||
<Card>
|
||||
<CardBody>
|
||||
<Flex mb="2">
|
||||
<Button onClick={onPreviousClick}>Previous</Button>
|
||||
<Spacer />
|
||||
<Button onClick={onNextClick}>Next</Button>
|
||||
</Flex>
|
||||
<TableContainer>
|
||||
<Table variant="simple">
|
||||
<TableCaption>{caption}</TableCaption>
|
||||
<Thead>
|
||||
{getHeaderGroups().map((headerGroup) => (
|
||||
<Tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<Th key={header.id}>
|
||||
<Box display="flex" alignItems="center">
|
||||
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
||||
{(header.column.columnDef as DataTableColumnDef<T>).filterable && (
|
||||
<FilterModal
|
||||
value={filterValues.find((value) => value.id === header.id)?.value ?? ""}
|
||||
onChange={(value) => handleFilterChange({ id: header.id, value })}
|
||||
label={flexRender(header.column.columnDef.header, header.getContext())}
|
||||
></FilterModal>
|
||||
)}
|
||||
</Box>
|
||||
</Th>
|
||||
))}
|
||||
</Tr>
|
||||
))}
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{getRowModel().rows.map((row) => (
|
||||
<Tr key={row.id}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<Td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</Td>
|
||||
))}
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<>
|
||||
<Flex mb="2">
|
||||
<Button onClick={onPreviousClick} disabled={disablePrevious}>
|
||||
Previous
|
||||
</Button>
|
||||
<Spacer />
|
||||
<Button onClick={onNextClick} disabled={disableNext}>
|
||||
Next
|
||||
</Button>
|
||||
</Flex>
|
||||
<TableContainer>
|
||||
<Table variant="simple">
|
||||
<TableCaption>{caption}</TableCaption>
|
||||
<Thead>
|
||||
{getHeaderGroups().map((headerGroup) => (
|
||||
<Tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<Th key={header.id}>
|
||||
<Box display="flex" alignItems="center">
|
||||
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
||||
{(header.column.columnDef as DataTableColumnDef<T>).filterable && (
|
||||
<FilterModal
|
||||
value={filterValues.find((value) => value.id === header.id)?.value ?? ""}
|
||||
onChange={(value) => handleFilterChange({ id: header.id, value })}
|
||||
label={flexRender(header.column.columnDef.header, header.getContext())}
|
||||
></FilterModal>
|
||||
)}
|
||||
</Box>
|
||||
</Th>
|
||||
))}
|
||||
</Tr>
|
||||
))}
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{getRowModel().rows.map((row) => (
|
||||
<Tr key={row.id}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<Td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</Td>
|
||||
))}
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IconButton, useToast } from "@chakra-ui/react";
|
||||
import { Card, CardBody, IconButton } from "@chakra-ui/react";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import Link from "next/link";
|
||||
import { memo, useState } from "react";
|
||||
@@ -57,11 +57,7 @@ const columns: DataTableColumnDef<User>[] = [
|
||||
];
|
||||
|
||||
export const UserTable = memo(function UserTable() {
|
||||
const toast = useToast();
|
||||
const [pagination, setPagination] = useState<Pagination>({ cursor: "", direction: "forward" });
|
||||
const [response, setResponse] = useState<Omit<FetchUsersResponse<User>, "sort_key" | "order">>({
|
||||
items: [],
|
||||
});
|
||||
const [filterValues, setFilterValues] = useState<FilterItem[]>([]);
|
||||
const handleFilterValuesChange = (values: FilterItem[]) => {
|
||||
setFilterValues(values);
|
||||
@@ -71,68 +67,46 @@ export const UserTable = memo(function UserTable() {
|
||||
// This follows useSWR's recommendation for simple pagination:
|
||||
// https://swr.vercel.app/docs/pagination#when-to-use-useswr
|
||||
const display_name = filterValues.find((value) => value.id === "display_name")?.value ?? "";
|
||||
useSWR<
|
||||
FetchUsersResponse<User>
|
||||
>(`/api/admin/users?direction=${pagination.direction}&cursor=${pagination.cursor}&searchDisplayName=${display_name}&sortKey=display_name`, get, {
|
||||
onSuccess: (data) => {
|
||||
// When no more users can be found, trigger a toast to indicate why no
|
||||
// changes have taken place. We have to maintain a non-empty set of
|
||||
// users otherwise we can't paginate using a cursor (since we've lost the
|
||||
// cursor).
|
||||
if (data.items.length === 0) {
|
||||
toast({
|
||||
title: "No more users",
|
||||
status: "warning",
|
||||
duration: 1000,
|
||||
isClosable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setResponse(data);
|
||||
},
|
||||
});
|
||||
const { data, error } = useSWR<FetchUsersResponse<User>>(
|
||||
`/api/admin/users?direction=${pagination.direction}&cursor=${pagination.cursor}&searchDisplayName=${display_name}&sortKey=display_name`,
|
||||
get,
|
||||
{
|
||||
keepPreviousData: true,
|
||||
}
|
||||
);
|
||||
|
||||
const toPreviousPage = () => {
|
||||
if (response.items.length >= 0) {
|
||||
setPagination({
|
||||
cursor: response.prev,
|
||||
direction: "back",
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Can not paginate when no users are found",
|
||||
status: "warning",
|
||||
duration: 1000,
|
||||
isClosable: true,
|
||||
});
|
||||
}
|
||||
setPagination({
|
||||
cursor: data.prev,
|
||||
direction: "back",
|
||||
});
|
||||
};
|
||||
|
||||
const toNextPage = () => {
|
||||
if (response.items.length >= 0) {
|
||||
setPagination({
|
||||
cursor: response.next,
|
||||
direction: "forward",
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Can not paginate when no users are found",
|
||||
status: "warning",
|
||||
duration: 1000,
|
||||
isClosable: true,
|
||||
});
|
||||
}
|
||||
setPagination({
|
||||
cursor: data.next,
|
||||
direction: "forward",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
data={response.items}
|
||||
columns={columns}
|
||||
caption="Users"
|
||||
onNextClick={toNextPage}
|
||||
onPreviousClick={toPreviousPage}
|
||||
filterValues={filterValues}
|
||||
onFilterChange={handleFilterValuesChange}
|
||||
></DataTable>
|
||||
<Card>
|
||||
<CardBody>
|
||||
{data && (
|
||||
<DataTable
|
||||
data={data.items}
|
||||
columns={columns}
|
||||
caption="Users"
|
||||
onNextClick={toNextPage}
|
||||
onPreviousClick={toPreviousPage}
|
||||
disableNext={!data.next}
|
||||
disablePrevious={!data.prev}
|
||||
filterValues={filterValues}
|
||||
onFilterChange={handleFilterValuesChange}
|
||||
></DataTable>
|
||||
)}
|
||||
{error && "Unable to load users."}
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import prisma from "src/lib/prismadb";
|
||||
/**
|
||||
* The number of users to fetch in a single request. Could later be a query parameter.
|
||||
*/
|
||||
const PAGE_SIZE = 20;
|
||||
const PAGE_SIZE = 2;
|
||||
|
||||
/**
|
||||
* Returns a list of user results from the database when the requesting user is
|
||||
|
||||
Reference in New Issue
Block a user