diff --git a/apps/web/src/views/home.ejs b/apps/web/src/views/home.ejs index bd933ff..3a3f6eb 100644 --- a/apps/web/src/views/home.ejs +++ b/apps/web/src/views/home.ejs @@ -53,9 +53,15 @@ const downCount = monitorsWithPings.filter(m => m.pings[0]?.up === false).length; summary.innerHTML = `${upCount} up · ${downCount} down · ${monitors.length} total`; + // Store latencies per monitor for live sparkline updates + window._monitorLatencies = window._monitorLatencies || {}; + monitorsWithPings.forEach(m => { + window._monitorLatencies[m.id] = m.pings.filter(c => c.latency_ms != null).map(c => c.latency_ms).reverse(); + }); + list.innerHTML = monitorsWithPings.map(m => { const lastPing = m.pings[0]; - const latencies = m.pings.filter(c => c.latency_ms != null).map(c => c.latency_ms).reverse(); + const latencies = window._monitorLatencies[m.id]; const avgLatency = latencies.length ? Math.round(latencies.reduce((a, b) => a + b, 0) / latencies.length) : null; return ` @@ -69,7 +75,7 @@
- +
${avgLatency != null ? avgLatency + 'ms' : '—'}
${lastPing ? timeAgo(lastPing.checked_at) : 'no pings'}
@@ -96,17 +102,28 @@ const monitors = await api('/monitors/'); monitors.forEach(m => { const es = watchMonitor(m.id, (ping) => { - // Update the card's last ping info without full reload const card = document.querySelector(`[data-monitor-id="${m.id}"]`); if (!card) return; + + // Status dot const statusDot = card.querySelector('.status-dot'); - const latencyEl = card.querySelector('.stat-latency'); - const lastEl = card.querySelector('.stat-last'); - if (statusDot) { - statusDot.className = `status-dot w-2.5 h-2.5 rounded-full ${ping.up ? 'bg-green-500' : 'bg-red-500'}`; + if (statusDot) statusDot.className = `status-dot w-2.5 h-2.5 rounded-full ${ping.up ? 'bg-green-500' : 'bg-red-500'}`; + + // Latency text + if (ping.latency_ms) card.querySelector('.stat-latency').textContent = `${ping.latency_ms}ms`; + + // Timestamp + card.querySelector('.stat-last').innerHTML = timeAgo(ping.checked_at); + + // Sparkline — push new value, keep last 20, redraw + if (ping.latency_ms != null) { + const lats = window._monitorLatencies[m.id] || []; + lats.push(ping.latency_ms); + if (lats.length > 20) lats.shift(); + window._monitorLatencies[m.id] = lats; + const sparkEl = card.querySelector('.stat-sparkline'); + if (sparkEl) sparkEl.innerHTML = sparkline(lats); } - if (latencyEl && ping.latency_ms) latencyEl.textContent = `${ping.latency_ms}ms`; - if (lastEl) lastEl.innerHTML = timeAgo(ping.checked_at); }); if (es) sseConnections.push(es); });