From 509d1a2e2443318a538dd381a33798696b37c7fd Mon Sep 17 00:00:00 2001 From: zhaoying Date: Sat, 7 Mar 2026 17:18:27 +0800 Subject: [PATCH] feat(web): model select component replace --- web/src/components/ModelSelect/index.tsx | 87 +++ web/src/views/ApplicationConfig/Cluster.tsx | 15 +- .../components/AiPromptModal.tsx | 28 +- .../Knowledge/KnowledgeGlobalConfigModal.tsx | 14 +- web/src/views/ModelManagement/types.ts | 24 +- web/src/views/Prompt/index.tsx | 29 +- .../Knowledge/KnowledgeGlobalConfigModal.tsx | 12 +- .../Properties/ModelConfig/index.tsx | 12 +- .../Workflow/components/Properties/index.tsx | 700 +++++++++--------- web/src/views/Workflow/constant.ts | 21 +- 10 files changed, 501 insertions(+), 441 deletions(-) create mode 100644 web/src/components/ModelSelect/index.tsx diff --git a/web/src/components/ModelSelect/index.tsx b/web/src/components/ModelSelect/index.tsx new file mode 100644 index 00000000..e5fc280a --- /dev/null +++ b/web/src/components/ModelSelect/index.tsx @@ -0,0 +1,87 @@ +/* + * @Author: ZhaoYing + * @Date: 2026-03-07 16:49:59 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-03-07 17:14:57 + */ +import { useEffect, useState, type FC } from 'react'; +import { Select, Flex, Space } from 'antd'; +import type { SelectProps } from 'antd/es/select'; +import { useTranslation } from 'react-i18next'; + +import { getModelList } from '@/api/models'; +import type { Query, Model } from '@/views/ModelManagement/types'; +import { getListLogoUrl } from '@/views/ModelManagement/utils'; +import Tag from '@/components/Tag'; + +/** Extends AntD SelectProps; omits filterOption since it's handled internally */ +interface ModelSelectProps extends SelectProps { + /** Extra query params passed to getModelList */ + params?: Query; + placeholder?: string; +} + +const ModelSelect: FC = ({ + params, + placeholder, + ...props +}) => { + const { t } = useTranslation(); + const [options, setOptions] = useState([]); + + // Fetch active models whenever params change; stringify for stable deep comparison + useEffect(() => { + getModelList({ + ...(params ?? {}), + pagesize: 100, + is_active: true + }).then((res) => { + setOptions((res as { items: Model[] }).items ?? []); + }); + }, [JSON.stringify(params)]); + + // Render the selected value inside the trigger with logo + truncated name + const labelRender: SelectProps['labelRender'] = ({ value }) => { + const item = options.find((o) => o.id === value); + if (!item) return undefined; + const logo = getListLogoUrl(item.provider, item.logo as string); + return ( + + {logo && } +
{item.name}
+
+ ); + }; + + return ( + - : config.type === 'textarea' - ? - : config.type === 'select' - ? + : config.type === 'textarea' + ? + : config.type === 'select' + ?