diff --git a/apps/web/src/dashboard/app.js b/apps/web/src/dashboard/app.js
index 5e392b6..d944cfc 100644
--- a/apps/web/src/dashboard/app.js
+++ b/apps/web/src/dashboard/app.js
@@ -44,14 +44,28 @@ async function api(path, opts = {}) {
}
// Format relative time
-function timeAgo(date) {
- const s = Math.floor((Date.now() - new Date(date).getTime()) / 1000);
- if (s < 60) return `${s}s ago`;
+function formatAgo(ms) {
+ const s = Math.floor(ms / 1000);
+ if (s < 60) return `${s}s ago`;
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
- if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
+ if (s < 86400)return `${Math.floor(s / 3600)}h ago`;
return `${Math.floor(s / 86400)}d ago`;
}
+function timeAgo(date) {
+ const ts = new Date(date).getTime();
+ const elapsed = Date.now() - ts;
+ return `${formatAgo(elapsed)}`;
+}
+
+// Tick all live timestamps every second
+setInterval(() => {
+ document.querySelectorAll('.timestamp[data-ts]').forEach(el => {
+ const elapsed = Date.now() - Number(el.dataset.ts);
+ el.textContent = formatAgo(elapsed);
+ });
+}, 1000);
+
// Render a tiny sparkline SVG from latency values
function sparkline(values, width = 120, height = 32) {
if (!values.length) return '';
diff --git a/apps/web/src/views/detail.ejs b/apps/web/src/views/detail.ejs
index 4837076..d5d58bf 100644
--- a/apps/web/src/views/detail.ejs
+++ b/apps/web/src/views/detail.ejs
@@ -164,7 +164,7 @@
: '—';
document.getElementById('stat-latency').textContent = avgLatency != null ? `${avgLatency}ms` : '—';
document.getElementById('stat-uptime').textContent = uptime != null ? `${uptime}%` : '—';
- document.getElementById('stat-last').textContent = lastPing ? timeAgo(lastPing.checked_at) : '—';
+ document.getElementById('stat-last').innerHTML = lastPing ? timeAgo(lastPing.checked_at) : '—';
// Latency chart
renderLatencyChart(results.slice().reverse());