feat: provider form
This commit is contained in:
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
|
|||||||
// import './iconfont/iconfont.js';
|
// import './iconfont/iconfont.js';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_qm5jah0zmp8.js'
|
scriptUrl: '//at.alicdn.com/t/c/font_4613488_j0qgzymxj98.js'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ interface ListInputProps {
|
|||||||
onChange: (data: string[]) => void;
|
onChange: (data: string[]) => void;
|
||||||
onBlur?: (e: any, index: number) => void;
|
onBlur?: (e: any, index: number) => void;
|
||||||
onDelete?: (index: number) => void;
|
onDelete?: (index: number) => void;
|
||||||
|
renderItem?: (
|
||||||
|
data: any,
|
||||||
|
props: {
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
onBlur?: (e: any) => void;
|
||||||
|
}
|
||||||
|
) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListInput: React.FC<ListInputProps> = (props) => {
|
const ListInput: React.FC<ListInputProps> = (props) => {
|
||||||
@@ -28,7 +35,8 @@ const ListInput: React.FC<ListInputProps> = (props) => {
|
|||||||
btnText,
|
btnText,
|
||||||
options,
|
options,
|
||||||
labelExtra,
|
labelExtra,
|
||||||
trim = true
|
trim = true,
|
||||||
|
renderItem
|
||||||
} = props;
|
} = props;
|
||||||
const [list, setList] = React.useState<{ value: string; uid: number }[]>([]);
|
const [list, setList] = React.useState<{ value: string; uid: number }[]>([]);
|
||||||
const countRef = React.useRef(0);
|
const countRef = React.useRef(0);
|
||||||
@@ -92,12 +100,14 @@ const ListInput: React.FC<ListInputProps> = (props) => {
|
|||||||
<ListItem
|
<ListItem
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
options={options}
|
options={options}
|
||||||
|
data={item}
|
||||||
key={item.uid}
|
key={item.uid}
|
||||||
value={item.value}
|
value={item.value}
|
||||||
onBlur={(e) => onBlur?.(e, index)}
|
onBlur={(e) => onBlur?.(e, index)}
|
||||||
onRemove={() => handleOnRemove(index)}
|
onRemove={() => handleOnRemove(index)}
|
||||||
onChange={(val) => handleOnChange(val, index)}
|
onChange={(val) => handleOnChange(val, index)}
|
||||||
trim={trim}
|
trim={trim}
|
||||||
|
renderItem={renderItem}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -8,11 +8,19 @@ interface LabelItemProps {
|
|||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
onBlur?: (e: any) => void;
|
onBlur?: (e: any) => void;
|
||||||
|
renderItem?: (
|
||||||
|
data: any,
|
||||||
|
props: {
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
onBlur?: (e: any) => void;
|
||||||
|
}
|
||||||
|
) => React.ReactNode;
|
||||||
value: string;
|
value: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
options?: Global.HintOptions[];
|
options?: Global.HintOptions[];
|
||||||
trim?: boolean;
|
trim?: boolean;
|
||||||
|
data?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem: React.FC<LabelItemProps> = (props) => {
|
const ListItem: React.FC<LabelItemProps> = (props) => {
|
||||||
@@ -23,7 +31,9 @@ const ListItem: React.FC<LabelItemProps> = (props) => {
|
|||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
options,
|
options,
|
||||||
trim = true
|
trim = true,
|
||||||
|
data,
|
||||||
|
renderItem
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const handleOnChange = (value: any) => {
|
const handleOnChange = (value: any) => {
|
||||||
@@ -32,15 +42,22 @@ const ListItem: React.FC<LabelItemProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="list-item">
|
<div className="list-item">
|
||||||
<HintInput
|
{renderItem ? (
|
||||||
value={value}
|
renderItem(data, {
|
||||||
onChange={handleOnChange}
|
onChange: handleOnChange,
|
||||||
onBlur={onBlur}
|
onBlur
|
||||||
label={label}
|
})
|
||||||
sourceOptions={options}
|
) : (
|
||||||
trim={trim}
|
<HintInput
|
||||||
placeholder={props.placeholder}
|
value={value}
|
||||||
/>
|
onChange={handleOnChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
label={label}
|
||||||
|
sourceOptions={options}
|
||||||
|
trim={trim}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
className="btn"
|
className="btn"
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import Wrapper from './wrapper';
|
|||||||
import SelectWrapper from './wrapper/select';
|
import SelectWrapper from './wrapper/select';
|
||||||
|
|
||||||
const SealSelect: React.FC<
|
const SealSelect: React.FC<
|
||||||
SelectProps & SealFormItemProps & { footer?: React.ReactNode }
|
SelectProps &
|
||||||
|
SealFormItemProps & { footer?: React.ReactNode; alwaysFocus?: boolean }
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
const {
|
const {
|
||||||
label,
|
label,
|
||||||
@@ -25,6 +26,7 @@ const SealSelect: React.FC<
|
|||||||
notFoundContent = null,
|
notFoundContent = null,
|
||||||
loading,
|
loading,
|
||||||
footer,
|
footer,
|
||||||
|
alwaysFocus = false,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -99,7 +101,7 @@ const SealSelect: React.FC<
|
|||||||
className="seal-select-wrapper"
|
className="seal-select-wrapper"
|
||||||
status={status}
|
status={status}
|
||||||
label={label}
|
label={label}
|
||||||
isFocus={isFocus}
|
isFocus={alwaysFocus || isFocus}
|
||||||
required={required}
|
required={required}
|
||||||
description={description}
|
description={description}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import styled from 'styled-components';
|
|||||||
import { BORDERRADIUS, INPUT_INNER_PADDING, INPUTHEIGHT } from '../config';
|
import { BORDERRADIUS, INPUT_INNER_PADDING, INPUTHEIGHT } from '../config';
|
||||||
|
|
||||||
const SelectWrapper = styled.div`
|
const SelectWrapper = styled.div`
|
||||||
|
flex: 1;
|
||||||
.seal-select-wrapper {
|
.seal-select-wrapper {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@@ -89,6 +90,9 @@ const SelectWrapper = styled.div`
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
.ant-select .ant-select-content {
|
||||||
|
padding-block: 0px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ant-select-selection-overflow-item > span {
|
.ant-select-selection-overflow-item > span {
|
||||||
@@ -118,7 +122,7 @@ const SelectWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-select-content {
|
.ant-select-content {
|
||||||
padding-block: 20px 0 !important;
|
padding-block: 20px 0;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
&.ant-cascader {
|
&.ant-cascader {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { request } from '@umijs/max';
|
import { request } from '@umijs/max';
|
||||||
import { FormData, MaasProviderItem } from '../config/types';
|
import { FormData, MaasProviderItem } from '../config/types';
|
||||||
|
|
||||||
export const MAAS_PROVIDERS_API = '/maas-providers';
|
export const MAAS_PROVIDERS_API = '/models';
|
||||||
|
|
||||||
export const PROVIDER_MODELS_API = '/maas-provider-models';
|
export const PROVIDER_MODELS_API = '/models';
|
||||||
|
|
||||||
export async function queryMaasProviders(
|
export async function queryMaasProviders(
|
||||||
params: Global.SearchParams,
|
params: Global.SearchParams,
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
import { categoryOptions, modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
|
import {
|
||||||
|
CheckCircleOutlined,
|
||||||
|
CloseCircleOutlined,
|
||||||
|
ExclamationCircleOutlined
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { Flex, Tag } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface ProviderModelProps {
|
interface ProviderModelProps {
|
||||||
@@ -6,8 +13,61 @@ interface ProviderModelProps {
|
|||||||
providerId: number;
|
providerId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const models: {
|
||||||
|
name: string;
|
||||||
|
status: 'accessible' | 'inaccessible' | 'none';
|
||||||
|
type: string;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
name: 'model-1',
|
||||||
|
status: 'accessible',
|
||||||
|
type: modelCategoriesMap.llm
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'model-2',
|
||||||
|
status: 'inaccessible',
|
||||||
|
type: modelCategoriesMap.embedding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'model-3',
|
||||||
|
status: 'none',
|
||||||
|
type: modelCategoriesMap.image
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'model-4',
|
||||||
|
status: 'accessible',
|
||||||
|
type: modelCategoriesMap.llm
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const ProviderModels: React.FC<ProviderModelProps> = () => {
|
const ProviderModels: React.FC<ProviderModelProps> = () => {
|
||||||
return <div>Provider Models Component</div>;
|
const iconsMap = {
|
||||||
|
accessible: <CheckCircleOutlined />,
|
||||||
|
inaccessible: <CloseCircleOutlined />,
|
||||||
|
none: <ExclamationCircleOutlined />
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div style={{ paddingInline: 16 }}>
|
||||||
|
<Flex gap="8px" wrap="wrap">
|
||||||
|
{models.map((model) => (
|
||||||
|
<Tag
|
||||||
|
key={model.name}
|
||||||
|
icon={iconsMap[model.status]}
|
||||||
|
color={
|
||||||
|
model.status === 'accessible'
|
||||||
|
? 'success'
|
||||||
|
: model.status === 'inaccessible'
|
||||||
|
? 'red'
|
||||||
|
: 'gray'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{model.name} (
|
||||||
|
{categoryOptions.find((item) => item.value === model.type)?.label})
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProviderModels;
|
export default ProviderModels;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const maasProviderLabelMap = {
|
|||||||
[maasProviderValueMap.Doubao]: 'Doubao',
|
[maasProviderValueMap.Doubao]: 'Doubao',
|
||||||
[maasProviderValueMap.Qwen]: 'Qwen',
|
[maasProviderValueMap.Qwen]: 'Qwen',
|
||||||
[maasProviderValueMap.OpenAI]: 'OpenAI',
|
[maasProviderValueMap.OpenAI]: 'OpenAI',
|
||||||
[maasProviderValueMap.Deepseek]: 'Deepseek',
|
[maasProviderValueMap.Deepseek]: 'DeepSeek',
|
||||||
[maasProviderValueMap.Anthropic]: 'Anthropic'
|
[maasProviderValueMap.Anthropic]: 'Anthropic'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import ListInput from '@/components/list-input';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form } from 'antd';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
|
const AccessToken = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const form = Form.useFormInstance<FormData>();
|
||||||
|
|
||||||
|
const handleOnChange = (values: string[]) => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item name="tokens">
|
||||||
|
<ListInput
|
||||||
|
btnText="Add Token"
|
||||||
|
label="Access Tokens"
|
||||||
|
dataList={[]}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
></ListInput>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccessToken;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import { PageActionType } from '@/config/types';
|
||||||
|
import YamlEditor from '@/pages/_components/yaml-editor';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form } from 'antd';
|
||||||
|
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||||
|
import { maasProviderType } from '../config';
|
||||||
|
|
||||||
|
const AdvanceConfig: React.FC<{
|
||||||
|
action: PageActionType;
|
||||||
|
provider?: maasProviderType;
|
||||||
|
ref?: any;
|
||||||
|
}> = forwardRef(({ action, provider }, ref) => {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const intl = useIntl();
|
||||||
|
const editorRef = React.useRef<any>(null);
|
||||||
|
const [fileContent, setFileContent] = React.useState<string>('');
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
getYamlValue: () => {
|
||||||
|
return editorRef.current?.getValue();
|
||||||
|
},
|
||||||
|
setYamlValue: (values: any) => {
|
||||||
|
console.log('setYamlValue:', values);
|
||||||
|
editorRef.current?.setValue(values || '');
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div data-field="customConfig"></div>
|
||||||
|
<Form.Item
|
||||||
|
hidden
|
||||||
|
name="custom_config"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: false,
|
||||||
|
message: ''
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealInput.TextArea required={false} trim={false}></SealInput.TextArea>
|
||||||
|
</Form.Item>
|
||||||
|
<YamlEditor
|
||||||
|
ref={editorRef}
|
||||||
|
title={'Yaml'}
|
||||||
|
value={fileContent}
|
||||||
|
height={300}
|
||||||
|
onUpload={(content) => {
|
||||||
|
setFileContent(content);
|
||||||
|
}}
|
||||||
|
></YamlEditor>
|
||||||
|
<div className="scroller-to-holder" style={{ height: 1 }}></div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AdvanceConfig;
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form } from 'antd';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
|
const Basic = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const form = Form.useFormInstance<FormData>();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item name="name" data-field="name">
|
||||||
|
<SealInput.Input
|
||||||
|
required
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'common.table.name'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="provider" hidden>
|
||||||
|
<SealInput.Input
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'providers.table.providerName'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="description">
|
||||||
|
<SealInput.TextArea
|
||||||
|
scaleSize={true}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'common.table.description'
|
||||||
|
})}
|
||||||
|
></SealInput.TextArea>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Basic;
|
||||||
@@ -1,17 +1,75 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||||
|
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
|
||||||
|
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import { forwardRef, useImperativeHandle } from 'react';
|
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
||||||
|
import { maasProviderType } from '../config';
|
||||||
import { MaasProviderItem as ListItem } from '../config/types';
|
import { 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';
|
||||||
|
|
||||||
interface ProviderFormProps {
|
interface ProviderFormProps {
|
||||||
ref?: any;
|
ref?: any;
|
||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
|
provider?: maasProviderType;
|
||||||
currentData?: ListItem; // Used when action is EDIT
|
currentData?: ListItem; // Used when action is EDIT
|
||||||
onFinish: (values: FormData) => void;
|
onFinish: (values: FormData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TABKeysMap = {
|
||||||
|
BASIC: 'basic',
|
||||||
|
SUPPORTEDMODELS: 'supportedModels',
|
||||||
|
CUSTOMCONFIG: 'customConfig',
|
||||||
|
ADVANCED: 'advanced'
|
||||||
|
};
|
||||||
|
|
||||||
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
|
const { action, provider, currentData, onFinish } = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
|
const [activeKey, setActiveKey] = useState<string[]>([TABKeysMap.BASIC]);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const scrollTabsRef = useRef<any>(null);
|
||||||
|
|
||||||
|
const segmentOptions = [
|
||||||
|
{
|
||||||
|
value: TABKeysMap.BASIC,
|
||||||
|
label: 'Basic',
|
||||||
|
icon: <IconFont type="icon-basic" />,
|
||||||
|
field: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: TABKeysMap.SUPPORTEDMODELS,
|
||||||
|
label: 'Supported Models',
|
||||||
|
icon: <IconFont type="icon-speed" />,
|
||||||
|
field: 'supportedModels'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: TABKeysMap.CUSTOMCONFIG,
|
||||||
|
label: 'Custom Config',
|
||||||
|
icon: <IconFont type="icon-settings" />,
|
||||||
|
field: 'customConfig'
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// value: TABKeysMap.ADVANCED,
|
||||||
|
// label: intl.formatMessage({ id: 'resources.form.advanced' }),
|
||||||
|
// icon: <IconFont type="icon-settings" />,
|
||||||
|
// field: 'categories'
|
||||||
|
// }
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleActiveChange = (key: string[]) => {
|
||||||
|
setActiveKey(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnCollapseChange = (keys: string | string[]) => {
|
||||||
|
setActiveKey(Array.isArray(keys) ? keys : [keys]);
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
@@ -23,9 +81,47 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form form={form} layout="vertical">
|
<ScrollSpyTabs
|
||||||
{/* Form fields go here */}
|
ref={scrollTabsRef}
|
||||||
</Form>
|
defaultTarget="basic"
|
||||||
|
segmentOptions={segmentOptions}
|
||||||
|
activeKey={activeKey}
|
||||||
|
setActiveKey={handleActiveChange}
|
||||||
|
segmentedTop={{
|
||||||
|
top: 0,
|
||||||
|
offsetTop: 96
|
||||||
|
}}
|
||||||
|
getScrollElementScrollableHeight={getScrollElementScrollableHeight}
|
||||||
|
>
|
||||||
|
<Form form={form}>
|
||||||
|
<Basic />
|
||||||
|
<AccessToken />
|
||||||
|
<CollapsePanel
|
||||||
|
activeKey={activeKey}
|
||||||
|
accordion={false}
|
||||||
|
onChange={handleOnCollapseChange}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: TABKeysMap.SUPPORTEDMODELS,
|
||||||
|
label: 'Supported Models',
|
||||||
|
forceRender: true,
|
||||||
|
children: <SupportedModels></SupportedModels>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: TABKeysMap.CUSTOMCONFIG,
|
||||||
|
label: 'Custom Config',
|
||||||
|
forceRender: true,
|
||||||
|
children: (
|
||||||
|
<AdvanceConfig
|
||||||
|
action={action}
|
||||||
|
provider={provider}
|
||||||
|
></AdvanceConfig>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
></CollapsePanel>
|
||||||
|
</Form>
|
||||||
|
</ScrollSpyTabs>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import ListInput from '@/components/list-input';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
|
import { CheckCircleFilled } from '@ant-design/icons';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Button, Form } from 'antd';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
|
const SelectWrapper = styled.div`
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
.icon-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SupportedModels = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const form = Form.useFormInstance<FormData>();
|
||||||
|
|
||||||
|
const renderModelItem = (
|
||||||
|
data: any,
|
||||||
|
{
|
||||||
|
onChange,
|
||||||
|
onBlur
|
||||||
|
}: { onChange: (value: string) => void; onBlur?: (e: any) => void }
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<SelectWrapper>
|
||||||
|
<SealSelect
|
||||||
|
alwaysFocus={true}
|
||||||
|
value={data.value}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
options={[
|
||||||
|
{ label: 'Model A', value: 'model_a' },
|
||||||
|
{ label: 'Model B', value: 'model_b' },
|
||||||
|
{ label: 'Model C', value: 'model_c' }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<span className="icon-wrapper">
|
||||||
|
<CheckCircleFilled
|
||||||
|
style={{ color: 'var(--ant-color-success)', fontSize: 16 }}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<Button type="link" size="small">
|
||||||
|
Test
|
||||||
|
</Button>
|
||||||
|
</SelectWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnChange = (values: string[]) => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item name="models">
|
||||||
|
<div data-field="supportedModels"></div>
|
||||||
|
<ListInput
|
||||||
|
btnText="Add Model"
|
||||||
|
label="Supported Models"
|
||||||
|
dataList={[]}
|
||||||
|
renderItem={renderModelItem}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
></ListInput>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SupportedModels;
|
||||||
@@ -19,8 +19,15 @@ const useCreateProvider = (options: { refresh: () => void }) => {
|
|||||||
provider: null
|
provider: null
|
||||||
});
|
});
|
||||||
|
|
||||||
const openModal = () => {
|
const openModal = (action: PageActionType, row?: ListItem) => {
|
||||||
setOpenModalStatus({ ...openModalStatus, open: true });
|
setOpenModalStatus({
|
||||||
|
...openModalStatus,
|
||||||
|
open: true,
|
||||||
|
title: action === PageAction.CREATE ? 'Create Provider' : 'Edit Provider',
|
||||||
|
action,
|
||||||
|
currentData: row,
|
||||||
|
provider: row ? row.provider : null
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
PROVIDER_MODELS_API,
|
PROVIDER_MODELS_API,
|
||||||
deleteProvider,
|
deleteProvider,
|
||||||
queryMaasProviders,
|
queryMaasProviders,
|
||||||
queryProviderModels,
|
|
||||||
updateProvider
|
updateProvider
|
||||||
} from './apis';
|
} from './apis';
|
||||||
import AddMaasProvider from './components/add-provider-modal';
|
import AddMaasProvider from './components/add-provider-modal';
|
||||||
@@ -73,7 +72,7 @@ const MaasProvider: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleClickDropdown = () => {
|
const handleClickDropdown = () => {
|
||||||
openProviderModal();
|
openProviderModal('create');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalOk = async (data: FormData) => {
|
const handleModalOk = async (data: FormData) => {
|
||||||
@@ -149,10 +148,10 @@ const MaasProvider: React.FC = () => {
|
|||||||
cluster_id: row.id,
|
cluster_id: row.id,
|
||||||
page: -1
|
page: -1
|
||||||
};
|
};
|
||||||
const data = await queryProviderModels(params, {
|
// const data = await queryProviderModels(params, {
|
||||||
token: options?.token
|
// token: options?.token
|
||||||
});
|
// });
|
||||||
return data?.items || [];
|
return [1, 2, 3];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -217,7 +216,7 @@ const MaasProvider: React.FC = () => {
|
|||||||
loadend={dataSource.loadend}
|
loadend={dataSource.loadend}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
childParentKey="cluster_id"
|
childParentKey="provider_id"
|
||||||
expandable={true}
|
expandable={true}
|
||||||
empty={
|
empty={
|
||||||
<NoResult
|
<NoResult
|
||||||
|
|||||||
Reference in New Issue
Block a user