swarm-ui/agents: fix detail panel going stale after refresh or an action
argus, PR review: detailTarget stored the whole AgentRow object at selection time, so it never picked up a later refresh() or a declareState patch - the card list updated live, the panel next to it kept showing whatever was true the moment it was opened. Concrete repro: open an agent's detail panel, wait for the next refresh or destroy it from inside the panel itself, watch the panel not update. Fix: store only the selected agent's name (detailTargetName) and re-derive the actual row from rows on every render (rows?.find(r => r.name === detailTargetName)). The panel can't drift from what the list is showing since it's reading the same array. Verified with a real refresh cycle against a mock server that returns different data on the second call: before, both card and panel show "idle"; after a live refresh, both show the new value in sync.
This commit is contained in:
parent
7003560569
commit
3b66f0c8d6
1 changed files with 13 additions and 5 deletions
|
|
@ -506,9 +506,17 @@ export function AgentsPage() {
|
|||
// confirmation of a `declareState` call, it's an unrelated action with
|
||||
// its own form (`LinkMatrixAccountForm`).
|
||||
const [matrixTarget, setMatrixTarget] = useState<AgentRow | null>(null);
|
||||
// The row showing the detail panel (see the `Dialog` below for what
|
||||
// it holds) — same null-means-closed shape as the two above.
|
||||
const [detailTarget, setDetailTarget] = useState<AgentRow | null>(null);
|
||||
// Which agent the detail panel shows, *by name* — not the `AgentRow`
|
||||
// object itself. Storing the row would snapshot it at selection time;
|
||||
// `rows` replaces its whole array on every `refresh()` and every
|
||||
// `declareState` patch, so a captured object goes stale the moment
|
||||
// either fires (argus, PR review: "open a detail panel, wait for the
|
||||
// next refresh or destroy from inside the panel itself — the card
|
||||
// list updates live, the panel next to it doesn't"). `detailTarget`
|
||||
// below re-derives the live row from `rows` every render instead, so
|
||||
// it can't drift from what the list is showing.
|
||||
const [detailTargetName, setDetailTargetName] = useState<string | null>(null);
|
||||
const detailTarget = rows?.find((r) => r.name === detailTargetName) ?? null;
|
||||
|
||||
async function refresh() {
|
||||
const res = await fetch("/api/agents/status");
|
||||
|
|
@ -851,11 +859,11 @@ export function AgentsPage() {
|
|||
row={a}
|
||||
pending={pendingAgents.has(a.name)}
|
||||
error={actionErrors.get(a.name)}
|
||||
selected={detailTarget?.name === a.name}
|
||||
selected={detailTargetName === a.name}
|
||||
onSelectUp={selectUp}
|
||||
onSelectOffline={selectOffline}
|
||||
onSelectPaused={selectPaused}
|
||||
onOpenDetail={setDetailTarget}
|
||||
onOpenDetail={(row) => setDetailTargetName(row.name)}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue