diff --git a/web/public/app.js b/web/public/app.js index 3aff8ab..c1fc1a3 100644 --- a/web/public/app.js +++ b/web/public/app.js @@ -731,10 +731,24 @@ function attachLiveJob(id, target, name, pinnedAgents) { } function updatePinnedLine() { - const n = state.currentJob?.pinnedAgents?.length || 0; - $('#livePinned').textContent = n - ? `${n} pinned lead(s): ${state.currentJob.pinnedAgents.join(', ')}` - : 'auto — recon-driven agent selection (no leads pinned)'; + const el = $('#livePinned'); + const pins = state.currentJob?.pinnedAgents || []; + const n = pins.length; + if (!n) { el.textContent = 'auto — recon-driven agent selection (no leads pinned)'; el.title = ''; el.onclick = null; el.classList.remove('expandable'); return; } + // A /run with every lead pinned (hundreds of agents) must not flood the + // header and push the tabs off-screen — collapse to a count + preview the + // operator can click to expand. + const CAP = 6; + const render = (expanded) => { + const shown = expanded ? pins : pins.slice(0, CAP); + const more = (!expanded && n > CAP) ? ` … +${n - CAP} more` : ''; + el.textContent = `${n} pinned lead(s): ${shown.join(', ')}${more}`; + el.classList.toggle('expandable', n > CAP); + }; + let expanded = false; + render(false); + el.title = n > CAP ? 'Click to show all pinned leads' : pins.join(', '); + el.onclick = n > CAP ? () => { expanded = !expanded; render(expanded); el.title = expanded ? 'Click to collapse' : 'Click to show all pinned leads'; } : null; } // Resume a live view across a page reload: the server-side job outlives the diff --git a/web/public/style.css b/web/public/style.css index fcf90dc..0ec13f8 100644 --- a/web/public/style.css +++ b/web/public/style.css @@ -481,6 +481,13 @@ textarea { resize: vertical; min-height: 72px; } .run-head-main { min-width: 0; } .run-target { font-size: var(--fs-lg); font-weight: 600; font-family: var(--mono); overflow-wrap: anywhere; } .run-meta { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--text-dim); font-family: var(--mono); } +/* Pinned-leads line: never let a /run with hundreds of pinned agents flood the + header and push the tabs below the fold. Collapsed by default (JS truncates + to a preview + count); clicking expands it, capped so it still scrolls. */ +#livePinned { display: block; line-height: 1.5; } +#livePinned.expandable { cursor: pointer; } +#livePinned.expandable:hover { color: var(--text); } +#livePinned { max-height: 4.5em; overflow-y: auto; } #liveTargetSub:empty, #detailTargetSub:empty { display: none; } .run-facts { flex-wrap: wrap; font-size: var(--fs-xs); color: var(--text-faint); } .run-facts span:not(:last-child)::after { content: " ·"; }