"use client"; import { OutputNodeData, UINode } from "lib/ai/workflow/workflow.interface"; import { memo, useCallback, useMemo } from "react"; import { ChevronDownIcon, PlusIcon, TrashIcon, TriangleAlertIcon, VariableIcon, } from "lucide-react"; import { VariableSelect } from "../variable-select"; import { useReactFlow } from "@xyflow/react"; import { Input } from "ui/input"; import { Button } from "ui/button"; import { cleanVariableName, generateUniqueKey } from "lib/utils"; import { Label } from "ui/label"; import { findJsonSchemaByPath } from "lib/ai/workflow/shared.workflow"; import { useTranslations } from "next-intl"; export const OutputNodeDataConfig = memo(function ({ data, }: { data: OutputNodeData; }) { const { getNodes, updateNodeData } = useReactFlow(); const t = useTranslations(); const outputVariables = useMemo(() => { const nodes = getNodes() as UINode[]; return data.outputData.map(({ key, source }) => { const targetNode = nodes.find((node) => node.data.id === source?.nodeId); const schema = targetNode ? findJsonSchemaByPath(targetNode.data.outputSchema, source?.path ?? []) : undefined; return { key, schema, path: source?.path ?? [], nodeName: targetNode?.data.name, nodeId: targetNode?.data.id, isNotFound: (source && !targetNode) || (targetNode && !schema), }; }); }, [data]); const updateOutputVariable = useCallback( ( index: number, item: { key?: string; source?: { nodeId: string; path: string[] } }, ) => { updateNodeData(data.id, (node) => { const prev = node.data as OutputNodeData; return { outputData: prev.outputData.map((v, i) => i === index ? { ...v, ...item } : v, ), }; }); }, [data.id], ); const deleteOutputVariable = useCallback( (index: number) => { updateNodeData(data.id, (node) => { const prev = node.data as OutputNodeData; return { outputData: prev.outputData.filter((_, i) => i !== index), }; }); }, [data.id], ); const addOutputVariable = useCallback( (key: string = "") => { updateNodeData(data.id, (node) => { const prev = node.data as OutputNodeData; const newKey = generateUniqueKey( key, prev.outputData.map((v) => v.key), ); return { outputData: [...prev.outputData, { key: newKey, source: undefined }], }; }); }, [data.id], ); return (
{outputVariables.map((item, index) => { return (
{ updateOutputVariable(index, { key: cleanVariableName(e.target.value), }); }} className="w-24" placeholder="name" /> { updateOutputVariable(index, { source: { nodeId: item.nodeId, path: item.path, }, }); }} >
{item.isNotFound ? ( ) : ( )} {item.nodeName}/ {item.path.join(".")} {item.schema?.type}
); })}
); }); OutputNodeDataConfig.displayName = "OutputNodeDataConfig"; export const OutputNodeDataOutputStack = memo(function ({ data, }: { data: OutputNodeData }) { const { getNodes } = useReactFlow(); const outputVariables = useMemo(() => { const nodes = getNodes() as UINode[]; return data.outputData.map(({ key, source }) => { const targetNode = nodes.find((node) => node.data.id === source?.nodeId); const schema = targetNode ? findJsonSchemaByPath(targetNode.data.outputSchema, source?.path ?? []) : undefined; return { key, schema, path: source?.path ?? [], nodeName: targetNode?.data.name, nodeId: targetNode?.data.id, isNotFound: (source && !targetNode) || (targetNode && !schema), }; }); }, [data.outputSchema]); if (!outputVariables.length) return null; return (
{outputVariables.map((item, index) => { return (
{item.isNotFound ? ( ) : ( )} {item.nodeName}/ {item.path.join(".")} {item.schema?.type}
); })}
); }); OutputNodeDataOutputStack.displayName = "OutputNodeDataOutputStack";