From 974d33b3dea55118b52c5ea032bbb9411e319dbe Mon Sep 17 00:00:00 2001 From: mannilakash Date: Fri, 13 Feb 2026 10:32:52 -0500 Subject: [PATCH] enhancement: add average and max response time for histogram --- .../common/charts/HistogramResponseTime.tsx | 209 ++++++++++++------ client/src/locales/en.json | 4 + 2 files changed, 148 insertions(+), 65 deletions(-) diff --git a/client/src/Components/v2/common/charts/HistogramResponseTime.tsx b/client/src/Components/v2/common/charts/HistogramResponseTime.tsx index e3b82cd50..c3c68643f 100644 --- a/client/src/Components/v2/common/charts/HistogramResponseTime.tsx +++ b/client/src/Components/v2/common/charts/HistogramResponseTime.tsx @@ -1,102 +1,181 @@ import Box from "@mui/material/Box"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; import { useTheme } from "@mui/material/styles"; import type { ResponsiveStyleValue } from "@mui/system"; import type { CheckSnapshot } from "@/Types/Check"; import { HeatmapResponseTimeTooltip } from "./HeatmapResponseTimeTooltip"; +import { useMemo } from "react"; +import { useTranslation } from "react-i18next"; interface HistogramResponseTimeProps { checks: CheckSnapshot[]; height?: ResponsiveStyleValue; gap?: ResponsiveStyleValue; + showStats?: boolean; + statsPosition?: "left" | "right"; +} + +interface ResponseTimeStats { + max: number; + avg: number; } const DEFAULT_HEIGHT = 50; +const calculateResponseTimeStats = (checks: CheckSnapshot[]): ResponseTimeStats => { + if (!Array.isArray(checks) || checks.length === 0) { + return { max: 0, avg: 0 }; + } + + const validChecks = checks.filter( + (check) => + (check as any).status !== "placeholder" && + (check.originalResponseTime != null || check.responseTime != null) + ); + + if (validChecks.length === 0) { + return { max: 0, avg: 0 }; + } + + const responseTimes = validChecks.map( + (check) => check.originalResponseTime ?? check.responseTime ?? 0 + ); + + const max = Math.max(...responseTimes); + const avg = Math.round( + responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length + ); + + return { max, avg }; +}; + export const HistogramResponseTime = ({ checks, height = DEFAULT_HEIGHT, gap, + showStats = true, + statsPosition = "right", }: HistogramResponseTimeProps) => { const theme = useTheme(); + const { t } = useTranslation(); + + const stats = useMemo(() => calculateResponseTimeStats(checks), [checks]); if (!Array.isArray(checks) || checks.length === 0) return null; - let data = Array(); + const data = + checks.length !== 25 + ? [...checks, ...Array(25 - checks.length).fill({ status: "placeholder" })] + : checks; - if (!checks || checks.length === 0) { - data = []; - } - if (checks.length !== 25) { - const placeholders = Array(25 - checks.length).fill({ - status: "placeholder", - }); - data = [...checks, ...placeholders]; - } else { - data = checks; - } const chartHeight = typeof height === "number" ? `${height}px` : height; const gridGap = gap ?? theme.spacing(0.5); - return ( - - 0 || stats.avg > 0) && ( + + - {data.map((check, index) => { - const isPlaceholder = (check as any).status === "placeholder"; - const heightPct = `${Math.max(0, Math.min(100, (check as any).responseTime ?? 0))}%`; - const barColor = - check.status === true - ? theme.palette.success.light - : theme.palette.error.light; - const bar = ( - + {t("common.charts.histogram.avg", { value: stats.avg })} + + + {t("common.charts.histogram.max", { value: stats.max })} + + + ); + + return ( + + {statsPosition === "left" && statsContent} + + + {data.map((check, index) => { + const isPlaceholder = (check as any).status === "placeholder"; + const heightPct = `${Math.max(0, Math.min(100, (check as any).responseTime ?? 0))}%`; + const barColor = + check.status === true + ? theme.palette.success.light + : theme.palette.error.light; + const bar = ( - - ); + > + + + ); - return isPlaceholder ? ( - - {bar} - - ) : ( - - {bar} - - ); - })} + return isPlaceholder ? ( + + {bar} + + ) : ( + + {bar} + + ); + })} + - + {statsPosition === "right" && statsContent} + ); }; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index d2a066c11..3b58827ca 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -231,6 +231,10 @@ "high": "High", "low": "Low", "uptime": "Uptime" + }, + "histogram": { + "avg": "Avg: {{value}} ms", + "max": "Max: {{value}} ms" } }, "dialogs": {