feat(alerts): live-refresh the table every 15s while the tab is visible

The alerts list is the one screen where staleness is genuinely
harmful — an operator can be looking at an Open tab that's already
been resolved by another admin or auto-resolved by the engine, and
take action on a row that no longer exists.

Add an htmx poll on just the table panel:

  hx-get        same URL with current querystring (filters preserved)
  hx-trigger    every 15s, only when document is visible (no idle CPU)
  hx-select     #alerts-table — pull this element out of the response
  hx-swap       outerHTML

Polling lives on the table div, not the page root, so the filter
strip and header don't flash on each tick. Header gains a small
'live ●' label so the polling is discoverable.

RefreshURL is r.URL.RequestURI() on the server side — keeps any
status/severity/host_id/q params intact across refreshes.

Other screens (dashboard, hosts, jobs) deliberately stay manual-
refresh per the project's anti-flicker stance.
This commit is contained in:
2026-05-04 23:30:19 +01:00
parent 85c62741b5
commit 595656ed59
2 changed files with 26 additions and 8 deletions
+15 -3
View File
@@ -90,8 +90,18 @@
</form>
</div>
{{/* alerts table */}}
<div class="panel mt-3.5 rounded-[7px] overflow-hidden">
{{/* alerts table — polled every 15s while the tab is visible.
hx-get re-fetches the same URL (so filter querystring is preserved)
and hx-select pulls just this element out of the full response,
replacing the live one. Pauses automatically when the tab is
backgrounded so we're not burning CPU on inactive tabs.
The polling lives here (not on the page root) so the filter strip
and header don't flash on each tick. */}}
<div id="alerts-table" class="panel mt-3.5 rounded-[7px] overflow-hidden"
hx-get="{{$page.RefreshURL}}"
hx-trigger="every 15s [document.visibilityState==='visible']"
hx-select="#alerts-table"
hx-swap="outerHTML">
{{/* header row */}}
<div class="alert-row head">
@@ -101,7 +111,9 @@
<div>Message</div>
<div>Raised</div>
<div>Last seen</div>
<div></div>
<div>
<span class="text-ink-fade" style="font-size: 10px;" title="auto-refresh every 15s">live ●</span>
</div>
</div>
{{if eq (len $page.Alerts) 0}}