import React, { useState, useCallback, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { RotateCcw, Settings, HelpCircle, Zap } from 'lucide-react'; import PropTypes from 'prop-types'; import Button from '../../design-system/components/Button'; import Input from '../../design-system/components/Input'; import Card from '../../design-system/components/Card'; const EnhancedPluginParameterForm = ({ parameters, initialValues, onSubmit, loading, onParameterChange, showAdvanced = false }) => { const [values, setValues] = useState(initialValues || {}); const [errors, setErrors] = useState({}); const [showAdvancedParams, setShowAdvancedParams] = useState(showAdvanced); const [focusedParam, setFocusedParam] = useState(null); // Categorize parameters const { basicParams, advancedParams } = useMemo(() => { const basic = parameters.filter(p => !p.advanced); const advanced = parameters.filter(p => p.advanced); return { basicParams: basic, advancedParams: advanced }; }, [parameters]); const validateParameter = useCallback((param, value) => { const errors = []; if (param.required && (value === undefined || value === null || value === '')) { errors.push('This field is required'); } if (param.type === 'int' || param.type === 'float') { const numValue = parseFloat(value); if (isNaN(numValue)) { errors.push('Must be a valid number'); } else { if (param.min !== undefined && numValue < param.min) { errors.push(`Must be at least ${param.min}`); } if (param.max !== undefined && numValue > param.max) { errors.push(`Must be at most ${param.max}`); } } } if (param.type === 'string' && param.max_length && value.length > param.max_length) { errors.push(`Must be at most ${param.max_length} characters`); } return errors; }, []); const handleChange = useCallback((paramName, value) => { setValues(prev => { const newValues = { ...prev, [paramName]: value }; // Validate the parameter const param = parameters.find(p => p.name === paramName); if (param) { const paramErrors = validateParameter(param, value); setErrors(prev => ({ ...prev, [paramName]: paramErrors.length > 0 ? paramErrors[0] : undefined })); } onParameterChange?.(newValues); return newValues; }); }, [parameters, validateParameter, onParameterChange]); const handleSubmit = useCallback((e) => { e.preventDefault(); // Validate all parameters const newErrors = {}; let hasErrors = false; parameters.forEach(param => { const paramErrors = validateParameter(param, values[param.name]); if (paramErrors.length > 0) { newErrors[param.name] = paramErrors[0]; hasErrors = true; } }); setErrors(newErrors); if (!hasErrors) { onSubmit(values); } }, [parameters, values, validateParameter, onSubmit]); const handleReset = useCallback(() => { setValues(initialValues || {}); setErrors({}); }, [initialValues]); const renderParameterInput = (param) => { const value = values[param.name] ?? param.default ?? ''; const error = errors[param.name]; const isFocused = focusedParam === param.name; const inputProps = { value, onChange: (e) => handleChange(param.name, e.target.value), onFocus: () => setFocusedParam(param.name), onBlur: () => setFocusedParam(null), error, required: param.required, disabled: loading, }; switch (param.type) { case 'int': case 'float': return ( ); case 'bool': return (