Compare commits
2 changed files with 23 additions and 24 deletions
|
|
@ -408,7 +408,7 @@ body sits to the right with three stacked lines
|
||||||
**icon-only nav strip** populated async from the agent backend
|
**icon-only nav strip** populated async from the agent backend
|
||||||
(`📊 stats`, `🖥 screen` when GUI is enabled, `⬡ forge profile`,
|
(`📊 stats`, `🖥 screen` when GUI is enabled, `⬡ forge profile`,
|
||||||
`↳ agent-configs mirror`, plus any agent-declared
|
`↳ agent-configs mirror`, plus any agent-declared
|
||||||
`dashboardLinks` extras). The dashboard JS fetches
|
`dashboardLinks` extras — issue #262). The dashboard JS fetches
|
||||||
`GET /api/agent/{name}/links`, a same-origin passthrough proxy
|
`GET /api/agent/{name}/links`, a same-origin passthrough proxy
|
||||||
that forwards the agent's own link list; the agent backend is
|
that forwards the agent's own link list; the agent backend is
|
||||||
the single source of truth. The frontend resolves each
|
the single source of truth. The frontend resolves each
|
||||||
|
|
@ -458,7 +458,7 @@ body sits to the right with three stacked lines
|
||||||
panel body.
|
panel body.
|
||||||
- Plain navigation links (config repo, forge profile,
|
- Plain navigation links (config repo, forge profile,
|
||||||
`dashboardLinks` extras) now live in the icon-only nav strip
|
`dashboardLinks` extras) now live in the icon-only nav strip
|
||||||
on Line 1 — see above. The agent's `config` link
|
on Line 1 — see above (issue #262). The agent's `config` link
|
||||||
goes to the repo root; the deployed sha shows separately on
|
goes to the repo root; the deployed sha shows separately on
|
||||||
Line 1 as the `deployed:<sha>` chip, since the agent harness
|
Line 1 as the `deployed:<sha>` chip, since the agent harness
|
||||||
can't know its own deployed commit.
|
can't know its own deployed commit.
|
||||||
|
|
@ -524,12 +524,12 @@ frosted-mauve bar slides up from the bottom of the viewport
|
||||||
- `▶ ST4RT` — stopped agents only
|
- `▶ ST4RT` — stopped agents only
|
||||||
- `↻ R3BU1LD` — always available
|
- `↻ R3BU1LD` — always available
|
||||||
- `DESTR0Y` / `PURG3` — sub-agents only (disabled if manager selected)
|
- `DESTR0Y` / `PURG3` — sub-agents only (disabled if manager selected)
|
||||||
- `⇡ M0V3 → ROOT` — promote selected agents to top-level
|
- `⇡ M0V3 → ROOT` (#486) — promote selected agents to top-level
|
||||||
(parent = null); disabled when all selected are already at root.
|
(parent = null); disabled when all selected are already at root.
|
||||||
Backend `topology::set_parent` refuses moves it can't satisfy
|
Backend `topology::set_parent` refuses moves it can't satisfy
|
||||||
(e.g. moving the manager) and the refusal surfaces in the
|
(e.g. moving the manager) and the refusal surfaces in the
|
||||||
failure roll-up.
|
failure roll-up.
|
||||||
- `⇢ M0V3 → [select]` — inline picker available for any
|
- `⇢ M0V3 → [select]` (#486) — inline picker available for any
|
||||||
selection size. The dropdown lists every container that isn't IN
|
selection size. The dropdown lists every container that isn't IN
|
||||||
the selection itself nor a descendant of any selected agent
|
the selection itself nor a descendant of any selected agent
|
||||||
(client-side BFS cycle prevention across the whole batch; the
|
(client-side BFS cycle prevention across the whole batch; the
|
||||||
|
|
|
||||||
|
|
@ -579,8 +579,8 @@ window.marked = marked;
|
||||||
// a same-origin proxy that forwards the agent backend's own link list
|
// a same-origin proxy that forwards the agent backend's own link list
|
||||||
// (stats / screen-if-gui / forge profile / agent-configs / extras).
|
// (stats / screen-if-gui / forge profile / agent-configs / extras).
|
||||||
// The agent backend is the single source of truth; no hardcoded link
|
// The agent backend is the single source of truth; no hardcoded link
|
||||||
// list here. DOM-built — link strings come from the agent's process
|
// list here (issue #262). DOM-built — link strings come from the
|
||||||
// and must never reach the HTML parser.
|
// agent's process and must never reach the HTML parser.
|
||||||
const navStrip = el('span', { class: 'nav-strip' });
|
const navStrip = el('span', { class: 'nav-strip' });
|
||||||
head.append(navStrip);
|
head.append(navStrip);
|
||||||
const forgeBase = `http://${hostname}:3000`;
|
const forgeBase = `http://${hostname}:3000`;
|
||||||
|
|
@ -709,8 +709,9 @@ window.marked = marked;
|
||||||
// The hardcoded config-repo trigger and the agent-declared
|
// The hardcoded config-repo trigger and the agent-declared
|
||||||
// extras block both moved into the unified nav strip in the
|
// extras block both moved into the unified nav strip in the
|
||||||
// head row above (sourced from the agent backend via
|
// head row above (sourced from the agent backend via
|
||||||
// `/api/agent/{name}/links`). Only the journald trigger stays
|
// `/api/agent/{name}/links` — issue #262). Only the journald
|
||||||
// here since it opens the side panel rather than a link.
|
// trigger stays here since it opens the side panel rather
|
||||||
|
// than a link.
|
||||||
body.append(drill);
|
body.append(drill);
|
||||||
|
|
||||||
li.append(icon, body);
|
li.append(icon, body);
|
||||||
|
|
@ -805,8 +806,7 @@ window.marked = marked;
|
||||||
disabledTitle: why('PURG3', managerNames.map((n) => `\`${n}\` is the manager`)),
|
disabledTitle: why('PURG3', managerNames.map((n) => `\`${n}\` is the manager`)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Move agent(s) in the topology tree — see
|
// #486 — move agent(s) in the topology tree. Two affordances:
|
||||||
// docs/web-ui.md::Selection bar for the two affordances:
|
|
||||||
//
|
//
|
||||||
// ⇡ M0V3 → ROOT promote selected agent(s) to top-level (parent=null)
|
// ⇡ M0V3 → ROOT promote selected agent(s) to top-level (parent=null)
|
||||||
// ⇢ M0V3 → [sel] reparent the single selected agent under a picked
|
// ⇢ M0V3 → [sel] reparent the single selected agent under a picked
|
||||||
|
|
@ -973,8 +973,9 @@ window.marked = marked;
|
||||||
// `opts.body` is a static object applied to every POST.
|
// `opts.body` is a static object applied to every POST.
|
||||||
// - `opts.perAgentBodyFor(name)` is set: `opts.action` is the
|
// - `opts.perAgentBodyFor(name)` is set: `opts.action` is the
|
||||||
// full URL (no name appended) and the per-agent body comes
|
// full URL (no name appended) and the per-agent body comes
|
||||||
// from the callback. Used by /api/topology/set-parent, where
|
// from the callback. Used by /api/topology/set-parent (#486),
|
||||||
// the agent name is a body field rather than a URL component.
|
// where the agent name is a body field rather than a URL
|
||||||
|
// component.
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
const body = opts.perAgentBodyFor
|
const body = opts.perAgentBodyFor
|
||||||
? new URLSearchParams(opts.perAgentBodyFor(name))
|
? new URLSearchParams(opts.perAgentBodyFor(name))
|
||||||
|
|
@ -1160,10 +1161,9 @@ window.marked = marked;
|
||||||
const idx = questionsState.pending.findIndex((q) => q.id === ev.id);
|
const idx = questionsState.pending.findIndex((q) => q.id === ev.id);
|
||||||
const existing = idx >= 0 ? questionsState.pending[idx] : null;
|
const existing = idx >= 0 ? questionsState.pending[idx] : null;
|
||||||
if (idx >= 0) questionsState.pending.splice(idx, 1);
|
if (idx >= 0) questionsState.pending.splice(idx, 1);
|
||||||
// Idempotent: a snapshot re-sync (post-disconnect SSE catchup) can
|
// Idempotent: a snapshot re-sync (issue #163) can carry this same
|
||||||
// carry this same answered row in `question_history` while a live
|
// answered row in `question_history` while a live event also
|
||||||
// event also delivers it — guard the unshift so history can't
|
// delivers it — guard the unshift so history can't double a row.
|
||||||
// double a row.
|
|
||||||
if (!questionsState.history.some((h) => h.id === ev.id)) {
|
if (!questionsState.history.some((h) => h.id === ev.id)) {
|
||||||
questionsState.history.unshift({
|
questionsState.history.unshift({
|
||||||
id: ev.id,
|
id: ev.id,
|
||||||
|
|
@ -1461,10 +1461,9 @@ window.marked = marked;
|
||||||
function applyApprovalResolved(ev) {
|
function applyApprovalResolved(ev) {
|
||||||
// Drop from pending; prepend to history (newest-first), cap at 30.
|
// Drop from pending; prepend to history (newest-first), cap at 30.
|
||||||
approvalsState.pending = approvalsState.pending.filter((a) => a.id !== ev.id);
|
approvalsState.pending = approvalsState.pending.filter((a) => a.id !== ev.id);
|
||||||
// Idempotent: a snapshot re-sync (post-disconnect SSE catchup) can
|
// Idempotent: a snapshot re-sync (issue #163) can carry this same
|
||||||
// carry this same resolved row in `approval_history` while a live
|
// resolved row in `approval_history` while a live event also
|
||||||
// event also delivers it — guard the unshift so history can't
|
// delivers it — guard the unshift so history can't double a row.
|
||||||
// double a row.
|
|
||||||
if (!approvalsState.history.some((h) => h.id === ev.id)) {
|
if (!approvalsState.history.some((h) => h.id === ev.id)) {
|
||||||
approvalsState.history.unshift({
|
approvalsState.history.unshift({
|
||||||
id: ev.id,
|
id: ev.id,
|
||||||
|
|
@ -3217,10 +3216,10 @@ window.marked = marked;
|
||||||
catch (err) { console.error('dashboard SSE handler', ev.kind, err); }
|
catch (err) { console.error('dashboard SSE handler', ev.kind, err); }
|
||||||
};
|
};
|
||||||
es.onopen = () => {
|
es.onopen = () => {
|
||||||
// Re-sync to recover events that fired during the SSE disconnect
|
// Re-sync to recover events that fired during a disconnect
|
||||||
// window. Initial connect also fires onopen — the first
|
// window (issue #163). Initial connect also fires onopen — the
|
||||||
// refreshState() above and this one race, but refreshState is
|
// first refreshState() above and this one race, but refreshState
|
||||||
// idempotent so the second call just overwrites with the
|
// is idempotent so the second call just overwrites with the
|
||||||
// freshest snapshot. Cheap on a quiescent server, fine to repeat.
|
// freshest snapshot. Cheap on a quiescent server, fine to repeat.
|
||||||
refreshState();
|
refreshState();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue