fix: ui issues

This commit is contained in:
jialin
2026-02-06 11:13:49 +08:00
parent d54722609c
commit 7f3d6bb55f
35 changed files with 364 additions and 141 deletions
+1 -4
View File
@@ -42,10 +42,7 @@ const AccessToken = () => {
rules={[
{
required: false,
message: getRuleMessage(
'input',
intl.formatMessage({ id: 'providers.form.tokens.title' })
)
message: getRuleMessage('input', 'providers.form.tokens.title')
}
]}
>
+28 -7
View File
@@ -4,12 +4,15 @@ import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import ProviderLogo from '../components/provider-logo';
import { maasProviderOptions } from '../config/providers';
import { maasProviderOptions, ProviderEnum } from '../config/providers';
import { FormData } from '../config/types';
const Basic = () => {
const Basic: React.FC<{
onAPIKeyBlur?: (e: any) => void;
}> = ({ onAPIKeyBlur }) => {
const intl = useIntl();
const form = Form.useFormInstance<FormData>();
const providerType = Form.useWatch(['config', 'type'], form);
const { getRuleMessage } = useAppUtils();
const optionRender = (option: any) => {
@@ -30,7 +33,17 @@ const Basic = () => {
return (
<>
<Form.Item<FormData> name="name" data-field="name">
<Form.Item<FormData>
name="name"
data-field="name"
required
rules={[
{
required: true,
message: getRuleMessage('input', 'common.table.name')
}
]}
>
<SealInput.Input
required
label={intl.formatMessage({
@@ -43,10 +56,7 @@ const Basic = () => {
rules={[
{
required: true,
message: getRuleMessage(
'select',
intl.formatMessage({ id: 'common.table.type' })
)
message: getRuleMessage('select', 'common.table.type')
}
]}
>
@@ -63,6 +73,16 @@ const Basic = () => {
})}
/>
</Form.Item>
{providerType === ProviderEnum.OPENAI && (
<Form.Item<FormData> name={['config', 'openaiCustomUrl']}>
<SealInput.Input
placeholder="http://<your-inference-server>/v1"
label={intl.formatMessage({
id: 'providers.form.custombeckendUrl'
})}
/>
</Form.Item>
)}
<Form.Item<FormData>
name="api_key"
rules={[
@@ -74,6 +94,7 @@ const Basic = () => {
>
<SealInput.Password
required
onBlur={onAPIKeyBlur}
label={intl.formatMessage({
id: 'providers.form.tokens.title'
})}
+3 -1
View File
@@ -107,7 +107,9 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
api_key: currentData.api_tokens?.[0] || '',
api_tokens: currentData.api_tokens?.slice(1) || [],
proxy_enabled: !!currentData.proxy_url,
custom_config: json2Yaml(_.omit(currentData.config, ['type']) || {})
custom_config: json2Yaml(
_.omit(currentData.config, ['type', 'openaiCustomUrl']) || {}
)
});
}
}, [form, currentData, action]);
+21 -10
View File
@@ -3,8 +3,8 @@ import SealSelect from '@/components/seal-form/seal-select';
import { categoryOptions } from '@/pages/llmodels/config';
import {
CheckCircleFilled,
CloseCircleFilled,
LoadingOutlined
LoadingOutlined,
WarningFilled
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Form, Tooltip } from 'antd';
@@ -27,9 +27,15 @@ const SelectWrapper = styled.div`
`;
interface ModelItemProps {
onOpenChange: (open: boolean) => void;
onOpenChange?: (open: boolean) => void;
onChange: (data: ProviderModel) => void;
providerModelList: Global.BaseOption<string>[];
providerModelList: Global.BaseOption<
string,
{
category: string;
accessible: boolean;
}
>[];
selectedModelList: ProviderModel[];
item: ProviderModel;
loading?: boolean;
@@ -63,10 +69,9 @@ const ModelItem: React.FC<ModelItemProps> = ({
});
};
const handleOnChange = (value: string) => {
const handleOnChange = (value: string, option: any) => {
onChange({
...item,
accessible: null,
...option,
name: value
});
};
@@ -79,20 +84,26 @@ const ModelItem: React.FC<ModelItemProps> = ({
};
const renderSuffixIcon = () => {
console.log(
'testLoading',
testLoading,
item.accessible,
item.accessible === false
);
if (testLoading) {
return <LoadingOutlined />;
}
if (item.accessible === true) {
return (
<CheckCircleFilled
style={{ color: 'var(--ant-color-success)', fontSize: 16 }}
style={{ color: 'var(--ant-color-success)', fontSize: 14 }}
/>
);
}
if (item.accessible === false) {
return (
<CloseCircleFilled
style={{ color: 'var(--ant-color-error)', fontSize: 16 }}
<WarningFilled
style={{ color: 'var(--ant-color-error)', fontSize: 14 }}
/>
);
}
@@ -1,6 +1,8 @@
import MetadataList from '@/components/metadata-list';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import { useRef } from 'react';
import { FormData, ProviderModel } from '../config/types';
import { useQueryProviderModels } from '../hooks/use-query-provider-models';
import ModelItem from './model-item';
@@ -11,15 +13,26 @@ const SupportedModels = () => {
useQueryProviderModels();
const form = Form.useFormInstance<FormData>();
const modelList = Form.useWatch('models', form) || [];
const prevAPIKeyRef = useRef<string>('');
const { getRuleMessage } = useAppUtils();
const handleOpenChange = async (open: boolean) => {
try {
await form.validateFields(['api_key']);
if (open && providerModelList.length === 0) {
const currentAPIKey = form.getFieldValue('api_key') || '';
// Avoid repeated requests with the same API key
if (
open &&
providerModelList.length === 0 &&
prevAPIKeyRef.current !== currentAPIKey &&
currentAPIKey
) {
prevAPIKeyRef.current = currentAPIKey;
fetchProviderModels({
data: {
api_token: form.getFieldValue('api_key') || '',
api_token: currentAPIKey,
config: {
type: form.getFieldValue(['config', 'type']) || ''
}
@@ -55,7 +68,33 @@ const SupportedModels = () => {
return (
<>
<Form.Item name="models" data-field="supportedModels">
<Form.Item
name="models"
data-field="supportedModels"
rules={[
{
required: true,
validator: async (_, value) => {
if (!value || value.length === 0) {
return Promise.reject(
new Error(
getRuleMessage('input', 'providers.form.rules.models')
)
);
}
if (value.some((item: ProviderModel) => !item.name)) {
return Promise.reject(
new Error(
getRuleMessage('select', 'providers.form.rules.model')
)
);
}
return Promise.resolve();
}
}
]}
>
<MetadataList
styles={{
wrapper: {