Skip to content

Commit b200157

Browse files
committed
chart
1 parent 6323f70 commit b200157

File tree

6 files changed

+214
-222
lines changed

6 files changed

+214
-222
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import Stack from "@mui/material/Stack";
2+
import Grid from "@mui/material/Grid";
3+
import Box from "@mui/material/Box";
4+
import Typography from "@mui/material/Typography";
5+
import { StatusLabel, ValueLabel } from "@/components/design-elements";
6+
import { BaseBox } from "@/components/design-elements";
7+
8+
import { useAppSelector } from "@/hooks/AppHooks";
9+
import type { ICheck } from "@/types/check";
10+
import type { MonitorStatus } from "@/types/monitor";
11+
import { formatDateWithTz } from "@/utils/TimeUtils";
12+
13+
type CheckDetailsCardProps = {
14+
check: ICheck;
15+
};
16+
17+
export const CheckDetailsCard = ({ check }: CheckDetailsCardProps) => {
18+
const uiTimezone = useAppSelector((state: any) => state.ui.timezone);
19+
const phases = check?.timings?.phases;
20+
const phaseKeys = [
21+
"wait",
22+
"dns",
23+
"tcp",
24+
"tls",
25+
"request",
26+
"firstByte",
27+
"download",
28+
] as const;
29+
const totalMs = phases
30+
? phaseKeys.reduce(
31+
(sum, key) => sum + Math.max(0, Number((phases as any)[key] ?? 0)),
32+
0
33+
)
34+
: Number(check.responseTime ?? 0);
35+
36+
return (
37+
<BaseBox p={4} flex={1} height={"100%"}>
38+
<Stack spacing={2} sx={{ width: "100%" }}>
39+
<Typography>Check details</Typography>
40+
<Typography variant="body2">
41+
{`Total request time: ${check.timings.phases.total} ms`}
42+
</Typography>
43+
44+
<Grid container spacing={2}>
45+
<Grid size={6} sx={{ display: "flex", alignItems: "center" }}>
46+
<Typography variant="body1" color="text.secondary">
47+
Status
48+
</Typography>
49+
</Grid>
50+
51+
<Grid size={6} sx={{ display: "flex", alignItems: "center" }}>
52+
<Box>
53+
<StatusLabel status={check.status as MonitorStatus} />
54+
</Box>
55+
</Grid>
56+
57+
<Grid size={6} sx={{ display: "flex", alignItems: "center" }}>
58+
<Typography variant="body1" color="text.secondary">
59+
HTTP Code
60+
</Typography>
61+
</Grid>
62+
<Grid size={6} sx={{ display: "flex", alignItems: "center" }}>
63+
<Box>
64+
<ValueLabel
65+
value={
66+
check.httpStatusCode < 300
67+
? "positive"
68+
: check.httpStatusCode < 400
69+
? "neutral"
70+
: "negative"
71+
}
72+
text={String(check.httpStatusCode ?? "-")}
73+
/>
74+
</Box>
75+
</Grid>
76+
<Grid size={6}>
77+
<Typography variant="body1" color="text.secondary">
78+
Type
79+
</Typography>
80+
</Grid>
81+
<Grid size={6}>
82+
<Typography variant="body2">
83+
{check.metadata?.type || "-"}
84+
</Typography>
85+
</Grid>
86+
87+
<Grid size={6}>
88+
<Typography variant="body2">{Math.round(totalMs)} ms</Typography>
89+
</Grid>
90+
<Grid size={6}>
91+
<Typography variant="body1" color="text.secondary">
92+
Checked At
93+
</Typography>
94+
</Grid>
95+
<Grid size={6}>
96+
<Typography variant="body2">
97+
{formatDateWithTz(
98+
check.createdAt,
99+
"ddd, MMM D, YYYY, HH:mm A",
100+
uiTimezone
101+
)}
102+
</Typography>
103+
</Grid>
104+
<Grid size={6}>
105+
<Typography variant="body1" color="text.secondary">
106+
Message
107+
</Typography>
108+
</Grid>
109+
<Grid size={6}>
110+
<Typography variant="body2">{check.message || "-"}</Typography>
111+
</Grid>
112+
</Grid>
113+
</Stack>
114+
</BaseBox>
115+
);
116+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import type { ICheck, CheckTimingPhases } from "@/types/check";
2+
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from "recharts";
3+
import Stack from "@mui/material/Stack";
4+
import Typography from "@mui/material/Typography";
5+
import { alpha, useTheme } from "@mui/material/styles";
6+
import { BaseBox } from "@/components/design-elements";
7+
8+
type TimingsChartProps = { check: ICheck | null };
9+
10+
export type TimingSegment = {
11+
key: keyof CheckTimingPhases;
12+
label: string;
13+
value: number;
14+
percent: number;
15+
};
16+
17+
const PHASE_ORDER: (keyof CheckTimingPhases)[] = [
18+
"wait",
19+
"dns",
20+
"tcp",
21+
"tls",
22+
"request",
23+
"firstByte",
24+
"download",
25+
];
26+
27+
const buildTimingSegments = (phases?: CheckTimingPhases): TimingSegment[] => {
28+
if (!phases) return [];
29+
const raw = PHASE_ORDER.map((key) => ({
30+
key,
31+
value: Math.max(0, Number((phases as any)[key] ?? 0)),
32+
}));
33+
const total = raw.reduce((sum, p) => sum + p.value, 0);
34+
if (total <= 0) {
35+
return raw.map(({ key, value }) => ({
36+
key,
37+
label: key,
38+
value,
39+
percent: 0,
40+
}));
41+
}
42+
return raw.map(({ key, value }) => ({
43+
key,
44+
label: key,
45+
value,
46+
percent: (value / total) * 100,
47+
}));
48+
};
49+
50+
export const TimingsChart = ({ check }: TimingsChartProps) => {
51+
const segments = buildTimingSegments(check?.timings?.phases);
52+
if (!segments.length) return null;
53+
if (!check) return null;
54+
55+
const theme = useTheme();
56+
const strokeColor = alpha(theme.palette.success.main, 0.8);
57+
58+
return (
59+
<BaseBox p={4} flex={1} height={"100%"}>
60+
<Stack spacing={2} sx={{ width: "100%", height: 260 }}>
61+
<Typography>Request timings</Typography>
62+
<Typography variant="body2">
63+
{`Total request time: ${check.timings.phases.total} ms`}
64+
</Typography>
65+
<ResponsiveContainer width="100%" height="100%">
66+
<PieChart>
67+
<Pie
68+
data={segments}
69+
dataKey="value"
70+
nameKey="label"
71+
fill="transparent"
72+
stroke={strokeColor}
73+
strokeWidth={1}
74+
label={({ name, value }: any) => `${name}: ${Math.round(Number(value) || 0)} ms`}
75+
>
76+
{segments.map((entry) => (
77+
<Cell key={`cell-${entry.key}`} fill="transparent" />
78+
))}
79+
</Pie>
80+
<Tooltip
81+
formatter={(value: any) => `${Math.round(value as number)} ms`}
82+
/>
83+
</PieChart>
84+
</ResponsiveContainer>
85+
</Stack>
86+
</BaseBox>
87+
);
88+
};

client/src/components/checks/CheckDetailsCard.tsx

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)