feat create pagestate wrapper

This commit is contained in:
karenvicent committed 2025-09-05 15:53:22 -04:00
1 parent 2f6a0913dc
commit 8e13855b66
8 files changed
+328 -366

No files matched your search

@@ -22,7 +22,7 @@ const Bar = ({ width, height, backgroundColor, borderRadius, children }) => {
return (
<Box
width={width}
width={width}
position="relative"
height={height}
backgroundColor={backgroundColor}
@@ -0,0 +1,66 @@
import GenericFallback from "../GenericFallback";
import Fallback from "../Fallback";
import { Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
import { useIsAdmin } from "../../Hooks/useIsAdmin";
import PropTypes from "prop-types";
const PageStateWrapper = ({
networkError,
isLoading,
items,
type,
fallbackLink,
fallbackChildren,
children,
}) => {
const theme = useTheme();
const { t } = useTranslation();
const isAdmin = useIsAdmin();
const hasInitialized = !isLoading && items !== undefined;
const showEmpty = items == undefined || items.length === 0;
if (networkError) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
if (!hasInitialized) {
return null;
}
if (showEmpty) {
return (
<Fallback
type={type}
title={t(`${type}.fallback.title`)}
checks={t(`${type}.fallback.checks`, { returnObjects: true })}
link={fallbackLink}
isAdmin={isAdmin}
>
{fallbackChildren}
</Fallback>
);
}
return <>{children}</>;
};
PageStateWrapper.propTypes = {
networkError: PropTypes.any,
isLoading: PropTypes.bool,
items: PropTypes.oneOfType([PropTypes.array, PropTypes.oneOf([null])]),
type: PropTypes.string,
fallbackLink: PropTypes.string,
fallbackChildren: PropTypes.node,
children: PropTypes.node,
};
export default PageStateWrapper;
@@ -1,12 +1,11 @@
// Components
import { Stack, Typography } from "@mui/material";
import { Stack } from "@mui/material";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import MonitorCountHeader from "../../../Components/MonitorCountHeader";
import MonitorCreateHeader from "../../../Components/MonitorCreateHeader";
import MonitorsTable from "./Components/MonitorsTable";
import Pagination from "../../..//Components/Table/TablePagination";
import GenericFallback from "../../../Components/GenericFallback";
import Fallback from "../../../Components/Fallback";
import PageStateWrapper from "../../../Components/PageStateWrapper";
import Filter from "./Components/Filters";
import SearchComponent from "../../Uptime/Monitors/Components/SearchComponent";
// Utils
@@ -81,75 +80,58 @@ const InfrastructureMonitors = () => {
updateTrigger,
});
if (networkError === true) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
if (!isLoading && typeof summary?.totalMonitors === "undefined") {
return (
<Fallback
type="infrastructureMonitor"
title={t("infrastructureMonitor.fallback.title")}
checks={t("infrastructureMonitor.fallback.checks", { returnObjects: true })}
link="/infrastructure/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<MonitorCreateHeader
isAdmin={isAdmin}
<>
<PageStateWrapper
networkError={networkError}
isLoading={isLoading}
path="/infrastructure/create"
/>
<Stack direction={"row"}>
<MonitorCountHeader
isLoading={isLoading}
monitorCount={summary?.totalMonitors ?? 0}
/>
<Filter
selectedStatus={selectedStatus}
setSelectedStatus={setSelectedStatus}
setToFilterStatus={setToFilterStatus}
handleReset={handleReset}
/>
<SearchComponent
monitors={monitors}
onSearchChange={setSearch}
setIsSearching={setIsSearching}
/>
</Stack>
items={monitors}
type="infrastructureMonitor"
fallbackLink="/infrastructure/create"
>
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<MonitorCreateHeader
isAdmin={isAdmin}
isLoading={isLoading}
path="/infrastructure/create"
/>
<Stack direction={"row"}>
<MonitorCountHeader
isLoading={isLoading}
monitorCount={summary?.totalMonitors ?? 0}
/>
<Filter
selectedStatus={selectedStatus}
setSelectedStatus={setSelectedStatus}
setToFilterStatus={setToFilterStatus}
handleReset={handleReset}
/>
<SearchComponent
monitors={monitors}
onSearchChange={setSearch}
setIsSearching={setIsSearching}
/>
</Stack>
<MonitorsTable
isLoading={isLoading}
monitors={monitors}
isAdmin={isAdmin}
handleActionMenuDelete={handleActionMenuDelete}
isSearching={isSearching}
/>
<Pagination
itemCount={summary?.totalMonitors}
paginationLabel={t("monitors")}
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Stack>
<MonitorsTable
isLoading={isLoading}
monitors={monitors}
isAdmin={isAdmin}
handleActionMenuDelete={handleActionMenuDelete}
isSearching={isSearching}
/>
<Pagination
itemCount={summary?.totalMonitors}
paginationLabel={t("monitors")}
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Stack>
</PageStateWrapper>
</>
);
};
+43 -63
View File
@@ -1,6 +1,5 @@
import { Stack, Button } from "@mui/material";
import { useTheme } from "@emotion/react";
import Fallback from "../../Components/Fallback";
import { useState, useEffect } from "react";
import "./index.css";
import MaintenanceTable from "./MaintenanceTable";
@@ -8,24 +7,21 @@ import { useSelector } from "react-redux";
import { networkService } from "../../main";
import Breadcrumbs from "../../Components/Breadcrumbs";
import { useNavigate } from "react-router-dom";
import { useIsAdmin } from "../../Hooks/useIsAdmin";
import { useTranslation } from "react-i18next";
import { Typography } from "@mui/material";
import GenericFallback from "../../Components/GenericFallback";
import PageStateWrapper from "../../Components/PageStateWrapper";
const Maintenance = () => {
const theme = useTheme();
const { t } = useTranslation();
const navigate = useNavigate();
const rowsPerPage = useSelector((state) => state?.ui?.maintenance?.rowsPerPage ?? 5);
const isAdmin = useIsAdmin();
const [maintenanceWindows, setMaintenanceWindows] = useState([]);
const [maintenanceWindowCount, setMaintenanceWindowCount] = useState(0);
const [page, setPage] = useState(0);
const [sort, setSort] = useState({});
const [updateTrigger, setUpdateTrigger] = useState(false);
const [networkError, setNetworkError] = useState(false);
const [isDataFetched, setIsDataFetched] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleActionMenuDelete = () => {
setUpdateTrigger((prev) => !prev);
@@ -34,6 +30,7 @@ const Maintenance = () => {
useEffect(() => {
const fetchMaintenanceWindows = async () => {
try {
setIsLoading(true);
const response = await networkService.getMaintenanceWindowsByTeamId({
page: page,
rowsPerPage: rowsPerPage,
@@ -44,70 +41,53 @@ const Maintenance = () => {
} catch (error) {
setNetworkError(true);
} finally {
setIsDataFetched(true);
setIsLoading(false);
}
};
fetchMaintenanceWindows();
}, [page, rowsPerPage, updateTrigger]);
if (networkError) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
// Only show the fallback if we've fetched data and there are no maintenance windows
if (isDataFetched && maintenanceWindows.length === 0) {
return (
<Fallback
type="maintenanceWindow"
title={t("maintenanceWindow.fallback.title")}
checks={t("maintenanceWindow.fallback.checks", { returnObjects: true })}
link="/maintenance/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
mt={theme.spacing(5)}
<>
<PageStateWrapper
networkError={networkError}
isLoading={isLoading}
items={maintenanceWindows}
type="maintenanceWindow"
fallbackLink="/maintenance/create"
>
<Breadcrumbs list={[{ name: "maintenance", path: "/maintenance" }]} />
<Button
variant="contained"
color="accent"
onClick={() => {
navigate("/maintenance/create");
}}
sx={{ fontWeight: 500 }}
>
{t("createMaintenanceWindow")}
</Button>
</Stack>
<MaintenanceTable
page={page}
setPage={setPage}
rowsPerPage={rowsPerPage}
sort={sort}
setSort={setSort}
maintenanceWindows={maintenanceWindows}
maintenanceWindowCount={maintenanceWindowCount}
updateCallback={handleActionMenuDelete}
/>
</Stack>
<Stack gap={theme.spacing(10)}>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
mt={theme.spacing(5)}
>
<Breadcrumbs list={[{ name: "maintenance", path: "/maintenance" }]} />
<Button
variant="contained"
color="accent"
onClick={() => {
navigate("/maintenance/create");
}}
sx={{ fontWeight: 500 }}
>
{t("createMaintenanceWindow")}
</Button>
</Stack>
<MaintenanceTable
page={page}
setPage={setPage}
rowsPerPage={rowsPerPage}
sort={sort}
setSort={setSort}
maintenanceWindows={maintenanceWindows}
maintenanceWindowCount={maintenanceWindowCount}
updateCallback={handleActionMenuDelete}
/>
</Stack>
</PageStateWrapper>
</>
);
};
+40 -44
View File
@@ -4,11 +4,10 @@ import Typography from "@mui/material/Typography";
import Breadcrumbs from "../../Components/Breadcrumbs";
import Button from "@mui/material/Button";
import DataTable from "../../Components/Table";
import Fallback from "../../Components/Fallback";
import ActionMenu from "./components/ActionMenu";
import PageStateWrapper from "../../Components/PageStateWrapper";
// Utils
import { useIsAdmin } from "../../Hooks/useIsAdmin";
import { useState } from "react";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
@@ -23,7 +22,6 @@ const Notifications = () => {
const theme = useTheme();
const BREADCRUMBS = [{ name: "notifications", path: "/notifications" }];
const [updateTrigger, setUpdateTrigger] = useState(false);
const isAdmin = useIsAdmin();
const [notifications, isLoading, error] = useGetNotificationsByTeamId(updateTrigger);
const [deleteNotification, isDeleting, deleteError] = useDeleteNotification();
const { t } = useTranslation();
@@ -76,49 +74,47 @@ const Notifications = () => {
},
];
if (notifications?.length === 0) {
return (
<Fallback
type="notifications"
title={t("notifications.fallback.title")}
checks={t("notifications.fallback.checks", { returnObjects: true })}
link="/notifications/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<Stack
direction="row"
justifyContent="flex-end"
<>
<PageStateWrapper
networkError={error}
isLoading={isLoading}
items={notifications}
type="notifications"
fallbackLink="/notifications/create"
>
<Button
variant="contained"
color="accent"
onClick={() => navigate("/notifications/create")}
>
{t("notifications.createButton")}
</Button>
</Stack>
<Typography variant="h1">{t("notifications.createTitle")}</Typography>
<DataTable
config={{
onRowClick: (row) => navigate(`/notifications/${row._id}`),
rowSX: {
cursor: "pointer",
"&:hover td": {
backgroundColor: theme.palette.tertiary.main,
transition: "background-color .3s ease",
},
},
}}
headers={headers}
data={notifications}
/>
</Stack>
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<Stack
direction="row"
justifyContent="flex-end"
>
<Button
variant="contained"
color="accent"
onClick={() => navigate("/notifications/create")}
>
{t("notifications.createButton")}
</Button>
</Stack>
<Typography variant="h1">{t("notifications.createTitle")}</Typography>
<DataTable
config={{
onRowClick: (row) => navigate(`/notifications/${row._id}`),
rowSX: {
cursor: "pointer",
"&:hover td": {
backgroundColor: theme.palette.tertiary.main,
transition: "background-color .3s ease",
},
},
}}
headers={headers}
data={notifications}
/>
</Stack>
</PageStateWrapper>
</>
);
};
+36 -53
View File
@@ -1,18 +1,16 @@
// Components
import { useState } from "react";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import { Stack, Typography } from "@mui/material";
import { Stack } from "@mui/material";
import CreateMonitorHeader from "../../../Components/MonitorCreateHeader";
import MonitorCountHeader from "../../../Components/MonitorCountHeader";
import MonitorGrid from "./Components/MonitorGrid";
import Fallback from "../../../Components/Fallback";
import GenericFallback from "../../../Components/GenericFallback";
import PageStateWrapper from "../../../Components/PageStateWrapper";
import FallbackPageSpeedWarning from "../../../Components/Fallback/FallbackPageSpeedWarning";
// Utils
import { useTheme } from "@emotion/react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useTranslation } from "react-i18next";
import { useFetchMonitorsByTeamId } from "../../../Hooks/monitorHooks";
import { useFetchSettings } from "../../../Hooks/settingsHooks";
// Constants
@@ -20,7 +18,6 @@ const BREADCRUMBS = [{ name: `pagespeed`, path: "/pagespeed" }];
const TYPES = ["pagespeed"];
const PageSpeed = () => {
const theme = useTheme();
const { t } = useTranslation();
const isAdmin = useIsAdmin();
const [monitors, monitorsSummary, isLoading, networkError] = useFetchMonitorsByTeamId({
@@ -40,56 +37,42 @@ const PageSpeed = () => {
setIsEmailPasswordSet: () => {},
});
if (networkError === true) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
if (!isLoading && monitors?.length === 0) {
return (
<Fallback
type="pageSpeed"
title={t("pageSpeed.fallback.title")}
checks={t("pageSpeed.fallback.checks", { returnObjects: true })}
link="/pagespeed/create"
isAdmin={isAdmin}
>
{isAdmin && settingsData && !settingsData.pagespeedApiKey && (
<FallbackPageSpeedWarning settingsData={settingsData} />
)}
</Fallback>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<CreateMonitorHeader
isAdmin={isAdmin}
<>
<PageStateWrapper
networkError={networkError}
isLoading={isLoading}
path="/pagespeed/create"
/>
<MonitorCountHeader
isLoading={isLoading}
monitorCount={monitorsSummary?.totalMonitors}
sx={{ mb: theme.spacing(8) }}
/>
<MonitorGrid
size={6}
shouldRender={!isLoading}
monitors={monitors}
/>
</Stack>
items={monitors}
type="pageSpeed"
fallbackLink="/pagespeed/create"
fallbackChildren={
isAdmin &&
settingsData &&
!settingsData.pagespeedApiKey && (
<FallbackPageSpeedWarning settingsData={settingsData} />
)
}
>
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<CreateMonitorHeader
isAdmin={isAdmin}
isLoading={isLoading}
path="/pagespeed/create"
/>
<MonitorCountHeader
isLoading={isLoading}
monitorCount={monitorsSummary?.totalMonitors}
sx={{ mb: theme.spacing(8) }}
/>
<MonitorGrid
size={6}
shouldRender={!isLoading}
monitors={monitors}
/>
</Stack>
</PageStateWrapper>
</>
);
};
@@ -1,14 +1,11 @@
// Components
import { Stack, Typography } from "@mui/material";
import { Stack } from "@mui/material";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import Fallback from "../../../Components/Fallback";
import MonitorCreateHeader from "../../../Components/MonitorCreateHeader";
import GenericFallback from "../../../Components/GenericFallback";
import StatusPagesTable from "./Components/StatusPagesTable";
import SkeletonLayout from "../../../Components/Skeletons/FullPage";
import PageStateWrapper from "../../../Components/PageStateWrapper";
// Utils
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
import { useStatusPagesFetch } from "./Hooks/useStatusPagesFetch";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
const BREADCRUMBS = [{ name: `Status Pages`, path: "" }];
@@ -16,52 +13,30 @@ const BREADCRUMBS = [{ name: `Status Pages`, path: "" }];
const StatusPages = () => {
// Utils
const theme = useTheme();
const { t } = useTranslation();
const isAdmin = useIsAdmin();
const [isLoading, networkError, statusPages] = useStatusPagesFetch();
if (isLoading) {
return <SkeletonLayout />;
}
if (networkError === true) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
if (!isLoading && typeof statusPages !== "undefined" && statusPages.length === 0) {
return (
<Fallback
title={t("statusPage.fallback.title")}
checks={t("statusPage.fallback.checks", { returnObjects: true })}
type="statusPage"
link="/status/uptime/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<MonitorCreateHeader
label="Create status page"
isAdmin={isAdmin}
path="/status/uptime/create"
<>
<PageStateWrapper
networkError={networkError}
isLoading={isLoading}
/>
<StatusPagesTable data={statusPages} />
</Stack>
items={statusPages}
type="statusPage"
fallbackLink="/status/uptime/create"
>
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<MonitorCreateHeader
label="Create status page"
isAdmin={isAdmin}
path="/status/uptime/create"
isLoading={isLoading}
/>
<StatusPagesTable data={statusPages} />
</Stack>
</PageStateWrapper>
</>
);
};
+70 -90
View File
@@ -10,16 +10,14 @@ import StatusBoxes from "./Components/StatusBoxes";
import UptimeDataTable from "./Components/UptimeDataTable";
import Pagination from "../../../Components/Table/TablePagination";
import CreateMonitorHeader from "../../../Components/MonitorCreateHeader";
import Fallback from "../../../Components/Fallback";
import GenericFallback from "../../../Components/GenericFallback";
import SearchComponent from "./Components/SearchComponent";
import Filter from "./Components/Filter";
import PageStateWrapper from "../../../Components/PageStateWrapper";
import MonitorCountHeader from "../../../Components/MonitorCountHeader";
// MUI Components
import { Stack, Box, Button, Typography } from "@mui/material";
import { Stack, Box, Button } from "@mui/material";
// Utils
import { useState, useCallback, useEffect } from "react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
@@ -153,93 +151,75 @@ const UptimeMonitors = () => {
}, [isSearching]);
const isLoading = monitorsWithSummaryIsLoading || monitorsWithChecksIsLoading;
if (networkError) {
return (
<GenericFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{t("common.toasts.networkError")}
</Typography>
<Typography>{t("common.toasts.checkConnection")}</Typography>
</GenericFallback>
);
}
if (
!isLoading &&
(monitorsSummary?.totalMonitors === 0 ||
typeof monitorsSummary?.totalMonitors === "undefined")
) {
return (
<Fallback
type="uptimeMonitor"
title={t("uptimeMonitor.fallback.title")}
checks={t("uptimeMonitor.fallback.checks", { returnObjects: true })}
link="/uptime/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack
className="monitors"
gap={theme.spacing(10)}
>
<Breadcrumbs list={BREADCRUMBS} />
<CreateMonitorHeader
isAdmin={isAdmin}
isLoading={isLoading}
path="/uptime/create"
bulkPath="/uptime/bulk-import"
/>
<Greeting type="uptime" />
<StatusBoxes
monitorsSummary={monitorsSummary}
shouldRender={!monitorsWithSummaryIsLoading}
/>
<Stack direction={"row"}>
<MonitorCountHeader
isLoading={monitorsWithSummaryIsLoading}
monitorCount={monitorsSummary?.totalMonitors}
/>
<Filter
selectedTypes={selectedTypes}
setSelectedTypes={setSelectedTypes}
selectedStatus={selectedStatus}
setSelectedStatus={setSelectedStatus}
selectedState={selectedState}
setSelectedState={setSelectedState}
setToFilterStatus={setToFilterStatus}
setToFilterActive={setToFilterActive}
handleReset={handleReset}
/>
<SearchComponent
monitors={monitors}
onSearchChange={setSearch}
setIsSearching={setIsSearching}
/>
</Stack>
<UptimeDataTable
isAdmin={isAdmin}
isSearching={isSearching}
filteredMonitors={monitorsWithChecks}
sort={sort}
setSort={setSort}
monitorsAreLoading={monitorsWithChecksIsLoading}
triggerUpdate={triggerUpdate}
/>
<Pagination
itemCount={monitorsWithChecksCount}
paginationLabel="monitors"
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Stack>
return (
<>
<PageStateWrapper
networkError={networkError}
isLoading={isLoading}
items={monitors}
type="uptimeMonitor"
fallbackLink="/uptime/create"
>
<Stack
className="monitors"
gap={theme.spacing(10)}
>
<Breadcrumbs list={BREADCRUMBS} />
<CreateMonitorHeader
isAdmin={isAdmin}
isLoading={isLoading}
path="/uptime/create"
bulkPath="/uptime/bulk-import"
/>
<Greeting type="uptime" />
<StatusBoxes
monitorsSummary={monitorsSummary}
shouldRender={!monitorsWithSummaryIsLoading}
/>
<Stack direction={"row"}>
<MonitorCountHeader
isLoading={monitorsWithSummaryIsLoading}
monitorCount={monitorsSummary?.totalMonitors}
/>
<Filter
selectedTypes={selectedTypes}
setSelectedTypes={setSelectedTypes}
selectedStatus={selectedStatus}
setSelectedStatus={setSelectedStatus}
selectedState={selectedState}
setSelectedState={setSelectedState}
setToFilterStatus={setToFilterStatus}
setToFilterActive={setToFilterActive}
handleReset={handleReset}
/>
<SearchComponent
monitors={monitors}
onSearchChange={setSearch}
setIsSearching={setIsSearching}
/>
</Stack>
<UptimeDataTable
isAdmin={isAdmin}
isSearching={isSearching}
filteredMonitors={monitorsWithChecks}
sort={sort}
setSort={setSort}
monitorsAreLoading={monitorsWithChecksIsLoading}
triggerUpdate={triggerUpdate}
/>
<Pagination
itemCount={monitorsWithChecksCount}
paginationLabel="monitors"
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Stack>
</PageStateWrapper>
</>
);
};