Просмотр исходного кода

✨ refactor: unify model-select searching & UX across the dashboard

This patch standardises how all “model” (and related) `<Select>` components handle searching.

Highlights
• Added a shared helper `modelSelectFilter` to `helpers/utils.js` – performs case-insensitive  value-based matching, independent of ReactNode labels.
• Removed the temporary `helpers/selectFilter.js`; all components now import from the core helpers barrel.
• Updated Selects to use the new filter *and* set `autoClearSearchValue={false}` so the query text is preserved after a choice is made.

Affected components
• Channel editor (EditChannelModal) – channel type & model lists
• Tag editor (EditTagModal) – model list
• Token editor (EditTokenModal) – model-limit list
• Playground SettingsPanel – model selector

Benefits
✓ Consistent search behaviour across the app
✓ Better user experience when selecting multiple items
✓ Cleaner codebase with one canonical filter implementation
t0ng7u 7 месяцев назад
Родитель
Сommit
847a8c8c4d

+ 3 - 3
web/src/components/playground/SettingsPanel.js

@@ -33,7 +33,7 @@ import {
   Settings,
 } from 'lucide-react';
 import { useTranslation } from 'react-i18next';
-import { renderGroupOption } from '../../helpers';
+import { renderGroupOption, modelSelectFilter } from '../../helpers';
 import ParameterControl from './ParameterControl';
 import ImageUrlInput from './ImageUrlInput';
 import ConfigManager from './ConfigManager';
@@ -173,8 +173,8 @@ const SettingsPanel = ({
             name='model'
             required
             selection
-            searchPosition='dropdown'
-            filter
+            filter={modelSelectFilter}
+            autoClearSearchValue={false}
             onChange={(value) => onInputChange('model', value)}
             value={inputs.model}
             autoComplete='new-password'

+ 5 - 3
web/src/components/table/channels/modals/EditChannelModal.jsx

@@ -46,7 +46,7 @@ import {
   Col,
   Highlight,
 } from '@douyinfe/semi-ui';
-import { getChannelModels, copy, getChannelIcon, getModelCategories } from '../../../../helpers';
+import { getChannelModels, copy, getChannelIcon, getModelCategories, modelSelectFilter } from '../../../../helpers';
 import {
   IconSave,
   IconClose,
@@ -853,7 +853,8 @@ const EditChannelModal = (props) => {
                     rules={[{ required: true, message: t('请选择渠道类型') }]}
                     optionList={channelOptionList}
                     style={{ width: '100%' }}
-                    filter
+                    filter={modelSelectFilter}
+                    autoClearSearchValue={false}
                     searchPosition='dropdown'
                     onSearch={(value) => setChannelSearchValue(value)}
                     renderOptionItem={renderChannelOption}
@@ -1251,7 +1252,8 @@ const EditChannelModal = (props) => {
                     placeholder={t('请选择该渠道所支持的模型')}
                     rules={[{ required: true, message: t('请选择模型') }]}
                     multiple
-                    filter
+                    filter={modelSelectFilter}
+                    autoClearSearchValue={false}
                     searchPosition='dropdown'
                     optionList={modelOptions}
                     style={{ width: '100%' }}

+ 3 - 1
web/src/components/table/channels/modals/EditTagModal.jsx

@@ -25,6 +25,7 @@ import {
   showSuccess,
   showWarning,
   verifyJSON,
+  modelSelectFilter,
 } from '../../../../helpers';
 import {
   SideSheet,
@@ -394,7 +395,8 @@ const EditTagModal = (props) => {
                     label={t('模型')}
                     placeholder={t('请选择该渠道所支持的模型,留空则不更改')}
                     multiple
-                    filter
+                    filter={modelSelectFilter}
+                    autoClearSearchValue={false}
                     searchPosition='dropdown'
                     optionList={modelOptions}
                     style={{ width: '100%' }}

+ 3 - 1
web/src/components/table/tokens/modals/EditTokenModal.jsx

@@ -26,6 +26,7 @@ import {
   renderGroupOption,
   renderQuotaWithPrompt,
   getModelCategories,
+  modelSelectFilter,
 } from '../../../../helpers';
 import { useIsMobile } from '../../../../hooks/common/useIsMobile.js';
 import {
@@ -513,7 +514,8 @@ const EditTokenModal = (props) => {
                       multiple
                       optionList={models}
                       extraText={t('非必要,不建议启用模型限制')}
-                      filter
+                      filter={modelSelectFilter}
+                      autoClearSearchValue={false}
                       searchPosition='dropdown'
                       showClear
                       style={{ width: '100%' }}

+ 10 - 0
web/src/helpers/utils.js

@@ -557,3 +557,13 @@ export function setTableCompactMode(compact, tableKey = 'global') {
   modes[tableKey] = compact;
   writeTableCompactModes(modes);
 }
+
+// -------------------------------
+// Select 组件统一过滤逻辑
+// 解决 label 为 ReactNode(带图标等)时无法用内置 filter 搜索的问题。
+// 使用方式: <Select filter={modelSelectFilter} ... />
+export const modelSelectFilter = (input, option) => {
+  if (!input) return true;
+  const val = (option?.value || '').toString().toLowerCase();
+  return val.includes(input.trim().toLowerCase());
+};