diff --git a/Client/src/Pages/Monitors/Details/Charts/index.jsx b/Client/src/Pages/Monitors/Details/Charts/index.jsx new file mode 100644 index 000000000..54d9716fa --- /dev/null +++ b/Client/src/Pages/Monitors/Details/Charts/index.jsx @@ -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 ( + <> + + {formatDate(new Date(firstDataPoint.day), options)} + + + {formatDate(new Date(lastDataPoint.day), options)} + + + ); +}; + +export const UpBarChart = ({ data, dateRange }) => { + const theme = useTheme(); + + return ( + + + + } + /> + + + + ); +}; + +export const DownBarChart = ({ data }) => { + const theme = useTheme(); + + return ( + + + + } + /> + + + + ); +}; diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 8aef758a0..6f717143e 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -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 ( {loading ? ( @@ -431,18 +481,22 @@ const DetailsPage = ({ isAdmin }) => { Uptime - + Total Checks - 87 + + {monitorStats.totalChecks} + Uptime Percentage - 98.3% + {monitorStats.uptime} + % + @@ -451,10 +505,13 @@ const DetailsPage = ({ isAdmin }) => { Incidents - + Total Incidents - 0 + + {monitorStats.totalIncidents} + + diff --git a/Client/src/Pages/Monitors/Details/styled.jsx b/Client/src/Pages/Monitors/Details/styled.jsx index 8e1ee9774..1ed6ca8ee 100644 --- a/Client/src/Pages/Monitors/Details/styled.jsx +++ b/Client/src/Pages/Monitors/Details/styled.jsx @@ -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 }) => ({ diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 6dcde82bb..acb1134e4 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -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} 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