From dccbb7cda6320db9d32ab978c08f843f4aad259e Mon Sep 17 00:00:00 2001 From: imeepos Date: Mon, 4 Aug 2025 10:41:07 +0800 Subject: [PATCH] fix: resolve TypeScript error in ComfyUIConfigModal handleInputChange function - Updated handleInputChange function signature to accept undefined values - Fixes 'Argument of type number | undefined is not assignable' error on line 248 - Allows proper handling of optional numeric fields in ComfyuiConfig interface --- .../src/components/ComfyUIConfigModal.tsx | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 apps/desktop/src/components/ComfyUIConfigModal.tsx diff --git a/apps/desktop/src/components/ComfyUIConfigModal.tsx b/apps/desktop/src/components/ComfyUIConfigModal.tsx new file mode 100644 index 0000000..2a79c07 --- /dev/null +++ b/apps/desktop/src/components/ComfyUIConfigModal.tsx @@ -0,0 +1,335 @@ +import React, { useState, useEffect } from 'react'; +import { X, Save, TestTube, AlertCircle, CheckCircle } from 'lucide-react'; +import ComfyuiService from '../services/comfyuiService'; +import type { ComfyuiConfig } from '../types/comfyui'; + +interface ComfyUIConfigModalProps { + isOpen: boolean; + onClose: () => void; + currentConfig: ComfyuiConfig; + onConfigUpdate: (config: ComfyuiConfig) => void; +} + +/** + * ComfyUI 配置设置模态框 + */ +const ComfyUIConfigModal: React.FC = ({ + isOpen, + onClose, + currentConfig, + onConfigUpdate, +}) => { + const [config, setConfig] = useState(currentConfig); + const [testing, setTesting] = useState(false); + const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); + const [saving, setSaving] = useState(false); + const [errors, setErrors] = useState>({}); + + useEffect(() => { + if (isOpen) { + setConfig(currentConfig); + setTestResult(null); + setErrors({}); + } + }, [isOpen, currentConfig]); + + // ============================================================================ + // 表单验证 + // ============================================================================ + + const validateConfig = (configToValidate: ComfyuiConfig): Record => { + const newErrors: Record = {}; + + // 验证 base_url + if (!configToValidate.base_url.trim()) { + newErrors.base_url = 'API 基础 URL 不能为空'; + } else { + try { + new URL(configToValidate.base_url); + } catch { + newErrors.base_url = '请输入有效的 URL 格式'; + } + } + + // 验证 timeout + if (configToValidate.timeout !== undefined) { + if (configToValidate.timeout < 1 || configToValidate.timeout > 300) { + newErrors.timeout = '超时时间应在 1-300 秒之间'; + } + } + + // 验证 retry_attempts + if (configToValidate.retry_attempts !== undefined) { + if (configToValidate.retry_attempts < 0 || configToValidate.retry_attempts > 10) { + newErrors.retry_attempts = '重试次数应在 0-10 次之间'; + } + } + + // 验证 max_concurrency + if (configToValidate.max_concurrency !== undefined) { + if (configToValidate.max_concurrency < 1 || configToValidate.max_concurrency > 50) { + newErrors.max_concurrency = '最大并发数应在 1-50 之间'; + } + } + + return newErrors; + }; + + // ============================================================================ + // 事件处理 + // ============================================================================ + + const handleInputChange = (field: keyof ComfyuiConfig, value: string | number | boolean | undefined) => { + setConfig(prev => ({ ...prev, [field]: value })); + + // 清除对应字段的错误 + if (errors[field]) { + setErrors(prev => { + const newErrors = { ...prev }; + delete newErrors[field]; + return newErrors; + }); + } + }; + + const handleTestConnection = async () => { + const validationErrors = validateConfig(config); + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } + + setTesting(true); + setTestResult(null); + + try { + // 临时更新配置进行测试 + await ComfyuiService.updateConfig(config); + const isConnected = await ComfyuiService.testConnection(); + + setTestResult({ + success: isConnected, + message: isConnected ? '连接成功!' : '连接失败,请检查配置', + }); + } catch (error) { + setTestResult({ + success: false, + message: `连接测试失败: ${error}`, + }); + } finally { + setTesting(false); + } + }; + + const handleSave = async () => { + const validationErrors = validateConfig(config); + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } + + setSaving(true); + try { + await ComfyuiService.updateConfig(config); + onConfigUpdate(config); + onClose(); + } catch (error) { + setTestResult({ + success: false, + message: `保存配置失败: ${error}`, + }); + } finally { + setSaving(false); + } + }; + + const handleReset = () => { + const defaultConfig: ComfyuiConfig = { + base_url: 'https://bowongai-dev--waas-demo-fastapi-webapp.modal.run', + timeout: 30, + retry_attempts: 3, + enable_cache: true, + max_concurrency: 8, + }; + setConfig(defaultConfig); + setErrors({}); + setTestResult(null); + }; + + if (!isOpen) return null; + + return ( +
+
+ {/* 标题栏 */} +
+

ComfyUI 配置设置

+ +
+ + {/* 表单内容 */} +
+ {/* API 基础 URL */} +
+ + handleInputChange('base_url', e.target.value)} + className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${ + errors.base_url ? 'border-red-300' : 'border-gray-300' + }`} + placeholder="https://api.example.com" + /> + {errors.base_url && ( +

{errors.base_url}

+ )} +
+ + {/* 超时设置 */} +
+ + handleInputChange('timeout', parseInt(e.target.value) || undefined)} + className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${ + errors.timeout ? 'border-red-300' : 'border-gray-300' + }`} + placeholder="30" + /> + {errors.timeout && ( +

{errors.timeout}

+ )} +
+ + {/* 重试次数 */} +
+ + handleInputChange('retry_attempts', parseInt(e.target.value) || undefined)} + className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${ + errors.retry_attempts ? 'border-red-300' : 'border-gray-300' + }`} + placeholder="3" + /> + {errors.retry_attempts && ( +

{errors.retry_attempts}

+ )} +
+ + {/* 最大并发数 */} +
+ + handleInputChange('max_concurrency', parseInt(e.target.value) || undefined)} + className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${ + errors.max_concurrency ? 'border-red-300' : 'border-gray-300' + }`} + placeholder="8" + /> + {errors.max_concurrency && ( +

{errors.max_concurrency}

+ )} +
+ + {/* 启用缓存 */} +
+ handleInputChange('enable_cache', e.target.checked)} + className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" + /> + +
+ + {/* 测试结果 */} + {testResult && ( +
+
+ {testResult.success ? ( + + ) : ( + + )} + + {testResult.message} + +
+
+ )} +
+ + {/* 操作按钮 */} +
+ + +
+ + + + + +
+
+
+
+ ); +}; + +export default ComfyUIConfigModal;