({
node,
onChange,
onDelete,
}: NodeConfigPanelProps)
| 116 | } |
| 117 | |
| 118 | export default function NodeConfigPanel({ |
| 119 | node, |
| 120 | onChange, |
| 121 | onDelete, |
| 122 | }: NodeConfigPanelProps) { |
| 123 | const config = NODE_CONFIGS[node.data.nodeType as NodeType]; |
| 124 | const isProtected = node.type === 'start' || node.type === 'end'; |
| 125 | |
| 126 | /** Typed accessor for node data fields. */ |
| 127 | const d = node.data as Record<string, unknown>; |
| 128 | |
| 129 | const handleChange = (field: string, value: unknown) => { |
| 130 | onChange(node.id, { [field]: value } as Partial<FlowNodeData>); |
| 131 | }; |
| 132 | |
| 133 | const renderField = ( |
| 134 | label: string, |
| 135 | field: string, |
| 136 | type: 'text' | 'textarea' | 'number' = 'text', |
| 137 | placeholder?: string |
| 138 | ) => { |
| 139 | const value = d[field] ?? ''; |
| 140 | |
| 141 | if (type === 'textarea') { |
| 142 | return ( |
| 143 | <div className="mb-4"> |
| 144 | <label className="block text-xs font-medium text-gray-600 mb-1"> |
| 145 | {label} |
| 146 | </label> |
| 147 | <textarea |
| 148 | value={String(value)} |
| 149 | onChange={(e) => handleChange(field, e.target.value)} |
| 150 | placeholder={placeholder} |
| 151 | className="w-full px-3 py-2 border border-gray-200 rounded-md text-sm resize-y min-h-[80px] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" |
| 152 | /> |
| 153 | </div> |
| 154 | ); |
| 155 | } |
| 156 | |
| 157 | return ( |
| 158 | <div className="mb-4"> |
| 159 | <label className="block text-xs font-medium text-gray-600 mb-1"> |
| 160 | {label} |
| 161 | </label> |
| 162 | <input |
| 163 | type={type} |
| 164 | value={type === 'number' ? Number(value) || 0 : String(value)} |
| 165 | onChange={(e) => |
| 166 | handleChange( |
| 167 | field, |
| 168 | type === 'number' ? Number(e.target.value) : e.target.value |
| 169 | ) |
| 170 | } |
| 171 | placeholder={placeholder} |
| 172 | className="w-full px-3 py-2 border border-gray-200 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" |
| 173 | /> |
| 174 | </div> |
| 175 | ); |
nothing calls this directly
no test coverage detected