fix: client-side sparkline with local buffer, no server fetch on update

This commit is contained in:
M1 2026-03-17 07:38:26 +04:00
parent 6929d8f51f
commit 72bc11813d
1 changed files with 46 additions and 19 deletions

View File

@ -75,9 +75,44 @@
} catch {}
}, 30000);
// SSE: on each ping, update text fields and fetch fresh sparkline
const _fetchingSparkline = new Set();
watchAccount(async (ping) => {
// Client-side sparkline — seed with SSR data, update locally on SSE
const _sparkData = {
<% it.monitors.forEach(function(m, i) {
const lats = (m.pings || []).filter(p => p.latency_ms != null).map(p => p.latency_ms);
%>'<%= m.id %>': [<%- lats.join(',') %>]<% if (i < it.monitors.length - 1) { %>,<% } %>
<% }) %>
};
function drawSparkline(values, el) {
const W = 120, H = 32;
if (!values.length) { el.innerHTML = ''; return; }
const max = Math.max(...values, 1);
const min = Math.min(...values, 0);
const range = max - min || 1;
const step = W / Math.max(values.length - 1, 1);
const pts = values.map((v, i) => {
const x = i * step;
const y = H - ((v - min) / range) * (H - 4) - 2;
return `${x},${y}`;
}).join(' ');
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', `0 0 ${W} ${H}`);
svg.setAttribute('width', W);
svg.setAttribute('height', H);
const pl = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
pl.setAttribute('points', pts);
pl.setAttribute('fill', 'none');
pl.setAttribute('stroke', '#60a5fa');
pl.setAttribute('stroke-width', '1.5');
pl.setAttribute('stroke-linecap', 'round');
pl.setAttribute('stroke-linejoin', 'round');
svg.appendChild(pl);
const old = el.querySelector('svg');
if (old) old.replaceWith(svg); else el.appendChild(svg);
}
// SSE: update cards in realtime
watchAccount((ping) => {
const card = document.querySelector(`[data-monitor-id="${ping.monitor_id}"]`);
if (!card) return;
@ -89,22 +124,14 @@
if (ping.latency_ms != null) card.querySelector('.stat-latency').textContent = ping.latency_ms + 'ms';
card.querySelector('.stat-last').innerHTML = timeAgo(ping.checked_at);
// Sparkline
// Sparkline — update buffer and redraw locally
if (ping.latency_ms != null) {
const buf = _sparkData[ping.monitor_id] = _sparkData[ping.monitor_id] || [];
buf.push(ping.latency_ms);
if (buf.length > 20) buf.shift();
const sparkEl = card.querySelector('.stat-sparkline');
if (!sparkEl || _fetchingSparkline.has(ping.monitor_id)) return;
_fetchingSparkline.add(ping.monitor_id);
try {
const res = await fetch(`/dashboard/monitors/${ping.monitor_id}/sparkline`, { credentials: 'same-origin' });
if (res.ok) {
const tmp = document.createElement('div');
tmp.innerHTML = await res.text();
const newSvg = tmp.firstElementChild;
const oldSvg = sparkEl.querySelector('svg');
if (newSvg && oldSvg) oldSvg.replaceWith(newSvg);
else if (newSvg) sparkEl.appendChild(newSvg);
if (sparkEl) drawSparkline(buf, sparkEl);
}
} catch {}
_fetchingSparkline.delete(ping.monitor_id);
});
</script>