improve checks fetch and paginaiton
This commit is contained in:
1 parent
6978a7e2bb
commit
4667c59573
4 files changed
+131
-21
No files matched your search
@@ -10,6 +10,7 @@ import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import {
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Coffee,
|
||||
Ellipsis,
|
||||
PartyPopper,
|
||||
} from "lucide-react";
|
||||
|
||||
@@ -331,13 +333,118 @@ function TablePaginationActions(props: TablePaginationActionsProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export const Pagination = ({ ...props }: TablePaginationProps) => {
|
||||
interface HasMoreTablePaginationActionsProps {
|
||||
hasMore?: boolean;
|
||||
page: number;
|
||||
onPageChange: (
|
||||
event: React.MouseEvent<HTMLButtonElement>,
|
||||
newPage: number
|
||||
) => void;
|
||||
}
|
||||
function HasMoreTablePaginationActions(
|
||||
props: HasMoreTablePaginationActionsProps
|
||||
) {
|
||||
const theme = useTheme();
|
||||
const { hasMore, page, onPageChange } = props;
|
||||
console.log(JSON.stringify(props, null, 2));
|
||||
|
||||
const handleFirstPageButtonClick = (
|
||||
event: React.MouseEvent<HTMLButtonElement>
|
||||
) => {
|
||||
onPageChange(event, 0);
|
||||
};
|
||||
|
||||
const handleBackButtonClick = (
|
||||
event: React.MouseEvent<HTMLButtonElement>
|
||||
) => {
|
||||
onPageChange(event, page - 1);
|
||||
};
|
||||
|
||||
const handleNextButtonClick = (
|
||||
event: React.MouseEvent<HTMLButtonElement>
|
||||
) => {
|
||||
onPageChange(event, page + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{ flexShrink: 0, ml: { xs: 0, md: 2.5 } }}
|
||||
className="table-pagination-actions"
|
||||
>
|
||||
<IconButton
|
||||
onClick={handleFirstPageButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="first page"
|
||||
>
|
||||
{theme.direction === "rtl" ? (
|
||||
<ChevronsRight size={20} strokeWidth={1.5} />
|
||||
) : (
|
||||
<ChevronsLeft size={20} strokeWidth={1.5} />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleBackButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="previous page"
|
||||
>
|
||||
{theme.direction === "rtl" ? (
|
||||
<ChevronRight size={20} strokeWidth={1.5} />
|
||||
) : (
|
||||
<ChevronLeft size={20} strokeWidth={1.5} />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleNextButtonClick}
|
||||
disabled={hasMore === false}
|
||||
aria-label="next page"
|
||||
>
|
||||
{theme.direction === "rtl" ? (
|
||||
<ChevronLeft size={20} strokeWidth={1.5} />
|
||||
) : (
|
||||
<ChevronRight size={20} strokeWidth={1.5} />
|
||||
)}
|
||||
</IconButton>
|
||||
<Tooltip
|
||||
title={hasMore === true ? "More pages available" : "No more pages"}
|
||||
>
|
||||
<IconButton disabled={hasMore === false} aria-label="next page">
|
||||
<Ellipsis size={20} strokeWidth={1.5} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface PaginationProps extends TablePaginationProps {
|
||||
hasMore?: boolean;
|
||||
}
|
||||
|
||||
export const Pagination = ({ ...props }: PaginationProps) => {
|
||||
const hasMore = props.hasMore;
|
||||
const isSmall = useMediaQuery((theme: any) => theme.breakpoints.down("sm"));
|
||||
const theme = useTheme();
|
||||
const labelDisplayedRows = ({
|
||||
from,
|
||||
to,
|
||||
count,
|
||||
}: {
|
||||
from: number;
|
||||
to: number;
|
||||
count: number;
|
||||
}) => {
|
||||
if (hasMore) {
|
||||
return to === 0 ? "" : `${from}–${to}`;
|
||||
}
|
||||
return `${from}–${to} of ${count}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<TablePagination
|
||||
ActionsComponent={TablePaginationActions}
|
||||
ActionsComponent={
|
||||
hasMore ? HasMoreTablePaginationActions : TablePaginationActions
|
||||
}
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
labelDisplayedRows={labelDisplayedRows}
|
||||
{...props}
|
||||
sx={{
|
||||
"& .MuiTablePagination-toolbar": isSmall
|
||||
|
||||
@@ -29,7 +29,7 @@ const ChecksPage = () => {
|
||||
const monitors: IMonitor[] = monitorResponse?.data || [];
|
||||
|
||||
const { response: checksResponse, loading: checksLoading } = useGet<
|
||||
ApiResponse<{ count: number; checks: ICheck[] }>
|
||||
ApiResponse<{ hasMore: boolean; checks: ICheck[] }>
|
||||
>(
|
||||
`/checks?page=${page}&rowsPerPage=${rowsPerPage}&range=${range}&status=${status}${
|
||||
selectedMonitorId !== "all" ? `&monitorId=${selectedMonitorId}` : ""
|
||||
@@ -44,7 +44,7 @@ const ChecksPage = () => {
|
||||
);
|
||||
|
||||
const checks = checksResponse?.data?.checks || [];
|
||||
const checksCount = checksResponse?.data?.count || 0;
|
||||
const hasMore = checksResponse?.data?.hasMore;
|
||||
|
||||
return (
|
||||
<BasePage>
|
||||
@@ -97,7 +97,7 @@ const ChecksPage = () => {
|
||||
</Stack>
|
||||
<ChecksTable
|
||||
checks={checks}
|
||||
count={checksCount}
|
||||
hasMore={hasMore}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
rowsPerPage={rowsPerPage}
|
||||
|
||||
@@ -20,14 +20,14 @@ type CheckWithMonitor = ICheck & {
|
||||
|
||||
export const ChecksTable = ({
|
||||
checks,
|
||||
count,
|
||||
hasMore,
|
||||
page,
|
||||
setPage,
|
||||
rowsPerPage,
|
||||
setRowsPerPage,
|
||||
}: {
|
||||
checks: CheckWithMonitor[];
|
||||
count: number;
|
||||
hasMore?: boolean;
|
||||
page: number;
|
||||
setPage: (page: number) => void;
|
||||
rowsPerPage: number;
|
||||
@@ -76,7 +76,7 @@ export const ChecksTable = ({
|
||||
},
|
||||
{
|
||||
id: "message",
|
||||
content: t("checks.table.headers.message"),
|
||||
content: t("common.table.headers.message"),
|
||||
render: (row) => {
|
||||
return row.message || "N/A";
|
||||
},
|
||||
@@ -114,7 +114,8 @@ export const ChecksTable = ({
|
||||
/>
|
||||
<Pagination
|
||||
component="div"
|
||||
count={count}
|
||||
count={0}
|
||||
hasMore={hasMore}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
onPageChange={handlePageChange}
|
||||
|
||||
@@ -31,7 +31,7 @@ export interface ICheckService {
|
||||
page: number,
|
||||
rowsPerPage: number,
|
||||
range: string
|
||||
) => Promise<{ checks: ICheck[]; count: number }>;
|
||||
) => Promise<{ checks: ICheck[]; hasMore: boolean }>;
|
||||
|
||||
getCheckById: (checkId: string, teamId: string) => Promise<ICheck | null>;
|
||||
|
||||
@@ -242,24 +242,26 @@ class CheckService implements ICheckService {
|
||||
status,
|
||||
"metadata.teamId": new mongoose.Types.ObjectId(teamId),
|
||||
"metadata.monitorId": new mongoose.Types.ObjectId(monitorId),
|
||||
createdAt: { $gte: startDate },
|
||||
createdAt: { $gte: startDate, $lte: new Date() },
|
||||
};
|
||||
} else {
|
||||
match = {
|
||||
status,
|
||||
"metadata.teamId": new mongoose.Types.ObjectId(teamId),
|
||||
createdAt: { $gte: startDate },
|
||||
createdAt: { $gte: startDate, $lte: new Date() },
|
||||
};
|
||||
}
|
||||
const [count, checks] = await Promise.all([
|
||||
Check.countDocuments(match),
|
||||
Check.find(match)
|
||||
.populate({ path: "metadata.monitorId", select: "name" })
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(page * rowsPerPage)
|
||||
.limit(rowsPerPage),
|
||||
]);
|
||||
return { checks, count };
|
||||
// Has-more pagination: over-fetch by 1 to infer existence of a next page
|
||||
const pageSizePlusOne = rowsPerPage + 1;
|
||||
const docs = await Check.find(match)
|
||||
.populate({ path: "metadata.monitorId", select: "name" })
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(page * rowsPerPage)
|
||||
.limit(pageSizePlusOne);
|
||||
|
||||
const hasMore = docs.length > rowsPerPage;
|
||||
const checks = hasMore ? docs.slice(0, rowsPerPage) : docs;
|
||||
return { checks, hasMore };
|
||||
};
|
||||
|
||||
getCheckById = async (checkId: string, teamId: string) => {
|
||||
|
||||
Reference in new issue
Block a user