This commit is contained in:
Alex Holliday
2025-10-06 10:56:29 -07:00
parent f6b97c691e
commit 7c3a05077c
4 changed files with 90 additions and 21 deletions

View File

@@ -2,6 +2,7 @@ import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import { useTheme } from "@mui/material/styles";
import type { Check } from "@/Types/Check";
import { HistogramResponseTimeTooltip } from "@/Components/v2/Monitors/HistogramResponseTimeTooltip";
export const HistogramResponseTime = ({ checks }: { checks: Check[] }) => {
let data = Array<any>();
@@ -39,8 +40,11 @@ export const HistogramResponseTime = ({ checks }: { checks: Check[] }) => {
{data.map((check, index) => {
const safeResponse = Math.max(check.responseTime, 1);
const logValue = Math.log10(safeResponse);
const minHeight = 10;
const barHeight =
logMax === logMin ? 100 : ((logValue - logMin) / (logMax - logMin)) * 100;
logMax === logMin
? 100
: Math.max(minHeight, ((logValue - logMin) / (logMax - logMin)) * 100);
if (check === "placeholder") {
return (
@@ -57,32 +61,36 @@ export const HistogramResponseTime = ({ checks }: { checks: Check[] }) => {
);
} else {
return (
<Box
<HistogramResponseTimeTooltip
key={`${check}-${index}`}
position="relative"
width="9px"
height="100%"
bgcolor={theme.palette.primary.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
}}
check={check}
>
<Box
position="absolute"
bottom={0}
width="100%"
height={`${barHeight}%`}
bgcolor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
position="relative"
width="9px"
height="100%"
bgcolor={theme.palette.primary.lowContrast}
sx={{
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>
</Box>
>
<Box
position="absolute"
bottom={0}
width="100%"
height={`${barHeight}%`}
bgcolor={
check.status
? theme.palette.success.lowContrast
: theme.palette.error.lowContrast
}
sx={{
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>
</Box>
</HistogramResponseTimeTooltip>
);
}
})}

View File

@@ -0,0 +1,29 @@
import Stack from "@mui/material/Stack";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { useSelector } from "react-redux";
import type { LatestCheck } from "@/Types/Check";
export const HistogramResponseTimeTooltip: React.FC<{
children: React.ReactElement;
check: LatestCheck;
}> = ({ children, check }) => {
const uiTimezone = useSelector((state: any) => state.ui.timezone);
return (
<Tooltip
title={
<Stack>
<Typography>
{formatDateWithTz(check?.checkedAt, "ddd, MMMM D, YYYY, HH:mm A", uiTimezone)}
</Typography>
{check?.responseTime && (
<Typography>Response Time: {check.responseTime} ms</Typography>
)}
</Stack>
}
>
{children}
</Tooltip>
);
};

View File

@@ -10,3 +10,10 @@ export interface GroupedCheck {
avgResponseTime: number;
count: number;
}
export interface LatestCheck {
status: string;
responseTime: number;
checkedAt: string;
_id: string;
}

View File

@@ -0,0 +1,25 @@
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
import customParseFormat from "dayjs/plugin/customParseFormat";
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(customParseFormat);
dayjs.extend(duration);
export const MS_PER_SECOND = 1000;
export const MS_PER_MINUTE = 60 * MS_PER_SECOND;
export const MS_PER_HOUR = 60 * MS_PER_MINUTE;
export const MS_PER_DAY = 24 * MS_PER_HOUR;
export const MS_PER_WEEK = MS_PER_DAY * 7;
export const formatDateWithTz = (timestamp: string, format: string, timezone: string) => {
if (!timestamp) {
return "Unknown time";
}
const formattedDate = dayjs(timestamp).tz(timezone).format(format);
return formattedDate;
};