fix(styles): providers access token

This commit is contained in:
jialin
2026-02-03 18:21:08 +08:00
parent 26e3a1944b
commit 497813eced
29 changed files with 294 additions and 106 deletions
+6 -2
View File
@@ -77,7 +77,10 @@ const OptionNodes = (props: {
const SealCascader: React.FC<
CascaderAutoProps &
SealFormItemProps & { optionNode?: React.FC<{ data: any }> }
SealFormItemProps & {
alwaysFocus?: boolean;
optionNode?: React.FC<{ data: any }>;
}
> = (props) => {
const {
label,
@@ -88,6 +91,7 @@ const SealCascader: React.FC<
options,
allowNull,
isInFormItems = true,
alwaysFocus = false,
optionNode,
notFoundContent,
tagRender,
@@ -167,7 +171,7 @@ const SealCascader: React.FC<
classList={visible ? 'dropdown-visible' : ''}
status={status}
label={label}
isFocus={isFocus}
isFocus={alwaysFocus || isFocus}
required={required}
description={description}
disabled={props.disabled}
+2
View File
@@ -255,6 +255,8 @@ export default {
'models.catalog.precision': 'Precision',
'models.form.gpuPerReplica.tips': 'Enter a custom number',
'models.form.generic_proxy': 'Enable Generic Proxy',
'models.form.enable_model_access': 'Enable Model Access',
'models.form.enable_model_access.tips': 'Enable Model Access',
'models.form.generic_proxy.tips':
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
'models.form.generic_proxy.button': 'Generic Proxy',
+5 -3
View File
@@ -4,13 +4,15 @@ export default {
'providers.table.providerName': 'Provider',
'providers.table.models': 'Models',
'providers.table.proxy': 'Proxy',
'providers.form.tokens.title': ' API Tokens',
'providers.form.tokens.add': 'Add API Token',
'providers.form.tokens.title': ' API Key',
'providers.form.tokens.add': 'Add API Key',
'providers.form.models.add': 'Add Model',
'providers.form.proxy.enable': 'Enable Proxy',
'providers.form.proxy.url': 'Proxy URL',
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
'providers.form.customConfig': 'Custom Configuration',
'providers.form.model.test': 'Test',
'providers.form.model.test.tips': 'Test Connection'
'providers.form.model.test.tips': 'Test Connection',
'providers.form.endpoint.placeholder': 'provider/models',
'providers.form.fallback.token': 'Fallback API Keys'
};
+4
View File
@@ -255,6 +255,8 @@ export default {
'models.catalog.precision': 'Precision',
'models.form.gpuPerReplica.tips': 'Enter a custom number',
'models.form.generic_proxy': 'Enable Generic Proxy',
'models.form.enable_model_access': 'Enable Model Access',
'models.form.enable_model_access.tips': 'Enable Model Access',
'models.form.generic_proxy.tips':
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
'models.form.generic_proxy.button': 'Generic Proxy',
@@ -375,4 +377,6 @@ export default {
// 76. 'models.form.maxContextLength': 'Maximum Context Length',
// 77. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
// 78. 'models.table.instance.benchmark': 'Run Benchmark'
// 77. 'models.form.enable_model_access': 'Enable Model Access',
// 78. 'models.form.enable_model_access.tips': 'Enable Model Access',
// ========== End of To-Do List ==========
+5 -3
View File
@@ -4,13 +4,15 @@ export default {
'providers.table.providerName': 'Provider',
'providers.table.models': 'Models',
'providers.table.proxy': 'Proxy',
'providers.form.tokens.title': ' API Tokens',
'providers.form.tokens.add': 'Add API Token',
'providers.form.tokens.title': ' API Key',
'providers.form.tokens.add': 'Add API Key',
'providers.form.models.add': 'Add Model',
'providers.form.proxy.enable': 'Enable Proxy',
'providers.form.proxy.url': 'Proxy URL',
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
'providers.form.customConfig': 'Custom Configuration',
'providers.form.model.test': 'Test',
'providers.form.model.test.tips': 'Test Connection'
'providers.form.model.test.tips': 'Test Connection',
'providers.form.endpoint.placeholder': 'provider/models',
'providers.form.fallback.token': 'Fallback API Keys'
};
+4
View File
@@ -260,6 +260,8 @@ export default {
'models.catalog.precision': 'Точность',
'models.form.gpuPerReplica.tips': 'Введите произвольное число',
'models.form.generic_proxy': 'Включить универсальный прокси',
'models.form.enable_model_access': 'Enable Model Access',
'models.form.enable_model_access.tips': 'Enable Model Access',
'models.form.generic_proxy.tips':
'После включения универсального прокси вы можете получать доступ к URI-путям, которые не следуют стандарту OpenAI API.',
'models.form.generic_proxy.button': 'Универсальный прокси',
@@ -287,4 +289,6 @@ export default {
// 1. 'models.form.maxContextLength': 'Maximum Context Length',
// 2. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
// 3. 'models.table.instance.benchmark': 'Run Benchmark'
// 2. 'models.form.enable_model_access': 'Enable Model Access',
// 3. 'models.form.enable_model_access.tips': 'Enable Model Access',
// ========== End of To-Do List ==========
+5 -3
View File
@@ -4,13 +4,15 @@ export default {
'providers.table.providerName': 'Provider',
'providers.table.models': 'Models',
'providers.table.proxy': 'Proxy',
'providers.form.tokens.title': ' API Tokens',
'providers.form.tokens.add': 'Add API Token',
'providers.form.tokens.title': ' API Key',
'providers.form.tokens.add': 'Add API Key',
'providers.form.models.add': 'Add Model',
'providers.form.proxy.enable': 'Enable Proxy',
'providers.form.proxy.url': 'Proxy URL',
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
'providers.form.customConfig': 'Custom Configuration',
'providers.form.model.test': 'Test',
'providers.form.model.test.tips': 'Test Connection'
'providers.form.model.test.tips': 'Test Connection',
'providers.form.endpoint.placeholder': 'provider/models',
'providers.form.fallback.token': 'Fallback API Keys'
};
+2
View File
@@ -242,6 +242,8 @@ export default {
'models.catalog.precision': '精度',
'models.form.gpuPerReplica.tips': '输入自定义数值',
'models.form.generic_proxy': '启用通用代理',
'models.form.enable_model_access': '启用模型接入',
'models.form.enable_model_access.tips': '启用模型接入',
'models.form.generic_proxy.tips':
'启用通用代理后可支持访问非 OpenAI-API 标准的 URI 路径。',
'models.form.generic_proxy.button': '通用代理',
+5 -3
View File
@@ -4,13 +4,15 @@ export default {
'providers.table.providerName': '提供商',
'providers.table.models': '模型',
'providers.table.proxy': '代理',
'providers.form.tokens.title': 'API 令牌',
'providers.form.tokens.add': '添加 API 令牌',
'providers.form.tokens.title': 'API Key',
'providers.form.tokens.add': '添加 API Key',
'providers.form.models.add': '添加模型',
'providers.form.proxy.enable': '启用代理',
'providers.form.proxy.url': '代理地址',
'providers.form.proxy.timeout': '代理超时(秒)',
'providers.form.customConfig': '自定义配置',
'providers.form.model.test': '测试',
'providers.form.model.test.tips': '测试连接'
'providers.form.model.test.tips': '测试连接',
'providers.form.endpoint.placeholder': '提供商/模型',
'providers.form.fallback.token': '备用 API Key'
};
+30
View File
@@ -0,0 +1,30 @@
import SealSelect from '@/components/seal-form/seal-select';
import React from 'react';
import { categoryConfig } from './model-tag';
const CategorySelect = (props: any) => {
const { options, ...rest } = props;
const optionRenderer = (option: any) => {
const config = categoryConfig[option.value] || {};
console.log('option:', option, 'config:', config);
return (
<span className="flex-center">
<span style={{ color: config.color }}>
{React.cloneElement(config.icon)}
</span>
<span style={{ marginLeft: 8 }}>{option.label}</span>
</span>
);
};
return (
<SealSelect
options={options}
optionRenderer={optionRenderer}
labelRender={optionRenderer}
{...rest}
/>
);
};
export default CategorySelect;
+3 -2
View File
@@ -3,6 +3,7 @@ import { downloadFile, listFiles, listModels } from '@huggingface/hub';
import { PipelineType } from '@huggingface/tasks';
import { request } from '@umijs/max';
import qs from 'query-string';
import { ACCESS_API } from '../../model-access/apis';
import {
AccessControlFormData,
BackendItem,
@@ -418,7 +419,7 @@ export async function queryBackendList(params?: { cluster_id: number }) {
}
export async function queryModelAccessUserList(id: number) {
return request<{ items: UserListItem[] }>(`${MODELS_API}/${id}/access`, {
return request<{ items: UserListItem[] }>(`${ACCESS_API}/${id}/access`, {
method: 'GET'
});
}
@@ -427,7 +428,7 @@ export async function updateModelAccessUser(params: {
id: number;
data: AccessControlFormData;
}) {
return request(`${MODELS_API}/${params.id}/access`, {
return request(`${ACCESS_API}/${params.id}/access`, {
method: 'POST',
data: params.data
});
@@ -1,7 +1,7 @@
import AlertBlockInfo from '@/components/alert-info/block';
import ModalFooter from '@/components/modal-footer';
import ScrollerModal from '@/components/scroller-modal';
import { PageActionType } from '@/config/types';
import FormDrawer from '@/pages/_components/form-drawer';
import { useIntl } from '@umijs/max';
import { message } from 'antd';
import _ from 'lodash';
@@ -75,19 +75,13 @@ const AccessControlModal: React.FC<
}, [open, currentData]);
return (
<ScrollerModal
<FormDrawer
title={title}
open={open}
centered={true}
onCancel={onCancel}
destroyOnHidden={true}
closeIcon={true}
maskClosable={false}
keyboard={false}
width={700}
height={660}
footer={
<>
<div style={{ paddingInline: 24, paddingBottom: 8 }}>
{isChanged && (
<AlertBlockInfo
type="warning"
@@ -99,7 +93,7 @@ const AccessControlModal: React.FC<
></AlertBlockInfo>
)}
<ModalFooter onOk={handleSumit} onCancel={onCancel}></ModalFooter>
</>
</div>
}
>
<AccessControlForm
@@ -109,7 +103,7 @@ const AccessControlModal: React.FC<
onFinish={handleOnFinish}
onValuesChange={handleOnValuesChange}
/>
</ScrollerModal>
</FormDrawer>
);
};
+7 -29
View File
@@ -1,12 +1,5 @@
import IconFont from '@/components/icon-font';
import { StatusMaps } from '@/config';
import {
AudioOutlined,
EditOutlined,
PictureOutlined,
WechatWorkOutlined
} from '@ant-design/icons';
import React from 'react';
import { EditOutlined } from '@ant-design/icons';
import { backendOptionsMap } from './backend-parameters';
export const backendTipsList = [
@@ -299,42 +292,27 @@ export const modelCategoriesMap = {
export const categoryOptions = [
{
label: 'LLM',
value: modelCategoriesMap.llm,
icon: React.createElement(WechatWorkOutlined, { style: { color: 'green' } })
value: modelCategoriesMap.llm
},
{
label: 'Embedding',
value: modelCategoriesMap.embedding,
icon: React.createElement(IconFont, {
type: 'icon-cube',
style: { color: 'magenta' }
})
value: modelCategoriesMap.embedding
},
{
label: 'Reranker',
value: modelCategoriesMap.reranker,
icon: React.createElement(IconFont, {
type: 'icon-rank1',
style: { color: 'cyan' }
})
value: modelCategoriesMap.reranker
},
{
label: 'Image',
value: modelCategoriesMap.image,
icon: React.createElement(PictureOutlined, { style: { color: 'orange' } })
value: modelCategoriesMap.image
},
{
label: 'Text-to-Speech',
value: modelCategoriesMap.text_to_speech,
icon: React.createElement(IconFont, {
type: 'icon-sound-wave',
style: { color: 'geekblue' }
})
value: modelCategoriesMap.text_to_speech
},
{
label: 'Speech-to-Text',
value: modelCategoriesMap.speech_to_text,
icon: React.createElement(AudioOutlined, { style: { color: 'processing' } })
value: modelCategoriesMap.speech_to_text
}
];
+1
View File
@@ -44,6 +44,7 @@ export type SourceType =
export interface FormData {
image_name?: string;
run_command?: string;
enable_model_access?: boolean;
backend: string;
restart_on_error?: boolean;
env?: Record<string, any>;
+27 -5
View File
@@ -16,8 +16,14 @@ const AdvanceConfig = () => {
const form = Form.useFormInstance();
const EnviromentVars = Form.useWatch('env', form);
const backend = Form.useWatch('backend', form);
const { onValuesChange, isGGUF, modelContextData, flatBackendOptions } =
useFormContext();
const modelAccessEnable = Form.useWatch('enable_model_access', form);
const {
onValuesChange,
backendOptions,
flatBackendOptions,
isGGUF,
modelContextData
} = useFormContext();
const currentBackendOptions = useMemo(() => {
return flatBackendOptions?.find((item) => item.value === backend);
@@ -128,19 +134,35 @@ const AdvanceConfig = () => {
></CheckboxField>
</Form.Item>
<Form.Item<FormData>
name="generic_proxy"
name="enable_model_access"
valuePropName="checked"
style={{ marginBottom: 8 }}
>
<CheckboxField
description={intl.formatMessage({
id: 'models.form.generic_proxy.tips'
id: 'models.form.enable_model_access.tips'
})}
label={intl.formatMessage({
id: 'models.form.generic_proxy'
id: 'models.form.enable_model_access'
})}
></CheckboxField>
</Form.Item>
{modelAccessEnable && (
<Form.Item<FormData>
name="generic_proxy"
valuePropName="checked"
style={{ marginBottom: 8 }}
>
<CheckboxField
description={intl.formatMessage({
id: 'models.form.generic_proxy.tips'
})}
label={intl.formatMessage({
id: 'models.form.generic_proxy'
})}
></CheckboxField>
</Form.Item>
)}
</>
);
};
+1
View File
@@ -9,6 +9,7 @@ export interface FormData {
description: string;
api_tokens: string[];
models: ProviderModel[];
api_key: string;
config: {
type: maasProviderType;
[key: string]: any;
+40 -10
View File
@@ -1,4 +1,5 @@
import ListInput from '@/components/list-input';
import MetadataList from '@/components/metadata-list';
import SealInput from '@/components/seal-form/seal-input';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
@@ -10,17 +11,37 @@ const AccessToken = () => {
const form = Form.useFormInstance<FormData>();
const tokenList = Form.useWatch('api_tokens', form) || [];
const handleOnChange = (values: string[]) => {
form.setFieldValue('api_tokens', values);
const onAdd = () => {
const newList = [...tokenList];
newList.push('');
form.setFieldValue('api_tokens', newList);
};
const onDelete = (index: number) => {
const newList = [...tokenList];
newList.splice(index, 1);
form.setFieldValue('api_tokens', newList);
};
const handleInputChange = (
index: number,
e: React.ChangeEvent<HTMLInputElement>
) => {
const newList = [...tokenList];
newList[index] = e.target.value;
form.setFieldValue('api_tokens', newList);
};
return (
<>
<Form.Item
name="api_tokens"
style={{
marginBottom: 8
}}
rules={[
{
required: true,
required: false,
message: getRuleMessage(
'input',
intl.formatMessage({ id: 'providers.form.tokens.title' })
@@ -28,13 +49,22 @@ const AccessToken = () => {
}
]}
>
<ListInput
required={true}
btnText={intl.formatMessage({ id: 'providers.form.tokens.add' })}
label={intl.formatMessage({ id: 'providers.form.tokens.title' })}
<MetadataList
dataList={tokenList}
onChange={handleOnChange}
></ListInput>
btnText={intl.formatMessage({ id: 'providers.form.tokens.add' })}
label={intl.formatMessage({ id: 'providers.form.fallback.token' })}
onAdd={onAdd}
onDelete={onDelete}
>
{(item, index) => (
<div style={{ width: '100%' }} key={index}>
<SealInput.Password
value={item}
onChange={(e) => handleInputChange(index, e)}
></SealInput.Password>
</div>
)}
</MetadataList>
</Form.Item>
</>
);
@@ -4,6 +4,7 @@ import YamlEditor from '@/pages/_components/yaml-editor';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React, { forwardRef, useImperativeHandle } from 'react';
import AccessToken from './access-token';
import ProxyConfig from './proxy-config';
const AdvanceConfig: React.FC<{
@@ -28,6 +29,7 @@ const AdvanceConfig: React.FC<{
return (
<>
<div data-field="advanceConfig"></div>
<AccessToken></AccessToken>
<ProxyConfig></ProxyConfig>
<Form.Item
hidden
+16
View File
@@ -54,6 +54,22 @@ const Basic = () => {
})}
/>
</Form.Item>
<Form.Item<FormData>
name="api_key"
rules={[
{
required: true,
message: getRuleMessage('input', 'providers.form.tokens.title')
}
]}
>
<SealInput.Password
required
label={intl.formatMessage({
id: 'providers.form.tokens.title'
})}
/>
</Form.Item>
<Form.Item<FormData> name="description">
<SealInput.TextArea
scaleSize={true}
+15 -3
View File
@@ -6,6 +6,7 @@ import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrappe
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import {
forwardRef,
useEffect,
@@ -15,7 +16,6 @@ import {
} from 'react';
import FormContext from '../config/form-context';
import { FormData, MaasProviderItem as ListItem } from '../config/types';
import AccessToken from './access-token';
import AdvanceConfig from './advance-config';
import Basic from './basic';
import SupportedModels from './supported-models';
@@ -63,6 +63,17 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
}
];
const handleOnFinish = (values: FormData) => {
const apiTokens = values.api_tokens?.filter?.(
(item) => item && item.trim() !== ''
);
const data = {
..._.omit(values, ['api_key']),
api_tokens: _.concat([], values.api_key, apiTokens || [])
};
onFinish(data);
};
const handleActiveChange = (key: string[]) => {
setActiveKey(key);
};
@@ -87,6 +98,8 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
) {
form.setFieldsValue({
...currentData,
api_key: currentData.api_tokens?.[0] || '',
api_tokens: currentData.api_tokens?.slice(1) || [],
proxy_enabled: !!currentData.proxy_url
});
}
@@ -108,7 +121,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
<FormContext.Provider value={{ action }}>
<Form
form={form}
onFinish={onFinish}
onFinish={handleOnFinish}
initialValues={{
proxy_enabled: false,
proxy_url: '',
@@ -116,7 +129,6 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
}}
>
<Basic />
<AccessToken />
<CollapsePanel
activeKey={activeKey}
accordion={false}
+1 -1
View File
@@ -48,7 +48,7 @@ const ModelItem: React.FC<ModelItemProps> = ({
const res = await runTestModel({
data: {
model_name: item.name,
api_token: form.getFieldValue('api_tokens')?.[0] || '',
api_token: form.getFieldValue('api_key') || '',
config: {
type: form.getFieldValue(['config', 'type']) || ''
}
@@ -14,12 +14,12 @@ const SupportedModels = () => {
const handleOpenChange = async (open: boolean) => {
try {
await form.validateFields(['api_tokens', ['config', 'type']]);
await form.validateFields(['api_key']);
if (open && providerModelList.length === 0) {
fetchProviderModels({
data: {
api_token: form.getFieldValue('api_tokens')?.[0] || '',
api_token: form.getFieldValue('api_key') || '',
config: {
type: form.getFieldValue(['config', 'type']) || ''
}
@@ -20,11 +20,13 @@ const CellContent = styled.div`
interface ProviderModelProps {
dataList: AccessPointItem[];
onSelect: (val: any, record: any) => void;
sourceModels: any[];
}
interface AccessItemProps {
onSelect: (val: any, record: any) => void;
data: any;
sourceModels: any[];
}
export const childActionList = [
@@ -48,13 +50,24 @@ export const childActionList = [
}
];
const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
const AccessItem: React.FC<AccessItemProps> = ({
onSelect,
data,
sourceModels
}) => {
const intl = useIntl();
const renderProviderSource = () => {
const model = sourceModels.find(
(item: any) => item.value === data.provider_id || item.id === data.model
);
return model.label || '-';
};
return (
<div style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}>
<RowChildren>
<Row gutter={16} style={{ width: '100%' }}>
<Col span={6}>
<Col span={4}>
<CellContent
style={{
paddingInline: 'var(--ant-table-cell-padding-inline)'
@@ -64,7 +77,7 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
</CellContent>
</Col>
<Col span={3}>
<CellContent>-</CellContent>
<CellContent>{renderProviderSource()}</CellContent>
</Col>
<Col span={4}>
<CellContent>
@@ -88,7 +101,7 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
)}
</CellContent>
</Col>
<Col span={3}>
<Col span={4}>
<CellContent>
<AutoTooltip ghost>
<StatusTag
@@ -102,16 +115,16 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
</CellContent>
</Col>
<Col span={5}>
<CellContent style={{ marginLeft: -6 }}>
<CellContent style={{ paddingLeft: 45 }}>
<AutoTooltip ghost minWidth={20}>
{dayjs(data.created_at).format('YYYY-MM-DD HH:mm:ss')}
</AutoTooltip>
</CellContent>
</Col>
<Col span={3}>
<Col span={4}>
<CellContent
style={{
marginLeft: -12
paddingLeft: 38
}}
>
<DropdownButtons
@@ -126,12 +139,21 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
);
};
const AccessPoints: React.FC<ProviderModelProps> = ({ dataList, onSelect }) => {
const AccessPoints: React.FC<ProviderModelProps> = ({
dataList,
onSelect,
sourceModels
}) => {
console.log('AccessPoints dataList:', dataList);
return (
<div>
{dataList.map((item, index) => (
<AccessItem data={item} key={index} onSelect={onSelect}></AccessItem>
<AccessItem
data={item}
key={index}
onSelect={onSelect}
sourceModels={sourceModels}
></AccessItem>
))}
</div>
);
+1
View File
@@ -3,6 +3,7 @@ export interface FormData {
description: string;
categories: any[];
meta: Record<string, any>;
generic_proxy: boolean;
fallback_endpoint: {
provider_model_name?: string;
model_id?: number;
+19 -4
View File
@@ -1,6 +1,7 @@
import CheckboxField from '@/components/seal-form/checkbox-field';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import useAppUtils from '@/hooks/use-app-utils';
import CategorySelect from '@/pages/_components/category-select';
import { categoryOptions } from '@/pages/llmodels/config';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
@@ -31,13 +32,13 @@ const Basic = () => {
}
]}
>
<SealSelect
<CategorySelect
required
options={categoryOptions}
label={intl.formatMessage({ id: 'models.form.categories' })}
></SealSelect>
></CategorySelect>
</Form.Item>
<Form.Item name="description">
<Form.Item name="description" style={{ marginBottom: 8 }}>
<SealInput.TextArea
scaleSize={true}
label={intl.formatMessage({
@@ -45,6 +46,20 @@ const Basic = () => {
})}
></SealInput.TextArea>
</Form.Item>
<Form.Item<FormData>
name="generic_proxy"
valuePropName="checked"
style={{ marginBottom: 8 }}
>
<CheckboxField
description={intl.formatMessage({
id: 'models.form.generic_proxy.tips'
})}
label={intl.formatMessage({
id: 'models.form.generic_proxy'
})}
></CheckboxField>
</Form.Item>
</>
);
};
+26 -1
View File
@@ -5,9 +5,29 @@ import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import styled from 'styled-components';
import { FormData } from '../config/types';
import useEndpointSourceModels from '../hooks/use-endpoint-source-models';
const Inner = styled.div`
display: flex;
align-items: center;
width: 100%;
ul.ant-cascader-menu:first-child {
li[data-path-key='deployments'] {
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
border-bottom: 1px solid var(--ant-color-split);
}
}
}
`;
const EndpointsForm = forwardRef((props, ref) => {
const intl = useIntl();
const { sourceModels, loading, fetchSourceModels } =
@@ -164,6 +184,7 @@ const EndpointsForm = forwardRef((props, ref) => {
showSearch
expandTrigger="hover"
multiple={false}
alwaysFocus={true}
onChange={(value, options) =>
handleEndpointsChange(value, index, options)
}
@@ -174,7 +195,7 @@ const EndpointsForm = forwardRef((props, ref) => {
}}
maxTagCount={1}
placeholder={intl.formatMessage({
id: 'accesses.form.endpoint.model'
id: 'providers.form.endpoint.placeholder'
})}
value={item.value}
options={sourceModels}
@@ -201,6 +222,7 @@ const EndpointsForm = forwardRef((props, ref) => {
showSearch
expandTrigger="hover"
multiple={false}
alwaysFocus={true}
classNames={{
popup: {
root: 'cascader-popup-wrapper gpu-selector'
@@ -209,6 +231,9 @@ const EndpointsForm = forwardRef((props, ref) => {
label={intl.formatMessage({
id: 'accesses.form.endpoint.fallback'
})}
placeholder={intl.formatMessage({
id: 'providers.form.endpoint.placeholder'
})}
maxTagCount={1}
value={fallbackValues.value}
options={sourceModels}
-13
View File
@@ -18,7 +18,6 @@ import { FormData, AccessItem as ListItem } from '../config/types';
import useEditEndpoints from '../hooks/use-edit-endpoints';
import Basic from './basic';
import Endpoints from './endpoints';
import MetaData from './meta-data';
interface ProviderFormProps {
ref?: any;
@@ -50,12 +49,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
icon: <IconFont type="icon-basic" />,
field: 'name'
},
{
value: TABKeysMap.METADATA,
label: intl.formatMessage({ id: 'accesses.form.metadata.title' }),
icon: <IconFont type="icon-database" />,
field: 'metaSize'
},
{
value: TABKeysMap.ENDPOINTS,
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
@@ -202,12 +195,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
accordion={false}
onChange={handleOnCollapseChange}
items={[
{
key: TABKeysMap.METADATA,
label: intl.formatMessage({ id: 'accesses.form.metadata.title' }),
forceRender: true,
children: <MetaData></MetaData>
},
{
key: TABKeysMap.ENDPOINTS,
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
@@ -2,6 +2,7 @@ import { queryModelsList } from '@/pages/llmodels/apis';
import { ListItem as ModelListItem } from '@/pages/llmodels/config/types';
import { queryMaasProviders } from '@/pages/maas-provider/apis';
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
import { useIntl } from '@umijs/max';
import { useState } from 'react';
type EmptyObject = Record<never, never>;
@@ -15,6 +16,7 @@ type CascaderOption<T extends object = EmptyObject> = {
} & Partial<T>;
const useEndpointSourceModels = () => {
const intl = useIntl();
const [sourceModels, setSourceModels] = useState<CascaderOption[]>([]);
const [loading, setLoading] = useState<boolean>(false);
@@ -28,7 +30,19 @@ const useEndpointSourceModels = () => {
const modelsList = [
{
label: 'Deployments',
label: (
<span>
{intl.formatMessage({ id: 'menu.models.deployment' })}
<span
style={{
color: 'var(--ant-color-text-tertiary)',
marginLeft: 4
}}
>
[GPUStack]
</span>
</span>
),
value: 'deployments',
parent: true,
children: models.items?.map?.((model: ModelListItem) => ({
+14 -1
View File
@@ -15,6 +15,7 @@ import { useMemoizedFn } from 'ahooks';
import { message } from 'antd';
import { useAtom } from 'jotai';
import _ from 'lodash';
import { useEffect } from 'react';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import AccessControlModal from '../llmodels/components/access-control-modal';
@@ -35,6 +36,7 @@ import { FormData, AccessItem as ListItem } from './config/types';
import useAccessColumns from './hooks/use-access-columns';
import useAccessControl from './hooks/use-access-control';
import useCreateAccess from './hooks/use-create-access';
import useEndpointSourceModels from './hooks/use-endpoint-source-models';
const Accesses: React.FC = () => {
const {
@@ -69,6 +71,7 @@ const Accesses: React.FC = () => {
closeAccessControlModal,
openAccessControlModalStatus
} = useAccessControl();
const { sourceModels, fetchSourceModels } = useEndpointSourceModels();
const handleClickDropdown = () => {
openAccessModal(
@@ -188,9 +191,19 @@ const Accesses: React.FC = () => {
list: any,
options: { parent?: any; [key: string]: any }
) => {
return <AccessPoints dataList={list} onSelect={onChildSelect} />;
return (
<AccessPoints
dataList={list}
onSelect={onChildSelect}
sourceModels={sourceModels}
/>
);
};
useEffect(() => {
fetchSourceModels();
}, []);
const columns = useAccessColumns(handleSelect);
return (