From 69eb87ebc99a1eeb28bd4bd99fd6204961cc98f3 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Sat, 27 Jun 2026 10:35:33 -0700 Subject: [PATCH] feat(web-ui): improve Agents page legibility and scannability Targeted UI/UX polish on the Agents page, keeping the existing dark aesthetic and both Overview/Live view modes: - Add a readable --text-mute token (dark + light) and apply it to the summary chips, lane meta, and idle/offline status, which previously used the near-invisible --text-dim. - Event feed: demote the generic "Span Started/Completed" label to a quiet mono category tag and promote the tool name, with a left-edge accent by event kind (run/span/error/session). Scoped to #agents-content so other pages' feeds are unaffected. - Active-op pills: add a per-kind left accent bar (tool/subagent/run). - Lane sparkline: raise opacity and add a gradient so it actually reads. Co-Authored-By: Claude Opus 4.8 --- cmd/web-ui/static/modules/pages/agents.js | 15 ++++++-- cmd/web-ui/static/style.css | 46 ++++++++++++++++++++--- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/cmd/web-ui/static/modules/pages/agents.js b/cmd/web-ui/static/modules/pages/agents.js index 8635b8c..e724967 100644 --- a/cmd/web-ui/static/modules/pages/agents.js +++ b/cmd/web-ui/static/modules/pages/agents.js @@ -46,6 +46,14 @@ let _agentsRenderTimer = null; // ── Private helpers ────────────────────────────────────── +function eventKindClass(eventType) { + if (eventType === 'run.start' || eventType === 'run.end') return 'evt-run'; + if (eventType === 'span.start' || eventType === 'span.end') return 'evt-span'; + if (eventType === 'error') return 'evt-error'; + if (eventType === 'session.start' || eventType === 'session.end') return 'evt-session'; + return 'evt-other'; +} + function ensureAgentBucket(evt) { const identity = getAgentIdentity(evt); if (!identity.key) return null; @@ -258,7 +266,8 @@ function renderAgentLanes() { const opsHTML = ops.length > 0 ? `
${ops.map(op => { const elapsed = Math.floor((Date.now() - op.startedAt) / 1000); const stale = elapsed > 300; - const kindClass = op.kind === 'agent' || op.subType === 'subagent' ? ' subagent' : ''; + const kindClass = op.kind === 'agent' || op.subType === 'subagent' ? ' subagent' + : op.kind === 'run' ? ' run' : ''; return `
@@ -276,7 +285,7 @@ function renderAgentLanes() { const expandHTML = details ? '' : ''; return ` -
+
${getEventIcon(eventType)} ${escapeHTML(getEventLabel(eventType))} @@ -675,7 +684,7 @@ function renderAgentsLive() {
${group.events.map(evt => ` -
+
${getEventIcon(getEnvelopeType(evt))} ${escapeHTML(getEventLabel(getEnvelopeType(evt)))} diff --git a/cmd/web-ui/static/style.css b/cmd/web-ui/static/style.css index d7d1bbe..0b2da2e 100644 --- a/cmd/web-ui/static/style.css +++ b/cmd/web-ui/static/style.css @@ -12,6 +12,7 @@ --text: #b8c5d4; --text-dim: #465a6e; + --text-mute: #6b7f94; --text-bright: #e4edf5; --accent: #22d3ee; @@ -2147,6 +2148,7 @@ tr.expandable:hover .expand-icon::before { --text: #3d4a5c; --text-dim: #8b9ab0; + --text-mute: #5c6b80; --text-bright: #1a2332; --accent: #0891b2; @@ -2270,7 +2272,8 @@ tr.expandable:hover .expand-icon::before { padding: 0.6rem 1rem; font-family: var(--font-mono); font-size: 0.78rem; - color: var(--text-dim); + color: var(--text-mute); + letter-spacing: 0.02em; display: flex; align-items: center; gap: 0.5rem; @@ -2333,7 +2336,7 @@ tr.expandable:hover .expand-icon::before { margin-top: 0.2rem; font-family: var(--font-mono); font-size: 0.68rem; - color: var(--text-dim); + color: var(--text-mute); } /* ── Agent Lane Sparklines ────────────────────────────────── */ @@ -2347,10 +2350,10 @@ tr.expandable:hover .expand-icon::before { .agent-lane-sparkline-bar { flex: 1; - background: var(--accent); + background: linear-gradient(to top, var(--accent), var(--accent-glow)); border-radius: 1px 1px 0 0; - opacity: 0.5; - min-height: 1px; + opacity: 0.8; + min-height: 2px; } .agent-lane-dot { @@ -2374,7 +2377,7 @@ tr.expandable:hover .expand-icon::before { .agent-lane-status { font-size: 0.7rem; font-weight: 600; - color: var(--text-dim); + color: var(--text-mute); text-transform: uppercase; letter-spacing: 0.06em; } @@ -2399,6 +2402,7 @@ tr.expandable:hover .expand-icon::before { padding: 0.35rem 0.625rem; background: var(--accent-dim); border: 1px solid rgba(34, 211, 238, 0.15); + border-left: 2px solid var(--accent); border-radius: var(--radius); font-size: 0.75rem; animation: fadeUp 0.2s ease both; @@ -2406,11 +2410,17 @@ tr.expandable:hover .expand-icon::before { [data-theme="light"] .active-op { border-color: rgba(8, 145, 178, 0.2); + border-left-color: var(--accent); +} + +.active-op.run { + border-left-color: var(--accent); } .active-op.subagent { background: rgba(167, 139, 250, 0.12); border-color: rgba(167, 139, 250, 0.22); + border-left-color: var(--purple); } .active-op.stale { @@ -2482,6 +2492,7 @@ tr.expandable:hover .expand-icon::before { border-radius: var(--radius); margin-bottom: 0.25rem; border: 1px solid var(--border-soft); + border-left: 2px solid var(--border); background: transparent; font-size: 0.82rem; } @@ -2494,6 +2505,29 @@ tr.expandable:hover .expand-icon::before { font-size: 0.6rem; } +/* ── Event-kind accents + hierarchy (scoped to Agents page) ── */ +#agents-content .timeline-event.evt-run { border-left-color: var(--accent); } +#agents-content .timeline-event.evt-error { border-left-color: var(--error); } +#agents-content .timeline-event.evt-session { border-left-color: var(--success); } +#agents-content .timeline-event.evt-span { border-left-color: rgba(34, 211, 238, 0.4); } + +/* Demote the generic type label to a quiet category tag; let the + tool name / preview body carry the line. */ +#agents-content .timeline-event-type { + font-family: var(--font-mono); + font-size: 0.62rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--text-mute); +} + +#agents-content .timeline-event-body.tool-name, +#agents-content .timeline-event-body.subagent-name { + font-size: 0.82rem; + font-weight: 500; +} + .agent-lane-events .empty-state { padding: 2rem 1rem; font-size: 0.78rem;