deny: operator can attach a reason that reaches the manager

clicking DENY on the dashboard now prompts for an optional reason
('reason for denying (optional, sent to manager):'). the value
rides along as a hidden 'note' form field; backend chain:

  POST /deny/{id} { note }
    → actions::deny(coord, id, Some(note))
    → Approvals::mark_denied writes it to the row
    → HelperEvent::ApprovalResolved { ..., note: Some("...") }

manager already had note: Option<String> on the event, just never
populated for denials before. host admin socket (hive-c0re deny)
still passes None.

generalized the prompt-on-submit pattern: any form with a
data-prompt attribute pops a window.prompt() before the POST and
stashes the answer in a hidden input named by data-prompt-field
(default 'note'). reusable for future opt-in note fields.
This commit is contained in:
müde 2026-05-15 21:58:42 +02:00
parent 91c78d626f
commit 2029840671
5 changed files with 52 additions and 12 deletions

View file

@ -178,17 +178,17 @@ pub async fn destroy(coord: &Coordinator, name: &str, purge: bool) -> Result<()>
Ok(())
}
pub fn deny(coord: &Coordinator, id: i64) -> Result<()> {
pub fn deny(coord: &Coordinator, id: i64, note: Option<&str>) -> Result<()> {
let approval = coord.approvals.get(id)?;
coord.approvals.mark_denied(id)?;
tracing::info!(%id, "approval denied");
coord.approvals.mark_denied(id, note)?;
tracing::info!(%id, note, "approval denied");
if let Some(a) = approval {
coord.notify_manager(&HelperEvent::ApprovalResolved {
id: a.id,
agent: a.agent,
commit_ref: a.commit_ref,
status: ApprovalStatus::Denied,
note: None,
note: note.map(String::from),
});
}
Ok(())