feat: yaml editor

This commit is contained in:
jialin
2025-10-13 14:40:26 +08:00
parent e863b84016
commit 54703c67c1
48 changed files with 2062 additions and 246 deletions
+77
View File
@@ -0,0 +1,77 @@
import ListInput from '@/components/list-input';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { PageActionType } from '@/config/types';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React from 'react';
import { FormData } from '../config/types';
type AddModalProps = {
action: PageActionType;
};
const BasicForm: React.FC<AddModalProps> = ({ action }) => {
const form = Form.useFormInstance();
const intl = useIntl();
const { getRuleMessage } = useAppUtils();
return (
<>
<Form.Item<FormData>
name="backend_name"
rules={[
{
required: true,
message: getRuleMessage('input', 'common.table.name')
}
]}
>
<SealInput.Input
label={intl.formatMessage({ id: 'common.table.name' })}
required
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
name="compatibility_type"
rules={[
{
required: true,
message: getRuleMessage('select', 'template', false)
}
]}
>
<SealSelect
label={'Compatibility Template'}
required
options={[
{ label: 'Template 1', value: 'tensorflow' },
{ label: 'Template 2', value: 'torchserve' }
]}
></SealSelect>
</Form.Item>
<Form.Item<FormData>
name="allowed_proxy_uris"
rules={[{ required: false }]}
>
<ListInput
dataList={form.getFieldValue('allowed_proxy_uris') || []}
onChange={(data: string[]) => {
form.setFieldValue('allowed_proxy_uris', data);
}}
btnText={'Add Allowed Proxy URI'}
label={'Proxy URI'}
></ListInput>
</Form.Item>
<Form.Item<FormData> name="description" rules={[{ required: false }]}>
<SealInput.TextArea
label={intl.formatMessage({ id: 'common.table.description' })}
></SealInput.TextArea>
</Form.Item>
</>
);
};
export default BasicForm;
+73
View File
@@ -0,0 +1,73 @@
import { PageActionType } from '@/config/types';
import CollapsePanel from '@/pages/_components/collapse-panel';
import { Form } from 'antd';
import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
import { FormData, ListItem } from '../config/types';
import BasicForm from './basic';
import ParametersForm from './parameters';
import VersionsForm from './versions-config';
type AddModalProps = {
action: PageActionType;
currentData?: ListItem; // Used when action is EDIT
onFinish: (values: FormData) => void;
ref?: any;
};
const BackendForm: React.FC<AddModalProps> = forwardRef(
({ action, currentData, onFinish }, ref) => {
const [form] = Form.useForm();
useEffect(() => {
if (currentData) {
form.setFieldsValue(currentData);
}
}, [currentData]);
useImperativeHandle(ref, () => ({
resetFields: () => {
form.resetFields();
},
submit: () => {
form.submit();
},
setFieldsValue: (values: any) => {
form.setFieldsValue(values);
},
getFieldsValue: () => {
return form.getFieldsValue();
},
validateFields: async () => {
return await form.validateFields();
}
}));
return (
<Form
name="basicForm"
form={form}
onFinish={onFinish}
preserve={false}
scrollToFirstError={true}
initialValues={currentData}
>
<BasicForm action={action}></BasicForm>
<CollapsePanel
items={[
{
key: 'versions',
label: 'Versions',
children: <VersionsForm action={action}></VersionsForm>
},
{
key: 'parameters',
label: 'Default Parameters',
children: <ParametersForm action={action}></ParametersForm>
}
]}
></CollapsePanel>
</Form>
);
}
);
export default BackendForm;
+32
View File
@@ -0,0 +1,32 @@
import ListInput from '@/components/list-input';
import { PageActionType } from '@/config/types';
import { Form } from 'antd';
import React from 'react';
import { FormData } from '../config/types';
type AddModalProps = {
action: PageActionType;
};
const ParametersForm: React.FC<AddModalProps> = ({ action }) => {
const form = Form.useFormInstance();
return (
<>
<Form.Item<FormData>
name="default_backend_param"
rules={[{ required: false }]}
>
<ListInput
dataList={form.getFieldValue('default_backend_param') || []}
onChange={(data: string[]) => {
form.setFieldValue('default_backend_param', data);
}}
btnText={'Add Backend Parameter'}
label={'Default Backend Parameters'}
></ListInput>
</Form.Item>
</>
);
};
export default ParametersForm;
@@ -0,0 +1,139 @@
import SealInput from '@/components/seal-form/seal-input';
import { PageActionType } from '@/config/types';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Checkbox, Divider, Form } from 'antd';
import React, { useEffect } from 'react';
import styled from 'styled-components';
const Box = styled.div`
display: grid;
grid-template-columns: 200px 1fr;
gap: 16px;
align-items: center;
`;
const ItemWrapper = styled.div`
&:hover {
.divider {
border-top: 1px dashed var(--ant-color-primary) !important;
}
}
`;
const Label = styled.div`
color: var(--ant-color-text-tertiary);
font-size: var(--font-size-base);
margin-bottom: 10px;
`;
type AddModalProps = {
action: PageActionType;
};
const VersionsForm: React.FC<AddModalProps> = ({ action }) => {
const form = Form.useFormInstance();
const versionList = [
{
version_no: '',
image_name: '',
run_command: '',
is_default: false
}
];
useEffect(() => {
const versions = form.getFieldValue('version_configs') || [];
if (Array.isArray(versions) && versions.length === 0) {
form.setFieldValue('version_configs', versionList);
}
}, []);
return (
<Form.List name="version_configs">
{(fields, { add, remove }) => {
return (
<div
style={{
border: '1px solid var(--ant-color-border)',
borderRadius: 'var(--border-radius-base)',
padding: '14px'
}}
>
{fields.map(({ key, name, ...restField }, index) => (
<ItemWrapper key={key}>
<Box>
<Form.Item
{...restField}
name={[name, 'version_no']}
rules={[
{ required: true, message: 'Version No. is required' }
]}
>
<SealInput.Input
label="Version No."
required
></SealInput.Input>
</Form.Item>
<Form.Item
{...restField}
name={[name, 'image_name']}
rules={[
{ required: true, message: 'Image Name is required' }
]}
>
<SealInput.Input
label="Image Name"
required
></SealInput.Input>
</Form.Item>
</Box>
<Form.Item name={[name, 'run_command']} {...restField}>
<SealInput.TextArea label="Execution Command"></SealInput.TextArea>
</Form.Item>
<div className="flex justify-between items-center">
<span className="flex-center">
<Form.Item
{...restField}
name={[name, 'is_default']}
valuePropName="checked"
initialValue={false}
noStyle
>
<Checkbox>Set as Default Version</Checkbox>
</Form.Item>
</span>
<div className="flex-center gap-16">
{fields.length > 1 && (
<Button
size="small"
onClick={() => remove(name)}
shape="circle"
>
<MinusOutlined />
</Button>
)}
</div>
</div>
<Divider
className="divider"
style={{ borderTop: '1px dashed var(--ant-color-border)' }}
/>
{index === fields.length - 1 && (
<Button
onClick={() => add()}
block
variant="filled"
color="default"
>
<PlusOutlined /> Add Version
</Button>
)}
</ItemWrapper>
))}
</div>
);
}}
</Form.List>
);
};
export default VersionsForm;