Approval Inline Diff
ns-ui/approval-inline-diffFreeComponent
Human-in-the-loop tool-call approval row: every argument is editable inline with an old→new diff, and deciding collapses the row irreversibly into a one-line receipt.
Live preview
live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://design.helpmarq.com/r/approval-inline-diff.jsonSource
1"use client";23import { useEffect, useId, useRef, useState } from "react";45// ---------------------------------------------------------------------------6// AssayGate — a human-in-the-loop approval row for an agent's proposed tool7// call. Every argument renders as a real, labelled, inline-editable field;8// touching one keeps the original value on the record and shows a Geist Mono9// old→new diff (strikethrough) beneath it rather than silently swapping the10// value. Approve and Deny are told apart by fill and weight, not colour —11// Approve is the solid accent action, Deny a plain outlined one, both with12// distinct glyphs. Deciding collapses the row into a one-line receipt13// (outcome · actor · time) that cannot be reopened for editing — the14// collapse is driven by grid-template-rows so it plays as a real motion, and15// once `decision` is set nothing in this component ever clears it. The full16// payload survives as-decided behind a native <details> disclosure on the17// receipt line.18// ---------------------------------------------------------------------------1920export type AssayField = {21 key: string;22 /** short label shown above the field, e.g. "command" */23 label: string;24 value: string;25};2627export type AssayDecision = {28 outcome: "approved" | "denied";29 /** who decided — the human at the console, not the requesting agent */30 actor: string;31 timestamp: number;32};3334export interface AssayGateProps {35 /** the tool being called, e.g. "execute_shell" */36 toolName: string;37 /** the agent/identity that proposed the call */38 requestedBy?: string;39 fields: AssayField[];40 /** seed one or more fields as already edited, keyed by field.key — the41 * diff renders immediately instead of waiting for the human to type */42 initialValues?: Record<string, string>;43 /** recorded on the receipt as the decider — default "you" */44 approverName?: string;45 onDecision?: (decision: AssayDecision, fields: AssayField[]) => void;46 /** pre-seed as already decided (e.g. rendering decision history) */47 initialDecision?: AssayDecision;48 className?: string;49}5051function timeLabel(ts: number) {52 return new Date(ts).toLocaleTimeString(undefined, {53 hour: "numeric",54 minute: "2-digit",55 second: "2-digit",56 });57}5859// A wall-clock stamp is the one thing in this component that can legitimately60// differ between the server render and the client one: `toLocaleTimeString`61// … truncated
Files it writes
More from ns-ui
All 228 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordion Latchaccordion-latch | ns-ui | Components | Free | no deps | |
| ASCII Engraving Contourascii-engraving-contour | ns-ui | Components | Free | no deps | |
| ASCII Globe Spinascii-globe-spin | ns-ui | Components | Free | no deps | |
| ASCII Torus Donutascii-torus-donut | ns-ui | Components | Free | no deps | |
| Autosave Ratchetautosave-ratchet | ns-ui | Components | Free | no deps | |
| Avatar Stack Flockavatar-stack-flock | ns-ui | Components | Free | no deps | |
| Background ASCII Ditherbackground-ascii-dither | ns-ui | Components | Free | no deps | |
| Background ASCII Plasmabackground-ascii-plasma | ns-ui | Components | Free | no deps |
