From 51da879db6506a432253666053bd778c890fa935 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 4 Oct 2026 16:31:15 +0200 Subject: [PATCH] swarm-ui: expand trigger on the right, connection badge as tall as it The floating row over the terminal now spans its top edge: the state badges (connection first, then the turn-state ones, which move over from the top-right corner) on the left, the expand trigger on the right. The connection badge takes the trigger's height. The row passes pointer events through its empty middle. --- .../src/pages/agents/AgentTermPreview.css | 51 ++++---- .../src/pages/agents/AgentTermPreview.tsx | 115 ++++++++++-------- 2 files changed, 95 insertions(+), 71 deletions(-) diff --git a/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.css b/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.css index 9fe8b1ae..12a07866 100644 --- a/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.css +++ b/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.css @@ -76,35 +76,40 @@ padding-block-start: 3.4em; } -/* Floating turn_state/agent_state/model/ctx/cost badge cluster — - positioned by `.terminal-wrap`'s own `position: relative`, same - anchor `@hive/shared/terminal.css`'s `.tail-pill` already uses, rather - than a second positioned ancestor of our own. Top-right corner: the - scroll-to-bottom `.tail-pill` (that same stylesheet) anchors - bottom-right, so the two overlays never compete for the same corner. - `flex-wrap` rather than a fixed width — a badge cluster this narrow - can still overflow the box at small viewport widths, and wrapping - beats clipping or shrinking the terminal underneath. */ -.ui-agent-term-preview-header-badges { - position: absolute; - top: 0.4em; - right: 0.4em; - z-index: 1; - display: flex; - flex-wrap: wrap; - justify-content: flex-end; - gap: 0.25em; - max-width: calc(100% - 0.8em); -} - -/* Connection badge and expand trigger — top-left floating twin of - `.ui-agent-term-preview-header-badges` (top-right), same anchor. */ +/* The floating row over the terminal's top edge: state badges (connection + first, then turn_state/agent_state/model/ctx/cost) on the left, the + expand trigger on the right. Positioned by `.terminal-wrap`'s own + `position: relative`, same anchor `@hive/shared/terminal.css`'s + `.tail-pill` uses, which anchors bottom-right and so never competes for + this edge. The row itself takes no pointer events, so the terminal + under its empty middle still scrolls and selects; only the badges and + the trigger do. `flex-wrap` on the badges rather than a fixed width — + at small viewport widths wrapping beats clipping. */ .ui-agent-term-preview-controls { position: absolute; top: 0.4em; left: 0.4em; + right: 0.4em; z-index: 1; display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 0.5em; + pointer-events: none; +} +.ui-agent-term-preview-controls > * { + pointer-events: auto; +} +.ui-agent-term-preview-header-badges { + display: flex; + flex-wrap: wrap; align-items: center; gap: 0.25em; + min-width: 0; +} + +/* Same height as the expand trigger beside it, which keeps an interactive + badge's 2.75em touch-target floor. */ +.ui-agent-term-preview-live { + min-height: 2.75em; } diff --git a/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.tsx b/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.tsx index 38937363..168f140f 100644 --- a/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.tsx +++ b/frontend/packages/swarm-ui/src/pages/agents/AgentTermPreview.tsx @@ -130,6 +130,60 @@ export function termPaths(agentName: string, subagent?: string): TermPaths { }; } +// Turn state, agent state, model, ctx and cost, as the badges beside the +// connection one. Siblings only, no wrapper: they sit in the caller's row. +function StateBadges({ + header, + ctx, + cost, +}: { + header: NonNullable["header"]>; + ctx: number | null; + cost: number | null; +}) { + return ( + <> + + {/* Only the non-boring case gets a badge — a healthy running + agent (`agent_state: "up"`) doesn't need one for the + obvious default. In practice this only ever fires for + "paused": `hive-agent` can only honestly publish "up" or + "paused" on this subject (see `AgentStateMsg::agent_state`'s + own doc), never "offline"/"destroyed" — a stopped or + destroyed agent publishes nothing at all. */} + {header.agent_state !== "up" && ( + + )} + + {ctx !== null && ( + + )} + {cost !== null && ( + + )} + + ); +} + export function AgentTermPreview({ agentName, subagent, @@ -176,15 +230,21 @@ export function AgentTermPreview({ } >
- {/* The connection badge and the expand trigger float in the - terminal's top-left corner (the other badges own the - top-right). The full-tab mount is already the destination, so + {/* One floating row over the terminal's top edge: the state + badges (connection first) on the left, the expand trigger on + the right. The full-tab mount is already the destination, so it has no expand trigger. */}
- +
+ + {header && showHeaderBadges && ( + + )} +
{!fullHeight && ( } @@ -194,47 +254,6 @@ export function AgentTermPreview({ /> )}
- {header && showHeaderBadges && ( -
- - {/* Only the non-boring case gets a badge — a healthy running - agent (`agent_state: "up"`) doesn't need one for the - obvious default. In practice this only ever fires for - "paused": `hive-agent` can only honestly publish "up" or - "paused" on this subject (see `AgentStateMsg::agent_state`'s - own doc), never "offline"/"destroyed" — a stopped or - destroyed agent publishes nothing at all. */} - {header.agent_state !== "up" && ( - - )} - - {ctx !== null && ( - - )} - {cost !== null && ( - - )} -
- )}
{rows.length === 0 ? (