import { DynamicFormItemType, IDynamicFormItemSchema, IFileConfig, } from '@/app/infra/entities/form/dynamic'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { ControllerRenderProps } from 'react-hook-form'; import { Button } from '@/components/ui/button'; import { useEffect, useState } from 'react'; import { httpClient } from '@/app/infra/http/HttpClient'; import { LLMModel, Bot, KnowledgeBase, ExternalKnowledgeBase, ApiRespPluginSystemStatus, } from '@/app/infra/entities/api'; import { toast } from 'sonner'; import { HoverCard, HoverCardContent, HoverCardTrigger, } from '@/components/ui/hover-card'; import { useTranslation } from 'react-i18next'; import { extractI18nObject } from '@/i18n/I18nProvider'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent } from '@/components/ui/card'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog'; import { Checkbox } from '@/components/ui/checkbox'; import { Plus, X } from 'lucide-react'; export default function DynamicFormItemComponent({ config, field, onFileUploaded, }: { config: IDynamicFormItemSchema; // eslint-disable-next-line @typescript-eslint/no-explicit-any field: ControllerRenderProps; onFileUploaded?: (fileKey: string) => void; }) { const [llmModels, setLlmModels] = useState([]); const [knowledgeBases, setKnowledgeBases] = useState([]); const [externalKnowledgeBases, setExternalKnowledgeBases] = useState< ExternalKnowledgeBase[] >([]); const [bots, setBots] = useState([]); const [uploading, setUploading] = useState(false); const [kbDialogOpen, setKbDialogOpen] = useState(false); const [tempSelectedKBIds, setTempSelectedKBIds] = useState([]); const [pluginSystemStatus, setPluginSystemStatus] = useState(null); const { t } = useTranslation(); const handleFileUpload = async (file: File): Promise => { const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB if (file.size > MAX_FILE_SIZE) { toast.error(t('plugins.fileUpload.tooLarge')); return null; } try { setUploading(true); const response = await httpClient.uploadPluginConfigFile(file); toast.success(t('plugins.fileUpload.success')); // 通知父组件文件已上传 onFileUploaded?.(response.file_key); return { file_key: response.file_key, mimetype: file.type, }; } catch (error) { toast.error( t('plugins.fileUpload.failed') + ': ' + (error as Error).message, ); return null; } finally { setUploading(false); } }; useEffect(() => { if (config.type === DynamicFormItemType.LLM_MODEL_SELECTOR) { httpClient .getProviderLLMModels() .then((resp) => { setLlmModels(resp.models); }) .catch((err) => { toast.error('Failed to get LLM model list: ' + err.message); }); } }, [config.type]); useEffect(() => { if ( config.type === DynamicFormItemType.KNOWLEDGE_BASE_SELECTOR || config.type === DynamicFormItemType.KNOWLEDGE_BASE_MULTI_SELECTOR ) { httpClient .getKnowledgeBases() .then((resp) => { setKnowledgeBases(resp.bases); }) .catch((err) => { toast.error('Failed to get knowledge base list: ' + err.message); }); // Fetch plugin system status httpClient .getPluginSystemStatus() .then((status) => { setPluginSystemStatus(status); }) .catch((err) => { console.error('Failed to get plugin system status:', err); }); } }, [config.type]); useEffect(() => { if ( (config.type === DynamicFormItemType.KNOWLEDGE_BASE_SELECTOR || config.type === DynamicFormItemType.KNOWLEDGE_BASE_MULTI_SELECTOR) && pluginSystemStatus?.is_enable && pluginSystemStatus?.is_connected ) { httpClient .getExternalKnowledgeBases() .then((resp) => { setExternalKnowledgeBases(resp.bases); }) .catch((err) => { console.error('Failed to get external knowledge base list:', err); }); } }, [config.type, pluginSystemStatus]); useEffect(() => { if (config.type === DynamicFormItemType.BOT_SELECTOR) { httpClient .getBots() .then((resp) => { setBots(resp.bots); }) .catch((err) => { toast.error('Failed to get bot list: ' + err.message); }); } }, [config.type]); switch (config.type) { case DynamicFormItemType.INT: case DynamicFormItemType.FLOAT: return ( field.onChange(Number(e.target.value))} /> ); case DynamicFormItemType.STRING: return ; case DynamicFormItemType.TEXT: return