diff --git a/Client/src/Components/Charts/ChartUtils.js b/Client/src/Components/Charts/ChartUtils.js
index a2c0faa9d..a484622ec 100644
--- a/Client/src/Components/Charts/ChartUtils.js
+++ b/Client/src/Components/Charts/ChartUtils.js
@@ -1,6 +1,3 @@
-const RANGE_MAX = 100;
-const RANGE_MIN = 1;
-
const calculatePercentile = (arr, percentile) => {
const sorted = arr.slice().sort((a, b) => a.responseTime - b.responseTime);
const index = (percentile / 100) * (sorted.length - 1);
@@ -14,27 +11,29 @@ const calculatePercentile = (arr, percentile) => {
);
};
-export const NormalizeData = (checks) => {
+export const NormalizeData = (checks, rangeMin, rangeMax) => {
if (checks.length > 1) {
// Get the 5th and 95th percentile
- const min = calculatePercentile(checks, 5);
+ const min = calculatePercentile(checks, 0);
const max = calculatePercentile(checks, 95);
const normalizedChecks = checks.map((check) => {
+ const originalResponseTime = check.responseTime;
// Normalize the response time between 1 and 100
let normalizedResponseTime =
- RANGE_MIN +
- ((check.responseTime - min) * (RANGE_MAX - RANGE_MIN)) / (max - min);
+ rangeMin +
+ ((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);
// Put a floor on the response times so we don't have extreme outliers
// Better visuals
normalizedResponseTime = Math.max(
- RANGE_MIN,
- Math.min(RANGE_MAX, normalizedResponseTime)
+ rangeMin,
+ Math.min(rangeMax, normalizedResponseTime)
);
return {
...check,
responseTime: normalizedResponseTime,
+ originalResponseTime: originalResponseTime,
};
});
diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
index 2b5074ccb..1d1ea3758 100644
--- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
+++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
@@ -1,15 +1,33 @@
import PropTypes from "prop-types";
-import {
- AreaChart,
- Area,
- XAxis,
- CartesianGrid,
- Tooltip,
- ResponsiveContainer,
-} from "recharts";
+import { AreaChart, Area, XAxis, Tooltip, ResponsiveContainer } from "recharts";
import { NormalizeData } from "../ChartUtils";
-const MonitorDetailsAreaChart = ({ checks }) => {
+const CustomToolTip = ({ active, payload, label }) => {
+ if (active && payload && payload.length) {
+ return (
+
+
+ {new Date(label).toLocaleDateString("en-US", {
+ weekday: "short", // Mon
+ month: "long", // July
+ day: "numeric", // 17
+ }) +
+ ", " +
+ new Date(label).toLocaleTimeString("en-US", {
+ hour: "numeric", // 12
+ minute: "2-digit", // 15
+ hour12: true, // AM/PM format
+ })}
+
+
Response Time (ms): {payload[0].payload.originalResponseTime}
{" "}
+ {/* Display original value */}
+
+ );
+ }
+ return null;
+};
+
+const MonitorDetailsAreaChart = ({ checks, filter }) => {
// SQUASH ERROR, NOT PERMANENT SOLUTION
const error = console.error;
console.error = (...args) => {
@@ -28,9 +46,30 @@ const MonitorDetailsAreaChart = ({ checks }) => {
});
};
+ const filterChecks = (checks, filter) => {
+ const limits = {
+ day: 24 * 60 * 60 * 1000,
+ week: 24 * 60 * 60 * 1000 * 7,
+ month: 24 * 60 * 60 * 1000 * 30, //TODO better monthly calculations
+ };
+
+ const now = new Date().getTime();
+ const result = [];
+ for (let i = 0; i < checks.length; i++) {
+ const checkTime = new Date(checks[i].createdAt).getTime();
+ if (now - checkTime < limits[filter]) {
+ result.push(checks[i]);
+ } else {
+ break;
+ }
+ }
+ return result;
+ };
+
let normalizedChecks = [];
if (checks && checks.length > 0) {
- normalizedChecks = NormalizeData(checks);
+ const filteredChecks = filterChecks(checks, filter);
+ normalizedChecks = NormalizeData(filteredChecks, 33, 100);
}
return (
@@ -51,7 +90,7 @@ const MonitorDetailsAreaChart = ({ checks }) => {
tickFormatter={formatDate}
tick={{ fontSize: "13px" }}
/>
-
+ } />
{
MonitorDetailsAreaChart.propTypes = {
checks: PropTypes.array,
+ filter: PropTypes.string,
+};
+
+CustomToolTip.propTypes = {
+ active: PropTypes.bool,
+ payload: PropTypes.arrayOf(
+ PropTypes.shape({
+ payload: PropTypes.shape({
+ originalResponseTime: PropTypes.number.isRequired,
+ }).isRequired,
+ })
+ ),
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
export default MonitorDetailsAreaChart;
diff --git a/Client/src/Components/Charts/ResponseTimeChart/index.jsx b/Client/src/Components/Charts/ResponseTimeChart/index.jsx
index 7a9bf71b2..d76abc196 100644
--- a/Client/src/Components/Charts/ResponseTimeChart/index.jsx
+++ b/Client/src/Components/Charts/ResponseTimeChart/index.jsx
@@ -4,7 +4,7 @@ import { BarChart, Bar, ResponsiveContainer, Cell } from "recharts";
import { NormalizeData } from "../ChartUtils";
const ResponseTimeChart = ({ checks = [] }) => {
- const normalizedChecks = NormalizeData(checks);
+ const normalizedChecks = NormalizeData(checks, 1, 100);
return (
diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx
index ebdd34611..74177b583 100644
--- a/Client/src/Pages/Monitors/Details/index.jsx
+++ b/Client/src/Pages/Monitors/Details/index.jsx
@@ -46,6 +46,8 @@ const DetailsPage = () => {
const [data, setData] = useState({});
const { monitorId } = useParams();
const { authToken } = useSelector((state) => state.auth);
+ const [filter, setFilter] = useState("day");
+
useEffect(() => {
const fetchMonitor = async () => {
const res = await axiosInstance.get(`/monitors/${monitorId}`, {
@@ -180,13 +182,25 @@ const DetailsPage = () => {
Response Times
-
-
-
+
-