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; 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 { useState } from 'react';
import styles from './addExperimentModal.less'; import styles from './addExperimentModal.less';


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


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


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

interface Workflow { interface Workflow {
id: string | number; id: string | number;
name: string; 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({ function AddExperimentModal({
isAdd, isAdd,
open, open,
@@ -38,20 +78,30 @@ function AddExperimentModal({
}: AddExperimentModalProps) { }: AddExperimentModalProps) {
const dialogTitle = isAdd ? '新建实验' : '编辑实验'; const dialogTitle = isAdd ? '新建实验' : '编辑实验';
const workflowDisabled = isAdd ? false : true; const workflowDisabled = isAdd ? false : true;
const [globalParam, setGlobalParam] = useState<GlobalParam[]>([]);
const [globalParam, setGlobalParam] = useState<PipelineGlobalParam[]>(
initialValues.global_param || [],
);
const [form] = Form.useForm(); 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); const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id);
if (pipeline && pipeline.global_param) { if (pipeline && pipeline.global_param) {
setGlobalParam(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 { } else {
setGlobalParam([]); setGlobalParam([]);
form.setFieldValue('global_param', []);
} }
}; };
return ( return (
@@ -73,11 +123,12 @@ function AddExperimentModal({
> >
<Form <Form
name="form" name="form"
layout="vertical"
layout="horizontal"
initialValues={initialValues} initialValues={initialValues}
onFinish={onFinish} onFinish={onFinish}
autoComplete="off" autoComplete="off"
form={form} form={form}
{...layout}
> >
<Form.Item <Form.Item
label="实验名称" label="实验名称"
@@ -114,11 +165,32 @@ function AddExperimentModal({
: null} : null}
</Select> </Select>
</Form.Item> </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.Item>
))}
)}
</Form> </Form>
</Modal> </Modal>
); );


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

@@ -119,22 +119,12 @@ function Experiment() {
}; };
// 创建或者编辑实验接口请求 // 创建或者编辑实验接口请求
const handleAddExperiment = async (values) => { 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) { if (!experimentId) {
const params = {
...values,
global_param,
};
const [res, _] = await to(postExperiment(params)); const [res, _] = await to(postExperiment(params));
if (res) { if (res) {
message.success('新建实验成功'); message.success('新建实验成功');
@@ -142,7 +132,7 @@ function Experiment() {
getList(); getList();
} }
} else { } else {
const params = { ...values, id: experimentId };
const params = { ...values, global_param, id: experimentId };
const [res, _] = await to(putExperiment(params)); const [res, _] = await to(putExperiment(params));
if (res) { if (res) {
message.success('编辑实验成功'); message.success('编辑实验成功');
@@ -431,14 +421,16 @@ function Experiment() {
rowExpandable: (record) => true, 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> </div>
); );
} }


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

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

&:first-child {
margin-top: 0;
}
}
.add_button_form_item .add_button {
padding: 0; 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 { type PipelineGlobalParam } from '@/types';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Drawer, Form, Input, Radio } from 'antd'; import { Button, Drawer, Form, Input, Radio } from 'antd';
import { NamePath } from 'antd/es/form/interface';
import { forwardRef, useImperativeHandle } from 'react'; import { forwardRef, useImperativeHandle } from 'react';
import styles from './globalParamsDrawer.less'; import styles from './globalParamsDrawer.less';


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

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

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


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

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


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

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


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

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


Loading…
Cancel
Save