From 8c94a30a81991d5d10ce5dcb7fec59964b0c03ec Mon Sep 17 00:00:00 2001 From: nessi Date: Thu, 12 Feb 2026 11:04:38 +0100 Subject: [PATCH] Add transaction rate and enhance chart tooltips Added transaction-per-second (TPS) metric calculation to the TargetDetailPage and updated the chart to display it. Improved tooltip design and functionality for better readability, including dynamic metrics display and styled components. --- frontend/src/pages/TargetDetailPage.jsx | 59 ++++++++++++++++++++----- frontend/src/styles.css | 31 +++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/frontend/src/pages/TargetDetailPage.jsx b/frontend/src/pages/TargetDetailPage.jsx index d33df01..f6f7983 100644 --- a/frontend/src/pages/TargetDetailPage.jsx +++ b/frontend/src/pages/TargetDetailPage.jsx @@ -36,6 +36,24 @@ function formatSeconds(value) { return `${(value / 3600).toFixed(1)}h`; } +function formatNumber(value, digits = 2) { + if (value === null || value === undefined || Number.isNaN(Number(value))) return "-"; + return Number(value).toFixed(digits); +} + +function MetricsTooltip({ active, payload, label }) { + if (!active || !payload || payload.length === 0) return null; + const row = payload[0]?.payload || {}; + return ( +
+
{label}
+
connections: {formatNumber(row.connections, 0)}
+
tps: {formatNumber(row.tps, 2)}
+
cache: {formatNumber(row.cache, 2)}%
+
+ ); +} + async function loadMetric(targetId, metric, range, tokens, refresh) { const { from, to } = toQueryRange(range); return apiFetch( @@ -91,13 +109,29 @@ export function TargetDetailPage() { }, [id, range, tokens, refresh]); const chartData = useMemo( - () => - (series.connections || []).map((point, idx) => ({ - ts: new Date(point.ts).toLocaleTimeString(), - connections: point.value, - xacts: series.xacts?.[idx]?.value || 0, - cache: series.cache?.[idx]?.value || 0, - })), + () => { + const con = series.connections || []; + const xacts = series.xacts || []; + const cache = series.cache || []; + return con.map((point, idx) => { + const prev = xacts[idx - 1]; + const curr = xacts[idx]; + let tps = 0; + if (prev && curr) { + const dt = (new Date(curr.ts).getTime() - new Date(prev.ts).getTime()) / 1000; + const dx = (curr.value || 0) - (prev.value || 0); + if (dt > 0 && dx >= 0) { + tps = dx / dt; + } + } + return { + ts: new Date(point.ts).toLocaleTimeString(), + connections: point.value, + tps, + cache: (cache[idx]?.value || 0) * 100, + }; + }); + }, [series] ); @@ -232,11 +266,12 @@ export function TargetDetailPage() { - - - - - + + + } /> + + + diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 98ddcb0..6f2c718 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -359,6 +359,37 @@ td { margin: 8px 0 0 18px; } +.chart-tooltip { + background: #0f1934ee; + border: 1px solid #2f4a8b; + border-radius: 10px; + padding: 10px 12px; + min-width: 170px; +} + +.chart-tooltip-time { + font-size: 12px; + color: #9cb2d8; + margin-bottom: 6px; +} + +.chart-tooltip-item { + font-size: 14px; + margin: 3px 0; +} + +.chart-tooltip-item.c1 { + color: #38bdf8; +} + +.chart-tooltip-item.c2 { + color: #22c55e; +} + +.chart-tooltip-item.c3 { + color: #f59e0b; +} + @media (max-width: 980px) { body { overflow: auto;