Files
Checkmate/client/src/components/common/HeatmapResponseTime.tsx
T

107 lines
3.4 KiB
TypeScript
Raw Normal View History

2025-11-25 19:03:48 +00:00
import Box from "@mui/material/Box";
2025-11-25 20:32:58 +00:00
// Using strip + square; icons removed
2025-11-25 19:03:48 +00:00
import { useTheme } from "@mui/material/styles";
import type { ICheck } from "@/types/check";
import { getResponseColor } from "@/utils/DataUtils";
2025-11-25 19:56:26 +00:00
import { HeatmapResponseTimeTooltip } from "./HeatmapResponseTimeTooltip";
import type { SxProps } from "@mui/material/styles";
2025-11-25 20:32:58 +00:00
import type { ResponsiveStyleValue } from "@mui/system";
2025-11-25 19:03:48 +00:00
interface HeatmapResponseTimeProps {
checks: ICheck[];
2025-11-25 20:32:58 +00:00
gap?: ResponsiveStyleValue<number | string>;
2025-11-25 19:56:26 +00:00
availabilityCellSx?: SxProps;
responseCellSx?: SxProps;
2025-11-25 19:03:48 +00:00
}
2025-11-25 19:56:26 +00:00
export const HeatmapResponseTime = ({
checks,
2025-11-25 20:32:58 +00:00
gap,
2025-11-25 19:56:26 +00:00
availabilityCellSx,
responseCellSx,
}: HeatmapResponseTimeProps) => {
2025-11-25 19:03:48 +00:00
const theme = useTheme();
2025-11-25 20:32:58 +00:00
if (!gap) {
gap = theme.spacing(0.5);
}
2025-11-25 19:03:48 +00:00
if (!checks || checks.length === 0) return null;
let data = Array<any>();
if (!checks || checks.length === 0) {
checks = [];
}
if (checks.length !== 25) {
const placeholders = Array(25 - checks.length).fill({
status: "placeholder",
});
data = [...checks, ...placeholders];
} else {
data = checks;
}
return (
<Box sx={{ width: "100%" }}>
<Box
sx={{
width: "100%",
display: "grid",
gridTemplateColumns: "repeat(25, 1fr)",
2025-11-25 20:32:58 +00:00
gap: gap,
2025-11-25 19:03:48 +00:00
alignItems: "stretch",
}}
>
{data.map((check, index) => {
const statusBg =
check.status === "placeholder"
2025-12-08 19:55:29 +00:00
? theme.palette.action.hover
2025-11-25 19:03:48 +00:00
: check.status === "up"
2025-12-08 19:55:29 +00:00
? theme.palette.success.light
: theme.palette.error.light;
2025-11-25 19:03:48 +00:00
const respBg =
check.status === "placeholder"
2025-12-08 19:55:29 +00:00
? theme.palette.action.hover
2025-11-25 19:03:48 +00:00
: getResponseColor(check.responseTime, {
2025-12-08 19:55:29 +00:00
start: theme.palette.success.main,
mid: theme.palette.warning.main,
end: theme.palette.error.main,
2025-11-25 19:03:48 +00:00
});
2025-11-25 23:58:30 +00:00
const statusBorder =
2025-12-08 19:55:29 +00:00
check.status === "placeholder" ? theme.palette.divider : check.status === "up" ? theme.palette.success.main : theme.palette.error.main;
2025-11-25 19:03:48 +00:00
return (
2025-11-25 19:56:26 +00:00
<HeatmapResponseTimeTooltip key={`${check}-${index}`} check={check}>
2025-11-25 19:03:48 +00:00
<Box
sx={{
display: "grid",
gridTemplateRows: "auto auto",
}}
>
<Box
sx={{
2025-11-25 19:56:26 +00:00
display: "flex",
flexDirection: "column",
gap: theme.spacing(2),
2025-11-25 19:03:48 +00:00
}}
2025-11-25 19:56:26 +00:00
>
2025-11-25 23:58:30 +00:00
<Box sx={{ position: "relative", width: "100%", aspectRatio: "10" }}>
<Box sx={{ position: "absolute", inset: 0, bgcolor: statusBg, borderRadius: theme.spacing(0.5), ...availabilityCellSx }} />
<Box sx={{ position: "absolute", inset: 0, pointerEvents: "none", borderRadius: theme.spacing(0.5), boxShadow: `inset 0 0 0 2px ${statusBorder}` }} />
</Box>
2025-11-25 19:56:26 +00:00
<Box
sx={{
width: "100%",
aspectRatio: "1 / 1",
bgcolor: respBg,
borderRadius: theme.spacing(0.5),
...responseCellSx,
}}
/>
</Box>
2025-11-25 19:03:48 +00:00
</Box>
2025-11-25 19:56:26 +00:00
</HeatmapResponseTimeTooltip>
2025-11-25 19:03:48 +00:00
);
})}
</Box>
</Box>
);
};