Merge pull request #3820 from bluewave-labs/chore/ms-cleanup

chore: ms cleanup
This commit is contained in:
Alexander Holliday authored and GitHub committed 2026-07-31 13:06:35 -07:00
commit 3646af9c04
36 files changed
+191 -174

No files matched your search

@@ -1,13 +1,12 @@
import Stack from "@mui/material/Stack";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { formatDateWithTz, formatMs } from "@/Utils/TimeUtils";
import type { CheckSnapshot } from "@/Types/Check";
import { useTheme } from "@mui/material/styles";
import { useSelector } from "react-redux";
import type { RootState } from "@/Types/state";
import { useTranslation } from "react-i18next";
import prettyMilliseconds from "pretty-ms";
type HeatmapCheck =
| CheckSnapshot
@@ -59,9 +58,7 @@ export const HeatmapResponseTimeTooltip = ({
</Typography>
<Typography>
{t("common.labels.responseTime")}:{" "}
{check?.responseTime
? prettyMilliseconds(check.responseTime, { compact: true })
: "N/A"}
{check?.responseTime ? formatMs(check.responseTime) : "N/A"}
</Typography>
<Typography textTransform={"capitalize"}>
Status:{" "}
@@ -9,6 +9,7 @@ import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { MAX_RECENT_CHECKS } from "@/Types/Monitor";
import { computeBarHeights } from "@/Utils/DataUtils";
import { formatMs } from "@/Utils/TimeUtils";
interface HistogramResponseTimeProps {
checks: CheckSnapshot[];
@@ -19,25 +20,25 @@ interface HistogramResponseTimeProps {
}
interface ResponseTimeStats {
max: number | string;
avg: number | string;
max: string | null;
avg: string | null;
}
const DEFAULT_HEIGHT = 50;
const calculateResponseTimeStats = (checks: CheckSnapshot[]): ResponseTimeStats => {
if (!Array.isArray(checks) || checks.length === 0) {
return { max: "-", avg: "-" };
return { max: null, avg: null };
}
const validChecks = checks.filter((check) => check.responseTime != null);
if (validChecks.length === 0) {
return { max: "-", avg: "-" };
return { max: null, avg: null };
}
const responseTimes = validChecks.map((check) => check.responseTime);
const max = Math.round(Math.max(...responseTimes));
const avg = Math.round(
const max = formatMs(Math.max(...responseTimes));
const avg = formatMs(
responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length
);
@@ -69,29 +70,28 @@ export const HistogramResponseTime = ({
const chartHeight = typeof height === "number" ? `${height}px` : height;
const gridGap = gap ?? theme.spacing(0.5);
const statsContent = showStats &&
(typeof stats.max === "number" || typeof stats.avg === "number") && (
<Stack
justifyContent="center"
alignItems={statsPosition === "left" ? "flex-end" : "flex-start"}
width={110}
pr={statsPosition === "left" ? theme.spacing(8) : 0}
pl={statsPosition === "right" ? theme.spacing(8) : 0}
const statsContent = showStats && (stats.max !== null || stats.avg !== null) && (
<Stack
justifyContent="center"
alignItems={statsPosition === "left" ? "flex-end" : "flex-start"}
width={110}
pr={statsPosition === "left" ? theme.spacing(8) : 0}
pl={statsPosition === "right" ? theme.spacing(8) : 0}
>
<Typography
variant="body2"
noWrap
>
<Typography
variant="body2"
noWrap
>
{t("common.charts.histogram.avg", { value: stats.avg })}
</Typography>
<Typography
variant="body2"
noWrap
>
{t("common.charts.histogram.max", { value: stats.max })}
</Typography>
</Stack>
);
{t("common.charts.histogram.avg", { value: stats.avg })}
</Typography>
<Typography
variant="body2"
noWrap
>
{t("common.charts.histogram.max", { value: stats.max })}
</Typography>
</Stack>
);
return (
<Stack
@@ -4,10 +4,10 @@ import Typography from "@mui/material/Typography";
import { PulseDot, Dot, StrategyBadge } from "@/Components/design-elements";
import { getStatusColor, formatUrl } from "@/Utils/MonitorUtils";
import { useTheme } from "@mui/material/styles";
import prettyMilliseconds from "pretty-ms";
import { typographyLevels } from "@/Utils/Theme/Palette";
import useMediaQuery from "@mui/material/useMediaQuery";
import { LAYOUT } from "@/Utils/Theme/constants";
import { formatDuration } from "@/Utils/TimeUtils";
export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => {
const theme = useTheme();
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
@@ -52,7 +52,7 @@ export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => {
<>
<Dot />
<Typography>
Checking every {prettyMilliseconds(monitor?.interval, { verbose: true })}
Checking every {formatDuration(monitor?.interval, true)}
</Typography>
</>
)}
@@ -6,6 +6,7 @@ import type { FlatGeoCheck } from "@/Types/GeoCheck";
import { useTranslation } from "react-i18next";
import { formatStatusCode } from "@/Utils/statusCode";
import "maplibre-gl/dist/maplibre-gl.css";
import { formatMs } from "@/Utils/TimeUtils";
interface GeoChecksMapProps {
geoChecks: FlatGeoCheck[];
@@ -83,10 +84,6 @@ export const GeoChecksMap = ({ geoChecks }: GeoChecksMapProps) => {
return status ? theme.palette.success.main : theme.palette.error.main;
};
const formatResponseTime = (timing: number): string => {
return `${timing.toFixed(0)}ms`;
};
return (
<>
{mapPopupStyles}
@@ -186,7 +183,7 @@ export const GeoChecksMap = ({ geoChecks }: GeoChecksMapProps) => {
>
Response Time:
</Typography>{" "}
{formatResponseTime(selectedCheck.timings.total)}
{formatMs(selectedCheck.timings.total)}
</Typography>
<Typography
variant="caption"
@@ -1,11 +1,11 @@
import Stack from "@mui/material/Stack";
import { StatBox } from "@/Components/design-elements";
import prettyMilliseconds from "pretty-ms";
import { useTheme } from "@mui/material/styles";
import type { MonitorStats, Monitor } from "@/Types/Monitor";
import { getStatusPalette } from "@/Utils/MonitorUtils";
import { useTranslation } from "react-i18next";
import { formatMs, formatDuration } from "@/Utils/TimeUtils";
interface MonitorStatBoxesProps {
monitor?: Monitor;
@@ -31,14 +31,9 @@ export const MonitorStatBoxes = ({
const timeOfLastCheck = monitorStats?.lastCheckTimestamp || 0;
const timeSinceLastCheck = Date.now() - timeOfLastCheck || 0;
const options = {
secondsDecimalDigits: 0,
millisecondsDecimalDigits: 0,
};
const streakTime = formatDuration(timeSinceLastFailure);
const streakTime = prettyMilliseconds(timeSinceLastFailure, options);
const lastCheckTime = prettyMilliseconds(timeSinceLastCheck, options);
const lastCheckTime = formatDuration(timeSinceLastCheck);
const isActive =
monitor?.status === "up" ||
monitor?.status === "paused" ||
@@ -67,7 +62,7 @@ export const MonitorStatBoxes = ({
/>
<StatBox
title={t("pages.common.monitors.statBoxes.lastResponseTime")}
subtitle={prettyMilliseconds(monitorStats?.lastResponseTime ?? 0)}
subtitle={formatMs(monitorStats?.lastResponseTime ?? 0)}
/>
{monitor?.type === "http" && (
@@ -14,11 +14,10 @@ import {
import type { TooltipProps } from "recharts";
import type { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent";
import Typography from "@mui/material/Typography";
import prettyMilliseconds from "pretty-ms";
import { XTick } from "@/Components/monitors/charts/XTick";
import { useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { formatDateWithTz, tooltipDateFormatLookup } from "@/Utils/TimeUtils";
import { formatDateWithTz, formatMs, tooltipDateFormatLookup } from "@/Utils/TimeUtils";
import { useTheme } from "@mui/material/styles";
import type { Theme } from "@mui/material/styles";
import type { GroupedCheck, GroupedUptimeCheck } from "@/Types/Check";
@@ -56,16 +55,13 @@ const ResponseTimeToolTip = ({
if (!active) return null;
const format = tooltipDateFormatLookup(range);
const responseTime = Math.floor(payload[0]?.payload?.avgResponseTime || 0);
const responseTime = payload[0]?.payload?.avgResponseTime ?? 0;
return (
<BaseBox sx={{ py: theme.spacing(2), px: theme.spacing(4) }}>
<Typography>{formatDateWithTz(String(label), format, uiTimezone)}</Typography>
<Typography>
{t("common.charts.histogram.responseTime", {
value: prettyMilliseconds(responseTime, {
formatSubMilliseconds: true,
compact: true,
}),
value: formatMs(responseTime),
})}
</Typography>
</BaseBox>
@@ -94,7 +90,7 @@ const TimingPhasesToolTip = ({
<BaseBox sx={{ py: theme.spacing(2), px: theme.spacing(4) }}>
<Typography>{formatDateWithTz(bucket.bucketDate, format, uiTimezone)}</Typography>
<Typography>
{t("common.charts.histogram.total", { value: prettyMilliseconds(total) })}
{t("common.charts.histogram.total", { value: formatMs(total) })}
</Typography>
{PHASE_KEYS.map((key) => (
<Stack
@@ -108,11 +104,7 @@ const TimingPhasesToolTip = ({
color={theme.palette.chart.phases[PHASE_COLOR_KEYS[key]]}
/>
<Typography>
{t(PHASE_LABEL_KEYS[key])}:{" "}
{prettyMilliseconds(bucket[key], {
formatSubMilliseconds: true,
compact: true,
})}
{t(PHASE_LABEL_KEYS[key])}: {formatMs(bucket[key])}
</Typography>
</Stack>
))}
@@ -3,7 +3,7 @@ import Typography from "@mui/material/Typography";
import { BaseChart } from "@/Components/design-elements";
import { useTheme } from "@mui/material/styles";
import { useSelector } from "react-redux";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { formatDateWithTz, formatMs } from "@/Utils/TimeUtils";
import { useTranslation } from "react-i18next";
import { ResponsiveContainer, BarChart, XAxis, Bar, Cell, Tooltip } from "recharts";
import { getResponseTimeColor } from "@/Utils/MonitorUtils";
@@ -100,7 +100,7 @@ export const HistogramStatus = ({
</Typography>
) : null}
<Typography variant="caption">{titleText}</Typography>
<Typography variant="body2">{Math.floor(avg)} ms</Typography>
<Typography variant="body2">{formatMs(avg)}</Typography>
</Stack>
);
};
@@ -7,6 +7,7 @@ import { Cell, RadialBarChart, RadialBar, ResponsiveContainer } from "recharts";
import { useTranslation } from "react-i18next";
import { getResponseTimeColor } from "@/Utils/MonitorUtils";
import { useTheme } from "@mui/material/styles";
import { formatMs } from "@/Utils/TimeUtils";
export const RadialAvgResponse = ({ avg, max }: { avg: number; max: number }) => {
const { t } = useTranslation();
@@ -84,7 +85,9 @@ export const RadialAvgResponse = ({ avg, max }: { avg: number; max: number }) =>
<Typography
variant="h1"
textAlign={"center"}
>{`${avg?.toFixed()}ms`}</Typography>
>
{formatMs(avg)}
</Typography>
</Stack>
</Stack>
</BaseChart>
+2 -5
View File
@@ -1,5 +1,5 @@
import type { Incident, IncidentSummaryItem } from "@/Types/Incident";
import prettyMilliseconds from "pretty-ms";
import { formatDuration } from "@/Utils/TimeUtils";
type IncidentLike = Pick<Incident, "startTime" | "endTime" | "status">;
@@ -24,8 +24,5 @@ export const getIncidentsDuration = (incident: IncidentLike | IncidentSummaryIte
return "-";
}
return prettyMilliseconds(durationMs, {
secondsDecimalDigits: 0,
millisecondsDecimalDigits: 0,
});
return formatDuration(durationMs);
};
+5 -9
View File
@@ -2,10 +2,10 @@ import Box from "@mui/material/Box";
import { StatBox } from "@/Components/design-elements";
import prettyBytes from "pretty-bytes";
import prettyMilliseconds from "pretty-ms";
import { useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
import type { Diagnostics } from "@/Types/Diagnostics";
import { formatDuration, formatMs } from "@/Utils/TimeUtils";
interface StatsProps {
diagnostics: Diagnostics | null;
@@ -18,13 +18,9 @@ export const Stats = ({ diagnostics }: StatsProps) => {
const theme = useTheme();
const eventLoopDelay = diagnostics
? prettyMilliseconds(diagnostics.eventLoopDelayMs ?? 0, {
millisecondsDecimalDigits: 2,
})
: PLACEHOLDER;
const uptime = diagnostics
? prettyMilliseconds(diagnostics.uptimeMs ?? 0, { hideSeconds: true })
? formatMs(diagnostics.eventLoopDelayMs ?? 0)
: PLACEHOLDER;
const uptime = diagnostics ? formatDuration(diagnostics.uptimeMs ?? 0) : PLACEHOLDER;
const usedHeap = diagnostics
? prettyBytes(diagnostics.v8HeapStats?.usedHeapSizeBytes ?? 0)
: PLACEHOLDER;
@@ -37,10 +33,10 @@ export const Stats = ({ diagnostics }: StatsProps) => {
return (
<Box
display="grid"
gap={theme.spacing(8)}
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", md: "repeat(5, 1fr)" },
gap: theme.spacing(8),
"& > *": { width: "100% !important" },
}}
>
@@ -1,7 +1,6 @@
import { Table, Pagination } from "@/Components/design-elements";
import { Typography, useTheme } from "@mui/material";
import prettyMilliseconds from "pretty-ms";
import { formatTimestamp } from "@/Utils/TimeUtils";
import { formatDuration, formatTimestamp } from "@/Utils/TimeUtils";
import { useTranslation } from "react-i18next";
import type { QueueJobFailure, QueueJobSummary, QueueMetrics } from "@/Types/Queue";
@@ -84,7 +83,7 @@ export const TableJobs = ({
id: "interval",
content: t("common.table.headers.interval"),
render: (row) => (
<Typography sx={cellSx}>{prettyMilliseconds(row.monitorInterval ?? 0)}</Typography>
<Typography sx={cellSx}>{formatDuration(row.monitorInterval ?? 0)}</Typography>
),
},
{
@@ -4,7 +4,6 @@ import { Pagination } from "@/Components/design-elements/Table";
import { ActionsMenu } from "@/Components/actions-menu";
import { DialogInput } from "@/Components/inputs/Dialog";
import prettyMilliseconds from "pretty-ms";
import { useTheme } from "@mui/material";
import type { Header } from "@/Components/design-elements/Table";
import type { ActionMenuItem } from "@/Components/actions-menu";
@@ -18,6 +17,7 @@ import { setRowsPerPage } from "@/Features/UI/uiSlice";
import dayjs from "dayjs";
import { useState } from "react";
import { useDelete, usePatch } from "@/Hooks/UseApi";
import { formatDuration } from "@/Utils/TimeUtils";
interface MaintenanceWindowTableProps {
maintenanceWindows: MaintenanceWindow[];
@@ -51,7 +51,7 @@ const getTimeToNextWindow = (
// Window is in the future
if (start.isAfter(now)) {
return prettyMilliseconds(start.diff(now), { unitCount: 2, hideSeconds: true });
return formatDuration(start.diff(now));
}
return "N/A";
@@ -152,9 +152,7 @@ export const MaintenanceWindowTable = ({
id: "repeat",
content: t("pages.maintenanceWindow.table.headers.repeat"),
render: (row) =>
row.repeat === 0
? t("common.labels.na")
: prettyMilliseconds(row.repeat, { verbose: true }),
row.repeat === 0 ? t("common.labels.na") : formatDuration(row.repeat),
},
{
id: "actions",
@@ -1,8 +1,7 @@
import type { CheckSnapshot } from "@/Types/Check";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import prettyMilliseconds from "pretty-ms";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { formatDateWithTz, formatMs } from "@/Utils/TimeUtils";
import { useStatusPageTheme } from "@/Pages/StatusPage/Status/themes/StatusPageThemeProvider";
import { useTranslation } from "react-i18next";
@@ -16,7 +15,7 @@ export const ThemedChartTooltip = ({ check }: { check: CheckSnapshot }) => {
fontWeight={600}
>
{check.status
? `${prettyMilliseconds(check.responseTime, { compact: true })}`
? formatMs(check.responseTime)
: t("pages.statusPages.monitorsList.chart.downTooltip")}
</Typography>
<Typography
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
import type { CheckSnapshot } from "@/Types/Check";
import { MAX_RECENT_CHECKS } from "@/Types/Monitor";
import { ThemedChartTooltip } from "@/Pages/StatusPage/Status/themes/shared/ThemedChartTooltip";
import { formatMs } from "@/Utils/TimeUtils";
const CELLS = MAX_RECENT_CHECKS;
@@ -59,7 +60,7 @@ export const ThemedHeatmap = ({ checks, containerSx, cellSx }: Props) => {
>
<Box
sx={cellSx(kind)}
aria-label={`${check.responseTime} ms, ${check.status ? "up" : "down"}`}
aria-label={`${formatMs(check.responseTime)}, ${check.status ? "up" : "down"}`}
/>
</Tooltip>
);
@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
import type { CheckSnapshot } from "@/Types/Check";
import { MAX_RECENT_CHECKS } from "@/Types/Monitor";
import { computeBarHeights } from "@/Utils/DataUtils";
import { formatMs } from "@/Utils/TimeUtils";
import { ThemedChartTooltip } from "@/Pages/StatusPage/Status/themes/shared/ThemedChartTooltip";
const CELLS = MAX_RECENT_CHECKS;
const MIN_HEIGHT_PCT = 6;
@@ -41,11 +42,11 @@ export const ThemedHistogram = ({
];
const heights = computeBarHeights(source);
const valid = out.filter((c): c is CheckSnapshot => c !== null && c.responseTime > 0);
const maxRt = valid.length ? Math.max(...valid.map((c) => c.responseTime)) : 1;
const maxRt = valid.length ? Math.max(...valid.map((c) => c.responseTime)) : 0;
const avgRt = valid.length
? Math.round(valid.reduce((s, c) => s + c.responseTime, 0) / valid.length)
? valid.reduce((s, c) => s + c.responseTime, 0) / valid.length
: 0;
return { padded: out, heights, avg: avgRt, peak: maxRt };
return { padded: out, heights, avg: formatMs(avgRt), peak: formatMs(maxRt) };
}, [checks]);
return (
@@ -71,7 +72,7 @@ export const ThemedHistogram = ({
>
<Box
sx={barSx(tone(check), height)}
aria-label={`${check.responseTime} ms`}
aria-label={formatMs(check.responseTime)}
/>
</Tooltip>
);
@@ -8,10 +8,9 @@ import Box from "@mui/material/Box";
import type { Header } from "@/Components/design-elements";
import type { FlatGeoCheck } from "@/Types/GeoCheck";
import { useTranslation } from "react-i18next";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { formatDateWithTz, formatMs } from "@/Utils/TimeUtils";
import type { RootState } from "@/Types/state";
import { useSelector } from "react-redux";
import prettyMilliseconds from "pretty-ms";
export const GeoChecksTable = ({
geoChecks,
@@ -69,7 +68,7 @@ export const GeoChecksTable = ({
content: t("common.table.headers.responseTime"),
render: (row) => {
if (!row.timings?.total) return "N/A";
return prettyMilliseconds(row.timings.total, { compact: true });
return formatMs(row.timings.total);
},
},
];
+43
View File
@@ -3,6 +3,7 @@ import duration from "dayjs/plugin/duration";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
import customParseFormat from "dayjs/plugin/customParseFormat";
import prettyMilliseconds from "pretty-ms";
dayjs.extend(utc);
dayjs.extend(timezone);
@@ -77,3 +78,45 @@ export const formatTimestamp = (timestamp: string | number | null): string => {
const date = new Date(timestamp);
return date.toLocaleString();
};
const DISPLAY_UNITS = [MS_PER_DAY, MS_PER_HOUR, MS_PER_MINUTE, MS_PER_SECOND];
// pretty-ms floors seconds-and-above and truncates fractional ms, so values
// must be rounded to their display unit first to land on the nearest whole
// unit (53.6 → "54 ms", 1937 → "2 s", 59500 → "1 m").
const roundToDisplayUnit = (ms: number): number => {
for (const unit of DISPLAY_UNITS) {
if (ms >= unit) return Math.round(ms / unit) * unit;
}
return ms >= 1 ? Math.round(ms) : ms;
};
export const formatMs = (ms: number, hasSpace: boolean = true): string => {
const formatted = prettyMilliseconds(roundToDisplayUnit(ms), {
compact: true,
formatSubMilliseconds: true,
secondsDecimalDigits: 0,
});
if (hasSpace) {
return formatted.replace(/^(\d+)(\D+)$/, "$1 $2");
}
return formatted;
};
export const formatDuration = (ms: number, verbose: boolean = false, hasSpace = true) => {
if (verbose) {
return prettyMilliseconds(ms, { verbose: true });
}
const formatted = prettyMilliseconds(ms, {
unitCount: 2,
secondsDecimalDigits: 0,
millisecondsDecimalDigits: 0,
});
if (hasSpace) {
return formatted.replace(/^(\d+)(\D+)$/, "$1 $2");
}
return formatted;
};
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "وقت التشغيل"
},
"histogram": {
"avg": "المتوسط: {{value}} مللي ثانية",
"max": "الحد الأقصى: {{value}} مللي ثانية"
"avg": "المتوسط: {{value}}",
"max": "الحد الأقصى: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "وقت الاستجابة"
},
"chart": {
"avg": "متوسط {{value}} مللي ثانية",
"avg": "متوسط {{value}}",
"downTooltip": "متوقف",
"heatmapAria": "خريطة حرارية لزمن الاستجابة",
"max": "أقصى {{value}} مللي ثانية"
"max": "أقصى {{value}}"
},
"status": {
"breached": "تم تجاوز الحد",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Temps en línia"
},
"histogram": {
"avg": "Mitjana: {{value}} ms",
"max": "Màx: {{value}} ms"
"avg": "Mitjana: {{value}}",
"max": "Màx: {{value}}"
}
},
"dialogs": {
@@ -1346,8 +1346,8 @@
"initializing": "Inicialitzant"
},
"chart": {
"avg": "mitj {{value}}ms",
"max": "màx {{value}}ms",
"avg": "mitj {{value}}",
"max": "màx {{value}}",
"downTooltip": "Caigut",
"heatmapAria": "Mapa de calor del temps de resposta"
},
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Dostupnost"
},
"histogram": {
"avg": "Prům.: {{value}} ms",
"max": "Max: {{value}} ms"
"avg": "Prům.: {{value}}",
"max": "Max: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Doba odezvy"
},
"chart": {
"avg": "průměr {{value}}ms",
"avg": "průměr {{value}}",
"downTooltip": "Mimo provoz",
"heatmapAria": "Tepelná mapa doby odezvy",
"max": "max {{value}}ms"
"max": "max {{value}}"
},
"status": {
"breached": "Překročen limit",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Verfügbarkeit"
},
"histogram": {
"avg": "Durchschn.: {{value}} ms",
"max": "Max.: {{value}} ms"
"avg": "Durchschn.: {{value}}",
"max": "Max.: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Antwortzeit"
},
"chart": {
"avg": "Ø {{value}}ms",
"avg": "Ø {{value}}",
"downTooltip": "Ausgefallen",
"heatmapAria": "Heatmap der Antwortzeit",
"max": "max. {{value}}ms"
"max": "max. {{value}}"
},
"status": {
"breached": "Schwellenwert überschritten",
+4 -4
View File
@@ -74,8 +74,8 @@
"uptime": "Uptime"
},
"histogram": {
"avg": "Avg: {{value}} ms",
"max": "Max: {{value}} ms",
"avg": "Avg: {{value}}",
"max": "Max: {{value}}",
"responseTime": "Response time: {{value}}",
"total": "Total: {{value}}"
},
@@ -1455,8 +1455,8 @@
"initializing": "Initializing"
},
"chart": {
"avg": "avg {{value}}ms",
"max": "max {{value}}ms",
"avg": "avg {{value}}",
"max": "max {{value}}",
"downTooltip": "Down",
"heatmapAria": "Response time heatmap"
},
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Tiempo de actividad"
},
"histogram": {
"avg": "Prom: {{value}} ms",
"max": "Máx: {{value}} ms"
"avg": "Prom: {{value}}",
"max": "Máx: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Tiempo de respuesta"
},
"chart": {
"avg": "prom {{value}}ms",
"avg": "prom {{value}}",
"downTooltip": "Caído",
"heatmapAria": "Mapa de calor del tiempo de respuesta",
"max": "máx {{value}}ms"
"max": "máx {{value}}"
},
"status": {
"breached": "Umbral superado",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Käytettävyys"
},
"histogram": {
"avg": "Keskim.: {{value}} ms",
"max": "Maks.: {{value}} ms"
"avg": "Keskim.: {{value}}",
"max": "Maks.: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Vasteaika"
},
"chart": {
"avg": "ka {{value}}ms",
"avg": "ka {{value}}",
"downTooltip": "Alhaalla",
"heatmapAria": "Vasteajan lämpökartta",
"max": "max {{value}}ms"
"max": "max {{value}}"
},
"status": {
"breached": "Kynnys ylittyi",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Disponibilité"
},
"histogram": {
"avg": "Moy : {{value}} ms",
"max": "Max : {{value}} ms"
"avg": "Moy : {{value}}",
"max": "Max : {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Temps de réponse"
},
"chart": {
"avg": "moy {{value}}ms",
"avg": "moy {{value}}",
"downTooltip": "Hors service",
"heatmapAria": "Carte thermique des temps de réponse",
"max": "max {{value}}ms"
"max": "max {{value}}"
},
"status": {
"breached": "Seuil dépassé",
+4 -4
View File
@@ -71,8 +71,8 @@
"uptime": "Uptime"
},
"histogram": {
"avg": "Media: {{value}} ms",
"max": "Max: {{value}} ms"
"avg": "Media: {{value}}",
"max": "Max: {{value}}"
}
},
"dialogs": {
@@ -1442,8 +1442,8 @@
"initializing": "Inizializzazione"
},
"chart": {
"avg": "media {{value}}ms",
"max": "max {{value}}ms",
"avg": "media {{value}}",
"max": "max {{value}}",
"downTooltip": "Non attivo",
"heatmapAria": "Heatmap del tempo di risposta"
},
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "稼働時間"
},
"histogram": {
"avg": "平均: {{value}} ms",
"max": "最大: {{value}} ms"
"avg": "平均: {{value}}",
"max": "最大: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "応答時間"
},
"chart": {
"avg": "平均 {{value}}ms",
"avg": "平均 {{value}}",
"downTooltip": "ダウン",
"heatmapAria": "応答時間のヒートマップ",
"max": "最大 {{value}}ms"
"max": "最大 {{value}}"
},
"status": {
"breached": "しきい値超過",
+4 -4
View File
@@ -53,8 +53,8 @@
},
"charts": {
"histogram": {
"avg": "Średnia: {{value}} ms",
"max": "Maks: {{value}} ms"
"avg": "Średnia: {{value}}",
"max": "Maks: {{value}}"
},
"labels": {
"averageResponseTime": "Średni czas odpowiedzi",
@@ -1542,10 +1542,10 @@
},
"monitorsList": {
"chart": {
"avg": "śr. {{value}}ms",
"avg": "śr. {{value}}",
"downTooltip": "Niedostępny",
"heatmapAria": "Heatmapa czasu odpowiedzi",
"max": "maks. {{value}}ms"
"max": "maks. {{value}}"
},
"chartTypeHeatmap": "Heatmapa",
"chartTypeHistogram": "Histogram",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Uptime"
},
"histogram": {
"avg": "Média: {{value}} ms",
"max": "Máx: {{value}} ms"
"avg": "Média: {{value}}",
"max": "Máx: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Tempo de resposta"
},
"chart": {
"avg": "méd {{value}}ms",
"avg": "méd {{value}}",
"downTooltip": "Fora do ar",
"heatmapAria": "Mapa de calor do tempo de resposta",
"max": "máx {{value}}ms"
"max": "máx {{value}}"
},
"status": {
"breached": "Limite excedido",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Аптайм"
},
"histogram": {
"avg": "Сред: {{value}} мс",
"max": "Макс: {{value}} мс"
"avg": "Сред: {{value}}",
"max": "Макс: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Время ответа"
},
"chart": {
"avg": "ср {{value}}мс",
"avg": "ср {{value}}",
"downTooltip": "Не работает",
"heatmapAria": "Тепловая карта времени отклика",
"max": "макс {{value}}мс"
"max": "макс {{value}}"
},
"status": {
"breached": "Превышен порог",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "อัปไทม์"
},
"histogram": {
"avg": "เฉลี่ย: {{value}} ms",
"max": "สูงสุด: {{value}} ms"
"avg": "เฉลี่ย: {{value}}",
"max": "สูงสุด: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "เวลาตอบสนอง"
},
"chart": {
"avg": "เฉลี่ย {{value}}ms",
"avg": "เฉลี่ย {{value}}",
"downTooltip": "ไม่พร้อมใช้งาน",
"heatmapAria": "แผนที่ความร้อนของเวลาตอบสนอง",
"max": "สูงสุด {{value}}ms"
"max": "สูงสุด {{value}}"
},
"status": {
"breached": "เกินขีดจำกัด",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Çalışma süresi"
},
"histogram": {
"avg": "Ort: {{value}} ms",
"max": "Maks: {{value}} ms"
"avg": "Ort: {{value}}",
"max": "Maks: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Yanıt süresi"
},
"chart": {
"avg": "ort {{value}}ms",
"avg": "ort {{value}}",
"downTooltip": "Çalışmıyor",
"heatmapAria": "Yanıt süresi ısı haritası",
"max": "maks {{value}}ms"
"max": "maks {{value}}"
},
"status": {
"breached": "Eşik aşıldı",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Час роботи"
},
"histogram": {
"avg": "Сер: {{value}} мс",
"max": "Макс: {{value}} мс"
"avg": "Сер: {{value}}",
"max": "Макс: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Час відповіді"
},
"chart": {
"avg": "сер {{value}}мс",
"avg": "сер {{value}}",
"downTooltip": "Не працює",
"heatmapAria": "Теплова карта часу відгуку",
"max": "макс {{value}}мс"
"max": "макс {{value}}"
},
"status": {
"breached": "Перевищено поріг",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "Thời gian hoạt động"
},
"histogram": {
"avg": "TB: {{value}} ms",
"max": "Tối đa: {{value}} ms"
"avg": "TB: {{value}}",
"max": "Tối đa: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "Thời gian phản hồi"
},
"chart": {
"avg": "TB {{value}}ms",
"avg": "TB {{value}}",
"downTooltip": "Ngừng hoạt động",
"heatmapAria": "Bản đồ nhiệt thời gian phản hồi",
"max": "tối đa {{value}}ms"
"max": "tối đa {{value}}"
},
"status": {
"breached": "Vượt ngưỡng",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "正常运行时间"
},
"histogram": {
"avg": "平均: {{value}} ms",
"max": "最大: {{value}} ms"
"avg": "平均: {{value}}",
"max": "最大: {{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "响应时间"
},
"chart": {
"avg": "平均 {{value}}ms",
"avg": "平均 {{value}}",
"downTooltip": "宕机",
"heatmapAria": "响应时间热图",
"max": "最大 {{value}}ms"
"max": "最大 {{value}}"
},
"status": {
"breached": "超出阈值",
+4 -4
View File
@@ -58,8 +58,8 @@
"uptime": "正常運行時間"
},
"histogram": {
"avg": "平均:{{value}} ms",
"max": "最大:{{value}} ms"
"avg": "平均:{{value}}",
"max": "最大:{{value}}"
}
},
"dialogs": {
@@ -1352,10 +1352,10 @@
"responseTime": "回應時間"
},
"chart": {
"avg": "平均 {{value}}ms",
"avg": "平均 {{value}}",
"downTooltip": "停機",
"heatmapAria": "回應時間熱圖",
"max": "最大 {{value}}ms"
"max": "最大 {{value}}"
},
"status": {
"breached": "超過閾值",