Implemented basic charts

This commit is contained in:
Daniel Cojocea
2024-09-03 20:00:48 -04:00
parent cd53f44928
commit 0be386513f
4 changed files with 183 additions and 5 deletions
@@ -0,0 +1,92 @@
import { useTheme } from "@emotion/react";
import {
BarChart,
Bar,
XAxis,
CartesianGrid,
ResponsiveContainer,
} from "recharts";
import { formatDate } from "../../../../Utils/timeUtils";
const CustomLabels = ({ x, width, height, firstDataPoint, lastDataPoint }) => {
let options = {
month: "short",
year: undefined,
hour: undefined,
minute: undefined,
};
return (
<>
<text x={x} y={height} dy={-5} textAnchor="start" fill="#666">
{formatDate(new Date(firstDataPoint.day), options)}
</text>
<text x={width} y={height} dy={-5} textAnchor="end" fill="#666">
{formatDate(new Date(lastDataPoint.day), options)}
</text>
</>
);
};
export const UpBarChart = ({ data, dateRange }) => {
const theme = useTheme();
return (
<ResponsiveContainer width="100%" height={160}>
<BarChart width="100%" height="100%" data={data}>
<XAxis
stroke={theme.palette.border.dark}
height={15}
tick={false}
label={
<CustomLabels
x={0}
y={0}
width="100%"
height="100%"
firstDataPoint={data[0]}
lastDataPoint={data[data.length - 1]}
dateRange={dateRange}
/>
}
/>
<Bar
dataKey="totalChecks"
fill={theme.palette.success.main}
barSize={5}
/>
</BarChart>
</ResponsiveContainer>
);
};
export const DownBarChart = ({ data }) => {
const theme = useTheme();
return (
<ResponsiveContainer width="100%" height={160}>
<BarChart width="100%" height="100%" data={data}>
<XAxis
stroke={theme.palette.border.dark}
height={15}
tick={false}
label={
<CustomLabels
x={0}
y={0}
width="100%"
height="100%"
firstDataPoint={data[0]}
lastDataPoint={data[data.length - 1]}
/>
}
/>
<Bar
dataKey="totalIncidents"
fill={theme.palette.error.text}
barSize={5}
/>
</BarChart>
</ResponsiveContainer>
);
};
+62 -5
View File
@@ -33,6 +33,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 "./index.css";
/**
@@ -186,6 +187,55 @@ const DetailsPage = ({ isAdmin }) => {
};
let loading = Object.keys(monitor).length === 0;
const [aggregateStats, setAggregateStats] = useState({});
useEffect(() => {
const fetchAggregateStats = async () => {
try {
const res = await networkService.getAggregateStatsById(
authToken,
monitorId,
dateRange
);
setAggregateStats(res?.data?.data);
} catch (error) {
console.error(error);
}
};
fetchAggregateStats();
}, [monitorId, dateRange]);
const calculateStats = () => {
let totalChecks = 0;
let totalIncidents = 0;
let totalResponseTime = 0;
let count = 0;
Object.keys(aggregateStats).forEach((entry) => {
totalChecks += aggregateStats[entry].totalChecks;
totalIncidents += aggregateStats[entry].totalIncidents;
totalResponseTime += aggregateStats[entry].totalIncidents;
count++;
});
let uptime =
dateRange === "day"
? monitor.uptime24Hours
: dateRange === "week"
? monitor.uptime7Days
: dateRange === "month" && monitor.uptime30Days;
return {
totalChecks: totalChecks,
totalIncidents: totalIncidents,
averageResponseTime: totalResponseTime / count,
uptime: uptime,
};
};
const monitorStats = calculateStats();
console.log(aggregateStats);
return (
<Box className="monitor-details">
{loading ? (
@@ -431,18 +481,22 @@ const DetailsPage = ({ isAdmin }) => {
</IconBox>
<Typography component="h2">Uptime</Typography>
</Stack>
<Stack justifyContent="space-between" mt={theme.spacing(8)}>
<Stack justifyContent="space-between" my={theme.spacing(8)}>
<Box>
<Typography>Total Checks</Typography>
<Typography component="span">87</Typography>
<Typography component="span">
{monitorStats.totalChecks}
</Typography>
</Box>
<Box>
<Typography>Uptime Percentage</Typography>
<Typography component="span">
98.3<Typography component="span">%</Typography>
{monitorStats.uptime}
<Typography component="span">%</Typography>
</Typography>
</Box>
</Stack>
<UpBarChart data={aggregateStats} type={dateRange} />
</ChartBox>
<ChartBox>
<Stack>
@@ -451,10 +505,13 @@ const DetailsPage = ({ isAdmin }) => {
</IconBox>
<Typography component="h2">Incidents</Typography>
</Stack>
<Box>
<Box mb={theme.spacing(8)}>
<Typography>Total Incidents</Typography>
<Typography component="span">0</Typography>
<Typography component="span">
{monitorStats.totalIncidents}
</Typography>
</Box>
<DownBarChart data={aggregateStats} />
</ChartBox>
<ChartBox>
<Stack>
@@ -36,6 +36,10 @@ export const ChartBox = styled(Box)(({ theme }) => ({
"& > .MuiBox-root:not(:first-of-type)": {
marginTop: theme.spacing(8),
},
"& tspan, & text": {
fontSize: 11,
fill: theme.palette.text.tertiary,
},
}));
export const IconBox = styled(Box)(({ theme }) => ({
+25
View File
@@ -146,6 +146,31 @@ class NetworkService {
);
}
/**
* ************************************
* Gets aggregate stats by monitor ID
* ************************************
*
* @async
* @param {string} authToken - The authorization token to be used in the request header.
* @param {string} monitorId - The ID of the monitor whose certificate expiry is to be retrieved.
* @returns {Promise<AxiosResponse>} The response from the axios GET request.
*
*/
async getAggregateStatsById(authToken, monitorId, dateRange) {
const params = new URLSearchParams();
if (dateRange) params.append("dateRange", dateRange);
return this.axiosInstance.get(
`/monitors/aggregate/${monitorId}?${params.toString()}`,
{
headers: {
Authorization: `Bearer ${authToken}`,
},
}
);
}
/**
* ************************************
* Updates a single monitor