({
value,
onChange,
placeholder,
label = 'Parameters (YAML)',
}: {
value: Record<string, unknown> | undefined;
onChange: (params: Record<string, unknown>) => void;
placeholder?: string;
label?: string;
})
| 51 | |
| 52 | // YAML Parameters Editor with local state for smooth editing |
| 53 | function YamlParamsEditor({ |
| 54 | value, |
| 55 | onChange, |
| 56 | placeholder, |
| 57 | label = 'Parameters (YAML)', |
| 58 | }: { |
| 59 | value: Record<string, unknown> | undefined; |
| 60 | onChange: (params: Record<string, unknown>) => void; |
| 61 | placeholder?: string; |
| 62 | label?: string; |
| 63 | }) { |
| 64 | const [localValue, setLocalValue] = useState(() => toYamlString(value)); |
| 65 | const [isValid, setIsValid] = useState(true); |
| 66 | |
| 67 | // Sync local state when external value changes (e.g., node selection change) |
| 68 | useEffect(() => { |
| 69 | setLocalValue(toYamlString(value)); |
| 70 | setIsValid(true); |
| 71 | }, [value]); |
| 72 | |
| 73 | const handleChange = useCallback((text: string) => { |
| 74 | setLocalValue(text); |
| 75 | // Validate but don't save yet |
| 76 | const parsed = parseYamlParams(text); |
| 77 | setIsValid(parsed !== null); |
| 78 | }, []); |
| 79 | |
| 80 | const handleBlur = useCallback(() => { |
| 81 | // Only save when valid |
| 82 | const parsed = parseYamlParams(localValue); |
| 83 | if (parsed !== null) { |
| 84 | onChange(parsed); |
| 85 | } |
| 86 | }, [localValue, onChange]); |
| 87 | |
| 88 | return ( |
| 89 | <div className="mb-4"> |
| 90 | <label className="block text-xs font-medium text-gray-600 mb-1"> |
| 91 | {label} |
| 92 | </label> |
| 93 | <textarea |
| 94 | value={localValue} |
| 95 | onChange={(e) => handleChange(e.target.value)} |
| 96 | onBlur={handleBlur} |
| 97 | placeholder={placeholder} |
| 98 | className={`w-full px-3 py-2 border rounded-md text-sm font-mono resize-y min-h-[100px] focus:outline-none focus:ring-2 focus:border-transparent ${ |
| 99 | isValid |
| 100 | ? 'border-gray-200 focus:ring-blue-500' |
| 101 | : 'border-red-300 focus:ring-red-500 bg-red-50' |
| 102 | }`} |
| 103 | /> |
| 104 | <div className="text-xs mt-1 flex justify-between"> |
| 105 | <span className="text-gray-400">Enter parameters in YAML format</span> |
| 106 | {!isValid && <span className="text-red-500">Invalid YAML</span>} |
| 107 | </div> |
| 108 | </div> |
| 109 | ); |
| 110 | } |
nothing calls this directly
no test coverage detected