"use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; import { AlertTriangleIcon, CheckIcon, Loader2Icon, PencilIcon, XIcon } from "lucide-react"; import { useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; interface InterruptResult { __interrupt__: true; __decided__?: "approve" | "reject" | "edit"; action_requests: Array<{ name: string; args: Record; description?: string; }>; review_configs: Array<{ action_name: string; allowed_decisions: Array<"approve" | "edit" | "reject">; }>; interrupt_type?: string; message?: string; context?: { accounts?: Array<{ id: number; name: string; workspace_id: string | null; workspace_name: string; workspace_icon: string; }>; parent_pages?: Record< number, Array<{ page_id: string; title: string; document_id: number; }> >; error?: string; }; } interface SuccessResult { status: "success"; page_id: string; title: string; url: string; content_preview?: string; content_length?: number; message?: string; } interface ErrorResult { status: "error"; message: string; } type CreateNotionPageResult = InterruptResult | SuccessResult | ErrorResult; function isInterruptResult(result: unknown): result is InterruptResult { return ( typeof result === "object" && result !== null && "__interrupt__" in result && (result as InterruptResult).__interrupt__ === true ); } function isErrorResult(result: unknown): result is ErrorResult { return ( typeof result === "object" && result !== null && "status" in result && (result as ErrorResult).status === "error" ); } function ApprovalCard({ args, interruptData, onDecision, }: { args: Record; interruptData: InterruptResult; onDecision: (decision: { type: "approve" | "reject" | "edit"; message?: string; edited_action?: { name: string; args: Record }; }) => void; }) { const [decided, setDecided] = useState<"approve" | "reject" | "edit" | null>( interruptData.__decided__ ?? null ); const [isEditing, setIsEditing] = useState(false); const [editedArgs, setEditedArgs] = useState>(args); const accounts = interruptData.context?.accounts ?? []; const parentPages = interruptData.context?.parent_pages ?? {}; const defaultAccountId = useMemo(() => { if (args.connector_id) return String(args.connector_id); if (accounts.length === 1) return String(accounts[0].id); return ""; }, [args.connector_id, accounts]); const [selectedAccountId, setSelectedAccountId] = useState(defaultAccountId); const [selectedParentPageId, setSelectedParentPageId] = useState( args.parent_page_id ? String(args.parent_page_id) : "__none__" ); const availableParentPages = useMemo(() => { if (!selectedAccountId) return []; return parentPages[Number(selectedAccountId)] ?? []; }, [selectedAccountId, parentPages]); const isTitleValid = useMemo(() => { const currentTitle = isEditing ? editedArgs.title : args.title; return currentTitle && typeof currentTitle === "string" && currentTitle.trim().length > 0; }, [isEditing, editedArgs.title, args.title]); const reviewConfig = interruptData.review_configs[0]; const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"]; const canEdit = allowedDecisions.includes("edit"); return (

Create Notion Page

{isEditing ? "You can edit the arguments below" : "Requires your approval to proceed"}

{/* Context section - account and parent page selection */} {!decided && interruptData.context && (
{interruptData.context.error ? (

{interruptData.context.error}

) : ( <> {accounts.length > 0 && (
Notion Account *
)} {selectedAccountId && (
Parent Page (optional)
{availableParentPages.length === 0 && selectedAccountId && (

No pages available. Page will be created at workspace root.

)}
)} )}
)} {/* Display mode - show args as read-only */} {!isEditing && (
{args.title != null && (

Title

{String(args.title)}

)} {args.content != null && (

Content

{String(args.content)}

)}
)} {/* Edit mode - show editable form fields */} {isEditing && !decided && (
setEditedArgs({ ...editedArgs, title: e.target.value })} placeholder="Enter page title" className={!isTitleValid ? "border-destructive" : ""} /> {!isTitleValid && (

Title is required and cannot be empty

)}