✨ feat(models): Revamp EditModelModal UI and UX
This commit significantly refactors the `EditModelModal` component to streamline the user interface and enhance usability, aligning it with the interaction patterns found elsewhere in the application. - **Consolidated Layout:** Merged the "Vendor Information" and "Feature Configuration" sections into a single "Basic Information" card. This simplifies the form, reduces clutter, and makes all settings accessible in one view. - **Improved Prefill Groups:** Replaced the separate `Select` dropdowns for tag and endpoint groups with a more intuitive button-based system within the `extraText` of the `TagInput` components. - **Additive Button Logic:** The prefill group buttons now operate in an additive mode. Users can click multiple group buttons to incrementally add tags or endpoints, with duplicates being automatically handled. - **Clear Functionality:** Added "Clear" buttons for both tags and endpoints, allowing users to easily reset the fields. - **Code Cleanup:** Removed the unused `endpointOptions` constant and unnecessary icon imports (`Building`, `Settings`) to keep the codebase clean.
This commit is contained in:
@@ -35,13 +35,13 @@ import {
|
||||
Save,
|
||||
X,
|
||||
FileText,
|
||||
Building,
|
||||
Settings,
|
||||
} from 'lucide-react';
|
||||
import { API, showError, showSuccess } from '../../../../helpers';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useIsMobile } from '../../../../hooks/common/useIsMobile';
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
const nameRuleOptions = [
|
||||
{ label: '精确名称匹配', value: 0 },
|
||||
{ label: '前缀名称匹配', value: 1 },
|
||||
@@ -49,16 +49,6 @@ const nameRuleOptions = [
|
||||
{ label: '后缀名称匹配', value: 3 },
|
||||
];
|
||||
|
||||
const endpointOptions = [
|
||||
{ label: 'OpenAI', value: 'openai' },
|
||||
{ label: 'Anthropic', value: 'anthropic' },
|
||||
{ label: 'Gemini', value: 'gemini' },
|
||||
{ label: 'Image Generation', value: 'image-generation' },
|
||||
{ label: 'Jina Rerank', value: 'jina-rerank' },
|
||||
];
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
const EditModelModal = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -332,23 +322,6 @@ const EditModelModal = (props) => {
|
||||
showClear
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Select
|
||||
field='tag_group'
|
||||
label={t('标签组')}
|
||||
placeholder={t('选择标签组后将自动填充标签')}
|
||||
optionList={tagGroups.map(g => ({ label: g.name, value: g.id }))}
|
||||
showClear
|
||||
onChange={(value) => {
|
||||
const g = tagGroups.find(item => item.id === value);
|
||||
if (g && formApiRef.current) {
|
||||
formApiRef.current.setValue('tags', g.items || []);
|
||||
}
|
||||
}}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Form.TagInput
|
||||
field='tags'
|
||||
@@ -366,23 +339,40 @@ const EditModelModal = (props) => {
|
||||
formApiRef.current.setValue('tags', normalized);
|
||||
}}
|
||||
style={{ width: '100%' }}
|
||||
extraText={(
|
||||
<Space wrap>
|
||||
{tagGroups.map(group => (
|
||||
<Button
|
||||
key={group.id}
|
||||
size='small'
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
if (formApiRef.current) {
|
||||
const currentTags = formApiRef.current.getValue('tags') || [];
|
||||
const newTags = [...currentTags, ...(group.items || [])];
|
||||
const uniqueTags = [...new Set(newTags)];
|
||||
formApiRef.current.setValue('tags', uniqueTags);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{group.name}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
size='small'
|
||||
type='warning'
|
||||
onClick={() => {
|
||||
if (formApiRef.current) {
|
||||
formApiRef.current.setValue('tags', []);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('清除标签')}
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* 供应商信息 */}
|
||||
<Card className='!rounded-2xl shadow-sm border-0'>
|
||||
<div className='flex items-center mb-2'>
|
||||
<Avatar size='small' color='blue' className='mr-2 shadow-md'>
|
||||
<Building size={16} />
|
||||
</Avatar>
|
||||
<div>
|
||||
<Text className='text-lg font-medium'>{t('供应商信息')}</Text>
|
||||
<div className='text-xs text-gray-600'>{t('设置模型的供应商相关信息')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Row gutter={12}>
|
||||
<Col span={24}>
|
||||
<Form.Select
|
||||
field='vendor_id'
|
||||
@@ -400,47 +390,46 @@ const EditModelModal = (props) => {
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* 功能配置 */}
|
||||
<Card className='!rounded-2xl shadow-sm border-0'>
|
||||
<div className='flex items-center mb-2'>
|
||||
<Avatar size='small' color='purple' className='mr-2 shadow-md'>
|
||||
<Settings size={16} />
|
||||
</Avatar>
|
||||
<div>
|
||||
<Text className='text-lg font-medium'>{t('功能配置')}</Text>
|
||||
<div className='text-xs text-gray-600'>{t('设置模型的功能和状态')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Row gutter={12}>
|
||||
<Col span={24}>
|
||||
<Form.Select
|
||||
field='endpoint_group'
|
||||
label={t('端点组')}
|
||||
placeholder={t('选择端点组后将自动填充端点')}
|
||||
optionList={endpointGroups.map(g => ({ label: g.name, value: g.id }))}
|
||||
showClear
|
||||
style={{ width: '100%' }}
|
||||
onChange={(value) => {
|
||||
const g = endpointGroups.find(item => item.id === value);
|
||||
if (g && formApiRef.current) {
|
||||
formApiRef.current.setValue('endpoints', g.items || []);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Form.Select
|
||||
<Form.TagInput
|
||||
field='endpoints'
|
||||
label={t('支持端点')}
|
||||
placeholder={t('选择模型支持的端点类型')}
|
||||
optionList={endpointOptions}
|
||||
multiple
|
||||
placeholder={t('输入端点名称,按回车添加')}
|
||||
addOnBlur
|
||||
showClear
|
||||
style={{ width: '100%' }}
|
||||
extraText={(
|
||||
<Space wrap>
|
||||
{endpointGroups.map(group => (
|
||||
<Button
|
||||
key={group.id}
|
||||
size='small'
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
if (formApiRef.current) {
|
||||
const currentEndpoints = formApiRef.current.getValue('endpoints') || [];
|
||||
const newEndpoints = [...currentEndpoints, ...(group.items || [])];
|
||||
const uniqueEndpoints = [...new Set(newEndpoints)];
|
||||
formApiRef.current.setValue('endpoints', uniqueEndpoints);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{group.name}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
size='small'
|
||||
type='warning'
|
||||
onClick={() => {
|
||||
if (formApiRef.current) {
|
||||
formApiRef.current.setValue('endpoints', []);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('清除端点')}
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
|
||||
@@ -111,7 +111,7 @@ const MissingModelsModal = ({
|
||||
<Typography.Text strong className="!text-[var(--semi-color-text-0)] !text-base">
|
||||
{t('未配置的模型列表')}
|
||||
</Typography.Text>
|
||||
<Typography.Text type="tertiary" className="!text-xs flex items-center">
|
||||
<Typography.Text type="tertiary" size="small">
|
||||
{t('共')} {missingModels.length} {t('个未配置模型')}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user