import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks"; import { useOrg } from "@agent-native/core/client/org"; import { IconChevronRight } from "@tabler/icons-react"; import { useMemo, useState } from "react"; import { toast } from "sonner"; import { ActionQueryError } from "../../components/action-query-error"; import { DispatchShell } from "../../components/dispatch-shell"; import { Button } from "../../components/ui/button"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "../../components/ui/collapsible"; import { Input } from "../../components/ui/input"; import { Switch } from "../../components/ui/switch"; export function meta() { return [{ title: "Approvals — Dispatch" }]; } export default function ApprovalsRoute() { const settingsQuery = useActionQuery("get-dispatch-settings", {}); const approvalsQuery = useActionQuery("list-dispatch-approvals", {}); const { data: settings } = settingsQuery; const { data: approvals } = approvalsQuery; const { data: org } = useOrg(); const hasOrg = !!org?.orgId; const [emails, setEmails] = useState(""); const approverList = useMemo( () => emails .split(",") .map((value) => value.trim()) .filter(Boolean), [emails], ); const savePolicy = useActionMutation("set-dispatch-approval-policy", { onSuccess: () => toast.success("Approval policy updated"), onError: (err) => toast.error(String(err)), }); const approve = useActionMutation("approve-dispatch-change", { onSuccess: () => toast.success("Change approved"), onError: (err) => toast.error(String(err)), }); const reject = useActionMutation("reject-dispatch-change", { onSuccess: () => toast.success("Change rejected"), onError: (err) => toast.error(String(err)), }); return (
Approval policy {settings?.enabled ? "Durable changes require approval." : "Durable changes do not require approval."} {settingsQuery.isError ? ( void settingsQuery.refetch()} /> ) : (
Approver emails
setEmails(event.target.value)} placeholder={(settings?.approverEmails || []).join(", ")} disabled={!hasOrg} />
)}

Pending and recent requests

{approvalsQuery.isError ? ( void approvalsQuery.refetch()} /> ) : (
{(approvals || []).map((approval: any) => (
{approval.summary}
{approval.status} · requested by {approval.requestedBy}
{approval.status === "pending" && (
)}
))} {(approvals?.length || 0) === 0 && (
No approval requests yet.
)}
)}
); }