Watch
0
0
Fork
You've already forked hyperhive
0

swarm ui: the agent card has a terminal icon beside the wanted menu

It opens the agent's terminal tab without opening the card.
This commit is contained in:
iris 2026-11-01 12:18:51 +01:00 • committed by mara
commit 5b66a83112
2 changed files with 38 additions and 2 deletions

View file

@ -105,3 +105,24 @@ export function FilterIcon() {
</svg>
);
}
// A prompt in a window (`>_`), the standard "terminal" glyph — the agent
// card's shortcut to the agent's terminal tab. Same recipe as `LinkIcon`.
export function TerminalIcon() {
return (
<svg
width="1.3em"
height="1.3em"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<polyline points="4 17 10 11 4 5" />
<line x1="12" y1="19" x2="20" y2="19" />
</svg>
);
}

View file

@ -6,17 +6,23 @@
// shows the agent's status, message and wanted state, so the opened body is the
// rest: `AgentDetail`'s folded sections (`inCard`).
//
// The terminal badge beside the wanted menu opens the agent's terminal tab, the
// most common action, without opening the card.
//
// The `stopPropagation` wrappers around the login and `WantedMenu` controls
// keep their own clicks (mouse or keyboard-synthesized, they host real
// `<button>`s) from also toggling the card. The wanted menu carries the destroy
// option here, since no detail row repeats it any more.
import { useState } from "preact/hooks";
import { Badge } from "@hive/shared/badge.js";
import { TerminalIcon } from "@hive/shared/icons.js";
import { Card } from "../../ui/card/Card.js";
import { RelativeTime } from "../../ui/relative-time/RelativeTime.js";
import { useDynamicTabs } from "../../shell/useDynamicTabs.js";
import { AgentIcon } from "../AgentIcon.js";
import { ClaudeLoginDialog } from "../claude-login/ClaudeLoginDialog.js";
import { AgentDetail } from "../detail/AgentDetail.js";
import { termPaths } from "../terminal/AgentTermPreview.js";
import { FRESHNESS, showsLoginNeeded, type AgentRow } from "../AgentTypes.js";
import type { AgentActions } from "./AgentActions.js";
import { WantedMenu } from "./WantedMenu.js";
@ -34,6 +40,8 @@ export function AgentCard({
const [open, setOpen] = useState(false);
const error = actions.actionErrors.get(row.name);
const toggle = () => setOpen((was) => !was);
const { open: openTab } = useDynamicTabs();
const term = termPaths(row.name);
return (
<Card>
<div
@ -101,6 +109,12 @@ export function AgentCard({
class="ui-agent-card-wanted"
onClick={(e) => e.stopPropagation()}
>
<Badge
variant="quiet"
value={<TerminalIcon />}
title={`open ${row.name}'s terminal in its own tab`}
onClick={() => openTab({ href: term.page, label: term.label })}
/>
<WantedMenu
row={row}
pending={actions.pendingAgents.has(row.name)}