From 3208cc9e2c919a355d60b5ab06a5217d19df66d8 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 25 Jan 2026 16:48:56 +0000 Subject: [PATCH] strings and icons --- .../v2/monitors/charts/HistogramStatus.tsx | 63 +++++++++++++------ client/src/Pages/Uptime/Details/index.tsx | 11 ++++ client/src/Types/Monitor.ts | 16 +++-- client/src/locales/en.json | 7 +++ 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/client/src/Components/v2/monitors/charts/HistogramStatus.tsx b/client/src/Components/v2/monitors/charts/HistogramStatus.tsx index d6b378c25..ed78a1726 100644 --- a/client/src/Components/v2/monitors/charts/HistogramStatus.tsx +++ b/client/src/Components/v2/monitors/charts/HistogramStatus.tsx @@ -1,17 +1,25 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import { BaseChart } from "@/Components/v2/design-elements"; -import { TrendingUp, AlertTriangle } from "lucide-react"; import { useTheme } from "@mui/material/styles"; import { useSelector } from "react-redux"; import { formatDateWithTz } from "@/Utils/timeUtils"; import { useTranslation } from "react-i18next"; import { ResponsiveContainer, BarChart, XAxis, Bar, Cell, Tooltip } from "recharts"; import { getResponseTimeColor } from "@/Utils/MonitorUtils"; +import type { GroupedCheck } from "@/Types/Check"; +import type { MonitorData } from "@/Types/Monitor"; +import type { RootState } from "@/Types/state"; -const XLabel = ({ p1, p2, range }: { p1: any; p2: any; range: string }) => { +interface XLabelProps { + p1: GroupedCheck; + p2: GroupedCheck; + range: string; +} + +const XLabel = ({ p1, p2, range }: XLabelProps) => { const theme = useTheme(); - const uiTimezone = useSelector((state: any) => state.ui.timezone); + const uiTimezone = useSelector((state: RootState) => state.ui.timezone); const dateFormat = range === "day" ? "MMM D, h:mm A" : "MMM D"; return ( <> @@ -23,7 +31,7 @@ const XLabel = ({ p1, p2, range }: { p1: any; p2: any; range: string }) => { fontSize={11} fill={theme.palette.text.secondary} > - {formatDateWithTz(p1.bucketDate, dateFormat, uiTimezone)} + {formatDateWithTz(p1._id, dateFormat, uiTimezone)} { fontSize={11} fill={theme.palette.text.secondary} > - {formatDateWithTz(p2.bucketDate, dateFormat, uiTimezone)} + {formatDateWithTz(p2._id, dateFormat, uiTimezone)} ); }; -export const HistogramStatus = ({ monitorData, checks = [], range }) => { - console.log(checks); +interface HistogramStatusProps { + title: string; + icon: React.ReactNode; + monitorData?: MonitorData; + checks?: GroupedCheck[]; + range: string; +} + +export const HistogramStatus = ({ + title, + icon, + monitorData, + checks = [], + range, +}: HistogramStatusProps) => { const { t } = useTranslation(); const theme = useTheme(); - const CustomTooltip = ({ active, payload }: any) => { - const uiTimezone = useSelector((state: any) => state.ui.timezone); + const CustomTooltip = ({ + active, + payload, + }: { + active?: boolean; + payload?: Array<{ payload: GroupedCheck }>; + }) => { + const uiTimezone = useSelector((state: RootState) => state.ui.timezone); if (!active || !payload?.length) return null; - const d = payload[0]?.payload as any & { - avgResponseTime?: number; - }; + const d = payload[0]?.payload; const avg = d?.avgResponseTime ?? 0; - const titleText = t("common.charts.uptime.avgResponseTime"); + const titleText = t("common.charts.labels.averageRepsonseTime"); const fmt = range === "30d" ? "MMM D, YYYY" : "ddd, MMM D, YYYY, h:mm A"; let dateLabel = ""; - if (d?.bucketDate) { - const base = new Date(d.bucketDate); + if (d?._id) { + const base = new Date(d._id); const midBucket = range === "30d" ? new Date(base.getTime() + 12 * 60 * 60 * 1000) : base; dateLabel = formatDateWithTz(midBucket.toISOString(), fmt, uiTimezone); @@ -83,10 +108,12 @@ export const HistogramStatus = ({ monitorData, checks = [], range }) => { ); }; + const totalChecks = checks.reduce((acc, check) => acc + (check.totalChecks || 0), 0); + return ( } - title={"Test"} + icon={icon} + title={title} > { justifyContent="space-between" > - Checks: {"totalChecks"} + Total checks: {totalChecks} { gap={theme.spacing(8)} > } monitorData={monitorData} checks={monitorData?.groupedUpChecks} range={dateRange} /> + } + monitorData={monitorData} + checks={monitorData?.groupedDownChecks} + range={dateRange} + /> ); diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index e6098121a..cd5245386 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -1,4 +1,4 @@ -import type { Check } from "@/Types/Check"; +import type { Check, GroupedCheck } from "@/Types/Check"; export type MonitorStatus = boolean | undefined; export const MonitorTypes = [ @@ -48,12 +48,6 @@ export interface MonitorsWithChecksResponse { summary: MonitorsSummary; } -export interface MonitorGroupedCheck { - time: number; - responseTime: number; - originalResponseTime: number; - totalChecks: number; -} export interface MonitorStats { id: string; @@ -72,10 +66,14 @@ export interface MonitorStats { export interface MonitorData { monitor: Monitor; - groupedChecks: MonitorGroupedCheck[]; + groupedChecks: GroupedCheck[]; + groupedUpChecks: GroupedCheck[]; + groupedDownChecks: GroupedCheck[]; + groupedAvgResponseTime: number; + groupedUptimePercentage: number; } export interface MonitorDetailsResponse { monitorData: MonitorData; - monitorStats: MonitorStats; + monitorStats: MonitorStats | null; } diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 318398579..db3a54485 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -24,6 +24,13 @@ "type": "Type" }, "empty": "Nothing h" + }, + "charts": { + "labels": { + "uptime": "Uptime", + "downtime": "Downtime", + "averageRepsonseTime": "Average response time" + } } }, "submit": "Submit",