Implemented basic gauge chart

This commit is contained in:
Daniel Cojocea committed 2024-09-04 19:17:12 -04:00
1 parent 38fddf5b9b
commit 2a1afc8610
5 files changed
+109 -63

No files matched your search

@@ -1,53 +0,0 @@
import { BarChart, Bar, Cell, ReferenceLine, Label } from "recharts";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
const MonitorDetails60MinChart = ({ data }) => {
const theme = useTheme();
const labelStyle = {
fontSize: "10px",
fill: theme.palette.text.tertiary,
};
const color = {
true: theme.palette.success.main,
false: theme.palette.error.text,
undefined: theme.palette.unresolved.main,
};
return (
<BarChart
width={data.length * 10 + 30}
height={35}
data={data}
margin={{ top: 14, left: 15, right: 15, bottom: 2 }}
style={{ alignSelf: "baseline" }}
>
<Bar dataKey="value" barSize={10}>
{data.map((check, index) => (
<Cell key={`cell-${index}`} fill={color[check.status]} />
))}
</Bar>
<ReferenceLine x={0} stroke="black" strokeDasharray="3 3">
<Label value="60 mins" position="top" style={labelStyle} />
</ReferenceLine>
<ReferenceLine
x={Math.floor(data.length * (2 / 3))}
stroke="black"
strokeDasharray="3 3"
>
<Label value="20 mins" position="top" style={labelStyle} />
</ReferenceLine>
<ReferenceLine x={data.length - 1} stroke="black" strokeDasharray="3 3">
<Label value="now" position="top" style={labelStyle} />
</ReferenceLine>
</BarChart>
);
};
MonitorDetails60MinChart.propTypes = {
data: PropTypes.array.isRequired,
};
export default MonitorDetails60MinChart;
@@ -6,6 +6,8 @@ import {
CartesianGrid,
ResponsiveContainer,
Cell,
RadialBarChart,
RadialBar,
} from "recharts";
import { formatDate } from "../../../../Utils/timeUtils";
import { useState } from "react";
@@ -28,10 +30,10 @@ const CustomLabels = ({
return (
<>
<text x={x} y={height} dy={-3} textAnchor="start">
<text x={x} y={height} dy={-3} textAnchor="start" fontSize={11}>
{formatDate(new Date(firstDataPoint.time), options)}
</text>
<text x={width} y={height} dy={-3} textAnchor="end">
<text x={width} y={height} dy={-3} textAnchor="end" fontSize={11}>
{formatDate(new Date(lastDataPoint.time), options)}
</text>
</>
@@ -186,3 +188,87 @@ export const DownBarChart = ({ data, type, onBarHover }) => {
</ResponsiveContainer>
);
};
export const ResponseGaugeChart = ({ data }) => {
const theme = useTheme();
let max = 1000; // max ms
data = [{ response: max, fill: "transparent", background: false }, ...data];
let responseTime = Math.floor(data[1].response);
let responseProps =
responseTime <= 200
? {
category: "Excellent",
main: theme.palette.success.main,
bg: theme.palette.success.bg,
}
: responseTime <= 500
? {
category: "Fair",
main: theme.palette.success.main,
bg: theme.palette.success.bg,
}
: responseTime <= 600
? {
category: "Acceptable",
main: theme.palette.warning.main,
bg: theme.palette.warning.bg,
}
: {
category: "Poor",
main: theme.palette.error.text,
bg: theme.palette.error.bg,
};
return (
<ResponsiveContainer width="100%" height={155}>
<RadialBarChart
width="100%"
height="100%"
cy="89%"
data={data}
startAngle={180}
endAngle={0}
innerRadius={100}
outerRadius={150}
>
<text x={0} y="100%" dx="5%" dy={-2} textAnchor="start" fontSize={11}>
low
</text>
<text x="100%" y="100%" dx="-3%" dy={-2} textAnchor="end" fontSize={11}>
high
</text>
<text
x="50%"
y="45%"
textAnchor="middle"
dominantBaseline="middle"
fontSize={18}
fontWeight={400}
>
{responseProps.category}
</text>
<text
x="50%"
y="55%"
textAnchor="middle"
dominantBaseline="hanging"
fontSize={25}
>
<tspan fontWeight={600}>{responseTime}</tspan>{" "}
<tspan opacity={0.8}>ms</tspan>
</text>
<RadialBar
background={{ fill: responseProps.bg }}
clockWise
dataKey="response"
stroke="none"
>
<Cell fill="transparent" background={false} barSize={0} />
<Cell fill={responseProps.main} />
</RadialBar>
</RadialBarChart>
</ResponsiveContainer>
);
};
+5 -4
View File
@@ -32,7 +32,7 @@ import PaginationTable from "./PaginationTable";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import PulseDot from "../../../Components/Animated/PulseDot";
import { StatBox, ChartBox, IconBox } from "./styled";
import { DownBarChart, UpBarChart } from "./Charts";
import { DownBarChart, ResponseGaugeChart, UpBarChart } from "./Charts";
import SkeletonLayout from "./skeleton";
import "./index.css";
@@ -133,8 +133,6 @@ const DetailsPage = ({ isAdmin }) => {
undefined: "Pending...",
};
console.log(monitor);
return (
<Box className="monitor-details">
{loading ? (
@@ -463,7 +461,7 @@ const DetailsPage = ({ isAdmin }) => {
onBarHover={setHoveredIncidentsData}
/>
</ChartBox>
<ChartBox>
<ChartBox justifyContent="space-between">
<Stack>
<IconBox>
<AverageResponseIcon />
@@ -472,6 +470,9 @@ const DetailsPage = ({ isAdmin }) => {
Average Response Time
</Typography>
</Stack>
<ResponseGaugeChart
data={[{ response: monitor?.periodAvgResponseTime }]}
/>
</ChartBox>
<ChartBox>
<Stack>
@@ -37,7 +37,6 @@ export const ChartBox = styled(Stack)(({ theme }) => ({
alignItems: "center",
},
"& tspan, & text": {
fontSize: 11,
fill: theme.palette.text.tertiary,
},
"& path": {
+16 -3
View File
@@ -182,8 +182,9 @@ const getMonitorStatsById = async (req) => {
if (monitor.type === "http" || monitor.type === "ping") {
// HTTP/PING Specific stats
monitorStats.avgResponseTime = getAverageResponseTime(checksForDateRange);
monitorStats.uptime = getUptimePercentage(checksForDateRange);
monitorStats.periodAvgResponseTime =
getAverageResponseTime(checksForDateRange);
monitorStats.periodUptime = getUptimePercentage(checksForDateRange);
// Aggregate data
let groupedChecks;
@@ -198,11 +199,21 @@ const getMonitorStatsById = async (req) => {
acc[time].checks.push(check);
return acc;
}, {});
} else {
groupedChecks = checksForDateRange.reduce((acc, check) => {
const time = new Date(check.createdAt).toISOString().split("T")[0]; // Extract the date part
if (!acc[time]) {
acc[time] = { time, checks: [] };
}
acc[time].checks.push(check);
return acc;
}, {});
}
// Map grouped checks to stats
const aggregateData = Object.values(groupedChecks).map((group) => {
const totalChecks = group.checks.length;
const uptimePercentage = getUptimePercentage(group.checks);
const totalIncidents = group.checks.filter(
(check) => check.status === false
).length;
@@ -212,6 +223,7 @@ const getMonitorStatsById = async (req) => {
return {
time: group.time,
uptimePercentage,
totalChecks,
totalIncidents,
avgResponseTime,
@@ -220,7 +232,8 @@ const getMonitorStatsById = async (req) => {
monitorStats.aggregateData = aggregateData;
}
monitorStats.incidents = getIncidents(checksForDateRange);
monitorStats.periodIncidents = getIncidents(checksForDateRange);
monitorStats.periodTotalChecks = checksForDateRange.length;
// If more than numToDisplay checks, pick every nth check