"use client"; import { motion, AnimatePresence } from "framer-motion"; import { useState, useEffect } from "react"; import type { Node } from "@xyflow/react"; import { toast } from "sonner"; interface DataNodePanelProps { node: Node | null; onClose: () => void; onDelete: (nodeId: string) => void; onUpdate: (nodeId: string, data: any) => void; } export default function DataNodePanel({ node, onClose, onDelete, onUpdate, }: DataNodePanelProps) { const nodeData = node?.data as any; const nodeType = nodeData?.nodeType?.toLowerCase() || ""; // Transform state const [transformScript, setTransformScript] = useState( nodeData?.transformScript || `// Transform the input data return { ...input, processed: true, timestamp: new Date().toISOString() };`, ); // Transform mode (Expressions vs Object vs Advanced) const [transformMode, setTransformMode] = useState< "expressions" | "object" | "advanced" >(nodeData?.transformMode || "expressions"); const [expressionPairs, setExpressionPairs] = useState< Array<{ key: string; value: string }> >(nodeData?.expressionPairs || [{ key: "", value: "" }]); // JSON Schema Builder state (for Object mode) const [schemaMode, setSchemaMode] = useState<"simple" | "advanced">( nodeData?.schemaMode || "simple", ); const [schemaName, setSchemaName] = useState( nodeData?.schemaName || "blog_post_details", ); const [schemaFields, setSchemaFields] = useState< Array<{ name: string; type: string; value?: string; description?: string }> >( nodeData?.schemaFields || [ { name: "title", type: "STR", value: "", description: "The main heading of the blog post", }, { name: "author", type: "STR", value: "", description: "The full name of the post's author", }, { name: "date_published", type: "STR", value: "", description: "Date the post was published (YYYY-MM-DD)", }, { name: "content", type: "STR", value: "", description: "The full content/body of the blog post", }, { name: "tags", type: "ARR", value: "", description: "A list of tag strings associated with the blog post", }, ], ); const [isGenerating, setIsGenerating] = useState(false); const [generatedSchema, setGeneratedSchema] = useState(""); // Set State variables const [stateKey, setStateKey] = useState(nodeData?.stateKey || "myVariable"); const [stateValue, setStateValue] = useState(nodeData?.stateValue || "value"); const [valueType, setValueType] = useState< "string" | "number" | "boolean" | "json" | "expression" >(nodeData?.valueType || "string"); // Auto-save changes useEffect(() => { if (!node?.id) return; const timeoutId = setTimeout(() => { onUpdate(node.id, { transformScript, transformMode, expressionPairs, stateKey, stateValue, valueType, schemaName, schemaFields, schemaMode, }); }, 500); return () => clearTimeout(timeoutId); }, [ transformScript, transformMode, expressionPairs, stateKey, stateValue, valueType, schemaName, schemaFields, schemaMode, ]); // Generate schema using AI const handleGenerateSchema = async () => { setIsGenerating(true); try { // Build schema from fields const properties: any = {}; schemaFields.forEach((field) => { if (field.name) { const typeMap: any = { STR: "string", NUM: "number", BOOL: "boolean", ARR: "array", OBJ: "object", }; const fieldDef: any = { type: typeMap[field.type] || "string", }; if (field.description) { fieldDef.description = field.description; } if (field.value) { fieldDef.default = field.value; } // Handle array type if (field.type === "ARR") { fieldDef.items = { type: "string" }; } properties[field.name] = fieldDef; } }); const schema = { type: "object", properties, additionalProperties: false, required: schemaFields.filter((f) => f.name).map((f) => f.name), }; const schemaJson = JSON.stringify(schema, null, 2); setGeneratedSchema(schemaJson); // Update transform script to use this schema const newScript = `// Extract data matching the schema const result = ${schemaJson}; // TODO: Map input data to schema fields return { ${schemaFields.map((f) => ` ${f.name}: input.${f.name} || ${f.value ? `"${f.value}"` : "null"}`).join(",\n")} };`; setTransformScript(newScript); toast.success("Schema generated!", { description: "Transform script updated with schema structure", }); } catch (error) { toast.error("Failed to generate schema", { description: error instanceof Error ? error.message : "Unknown error", }); } finally { setIsGenerating(false); } }; const renderValueInput = () => { switch (valueType) { case "boolean": return ( ); case "number": return ( setStateValue(e.target.value)} placeholder="42 or {{lastOutput.count}}" className="w-full px-12 py-8 bg-accent-white border border-border-faint rounded-8 text-sm text-accent-black font-mono focus:outline-none focus:border-heat-100 transition-colors" /> ); case "json": return (