diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index eafca6d1..1784650a 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -1,8 +1,6 @@ import { Box, Button, - Card, - CardBody, Flex, FormControl, FormLabel, @@ -47,6 +45,8 @@ export type DataTableProps = { onNextClick?: () => void; onPreviousClick?: () => void; onFilterChange?: (items: FilterItem[]) => void; + disableNext?: boolean; + disablePrevious?: boolean; }; export const DataTable = ({ @@ -57,6 +57,8 @@ export const DataTable = ({ onNextClick, onPreviousClick, onFilterChange, + disableNext, + disablePrevious, }: DataTableProps) => { const { getHeaderGroups, getRowModel } = useReactTable({ data, @@ -75,49 +77,51 @@ export const DataTable = ({ onFilterChange(newValues); }; return ( - - - - - - - - - - {caption} - - {getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - - {getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
- - {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} - {(header.column.columnDef as DataTableColumnDef).filterable && ( - value.id === header.id)?.value ?? ""} - onChange={(value) => handleFilterChange({ id: header.id, value })} - label={flexRender(header.column.columnDef.header, header.getContext())} - > - )} - -
{flexRender(cell.column.columnDef.cell, cell.getContext())}
-
-
-
+ <> + + + + + + + + {caption} + + {getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ + {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} + {(header.column.columnDef as DataTableColumnDef).filterable && ( + value.id === header.id)?.value ?? ""} + onChange={(value) => handleFilterChange({ id: header.id, value })} + label={flexRender(header.column.columnDef.header, header.getContext())} + > + )} + +
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ); }; diff --git a/website/src/components/UserTable.tsx b/website/src/components/UserTable.tsx index 68285bfa..1f4ccfca 100644 --- a/website/src/components/UserTable.tsx +++ b/website/src/components/UserTable.tsx @@ -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[] = [ ]; export const UserTable = memo(function UserTable() { - const toast = useToast(); const [pagination, setPagination] = useState({ cursor: "", direction: "forward" }); - const [response, setResponse] = useState, "sort_key" | "order">>({ - items: [], - }); const [filterValues, setFilterValues] = useState([]); 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 - >(`/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>( + `/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 ( - + + + {data && ( + + )} + {error && "Unable to load users."} + + ); }); diff --git a/website/src/pages/api/admin/users.ts b/website/src/pages/api/admin/users.ts index 57944cff..f43af305 100644 --- a/website/src/pages/api/admin/users.ts +++ b/website/src/pages/api/admin/users.ts @@ -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