From 357918013d617ed1afad324ed0834f9bc7a9c3c1 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Mar 2026 04:03:57 -0500 Subject: [PATCH] Compact sentinel card: single-line with mini ring + collapsible verdicts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Entire sentinel status fits in one header row now - Mini 28px countdown ring (was 64px) inline with title - Scans/bans counts inline as text, not grid boxes - Verdicts collapsed by default — click to expand - Card padding reduced (8px vs 14px) Co-Authored-By: Claude Opus 4.6 (1M context) --- llm_team_ui.py | 99 +++++++++++++++++++------------------------------- 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/llm_team_ui.py b/llm_team_ui.py index 5cc3c5d..117bf93 100644 --- a/llm_team_ui.py +++ b/llm_team_ui.py @@ -740,7 +740,7 @@ async function loadThreats() { // Sentinel status card var sentinelCard = document.createElement('div'); - sentinelCard.style.cssText = 'background:rgba(0,0,0,0.3);border:2px solid rgba(217,70,239,0.3);border-radius:2px;padding:14px;margin-bottom:16px;backdrop-filter:blur(16px)'; + sentinelCard.style.cssText = 'background:rgba(0,0,0,0.3);border:2px solid rgba(217,70,239,0.3);border-radius:2px;padding:8px 12px;margin-bottom:12px;backdrop-filter:blur(16px)'; var sHeader = document.createElement('div'); sHeader.style.cssText = 'display:flex;align-items:center;gap:8px;margin-bottom:8px'; var sDot = document.createElement('div'); @@ -748,85 +748,61 @@ async function loadThreats() { var sTitle = document.createElement('span'); sTitle.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#d946ef;font-weight:700'; sTitle.textContent = 'AI Sentinel — ' + (sentinel.model || '?'); - sHeader.appendChild(sDot);sHeader.appendChild(sTitle);sentinelCard.appendChild(sHeader); + sHeader.appendChild(sDot);sHeader.appendChild(sTitle); - // Countdown + metrics row + // Inline stats + countdown — all in one row var ss = sentinel.stats || {}; var nextIn = sentinel.next_scan_in || 0; var interval = sentinel.interval || 300; - - var metricsRow = document.createElement('div'); - metricsRow.style.cssText = 'display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:center;margin-bottom:10px'; - - // Countdown ring - var ringWrap = document.createElement('div'); - ringWrap.style.cssText = 'position:relative;width:64px;height:64px;flex-shrink:0'; var pct = interval > 0 ? ((interval - nextIn) / interval) : 0; - var deg = Math.round(pct * 360); - ringWrap.innerHTML = '' - + '' - + '' - + ''; - var countText = document.createElement('div'); - countText.id = 'sentinel-countdown'; - countText.style.cssText = 'position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:JetBrains Mono,monospace'; - var countNum = document.createElement('div'); - countNum.style.cssText = 'font-size:16px;font-weight:700;color:#d946ef;line-height:1'; - countNum.textContent = Math.ceil(nextIn) + 's'; - var countLabel = document.createElement('div'); - countLabel.style.cssText = 'font-size:7px;color:#7a7872;text-transform:uppercase;letter-spacing:1px;margin-top:2px'; - countLabel.textContent = 'next scan'; - countText.appendChild(countNum); countText.appendChild(countLabel); - ringWrap.appendChild(countText); - metricsRow.appendChild(ringWrap); - // Stats grid - var statsGrid = document.createElement('div'); - statsGrid.style.cssText = 'display:grid;grid-template-columns:repeat(4,1fr);gap:6px'; - [{v:ss.scans||0,l:'Scans',c:'#d946ef'},{v:ss.bans||0,l:'AI Bans',c:'#e05252'},{v:ss.last_run||'—',l:'Last Run',c:'#e8e6e3',small:true},{v:(sentinel.interval||300)+'s',l:'Interval',c:'#7a7872'}].forEach(function(m){ - var box = document.createElement('div'); - box.style.cssText = 'text-align:center'; - var val = document.createElement('div'); - val.style.cssText = 'font-family:JetBrains Mono,monospace;font-weight:700;color:'+m.c+';font-size:'+(m.small?'10px':'14px'); - val.textContent = m.v; - var lab = document.createElement('div'); - lab.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:7px;text-transform:uppercase;letter-spacing:1px;color:#7a7872;margin-top:2px'; - lab.textContent = m.l; - box.appendChild(val);box.appendChild(lab);statsGrid.appendChild(box); - }); - metricsRow.appendChild(statsGrid); - sentinelCard.appendChild(metricsRow); + // Mini ring + var ring = document.createElement('span'); + ring.style.cssText = 'position:relative;width:28px;height:28px;flex-shrink:0;display:inline-block;vertical-align:middle;margin-left:auto'; + ring.innerHTML = ''; + var countTxt = document.createElement('span'); + countTxt.id = 'sentinel-countdown'; + countTxt.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-family:JetBrains Mono,monospace;font-size:8px;font-weight:700;color:#d946ef'; + countTxt.textContent = Math.ceil(nextIn) + ''; + ring.appendChild(countTxt); + sHeader.appendChild(ring); - // Start countdown timer + // Compact stats inline + var inlineStats = document.createElement('span'); + inlineStats.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:#7a7872;display:flex;gap:10px;margin-left:8px'; + inlineStats.innerHTML = ''+(ss.scans||0)+' scans'+(ss.bans||0)+' bans'; + sHeader.appendChild(inlineStats); + + sentinelCard.appendChild(sHeader); + + // Start countdown if (window._sentinelTimer) clearInterval(window._sentinelTimer); window._sentinelCountdown = nextIn; window._sentinelTimer = setInterval(function(){ window._sentinelCountdown = Math.max(0, window._sentinelCountdown - 1); var el = document.getElementById('sentinel-countdown'); - if (el) el.querySelector('div').textContent = Math.ceil(window._sentinelCountdown) + 's'; - if (window._sentinelCountdown <= 0) { - clearInterval(window._sentinelTimer); - var el2 = document.getElementById('sentinel-countdown'); - if (el2) { el2.querySelector('div').textContent = 'scanning...'; el2.querySelector('div').style.color = '#4ade80'; } - } + if (el) { el.textContent = Math.ceil(window._sentinelCountdown) || '...'; if (window._sentinelCountdown <= 0) { el.textContent = '✓'; el.style.color = '#4ade80'; clearInterval(window._sentinelTimer); } } }, 1000); if (ss.last_error) { var sErr = document.createElement('div'); - sErr.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:#e05252;border-left:2px solid #e05252;padding-left:8px;margin-bottom:8px'; - sErr.textContent = 'Last error: ' + ss.last_error; + sErr.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:#e05252;border-left:2px solid #e05252;padding-left:8px;margin-bottom:4px'; + sErr.textContent = 'Error: ' + ss.last_error; sentinelCard.appendChild(sErr); } - // Recent AI verdicts + // Recent AI verdicts — collapsible var verdicts = sentinel.recent_verdicts || []; if (verdicts.length) { - var vTitle = document.createElement('div'); - vTitle.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;letter-spacing:2px;color:#d946ef;margin:10px 0 6px;opacity:0.6'; - vTitle.textContent = 'Recent AI Verdicts'; - sentinelCard.appendChild(vTitle); + var vToggle = document.createElement('div'); + vToggle.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;letter-spacing:1.5px;color:#d946ef;margin:4px 0 0;opacity:0.5;cursor:pointer'; + vToggle.textContent = '▶ ' + verdicts.length + ' recent verdicts'; + var vList = document.createElement('div'); + vList.style.display = 'none'; + vToggle.onclick = function(){ + if (vList.style.display === 'none') { vList.style.display = 'block'; vToggle.textContent = '▼ ' + verdicts.length + ' recent verdicts'; vToggle.style.opacity = '1'; } + else { vList.style.display = 'none'; vToggle.textContent = '▶ ' + verdicts.length + ' recent verdicts'; vToggle.style.opacity = '0.5'; } + }; + sentinelCard.appendChild(vToggle); verdicts.slice(0,8).forEach(function(v){ var vLine = document.createElement('div'); vLine.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:10px;color:#7a7872;padding:3px 0;border-bottom:1px solid rgba(42,45,53,0.3);display:flex;gap:8px'; @@ -835,8 +811,9 @@ async function loadThreats() { + ''+esc(v.ip||'?')+'' + ''+esc(v.attack_type||'?')+'' + ''+esc(v.reason||'')+''; - sentinelCard.appendChild(vLine); + vList.appendChild(vLine); }); + sentinelCard.appendChild(vList); } view.appendChild(sentinelCard);