From 10dfd8ffd23c5238a2bb59c4d587a7dd89f8bff0 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 20 Jun 2026 12:25:51 -0400 Subject: [PATCH] fix(host_agent): update full-metrics charts in place to kill refresh flicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The live refresh re-created the Chart.js charts each poll, which blanked the canvases and re-ran the grow-in animation — a jarring flash/jump every cycle. Make the canvases persistent in the page shell and poll only the data: - The 3 chart canvases + their Chart instances are created once in the shell, with animation disabled. - /charts is now a data-only fragment swapped into a hidden div; it calls window.applyHostSeries(series, range), which sets each dataset's data and calls chart.update("none") — in-place, no re-create, no animation, fixed height. Range labels update via .hm-chart-range spans. - Current-state fragment keeps its atomic innerHTML poll into fixed-height cards, so numbers update without a layout jump. Net: live updates morph smoothly with no flicker or layout shift. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC --- .../host_agent/templates/_host_charts.html | 72 +------------- plugins/host_agent/templates/host_detail.html | 98 ++++++++++++++++--- 2 files changed, 91 insertions(+), 79 deletions(-) diff --git a/plugins/host_agent/templates/_host_charts.html b/plugins/host_agent/templates/_host_charts.html index 96bc142..72899ee 100644 --- a/plugins/host_agent/templates/_host_charts.html +++ b/plugins/host_agent/templates/_host_charts.html @@ -1,70 +1,6 @@ -{# History-charts fragment for the full-metrics page — lazy-loaded via HTMX so - the date_bin history query never blocks the page shell, and refreshed on a - slow cadence / range change. #} -
-
-
Utilization % — last {{ range_key }}
-
-
-
-
Throughput (B/s) — last {{ range_key }}
-
-
-
-
Load & pressure — last {{ range_key }}
-
-
-
- +{# History data-only fragment. Swapped into the hidden #hm-charts-data poller; + the script runs and feeds the persistent charts created by host_detail.html, + updating them in place (no canvas swap → no flicker / no re-animation). #} diff --git a/plugins/host_agent/templates/host_detail.html b/plugins/host_agent/templates/host_detail.html index 44b4bb2..359b1fc 100644 --- a/plugins/host_agent/templates/host_detail.html +++ b/plugins/host_agent/templates/host_detail.html @@ -3,15 +3,17 @@ {% block title %}{{ host.name }} — Metrics — Steward{% endblock %} {% block breadcrumb %}{{ crumbs([("Hosts", "/hosts/"), (host.name, "/hosts/" ~ host.id), ("Metrics", "")]) }}{% endblock %} {% block content %} -{# Shell only: the current-state and history-chart sections stream in via HTMX - below, so the heavy history query never blocks first paint and the data - refreshes live (≈ the agent's push cadence) without a full reload. #} +{# Shell only: current-state + history data stream in via HTMX so the heavy + history query never blocks first paint and the data refreshes live (≈ the + agent's push cadence). The chart CANVASES live here permanently — only their + data is polled and applied in place, so refreshes never re-create/flicker. #}

{{ host.name }}

{% include "_time_range.html" %}
-{# Current state — lazy + polled live (latest snapshot the server holds). #} +{# Current state — lazy + polled live. Atomic innerHTML swap of fixed-height + cards, so values update without a layout jump. #}
Loading metrics…
-{# History charts — lazy (never blocks paint), refreshed on a slow cadence and - on range change; range comes from the shared #time-range input. #} -
+
+
Utilization % — last {{ current_range }}
+
+
+
+
Throughput (B/s) — last {{ current_range }}
+
+
+
+
Load & pressure — last {{ current_range }}
+
+
+
+{# Hidden poller: fetches the history series and applies it to the charts above + (no visible swap). Lazy on load → never blocks paint; refreshed slowly + on + range change. #} + + hx-swap="innerHTML"> + + {% endblock %}