From 2ede06f32ada69810e276daaa2d001dce4b62031 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:42:10 +0200 Subject: [PATCH] fix: chart Y-axis auto-scaling, error rate unit, memory reference line, pointer events - Throughput chart: divide totalCount by bucket duration (seconds) so Y-axis shows true msg/s instead of raw bucket counts; fixes flat-line appearance when TPS is low but totalCount is large - Error Rate chart: convert failedCount/totalCount to percentage; change yLabel from "err/h" to "%" to match KPI stat card unit - Memory chart: add threshold line at jvm.memory.heap.max so chart Y-axis extends to max heap and shows the reference line (spec 5.3) - Agent state: suppress containerStatus badge when value is "UNKNOWN"; only render it with "Container: " label when a non-UNKNOWN secondary state is present (spec 5.4) - DashboardTab chartGrid: add pointer-events:none with pointer-events:auto on children so the chart grid overlay does not intercept clicks on the Application Health table rows below (spec 5.5) Co-Authored-By: Claude Sonnet 4.6 --- ui/src/pages/AgentInstance/AgentInstance.tsx | 40 ++++++++++++------- .../DashboardTab/DashboardTab.module.css | 5 +++ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/ui/src/pages/AgentInstance/AgentInstance.tsx b/ui/src/pages/AgentInstance/AgentInstance.tsx index ba583f45..4649b5e3 100644 --- a/ui/src/pages/AgentInstance/AgentInstance.tsx +++ b/ui/src/pages/AgentInstance/AgentInstance.tsx @@ -66,16 +66,20 @@ export default function AgentInstance() { 60, ); - const chartData = useMemo( - () => - (timeseries?.buckets || []).map((b: any) => ({ - time: new Date(b.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), - throughput: b.totalCount, - latency: b.avgDurationMs, - errors: b.failedCount, - })), - [timeseries], - ); + const chartData = useMemo(() => { + const buckets: any[] = timeseries?.buckets || []; + // Compute bucket duration in seconds from consecutive timestamps (for msg/s conversion) + const bucketSecs = + buckets.length >= 2 + ? (new Date(buckets[1].timestamp).getTime() - new Date(buckets[0].timestamp).getTime()) / 1000 + : 60; + return buckets.map((b: any) => ({ + time: new Date(b.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), + throughput: bucketSecs > 0 ? b.totalCount / bucketSecs : b.totalCount, + latency: b.avgDurationMs, + errorPct: b.totalCount > 0 ? (b.failedCount / b.totalCount) * 100 : 0, + })); + }, [timeseries]); const feedEvents = useMemo(() => { const mapped = (events || []) @@ -118,7 +122,7 @@ export default function AgentInstance() { const throughputSeries = useMemo( () => chartData.length - ? [{ label: 'Throughput', data: chartData.map((d: any, i: number) => ({ x: i, y: d.throughput })) }] + ? [{ label: 'msg/s', data: chartData.map((d: any, i: number) => ({ x: i, y: d.throughput })) }] : null, [chartData], ); @@ -126,7 +130,7 @@ export default function AgentInstance() { const errorSeries = useMemo( () => chartData.length - ? [{ label: 'Errors', data: chartData.map((d: any, i: number) => ({ x: i, y: d.errors })) }] + ? [{ label: 'Error %', data: chartData.map((d: any, i: number) => ({ x: i, y: d.errorPct })) }] : null, [chartData], ); @@ -229,6 +233,9 @@ export default function AgentInstance() { {agent.displayName} + {agent.containerStatus && agent.containerStatus !== 'UNKNOWN' && ( + + )} {agent.version && } {heapSeries ? ( - + ) : ( )} @@ -352,7 +364,7 @@ export default function AgentInstance() { {errorSeries ? ( - + ) : ( )} diff --git a/ui/src/pages/DashboardTab/DashboardTab.module.css b/ui/src/pages/DashboardTab/DashboardTab.module.css index 2c6d0f16..ce114578 100644 --- a/ui/src/pages/DashboardTab/DashboardTab.module.css +++ b/ui/src/pages/DashboardTab/DashboardTab.module.css @@ -14,6 +14,11 @@ display: grid; grid-template-columns: 1fr 1fr; gap: 16px; + pointer-events: none; +} + +.chartGrid > * { + pointer-events: auto; } .chartRow {