2025-11-25 19:03:48 +00:00
|
|
|
import Box from "@mui/material/Box";
|
|
|
|
|
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 21:10: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-12-08 21:10:29 +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}`,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2025-11-25 23:58:30 +00:00
|
|
|
</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>
|
|
|
|
|
);
|
|
|
|
|
};
|