diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
index c45fa1b72..947f776a4 100644
--- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
+++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
@@ -12,12 +12,12 @@ import { Box, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useMemo, useState } from "react";
import { useSelector } from "react-redux";
-import { formatDateWithTz } from "../../../Utils/timeUtils";
+import { formatDateWithTz, toTimeStamp } from "../../../Utils/timeUtils";
import "./index.css";
const CustomToolTip = ({ active, payload, label }) => {
const uiTimezone = useSelector((state) => state.ui.timezone);
-
+ const dateFormat = label?.length === 10 ? "YYYY-MM-DD" : "YYYY-MM-DD-HH";
const theme = useTheme();
if (active && payload && payload.length) {
return (
@@ -39,7 +39,11 @@ const CustomToolTip = ({ active, payload, label }) => {
fontWeight: 500,
}}
>
- {formatDateWithTz(label, "ddd, MMMM D, YYYY, h:mm A", uiTimezone)}
+ {formatDateWithTz(
+ toTimeStamp(label, dateFormat),
+ "ddd, MMMM D, YYYY, h:mm A",
+ uiTimezone
+ )}
{
Response Time
{" "}
- {payload[0].payload.originalResponseTime}
+ {Math.floor(payload[0].payload.originalAvgResponseTime)}
{
return null;
};
+CustomToolTip.propTypes = {
+ active: PropTypes.bool,
+ payload: PropTypes.arrayOf(
+ PropTypes.shape({
+ payload: PropTypes.shape({
+ _id: PropTypes.string.isRequired, // Add this line to validate _id
+ originalResponseTime: PropTypes.number.isRequired,
+ }).isRequired,
+ })
+ ),
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
const CustomTick = ({ x, y, payload, index }) => {
const theme = useTheme();
const uiTimezone = useSelector((state) => state.ui.timezone);
-
+ const dateFormat = payload?.value.length === 10 ? "YYYY-MM-DD" : "YYYY-MM-DD-HH";
// Render nothing for the first tick
if (index === 0) return null;
return (
@@ -103,7 +120,7 @@ const CustomTick = ({ x, y, payload, index }) => {
fontSize={11}
fontWeight={400}
>
- {formatDateWithTz(payload?.value, "h:mm a", uiTimezone)}
+ {formatDateWithTz(toTimeStamp(payload?.value, dateFormat), "h:mm a", uiTimezone)}
);
};
@@ -168,7 +185,7 @@ const MonitorDetailsAreaChart = ({ checks }) => {
}
minTickGap={0}
axisLine={false}
@@ -183,7 +200,7 @@ const MonitorDetailsAreaChart = ({ checks }) => {
/>
{
+ const uiTimezone = useSelector((state) => state.ui.timezone);
+ const formatString = type === "month" ? "YYYY-MM-DD" : "YYYY-MM-DD-HH";
+ const dateFormat = type === "day" ? "MMM D, h:mm A" : "MMM D";
+
+ return (
+ <>
+
+ {formatDateWithTz(
+ toTimeStamp(firstDataPoint._id, formatString),
+ dateFormat,
+ uiTimezone
+ )}
+
+
+ {formatDateWithTz(
+ toTimeStamp(lastDataPoint._id, formatString),
+ dateFormat,
+ uiTimezone
+ )}
+
+ >
+ );
+};
+
+CustomLabels.propTypes = {
+ x: PropTypes.number.isRequired,
+ width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ firstDataPoint: PropTypes.object.isRequired,
+ lastDataPoint: PropTypes.object.isRequired,
+ type: PropTypes.string.isRequired,
+};
+
+export default CustomLabels;
diff --git a/Client/src/Pages/Uptime/Details/Charts/DownBarChart.jsx b/Client/src/Pages/Uptime/Details/Charts/DownBarChart.jsx
new file mode 100644
index 000000000..a851a93ea
--- /dev/null
+++ b/Client/src/Pages/Uptime/Details/Charts/DownBarChart.jsx
@@ -0,0 +1,89 @@
+import { memo, useState } from "react";
+import { useTheme } from "@mui/material";
+import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
+import PropTypes from "prop-types";
+import CustomLabels from "./CustomLabels";
+
+const DownBarChart = memo(({ stats, type, onBarHover }) => {
+ const theme = useTheme();
+
+ const [chartHovered, setChartHovered] = useState(false);
+ const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
+
+ return (
+
+ {
+ setChartHovered(true);
+ onBarHover({ time: null, totalChecks: 0 });
+ }}
+ onMouseLeave={() => {
+ setChartHovered(false);
+ setHoveredBarIndex(null);
+ onBarHover(null);
+ }}
+ >
+
+ }
+ />
+
+ {stats.downChecks.map((entry, index) => (
+ | {
+ setHoveredBarIndex(index);
+ onBarHover(entry);
+ }}
+ onMouseLeave={() => {
+ setHoveredBarIndex(null);
+ onBarHover({ time: null, totalChecks: 0 });
+ }}
+ />
+ ))}
+ |
+
+
+ );
+});
+
+DownBarChart.displayName = "DownBarChart";
+DownBarChart.propTypes = {
+ stats: PropTypes.shape({
+ downChecks: PropTypes.arrayOf(PropTypes.object),
+ downChecksAggregate: PropTypes.object,
+ }),
+ type: PropTypes.string,
+ onBarHover: PropTypes.func,
+};
+export default DownBarChart;
diff --git a/Client/src/Pages/Uptime/Details/Charts/ResponseGaugeChart.jsx b/Client/src/Pages/Uptime/Details/Charts/ResponseGaugeChart.jsx
new file mode 100644
index 000000000..29e0cc8bb
--- /dev/null
+++ b/Client/src/Pages/Uptime/Details/Charts/ResponseGaugeChart.jsx
@@ -0,0 +1,117 @@
+import PropTypes from "prop-types";
+import { useTheme } from "@mui/material";
+import { ResponsiveContainer, RadialBarChart, RadialBar, Cell } from "recharts";
+
+const ResponseGaugeChart = ({ avgResponseTime }) => {
+ const theme = useTheme();
+
+ let max = 1000; // max ms
+
+ const data = [
+ { response: max, fill: "transparent", background: false },
+ { response: avgResponseTime, background: true },
+ ];
+ let responseTime = Math.floor(avgResponseTime);
+ let responseProps =
+ responseTime <= 200
+ ? {
+ category: "Excellent",
+ main: theme.palette.success.main,
+ bg: theme.palette.success.contrastText,
+ }
+ : responseTime <= 500
+ ? {
+ category: "Fair",
+ main: theme.palette.success.main,
+ bg: theme.palette.success.contrastText,
+ }
+ : responseTime <= 600
+ ? {
+ category: "Acceptable",
+ main: theme.palette.warning.main,
+ bg: theme.palette.warning.dark,
+ }
+ : {
+ category: "Poor",
+ main: theme.palette.error.main,
+ bg: theme.palette.error.light,
+ };
+
+ return (
+
+
+
+ low
+
+
+ high
+
+
+ {responseProps.category}
+
+
+ {responseTime} ms
+
+
+ |
+ |
+
+
+
+ );
+};
+
+ResponseGaugeChart.propTypes = {
+ avgResponseTime: PropTypes.number.isRequired,
+};
+
+export default ResponseGaugeChart;
diff --git a/Client/src/Pages/Uptime/Details/Charts/UpBarChart.jsx b/Client/src/Pages/Uptime/Details/Charts/UpBarChart.jsx
new file mode 100644
index 000000000..7ee77864d
--- /dev/null
+++ b/Client/src/Pages/Uptime/Details/Charts/UpBarChart.jsx
@@ -0,0 +1,100 @@
+import { memo, useState } from "react";
+import { useTheme } from "@mui/material";
+import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
+import PropTypes from "prop-types";
+import CustomLabels from "./CustomLabels";
+
+const UpBarChart = memo(({ stats, type, onBarHover }) => {
+ const theme = useTheme();
+ const [chartHovered, setChartHovered] = useState(false);
+ const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
+
+ const getColorRange = (responseTime) => {
+ return responseTime < 200
+ ? { main: theme.palette.success.main, light: theme.palette.success.light }
+ : responseTime < 300
+ ? { main: theme.palette.warning.main, light: theme.palette.warning.light }
+ : { main: theme.palette.error.contrastText, light: theme.palette.error.light };
+ };
+
+ return (
+
+ {
+ setChartHovered(true);
+ onBarHover({ time: null, totalChecks: 0, avgResponseTime: 0 });
+ }}
+ onMouseLeave={() => {
+ setChartHovered(false);
+ setHoveredBarIndex(null);
+ onBarHover(null);
+ }}
+ >
+
+ }
+ />
+
+ {stats.upChecks.map((entry, index) => {
+ let { main, light } = getColorRange(entry.avgResponseTime);
+ return (
+ {
+ setHoveredBarIndex(index);
+ onBarHover(entry);
+ }}
+ onMouseLeave={() => {
+ setHoveredBarIndex(null);
+ onBarHover({
+ time: null,
+ totalChecks: 0,
+ groupUptimePercentage: 0,
+ });
+ }}
+ />
+ );
+ })}
+ |
+
+
+ );
+});
+
+// Add display name for the component
+UpBarChart.displayName = "UpBarChart";
+
+// Validate props using PropTypes
+UpBarChart.propTypes = {
+ stats: PropTypes.shape({
+ upChecks: PropTypes.array,
+ upChecksAggregate: PropTypes.object,
+ }),
+ type: PropTypes.string,
+ onBarHover: PropTypes.func,
+};
+export default UpBarChart;
diff --git a/Client/src/Pages/Uptime/Details/Charts/index.jsx b/Client/src/Pages/Uptime/Details/Charts/index.jsx
deleted file mode 100644
index 8f135196a..000000000
--- a/Client/src/Pages/Uptime/Details/Charts/index.jsx
+++ /dev/null
@@ -1,350 +0,0 @@
-import { useTheme } from "@emotion/react";
-import PropTypes from "prop-types";
-import {
- BarChart,
- Bar,
- XAxis,
- ResponsiveContainer,
- Cell,
- RadialBarChart,
- RadialBar,
-} from "recharts";
-import { memo, useMemo, useState } from "react";
-import { useSelector } from "react-redux";
-import { formatDateWithTz, toTimeStamp } from "../../../../Utils/timeUtils";
-
-const CustomLabels = ({ x, width, height, firstDataPoint, lastDataPoint, type }) => {
- const uiTimezone = useSelector((state) => state.ui.timezone);
- const formatString = type === "month" ? "YYYY-MM-DD" : "YYYY-MM-DD-HH";
- const dateFormat = type === "day" ? "MMM D, h:mm A" : "MMM D";
-
- return (
- <>
-
- {formatDateWithTz(
- toTimeStamp(firstDataPoint._id, formatString),
- dateFormat,
- uiTimezone
- )}
-
-
- {formatDateWithTz(
- toTimeStamp(lastDataPoint._id, formatString),
- dateFormat,
- uiTimezone
- )}
-
- >
- );
-};
-
-CustomLabels.propTypes = {
- x: PropTypes.number.isRequired,
- width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
- height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
- firstDataPoint: PropTypes.object.isRequired,
- lastDataPoint: PropTypes.object.isRequired,
- type: PropTypes.string.isRequired,
-};
-
-const UpBarChart = memo(({ data, type, onBarHover }) => {
- const theme = useTheme();
-
- const [chartHovered, setChartHovered] = useState(false);
- const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
-
- const getColorRange = (uptime) => {
- return uptime > 0.8
- ? { main: theme.palette.success.main, light: theme.palette.success.light }
- : uptime > 0.5
- ? { main: theme.palette.warning.main, light: theme.palette.warning.light }
- : { main: theme.palette.error.contrastText, light: theme.palette.error.light };
- };
-
- // TODO - REMOVE THIS LATER
-
- return (
-
- {
- setChartHovered(true);
- onBarHover({ time: null, totalChecks: 0, groupUptimePercentage: 0 });
- }}
- onMouseLeave={() => {
- setChartHovered(false);
- setHoveredBarIndex(null);
- onBarHover(null);
- }}
- >
-
- }
- />
-
- {data.map((entry, index) => {
- let { main, light } = getColorRange(entry.groupUptimePercentage);
- return (
- {
- setHoveredBarIndex(index);
- onBarHover(entry);
- }}
- onMouseLeave={() => {
- setHoveredBarIndex(null);
- onBarHover({
- time: null,
- totalChecks: 0,
- groupUptimePercentage: 0,
- });
- }}
- />
- );
- })}
- |
-
-
- );
-});
-
-// Add display name for the component
-UpBarChart.displayName = "UpBarChart";
-
-// Validate props using PropTypes
-UpBarChart.propTypes = {
- data: PropTypes.arrayOf(PropTypes.object),
- type: PropTypes.string,
- onBarHover: PropTypes.func,
-};
-export { UpBarChart };
-
-const DownBarChart = memo(({ data, type, onBarHover }) => {
- const theme = useTheme();
-
- const [chartHovered, setChartHovered] = useState(false);
- const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
-
- return (
-
- {
- setChartHovered(true);
- onBarHover({ time: null, totalChecks: 0 });
- }}
- onMouseLeave={() => {
- setChartHovered(false);
- setHoveredBarIndex(null);
- onBarHover(null);
- }}
- >
-
- }
- />
-
- {data.map((entry, index) => (
- {
- setHoveredBarIndex(index);
- onBarHover(entry);
- }}
- onMouseLeave={() => {
- setHoveredBarIndex(null);
- onBarHover({ time: null, totalChecks: 0 });
- }}
- />
- ))}
- |
-
-
- );
-});
-
-DownBarChart.displayName = "DownBarChart";
-DownBarChart.propTypes = {
- data: PropTypes.arrayOf(PropTypes.object),
- type: PropTypes.string,
- onBarHover: PropTypes.func,
-};
-export { DownBarChart };
-
-const ResponseGaugeChart = ({ avgResponseTime }) => {
- const theme = useTheme();
-
- let max = 1000; // max ms
-
- const data = [
- { response: max, fill: "transparent", background: false },
- { response: avgResponseTime, background: true },
- ];
- let responseTime = Math.floor(avgResponseTime);
- let responseProps =
- responseTime <= 200
- ? {
- category: "Excellent",
- main: theme.palette.success.main,
- bg: theme.palette.success.contrastText,
- }
- : responseTime <= 500
- ? {
- category: "Fair",
- main: theme.palette.success.main,
- bg: theme.palette.success.contrastText,
- }
- : responseTime <= 600
- ? {
- category: "Acceptable",
- main: theme.palette.warning.main,
- bg: theme.palette.warning.dark,
- }
- : {
- category: "Poor",
- main: theme.palette.error.main,
- bg: theme.palette.error.light,
- };
-
- return (
-
-
-
- low
-
-
- high
-
-
- {responseProps.category}
-
-
- {responseTime} ms
-
-
- |
- |
-
-
-
- );
-};
-
-ResponseGaugeChart.propTypes = {
- data: PropTypes.arrayOf(PropTypes.object).isRequired,
-};
-
-export { ResponseGaugeChart };
diff --git a/Client/src/Pages/Uptime/Details/index.jsx b/Client/src/Pages/Uptime/Details/index.jsx
index 93c1b99d7..45a99095e 100644
--- a/Client/src/Pages/Uptime/Details/index.jsx
+++ b/Client/src/Pages/Uptime/Details/index.jsx
@@ -17,7 +17,6 @@ import PaginationTable from "./PaginationTable";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import PulseDot from "../../../Components/Animated/PulseDot";
import { ChartBox } from "./styled";
-import { DownBarChart, ResponseGaugeChart, UpBarChart } from "./Charts";
import SkeletonLayout from "./skeleton";
import "./index.css";
import useUtils from "../utils";
@@ -26,7 +25,9 @@ import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import IconBox from "../../../Components/IconBox";
import StatBox from "../../../Components/StatBox";
import { toTimeStamp } from "../../../Utils/timeUtils";
-
+import UpBarChart from "./Charts/UpBarChart";
+import DownBarChart from "./Charts/DownBarChart";
+import ResponseGaugeChart from "./Charts/ResponseGaugeChart";
/**
* Details page component displaying monitor details and related information.
* @component
@@ -54,7 +55,6 @@ const DetailsPage = () => {
dateRange: dateRange,
normalize: true,
});
- console.log(res?.data?.data);
setMonitor(res?.data?.data ?? {});
} catch (error) {
logger.error(error);
@@ -105,10 +105,6 @@ const DetailsPage = () => {
const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
- useEffect(() => {
- console.log(hoveredUptimeData);
- }, [hoveredUptimeData]);
-
const BREADCRUMBS = [
{ name: "uptime", path: "/uptime" },
{ name: "details", path: `/uptime/${monitorId}` },
@@ -226,17 +222,17 @@ const DetailsPage = () => {
- {monitor?.aggregateData?.latestResponseTime}
+ {monitor?.stats?.latestResponseTime}
{"ms"}
>
}
@@ -313,7 +309,7 @@ const DetailsPage = () => {
{hoveredUptimeData !== null
? hoveredUptimeData.totalChecks
- : (monitor.groupUpChecks[0]?.upChecksCount ?? 0)}
+ : (monitor.stats?.totalChecks ?? 0)}
{hoveredUptimeData !== null && hoveredUptimeData.time !== null && (
{
)}
- Uptime Percentage
+
+ {hoveredUptimeData !== null
+ ? "Avg Response Time"
+ : "Uptime Percentage"}
+
{hoveredUptimeData !== null
- ? Math.floor(hoveredUptimeData.groupUptimePercentage * 100)
+ ? Math.floor(hoveredUptimeData?.avgResponseTime ?? 0)
: Math.floor(
- (monitor?.groupUpChecks[0]?.overallUptimePercentage ?? 0) *
+ ((monitor?.stats?.upChecksAggregate.totalChecks ?? 0) /
+ (monitor?.stats?.totalChecks ?? 1)) *
100
)}
- %
+
+ {hoveredUptimeData !== null ? " ms" : " %"}
+
@@ -365,7 +368,7 @@ const DetailsPage = () => {
{hoveredIncidentsData !== null
? hoveredIncidentsData.totalChecks
- : (monitor.groupDownChecks[0]?.downChecksCount ?? 0)}
+ : (monitor.stats?.downChecksAggregate.totalChecks ?? 0)}
{hoveredIncidentsData !== null &&
hoveredIncidentsData.time !== null && (
@@ -388,7 +391,7 @@ const DetailsPage = () => {
)}
@@ -401,7 +404,7 @@ const DetailsPage = () => {
Average Response Time
@@ -414,7 +417,7 @@ const DetailsPage = () => {
Response Times
- {/* */}
+
{
History
- {/* */}
+ />