mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-18 23:48:43 -05:00
Implemented basic charts
This commit is contained in:
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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 }) => ({
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user