From 6f0499d34b5227cf969e51b215230fe62806f565 Mon Sep 17 00:00:00 2001 From: nate Date: Thu, 19 Mar 2026 15:18:16 +0400 Subject: [PATCH] feat: combine status blips by run id --- apps/web/src/views/detail.ejs | 50 ++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/apps/web/src/views/detail.ejs b/apps/web/src/views/detail.ejs index f5eb334..481bd81 100644 --- a/apps/web/src/views/detail.ejs +++ b/apps/web/src/views/detail.ejs @@ -9,7 +9,19 @@ const latencies = pings.filter(p => p.latency_ms != null).map(p => p.latency_ms); const avgLatency = latencies.length ? Math.round(latencies.reduce((a, b) => a + b, 0) / latencies.length) : null; const uptime = pings.length ? Math.round((upPings.length / pings.length) * 100) : null; - const barPings = pings.slice(0, 60).reverse(); + // Group pings by run_id for status bar + const barRuns = []; + const runMap = {}; + for (const p of pings.slice(0, 120).reverse()) { + const rid = p.run_id || p.checked_at; + if (!runMap[rid]) { + runMap[rid] = { run_id: rid, up: 0, down: 0, checked_at: p.checked_at, latency_ms: p.latency_ms }; + barRuns.push(runMap[rid]); + } + if (p.up) runMap[rid].up++; else runMap[rid].down++; + } + // Keep last 60 runs + const barPings = barRuns.slice(-60); const chartPings = pings.slice().reverse(); %> @@ -80,8 +92,11 @@

Status History

<% if (barPings.length > 0) { %> - <% barPings.forEach(function(c) { %> -
+ <% barPings.forEach(function(c) { + const color = c.down === 0 ? 'bg-green-500/70' : (c.up === 0 ? 'bg-red-500/70' : 'bg-orange-400/70'); + const label = c.down === 0 ? 'Up' : (c.up === 0 ? 'Down' : 'Partial'); + %> +
<% }) %> <% } else { %>
No data
@@ -479,14 +494,31 @@ // Last ping document.getElementById('stat-last').innerHTML = timeAgo(ping.checked_at); - // Status bar — prepend segment, cap at 60 + // Status bar — group by run_id, cap at 60 const bar = document.getElementById('status-bar'); if (bar) { - const seg = document.createElement('div'); - seg.className = `flex-1 rounded-sm ${ping.up ? 'bg-green-500/70' : 'bg-red-500/70'}`; - seg.title = `${new Date(ping.checked_at).toLocaleString()} — ${ping.up ? 'Up' : 'Down'}${ping.latency_ms ? ' ' + ping.latency_ms + 'ms' : ''}`; - bar.prepend(seg); - while (bar.children.length > 60) bar.removeChild(bar.lastChild); + const rid = ping.run_id || ping.checked_at; + let existing = bar.querySelector(`[data-run="${rid}"]`); + if (existing) { + // Update existing run segment + const up = parseInt(existing.dataset.up || '0') + (ping.up ? 1 : 0); + const down = parseInt(existing.dataset.down || '0') + (ping.up ? 0 : 1); + existing.dataset.up = up; + existing.dataset.down = down; + const color = down === 0 ? 'bg-green-500/70' : (up === 0 ? 'bg-red-500/70' : 'bg-orange-400/70'); + const label = down === 0 ? 'Up' : (up === 0 ? 'Down' : 'Partial'); + existing.className = `flex-1 rounded-sm ${color}`; + existing.title = `${new Date(ping.checked_at).toLocaleString()} — ${label}`; + } else { + const seg = document.createElement('div'); + seg.className = `flex-1 rounded-sm ${ping.up ? 'bg-green-500/70' : 'bg-red-500/70'}`; + seg.dataset.run = rid; + seg.dataset.up = ping.up ? '1' : '0'; + seg.dataset.down = ping.up ? '0' : '1'; + seg.title = `${new Date(ping.checked_at).toLocaleString()} — ${ping.up ? 'Up' : 'Down'}`; + bar.appendChild(seg); + while (bar.children.length > 60) bar.removeChild(bar.firstChild); + } } // Pings table — prepend row, cap at 100