dashboard: approval_added / approval_resolved mutation events + client derived state

This commit is contained in:
müde 2026-05-17 13:30:25 +02:00
parent 291f1fce42
commit 56d615b51f
6 changed files with 244 additions and 11 deletions

View file

@ -114,6 +114,29 @@ fn finish_approval(
sha: approval.fetched_sha.clone(),
tag: terminal_tag.clone(),
});
// Phase 5b: also fire on the dashboard event channel so the
// browser moves the row out of pending into history without a
// snapshot refetch. `approved` rows that succeed get the
// approval's logged resolved_at indirectly via `now_unix()`;
// failures already wrote it via mark_failed above.
let approval_kind = match approval.kind {
ApprovalKind::Spawn => "spawn",
ApprovalKind::ApplyCommit => "apply_commit",
};
let sha_short = approval
.fetched_sha
.as_deref()
.map(|s| s[..s.len().min(12)].to_owned());
let status_str = if ok { "approved" } else { "failed" };
coord.emit_approval_resolved(
approval.id,
&approval.agent,
approval_kind,
sha_short,
status_str,
note.clone(),
approval.description.clone(),
);
// For spawn/rebuild approvals, also surface the underlying action so
// the manager knows whether the container actually came up. The
// ApprovalResolved event already carries the same `ok` signal but
@ -381,6 +404,13 @@ pub async fn deny(coord: &Coordinator, id: i64, note: Option<&str>) -> Result<()
}
}
}
let approval_kind = match a.kind {
ApprovalKind::Spawn => "spawn",
ApprovalKind::ApplyCommit => "apply_commit",
};
let sha_short = sha.as_deref().map(|s| s[..s.len().min(12)].to_owned());
let description = a.description.clone();
let agent_owned = a.agent.clone();
coord.notify_manager(&HelperEvent::ApprovalResolved {
id: a.id,
agent: a.agent,
@ -390,6 +420,15 @@ pub async fn deny(coord: &Coordinator, id: i64, note: Option<&str>) -> Result<()
sha,
tag,
});
coord.emit_approval_resolved(
id,
&agent_owned,
approval_kind,
sha_short,
"denied",
note.map(String::from),
description,
);
}
Ok(())
}