Skip to content
Twentyfirst UIPro

Approval Card

AI · ApprovalCard

View as Markdown

The human-in-the-loop decision: what an agent wants to do, the exact payload, and the four answers A–D.

Props: title (the action as one sentence), text (why), children (the payload, verbatim), agent, project, family ("money" | "infra" | "comms" | "marketing" | "apps" | "legal") or familyLabel, age, escalation, trace (node), note, heading, onDecide(key, text), decision ({key, by, at, text}: renders the one-line record), options (override A–D; each {key, label, input}), approveLabel (relabels A), compact. Legacy onApprove / onDeny / onEdit and state still work.

  • Always four answers in this order: A yes, as shown · B yes, with a change · C no, discard · D different instruction. B and D open a text field; ⌘/Ctrl+Enter sends.
  • A–D work as keys while the card has focus.
  • The payload is exactly what will run: the full mail, the amount and recipient, the command, the DNS change before and after. Never a summary.
  • Show the risk family, the age and the escalation time. Nothing runs automatically when time is up.
  • After a decision the card collapses to one line: letter, who, when (and the change or instruction).
  • The A–D wording can be changed through options.
Approval neededAtlas · SupportCommunication4 min

Send this email to ida@northwind.io

Atlas is set to drafts only, so it needs your OK.

Hi Ida, happy to add 40 seats before your renewal on May 1. The quote is attached. Best, Mara
Escalates to the owner in 1:52 hOpen trace
C · No, discardRefund €10.00 to the card ending 4242Lukas · Yesterday 18:02
B · Yes, with a changeAdd TXT record ops-testMara Ellis · 08:10“Use TTL 300 instead”

Props

ApprovalCard

PropTypeNotes
titleReactNodeRequired
text?ReactNode
children?ReactNode
agent?string
project?string
family?RiskFamily
familyLabel?string
age?string
escalation?ReactNode
trace?ReactNode
note?ReactNode
heading?string
options?ApprovalOption[]
approveLabel?string
onDecide?(key: ApprovalKey, text?: string) => void
decision?ApprovalDecision | null
compact?boolean
onApprove?() => void
onDeny?() => void
onEdit?(text: string) => void
state?"approved" | "denied"
className?stringExtra class on the root element.
style?CSSPropertiesInline style on the root element.