swarm-controller: state route refuses an agent the swarm has not declared on that hive
A placing state is accepted only for an agent declared or queued on the hive; anything else gets 404 telling the caller to create it at swarm level. swarm-ui's wanted badge no longer offers a first declaration for an undeclared row.
This commit is contained in:
parent
bd54372fcc
commit
716290e4d2
3 changed files with 131 additions and 40 deletions
|
|
@ -1,13 +1,8 @@
|
|||
// <WantedMenu> — the "wanted" state control: one badge showing the
|
||||
// current declaration, opening a `Dropdown` with the four explicit
|
||||
// states — replaces the old toggle-badge-plus-separate-destroy-badge
|
||||
// pair. Explicit options also fix a real bug the toggle had: for an
|
||||
// undeclared row, the toggle inferred a target as "the opposite of
|
||||
// `snapshot.running`", so a click on an undeclared-but-running agent
|
||||
// silently declared it *offline* rather than making its real state
|
||||
// explicit — a dropdown just lets "up" be picked directly regardless
|
||||
// of what's inferred, no flip-to-the-opposite-of-a-guess involved
|
||||
// (mara: "when no state is declared, i want to set it to online").
|
||||
// states. An agent with no declaration has none to change: its badge is
|
||||
// disabled and points at creating it at swarm level, because the state
|
||||
// route refuses an agent the swarm never declared on that hive.
|
||||
// Presentational only, same split as `StatusChips`'s
|
||||
// `StatusMenu`: the caller owns what each selection actually does.
|
||||
//
|
||||
|
|
@ -66,6 +61,8 @@ export function WantedMenu({
|
|||
const [open, setOpen] = useState(false);
|
||||
const anchorRef = useRef<HTMLDivElement>(null);
|
||||
const destroyed = row.wanted === "destroyed";
|
||||
const undeclared = !row.wanted;
|
||||
const canDeclare = !!row.hive && !destroyed && !undeclared;
|
||||
const tone: BadgeTone =
|
||||
row.wanted === "up"
|
||||
? "positive"
|
||||
|
|
@ -87,20 +84,20 @@ export function WantedMenu({
|
|||
<div class="ui-dropdown-anchor" ref={anchorRef}>
|
||||
<Badge
|
||||
tone={tone}
|
||||
value={pending ? "…" : (row.wanted ?? "no declaration")}
|
||||
// `destroyed` blocks opening the menu at all — same UX-only
|
||||
// guard as before (real enforcement is server-side, see
|
||||
// `declareState`'s caller), just applied to the trigger instead
|
||||
// of a `disabled` toggle badge.
|
||||
onClick={row.hive && !destroyed ? () => setOpen((o) => !o) : undefined}
|
||||
// `destroyed` and an undeclared row block opening the menu at
|
||||
// all — a UX-only guard, the server enforces both (see
|
||||
// `declareState`'s caller).
|
||||
onClick={canDeclare ? () => setOpen((o) => !o) : undefined}
|
||||
expanded={open}
|
||||
disabled={pending || !row.hive || destroyed}
|
||||
disabled={pending || !canDeclare}
|
||||
title={
|
||||
destroyed
|
||||
? `${row.name} is destroyed — redeploy via "+ agent" to bring it back`
|
||||
: row.hive
|
||||
? `declare a new state for ${row.name}`
|
||||
: "no hive on record for this agent — nothing to declare against"
|
||||
: !row.hive
|
||||
? "no hive on record for this agent — nothing to declare against"
|
||||
: undeclared
|
||||
? `${row.name} is not declared at swarm level — create it there`
|
||||
: `declare a new state for ${row.name}`
|
||||
}
|
||||
/>
|
||||
<Dropdown
|
||||
|
|
|
|||
Loading…
Reference in a new issue