diff --git a/client/src/Components/v2/DesignElements/StatusLabel.tsx b/client/src/Components/v2/DesignElements/StatusLabel.tsx index 69b788e96..a314c09b0 100644 --- a/client/src/Components/v2/DesignElements/StatusLabel.tsx +++ b/client/src/Components/v2/DesignElements/StatusLabel.tsx @@ -5,7 +5,13 @@ import type { MonitorStatus } from "@/Types/Monitor"; import { getStatusPalette } from "@/Utils/MonitorUtils"; import { useTheme } from "@mui/material/styles"; -export const StatusLabel = ({ status }: { status: MonitorStatus }) => { +export const StatusLabel = ({ + status, + isActive, +}: { + status: MonitorStatus; + isActive?: boolean; +}) => { const theme = useTheme(); const palette = getStatusPalette(status); const transformedText = status.charAt(0).toUpperCase() + status.slice(1).toLowerCase(); @@ -29,7 +35,7 @@ export const StatusLabel = ({ status }: { status: MonitorStatus }) => { borderRadius="50%" marginRight="5px" /> - {transformedText} + {isActive === false ? "Paused" : transformedText} ); }; diff --git a/client/src/Components/v2/Layouts/Sidebar/Menu.tsx b/client/src/Components/v2/Layouts/Sidebar/Menu.tsx index 5b3ed705e..f0f99f33a 100644 --- a/client/src/Components/v2/Layouts/Sidebar/Menu.tsx +++ b/client/src/Components/v2/Layouts/Sidebar/Menu.tsx @@ -1,12 +1,12 @@ -import Notifications from "@/assets/icons/notifications.svg?react"; +// import Notifications from "@/assets/icons/notifications.svg?react"; import Monitors from "@/assets/icons/monitors.svg?react"; -import PageSpeed from "@/assets/icons/page-speed.svg?react"; -import Integrations from "@/assets/icons/integrations.svg?react"; -import Incidents from "@/assets/icons/incidents.svg?react"; -import StatusPages from "@/assets/icons/status-pages.svg?react"; -import Maintenance from "@/assets/icons/maintenance.svg?react"; -import Logs from "@/assets/icons/logs.svg?react"; -import Settings from "@/assets/icons/settings.svg?react"; +// import PageSpeed from "@/assets/icons/page-speed.svg?react"; +// import Integrations from "@/assets/icons/integrations.svg?react"; +// import Incidents from "@/assets/icons/incidents.svg?react"; +// import StatusPages from "@/assets/icons/status-pages.svg?react"; +// import Maintenance from "@/assets/icons/maintenance.svg?react"; +// import Logs from "@/assets/icons/logs.svg?react"; +// import Settings from "@/assets/icons/settings.svg?react"; import Support from "@/assets/icons/support.svg?react"; import Discussions from "@/assets/icons/discussions.svg?react"; import Docs from "@/assets/icons/docs.svg?react"; @@ -14,25 +14,25 @@ import ChangeLog from "@/assets/icons/changeLog.svg?react"; export const getMenu = (t: Function) => [ { name: t("menu.uptime"), path: "v2/uptime", icon: }, - { name: t("menu.pagespeed"), path: "pagespeed", icon: }, + // { name: t("menu.pagespeed"), path: "pagespeed", icon: }, - { name: t("menu.infrastructure"), path: "infrastructure", icon: }, - { - name: t("menu.notifications"), - path: "notifications", - icon: , - }, - { name: t("menu.incidents"), path: "incidents", icon: }, + // { name: t("menu.infrastructure"), path: "infrastructure", icon: }, + // { + // name: t("menu.notifications"), + // path: "notifications", + // icon: , + // }, + // { name: t("menu.incidents"), path: "incidents", icon: }, - { name: t("menu.statusPages"), path: "status", icon: }, - { name: t("menu.maintenance"), path: "maintenance", icon: }, - { name: t("menu.logs"), path: "logs", icon: }, + // { name: t("menu.statusPages"), path: "status", icon: }, + // { name: t("menu.maintenance"), path: "maintenance", icon: }, + // { name: t("menu.logs"), path: "logs", icon: }, - { - name: t("menu.settings"), - icon: , - path: "settings", - }, + // { + // name: t("menu.settings"), + // icon: , + // path: "settings", + // }, ]; export const getBottomMenu = (t: Function) => [ diff --git a/client/src/Components/v2/Monitors/ChartResponseTime.tsx b/client/src/Components/v2/Monitors/ChartResponseTime.tsx index 97aef314d..28f40f254 100644 --- a/client/src/Components/v2/Monitors/ChartResponseTime.tsx +++ b/client/src/Components/v2/Monitors/ChartResponseTime.tsx @@ -1,6 +1,7 @@ import { BaseChart } from "./HistogramStatus"; import { BaseBox } from "../DesignElements"; import ResponseTimeIcon from "@/assets/icons/response-time-icon.svg?react"; +import { normalizeResponseTimes } from "@/Utils/DataUtils"; import { AreaChart, Area, @@ -68,7 +69,7 @@ const ResponseTimeToolTip: React.FC = ({ if (!active) return null; const format = tooltipDateFormatLookup(range); - const responseTime = Math.floor(payload?.[0]?.value || 0); + const responseTime = Math.floor(payload?.[0]?.payload?.avgResponseTime || 0); return ( {formatDateWithTz(label, format, uiTimezone)} @@ -86,7 +87,10 @@ export const ChartResponseTime = ({ }) => { const theme = useTheme(); const uiTimezone = useSelector((state: any) => state.ui.timezone); - + const normalized = normalizeResponseTimes( + checks, + "avgResponseTime" + ); return ( } @@ -96,7 +100,7 @@ export const ChartResponseTime = ({ width="100%" height={300} > - + diff --git a/client/src/Components/v2/Monitors/HistogramResponseTime.tsx b/client/src/Components/v2/Monitors/HistogramResponseTime.tsx index d19ddbf53..1925ac93c 100644 --- a/client/src/Components/v2/Monitors/HistogramResponseTime.tsx +++ b/client/src/Components/v2/Monitors/HistogramResponseTime.tsx @@ -3,24 +3,20 @@ import Box from "@mui/material/Box"; import { useTheme } from "@mui/material/styles"; import type { Check } from "@/Types/Check"; import { HistogramResponseTimeTooltip } from "@/Components/v2/Monitors/HistogramResponseTimeTooltip"; +import { normalizeResponseTimes } from "@/Utils/DataUtils"; export const HistogramResponseTime = ({ checks }: { checks: Check[] }) => { + const normalChecks = normalizeResponseTimes(checks, "responseTime"); let data = Array(); - data = checks.map((c) => Math.max(c.responseTime, 1)); - - const logResponses = data.map((r) => Math.log10(r)); - const logMin = Math.min(...logResponses); - const logMax = Math.max(...logResponses); - - if (!checks) { + if (!normalChecks || normalChecks.length === 0) { return null; } - if (checks.length !== 25) { - const placeholders = Array(25 - checks.length).fill("placeholder"); - data = [...checks, ...placeholders]; + if (normalChecks.length !== 25) { + const placeholders = Array(25 - normalChecks.length).fill("placeholder"); + data = [...normalChecks, ...placeholders]; } else { - data = checks; + data = normalChecks; } const theme = useTheme(); @@ -38,14 +34,6 @@ export const HistogramResponseTime = ({ checks }: { checks: Check[] }) => { }} > {data.map((check, index) => { - const safeResponse = Math.max(check.responseTime, 1); - const logValue = Math.log10(safeResponse); - const minHeight = 10; - const barHeight = - logMax === logMin - ? 100 - : Math.max(minHeight, ((logValue - logMin) / (logMax - logMin)) * 100); - if (check === "placeholder") { return ( { position="absolute" bottom={0} width="100%" - height={`${barHeight}%`} + height={`${check.normalResponseTime}%`} bgcolor={ check.status ? theme.palette.success.lowContrast diff --git a/client/src/Components/v2/Monitors/HistogramStatus.tsx b/client/src/Components/v2/Monitors/HistogramStatus.tsx index aeacf31d2..2e10a8042 100644 --- a/client/src/Components/v2/Monitors/HistogramStatus.tsx +++ b/client/src/Components/v2/Monitors/HistogramStatus.tsx @@ -9,6 +9,7 @@ import IncidentsIcon from "@/assets/icons/incidents.svg?react"; import type { GroupedCheck } from "@/Types/Check"; import type { MonitorStatus } from "@/Types/Monitor"; +import { normalizeResponseTimes } from "@/Utils/DataUtils"; import { useState } from "react"; import { formatDateWithTz } from "@/Utils/TimeUtils"; import { useSelector } from "react-redux"; @@ -122,8 +123,9 @@ export const HistogramStatus = ({ const theme = useTheme(); const [idx, setIdx] = useState(null); const dateFormat = range === "1d" || range === "2h" ? "MMM D, h A" : "MMM D"; + const normalChecks = normalizeResponseTimes(checks, "avgResponseTime"); - if (checks.length === 0) { + if (normalChecks.length === 0) { return ( { + const totalChecks = normalChecks.reduce((count, check) => { return count + check.count; }, 0); @@ -161,12 +163,12 @@ export const HistogramStatus = ({ Total checks {idx ? ( - {checks[idx].count} + {normalChecks[idx].count} - {formatDateWithTz(checks[idx]._id, dateFormat, uiTimezone)} + {formatDateWithTz(normalChecks[idx]._id, dateFormat, uiTimezone)} ) : ( @@ -178,26 +180,26 @@ export const HistogramStatus = ({ width="100%" height={155} > - + } /> - {checks?.map((groupedCheck, idx) => { - const fillColor = getResponseTimeColor(groupedCheck.avgResponseTime); + {normalChecks?.map((groupedCheck, idx) => { + const fillColor = getResponseTimeColor(groupedCheck.normalResponseTime); return ( setIdx(idx)} diff --git a/client/src/Pages/v2/Uptime/MonitorTable.tsx b/client/src/Pages/v2/Uptime/MonitorTable.tsx index a7b1d203f..209784309 100644 --- a/client/src/Pages/v2/Uptime/MonitorTable.tsx +++ b/client/src/Pages/v2/Uptime/MonitorTable.tsx @@ -104,7 +104,12 @@ export const MonitorTable = ({ id: "status", content: t("status"), render: (row) => { - return ; + return ( + + ); }, }, { diff --git a/client/src/Types/Check.ts b/client/src/Types/Check.ts index 542507a4b..cccc56f3d 100644 --- a/client/src/Types/Check.ts +++ b/client/src/Types/Check.ts @@ -27,6 +27,7 @@ export interface Check { status: string; message: string; responseTime: number; + normalResponseTime?: number; httpStatusCode: number; ack: boolean; expiry: string; diff --git a/client/src/Utils/DataUtils.ts b/client/src/Utils/DataUtils.ts new file mode 100644 index 000000000..3878d7d6a --- /dev/null +++ b/client/src/Utils/DataUtils.ts @@ -0,0 +1,37 @@ +const MIN_OUT = 10; +const MAX_OUT = 100; + +export const normalizeResponseTimes = , K extends keyof T>( + checks: T[], + key: K +): (T & { normalResponseTime: number })[] => { + if (!Array.isArray(checks) || checks.length === 0) + return checks as (T & { + normalResponseTime: number; + })[]; + + if (checks.length === 1) { + return [ + { + ...checks[0], + normalResponseTime: 50, + }, + ]; + } + + const { min, max } = checks.reduce( + (acc, check) => { + if (check[key] > acc.max) acc.max = check[key]; + if (check[key] < acc.min) acc.min = check[key]; + return acc; + }, + { max: -Infinity, min: Infinity } + ); + + const range = max - min || 1; + + return checks.map((check) => ({ + ...check, + normalResponseTime: MIN_OUT + ((check[key] - min) * (MAX_OUT - MIN_OUT)) / range, + })); +};