DesignX
Agent Ops@paxeer/agent-ops/approval-gateimplemented

Approval gate

Operator approval using Alert + Dialog.

Install

$pnpm exec designx add @paxeer/agent-ops/approval-gate

Preview

Loading preview...

Source code

components/designx/agent-ops/approval-gate.tsxtsx
"use client";

import { useState } from "react";
import {
  Alert,
  AlertDescription,
  AlertTitle,
  Button,
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@paxeer/core";

export function ApprovalGate({
  title = "Approve outgoing action",
  summary = "helix-exec wants to submit a 1.50 ETH limit bid at 2480.40.",
}: {
  title?: string;
  summary?: string;
}) {
  const [decision, setDecision] = useState<"pending" | "approved" | "rejected">("pending");

  return (
    <Card className="gap-3 py-4" data-slot="approval-gate">
      <CardHeader className="px-4">
        <CardTitle className="text-[length:var(--md-sys-typescale-title-small-size)]">
          {title}
        </CardTitle>
      </CardHeader>
      <CardContent className="flex flex-col gap-3 px-4">
        <Alert variant={decision === "rejected" ? "destructive" : "default"}>
          <AlertTitle>
            {decision === "pending"
              ? "Waiting on an operator"
              : decision === "approved"
                ? "Approved"
                : "Rejected"}
          </AlertTitle>
          <AlertDescription>{summary}</AlertDescription>
        </Alert>
      </CardContent>
      <CardFooter className="gap-2 px-4">
        <Dialog>
          <DialogTrigger asChild>
            <Button size="dense" disabled={decision !== "pending"}>
              Review
            </Button>
          </DialogTrigger>
          <DialogContent>
            <DialogHeader>
              <DialogTitle>Confirm approval</DialogTitle>
              <DialogDescription>{summary}</DialogDescription>
            </DialogHeader>
            <DialogFooter>
              <Button variant="outlined" onClick={() => setDecision("rejected")}>
                Reject
              </Button>
              <Button onClick={() => setDecision("approved")}>Approve</Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
        <Button
          size="dense"
          variant="outlined"
          disabled={decision !== "pending"}
          onClick={() => setDecision("rejected")}
        >
          Reject
        </Button>
      </CardFooter>
    </Card>
  );
}