From f00c78116bc2d6a72791f52eff4afddd07998b72 Mon Sep 17 00:00:00 2001 From: M1 Date: Tue, 17 Mar 2026 07:23:54 +0400 Subject: [PATCH] fix: detail page updates all stats, status bar, pings table in realtime via SSE --- apps/web/src/views/detail.ejs | 61 +++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/apps/web/src/views/detail.ejs b/apps/web/src/views/detail.ejs index 298c764..55dac84 100644 --- a/apps/web/src/views/detail.ejs +++ b/apps/web/src/views/detail.ejs @@ -265,10 +265,67 @@ } }); - // SSE: on ping for this monitor, fetch fresh chart + // Running totals for incremental stat updates + let _total = <%= pings.length %>, _up = <%= upPings.length %>; + let _latSum = <%= latencies.reduce((a,b)=>a+b,0) %>, _latCount = <%= latencies.length %>; + + // SSE: update everything on ping let _fetchingChart = false; watchAccount(async (ping) => { - if (ping.monitor_id !== monitorId || _fetchingChart) return; + if (ping.monitor_id !== monitorId) return; + + // Accumulate + _total++; + if (ping.up) _up++; + if (ping.latency_ms != null) { _latSum += ping.latency_ms; _latCount++; } + + // Status + document.getElementById('stat-status').innerHTML = ping.up + ? 'Up' + : 'Down'; + document.getElementById('status-dot').innerHTML = ping.up + ? '' + : ''; + + // Avg latency + if (_latCount > 0) + document.getElementById('stat-latency').textContent = Math.round(_latSum / _latCount) + 'ms'; + + // Uptime + if (_total > 0) + document.getElementById('stat-uptime').textContent = Math.round((_up / _total) * 100) + '%'; + + // Last ping + document.getElementById('stat-last').innerHTML = timeAgo(ping.checked_at); + + // Status bar — prepend segment, cap at 60 + const bar = document.getElementById('status-bar'); + if (bar) { + const seg = document.createElement('div'); + seg.className = `flex-1 ${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); + } + + // Pings table — prepend row, cap at 100 + const tbody = document.getElementById('pings-table'); + if (tbody) { + const tr = document.createElement('tr'); + tr.className = 'hover:bg-gray-800/50'; + tr.innerHTML = ` + ${ping.up ? 'Up' : 'Down'} + ${ping.status_code ?? '—'} + ${ping.latency_ms != null ? ping.latency_ms + 'ms' : '—'} + ${timeAgo(ping.checked_at)} + ${ping.error ? escapeHtml(ping.error) : ''} + `; + tbody.prepend(tr); + while (tbody.children.length > 100) tbody.removeChild(tbody.lastChild); + } + + // Chart + if (_fetchingChart) return; _fetchingChart = true; try { const res = await fetch(`/dashboard/monitors/${monitorId}/chart`, { credentials: 'same-origin' });