Implemented basic gauge chart
This commit is contained in:
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>
|
||||
);
|
||||
};
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user