update details page to use new queries

This commit is contained in:
Alex Holliday committed 2025-03-19 12:15:04 -07:00
1 parent 9ac563bf8c
commit 3d71e7759b
11 files changed
+131 -81

No files matched your search

+4 -4
View File
@@ -8,10 +8,10 @@ import ConfigButton from "./ConfigButton";
import SkeletonLayout from "./skeleton";
import PropTypes from "prop-types";
const MonitorStatusHeader = ({ path, shouldRender = true, isAdmin, monitor }) => {
const MonitorStatusHeader = ({ path, isLoading = false, isAdmin, monitor }) => {
const theme = useTheme();
const { statusColor, statusMsg, determineState } = useUtils();
if (!shouldRender) {
const { statusColor, determineState } = useUtils();
if (isLoading) {
return <SkeletonLayout />;
}
@@ -48,7 +48,7 @@ const MonitorStatusHeader = ({ path, shouldRender = true, isAdmin, monitor }) =>
MonitorStatusHeader.propTypes = {
path: PropTypes.string.isRequired,
shouldRender: PropTypes.bool,
isLoading: PropTypes.bool,
isAdmin: PropTypes.bool,
monitor: PropTypes.object,
};
@@ -4,14 +4,14 @@ import SkeletonLayout from "./skeleton";
import PropTypes from "prop-types";
const MonitorTimeFrameHeader = ({
shouldRender = true,
isLoading = false,
hasDateRange = true,
dateRange,
setDateRange,
}) => {
const theme = useTheme();
if (!shouldRender) {
if (isLoading) {
return <SkeletonLayout />;
}
@@ -77,7 +77,7 @@ const MonitorTimeFrameHeader = ({
};
MonitorTimeFrameHeader.propTypes = {
shouldRender: PropTypes.bool,
isLoading: PropTypes.bool,
hasDateRange: PropTypes.bool,
dateRange: PropTypes.string,
setDateRange: PropTypes.func,
+36
View File
@@ -0,0 +1,36 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { useNavigate } from "react-router-dom";
import { createToast } from "../Utils/toastUtils";
export const useFetchUptimeMonitorDetails = ({ monitorId, dateRange }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
const [monitorStats, setMonitorStats] = useState(undefined);
const navigate = useNavigate();
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getUptimeDetailsById({
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
const { monitorData, monitorStats } = res?.data?.data ?? {};
setMonitor(monitorData);
setMonitorStats(monitorStats);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [dateRange, monitorId, navigate]);
return [monitor, monitorStats, isLoading, networkError];
};
export default useFetchUptimeMonitorDetails;
@@ -27,7 +27,7 @@ const StatusPagesTable = ({ data }) => {
row.type === "distributed"
? `/status/distributed/public/${row.url}`
: `/status/uptime/public/${row.url}`;
window.open(url, "_blank", "noopener,noreferrer")
window.open(url, "_blank", "noopener,noreferrer");
}
},
render: (row) => {
@@ -12,29 +12,23 @@ import SkeletonLayout from "./skeleton";
import { formatDateWithTz } from "../../../../../Utils/timeUtils";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { useState } from "react";
const ChartBoxes = ({
shouldRender = true,
monitor,
isLoading = false,
monitorData,
dateRange,
uiTimezone,
dateFormat,
hoveredUptimeData,
setHoveredUptimeData,
hoveredIncidentsData,
setHoveredIncidentsData,
}) => {
// Local state
const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
const theme = useTheme();
if (!shouldRender) {
if (isLoading) {
return <SkeletonLayout />;
}
const totalUpChecks = monitor?.upChecks?.totalChecks ?? 0;
const totalDownChecks = monitor?.downChecks?.totalChecks ?? 0;
const denominator =
totalUpChecks + totalDownChecks > 0 ? totalUpChecks + totalDownChecks : 1;
const groupedUptimePercentage = (totalUpChecks / denominator) * 100;
const noIncidentsMessage = "Great. No Incidents, yet!";
return (
@@ -46,7 +40,7 @@ const ChartBoxes = ({
<ChartBox
icon={<UptimeIcon />}
header="Uptime"
isEmpty={monitor?.uptimePercentage === 0 && !monitor?.upChecks?.length}
isEmpty={false} // TODO
>
<Stack
width={"100%"}
@@ -58,7 +52,7 @@ const ChartBoxes = ({
<Typography component="span">
{hoveredUptimeData !== null
? hoveredUptimeData.totalChecks
: (monitor?.groupedUpChecks?.reduce((count, checkGroup) => {
: (monitorData?.groupedUpChecks?.reduce((count, checkGroup) => {
return count + checkGroup.totalChecks;
}, 0) ?? 0)}
</Typography>
@@ -81,7 +75,7 @@ const ChartBoxes = ({
<Typography component="span">
{hoveredUptimeData !== null
? Math.floor(hoveredUptimeData?.avgResponseTime ?? 0)
: Math.floor(groupedUptimePercentage)}
: Math.floor(monitorData?.groupedUptimePercentage * 100 ?? 0)}
<Typography component="span">
{hoveredUptimeData !== null ? " ms" : " %"}
</Typography>
@@ -89,7 +83,7 @@ const ChartBoxes = ({
</Box>
</Stack>
<UpBarChart
monitor={monitor}
groupedUpChecks={monitorData?.groupedUpChecks}
type={dateRange}
onBarHover={setHoveredUptimeData}
/>
@@ -98,14 +92,14 @@ const ChartBoxes = ({
icon={<IncidentsIcon />}
header="Incidents"
noDataMessage={noIncidentsMessage}
isEmpty={monitor?.groupedDownChecks?.length === 0}
isEmpty={monitorData?.groupedDownChecks?.length === 0}
>
<Stack width={"100%"}>
<Box position="relative">
<Typography component="span">
{hoveredIncidentsData !== null
? hoveredIncidentsData.totalChecks
: (monitor?.groupedDownChecks?.reduce((count, checkGroup) => {
: (monitorData?.groupedDownChecks?.reduce((count, checkGroup) => {
return count + checkGroup.totalChecks;
}, 0) ?? 0)}
</Typography>
@@ -123,7 +117,7 @@ const ChartBoxes = ({
</Box>
</Stack>
<DownBarChart
monitor={monitor}
groupedDownChecks={monitorData?.groupedDownChecks}
type={dateRange}
onBarHover={setHoveredIncidentsData}
/>
@@ -132,7 +126,7 @@ const ChartBoxes = ({
icon={<AverageResponseIcon />}
header="Average Response Time"
>
<ResponseGaugeChart avgResponseTime={monitor?.avgResponseTime ?? 0} />
<ResponseGaugeChart avgResponseTime={monitorData?.groupedAvgResponseTime ?? 0} />
</ChartBox>
</Stack>
);
@@ -141,8 +135,8 @@ const ChartBoxes = ({
export default ChartBoxes;
ChartBoxes.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object,
isLoading: PropTypes.bool,
monitorData: PropTypes.object,
dateRange: PropTypes.string.isRequired,
uiTimezone: PropTypes.string.isRequired,
dateFormat: PropTypes.string.isRequired,
@@ -4,7 +4,7 @@ import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
import PropTypes from "prop-types";
import CustomLabels from "./CustomLabels";
const DownBarChart = memo(({ monitor, type, onBarHover }) => {
const DownBarChart = memo(({ groupedDownChecks = [], type, onBarHover }) => {
const theme = useTheme();
const [chartHovered, setChartHovered] = useState(false);
@@ -19,7 +19,7 @@ const DownBarChart = memo(({ monitor, type, onBarHover }) => {
<BarChart
width="100%"
height="100%"
data={monitor?.groupedDownChecks}
data={groupedDownChecks}
onMouseEnter={() => {
setChartHovered(true);
onBarHover({ time: null, totalChecks: 0 });
@@ -40,10 +40,8 @@ const DownBarChart = memo(({ monitor, type, onBarHover }) => {
y={0}
width="100%"
height="100%"
firstDataPoint={monitor?.groupedDownChecks?.[0] ?? {}}
lastDataPoint={
monitor?.groupedDownChecks?.[monitor?.groupedDownChecks?.length - 1] ?? {}
}
firstDataPoint={groupedDownChecks?.[0] ?? {}}
lastDataPoint={groupedDownChecks?.[groupedDownChecks?.length - 1] ?? {}}
type={type}
/>
}
@@ -53,7 +51,7 @@ const DownBarChart = memo(({ monitor, type, onBarHover }) => {
maxBarSize={7}
background={{ fill: "transparent" }}
>
{monitor?.groupedDownChecks?.map((entry, index) => {
{groupedDownChecks?.map((entry, index) => {
return (
<Cell
key={`cell-${entry.time}`}
@@ -4,8 +4,8 @@ import ResponseTimeIcon from "../../../../../assets/icons/response-time-icon.svg
import SkeletonLayout from "./ResponseTimeChartSkeleton";
import PropTypes from "prop-types";
const ResponseTImeChart = ({ shouldRender = true, monitor, dateRange }) => {
if (!shouldRender) {
const ResponseTImeChart = ({ isLoading = false, groupedChecks = [], dateRange }) => {
if (isLoading) {
return <SkeletonLayout />;
}
@@ -15,7 +15,7 @@ const ResponseTImeChart = ({ shouldRender = true, monitor, dateRange }) => {
header="Response Times"
>
<MonitorDetailsAreaChart
checks={monitor?.groupedChecks ?? []}
checks={groupedChecks}
dateRange={dateRange}
/>
</ChartBox>
@@ -23,8 +23,8 @@ const ResponseTImeChart = ({ shouldRender = true, monitor, dateRange }) => {
};
ResponseTImeChart.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object,
isLoading: PropTypes.bool,
groupedChecks: PropTypes.array,
dateRange: PropTypes.string,
};
@@ -14,7 +14,7 @@ const getThemeColor = (responseTime) => {
}
};
const UpBarChart = memo(({ monitor, type, onBarHover }) => {
const UpBarChart = memo(({ groupedUpChecks = [], type, onBarHover }) => {
const theme = useTheme();
const [chartHovered, setChartHovered] = useState(false);
const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
@@ -28,7 +28,7 @@ const UpBarChart = memo(({ monitor, type, onBarHover }) => {
<BarChart
width="100%"
height="100%"
data={monitor?.groupedUpChecks}
data={groupedUpChecks}
onMouseEnter={() => {
setChartHovered(true);
onBarHover({ time: null, totalChecks: 0, avgResponseTime: 0 });
@@ -49,10 +49,8 @@ const UpBarChart = memo(({ monitor, type, onBarHover }) => {
y={0}
width="100%"
height="100%"
firstDataPoint={monitor?.groupedUpChecks?.[0]}
lastDataPoint={
monitor?.groupedUpChecks?.[monitor?.groupedUpChecks?.length - 1]
}
firstDataPoint={groupedUpChecks?.[0]}
lastDataPoint={groupedUpChecks?.[groupedUpChecks?.length - 1]}
type={type}
/>
}
@@ -62,7 +60,7 @@ const UpBarChart = memo(({ monitor, type, onBarHover }) => {
maxBarSize={7}
background={{ fill: "transparent" }}
>
{monitor?.groupedUpChecks?.map((entry, index) => {
{groupedUpChecks?.map((entry, index) => {
const themeColor = getThemeColor(entry.avgResponseTime);
return (
<Cell
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
import { formatDateWithTz } from "../../../../../Utils/timeUtils";
import SkeletonLayout from "./skeleton";
const ResponseTable = ({
shouldRender = true,
isLoading = false,
checks = [],
checksCount,
uiTimezone,
@@ -17,8 +17,12 @@ const ResponseTable = ({
rowsPerPage,
setRowsPerPage,
}) => {
<<<<<<< Updated upstream
const { t } = useTranslation();
if (!shouldRender) {
=======
if (isLoading) {
>>>>>>> Stashed changes
return <SkeletonLayout />;
}
@@ -78,7 +82,7 @@ const ResponseTable = ({
};
ResponseTable.propTypes = {
shouldRender: PropTypes.bool,
isLoading: PropTypes.bool,
checks: PropTypes.array,
checksCount: PropTypes.number,
uiTimezone: PropTypes.string.isRequired,
@@ -1,23 +1,36 @@
import StatusBoxes from "../../../../../Components/StatusBoxes";
import StatBox from "../../../../../Components/StatBox";
import PropTypes from "prop-types";
import { getHumanReadableDuration } from "../../../../../Utils/timeUtils";
import { useTheme } from "@mui/material/styles";
import { Typography } from "@mui/material";
import useUtils from "../../../Monitors/Hooks/useUtils";
const UptimeStatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
const UptimeStatusBoxes = ({
isLoading = false,
monitor,
monitorStats,
certificateExpiry,
}) => {
const theme = useTheme();
const { determineState } = useUtils();
const { time: streakTime, units: streakUnits } = getHumanReadableDuration(
monitor?.uptimeStreak
);
// Determine time since last failure
const timeOfLastFailure = monitorStats?.timeOfLastFailure;
const timeSinceLastFailure = timeOfLastFailure > 0 ? Date.now() - timeOfLastFailure : 0;
const { time: lastCheckTime, units: lastCheckUnits } = getHumanReadableDuration(
monitor?.timeSinceLastCheck
);
// Determine time since last check
const timeOfLastCheck = monitorStats?.lastCheckTimestamp;
const timeSinceLastCheck = Date.now() - timeOfLastCheck;
const { time: streakTime, units: streakUnits } =
getHumanReadableDuration(timeSinceLastFailure);
const { time: lastCheckTime, units: lastCheckUnits } =
getHumanReadableDuration(timeSinceLastCheck);
return (
<StatusBoxes shouldRender={shouldRender}>
<StatusBoxes shouldRender={!isLoading}>
<StatBox
gradient={true}
status={determineState(monitor)}
@@ -43,7 +56,7 @@ const UptimeStatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
heading="last response time"
subHeading={
<>
{monitor?.latestResponseTime}
{monitorStats?.lastResponseTime}
<Typography component="span">{"ms"}</Typography>
</>
}
@@ -64,4 +77,11 @@ const UptimeStatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
);
};
UptimeStatusBoxes.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object,
monitorStats: PropTypes.object,
certificateExpiry: PropTypes.string,
};
export default UptimeStatusBoxes;
+20 -20
View File
@@ -16,7 +16,7 @@ import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import useMonitorFetch from "./Hooks/useMonitorFetch";
import useFetchUptimeMonitorDetails from "../../../Hooks/useFetchUptimeMonitorDetails";
import useCertificateFetch from "./Hooks/useCertificateFetch";
import useChecksFetch from "./Hooks/useChecksFetch";
import { useTranslation } from "react-i18next";
@@ -36,8 +36,7 @@ const UptimeDetails = () => {
// Local state
const [dateRange, setDateRange] = useState("recent");
const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
@@ -49,10 +48,13 @@ const UptimeDetails = () => {
const isAdmin = useIsAdmin();
const { t } = useTranslation();
const [monitor, monitorIsLoading, monitorNetworkError] = useMonitorFetch({
monitorId,
dateRange,
});
const [monitorData, monitorStats, monitorIsLoading, monitorNetworkError] =
useFetchUptimeMonitorDetails({
monitorId,
dateRange,
});
const monitor = monitorData?.monitor;
const [certificateExpiry, certificateIsLoading] = useCertificateFetch({
monitor,
@@ -62,7 +64,6 @@ const UptimeDetails = () => {
});
const monitorType = monitor?.type;
const [checks, checksCount, checksAreLoading, checksNetworkError] = useChecksFetch({
monitorId,
monitorType,
@@ -71,6 +72,8 @@ const UptimeDetails = () => {
rowsPerPage,
});
console.log("render");
// Handlers
const handlePageChange = (_, newPage) => {
setPage(newPage);
@@ -119,38 +122,35 @@ const UptimeDetails = () => {
<MonitorStatusHeader
path={"uptime"}
isAdmin={isAdmin}
shouldRender={!monitorIsLoading}
isLoading={monitorIsLoading}
monitor={monitor}
/>
<UptimeStatusBoxes
shouldRender={!monitorIsLoading}
isLoading={monitorIsLoading}
monitor={monitor}
monitorStats={monitorStats}
certificateExpiry={certificateExpiry}
/>
<MonitorTimeFrameHeader
shouldRender={!monitorIsLoading}
isLoading={monitorIsLoading}
hasDateRange={true}
dateRange={dateRange}
setDateRange={setDateRange}
/>
<ChartBoxes
shouldRender={!monitorIsLoading}
monitor={monitor}
isLoading={monitorIsLoading}
monitorData={monitorData}
uiTimezone={uiTimezone}
dateRange={dateRange}
dateFormat={dateFormat}
hoveredUptimeData={hoveredUptimeData}
setHoveredUptimeData={setHoveredUptimeData}
hoveredIncidentsData={hoveredIncidentsData}
setHoveredIncidentsData={setHoveredIncidentsData}
/>
<ResponseTimeChart
shouldRender={!monitorIsLoading}
monitor={monitor}
isLoading={monitorIsLoading}
groupedChecks={monitorData?.groupedChecks}
dateRange={dateRange}
/>
<ResponseTable
shouldRender={!checksAreLoading}
isLoading={checksAreLoading}
checks={checks}
uiTimezone={uiTimezone}
page={page}