| @@ -1,3 +1,4 @@ | |||||
| import { PipelineGlobalParamType, type PipelineGlobalParam } from '@/types'; | |||||
| import { formatEnum } from '@/utils/format'; | import { formatEnum } from '@/utils/format'; | ||||
| import { Typography, type SelectProps } from 'antd'; | import { Typography, type SelectProps } from 'antd'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| @@ -16,6 +17,8 @@ type FormInfoProps = { | |||||
| options?: SelectProps['options']; | options?: SelectProps['options']; | ||||
| /** 自定义节点 label、value 的字段 */ | /** 自定义节点 label、value 的字段 */ | ||||
| fieldNames?: SelectProps['fieldNames']; | fieldNames?: SelectProps['fieldNames']; | ||||
| /** 全局参数 */ | |||||
| globalParams?: PipelineGlobalParam[] | null; | |||||
| /** 自定义类名 */ | /** 自定义类名 */ | ||||
| className?: string; | className?: string; | ||||
| /** 自定义样式 */ | /** 自定义样式 */ | ||||
| @@ -32,12 +35,29 @@ function FormInfo({ | |||||
| select = false, | select = false, | ||||
| options, | options, | ||||
| fieldNames, | fieldNames, | ||||
| globalParams, | |||||
| className, | className, | ||||
| style, | style, | ||||
| }: FormInfoProps) { | }: FormInfoProps) { | ||||
| let showValue = value; | let showValue = value; | ||||
| if (value && typeof value === 'object' && valuePropName) { | if (value && typeof value === 'object' && valuePropName) { | ||||
| showValue = value[valuePropName]; | showValue = value[valuePropName]; | ||||
| const reg = /^\$\{(.*)\}$/; | |||||
| if (value.fromSelect && Array.isArray(globalParams) && globalParams.length > 0) { | |||||
| const match = reg.exec(showValue); | |||||
| if (match) { | |||||
| const paramName = match[1]; | |||||
| const foundParam = globalParams.find((v) => v.param_name === paramName); | |||||
| if (foundParam) { | |||||
| showValue = | |||||
| foundParam.param_type === PipelineGlobalParamType.Boolean // 布尔类型转换 | |||||
| ? foundParam.param_value | |||||
| ? 'true' | |||||
| : 'false' | |||||
| : foundParam.param_value; | |||||
| } | |||||
| } | |||||
| } | |||||
| } else if (select === true && options) { | } else if (select === true && options) { | ||||
| let _options: SelectProps['options'] = options; | let _options: SelectProps['options'] = options; | ||||
| if (fieldNames) { | if (fieldNames) { | ||||
| @@ -110,13 +110,14 @@ function ParameterSelect({ | |||||
| onChange?.(selectValue); | onChange?.(selectValue); | ||||
| } | } | ||||
| } else { | } else { | ||||
| const selectValue = text ? text : ''; | |||||
| if (typeof value === 'object' && value !== null) { | if (typeof value === 'object' && value !== null) { | ||||
| onChange?.({ | onChange?.({ | ||||
| ...value, | ...value, | ||||
| value: text, | |||||
| value: selectValue, | |||||
| }); | }); | ||||
| } else { | } else { | ||||
| onChange?.(text); | |||||
| onChange?.(selectValue); | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -169,16 +169,16 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| const handleMessage = (e: MessageEvent) => { | const handleMessage = (e: MessageEvent) => { | ||||
| const { type, payload } = e.data; | const { type, payload } = e.data; | ||||
| if (type === ExperimentCompleted) { | if (type === ExperimentCompleted) { | ||||
| const { experimentId, experimentInsId, status, finishTime } = payload; | |||||
| const { experimentId, experimentInsId, status /*finishTime*/ } = payload; | |||||
| const currentIns = experimentInsList.find((v) => v.id === experimentInsId); | const currentIns = experimentInsList.find((v) => v.id === experimentInsId); | ||||
| console.log( | |||||
| '实验实例状态变化', | |||||
| currentIns?.status, | |||||
| status, | |||||
| experimentId, | |||||
| experimentInsId, | |||||
| finishTime, | |||||
| ); | |||||
| // console.log( | |||||
| // '实验实例状态变化', | |||||
| // currentIns?.status, | |||||
| // status, | |||||
| // experimentId, | |||||
| // experimentInsId, | |||||
| // finishTime, | |||||
| // ); | |||||
| if ( | if ( | ||||
| !currentIns || | !currentIns || | ||||
| @@ -95,16 +95,13 @@ function ExperimentText() { | |||||
| return; | return; | ||||
| } | } | ||||
| const workflow = parseJsonText(dag); | |||||
| const workflow = dag; | |||||
| const experimentStatusObjs = parseJsonText(nodes_status); | const experimentStatusObjs = parseJsonText(nodes_status); | ||||
| if (!workflow || !workflow.nodes) { | if (!workflow || !workflow.nodes) { | ||||
| return; | return; | ||||
| } | } | ||||
| workflow.nodes.forEach((item) => { | workflow.nodes.forEach((item) => { | ||||
| item.in_parameters = parseJsonText(item.in_parameters); | |||||
| item.out_parameters = parseJsonText(item.out_parameters); | |||||
| item.control_strategy = parseJsonText(item.control_strategy); | |||||
| item.imgName = item.img.slice(0, item.img.length - 4); | item.imgName = item.img.slice(0, item.img.length - 4); | ||||
| }); | }); | ||||
| workflowRef.current = workflow; | workflowRef.current = workflow; | ||||
| @@ -140,8 +137,11 @@ function ExperimentText() { | |||||
| } else if (status === ExperimentStatus.Running) { | } else if (status === ExperimentStatus.Running) { | ||||
| // 如果状态是 Running,打开第一个 Running 或者 pending 的节点,如果没有,则打开第一个节点 | // 如果状态是 Running,打开第一个 Running 或者 pending 的节点,如果没有,则打开第一个节点 | ||||
| const node = | const node = | ||||
| workflow.nodes.find((item) => item.experimentStatus === ExperimentStatus.Running || item.experimentStatus === ExperimentStatus.Pending) ?? | |||||
| workflow.nodes[0]; | |||||
| workflow.nodes.find( | |||||
| (item) => | |||||
| item.experimentStatus === ExperimentStatus.Running || | |||||
| item.experimentStatus === ExperimentStatus.Pending, | |||||
| ) ?? workflow.nodes[0]; | |||||
| if (node) { | if (node) { | ||||
| setExperimentNodeData(node); | setExperimentNodeData(node); | ||||
| openPropsDrawer(); | openPropsDrawer(); | ||||
| @@ -567,12 +567,13 @@ function ExperimentText() { | |||||
| instanceNodeStatus={experimentNodeData.experimentStatus} | instanceNodeStatus={experimentNodeData.experimentStatus} | ||||
| instanceNodeStartTime={experimentNodeData.experimentStartTime} | instanceNodeStartTime={experimentNodeData.experimentStartTime} | ||||
| instanceNodeEndTime={experimentNodeData.experimentEndTime} | instanceNodeEndTime={experimentNodeData.experimentEndTime} | ||||
| globalParams={experimentIns?.global_param} | |||||
| ></ExperimentDrawer> | ></ExperimentDrawer> | ||||
| ) : null} | ) : null} | ||||
| <ParamsModal | <ParamsModal | ||||
| open={paramsModalOpen} | open={paramsModalOpen} | ||||
| onCancel={closeParamsModal} | onCancel={closeParamsModal} | ||||
| globalParam={experimentIns?.global_param} | |||||
| globalParams={experimentIns?.global_param} | |||||
| ></ParamsModal> | ></ParamsModal> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -1,7 +1,7 @@ | |||||
| import createExperimentIcon from '@/assets/img/create-experiment.png'; | import createExperimentIcon from '@/assets/img/create-experiment.png'; | ||||
| import editExperimentIcon from '@/assets/img/edit-experiment.png'; | import editExperimentIcon from '@/assets/img/edit-experiment.png'; | ||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import { type PipelineGlobalParam } from '@/types'; | |||||
| import { PipelineGlobalParamType, type PipelineGlobalParam } from '@/types'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { Button, Form, Input, Radio, Select, Typography, type FormRule } from 'antd'; | import { Button, Form, Input, Radio, Select, Typography, type FormRule } from 'antd'; | ||||
| import { useState } from 'react'; | import { useState } from 'react'; | ||||
| @@ -32,7 +32,7 @@ interface Workflow { | |||||
| // 根据参数设置输入组件 | // 根据参数设置输入组件 | ||||
| export const getParamComponent = (paramType: number): JSX.Element => { | export const getParamComponent = (paramType: number): JSX.Element => { | ||||
| // 防止后台返回不是 number 类型 | // 防止后台返回不是 number 类型 | ||||
| if (Number(paramType) === 3) { | |||||
| if (Number(paramType) === PipelineGlobalParamType.Boolean) { | |||||
| return ( | return ( | ||||
| <Radio.Group> | <Radio.Group> | ||||
| <Radio value={1}>是</Radio> | <Radio value={1}>是</Radio> | ||||
| @@ -50,7 +50,7 @@ export const getParamComponent = (paramType: number): JSX.Element => { | |||||
| export const getParamRules = (paramType: number, required: boolean = false): FormRule[] => { | export const getParamRules = (paramType: number, required: boolean = false): FormRule[] => { | ||||
| const rules = []; | const rules = []; | ||||
| // 防止后台返回不是 number 类型 | // 防止后台返回不是 number 类型 | ||||
| if (Number(paramType) === 2) { | |||||
| if (Number(paramType) === PipelineGlobalParamType.Number) { | |||||
| rules.push({ | rules.push({ | ||||
| pattern: /^-?((0(\.0*[1-9]\d*)?)|([1-9]\d*(\.\d+)?))$/, | pattern: /^-?((0(\.0*[1-9]\d*)?)|([1-9]\d*(\.\d+)?))$/, | ||||
| message: '整型必须是数字', | message: '整型必须是数字', | ||||
| @@ -64,10 +64,10 @@ export const getParamRules = (paramType: number, required: boolean = false): For | |||||
| // 根据参数设置 label | // 根据参数设置 label | ||||
| export const getParamLabel = (param: PipelineGlobalParam): React.ReactNode => { | export const getParamLabel = (param: PipelineGlobalParam): React.ReactNode => { | ||||
| const paramTypes: Readonly<Record<number, string>> = { | |||||
| 1: '字符串', | |||||
| 2: '整型', | |||||
| 3: '布尔类型', | |||||
| const paramTypes: Readonly<Record<PipelineGlobalParamType, string>> = { | |||||
| [PipelineGlobalParamType.String]: '字符串', | |||||
| [PipelineGlobalParamType.Number]: '整型', | |||||
| [PipelineGlobalParamType.Boolean]: '布尔类型', | |||||
| }; | }; | ||||
| const label = param.param_name + `(${paramTypes[param.param_type]})`; | const label = param.param_name + `(${paramTypes[param.param_type]})`; | ||||
| return <Typography.Text ellipsis={{ tooltip: label }}>{label}</Typography.Text>; | return <Typography.Text ellipsis={{ tooltip: label }}>{label}</Typography.Text>; | ||||
| @@ -1,7 +1,7 @@ | |||||
| import RunDuration from '@/components/RunDuration'; | import RunDuration from '@/components/RunDuration'; | ||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { PipelineNodeModelSerialize } from '@/types'; | |||||
| import { PipelineNodeModelSerialize, type PipelineGlobalParam } from '@/types'; | |||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; | import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; | ||||
| import { Drawer, Tabs, Typography } from 'antd'; | import { Drawer, Tabs, Typography } from 'antd'; | ||||
| @@ -25,6 +25,7 @@ type ExperimentDrawerProps = { | |||||
| instanceNodeStatus?: ExperimentStatus; // 实例节点状态 | instanceNodeStatus?: ExperimentStatus; // 实例节点状态 | ||||
| instanceNodeStartTime?: string; // 开始时间 | instanceNodeStartTime?: string; // 开始时间 | ||||
| instanceNodeEndTime?: string; // 在定时刷新实验实例状态中,会经常变化 | instanceNodeEndTime?: string; // 在定时刷新实验实例状态中,会经常变化 | ||||
| globalParams?: PipelineGlobalParam[] | null; // 全局参数 | |||||
| }; | }; | ||||
| const ExperimentDrawer = ({ | const ExperimentDrawer = ({ | ||||
| @@ -41,6 +42,7 @@ const ExperimentDrawer = ({ | |||||
| instanceNodeStatus, | instanceNodeStatus, | ||||
| instanceNodeStartTime, | instanceNodeStartTime, | ||||
| instanceNodeEndTime, | instanceNodeEndTime, | ||||
| globalParams, | |||||
| }: ExperimentDrawerProps) => { | }: ExperimentDrawerProps) => { | ||||
| // 如果性能有问题,可以进一步拆解 | // 如果性能有问题,可以进一步拆解 | ||||
| const items = useMemo( | const items = useMemo( | ||||
| @@ -66,7 +68,7 @@ const ExperimentDrawer = ({ | |||||
| key: '2', | key: '2', | ||||
| label: '配置参数', | label: '配置参数', | ||||
| icon: <DatabaseOutlined />, | icon: <DatabaseOutlined />, | ||||
| children: <ExperimentParameter nodeData={instanceNodeData} />, | |||||
| children: <ExperimentParameter nodeData={instanceNodeData} globalParams={globalParams} />, | |||||
| }, | }, | ||||
| { | { | ||||
| key: '3', | key: '3', | ||||
| @@ -94,6 +96,7 @@ const ExperimentDrawer = ({ | |||||
| experimentName, | experimentName, | ||||
| experimentId, | experimentId, | ||||
| pipelineId, | pipelineId, | ||||
| globalParams, | |||||
| ], | ], | ||||
| ); | ); | ||||
| @@ -15,4 +15,24 @@ | |||||
| font-size: @font-size; | font-size: @font-size; | ||||
| background: #f8fbff; | background: #f8fbff; | ||||
| } | } | ||||
| &__form-list { | |||||
| :global { | |||||
| .ant-row { | |||||
| padding: 0 !important; | |||||
| } | |||||
| } | |||||
| &:last-child { | |||||
| :global { | |||||
| .ant-form-item { | |||||
| margin-bottom: 0 !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| &__list-empty { | |||||
| color: @text-color-tertiary; | |||||
| } | |||||
| } | } | ||||
| @@ -1,25 +1,92 @@ | |||||
| import FormInfo from '@/components/FormInfo'; | import FormInfo from '@/components/FormInfo'; | ||||
| import ParameterSelect from '@/components/ParameterSelect'; | |||||
| import ParameterSelect, { type ParameterSelectDataType } from '@/components/ParameterSelect'; | |||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | import SubAreaTitle from '@/components/SubAreaTitle'; | ||||
| import { PipelineNodeModelSerialize } from '@/types'; | |||||
| import { Form } from 'antd'; | |||||
| import { ComponentType } from '@/enums'; | |||||
| import type { | |||||
| PipelineGlobalParam, | |||||
| PipelineNodeModelParameter, | |||||
| PipelineNodeModelSerialize, | |||||
| } from '@/types'; | |||||
| import { Flex, Form } from 'antd'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ExperimentParameterProps = { | type ExperimentParameterProps = { | ||||
| nodeData: PipelineNodeModelSerialize; | nodeData: PipelineNodeModelSerialize; | ||||
| globalParams?: PipelineGlobalParam[] | null; // 全局参数 | |||||
| }; | }; | ||||
| function ExperimentParameter({ nodeData }: ExperimentParameterProps) { | |||||
| function ExperimentParameter({ nodeData, globalParams }: ExperimentParameterProps) { | |||||
| // 表单组件 | |||||
| const getFormComponent = ( | |||||
| item: { key: string; value: PipelineNodeModelParameter }, | |||||
| parentName: string, | |||||
| ) => { | |||||
| return ( | |||||
| <Form.Item | |||||
| key={item.key} | |||||
| name={[parentName, item.key]} | |||||
| label={item.value.label + '(' + item.key + ')'} | |||||
| rules={[{ required: item.value.require ? true : false }]} | |||||
| > | |||||
| {item.value.type === ComponentType.Map && ( | |||||
| <Form.List name={[parentName, item.key, 'value']}> | |||||
| {(fields) => ( | |||||
| <> | |||||
| {fields.length > 0 ? ( | |||||
| fields.map(({ key, name, ...restField }) => ( | |||||
| <Flex | |||||
| key={key} | |||||
| gap="0 8px" | |||||
| style={{ width: '100%' }} | |||||
| className={styles['experiment-parameter__form-list']} | |||||
| > | |||||
| <Form.Item | |||||
| {...restField} | |||||
| name={[name, 'name']} | |||||
| style={{ flex: 1, minWidth: 0 }} | |||||
| > | |||||
| <FormInfo /> | |||||
| </Form.Item> | |||||
| <span style={{ lineHeight: '32px' }}>=</span> | |||||
| <Form.Item | |||||
| {...restField} | |||||
| name={[name, 'value']} | |||||
| style={{ flex: 1, minWidth: 0 }} | |||||
| > | |||||
| <FormInfo valuePropName="showValue" globalParams={globalParams} /> | |||||
| </Form.Item> | |||||
| </Flex> | |||||
| )) | |||||
| ) : ( | |||||
| <div className={styles['experiment-parameter__list-empty']}>无参数</div> | |||||
| )} | |||||
| </> | |||||
| )} | |||||
| </Form.List> | |||||
| )} | |||||
| {item.value.type === ComponentType.Select && | |||||
| (['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( | |||||
| <ParameterSelect dataType={item.value.item_type as ParameterSelectDataType} display /> | |||||
| ) : null)} | |||||
| {item.value.type !== ComponentType.Map && item.value.type !== ComponentType.Select && ( | |||||
| <FormInfo valuePropName="showValue" globalParams={globalParams} /> | |||||
| )} | |||||
| </Form.Item> | |||||
| ); | |||||
| }; | |||||
| // 基本参数 | |||||
| const basicParametersList = Object.entries(nodeData.task_info ?? {}) | |||||
| .map(([key, value]) => ({ | |||||
| key, | |||||
| value, | |||||
| })) | |||||
| .filter((v) => v.value.visible === true); | |||||
| // 控制策略 | // 控制策略 | ||||
| // const controlStrategyList = Object.entries(nodeData.control_strategy ?? {}).map( | |||||
| // ([key, value]) => ({ key, value }), | |||||
| // ); | |||||
| const nodeId = nodeData.id; | |||||
| const hasTaskInfo = | |||||
| nodeId && | |||||
| !nodeId.startsWith('git-clone') && | |||||
| !nodeId.startsWith('dataset-export') && | |||||
| !nodeId.startsWith('model-export'); | |||||
| const controlStrategyList = Object.entries(nodeData.control_strategy ?? {}) | |||||
| .map(([key, value]) => ({ key, value })) | |||||
| .filter((v) => v.value.visible === true); | |||||
| // 输入参数 | // 输入参数 | ||||
| const inParametersList = Object.entries(nodeData.in_parameters ?? {}).map(([key, value]) => ({ | const inParametersList = Object.entries(nodeData.in_parameters ?? {}).map(([key, value]) => ({ | ||||
| @@ -80,96 +147,56 @@ function ExperimentParameter({ nodeData }: ExperimentParameterProps) { | |||||
| > | > | ||||
| <FormInfo /> | <FormInfo /> | ||||
| </Form.Item> | </Form.Item> | ||||
| {hasTaskInfo && ( | |||||
| {basicParametersList.length + controlStrategyList.length > 0 && ( | |||||
| <div className={styles['experiment-parameter__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="任务信息" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| )} | |||||
| {/* 基本参数 */} | |||||
| {basicParametersList.map((item) => getFormComponent(item, 'task_info'))} | |||||
| {/* 控制参数 */} | |||||
| {controlStrategyList.map((item) => getFormComponent(item, 'control_strategy'))} | |||||
| {/* 输入参数 */} | |||||
| {inParametersList.length > 0 && ( | |||||
| <> | <> | ||||
| <div className={styles['experiment-parameter__title']}> | <div className={styles['experiment-parameter__title']}> | ||||
| <SubAreaTitle | <SubAreaTitle | ||||
| image={require('@/assets/img/duty-message.png')} | image={require('@/assets/img/duty-message.png')} | ||||
| title="任务信息" | |||||
| title="输入参数" | |||||
| ></SubAreaTitle> | ></SubAreaTitle> | ||||
| </div> | </div> | ||||
| <Form.Item | |||||
| label="镜像" | |||||
| name="image" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <FormInfo /> | |||||
| </Form.Item> | |||||
| <Form.Item label="工作目录" name="working_directory"> | |||||
| <FormInfo /> | |||||
| </Form.Item> | |||||
| {inParametersList.map((item) => getFormComponent(item, 'in_parameters'))} | |||||
| </> | |||||
| )} | |||||
| <Form.Item label="启动命令" name="command"> | |||||
| <FormInfo textArea /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="资源规格" | |||||
| name="resources_standard" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入资源规格', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <ParameterSelect dataType="resource" placeholder="请选择资源规格" display /> | |||||
| </Form.Item> | |||||
| {/* <Form.Item label="挂载路径" name="mount_path"> | |||||
| <FormInfo /> | |||||
| </Form.Item> */} | |||||
| <Form.Item label="环境变量" name="env_variables"> | |||||
| <FormInfo textArea /> | |||||
| </Form.Item> | |||||
| {/* {controlStrategyList.map((item) => ( | |||||
| <Form.Item key={item.key} name={['control_strategy', item.key]} label={item.value.label}> | |||||
| <FormInfo valuePropName="showValue" /> | |||||
| </Form.Item> | |||||
| ))} */} | |||||
| {/* 输出参数 */} | |||||
| {outParametersList.length > 0 && ( | |||||
| <> | |||||
| <div className={styles['experiment-parameter__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="输出参数" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| {outParametersList.map((item) => ( | |||||
| <Form.Item | |||||
| key={item.key} | |||||
| name={['out_parameters', item.key]} | |||||
| label={item.value.label + '(' + item.key + ')'} | |||||
| rules={[{ required: item.value.require ? true : false }]} | |||||
| > | |||||
| <FormInfo valuePropName="showValue" /> | |||||
| </Form.Item> | |||||
| ))} | |||||
| </> | </> | ||||
| )} | )} | ||||
| <div className={styles['experiment-parameter__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="输入参数" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| {inParametersList.map((item) => ( | |||||
| <Form.Item | |||||
| key={item.key} | |||||
| name={['in_parameters', item.key]} | |||||
| label={item.value.label + '(' + item.key + ')'} | |||||
| rules={[{ required: item.value.require ? true : false }]} | |||||
| > | |||||
| {item.value.type === 'select' ? ( | |||||
| ['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( | |||||
| <ParameterSelect dataType={item.value.item_type as any} display /> | |||||
| ) : null | |||||
| ) : ( | |||||
| <FormInfo valuePropName="showValue" /> | |||||
| )} | |||||
| </Form.Item> | |||||
| ))} | |||||
| <div className={styles['experiment-parameter__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="输出参数" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| {outParametersList.map((item) => ( | |||||
| <Form.Item | |||||
| key={item.key} | |||||
| name={['out_parameters', item.key]} | |||||
| label={item.value.label + '(' + item.key + ')'} | |||||
| rules={[{ required: item.value.require ? true : false }]} | |||||
| > | |||||
| <FormInfo valuePropName="showValue" /> | |||||
| </Form.Item> | |||||
| ))} | |||||
| </Form> | </Form> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -14,10 +14,10 @@ import styles from './index.less'; | |||||
| type ParamsModalProps = { | type ParamsModalProps = { | ||||
| open: boolean; | open: boolean; | ||||
| onCancel: () => void; | onCancel: () => void; | ||||
| globalParam?: PipelineGlobalParam[] | null; | |||||
| globalParams?: PipelineGlobalParam[] | null; | |||||
| }; | }; | ||||
| function ParamsModal({ open, onCancel, globalParam = [] }: ParamsModalProps) { | |||||
| function ParamsModal({ open, onCancel, globalParams = [] }: ParamsModalProps) { | |||||
| return ( | return ( | ||||
| <KFModal | <KFModal | ||||
| title="执行参数" | title="执行参数" | ||||
| @@ -28,13 +28,13 @@ function ParamsModal({ open, onCancel, globalParam = [] }: ParamsModalProps) { | |||||
| cancelButtonProps={{ style: { display: 'none' } }} | cancelButtonProps={{ style: { display: 'none' } }} | ||||
| width={825} | width={825} | ||||
| > | > | ||||
| {Array.isArray(globalParam) && globalParam.length > 0 ? ( | |||||
| {Array.isArray(globalParams) && globalParams.length > 0 ? ( | |||||
| <div className={styles['params-container']}> | <div className={styles['params-container']}> | ||||
| <Form | <Form | ||||
| name="view_params_form" | name="view_params_form" | ||||
| labelCol={{ span: 6 }} | labelCol={{ span: 6 }} | ||||
| wrapperCol={{ span: 18 }} | wrapperCol={{ span: 18 }} | ||||
| initialValues={{ global_param: globalParam }} | |||||
| initialValues={{ global_param: globalParams }} | |||||
| labelAlign="left" | labelAlign="left" | ||||
| disabled | disabled | ||||
| > | > | ||||
| @@ -45,9 +45,9 @@ function ParamsModal({ open, onCancel, globalParam = [] }: ParamsModalProps) { | |||||
| {...restField} | {...restField} | ||||
| key={key} | key={key} | ||||
| name={[name, 'param_value']} | name={[name, 'param_value']} | ||||
| label={getParamLabel(globalParam[name])} | |||||
| label={getParamLabel(globalParams[name])} | |||||
| > | > | ||||
| {getParamComponent(globalParam[name]['param_type'])} | |||||
| {getParamComponent(globalParams[name]['param_type'])} | |||||
| </Form.Item> | </Form.Item> | ||||
| )) | )) | ||||
| } | } | ||||
| @@ -226,14 +226,14 @@ function Experiment() { | |||||
| if (type === ExperimentCompleted) { | if (type === ExperimentCompleted) { | ||||
| const { experimentId, experimentInsId, status, finishTime } = payload; | const { experimentId, experimentInsId, status, finishTime } = payload; | ||||
| const currentIns = experimentInsList.find((v) => v.id === experimentInsId); | const currentIns = experimentInsList.find((v) => v.id === experimentInsId); | ||||
| console.log( | |||||
| '实验实例状态变化', | |||||
| currentIns?.status, | |||||
| status, | |||||
| experimentId, | |||||
| experimentInsId, | |||||
| finishTime, | |||||
| ); | |||||
| // console.log( | |||||
| // '实验实例状态变化', | |||||
| // currentIns?.status, | |||||
| // status, | |||||
| // experimentId, | |||||
| // experimentInsId, | |||||
| // finishTime, | |||||
| // ); | |||||
| if ( | if ( | ||||
| !currentIns || | !currentIns || | ||||
| @@ -1,6 +1,6 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { getParamComponent, getParamRules } from '@/pages/Experiment/components/AddExperimentModal'; | import { getParamComponent, getParamRules } from '@/pages/Experiment/components/AddExperimentModal'; | ||||
| import { type PipelineGlobalParam } from '@/types'; | |||||
| import { type PipelineGlobalParam, PipelineGlobalParamType } from '@/types'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { PlusOutlined } from '@ant-design/icons'; | import { PlusOutlined } from '@ant-design/icons'; | ||||
| @@ -131,9 +131,9 @@ const GlobalParamsDrawer = forwardRef( | |||||
| <Radio.Group | <Radio.Group | ||||
| onChange={() => handleTypeChange(['global_param', name, 'param_value'])} | onChange={() => handleTypeChange(['global_param', name, 'param_value'])} | ||||
| > | > | ||||
| <Radio value={1}>字符串</Radio> | |||||
| <Radio value={2}>整型</Radio> | |||||
| <Radio value={3}>布尔类型</Radio> | |||||
| <Radio value={PipelineGlobalParamType.String}>字符串</Radio> | |||||
| <Radio value={PipelineGlobalParamType.Number}>整型</Radio> | |||||
| <Radio value={PipelineGlobalParamType.Boolean}>布尔类型</Radio> | |||||
| </Radio.Group> | </Radio.Group> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| @@ -614,12 +614,14 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| <Input disabled /> | <Input disabled /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <div className={styles['pipeline-drawer__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="任务信息" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| {basicParametersList.length + controlStrategyList.length > 0 && ( | |||||
| <div className={styles['pipeline-drawer__title']}> | |||||
| <SubAreaTitle | |||||
| image={require('@/assets/img/duty-message.png')} | |||||
| title="任务信息" | |||||
| ></SubAreaTitle> | |||||
| </div> | |||||
| )} | |||||
| {/* 基本参数 */} | {/* 基本参数 */} | ||||
| {basicParametersList.map((item) => ( | {basicParametersList.map((item) => ( | ||||
| @@ -663,6 +665,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| ))} | ))} | ||||
| </> | </> | ||||
| )} | )} | ||||
| {/* 输出参数 */} | {/* 输出参数 */} | ||||
| {outParametersList.length > 0 && ( | {outParametersList.length > 0 && ( | ||||
| <> | <> | ||||
| @@ -29,11 +29,17 @@ export type GlobalInitialState = { | |||||
| clientInfo?: ClientInfo; | clientInfo?: ClientInfo; | ||||
| }; | }; | ||||
| export enum PipelineGlobalParamType { | |||||
| String = 1, | |||||
| Number = 2, | |||||
| Boolean = 3, | |||||
| } | |||||
| // 流水线全局参数 | // 流水线全局参数 | ||||
| export type PipelineGlobalParam = { | export type PipelineGlobalParam = { | ||||
| param_name: string; | param_name: string; | ||||
| description: string; | description: string; | ||||
| param_type: number; | |||||
| param_type: PipelineGlobalParamType; | |||||
| param_value: number | string | boolean; | param_value: number | string | boolean; | ||||
| is_sensitive: number; | is_sensitive: number; | ||||
| }; | }; | ||||