From de7f0a119339491ffe9f2114045a603c2f42188f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 30 Jan 2025 14:23:05 -0800 Subject: [PATCH 1/7] rename CreateMonitor header to match other headers --- .../{CreateMonitorHeader => MonitorCreateHeader}/index.jsx | 2 +- .../{CreateMonitorHeader => MonitorCreateHeader}/skeleton.jsx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Client/src/Components/{CreateMonitorHeader => MonitorCreateHeader}/index.jsx (90%) rename Client/src/Components/{CreateMonitorHeader => MonitorCreateHeader}/skeleton.jsx (100%) diff --git a/Client/src/Components/CreateMonitorHeader/index.jsx b/Client/src/Components/MonitorCreateHeader/index.jsx similarity index 90% rename from Client/src/Components/CreateMonitorHeader/index.jsx rename to Client/src/Components/MonitorCreateHeader/index.jsx index b8fcbc39a..03dcc57e5 100644 --- a/Client/src/Components/CreateMonitorHeader/index.jsx +++ b/Client/src/Components/MonitorCreateHeader/index.jsx @@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; import SkeletonLayout from "./skeleton"; -const CreateMonitorHeader = ({ isAdmin, shouldRender, path }) => { +const CreateMonitorHeader = ({ isAdmin, shouldRender = true, path }) => { const navigate = useNavigate(); if (!isAdmin) return null; if (!shouldRender) return ; diff --git a/Client/src/Components/CreateMonitorHeader/skeleton.jsx b/Client/src/Components/MonitorCreateHeader/skeleton.jsx similarity index 100% rename from Client/src/Components/CreateMonitorHeader/skeleton.jsx rename to Client/src/Components/MonitorCreateHeader/skeleton.jsx From cdc407fd21191a6311eb45815fefec40cfa67c40 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 30 Jan 2025 14:23:42 -0800 Subject: [PATCH 2/7] update route --- Client/src/Routes/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 36c930ace..555c335f7 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -1,6 +1,5 @@ import { Navigate, Route, Routes as LibRoutes } from "react-router"; import HomeLayout from "../Components/Layouts/HomeLayout"; -import { Infrastructure } from "../Pages/Infrastructure"; import NotFound from "../Pages/NotFound"; // Auth @@ -24,6 +23,7 @@ import PageSpeedDetails from "../Pages/PageSpeed/Details"; import PageSpeedConfigure from "../Pages/PageSpeed/Configure"; // Infrastructure +import Infrastructure from "../Pages/Infrastructure/Monitors"; import InfrastructureCreate from "../Pages/Infrastructure/Create"; import InfrastructureDetails from "../Pages/Infrastructure/Details"; From 016cd6976349750e68e12018d0c2f3c93c684395 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 30 Jan 2025 14:24:46 -0800 Subject: [PATCH 3/7] Add shouldRender prop to table --- Client/src/Components/Table/index.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Client/src/Components/Table/index.jsx b/Client/src/Components/Table/index.jsx index 54e47ed1f..b716038e9 100644 --- a/Client/src/Components/Table/index.jsx +++ b/Client/src/Components/Table/index.jsx @@ -7,6 +7,7 @@ import { TableHead, TableRow, } from "@mui/material"; +import SkeletonLayout from "./skeleton"; import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; @@ -33,6 +34,7 @@ import { useTheme } from "@emotion/react"; */ const DataTable = ({ + shouldRender = true, headers = [], data = [], config = { @@ -41,6 +43,10 @@ const DataTable = ({ }, }) => { const theme = useTheme(); + if (!shouldRender) { + return ; + } + if ((headers?.length ?? 0) === 0) { return "No data"; } @@ -117,6 +123,7 @@ const DataTable = ({ }; DataTable.propTypes = { + shouldRender: PropTypes.bool, headers: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, From 880195efde8aece9e9086902d6c7ca7cd232cc6a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 30 Jan 2025 14:26:18 -0800 Subject: [PATCH 4/7] set initial loading state to true, skip one render --- Client/src/Pages/Incidents/Hooks/useChecksFetch.jsx | 2 +- Client/src/Pages/Incidents/Hooks/useMonitorsFetch.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/src/Pages/Incidents/Hooks/useChecksFetch.jsx b/Client/src/Pages/Incidents/Hooks/useChecksFetch.jsx index 57444ad05..614006792 100644 --- a/Client/src/Pages/Incidents/Hooks/useChecksFetch.jsx +++ b/Client/src/Pages/Incidents/Hooks/useChecksFetch.jsx @@ -7,7 +7,7 @@ const useChecksFetch = ({ selectedMonitor, filter, dateRange, page, rowsPerPage const { authToken, user } = useSelector((state) => state.auth); //Local - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); const [networkError, setNetworkError] = useState(false); const [checks, setChecks] = useState(undefined); const [checksCount, setChecksCount] = useState(undefined); diff --git a/Client/src/Pages/Incidents/Hooks/useMonitorsFetch.jsx b/Client/src/Pages/Incidents/Hooks/useMonitorsFetch.jsx index 0ffd18571..20043e80d 100644 --- a/Client/src/Pages/Incidents/Hooks/useMonitorsFetch.jsx +++ b/Client/src/Pages/Incidents/Hooks/useMonitorsFetch.jsx @@ -3,7 +3,7 @@ import { networkService } from "../../../main"; import { createToast } from "../../../Utils/toastUtils"; const useMonitorsFetch = ({ authToken, teamId }) => { //Local state - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); const [networkError, setNetworkError] = useState(false); const [monitors, setMonitors] = useState(undefined); From b928210f8a26829ba676c71796a61ff7c9d660de Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 30 Jan 2025 14:27:11 -0800 Subject: [PATCH 5/7] reactor infrastructure monitors page --- .../Components/MonitorsTable/index.jsx | 134 ++++++++ .../Components/MonitorsTableMenu}/index.jsx | 8 +- .../Monitors/Hooks/useMonitorFetch.jsx | 45 +++ .../Pages/Infrastructure/Monitors/index.jsx | 110 +++++++ Client/src/Pages/Infrastructure/index.jsx | 295 ------------------ Client/src/Pages/PageSpeed/Monitors/index.jsx | 2 +- Client/src/Pages/Uptime/Monitors/index.jsx | 5 +- 7 files changed, 297 insertions(+), 302 deletions(-) create mode 100644 Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx rename Client/src/Pages/Infrastructure/{components/Menu => Monitors/Components/MonitorsTableMenu}/index.jsx (93%) create mode 100644 Client/src/Pages/Infrastructure/Monitors/Hooks/useMonitorFetch.jsx create mode 100644 Client/src/Pages/Infrastructure/Monitors/index.jsx delete mode 100644 Client/src/Pages/Infrastructure/index.jsx diff --git a/Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx b/Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx new file mode 100644 index 000000000..f44b844a7 --- /dev/null +++ b/Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx @@ -0,0 +1,134 @@ +// Components +import DataTable from "../../../../../Components/Table"; +import Host from "../../../../Uptime/Monitors/Components/Host"; +import { StatusLabel } from "../../../../../Components/Label"; +import { Stack } from "@mui/material"; +import { InfrastructureMenu } from "../MonitorsTableMenu"; +// Assets +import CPUChipIcon from "../../../../../assets/icons/cpu-chip.svg?react"; +import CustomGauge from "../../../../../Components/Charts/CustomGauge"; + +// Utils +import { useTheme } from "@emotion/react"; +import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils"; +import { useNavigate } from "react-router-dom"; + +const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete }) => { + // Utils + const theme = useTheme(); + const { determineState } = useUtils(); + const navigate = useNavigate(); + + // Handlers + const openDetails = (id) => { + navigate(`/infrastructure/${id}`); + }; + const headers = [ + { + id: "host", + content: "Host", + render: (row) => ( + + ), + }, + { + id: "status", + content: "Status", + render: (row) => ( + + ), + }, + { + id: "frequency", + content: "Frequency", + render: (row) => ( + + + {row.processor} + + ), + }, + { id: "cpu", content: "CPU", render: (row) => }, + { id: "mem", content: "Mem", render: (row) => }, + { id: "disk", content: "Disk", render: (row) => }, + { + id: "actions", + content: "Actions", + render: (row) => ( + + ), + }, + ]; + + const data = monitors?.map((monitor) => { + const processor = + ((monitor.checks[0]?.cpu?.frequency ?? 0) / 1000).toFixed(2) + " GHz"; + const cpu = (monitor?.checks[0]?.cpu.usage_percent ?? 0) * 100; + const mem = (monitor?.checks[0]?.memory.usage_percent ?? 0) * 100; + const disk = (monitor?.checks[0]?.disk[0]?.usage_percent ?? 0) * 100; + const status = determineState(monitor); + const uptimePercentage = ((monitor?.uptimePercentage ?? 0) * 100) + .toFixed(2) + .toString(); + const percentageColor = + monitor.uptimePercentage < 0.25 + ? theme.palette.error.main + : monitor.uptimePercentage < 0.5 + ? theme.palette.warning.main + : theme.palette.success.main; + + return { + id: monitor._id, + name: monitor.name, + url: monitor.url, + processor, + cpu, + mem, + disk, + status, + uptimePercentage, + percentageColor, + }; + }); + + return ( + openDetails(row.id), + }} + /> + ); +}; + +export default MonitorsTable; diff --git a/Client/src/Pages/Infrastructure/components/Menu/index.jsx b/Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTableMenu/index.jsx similarity index 93% rename from Client/src/Pages/Infrastructure/components/Menu/index.jsx rename to Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTableMenu/index.jsx index f036b9d86..39a9d18cb 100644 --- a/Client/src/Pages/Infrastructure/components/Menu/index.jsx +++ b/Client/src/Pages/Infrastructure/Monitors/Components/MonitorsTableMenu/index.jsx @@ -4,12 +4,12 @@ import { useRef, useState } from "react"; import { useSelector } from "react-redux"; import { useTheme } from "@emotion/react"; import { useNavigate } from "react-router-dom"; -import { createToast } from "../../../../Utils/toastUtils"; +import { createToast } from "../../../../../Utils/toastUtils"; import { IconButton, Menu, MenuItem } from "@mui/material"; -import Settings from "../../../../assets/icons/settings-bold.svg?react"; +import Settings from "../../../../../assets/icons/settings-bold.svg?react"; import PropTypes from "prop-types"; -import Dialog from "../../../../Components/Dialog"; -import { networkService } from "../../../../Utils/NetworkService.js"; +import Dialog from "../../../../../Components/Dialog"; +import { networkService } from "../../../../../Utils/NetworkService.js"; /** * InfrastructureMenu Component diff --git a/Client/src/Pages/Infrastructure/Monitors/Hooks/useMonitorFetch.jsx b/Client/src/Pages/Infrastructure/Monitors/Hooks/useMonitorFetch.jsx new file mode 100644 index 000000000..8e316b728 --- /dev/null +++ b/Client/src/Pages/Infrastructure/Monitors/Hooks/useMonitorFetch.jsx @@ -0,0 +1,45 @@ +import { useState, useEffect } from "react"; +import { useSelector } from "react-redux"; +import { networkService } from "../../../../main"; +import { createToast } from "../../../../Utils/toastUtils"; + +const useMonitorFetch = ({ page, rowsPerPage, updateTrigger }) => { + // Redux state + const { authToken, user } = useSelector((state) => state.auth); + + // Local state + const [isLoading, setIsLoading] = useState(true); + const [networkError, setNetworkError] = useState(false); + const [monitors, setMonitors] = useState(undefined); + const [summary, setSummary] = useState(undefined); + + useEffect(() => { + const fetchMonitors = async () => { + try { + const response = await networkService.getMonitorsByTeamId({ + authToken, + teamId: user.teamId, + limit: 1, + types: ["hardware"], + page: page, + rowsPerPage: rowsPerPage, + }); + setMonitors(response?.data?.data?.filteredMonitors ?? []); + setSummary(response?.data?.data?.summary ?? {}); + } catch (error) { + setNetworkError(true); + createToast({ + body: error.message, + }); + } finally { + setIsLoading(false); + } + }; + + fetchMonitors(); + }, [page, rowsPerPage, authToken, user.teamId, updateTrigger]); + + return { monitors, summary, isLoading, networkError }; +}; + +export { useMonitorFetch }; diff --git a/Client/src/Pages/Infrastructure/Monitors/index.jsx b/Client/src/Pages/Infrastructure/Monitors/index.jsx new file mode 100644 index 000000000..6418dfd12 --- /dev/null +++ b/Client/src/Pages/Infrastructure/Monitors/index.jsx @@ -0,0 +1,110 @@ +// Components +import { Stack, Typography } 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"; +// Utils +import { useTheme } from "@emotion/react"; +import { useMonitorFetch } from "./Hooks/useMonitorFetch"; +import { useState } from "react"; +import { useIsAdmin } from "../../../Hooks/useIsAdmin"; +// Constants +const BREADCRUMBS = [{ name: `infrastructure`, path: "/infrastructure" }]; + +const InfrastructureMonitors = () => { + // Redux state + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(5); + const [updateTrigger, setUpdateTrigger] = useState(false); + + // Utils + const theme = useTheme(); + const isAdmin = useIsAdmin(); + + // Handlers + const handleActionMenuDelete = () => { + setUpdateTrigger(!updateTrigger); + }; + + const handleChangePage = (event, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(event.target.value); + }; + + const { monitors, summary, isLoading, networkError } = useMonitorFetch({ + page, + rowsPerPage, + updateTrigger, + }); + + if (networkError === true) { + return ( + + + Network error + + Please check your connection + + ); + } + + if (!isLoading && monitors?.length === 0) { + return ( + + ); + } + + console.log(isLoading); + return ( + + + + + + + + ); +}; + +export default InfrastructureMonitors; diff --git a/Client/src/Pages/Infrastructure/index.jsx b/Client/src/Pages/Infrastructure/index.jsx deleted file mode 100644 index 91367ce22..000000000 --- a/Client/src/Pages/Infrastructure/index.jsx +++ /dev/null @@ -1,295 +0,0 @@ -import { useEffect, useState, useCallback } from "react"; -import { useNavigate } from "react-router-dom"; -import { /* useDispatch, */ useSelector } from "react-redux"; -import { useTheme } from "@emotion/react"; -import useUtils from "../Uptime/Monitors/Hooks/useUtils.jsx"; -import { jwtDecode } from "jwt-decode"; -import SkeletonLayout from "./skeleton"; -import Fallback from "../../Components/Fallback"; -// import GearIcon from "../../Assets/icons/settings-bold.svg?react"; -import CPUChipIcon from "../../assets/icons/cpu-chip.svg?react"; -import DataTable from "../../Components/Table"; -import { Box, Button, IconButton, Stack } from "@mui/material"; -import Breadcrumbs from "../../Components/Breadcrumbs"; -import { StatusLabel } from "../../Components/Label"; -import { Heading } from "../../Components/Heading"; -import Pagination from "../../Components/Table/TablePagination/index.jsx"; -// import { getInfrastructureMonitorsByTeamId } from "../../Features/InfrastructureMonitors/infrastructureMonitorsSlice"; -import { networkService } from "../../Utils/NetworkService.js"; -import CustomGauge from "../../Components/Charts/CustomGauge/index.jsx"; -import Host from "../Uptime/Monitors/Components/Host/index.jsx"; -import { useIsAdmin } from "../../Hooks/useIsAdmin.js"; -import { InfrastructureMenu } from "./components/Menu"; - -const BREADCRUMBS = [{ name: `infrastructure`, path: "/infrastructure" }]; - -/** - * This is the Infrastructure monitoring page. This is a work in progress - * - * @param - Define params. - * @returns {JSX.Element} The infrastructure monitoring page. - */ - -function Infrastructure() { - /* Adding this custom hook so we can avoid using the HOC approach that can lower performance (we are calling the admin logic N times on initializing the project. using a custom hook will cal it ass needed ) */ - const isAdmin = useIsAdmin(); - const theme = useTheme(); - const [isLoading, setIsLoading] = useState(true); - - const navigate = useNavigate(); - const navigateToCreate = () => navigate("/infrastructure/create"); - - const [page, setPage] = useState(0); - /* TODO refactor this, so it is not aware of the MUI implementation. First argument only exists because of MUI. This should require onlu the new page. Adapting for MUI should happen inside of table pagination component */ - const handleChangePage = (_, newPage) => { - setPage(newPage); - }; - - const [rowsPerPage, setRowsPerPage] = useState(5); - const handleChangeRowsPerPage = (event) => { - setRowsPerPage(parseInt(event.target.value)); - setPage(0); - }; - const [monitors, setMonitors] = useState([]); - const [summary, setSummary] = useState({}); - - const { authToken } = useSelector((state) => state.auth); - const user = jwtDecode(authToken); - - const fetchMonitors = useCallback(async () => { - try { - setIsLoading(true); - const response = await networkService.getMonitorsByTeamId({ - authToken, - teamId: user.teamId, - limit: 1, - types: ["hardware"], - page: page, - rowsPerPage: rowsPerPage, - }); - setMonitors(response?.data?.data?.filteredMonitors ?? []); - setSummary(response?.data?.data?.summary ?? {}); - } catch (error) { - console.error(error); - } finally { - setIsLoading(false); - } - }, [page, rowsPerPage, authToken, user.teamId]); - - useEffect(() => { - fetchMonitors(); - }, [fetchMonitors]); - - const { determineState } = useUtils(); - // do it here - function openDetails(id) { - navigate(`/infrastructure/${id}`); - } - function handleActionMenuDelete() { - fetchMonitors(); - } - - const headers = [ - { - id: "host", - content: "Host", - render: (row) => ( - - ), - }, - { - id: "status", - content: "Status", - render: (row) => ( - - ), - }, - { - id: "frequency", - content: "Frequency", - render: (row) => ( - - - {row.processor} - - ), - }, - { id: "cpu", content: "CPU", render: (row) => }, - { id: "mem", content: "Mem", render: (row) => }, - { id: "disk", content: "Disk", render: (row) => }, - { - id: "actions", - content: "Actions", - render: (row) => ( - - ), - }, - ]; - - const monitorsAsRows = monitors.map((monitor) => { - const processor = - ((monitor.checks[0]?.cpu?.frequency ?? 0) / 1000).toFixed(2) + " GHz"; - const cpu = (monitor?.checks[0]?.cpu.usage_percent ?? 0) * 100; - const mem = (monitor?.checks[0]?.memory.usage_percent ?? 0) * 100; - const disk = (monitor?.checks[0]?.disk[0]?.usage_percent ?? 0) * 100; - const status = determineState(monitor); - const uptimePercentage = ((monitor?.uptimePercentage ?? 0) * 100) - .toFixed(2) - .toString(); - const percentageColor = - monitor.uptimePercentage < 0.25 - ? theme.palette.error.main - : monitor.uptimePercentage < 0.5 - ? theme.palette.warning.main - : theme.palette.success.main; - - return { - id: monitor._id, - name: monitor.name, - url: monitor.url, - processor, - cpu, - mem, - disk, - status, - uptimePercentage, - percentageColor, - }; - }); - - let isActuallyLoading = isLoading && monitors?.length === 0; - return ( - [class*="fallback__"])': { - position: "relative", - border: 1, - borderColor: theme.palette.primary.lowContrast, - borderRadius: theme.shape.borderRadius, - borderStyle: "dashed", - backgroundColor: theme.palette.primary.main, - overflow: "hidden", - }, - }} - > - {isActuallyLoading ? ( - - ) : monitors?.length !== 0 ? ( - - - - - {isAdmin && ( - - )} - - - - - Infrastructure monitors - {/* TODO Same as the one in UptimaDataTable. Create component */} - - {summary?.totalMonitors ?? 0} - - - - openDetails(row.id), - }} - headers={headers} - data={monitorsAsRows} - /> - - - - - ) : ( - - )} - - ); -} - -export { Infrastructure }; diff --git a/Client/src/Pages/PageSpeed/Monitors/index.jsx b/Client/src/Pages/PageSpeed/Monitors/index.jsx index 470a33f18..ea3ed93af 100644 --- a/Client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/Client/src/Pages/PageSpeed/Monitors/index.jsx @@ -1,7 +1,7 @@ // Components import Breadcrumbs from "../../../Components/Breadcrumbs"; import { Stack, Typography } from "@mui/material"; -import CreateMonitorHeader from "../../../Components/CreateMonitorHeader"; +import CreateMonitorHeader from "../../../Components/MonitorCreateHeader"; import MonitorCountHeader from "../../../Components/MonitorCountHeader"; import MonitorGrid from "./Components/MonitorGrid"; import Fallback from "../../../Components/Fallback"; diff --git a/Client/src/Pages/Uptime/Monitors/index.jsx b/Client/src/Pages/Uptime/Monitors/index.jsx index 31dcc93be..9f4b8c942 100644 --- a/Client/src/Pages/Uptime/Monitors/index.jsx +++ b/Client/src/Pages/Uptime/Monitors/index.jsx @@ -4,7 +4,7 @@ import Greeting from "../../../Utils/greeting"; import StatusBoxes from "./Components/StatusBoxes"; import UptimeDataTable from "./Components/UptimeDataTable"; import Pagination from "../../../Components/Table/TablePagination"; -import CreateMonitorHeader from "../../../Components/CreateMonitorHeader"; +import CreateMonitorHeader from "../../../Components/MonitorCreateHeader"; import Fallback from "../../../Components/Fallback"; import GenericFallback from "../../../Components/GenericFallback"; import SearchComponent from "./Components/SearchComponent"; @@ -107,7 +107,7 @@ const UptimeMonitors = () => { order: sort?.order, triggerUpdate: monitorUpdateTrigger, }); - const totalMonitors = monitorsSummary?.totalMonitors ?? 0; + const totalMonitors = monitorsSummary?.totalMonitors; if (networkError) { return ( @@ -135,6 +135,7 @@ const UptimeMonitors = () => { /> ); } + console.log({ isLoading }); return ( Date: Thu, 30 Jan 2025 14:31:36 -0800 Subject: [PATCH 6/7] replace default value of 0 for --- Client/src/Pages/Uptime/Monitors/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Uptime/Monitors/index.jsx b/Client/src/Pages/Uptime/Monitors/index.jsx index 9f4b8c942..962530d41 100644 --- a/Client/src/Pages/Uptime/Monitors/index.jsx +++ b/Client/src/Pages/Uptime/Monitors/index.jsx @@ -107,7 +107,7 @@ const UptimeMonitors = () => { order: sort?.order, triggerUpdate: monitorUpdateTrigger, }); - const totalMonitors = monitorsSummary?.totalMonitors; + const totalMonitors = monitorsSummary?.totalMonitors ?? 0; if (networkError) { return ( From 62f2888f2a9d35c83a4bd626ac0e5f11cb7f51f3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 31 Jan 2025 07:09:22 -0800 Subject: [PATCH 7/7] fix proptype --- Client/src/Components/MonitorCreateHeader/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Components/MonitorCreateHeader/index.jsx b/Client/src/Components/MonitorCreateHeader/index.jsx index 03dcc57e5..01a102b7d 100644 --- a/Client/src/Components/MonitorCreateHeader/index.jsx +++ b/Client/src/Components/MonitorCreateHeader/index.jsx @@ -28,6 +28,6 @@ export default CreateMonitorHeader; CreateMonitorHeader.propTypes = { isAdmin: PropTypes.bool.isRequired, - shouldRender: PropTypes.bool.isRequired, + shouldRender: PropTypes.bool, path: PropTypes.string.isRequired, };