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, systemInfo, userInfo } from '@/app/infra/http'; import { LLMModel, Bot, KnowledgeBase, EmbeddingModel, } from '@/app/infra/entities/api'; import { toast } from 'sonner'; 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, Eye, Wrench, Trash2, Sparkles, Info, Settings, } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip'; import ModelsDialog from '@/app/home/components/models-dialog/ModelsDialog'; 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 [embeddingModels, setEmbeddingModels] = useState([]); const [knowledgeBases, setKnowledgeBases] = useState([]); const [bots, setBots] = useState([]); const [uploading, setUploading] = useState(false); const [kbDialogOpen, setKbDialogOpen] = useState(false); const [tempSelectedKBIds, setTempSelectedKBIds] = useState([]); const { t } = useTranslation(); const [modelsDialogOpen, setModelsDialogOpen] = useState(false); const fetchLlmModels = () => { httpClient .getProviderLLMModels() .then((resp) => { setLlmModels(resp.models); }) .catch((err) => { toast.error(t('models.getModelListError') + err.msg); }); }; const handleModelsDialogChange = (open: boolean) => { setModelsDialogOpen(open); if (!open) { fetchLlmModels(); } }; 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); } }; // Whether to show Space login CTA in model selectors const showSpaceLoginCTA = !systemInfo.disable_models_service && userInfo?.account_type !== 'space'; const handleSpaceLogin = () => { try { const token = localStorage.getItem('token'); if (!token) { toast.error(t('common.error')); return; } const currentOrigin = window.location.origin; const redirectUri = `${currentOrigin}/auth/space/callback?mode=bind`; httpClient .getSpaceAuthorizeUrl(redirectUri, token) .then((response) => { window.location.href = response.authorize_url; }) .catch(() => { toast.error(t('common.spaceLoginFailed')); }); } catch { toast.error(t('common.spaceLoginFailed')); } }; useEffect(() => { if (config.type === DynamicFormItemType.LLM_MODEL_SELECTOR) { fetchLlmModels(); } }, [config.type]); useEffect(() => { if (config.type === DynamicFormItemType.EMBEDDING_MODEL_SELECTOR) { httpClient .getProviderEmbeddingModels() .then((resp) => { setEmbeddingModels(resp.models); }) .catch((err) => { toast.error(t('embedding.getModelListError') + err.msg); }); } }, [config.type]); useEffect(() => { if (config.type === DynamicFormItemType.MODEL_FALLBACK_SELECTOR) { fetchLlmModels(); } }, [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(t('knowledge.getKnowledgeBaseListError') + err.msg); }); } }, [config.type]); useEffect(() => { if (config.type === DynamicFormItemType.BOT_SELECTOR) { httpClient .getBots() .then((resp) => { setBots(resp.bots); }) .catch((err) => { toast.error(t('bots.getBotListError') + err.msg); }); } }, [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