"use client"; import { useState, useEffect } from "react"; interface OutputMapping { outputAs: "full" | "field" | "custom"; fieldName?: string; customPath?: string; } interface UniversalOutputSelectorProps { nodeId: string; nodeType: string; currentMapping?: OutputMapping; onUpdate: (mapping: OutputMapping) => void; } export default function UniversalOutputSelector({ nodeId, nodeType, currentMapping, onUpdate, }: UniversalOutputSelectorProps) { const [outputAs, setOutputAs] = useState<"full" | "field" | "custom">( currentMapping?.outputAs || "full" ); const [fieldName, setFieldName] = useState(currentMapping?.fieldName || "result"); const [customPath, setCustomPath] = useState(currentMapping?.customPath || ""); useEffect(() => { const timeoutId = setTimeout(() => { onUpdate({ outputAs, fieldName, customPath }); }, 300); return () => clearTimeout(timeoutId); }, [outputAs, fieldName, customPath, onUpdate]); const getDefaultFields = () => { switch (nodeType) { case 'agent': return ['message', 'text', 'response']; case 'mcp': case 'firecrawl': return ['markdown', 'html', 'json', 'results', 'urls']; case 'transform': return ['result', 'output', 'data']; case 'if-else': return ['condition', 'branch']; case 'while': return ['iterations', 'result']; case 'guardrails': return ['passed', 'sanitized', 'result']; case 'file-search': return ['files', 'matches']; default: return ['result', 'output']; } }; const defaultFields = getDefaultFields(); return (
Choose how downstream nodes access this node's output
Access as: state.variables.{nodeId}
Supports dot notation and array indexing
Preview:
state.variables.{nodeId}
{outputAs === 'field' && fieldName !== '__custom__' && ` → ${fieldName} only`}
{outputAs === 'custom' && customPath && ` → ${customPath}`}