Watch
0
0
Fork
You've already forked hyperhive
0

swarm ui: the freshness badge moves from the agent card onto the status panel

The card header carried a fresh/stale badge with the report's age. It now
sits in the status row of the opened card, which already showed it, and the
card header keeps the name, the message and the controls.
This commit is contained in:
iris 2026-11-10 18:09:20 +01:00 • committed by mara
commit 99ca130552
3 changed files with 7 additions and 24 deletions

View file

@ -78,7 +78,7 @@ action that asks first.
`/agents` is a column of separate cards: a filter card, then one `/agents` is a column of separate cards: a filter card, then one
card per agent, none of them inside a bigger card. A card's card per agent, none of them inside a bigger card. A card's
header shows its icon, name, freshness, the status message, a **terminal** header shows its icon, name, the status message, a **terminal**
button that opens the agent's terminal tab, the **wanted** menu (up, offline, button that opens the agent's terminal tab, the **wanted** menu (up, offline,
paused, destroy), a **paused by hive** badge when the agent's own harness paused paused, destroy), a **paused by hive** badge when the agent's own harness paused
its turn loop (hover for the reason; set the agent **up** to resume it), and a its turn loop (hover for the reason; set the agent **up** to resume it), and a
@ -94,7 +94,7 @@ when the data arrives. The placeholders stand still where motion is off.
An opened card has four sections, and each reads nothing until you open it. An opened card has four sections, and each reads nothing until you open it.
**status** and **terminal** start open, the other two folded: **status** and **terminal** start open, the other two folded:
- **status**: the agent's turn state, context and cost, its hive, links to its - **status**: how fresh the agent's last report is (with its age), its turn state, context and cost, its hive, links to its
profile and its config repo on the swarm's forge (built from the forge entry profile and its config repo on the swarm's forge (built from the forge entry
of `GET /api/links`; the row stays hidden when the swarm lists none), and its of `GET /api/links`; the row stays hidden when the swarm lists none), and its
open config PR. open config PR.

View file

@ -61,6 +61,11 @@ function HeaderRows({
<dd> <dd>
<Badge <Badge
tone={tone} tone={tone}
title={
row.freshness === "unknown"
? "reported by its hive but not registered in swarm-level identity — needs migration"
: undefined
}
value={ value={
<> <>
{label} {label}

View file

@ -17,14 +17,12 @@ import { useState } from "preact/hooks";
import { Badge } from "@hive/shared/badge.js"; import { Badge } from "@hive/shared/badge.js";
import { TerminalIcon } from "@hive/shared/icons.js"; import { TerminalIcon } from "@hive/shared/icons.js";
import { Card } from "../../ui/card/Card.js"; import { Card } from "../../ui/card/Card.js";
import { RelativeTime } from "../../ui/relative-time/RelativeTime.js";
import { useDynamicTabs } from "../../shell/useDynamicTabs.js"; import { useDynamicTabs } from "../../shell/useDynamicTabs.js";
import { AgentIcon } from "../AgentIcon.js"; import { AgentIcon } from "../AgentIcon.js";
import { ClaudeLoginDialog } from "../claude-login/ClaudeLoginDialog.js"; import { ClaudeLoginDialog } from "../claude-login/ClaudeLoginDialog.js";
import { AgentDetail } from "../detail/AgentDetail.js"; import { AgentDetail } from "../detail/AgentDetail.js";
import { termPaths } from "../terminal/term-paths.js"; import { termPaths } from "../terminal/term-paths.js";
import { import {
FRESHNESS,
hivePauseReason, hivePauseReason,
showsLoginNeeded, showsLoginNeeded,
type AgentRow, type AgentRow,
@ -41,7 +39,6 @@ export function AgentCard({
row: AgentRow; row: AgentRow;
actions: AgentActions; actions: AgentActions;
}) { }) {
const { tone, label } = FRESHNESS[row.freshness];
const [loggingIn, setLoggingIn] = useState(false); const [loggingIn, setLoggingIn] = useState(false);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const error = actions.actionErrors.get(row.name); const error = actions.actionErrors.get(row.name);
@ -68,25 +65,6 @@ export function AgentCard({
name={<span class="ui-agent-card-name">{row.name}</span>} name={<span class="ui-agent-card-name">{row.name}</span>}
status={ status={
<> <>
<Badge
tone={tone}
title={
row.freshness === "unknown"
? "reported by its hive but not registered in swarm-level identity — needs migration"
: undefined
}
value={
<>
{label}
{row.last_seen_unix !== null ? (
<>
{" "}
(<RelativeTime epochMs={row.last_seen_unix * 1000} />)
</>
) : null}
</>
}
/>
{hivePauseReason(row) !== null ? ( {hivePauseReason(row) !== null ? (
<Badge <Badge
tone="warning" tone="warning"