[object Object]

← back to Ventura Claw

Wizard: bulk health strip — see all saved connectors auth status at a glance

1ad784f8160a44aedf062eb2b075e0f9fc6b68d9 · 2026-05-06 16:58:34 -0700 · SteveStudio2

- New strip at top of wizard shows one pill per filled connector (✓ ok / ⊘ catalog-only / ✗ rejected)
- Pulls from existing /api/connectors/health-all (30s cached, no rate hit)
- Click a pill to insert that connector into the wizard queue at current cursor
  (handy for fixing a broken one without leaving the page)
- Re-test button refreshes the strip on demand
- Connectors absent from /health-all (catalog-only filled) render as ⊘ skipped, not stuck-in-testing
- Summary line: 'N authenticate · M no test handler · K rejected'

Files touched

Diff

commit 1ad784f8160a44aedf062eb2b075e0f9fc6b68d9
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 6 16:58:34 2026 -0700

    Wizard: bulk health strip — see all saved connectors auth status at a glance
    
    - New strip at top of wizard shows one pill per filled connector (✓ ok / ⊘ catalog-only / ✗ rejected)
    - Pulls from existing /api/connectors/health-all (30s cached, no rate hit)
    - Click a pill to insert that connector into the wizard queue at current cursor
      (handy for fixing a broken one without leaving the page)
    - Re-test button refreshes the strip on demand
    - Connectors absent from /health-all (catalog-only filled) render as ⊘ skipped, not stuck-in-testing
    - Summary line: 'N authenticate · M no test handler · K rejected'
---
 server/public/admin-wizard.html | 93 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/server/public/admin-wizard.html b/server/public/admin-wizard.html
index 309f779..73837bc 100644
--- a/server/public/admin-wizard.html
+++ b/server/public/admin-wizard.html
@@ -83,6 +83,34 @@
   .done-card .checkmark { font-size:64px; color:var(--good); margin-bottom:16px; }
   .done-card .stat { font-family:var(--serif); font-size:36px; color:var(--gold); margin:18px 0 8px 0; }
   .done-card .stat-label { font-family:var(--mono); font-size:11px; color:var(--ink-mute); letter-spacing:0.14em; text-transform:uppercase; }
+
+  /* Health strip — bulk-test view of every filled connector */
+  .health-strip {
+    margin-bottom: 22px; padding: 14px 18px;
+    background: var(--bg-2); border: 1px solid var(--rule); border-radius: 4px;
+  }
+  .health-strip-header {
+    display: flex; align-items: center; gap: 10px; margin-bottom: 10px;
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-mute);
+  }
+  .health-strip-header .retest {
+    margin-left: auto; padding: 5px 12px; border-radius: 2px; cursor: pointer;
+    font-family: var(--mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase;
+    background: transparent; color: var(--gold); border: 1px solid var(--gold);
+  }
+  .health-strip-header .retest:hover { background: rgba(212,160,74,0.10); }
+  .health-pills { display: flex; flex-wrap: wrap; gap: 6px; }
+  .health-pill {
+    padding: 5px 10px; border-radius: 12px; font-family: var(--mono); font-size: 11px;
+    border: 1px solid var(--rule); display: inline-flex; align-items: center; gap: 6px;
+    cursor: pointer; transition: filter 120ms ease;
+  }
+  .health-pill:hover { filter: brightness(1.15); }
+  .health-pill.ok       { background: rgba(143,184,154,0.10); border-color: var(--good);   color: var(--good); }
+  .health-pill.skipped  { background: rgba(212,160,74,0.06);  border-color: var(--ink-faint); color: var(--ink-mute); }
+  .health-pill.bad      { background: rgba(200,122,110,0.12); border-color: var(--bad);    color: var(--bad); }
+  .health-pill.testing  { background: var(--bg-3); color: var(--ink-mute); }
+  .health-pill .pill-icon { font-weight: 700; }
 </style>
 </head><body>
 
@@ -97,6 +125,15 @@
     <div class="progress-text"><span id="pos">0/0</span><span id="filled">0 connected</span></div>
   </div>
 
+  <div class="health-strip" id="health-strip" style="display:none">
+    <div class="health-strip-header">
+      <span>✦ Already saved · live health</span>
+      <span id="health-summary" style="color:var(--ink-faint);text-transform:none;letter-spacing:0">…</span>
+      <button class="retest" id="health-retest">Re-test</button>
+    </div>
+    <div class="health-pills" id="health-pills"></div>
+  </div>
+
   <div id="card" class="card">
     <div class="step-tag" id="step-tag">loading…</div>
     <h2 id="conn-name"></h2>
@@ -133,18 +170,72 @@ function toast(msg, isError) {
   toast._t = setTimeout(() => t.style.display = 'none', 3500);
 }
 
+let allFilled = []; // connections that already have credentials saved (for the health strip)
+
 async function load() {
   const r = await fetch('/api/me/connections');
   const d = await r.json();
   totalCatalog = d.connections.length;
   allConnectors = d.connections.filter(c => !c.filled);
+  allFilled = d.connections.filter(c => c.filled);
   // Already-connected count
   const filled = totalCatalog - allConnectors.length;
   $('#filled').textContent = filled + ' / ' + totalCatalog + ' connected';
+  // Show health strip if any are saved
+  if (allFilled.length) {
+    $('#health-strip').style.display = 'block';
+    renderHealthStrip();           // initial pass: testing… state
+    refreshHealth();                // hit /api/connectors/health-all in background
+  }
   if (!allConnectors.length) return showDone(filled, totalCatalog);
   render();
 }
 
+function renderHealthStrip(healthData) {
+  const wrap = $('#health-pills');
+  wrap.innerHTML = '';
+  for (const c of allFilled) {
+    const h = healthData ? healthData[c.id] : undefined;
+    let cls = 'testing', icon = '…', title = 'testing…';
+    if (healthData) {
+      // /health-all only probes real-impl connectors; absence means catalog-only
+      if (!h) { cls = 'skipped'; icon = '⊘'; title = 'catalog-only — no test handler yet'; }
+      else if (h.ok) { cls = 'ok'; icon = '✓'; title = h.label || h.account || h.business || h.email || 'authenticated'; }
+      else if (h.reason === 'not_implemented') { cls = 'skipped'; icon = '⊘'; title = 'no test handler — credentials stored'; }
+      else { cls = 'bad'; icon = '✗'; title = h.reason || h.error || 'failed'; }
+    }
+    const pill = document.createElement('span');
+    pill.className = 'health-pill ' + cls;
+    pill.title = c.name + ' · ' + title;
+    pill.innerHTML = '<span class="pill-icon">' + icon + '</span> ' + esc(c.name);
+    pill.addEventListener('click', () => {
+      // Click pill → push that connector to the queue at the current cursor and re-render
+      if (!allConnectors.find(x => x.id === c.id)) {
+        allConnectors.splice(cursor, 0, c);
+      }
+      render();
+    });
+    wrap.appendChild(pill);
+  }
+  if (healthData) {
+    const ok = allFilled.filter(c => healthData[c.id]?.ok).length;
+    const skipped = allFilled.filter(c => !healthData[c.id] || healthData[c.id]?.reason === 'not_implemented').length;
+    const bad = allFilled.length - ok - skipped;
+    $('#health-summary').textContent = ok + ' authenticate · ' + skipped + ' no test handler · ' + bad + ' rejected';
+  }
+}
+
+async function refreshHealth() {
+  $('#health-summary').textContent = 'testing all…';
+  try {
+    const r = await fetch('/api/connectors/health-all');
+    const j = await r.json();
+    renderHealthStrip(j.data || {});
+  } catch (e) {
+    $('#health-summary').textContent = 'health probe failed: ' + e.message;
+  }
+}
+
 function render() {
   const c = allConnectors[cursor];
   if (!c) return showDone(totalCatalog - allConnectors.length + cursor, totalCatalog);
@@ -292,6 +383,8 @@ $('#btn-vault').addEventListener('click', async () => {
   }
 });
 
+$('#health-retest').addEventListener('click', refreshHealth);
+
 // Cmd/Ctrl-Enter to save
 document.addEventListener('keydown', e => {
   if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {

← 437cf54 Wizard: Test button — saves + validates against connector he  ·  back to Ventura Claw  ·  ENV_KEY_TO_CONNECTOR: align field names with what the handle a6a5067 →