diff --git a/react-ui/mock/components.ts b/react-ui/mock/components.ts new file mode 100644 index 00000000..aecad839 --- /dev/null +++ b/react-ui/mock/components.ts @@ -0,0 +1,1286 @@ +import { defineMock } from 'umi'; + +export default defineMock({ + 'GET /api/mmp/workflow/235': { + code: 200, + msg: '操作成功', + data: { + id: 233, + name: '分布式训练', + description: 'aa', + dag: { + nodes: [ + { + id: 'git-clone-c0724278', + category_id: 1, + component_name: 'git-clone', + component_label: '代码拉取组件', + task_info: { + image: { + type: 'ref', + item_type: 'image', + label: '镜像', + value: null, + visible: false, + editable: false, + require: 1, + default: '', + condition: '', + description: '克隆代码的镜像', + placeholder: '请选择镜像', + rulers: {}, + }, + working_directory: { + type: 'str', + item_type: '', + label: '工作目录', + value: '', + visible: false, + editable: false, + require: 1, + default: '', + placeholder: '请输入工作目录', + condition: '', + description: '容器内的工作目录', + rulers: {}, + }, + command: { + type: 'str', + item_type: '', + label: '启动命令', + value: '', + visible: false, + editable: false, + require: 1, + default: '', + placeholder: '请输入启动命令', + description: '启动命令,不包括运行参数', + rulers: '', + }, + run_args: { + type: 'map', + item_type: '', + label: '运行参数', + value: [], + visible: false, + editable: false, + require: 0, + default: '', + placeholder: '', + condition: '', + description: '运行命令的参数', + rulers: '', + }, + resources_standard: { + type: 'select', + item_type: 'resource', + label: '资源', + value: {}, + visible: false, + editable: false, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '资源规格', + rulers: {}, + }, + }, + + control_strategy: { + retry_times: { + type: 'str', + item_type: '', + label: '重试次数', + require: 0, + default: '', + placeholder: '', + describe: '任务重试次数', + visible: true, + editable: false, + condition: '', + value: '', + rulers: {}, + }, + max_run_times: { + type: 'str', + item_type: '', + label: '最大运行时间', + require: 0, + default: '', + placeholder: '', + describe: '最大运行时间', + editable: false, + visible: true, + condition: '', + value: '', + rulers: {}, + }, + }, + + in_parameters: { + '--code_config': { + type: 'ref', + item_type: 'code', + label: '代码配置', + require: 1, + default: '', + placeholder: '私有仓库填写ssh地址,公有仓库填写https git地址', + describe: + '代码配置,支持私有仓库和公有仓库,私有仓库填写ssh地址,公有仓库填写https git地址', + editable: false, + visible: true, + condition: '', + value: { + id: 21, + name: '原子掺杂识别', + code_path: 'http://172.20.32.235:30202/fanshuai/material-atom-predict.git', + branch: 'optimize', + username: null, + password: null, + ssh_private_key: null, + }, + rulers: {}, + showValue: '原子掺杂识别', + fromSelect: true, + }, + }, + + out_parameters: { + '--code_output': { + type: 'str', + item_type: 'code', + label: '代码保存路径', + require: 1, + default: '/code', + editable: false, + visible: true, + placeholder: '代码保存路径', + describe: '代码保存路径', + condition: '', + showValue: '/mycode', + value: '/mycode', + rulers: {}, + fromSelect: false, + }, + }, + + available_range: 0, + description: '代码拉取组件', + icon_path: 'component-icon-1', + create_by: 'admin', + create_time: '2024-09-02T06:08:06.000+08:00', + update_by: 'admin', + update_time: '2024-09-02T06:08:06.000+08:00', + state: 1, + env_variables: [], + x: 612, + y: 215, + label: '代码拉取', + img: '/assets/images/component-icon-1.png', + isCluster: false, + formError: false, + type: 'rect-node', + size: [110, 36], + labelCfg: { + style: { + fill: 'transparent', + fontSize: 0, + boxShadow: '0px 0px 12px rgba(75, 84, 137, 0.05)', + overflow: 'hidden', + x: -20, + y: 0, + textAlign: 'left', + textBaseline: 'middle', + }, + }, + style: { + active: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + }, + selected: { + fill: 'rgb(255, 255, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 4, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + fill: 'rgb(223, 234, 255)', + stroke: '#4572d9', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(191, 213, 255)', + lineWidth: 1, + }, + disable: { + fill: 'rgb(250, 250, 250)', + stroke: 'rgb(224, 224, 224)', + lineWidth: 1, + }, + fill: '#fff', + stroke: 'transparent', + cursor: 'pointer', + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, + overflow: 'hidden', + lineWidth: 0.5, + }, + depth: 0, + }, + { + id: 'model-train-39e9bc7c', + category_id: 2, + component_name: 'model-train', + component_label: '模型训练', + task_info: { + image: { + type: 'ref', + item_type: 'image', + label: '镜像', + value: {}, + visible: true, + editable: true, + require: 1, + default: '', + condition: '', + description: '镜像', + placeholder: '', + rulers: {}, + }, + working_directory: { + type: 'str', + item_type: '', + label: '工作目录', + value: '{{git-clone-c0724278.--code_output}}', + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '容器内的工作目录', + rulers: {}, + }, + command: { + type: 'str', + item_type: '', + label: '启动命令', + value: 'conda run -n atom-predict python recognize_dophant/egnn/train_pl_vor.py', + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + description: '启动命令,不包括运行参数', + rulers: '', + }, + run_args: { + type: 'map', + item_type: '', + label: '运行参数', + value: [], + visible: true, + editable: true, + require: 0, + default: '', + placeholder: '', + condition: '', + description: '运行命令的参数', + rulers: '', + }, + resources_standard: { + type: 'select', + item_type: 'resource', + label: '资源', + value: { + id: 30, + resource_id: 4, + computing_resource: 'CPU', + standard: { + name: 'CPU', + value: { + gpu: 0, + cpu: 4, + memory: '8GB', + }, + }, + description: 'GPU: 0, CPU:4, 内存: 8GB', + cpu_cores: 4, + memory_gb: 8, + gpu_memory_gb: 0, + gpu_nums: 0, + credit_per_hour: 2.0, + labels: 'accelertor=cpu', + create_by: 'admin', + create_time: '2024-04-19T11:39:40.000+08:00', + update_by: 'admin', + update_time: '2024-04-19T11:39:40.000+08:00', + state: 1, + }, + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '资源规格', + rulers: {}, + }, + }, + + control_strategy: { + retry_times: { + type: 'str', + item_type: '', + label: '重试次数', + require: 0, + default: '', + placeholder: '', + describe: '任务重试次数', + visible: true, + editable: true, + condition: '', + value: '', + rulers: {}, + }, + max_run_times: { + type: 'str', + item_type: '', + label: '最大运行时间', + require: 0, + default: '', + placeholder: '', + describe: '最大运行时间', + editable: true, + visible: true, + condition: '', + value: '', + rulers: {}, + }, + }, + in_parameters: { + '--dataset': { + type: 'ref', + item_type: 'dataset', + label: '选择数据集', + require: 1, + default: '', + placeholder: '', + describe: '选择数据集', + condition: '', + visible: true, + editable: true, + value: { + id: '73', + name: '原子掺杂识别场景测试', + version: 'v1', + path: 'fanshuai/datasets/73/fanshuai_dataset_20250519103524/v1/dataset', + identifier: 'fanshuai_dataset_20250519103524', + owner: 'fanshuai', + }, + rulers: {}, + showValue: '原子掺杂识别场景测试:v1', + fromSelect: true, + activeTab: 'Private', + expandedKeys: ['73'], + checkedKeys: ['73-v1'], + }, + '--model_name': { + type: 'ref', + item_type: 'model', + label: '选择模型', + require: 0, + default: '', + placeholder: '', + describe: '最大运行时间', + editable: true, + visible: true, + condition: '', + value: { + id: '39', + name: '原子参杂识别模型', + version: 'v1', + path: 'fanshuai/model/39/fanshuai_model_20250513113514/v1/model', + identifier: 'fanshuai_model_20250513113514', + owner: 'fanshuai', + }, + rulers: {}, + showValue: '原子参杂识别模型:v1', + fromSelect: true, + activeTab: 'Private', + expandedKeys: ['39'], + checkedKeys: ['39-v1'], + }, + }, + out_parameters: { + '--model_output': { + type: 'str', + item_type: '', + label: '模型输出路径', + require: 1, + showValue: '/model', + default: '', + placeholder: '', + describe: '模型输出路径', + editable: true, + visible: true, + rulers: {}, + condition: '', + value: '/model', + fromSelect: false, + }, + }, + available_range: 1, + description: '通用模型训练组件介绍', + icon_path: 'component-icon-2', + create_by: 'admin', + create_time: '2024-05-28T07:33:53.000+08:00', + update_by: 'admin', + update_time: '2024-05-28T07:33:53.000+08:00', + state: 1, + env_variables: [], + x: 596, + y: 348, + label: '模型训练', + img: '/assets/images/component-icon-2.png', + isCluster: false, + formError: false, + type: 'rect-node', + size: [110, 36], + labelCfg: { + style: { + fill: 'transparent', + fontSize: 0, + boxShadow: '0px 0px 12px rgba(75, 84, 137, 0.05)', + overflow: 'hidden', + x: -20, + y: 0, + textAlign: 'left', + textBaseline: 'middle', + }, + }, + style: { + active: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + }, + selected: { + fill: 'rgb(255, 255, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 4, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + fill: 'rgb(223, 234, 255)', + stroke: '#4572d9', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(191, 213, 255)', + lineWidth: 1, + }, + disable: { + fill: 'rgb(250, 250, 250)', + stroke: 'rgb(224, 224, 224)', + lineWidth: 1, + }, + fill: '#fff', + stroke: 'transparent', + cursor: 'pointer', + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, + overflow: 'hidden', + lineWidth: 0.5, + }, + depth: 0, + }, + { + id: 'model-evaluate-c5b68e7c', + category_id: 4, + component_name: 'model-evaluate', + component_label: '模型测试', + task_info: { + image: { + type: 'ref', + item_type: 'image', + label: '镜像', + value: { + id: 15, + image_id: 17, + version: 'v1', + description: null, + url: '172.20.32.187/machine-learning/atom-egnn:v2', + tag_name: 'v1', + file_size: '125MB', + status: 'Available', + create_by: 'fanshuai', + create_time: '2024-04-18T00:00:00.000+08:00', + update_by: 'admin', + update_time: '2024-04-18T00:00:00.000+08:00', + state: 1, + host_ip: null, + }, + visible: false, + editable: false, + require: 0, + default: '', + condition: '', + description: '镜像', + placeholder: '', + rulers: {}, + }, + working_directory: { + type: 'str', + item_type: '', + label: '工作目录', + value: '{{git-clone-c0724278.--code_output}}', + visible: false, + editable: false, + require: 0, + default: '', + placeholder: '', + condition: '', + description: '容器内的工作目录', + rulers: {}, + }, + command: { + type: 'str', + item_type: '', + label: '启动命令', + value: 'conda run -n atom-predict python recognize_dophant/egnn/test_pl_vor.py', + visible: false, + editable: false, + require: 0, + default: '', + placeholder: '', + description: '启动命令,不包括运行参数', + rulers: '', + }, + run_args: { + type: 'map', + item_type: '', + label: '运行参数', + value: [], + visible: false, + editable: false, + require: 0, + default: '', + placeholder: '', + condition: '', + description: '运行命令的参数', + rulers: '', + }, + resources_standard: { + type: 'select', + item_type: 'resource', + label: '资源', + value: { + id: 30, + resource_id: 4, + computing_resource: 'CPU', + standard: { + name: 'CPU', + value: { + gpu: 0, + cpu: 4, + memory: '8GB', + }, + }, + description: 'GPU: 0, CPU:4, 内存: 8GB', + cpu_cores: 4, + memory_gb: 8, + gpu_memory_gb: 0, + gpu_nums: 0, + credit_per_hour: 2.0, + labels: 'accelertor=cpu', + create_by: 'admin', + create_time: '2024-04-19T11:39:40.000+08:00', + update_by: 'admin', + update_time: '2024-04-19T11:39:40.000+08:00', + state: 1, + }, + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '资源规格', + rulers: {}, + }, + }, + + control_strategy: { + retry_times: { + type: 'str', + item_type: '', + label: '重试次数', + require: 0, + default: '', + placeholder: '', + describe: '任务重试次数', + visible: true, + editable: true, + condition: '', + value: '', + rulers: {}, + }, + max_run_times: { + type: 'str', + item_type: '', + label: '最大运行时间', + require: 0, + default: '', + placeholder: '', + describe: '最大运行时间', + editable: true, + visible: true, + condition: '', + value: '', + rulers: {}, + }, + }, + + in_parameters: { + '--dataset': { + type: 'ref', + item_type: 'dataset', + label: '选择数据集', + require: 1, + default: '', + placeholder: '', + describe: '选择数据集', + condition: '', + editable: true, + visible: true, + value: { + id: '74', + name: '原子掺杂识别模型测试数据集', + version: 'v2', + path: 'fanshuai/datasets/74/fanshuai_dataset_20250519103749/v2/dataset', + identifier: 'fanshuai_dataset_20250519103749', + owner: 'fanshuai', + }, + rulers: {}, + showValue: '原子掺杂识别模型测试数据集:v2', + fromSelect: true, + activeTab: 'Private', + expandedKeys: ['74'], + checkedKeys: ['74-v2'], + }, + '--model_name': { + type: 'ref', + item_type: 'model', + label: '选择模型', + require: 1, + editable: true, + visible: true, + rulers: {}, + default: '', + placeholder: '', + describe: '这里是这个参数的描述和备注', + condition: '', + value: '{{model-train-39e9bc7c.--model_output}}', + showValue: '{{model-train-39e9bc7c.--model_output}}', + fromSelect: true, + }, + }, + out_parameters: { + '--model_output': { + type: 'str', + item_type: '', + label: '模型测试结果路径', + editable: true, + visible: true, + rulers: {}, + default: '', + placeholder: '', + describe: '这里是这个参数的描述和备注', + condition: '', + require: 1, + showValue: '/result', + value: '/result', + fromSelect: false, + }, + }, + available_range: 1, + description: '模型测试', + icon_path: 'component-icon-4', + create_by: 'admin', + create_time: '2024-05-24T07:00:10.000+08:00', + update_by: 'admin', + update_time: '2024-05-24T07:00:10.000+08:00', + state: 1, + env_variables: [], + x: 600, + y: 460, + label: '模型评估', + img: '/assets/images/component-icon-4.png', + isCluster: false, + formError: false, + type: 'rect-node', + size: [110, 36], + labelCfg: { + style: { + fill: 'transparent', + fontSize: 0, + boxShadow: '0px 0px 12px rgba(75, 84, 137, 0.05)', + overflow: 'hidden', + x: -20, + y: 0, + textAlign: 'left', + textBaseline: 'middle', + }, + }, + style: { + active: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + }, + selected: { + fill: 'rgb(255, 255, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 4, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + fill: 'rgb(223, 234, 255)', + stroke: '#4572d9', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(191, 213, 255)', + lineWidth: 1, + }, + disable: { + fill: 'rgb(250, 250, 250)', + stroke: 'rgb(224, 224, 224)', + lineWidth: 1, + }, + fill: '#fff', + stroke: 'transparent', + cursor: 'pointer', + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, + overflow: 'hidden', + lineWidth: 0.5, + }, + depth: 0, + }, + { + id: 'model-export-edcf438e', + category_id: 6, + component_name: 'model-export', + component_label: '模型导出', + task_info: { + image: { + type: 'ref', + item_type: 'image', + label: '镜像', + value: {}, + visible: true, + editable: true, + require: 1, + default: '', + condition: '', + description: '镜像', + placeholder: '', + rulers: {}, + }, + working_directory: { + type: 'str', + item_type: '', + label: '工作目录', + value: '{{git-clone-c0724278.--code_output}}', + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '容器内的工作目录', + rulers: {}, + }, + command: { + type: 'str', + item_type: '', + label: '启动命令', + value: 'conda run -n atom-predict python recognize_dophant/egnn/test_pl_vor.py', + visible: true, + editable: true, + require: 1, + default: '', + placeholder: '', + description: '启动命令,不包括运行参数', + rulers: '', + }, + run_args: { + type: 'map', + item_type: '', + label: '运行参数', + value: [], + visible: true, + editable: true, + require: 0, + default: '', + placeholder: '', + condition: '', + description: '运行命令的参数', + rulers: '', + }, + resources_standard: { + type: 'select', + item_type: 'resource', + label: '资源', + value: {}, + visible: false, + editable: false, + require: 1, + default: '', + placeholder: '', + condition: '', + description: '资源规格', + rulers: {}, + }, + }, + control_strategy: { + retry_times: { + type: 'str', + item_type: '', + label: '重试次数', + require: 0, + default: '', + placeholder: '', + describe: '任务重试次数', + visible: true, + editable: true, + condition: '', + value: '', + rulers: {}, + }, + max_run_times: { + type: 'str', + item_type: '', + label: '最大运行时间', + require: 0, + default: '', + placeholder: '', + describe: '最大运行时间', + editable: true, + visible: true, + condition: '', + value: '', + rulers: {}, + }, + }, + + in_parameters: { + '--model_source': { + type: 'str', + item_type: '', + label: '模型来源', + require: 1, + default: '', + placeholder: '模型来源', + describe: '模型来源', + editable: true, + visible: true, + condition: '', + value: '{{model-train-39e9bc7c.--model_output}}', + rulers: {}, + fromSelect: true, + showValue: '{{model-train-39e9bc7c.--model_output}}', + }, + '--model_id': { + type: 'select', + item_type: 'model', + label: '导出到模型', + require: 1, + default: '', + placeholder: '', + describe: '导出到模型', + editable: true, + visible: true, + condition: '', + value: { + id: '76', + name: '原子掺杂识别模型场景测试', + identifier: 'fanshuai_model_20250519105223', + owner: 'fanshuai', + }, + rulers: {}, + }, + '--version': { + type: 'str', + item_type: '', + label: '模型版本', + require: 1, + choice: [], + default: '1', + placeholder: '', + describe: '模型版本', + editable: false, + condition: '', + showValue: '${model_version}', + value: '${model_version}', + fromSelect: false, + }, + '--description': { + type: 'str', + item_type: '', + label: '版本描述', + require: 1, + choice: [], + default: '', + placeholder: '版本描述', + describe: '版本描述', + editable: false, + condition: '', + showValue: '流水线自动导出', + value: '流水线自动导出', + fromSelect: false, + }, + }, + available_range: 0, + description: '模型导出', + icon_path: 'component-icon-8', + create_by: 'admin', + create_time: '2024-05-29T01:12:01.000+08:00', + update_by: 'admin', + update_time: '2024-05-29T09:11:55.000+08:00', + state: 1, + env_variables: [], + x: 592, + y: 581, + label: '模型导出', + img: '/assets/images/component-icon-8.png', + isCluster: false, + formError: false, + type: 'rect-node', + size: [110, 36], + labelCfg: { + style: { + fill: 'transparent', + fontSize: 0, + boxShadow: '0px 0px 12px rgba(75, 84, 137, 0.05)', + overflow: 'hidden', + x: -20, + y: 0, + textAlign: 'left', + textBaseline: 'middle', + }, + }, + style: { + active: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + }, + selected: { + fill: 'rgb(255, 255, 255)', + stroke: 'rgb(95, 149, 255)', + lineWidth: 4, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + fill: 'rgb(223, 234, 255)', + stroke: '#4572d9', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + fill: 'rgb(247, 250, 255)', + stroke: 'rgb(191, 213, 255)', + lineWidth: 1, + }, + disable: { + fill: 'rgb(250, 250, 250)', + stroke: 'rgb(224, 224, 224)', + lineWidth: 1, + }, + fill: '#fff', + stroke: 'transparent', + cursor: 'pointer', + radius: 8, + shadowColor: 'rgba(75, 84, 137, 0.4)', + shadowBlur: 6, + shadowOffsetX: 0, + shadowOffsetY: 0, + overflow: 'hidden', + lineWidth: 0.5, + }, + depth: 0, + }, + ], + edges: [ + { + source: 'git-clone-c0724278', + target: 'model-train-39e9bc7c', + style: { + endArrow: { + path: 'M 6,0 L 9,-1.5 L 9,1.5 Z', + d: 4.5, + fill: '#CDD0DC', + }, + cursor: 'pointer', + lineWidth: 1, + lineAppendWidth: 4, + opacity: 1, + stroke: '#CDD0DC', + radius: 1, + active: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 1, + }, + selected: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + stroke: 'rgb(234, 234, 234)', + lineWidth: 1, + }, + disable: { + stroke: 'rgb(245, 245, 245)', + lineWidth: 1, + }, + }, + labelCfg: { + autoRotate: true, + style: { + fontSize: 10, + fill: '#FFF', + }, + }, + id: 'edge-0.163955357654560491741769193740', + startPoint: { + x: 612, + y: 233.25, + anchorIndex: 1, + }, + endPoint: { + x: 596, + y: 329.75, + anchorIndex: 0, + }, + sourceAnchor: 1, + targetAnchor: 0, + type: 'cubic-vertical', + curvePosition: [0.5, 0.5], + minCurveOffset: [0, 0], + depth: 0, + }, + { + source: 'model-train-39e9bc7c', + target: 'model-evaluate-c5b68e7c', + style: { + endArrow: { + path: 'M 6,0 L 9,-1.5 L 9,1.5 Z', + d: 4.5, + fill: '#CDD0DC', + }, + cursor: 'pointer', + lineWidth: 1, + lineAppendWidth: 4, + opacity: 1, + stroke: '#CDD0DC', + radius: 1, + active: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 1, + }, + selected: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + stroke: 'rgb(234, 234, 234)', + lineWidth: 1, + }, + disable: { + stroke: 'rgb(245, 245, 245)', + lineWidth: 1, + }, + }, + labelCfg: { + autoRotate: true, + style: { + fontSize: 10, + fill: '#FFF', + }, + }, + id: 'edge-0.150681812754051241741769198063', + startPoint: { + x: 596, + y: 366.25, + anchorIndex: 1, + }, + endPoint: { + x: 600, + y: 441.75, + anchorIndex: 0, + }, + sourceAnchor: 1, + targetAnchor: 0, + type: 'cubic-vertical', + curvePosition: [0.5, 0.5], + minCurveOffset: [0, 0], + depth: 0, + }, + { + source: 'model-evaluate-c5b68e7c', + target: 'model-export-edcf438e', + style: { + endArrow: { + path: 'M 6,0 L 9,-1.5 L 9,1.5 Z', + d: 4.5, + fill: '#CDD0DC', + }, + cursor: 'pointer', + lineWidth: 1, + lineAppendWidth: 4, + opacity: 1, + stroke: '#CDD0DC', + radius: 1, + active: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 1, + }, + selected: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + shadowColor: 'rgb(95, 149, 255)', + shadowBlur: 10, + 'text-shape': { + fontWeight: 500, + }, + }, + highlight: { + stroke: 'rgb(95, 149, 255)', + lineWidth: 2, + 'text-shape': { + fontWeight: 500, + }, + }, + inactive: { + stroke: 'rgb(234, 234, 234)', + lineWidth: 1, + }, + disable: { + stroke: 'rgb(245, 245, 245)', + lineWidth: 1, + }, + }, + labelCfg: { + autoRotate: true, + style: { + fontSize: 10, + fill: '#FFF', + }, + }, + id: 'edge-0.40652053406360491741769205906', + startPoint: { + x: 600, + y: 478.25, + anchorIndex: 1, + }, + endPoint: { + x: 592, + y: 562.75, + anchorIndex: 0, + }, + sourceAnchor: 1, + targetAnchor: 0, + type: 'cubic-vertical', + curvePosition: [0.5, 0.5], + minCurveOffset: [0, 0], + depth: 0, + }, + ], + combos: [], + }, + global_param: null, + create_by: 'fanshuai', + create_time: '2025-06-19T19:50:47.000+08:00', + update_by: 'fanshuai', + update_time: '2025-06-24T09:28:28.000+08:00', + state: 1, + }, + }, +}); diff --git a/react-ui/package.json b/react-ui/package.json index 21710bca..10086d10 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -8,7 +8,7 @@ "build": "max build", "deploy": "npm run build && npm run gh-pages", "dev": "npm run start:dev", - "dev-no-sso": "cross-env NO_SSO=true npm run start:dev", + "dev-no-sso": "cross-env NO_SSO=true npm run start:mock", "docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./", "docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build", "docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up", @@ -35,7 +35,7 @@ "serve": "umi-serve", "start": "cross-env UMI_ENV=dev max dev", "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev UMI_DEV_SERVER_COMPRESS=none max dev", - "start:mock": "cross-env REACT_APP_ENV=dev UMI_ENV=dev max dev", + "start:mock": "cross-env REACT_APP_ENV=dev UMI_ENV=dev UMI_DEV_SERVER_COMPRESS=none max dev", "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", "storybook": "storybook dev -p 6006", diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 08cf8649..fef6b900 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -9,6 +9,7 @@ import { CloseOutlined } from '@ant-design/icons'; import { ConfigProvider, Form, Input, Typography } from 'antd'; import { RuleObject } from 'antd/es/form'; import classNames from 'classnames'; +import { ReactNode } from 'react'; import './index.less'; // 如果值是对象时的类型 @@ -55,6 +56,8 @@ export interface ParameterInputProps { disabled?: boolean; /** 元素 id */ id?: string; + /** 带标签的 input,设置后置标签 */ + addonAfter?: ReactNode; } function ParameterInput({ @@ -75,7 +78,7 @@ function ParameterInput({ const valueObj = typeof value === 'string' ? { value: value, fromSelect: false, showValue: value } : value; if (valueObj && !valueObj.showValue) { - valueObj.showValue = valueObj.value; + valueObj.showValue = typeof valueObj.value === 'string' ? valueObj.value : ''; } const isSelect = valueObj?.fromSelect; const placeholder = valueObj?.placeholder || rest?.placeholder; diff --git a/react-ui/src/components/ResourceSelect/index.tsx b/react-ui/src/components/ResourceSelect/index.tsx index ccec75f1..db8a4fec 100644 --- a/react-ui/src/components/ResourceSelect/index.tsx +++ b/react-ui/src/components/ResourceSelect/index.tsx @@ -10,10 +10,10 @@ import ResourceSelectorModal, { ResourceSelectorType, selectorTypeConfig, } from '@/components/ResourceSelectorModal'; +import { CommonTabKeys } from '@/enums'; import { openAntdModal } from '@/utils/modal'; import { Button, ConfigProvider } from 'antd'; import classNames from 'classnames'; -import { pick } from 'lodash'; import ParameterInput, { type ParameterInputProps } from '../ParameterInput'; import './index.less'; @@ -27,6 +27,8 @@ export { ResourceSelectorType, selectorTypeConfig, type ResourceSelectorResponse interface ResourceSelectProps extends ParameterInputProps { /** 类型,数据集、模型、镜像 */ type: ResourceSelectorType; + /** 值 */ + value?: ResourceSelectorResponse; } // 获取选择数据集、模型、镜像后面按钮 icon @@ -47,68 +49,51 @@ function ResourceSelect({ }: ResourceSelectProps) { const { componentSize } = ConfigProvider.useConfig(); const mySize = size || componentSize; - let selectedResource: ResourceSelectorResponse | undefined = undefined; - if ( - value && - typeof value === 'object' && - value.activeTab && - value.id && - value.name && - value.version && - value.path && - (type === ResourceSelectorType.Mirror || (value.identifier && value.owner)) - ) { - selectedResource = pick(value, [ - 'activeTab', - 'id', - 'identifier', - 'name', - 'owner', - 'version', - 'path', - ]) as ResourceSelectorResponse; + let defaultActiveTab: CommonTabKeys | undefined, + defaultExpandedKeys: string[] = [], + defaultCheckedKeys: string[] = []; + if (value && typeof value === 'object') { + defaultActiveTab = value.activeTab; + if (type === ResourceSelectorType.Mirror) { + if (value.image_id && value.id) { + defaultExpandedKeys = [`${value.image_id}`]; + defaultCheckedKeys = [`${value.image_id}-${value.id}`]; + } + } else if (value.id && value.version) { + defaultExpandedKeys = [value.id]; + defaultCheckedKeys = [`${value.id}-${value.version}`]; + } } // 选择数据集、模型、镜像 const selectResource = () => { const { close } = openAntdModal(ResourceSelectorModal, { type, - defaultExpandedKeys: selectedResource ? [selectedResource.id] : [], - defaultCheckedKeys: selectedResource - ? [`${selectedResource.id}-${selectedResource.version}`] - : [], - defaultActiveTab: selectedResource?.activeTab, + defaultExpandedKeys: defaultExpandedKeys, + defaultCheckedKeys: defaultCheckedKeys, + defaultActiveTab: defaultActiveTab, onOk: (res) => { if (res) { - const { activeTab, id, name, version, path, identifier, owner } = res; if (type === ResourceSelectorType.Mirror) { + const { activeTab, ...rest } = res; + const { url } = rest; onChange?.({ - value: path, - showValue: path, + ...rest, + value: url, + showValue: url, fromSelect: true, activeTab, - id, - name, - version, - path, }); } else { - const jsonObj = { - id, - name, - version, - path, - identifier, - owner, - }; - const jsonObjStr = JSON.stringify(jsonObj); + const { activeTab, ...rest } = res; + const { name, version } = rest; const showValue = `${name}:${version}`; onChange?.({ - value: jsonObjStr, + ...rest, + value: showValue, showValue, fromSelect: true, activeTab, - ...jsonObj, }); } } else { diff --git a/react-ui/src/components/ResourceSelectorModal/config.tsx b/react-ui/src/components/ResourceSelectorModal/config.tsx index a5b38057..8fc193f6 100644 --- a/react-ui/src/components/ResourceSelectorModal/config.tsx +++ b/react-ui/src/components/ResourceSelectorModal/config.tsx @@ -52,9 +52,9 @@ const convertResourceVersionToTreeData = ( ): TreeDataNode[] => { return list.map((item: ResourceVersionData) => ({ ...pick(info, ['id', 'name', 'owner', 'identifier', 'is_public']), - version: item.name, - title: item.name, key: `${parentId}-${item.name}`, + title: item.name, + version: item.name, isLeaf: true, checkable: true, })); @@ -66,12 +66,11 @@ const convertMirrorVersionToTreeData = ( list: MirrorVersionData[], ): TreeDataNode[] => { return list.map((item: MirrorVersionData) => ({ - url: item.url, - title: item.tag_name, + ...item, key: `${parentId}-${item.id}`, + title: item.tag_name, isLeaf: true, checkable: true, - description: item.description, })); }; diff --git a/react-ui/src/components/ResourceSelectorModal/index.tsx b/react-ui/src/components/ResourceSelectorModal/index.tsx index 5bed94bb..b7abaf1b 100644 --- a/react-ui/src/components/ResourceSelectorModal/index.tsx +++ b/react-ui/src/components/ResourceSelectorModal/index.tsx @@ -8,6 +8,7 @@ import KFIcon from '@/components/KFIcon'; import KFModal from '@/components/KFModal'; import { CommonTabKeys } from '@/enums'; import { ResourceFileData } from '@/pages/Dataset/config'; +import { type MirrorVersionData } from '@/pages/Mirror/Info'; import { to } from '@/utils/promise'; import type { GetRef, ModalProps, TreeDataNode, TreeProps } from 'antd'; import { Input, Tabs, Tree } from 'antd'; @@ -19,13 +20,13 @@ export { ResourceSelectorType, selectorTypeConfig }; // 选择数据集、模型、镜像的返回类型 export type ResourceSelectorResponse = { activeTab: CommonTabKeys; // 是我的还是公开的 - id: string; // 数据集\模型\镜像 id - name: string; // 数据集\模型\镜像 name - version: string; // 数据集\模型\镜像版本 - path: string; // 数据集\模型\镜像版本路径 - identifier: string; // 数据集\模型 identifier,镜像这个字段为空 - owner: string; // 数据集\模型 owner,镜像这个字段为空 -}; + id: string; // 数据集\模型 id + name: string; // 数据集\模型 name + identifier: string; // 数据集\模型 identifier + owner: string; // 数据集\模型 owner + version: string; // 数据集\模型 version + path: string; // 数据集\模型 版本路径 +} & MirrorVersionData; export interface ResourceSelectorModalProps extends Omit { /** 类型,数据集、模型、镜像 */ @@ -241,15 +242,22 @@ function ResourceSelectorModal({ const name = (treeNode?.title ?? '') as string; const identifier = (treeNode?.identifier ?? '') as string; const owner = (treeNode?.owner ?? '') as string; - const res = { - id, - name, - path: versionPath, - version, - identifier, - owner, - activeTab: activeTab, - }; + const childNode = treeNode.children.filter((v: TreeDataNode) => v.key === last)[0]; + const res = + type === ResourceSelectorType.Mirror + ? { + activeTab: activeTab, + ...childNode, + } + : { + activeTab: activeTab, + id, + name, + path: versionPath, + version, + identifier, + owner, + }; onOk?.(res); } else { onOk?.(undefined); diff --git a/react-ui/src/enums/index.ts b/react-ui/src/enums/index.ts index 59a02938..848016f0 100644 --- a/react-ui/src/enums/index.ts +++ b/react-ui/src/enums/index.ts @@ -163,3 +163,11 @@ export enum AutoMLTrailStatus { CANCELLED = 'CANCELLED', // 取消 MEMOUT = 'MEMOUT', // 内存溢出 } + +// 流水线组件类型 +export enum ComponentType { + Ref = 'ref', + Select = 'select', + Map = 'map', + Str = 'str', +} diff --git a/react-ui/src/pages/Mirror/Info/index.tsx b/react-ui/src/pages/Mirror/Info/index.tsx index 30b6ad47..1a925831 100644 --- a/react-ui/src/pages/Mirror/Info/index.tsx +++ b/react-ui/src/pages/Mirror/Info/index.tsx @@ -46,6 +46,7 @@ export type MirrorInfoData = { }; export type MirrorVersionData = { + image_id: number; id: number; version: string; url: string; diff --git a/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx b/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx index b12f26f4..c679b643 100644 --- a/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx +++ b/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx @@ -23,7 +23,7 @@ import { removeFormListItem } from '@/utils/ui'; import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { useNavigate, useParams } from '@umijs/max'; import { App, Button, Col, Flex, Form, Input, InputNumber, Row } from 'antd'; -import { omit, pick } from 'lodash'; +import { omit } from 'lodash'; import { useEffect, useState } from 'react'; import { CreateServiceVersionFrom, ServiceOperationType, ServiceVersionData } from '../types'; import styles from './index.less'; @@ -79,7 +79,7 @@ function CreateServiceVersion() { if (res.model && typeof res.model === 'object') { model = changePropertyName(res.model, { show_value: 'showValue' }); // 接口返回是数据没有 value 值,但是 form 需要 value - model.value = model.showValue; + // model.value = model.showValue; } // 环境变量 if (res.env_variables && typeof res.env_variables === 'object') { @@ -128,10 +128,7 @@ function CreateServiceVersion() { ...omit(formData, ['replicas', 'env_variables', 'model']), replicas: Number(formData.replicas), env_variables: envVariables, - model: changePropertyName( - pick(model, ['id', 'name', 'version', 'path', 'identifier', 'owner', 'showValue']), - { showValue: 'show_value' }, - ), + model: changePropertyName(model, { showValue: 'show_value' }), service_id: serviceId, }; diff --git a/react-ui/src/pages/Pipeline/Info/index.jsx b/react-ui/src/pages/Pipeline/Info/index.jsx index 4e86dbbb..3bca3c65 100644 --- a/react-ui/src/pages/Pipeline/Info/index.jsx +++ b/react-ui/src/pages/Pipeline/Info/index.jsx @@ -290,7 +290,7 @@ const EditPipeline = () => { const { global_param, dag } = res.data; setGlobalParam(global_param || []); if (dag) { - getGraphData(parseJsonText(dag)); + getGraphData(dag); } } }; diff --git a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.less b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.less index 7a802a9b..bc9e1385 100644 --- a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.less +++ b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.less @@ -21,10 +21,7 @@ background: #f8fbff; } - &__ref-row { - display: flex; - align-items: center; - + &__component { &__select-button { display: flex; flex: none; @@ -34,5 +31,29 @@ padding-right: 0; padding-left: 0; } + + &__list-row { + :global { + .ant-row { + padding: 0 !important; + } + } + + &:last-child { + :global { + .ant-form-item { + margin-bottom: 0 !important; + } + } + } + } + + &__add-button { + border-color: .addAlpha(@primary-color, 0.5) []; + box-shadow: none !important; + &:hover { + border-style: solid; + } + } } } diff --git a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx index d65c26f6..7fac7e0b 100644 --- a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx +++ b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx @@ -8,7 +8,7 @@ import ResourceSelectorModal, { selectorTypeConfig, } from '@/components/ResourceSelectorModal'; import SubAreaTitle from '@/components/SubAreaTitle'; -import { CommonTabKeys } from '@/enums'; +import { CommonTabKeys, ComponentType } from '@/enums'; import { canInput, createMenuItems } from '@/pages/Pipeline/Info/utils'; import { PipelineGlobalParam, @@ -19,14 +19,21 @@ import { import { parseJsonText } from '@/utils'; import { openAntdModal } from '@/utils/modal'; import { to } from '@/utils/promise'; +import { removeFormListItem } from '@/utils/ui'; +import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { INode } from '@antv/g6'; -import { Button, Drawer, Form, Input, MenuProps } from 'antd'; +import { Button, Drawer, Flex, Form, Input, MenuProps } from 'antd'; import { RuleObject } from 'antd/es/form'; import { NamePath } from 'antd/es/form/interface'; import { forwardRef, useImperativeHandle, useState } from 'react'; import PropsLabel from '../PropsLabel'; import styles from './index.less'; -const { TextArea } = Input; + +// 表单列表数据 +export type FormListVariable = { + name: string; // 参数名 + value: string; // 参数值 +}; type PipelineNodeParameterProps = { onFormChange: (data: PipelineNodeModelSerialize) => void; @@ -37,12 +44,6 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete const [stagingItem, setStagingItem] = useState( {} as PipelineNodeModelSerialize, ); - const nodeId = Form.useWatch('id', form) as string; - const hasTaskInfo = - nodeId && - !nodeId.startsWith('git-clone') && - !nodeId.startsWith('dataset-export') && - !nodeId.startsWith('model-export'); const [open, setOpen] = useState(false); const [menuItems, setMenuItems] = useState([]); @@ -53,11 +54,16 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete // 不管是否验证成功,都需要获取表单数据 const fields = form.getFieldsValue(); - // 保存字段顺序 - // const control_strategy = { - // ...stagingItem.control_strategy, - // ...fields.control_strategy, - // }; + // 保持原有字段和顺序 + const task_info = { + ...stagingItem.task_info, + ...fields.task_info, + }; + + const control_strategy = { + ...stagingItem.control_strategy, + ...fields.control_strategy, + }; const in_parameters = { ...stagingItem.in_parameters, @@ -68,17 +74,18 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete ...fields.out_parameters, }; - // console.log('getFieldsValue', fields); + console.log('getFieldsValue', fields); const res = { ...stagingItem, ...fields, - // control_strategy: JSON.stringify(control_strategy), - in_parameters: JSON.stringify(in_parameters), - out_parameters: JSON.stringify(out_parameters), + task_info: task_info, + control_strategy: control_strategy, + in_parameters: in_parameters, + out_parameters: out_parameters, formError: !!error, }; - // console.log('res', res); + console.log('res', res); onFormChange(res); } }; @@ -96,19 +103,12 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete validate: boolean = false, ) { try { - const nodeData: PipelineNodeModelSerialize = { - ...model, - in_parameters: JSON.parse(model.in_parameters), - out_parameters: JSON.parse(model.out_parameters), - // control_strategy: JSON.parse(model.control_strategy), - }; - // console.log('model', nodeData); setStagingItem({ - ...nodeData, + ...model, }); form.resetFields(); form.setFieldsValue({ - ...nodeData, + ...model, }); if (validate) { form.validateFields(); @@ -237,32 +237,27 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete onOk: (res) => { if (res) { if (type === ResourceSelectorType.Mirror) { - const { activeTab, id, version, path } = res; - if (formItemName === 'image') { - // 单独的选择镜像 - form.setFieldValue(formItemName, path); - } else { - // 输入参数选择镜像 - form.setFieldValue(formItemName, { - ...item, - value: path, - showValue: path, - fromSelect: true, - activeTab, - expandedKeys: [id], - checkedKeys: [`${id}-${version}`], - }); - } + const { activeTab, ...rest } = res; + const { url, id, image_id } = rest; + form.setFieldValue(formItemName, { + ...item, + value: rest, + showValue: url, + fromSelect: true, + activeTab, + expandedKeys: [`${image_id}`], + checkedKeys: [`${image_id}-${id}`], + }); } else { const { activeTab, id, name, version, path, identifier, owner } = res; - const value = JSON.stringify({ + const value = { id, name, version, path, identifier, owner, - }); + }; const showValue = `${name}:${version}`; form.setFieldValue(formItemName, { ...item, @@ -275,19 +270,15 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete }); } } else { - if (type === ResourceSelectorType.Mirror && formItemName === 'image') { - form.setFieldValue(formItemName, undefined); - } else { - form.setFieldValue(formItemName, { - ...item, - value: undefined, - showValue: undefined, - fromSelect: false, - activeTab: undefined, - expandedKeys: [], - checkedKeys: [], - }); - } + form.setFieldValue(formItemName, { + ...item, + value: undefined, + showValue: undefined, + fromSelect: false, + activeTab: undefined, + expandedKeys: [], + checkedKeys: [], + }); } form.validateFields([formItemName]); close(); @@ -323,16 +314,16 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete // form item label const getLabel = ( item: { key: string; value: PipelineNodeModelParameter }, - namePrefix: string, + parentName: string, ) => { - return item.value.type === 'select' ? ( + return item.value.type === ComponentType.Select || item.value.type === ComponentType.Map ? ( item.value.label + '(' + item.key + ')' ) : ( { - handleParameterClick([namePrefix, item.key], { + handleParameterClick([parentName, item.key], { ...item.value, value, fromSelect: true, @@ -380,21 +371,229 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete return rules; }; + // 表单组件 + const getFormComponent = ( + item: { key: string; value: PipelineNodeModelParameter }, + parentName: string, + ) => { + return ( + <> + {item.value.type === ComponentType.Ref && ( + + + + + + + + + )} + {item.value.type === ComponentType.Select && + (['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( + + + + ) : null)} + {item.value.type === ComponentType.Map && ( + + {' '} + + {(fields, { add, remove }) => ( + <> + {fields.map(({ key, name, ...restField }, index) => ( + + [ + parentName, + item.key, + 'value', + i, + 'name', + ])} + rules={[ + { + validator: (_, value) => { + if (!value) { + return Promise.reject(new Error('请输入变量名')); + } + if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value)) { + return Promise.reject( + new Error( + '变量名只支持字母、数字、下划线、中横线并且必须以字母或下划线开头', + ), + ); + } + // 判断不能重名 + const list = form + .getFieldValue([parentName, item.key, 'value']) + .filter( + (item: FormListVariable | undefined) => + item !== undefined && item !== null, + ); + + const names = list.map((item: FormListVariable) => item.name); + if (new Set(names).size !== names.length) { + return Promise.reject(new Error('变量名不能重复')); + } + return Promise.resolve(); + }, + }, + ]} + > + + + = + + {/* */} + { + handleParameterClick( + [parentName, item.key, 'list', name, 'value'], + { + ...item.value, + value, + fromSelect: true, + showValue: value, + }, + ); + }} + /> + } + > + + + + {index === fields.length - 1 && ( + + )} + + + ))} + {fields.length === 0 && ( + + )} + + )} + + + )} + {item.value.type === ComponentType.Str && ( + + + + )} + + ); + }; + + // 基本参数 + const basicParametersList = Object.entries(stagingItem.task_info ?? {}) + .map(([key, value]) => ({ + key, + value, + })) + .filter((v) => v.value.visible === true); + // 控制策略 - // const controlStrategyList = Object.entries(stagingItem.control_strategy ?? {}).map( - // ([key, value]) => ({ key, value }), - // ); + const controlStrategyList = Object.entries(stagingItem.control_strategy ?? {}) + .map(([key, value]) => ({ key, value })) + .filter((v) => v.value.visible === true); // 输入参数 - const inParametersList = Object.entries(stagingItem.in_parameters ?? {}).map(([key, value]) => ({ - key, - value, - })); + const inParametersList = Object.entries(stagingItem.in_parameters ?? {}) + .map(([key, value]) => ({ + key, + value, + })) + .filter((v) => v.value.visible === true); // 输出参数 - const outParametersList = Object.entries(stagingItem.out_parameters ?? {}).map( - ([key, value]) => ({ key, value }), - ); + const outParametersList = Object.entries(stagingItem.out_parameters ?? {}) + .map(([key, value]) => ({ key, value })) + .filter((v) => v.value.visible === true); return (
- {hasTaskInfo && ( - <> -
- -
- -
- - - - - - -
-
- { - handleParameterClick('working_directory', value); - }} - /> - } - > - - - { - handleParameterClick('command', value); - }} - /> - } - > -