[object Object]

← back to Domain Sniper

dashboard ui: per-log source band with health dots

24e477fa13886422190d7822b5727e7012e1cc8b · 2026-05-12 18:08:36 -0700 · steve

Renders the perLog payload from the WebSocket stats broadcast as a
horizontal strip above the feed: one chip per active CT source showing
log-name + emitted count + idle count + colored health dot.

  green  = healthy (emitted > 0)
  yellow = alive but quiet (idle > 0, emitted == 0 this session)
  red    = stale (no tick/idle in 60s — wedged)

No dashboard restart needed; express.static serves the new HTML on
next page load. All 6 CT sources currently report green except Sectigo
elephant/tiger which sometimes show yellow during quiet bursts.

Files touched

Diff

commit 24e477fa13886422190d7822b5727e7012e1cc8b
Author: steve <steve@designerwallcoverings.com>
Date:   Tue May 12 18:08:36 2026 -0700

    dashboard ui: per-log source band with health dots
    
    Renders the perLog payload from the WebSocket stats broadcast as a
    horizontal strip above the feed: one chip per active CT source showing
    log-name + emitted count + idle count + colored health dot.
    
      green  = healthy (emitted > 0)
      yellow = alive but quiet (idle > 0, emitted == 0 this session)
      red    = stale (no tick/idle in 60s — wedged)
    
    No dashboard restart needed; express.static serves the new HTML on
    next page load. All 6 CT sources currently report green except Sectigo
    elephant/tiger which sometimes show yellow during quiet bursts.
---
 public/index.html | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/public/index.html b/public/index.html
index 50abeaa..efb0445 100644
--- a/public/index.html
+++ b/public/index.html
@@ -135,6 +135,10 @@
       <span id="conn">connecting…</span>
     </span>
   </div>
+  <div id="perlog-band" style="display:flex; gap:14px; padding:6px 14px; border-bottom:1px solid #1a1a1a; background:#0a0a0a; font-size:11px; color:var(--dim); overflow-x:auto; white-space:nowrap;">
+    <span style="color:#4ec9b0;">CT sources:</span>
+    <span id="perlog-empty">waiting…</span>
+  </div>
   <main id="feed"><div class="empty">waiting for the firehose…</div></main>
   <div id="toast" class="toast">copied</div>
 
@@ -329,6 +333,19 @@
     for (const el of [filterEl, showHot, showBrand]) el.addEventListener('input', scheduleRender);
     for (const el of [filterEl, showHot, showBrand]) el.addEventListener('change', scheduleRender);
 
+    const perlogBand = document.getElementById('perlog-band');
+    function renderPerLog(p) {
+      const names = Object.keys(p).sort();
+      if (!names.length) return;
+      const parts = names.map((name) => {
+        const v = p[name];
+        const short = name.replace(/2026h1$/, '');
+        const stale = v.stale ? 'background:#ff3b3b;' : (v.idle > 0 && v.emitted === 0 ? 'background:#e0a050;' : 'background:#4ec9b0;');
+        const dot = `<span style="display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:4px;vertical-align:middle;${stale}"></span>`;
+        return `<span title="${name}">${dot}<b style="color:#d4d4d4;">${short}</b> ${v.emitted}<span style="color:#5a5a5a;">/</span><span style="color:#5a5a5a;">i</span>${v.idle || 0}</span>`;
+      });
+      perlogBand.innerHTML = '<span style="color:#4ec9b0;">CT sources:</span>' + parts.join('');
+    }
     function connect() {
       const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
       const ws = new WebSocket(proto + '//' + location.host);
@@ -349,6 +366,7 @@
           stat.brand.textContent = m.brand.toLocaleString();
           startedAt = m.startedAt || startedAt;
           stat.uptime.textContent = fmtUptime(Date.now() - startedAt);
+          if (m.perLog) renderPerLog(m.perLog);
         }
       };
     }

← 7992d0c dashboard: per-log tracker + idle counter + /api/perlog endp  ·  back to Domain Sniper  ·  dashboard: /healthz liveness probe for pm2/launchd dfb3b86 →