Browse Source

feat: 完成实验全局参数配置

pull/14/head
cp3hnu 1 year ago
parent
commit
a00d861ab1
8 changed files with 159 additions and 55 deletions
  1. +8
    -0
      react-ui/src/pages/Experiment/experimentText/addExperimentModal.less
  2. +91
    -19
      react-ui/src/pages/Experiment/experimentText/addExperimentModal.tsx
  3. +16
    -24
      react-ui/src/pages/Experiment/index.jsx
  4. +7
    -1
      react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.less
  5. +34
    -9
      react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx
  6. +2
    -1
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  7. +0
    -1
      react-ui/src/types.ts
  8. +1
    -0
      react-ui/src/utils/index.js

+ 8
- 0
react-ui/src/pages/Experiment/experimentText/addExperimentModal.less View File

@@ -48,4 +48,12 @@
margin-right: 10px;
}
}

.global_param_item {
max-height: 230px;
padding: 20px 12px;
overflow-y: auto;
border: 1px solid #e6e6e6;
border-radius: 6px;
}
}

+ 91
- 19
react-ui/src/pages/Experiment/experimentText/addExperimentModal.tsx View File

@@ -1,4 +1,5 @@
import { Form, Input, Modal, Select } from 'antd';
import { type PipelineGlobalParam } from '@/types';
import { Form, Input, Modal, Radio, Select, type FormRule } from 'antd';
import { useState } from 'react';
import styles from './addExperimentModal.less';

@@ -6,6 +7,7 @@ type FormData = {
name?: string;
description?: string;
workflow_id?: string | number;
global_param?: PipelineGlobalParam[];
};

type AddExperimentModalProps = {
@@ -17,17 +19,55 @@ type AddExperimentModalProps = {
initialValues: FormData;
};

interface GlobalParam {
param_name: string;
param_value: string;
}

interface Workflow {
id: string | number;
name: string;
global_param?: GlobalParam[] | null;
global_param?: PipelineGlobalParam[] | null;
}

// 根据参数设置输入组件
export const getParamComponent = (paramType: number, isSensitive?: number): JSX.Element => {
// 防止后台返回不是 number 类型
if (Number(paramType) === 3) {
return (
<Radio.Group>
<Radio value={1}>是</Radio>
<Radio value={0}>否</Radio>
</Radio.Group>
);
}
if (isSensitive && Number(isSensitive) === 1) {
return <Input.Password visibilityToggle={false} allowClear />;
}
return <Input placeholder="请输入值" allowClear />;
};

// 根据参数设置校验规则
export const getParamRules = (paramType: number, required: boolean = false): FormRule[] => {
const rules = [];
// 防止后台返回不是 number 类型
if (Number(paramType) === 2) {
rules.push({
pattern: /^-?\d+(\.\d+)?$/,
message: '整型必须是数字',
});
}
if (required) {
rules.push({ required: true, message: '请输入值' });
}
return rules;
};

// 根据参数设置 label
const getParamType = (param: PipelineGlobalParam): string => {
const paramTypes: Readonly<Record<number, string>> = {
1: '字符串',
2: '整型',
3: '布尔类型',
};
return param.param_name + `(${paramTypes[param.param_type]})`;
};

function AddExperimentModal({
isAdd,
open,
@@ -38,20 +78,30 @@ function AddExperimentModal({
}: AddExperimentModalProps) {
const dialogTitle = isAdd ? '新建实验' : '编辑实验';
const workflowDisabled = isAdd ? false : true;
const [globalParam, setGlobalParam] = useState<GlobalParam[]>([]);
const [globalParam, setGlobalParam] = useState<PipelineGlobalParam[]>(
initialValues.global_param || [],
);
const [form] = Form.useForm();

const layout = {
labelCol: { span: 24 },
wrapperCol: { span: 24 },
};

const tailLayout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
};

// 除了流水线选择发生变化
const handleWorkflowChange = (id: string) => {
const handleWorkflowChange = (id: string | number) => {
const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id);
if (pipeline && pipeline.global_param) {
setGlobalParam(pipeline.global_param);
const fields = pipeline.global_param.reduce((acc, item) => {
acc[item.param_name] = item.param_value;
return acc;
}, {} as Record<string, string>);
form.setFieldsValue(fields);
form.setFieldValue('global_param', pipeline.global_param);
} else {
setGlobalParam([]);
form.setFieldValue('global_param', []);
}
};
return (
@@ -73,11 +123,12 @@ function AddExperimentModal({
>
<Form
name="form"
layout="vertical"
layout="horizontal"
initialValues={initialValues}
onFinish={onFinish}
autoComplete="off"
form={form}
{...layout}
>
<Form.Item
label="实验名称"
@@ -114,11 +165,32 @@ function AddExperimentModal({
: null}
</Select>
</Form.Item>
{globalParam.map((item) => (
<Form.Item label={item.param_name} name={item.param_name} key={item.param_name}>
<Input />
{globalParam.length > 0 && (
<Form.Item label="运行参数" tooltip="展示关联的流水线的参数,脱敏的参数以xxxx展示">
<div className={styles.global_param_item}>
<Form.List name="global_param">
{(fields) =>
fields.map(({ key, name, ...restField }) => (
<Form.Item
{...tailLayout}
{...restField}
key={key}
label={getParamType(globalParam[name])}
name={[name, 'param_value']}
labelAlign="left"
rules={getParamRules(globalParam[name]['param_type'])}
>
{getParamComponent(
globalParam[name]['param_type'],
globalParam[name]['is_sensitive'],
)}
</Form.Item>
))
}
</Form.List>
</div>
</Form.Item>
))}
)}
</Form>
</Modal>
);


+ 16
- 24
react-ui/src/pages/Experiment/index.jsx View File

@@ -119,22 +119,12 @@ function Experiment() {
};
// 创建或者编辑实验接口请求
const handleAddExperiment = async (values) => {
const workflow_id = values['workflow_id'];
let global_param = undefined;
const pipeline = workflowList.find((v) => v.id === workflow_id);
if (pipeline && pipeline.global_param) {
const globalParamList = [...pipeline.global_param];
for (const item of globalParamList) {
item.param_value = values[item.param_name];
values[item.param_name] = undefined;
}
global_param = JSON.stringify(globalParamList);
}
const params = {
...values,
global_param,
};
const global_param = JSON.stringify(values.global_param);
if (!experimentId) {
const params = {
...values,
global_param,
};
const [res, _] = await to(postExperiment(params));
if (res) {
message.success('新建实验成功');
@@ -142,7 +132,7 @@ function Experiment() {
getList();
}
} else {
const params = { ...values, id: experimentId };
const params = { ...values, global_param, id: experimentId };
const [res, _] = await to(putExperiment(params));
if (res) {
message.success('编辑实验成功');
@@ -431,14 +421,16 @@ function Experiment() {
rowExpandable: (record) => true,
}}
/>
<AddExperimentModal
isAdd={isAdd}
open={isModalOpen}
initialValues={addFormData}
onCancel={handleCancel}
onFinish={handleAddExperiment}
workflowList={workflowList}
/>
{isModalOpen && (
<AddExperimentModal
isAdd={isAdd}
open={isModalOpen}
initialValues={addFormData}
onCancel={handleCancel}
onFinish={handleAddExperiment}
workflowList={workflowList}
/>
)}
</div>
);
}


+ 7
- 1
react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.less View File

@@ -8,7 +8,13 @@
top: 5px;
right: 0;
}
.add_button {
.add_button_form_item {
margin-top: 15px;

&:first-child {
margin-top: 0;
}
}
.add_button_form_item .add_button {
padding: 0;
}

+ 34
- 9
react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx View File

@@ -1,7 +1,12 @@
import {
getParamComponent,
getParamRules,
} from '@/pages/Experiment/experimentText/addExperimentModal';
import { type PipelineGlobalParam } from '@/types';
import { to } from '@/utils/promise';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Drawer, Form, Input, Radio } from 'antd';
import { NamePath } from 'antd/es/form/interface';
import { forwardRef, useImperativeHandle } from 'react';
import styles from './globalParamsDrawer.less';

@@ -26,6 +31,11 @@ const GlobalParamsDrawer = forwardRef(
}
},
}));

const handleTypeChange = (name: NamePath) => {
form.setFieldValue(name, null);
};

return (
<Drawer
rootStyle={{ marginTop: '45px' }}
@@ -77,26 +87,41 @@ const GlobalParamsDrawer = forwardRef(
label="类  型"
rules={[{ required: true, message: '请选择类型' }]}
>
<Radio.Group>
<Radio.Group
onChange={() => handleTypeChange(['global_param', name, 'param_value'])}
>
<Radio value={1}>字符串</Radio>
<Radio value={2}>整型</Radio>
<Radio value={3}>布尔类型</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
{...restField}
name={[name, 'param_value']}
label="值"
rules={[{ required: true, message: '请输入值' }]}
noStyle
shouldUpdate={(prev, cur) =>
prev.global_param?.[name]?.param_type !==
cur.global_param?.[name]?.param_type
}
>
<Input placeholder="请输入值" allowClear />
{({ getFieldValue }) => (
<Form.Item
{...restField}
name={[name, 'param_value']}
label="值"
rules={getParamRules(
getFieldValue(['global_param', name, 'param_type']),
true,
)}
>
{getParamComponent(getFieldValue(['global_param', name, 'param_type']))}
</Form.Item>
)}
</Form.Item>
<Form.Item
{...restField}
name={[name, 'is_sensitive']}
label="脱敏显示"
rules={[{ required: true, message: '请选择' }]}
tooltip="脱敏后的参数以*****显示"
tooltip="展示关联的流水线的参数,脱敏的参数以xxxx展示"
>
<Radio.Group>
<Radio value={1}>是</Radio>
@@ -111,11 +136,11 @@ const GlobalParamsDrawer = forwardRef(
></Button>
</div>
))}
<Form.Item>
<Form.Item className={styles.add_button_form_item}>
<Button
className={styles.add_button}
type="link"
onClick={add}
onClick={() => add()}
icon={<PlusOutlined />}
>
流水线参数


+ 2
- 1
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -101,13 +101,14 @@ const EditPipeline = () => {
}
const data = graph.save();
console.log(data);
let params = {
const params = {
...locationParams,
dag: JSON.stringify(data),
global_param: JSON.stringify(res.global_param),
};
saveWorkflow(params).then((ret) => {
message.success('保存成功');
closeParamsDrawer();
setTimeout(() => {
if (val) {
navgite({ pathname: `/pipeline` });


+ 0
- 1
react-ui/src/types.ts View File

@@ -1,6 +1,5 @@
// 流水线全局参数
export type PipelineGlobalParam = {
workflow_id: number;
param_name: string;
description: string;
param_type: number;


+ 1
- 0
react-ui/src/utils/index.js View File

@@ -9,3 +9,4 @@ export function getNameByCode(list, code) {
});
return name;
}


Loading…
Cancel
Save