Browse Source

feat: 流水线添加参数

pull/46/head
cp3hnu 1 year ago
parent
commit
18216225a4
79 changed files with 391 additions and 441 deletions
  1. BIN
      react-ui/public/assets/images/compoent-icon-6.png
  2. BIN
      react-ui/public/assets/images/icon/流水线-1.png
  3. BIN
      react-ui/public/assets/images/mindspore模型转换.png
  4. BIN
      react-ui/public/assets/images/pipelieEditIcon.png
  5. BIN
      react-ui/public/assets/images/pipeline-edit-icon.png
  6. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Failed.png
  7. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Omitted.png
  8. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Pending.png
  9. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Running.png
  10. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Skipped.png
  11. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1-Succeeded.png
  12. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-1.png
  13. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Failed.png
  14. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Omitted.png
  15. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Pending.png
  16. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Running.png
  17. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Skipped.png
  18. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2-Succeeded.png
  19. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-2.png
  20. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Failed.png
  21. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Omitted.png
  22. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Pending.png
  23. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Running.png
  24. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Skipped.png
  25. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3-Succeeded.png
  26. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-3.png
  27. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Failed.png
  28. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Omitted.png
  29. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Pending.png
  30. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Running.png
  31. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Skipped.png
  32. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4-Succeeded.png
  33. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-4.png
  34. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Failed.png
  35. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Omitted.png
  36. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Pending.png
  37. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Running.png
  38. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Skipped.png
  39. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5-Succeeded.png
  40. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-5.png
  41. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Failed.png
  42. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Omitted.png
  43. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Pending.png
  44. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Running.png
  45. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Skipped.png
  46. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6-Succeeded.png
  47. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-6.png
  48. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Failed.png
  49. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Omitted.png
  50. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Pending.png
  51. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Running.png
  52. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Skipped.png
  53. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7-Succeeded.png
  54. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-7.png
  55. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Failed.png
  56. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Omitted.png
  57. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Pending.png
  58. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Running.png
  59. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Skipped.png
  60. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8-Succeeded.png
  61. +0
    -0
      react-ui/public/assets/images/pipeline/component-icon-8.png
  62. BIN
      react-ui/public/assets/images/pytorch推理.png
  63. BIN
      react-ui/public/assets/images/pytorch训练.png
  64. BIN
      react-ui/public/assets/images/sjj-icon-1.png
  65. BIN
      react-ui/public/assets/images/tensorflow模型转换.png
  66. BIN
      react-ui/public/assets/images/发送通知.png
  67. BIN
      react-ui/src/assets/img/model-deployment.zip
  68. +4
    -1
      react-ui/src/pages/Pipeline/components/GlobalParamsDrawer/index.tsx
  69. +6
    -0
      react-ui/src/pages/Pipeline/components/PropsLabel/index.less
  70. +44
    -0
      react-ui/src/pages/Pipeline/components/PropsLabel/index.tsx
  71. +11
    -0
      react-ui/src/pages/Pipeline/editPipeline/editPipeline.less
  72. +31
    -22
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  73. +2
    -19
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx
  74. +206
    -131
      react-ui/src/pages/Pipeline/editPipeline/props.jsx
  75. +79
    -0
      react-ui/src/pages/Pipeline/editPipeline/utils.tsx
  76. +1
    -267
      react-ui/src/pages/User/Login/index.tsx
  77. +0
    -0
      react-ui/src/utils/formRules.ts
  78. +1
    -1
      react-ui/src/utils/index.ts
  79. +6
    -0
      react-ui/src/utils/menuRender.tsx

BIN
react-ui/public/assets/images/compoent-icon-6.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.5 kB

BIN
react-ui/public/assets/images/icon/流水线-1.png View File

Before After
Width: 54  |  Height: 54  |  Size: 1.6 kB

BIN
react-ui/public/assets/images/mindspore模型转换.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.9 kB

BIN
react-ui/public/assets/images/pipelieEditIcon.png View File

Before After
Width: 42  |  Height: 40  |  Size: 1.1 kB

BIN
react-ui/public/assets/images/pipeline-edit-icon.png View File

Before After
Width: 42  |  Height: 40  |  Size: 1.1 kB

react-ui/public/assets/images/component-icon-1-Failed.png → react-ui/public/assets/images/pipeline/component-icon-1-Failed.png View File


react-ui/public/assets/images/component-icon-1-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-1-Omitted.png View File


react-ui/public/assets/images/component-icon-1-Pending.png → react-ui/public/assets/images/pipeline/component-icon-1-Pending.png View File


react-ui/public/assets/images/component-icon-1-Running.png → react-ui/public/assets/images/pipeline/component-icon-1-Running.png View File


react-ui/public/assets/images/component-icon-1-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-1-Skipped.png View File


react-ui/public/assets/images/component-icon-1-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-1-Succeeded.png View File


react-ui/public/assets/images/component-icon-1.png → react-ui/public/assets/images/pipeline/component-icon-1.png View File


react-ui/public/assets/images/component-icon-2-Failed.png → react-ui/public/assets/images/pipeline/component-icon-2-Failed.png View File


react-ui/public/assets/images/component-icon-2-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-2-Omitted.png View File


react-ui/public/assets/images/component-icon-2-Pending.png → react-ui/public/assets/images/pipeline/component-icon-2-Pending.png View File


react-ui/public/assets/images/component-icon-2-Running.png → react-ui/public/assets/images/pipeline/component-icon-2-Running.png View File


react-ui/public/assets/images/component-icon-2-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-2-Skipped.png View File


react-ui/public/assets/images/component-icon-2-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-2-Succeeded.png View File


react-ui/public/assets/images/component-icon-2.png → react-ui/public/assets/images/pipeline/component-icon-2.png View File


react-ui/public/assets/images/component-icon-3-Failed.png → react-ui/public/assets/images/pipeline/component-icon-3-Failed.png View File


react-ui/public/assets/images/component-icon-3-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-3-Omitted.png View File


react-ui/public/assets/images/component-icon-3-Pending.png → react-ui/public/assets/images/pipeline/component-icon-3-Pending.png View File


react-ui/public/assets/images/component-icon-3-Running.png → react-ui/public/assets/images/pipeline/component-icon-3-Running.png View File


react-ui/public/assets/images/component-icon-3-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-3-Skipped.png View File


react-ui/public/assets/images/component-icon-3-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-3-Succeeded.png View File


react-ui/public/assets/images/component-icon-3.png → react-ui/public/assets/images/pipeline/component-icon-3.png View File


react-ui/public/assets/images/component-icon-4-Failed.png → react-ui/public/assets/images/pipeline/component-icon-4-Failed.png View File


react-ui/public/assets/images/component-icon-4-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-4-Omitted.png View File


react-ui/public/assets/images/component-icon-4-Pending.png → react-ui/public/assets/images/pipeline/component-icon-4-Pending.png View File


react-ui/public/assets/images/component-icon-4-Running.png → react-ui/public/assets/images/pipeline/component-icon-4-Running.png View File


react-ui/public/assets/images/component-icon-4-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-4-Skipped.png View File


react-ui/public/assets/images/component-icon-4-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-4-Succeeded.png View File


react-ui/public/assets/images/component-icon-4.png → react-ui/public/assets/images/pipeline/component-icon-4.png View File


react-ui/public/assets/images/component-icon-5-Failed.png → react-ui/public/assets/images/pipeline/component-icon-5-Failed.png View File


react-ui/public/assets/images/component-icon-5-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-5-Omitted.png View File


react-ui/public/assets/images/component-icon-5-Pending.png → react-ui/public/assets/images/pipeline/component-icon-5-Pending.png View File


react-ui/public/assets/images/component-icon-5-Running.png → react-ui/public/assets/images/pipeline/component-icon-5-Running.png View File


react-ui/public/assets/images/component-icon-5-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-5-Skipped.png View File


react-ui/public/assets/images/component-icon-5-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-5-Succeeded.png View File


react-ui/public/assets/images/component-icon-5.png → react-ui/public/assets/images/pipeline/component-icon-5.png View File


react-ui/public/assets/images/component-icon-6-Failed.png → react-ui/public/assets/images/pipeline/component-icon-6-Failed.png View File


react-ui/public/assets/images/component-icon-6-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-6-Omitted.png View File


react-ui/public/assets/images/component-icon-6-Pending.png → react-ui/public/assets/images/pipeline/component-icon-6-Pending.png View File


react-ui/public/assets/images/component-icon-6-Running.png → react-ui/public/assets/images/pipeline/component-icon-6-Running.png View File


react-ui/public/assets/images/component-icon-6-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-6-Skipped.png View File


react-ui/public/assets/images/component-icon-6-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-6-Succeeded.png View File


react-ui/public/assets/images/component-icon-6.png → react-ui/public/assets/images/pipeline/component-icon-6.png View File


react-ui/public/assets/images/component-icon-7-Failed.png → react-ui/public/assets/images/pipeline/component-icon-7-Failed.png View File


react-ui/public/assets/images/component-icon-7-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-7-Omitted.png View File


react-ui/public/assets/images/component-icon-7-Pending.png → react-ui/public/assets/images/pipeline/component-icon-7-Pending.png View File


react-ui/public/assets/images/component-icon-7-Running.png → react-ui/public/assets/images/pipeline/component-icon-7-Running.png View File


react-ui/public/assets/images/component-icon-7-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-7-Skipped.png View File


react-ui/public/assets/images/component-icon-7-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-7-Succeeded.png View File


react-ui/public/assets/images/component-icon-7.png → react-ui/public/assets/images/pipeline/component-icon-7.png View File


react-ui/public/assets/images/component-icon-8-Failed.png → react-ui/public/assets/images/pipeline/component-icon-8-Failed.png View File


react-ui/public/assets/images/component-icon-8-Omitted.png → react-ui/public/assets/images/pipeline/component-icon-8-Omitted.png View File


react-ui/public/assets/images/component-icon-8-Pending.png → react-ui/public/assets/images/pipeline/component-icon-8-Pending.png View File


react-ui/public/assets/images/component-icon-8-Running.png → react-ui/public/assets/images/pipeline/component-icon-8-Running.png View File


react-ui/public/assets/images/component-icon-8-Skipped.png → react-ui/public/assets/images/pipeline/component-icon-8-Skipped.png View File


react-ui/public/assets/images/component-icon-8-Succeeded.png → react-ui/public/assets/images/pipeline/component-icon-8-Succeeded.png View File


react-ui/public/assets/images/component-icon-8.png → react-ui/public/assets/images/pipeline/component-icon-8.png View File


BIN
react-ui/public/assets/images/pytorch推理.png View File

Before After
Width: 72  |  Height: 72  |  Size: 2.3 kB

BIN
react-ui/public/assets/images/pytorch训练.png View File

Before After
Width: 72  |  Height: 72  |  Size: 4.8 kB

BIN
react-ui/public/assets/images/sjj-icon-1.png View File

Before After
Width: 44  |  Height: 44  |  Size: 1.1 kB

BIN
react-ui/public/assets/images/tensorflow模型转换.png View File

Before After
Width: 72  |  Height: 72  |  Size: 4.0 kB

BIN
react-ui/public/assets/images/发送通知.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.2 kB

BIN
react-ui/src/assets/img/model-deployment.zip View File


+ 4
- 1
react-ui/src/pages/Pipeline/components/GlobalParamsDrawer/index.tsx View File

@@ -19,7 +19,7 @@ const GlobalParamsDrawer = forwardRef(
const [form] = Form.useForm();

useImperativeHandle(ref, () => ({
getFieldsValue: async () => {
validateFields: async () => {
const [values, error] = await to(form.validateFields());
if (!error && values) {
return values;
@@ -27,6 +27,9 @@ const GlobalParamsDrawer = forwardRef(
return Promise.reject(error);
}
},
getFieldsValue: () => {
return form.getFieldsValue();
},
}));

// 处理参数类型变化


+ 6
- 0
react-ui/src/pages/Pipeline/components/PropsLabel/index.less View File

@@ -0,0 +1,6 @@
.props-label {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}

+ 44
- 0
react-ui/src/pages/Pipeline/components/PropsLabel/index.tsx View File

@@ -0,0 +1,44 @@
import { Button, Dropdown, type MenuProps } from 'antd';
import { useEffect } from 'react';
import styles from './index.less';

type PropsLabelProps = {
title: string;
menuItems: MenuProps['items'];
onClick?: (key: string) => void;
};

function PropsLabel({ title, menuItems, onClick }: PropsLabelProps) {
useEffect(() => {}, []);

const handleItemClick: MenuProps['onClick'] = (e) => {
const keyPath = e.keyPath.reverse();
if (keyPath[0] === 'global') {
onClick?.(`\${${e.key}}`);
} else {
onClick?.(`{{${keyPath.join('.')}}}`);
}
};

return (
<div className={styles['props-label']}>
<span>{title}</span>
<Dropdown
menu={{
items: menuItems,
onClick: handleItemClick,
triggerSubMenuAction: 'click',
}}
trigger={['click']}
placement="topRight"
arrow
>
<Button size="small" type="link">
参数
</Button>
</Dropdown>
</div>
);
}

export default PropsLabel;

+ 11
- 0
react-ui/src/pages/Pipeline/editPipeline/editPipeline.less View File

@@ -3,6 +3,17 @@
width: 100%;
height: 100%;
}
.editPipelineProps {
:global {
label {
width: 100%;

&::after {
display: none;
}
}
}
}
.editPipelinePropsContent {
display: flex;
align-items: center;


+ 31
- 22
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -1,27 +1,26 @@
import KFIcon from '@/components/KFIcon';
import { useVisible } from '@/hooks';
import { useStateRef, useVisible } from '@/hooks';
import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js';
import { to } from '@/utils/promise';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import G6 from '@antv/g6';
import { Button, message } from 'antd';
import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { s8 } from '../../../utils';
import GlobalParamsDrawer from '../components/GlobalParamsDrawer';
import Styles from './editPipeline.less';
import ModelMenus from './modelMenus';
import Props from './props';
import { findAllParentNodes, findFirstDuplicate } from './utils';

let graph = null;

const EditPipeline = () => {
const propsRef = useRef();
const navgite = useNavigate();
// const [contextMenu,setContextMenu]=useState({})
let contextMenu = {};
const locationParams = useParams(); //新版本获取路由参数接口
let sourceAnchorIdx, targetAnchorIdx;
const pipelineContainer = useEmotionCss(() => {
return {
display: 'flex',
@@ -59,8 +58,11 @@ const EditPipeline = () => {
});
const graphRef = useRef();
const paramsDrawerRef = useRef();
const propsRef = useRef();
const [paramsDrawerOpen, openParamsDrawer, closeParamsDrawer] = useVisible(false);
const [globalParam, setGlobalParam] = useState([]);
const [globalParam, setGlobalParam, globalParamRef] = useStateRef([]);

let sourceAnchorIdx, targetAnchorIdx;

const onDragEnd = (val) => {
console.log(val, 'eee');
@@ -93,17 +95,24 @@ const EditPipeline = () => {
}
};
const savePipeline = async (val) => {
const [res, error] = await to(paramsDrawerRef.current.getFieldsValue());
const [res, error] = await to(paramsDrawerRef.current.validateFields());
if (error) {
message.error('全局参数配置有误');
openParamsDrawer();
return;
}

const duplicateName = findFirstDuplicate(res.global_param || []);
if (duplicateName) {
message.error('全局参数配置有重复的参数名称:' + duplicateName);
openParamsDrawer();
return;
}

const [propsRes, propsError] = await to(propsRef.current.getFieldsValue());
console.log(await to(propsRef.current.getFieldsValue()));
if (propsError) {
message.error('基本信息必填项需配置');
// handlerClick();
return;
}
propsRef.current.propClose();
@@ -128,12 +137,19 @@ const EditPipeline = () => {
};
const handlerClick = (e) => {
e.stopPropagation();
// console.log(propsRef, graph);
propsRef.current.showDrawer(e);
if (e.target.get('name') !== 'anchor-point' && e.item) {
graph.setItemState(e.item, 'nodeClicked', true);
const parentNodes = findAllParentNodes(graph, e.item);
// 如果没有打开过全局参数抽屉,获取不到全局参数
const globalParams =
paramsDrawerRef.current.getFieldsValue().global_param || globalParamRef.current;
propsRef.current.showDrawer(e, globalParams, parentNodes);
}
};
const getGraphData = (data) => {
console.log('graph', graph);
if (graph) {
console.log(graph);
console.log(data);
graph.data(data);
graph.render();
} else {
@@ -275,14 +291,13 @@ const EditPipeline = () => {
if (graph && ret.data && ret.data.dag) {
getGraphData(JSON.parse(ret.data.dag));
}
// graph&&graph.data(JSON.parse(ret.dag))
// graph.render()
});
};
const handlerContextMenu = (e) => {
e.stopPropagation();
// this.menuType = e.item._cfg.type;
};
// 上下文菜单
const initMenu = () => {
// const selectedNodes = this.selectedNodes;
contextMenu = new G6.Menu({
@@ -330,8 +345,8 @@ const EditPipeline = () => {
initGraph();
};
useEffect(() => {
getFirstWorkflow(locationParams.id);
initMenu();
getFirstWorkflow(locationParams.id);

return () => {
graph.off('node:mouseenter', (e) => {
@@ -449,7 +464,7 @@ const EditPipeline = () => {
},
'rect',
);
console.log(graphRef, 'graphRef');
graph = new G6.Graph({
container: graphRef.current,
grid: true,
@@ -600,13 +615,7 @@ const EditPipeline = () => {
// handlerClick(e);
// }
// });
graph.on('node:click', (e) => {
console.log(e.target.get('name'));
if (e.target.get('name') !== 'anchor-point' && e.item) {
graph.setItemState(e.item, 'nodeClicked', true);
handlerClick(e);
}
});
graph.on('node:click', handlerClick);
graph.on('aftercreateedge', (e) => {
// update the sourceAnchor and targetAnchor for the newly added edge
graph.updateItem(e.edge, {


+ 2
- 19
react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx View File

@@ -2,23 +2,6 @@ import { getComponentAll } from '@/services/pipeline/index.js';
import { Collapse } from 'antd';
import { useEffect, useState } from 'react';
import Styles from './modelMenus.less';
const items = [
{
key: '1',
label: 'This is panel header 1',
children: [1, 2, 3, 4, 5],
},
{
key: '2',
label: 'This is panel header 2',
children: [1, 2, 3, 4, 5],
},
{
key: '3',
label: 'This is panel header 3',
children: [1, 2, 3, 4, 5],
},
];
const ModelMenus = ({ onParDragEnd }) => {
const [modelMenusList, setModelMenusList] = useState([]);
useEffect(() => {
@@ -36,7 +19,7 @@ const ModelMenus = ({ onParDragEnd }) => {
x: e.clientX,
y: e.clientY,
label: data.component_label,
img: `/assets/images/${data.icon_path}.png`,
img: `/assets/images/pipeline/${data.icon_path}.png`,
});
};
const { Panel } = Collapse;
@@ -64,7 +47,7 @@ const ModelMenus = ({ onParDragEnd }) => {
>
<img
style={{ height: '16px', marginRight: '15px' }}
src={`/assets/images/${ele.icon_path}.png`}
src={`/assets/images/pipeline/${ele.icon_path}.png`}
alt=""
/>
{ele.component_label}


+ 206
- 131
react-ui/src/pages/Pipeline/editPipeline/props.jsx View File

@@ -5,22 +5,25 @@ import { to } from '@/utils/promise';
import { Button, Drawer, Form, Input, Select } from 'antd';
import { pick } from 'lodash';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import PropsLabel from '../components/PropsLabel';
import ResourceSelectorModal, { ResourceSelectorType } from '../components/ResourceSelectorModal';
import Styles from './editPipeline.less';
import { createMenuItems } from './utils';
const { TextArea } = Input;

const Props = forwardRef(({ onParentChange }, ref) => {
const [form] = Form.useForm();

const [stagingItem, setStagingItem] = useState({});
const [open, setOpen] = useState(false);
const [selectedModel, setSelectedModel] = useState(undefined);
const [selectedDataset, setSelectedDataset] = useState(undefined);
const [resourceStandardList, setResourceStandardList] = useState([]);
const [selectedModel, setSelectedModel] = useState(undefined); // 选择的模型,为了再次打开时恢复原来的选择
const [selectedDataset, setSelectedDataset] = useState(undefined); // 选择的数据集,为了再次打开时恢复原来的选择
const [resourceStandardList, setResourceStandardList] = useState([]); // 资源规模列表
const [items, setItems] = useState([]);
useEffect(() => {
getComputingResource();
}, []);

// 获取资源规格列表数据
const getComputingResource = async () => {
const params = {
page: 0,
@@ -35,49 +38,22 @@ const Props = forwardRef(({ onParentChange }, ref) => {

const afterOpenChange = () => {
if (!open) {
console.log(stagingItem, form.getFieldsValue());
// 禁止校验 guard-for-in
/* eslint-disable */
for (let i in form.getFieldsValue()) {
for (let j in stagingItem.in_parameters) {
if (i == j) {
console.log(j, i);
stagingItem.in_parameters[j].value = form.getFieldsValue()[i];
}
}
for (let p in stagingItem.out_parameters) {
if (i == p) {
stagingItem.out_parameters[p].value = form.getFieldsValue()[i];
}
}
for (let k in stagingItem.control_strategy) {
if (i == k) {
stagingItem.control_strategy[k].value = form.getFieldsValue()[i];
}
}
}
/* eslint-enable */
// setStagingItem({...stagingItem,})
console.log(stagingItem.control_strategy);
// console.log('zzzz', stagingItem, form.getFieldsValue());
const control_strategy = form.getFieldValue('control_strategy');
const in_parameters = form.getFieldValue('in_parameters');
const out_parameters = form.getFieldValue('out_parameters');
onParentChange({
...stagingItem,
control_strategy: JSON.stringify(stagingItem.control_strategy),
in_parameters: JSON.stringify(stagingItem.in_parameters),
out_parameters: JSON.stringify(stagingItem.out_parameters),
...form.getFieldsValue(),
control_strategy: JSON.stringify(control_strategy),
in_parameters: JSON.stringify(in_parameters),
out_parameters: JSON.stringify(out_parameters),
});
// onParentChange({...stagingItem,...form.getFieldsValue()})
}
};
const onClose = () => {
setOpen(false);
};
const onFinish = (values) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useImperativeHandle(ref, () => ({
getFieldsValue: async () => {
const [propsRes, propsError] = await to(form.validateFields());
@@ -88,30 +64,27 @@ const Props = forwardRef(({ onParentChange }, ref) => {
return Promise.reject(propsError);
}
},
showDrawer(e) {
showDrawer(e, params, parentNodes) {
if (e.item && e.item.getModel()) {
// console.log(e.item.getModel().in_parameters);
form.resetFields();
form.setFieldsValue({
...e.item.getModel(),
in_parameters: JSON.parse(e.item.getModel().in_parameters),
out_parameters: JSON.parse(e.item.getModel().out_parameters),
control_strategy: JSON.parse(e.item.getModel().control_strategy),
});
const model = e.item.getModel();
const nodeData = {
...model,
in_parameters: JSON.parse(model.in_parameters),
out_parameters: JSON.parse(model.out_parameters),
control_strategy: JSON.parse(model.control_strategy),
};
setStagingItem({
...e.item.getModel(),
in_parameters: JSON.parse(e.item.getModel().in_parameters),
out_parameters: JSON.parse(e.item.getModel().out_parameters),
control_strategy: JSON.parse(e.item.getModel().control_strategy),
...nodeData,
});
form.setFieldsValue({
...nodeData,
});
// form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setTimeout(() => {
// console.log(stagingItem);
// }, (500));
setSelectedModel(undefined);
setSelectedDataset(undefined);
setOpen(true);

setItems(createMenuItems(params, parentNodes));
}
},
propClose: async () => {
@@ -119,16 +92,12 @@ const Props = forwardRef(({ onParentChange }, ref) => {
const [openRes, propsError] = await to(setOpen(false));
console.log(setOpen(false));
},
// propClose() {

// setOpen(false);
// },
}));

// 选择数据集、模型
const selectResource = (name, item) => {
let type;
let resource = undefined;
let resource;
switch (item.item_type) {
case 'dataset':
type = ResourceSelectorType.Dataset;
@@ -154,7 +123,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
} else {
const jsonObj = pick(res, ['id', 'version', 'path']);
const value = JSON.stringify(jsonObj);
form.setFieldValue(name, value);
form.setFieldValue(name, { ...item, value });
}

if (type === ResourceSelectorType.Dataset) {
@@ -187,16 +156,26 @@ const Props = forwardRef(({ onParentChange }, ref) => {
}
};

// 筛选资源规格
const filterResourceStandard = (input, { computing_resource = '' }) => {
return computing_resource.toLocaleLowerCase().includes(input.toLocaleLowerCase());
};

// 控制策略
const controlStrategy = stagingItem.control_strategy;
const controlStrategyList = Object.entries(stagingItem.control_strategy ?? {}).map(
([key, value]) => ({ key, value }),
);

// 输入参数
const inParameters = stagingItem.in_parameters;
const inParametersList = Object.entries(stagingItem.in_parameters ?? {}).map(([key, value]) => ({
key,
value,
}));

// 输出参数
const outParameters = stagingItem.out_parameters;
const outParametersList = Object.entries(stagingItem.out_parameters ?? {}).map(
([key, value]) => ({ key, value }),
);

return (
<>
@@ -209,15 +188,15 @@ const Props = forwardRef(({ onParentChange }, ref) => {
onClose={onClose}
afterOpenChange={afterOpenChange}
open={open}
width={420}
width={520}
className={Styles.editPipelineProps}
>
<Form
name="form"
form={form}
// layout="vertical"
layout="vertical"
labelCol={{
span: 16,
span: 24,
}}
wrapperCol={{
span: 24,
@@ -225,11 +204,6 @@ const Props = forwardRef(({ onParentChange }, ref) => {
style={{
maxWidth: 600,
}}
initialValues={{
remember: true,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<div className={Styles.editPipelinePropsContent}>
@@ -250,7 +224,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
},
]}
>
<Input />
<Input placeholder="请输入任务名称" allowClear />
</Form.Item>
<Form.Item
label="任务ID"
@@ -275,7 +249,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
<Form.Item label="镜像" required>
<div className={Styles['ref-row']}>
<Form.Item name="image" noStyle rules={[{ required: true, message: '请输入镜像' }]}>
<Input placeholder="请输入镜像" allowClear />
<Input placeholder="请输入或选择镜像" allowClear />
</Form.Item>
<Form.Item noStyle>
<Button
@@ -289,12 +263,33 @@ const Props = forwardRef(({ onParentChange }, ref) => {
</Form.Item>
</div>
</Form.Item>
<Form.Item label="工作目录" name="working_directory">
<Input />
<Form.Item
name="working_directory"
label={
<PropsLabel
menuItems={items}
title="工作目录"
onClick={(value) => {
form.setFieldValue('working_directory', value);
}}
/>
}
>
<Input placeholder="请输入工作目录" allowClear />
</Form.Item>

<Form.Item label="启动命令" name="command">
<TextArea />
<Form.Item
name="command"
label={
<PropsLabel
menuItems={items}
title="工作目录"
onClick={(value) => {
form.setFieldValue('command', value);
}}
/>
}
>
<TextArea placeholder="请输入启动命令" allowClear />
</Form.Item>
<Form.Item
label="资源规格"
@@ -317,19 +312,63 @@ const Props = forwardRef(({ onParentChange }, ref) => {
}}
/>
</Form.Item>
<Form.Item label="挂载路径" name="mount_path">
<Input />
<Form.Item
name="mount_path"
label={
<PropsLabel
menuItems={items}
title="挂载路径"
onClick={(value) => {
form.setFieldValue('mount_path', value);
}}
/>
}
>
<Input placeholder="请输入挂载路径" allowClear />
</Form.Item>
<Form.Item label="环境变量" name="env_variables">
<TextArea />
<Form.Item
name="env_variables"
label={
<PropsLabel
menuItems={items}
title="环境变量"
onClick={(value) => {
form.setFieldValue('env_variables', value);
}}
/>
}
>
<TextArea placeholder="请输入环境变量" allowClear />
</Form.Item>
{controlStrategy && Object.keys(controlStrategy).length > 0
? Object.keys(controlStrategy).map((item) => (
<Form.Item key={item} label={controlStrategy[item].label} name={item}>
<Input />
</Form.Item>
))
: ''}
{controlStrategyList.map((item) => (
<Form.Item
key={item.key}
name={['control_strategy', item.key]}
label={
<PropsLabel
menuItems={items}
title={item.value.label}
onClick={(value) => {
form.setFieldValue(['control_strategy', item.key], {
...item.value,
value,
});
}}
/>
}
getValueProps={(e) => {
return { value: e.value };
}}
getValueFromEvent={(e) => {
return {
...item.value,
value: e.target.value,
};
}}
>
<Input placeholder={item.value.label} allowClear />
</Form.Item>
))}
<div className={Styles.editPipelinePropsContent}>
<img
style={{ width: '15px', marginRight: '10px' }}
@@ -338,37 +377,55 @@ const Props = forwardRef(({ onParentChange }, ref) => {
/>
输入参数
</div>
{inParameters && Object.keys(inParameters).length > 0
? Object.keys(inParameters).map((item) => (
{inParametersList.map((item) => (
<Form.Item
key={item.key}
label={
<PropsLabel
menuItems={items}
title={item.value.label + '(' + item.key + ')'}
onClick={(value) => {
form.setFieldValue(['in_parameters', item.key], {
...item.value,
value,
});
}}
/>
}
required={item.value.require ? true : false}
>
<div className={Styles['ref-row']}>
<Form.Item
key={item}
label={inParameters[item].label + '(' + item + ')'}
required={inParameters[item].require ? true : false}
name={['in_parameters', item.key]}
noStyle
rules={[{ required: item.value.require ? true : false }]}
getValueProps={(e) => {
return { value: e.value };
}}
getValueFromEvent={(e) => {
return {
...item.value,
value: e.target.value,
};
}}
>
<div className={Styles['ref-row']}>
<Form.Item
name={item}
noStyle
rules={[{ required: inParameters[item].require ? true : false }]}
>
<Input />
</Form.Item>
{inParameters[item].type === 'ref' && (
<Form.Item noStyle>
<Button
type="link"
icon={getSelectBtnIcon(inParameters[item])}
onClick={() => selectResource(item, inParameters[item])}
className={Styles['select-button']}
>
{inParameters[item].label}
</Button>
</Form.Item>
)}
</div>
<Input placeholder={item.value.label} allowClear />
</Form.Item>
))
: ''}
{item.value.type === 'ref' && (
<Form.Item noStyle>
<Button
type="link"
icon={getSelectBtnIcon(item.value)}
onClick={() => selectResource(['in_parameters', item.key], item.value)}
className={Styles['select-button']}
>
{item.value.label}
</Button>
</Form.Item>
)}
</div>
</Form.Item>
))}
<div className={Styles.editPipelinePropsContent}>
<img
style={{ width: '15px', marginRight: '10px' }}
@@ -377,18 +434,36 @@ const Props = forwardRef(({ onParentChange }, ref) => {
/>
输出参数
</div>
{outParameters && Object.keys(outParameters).length > 0
? Object.keys(outParameters).map((item) => (
<Form.Item
key={item}
label={outParameters[item].label + '(' + item + ')'}
rules={[{ required: outParameters[item].require ? true : false }]}
name={item}
>
<Input />
</Form.Item>
))
: ''}
{outParametersList.map((item) => (
<Form.Item
key={item.key}
name={['out_parameters', item.key]}
label={
<PropsLabel
menuItems={items}
title={item.value.label + '(' + item.key + ')'}
onClick={(value) => {
form.setFieldValue(['out_parameters', item.key], {
...item.value,
value,
});
}}
/>
}
rules={[{ required: item.value.require ? true : false }]}
getValueProps={(e) => {
return { value: e.value };
}}
getValueFromEvent={(e) => {
return {
...item.value,
value: e.target.value,
};
}}
>
<Input placeholder={item.value.label} allowClear />
</Form.Item>
))}
</Form>
</Drawer>
</>


+ 79
- 0
react-ui/src/pages/Pipeline/editPipeline/utils.tsx View File

@@ -0,0 +1,79 @@
import { PipelineGlobalParam } from '@/types';
import { Graph, INode } from '@antv/g6';
import { type MenuProps } from 'antd';

// 找到节点所以的上游节点
export const findAllParentNodes = (graph: Graph, node: INode) => {
const parentNodes: INode[] = [];
let index = -1;
let targetNode = node;
while (targetNode) {
const neighbors: INode[] = graph.getNeighbors(targetNode, 'source');
for (const sourceNode of neighbors) {
// 避免重复,也避免循环
const idx = parentNodes.findIndex((item) => sourceNode.getID() === item.getID());
if (idx === -1 && sourceNode.getID() !== node.getID()) {
parentNodes.push(sourceNode);
}
}
targetNode = parentNodes[++index];
}

return parentNodes;
};

// 判断并找到全局参数第一个重复项,有重复项时,全局参数不允许保存
export function findFirstDuplicate(params: PipelineGlobalParam[]): string | null {
const seen = new Set();
for (const item of params) {
if (seen.has(item.param_name)) {
return item.param_name;
}
seen.add(item.param_name);
}
return null;
}

// 创建参数下拉菜单
export function createMenuItems(
params: PipelineGlobalParam[],
parentNodes: INode[],
): MenuProps['items'] {
const nodes: MenuProps['items'] = parentNodes.map((item) => {
const model = item.getModel();
const out_parameters = model.out_parameters as string | undefined | null;
const out_parametersObj = parseJsonText(out_parameters);
const outParametersList = Object.keys(out_parametersObj ?? {});
return {
key: model.id as string,
label: model.label as string,
children: outParametersList.map((key: string) => ({
key: key as string,
label: out_parametersObj[key].label,
})),
};
});

return [
{
key: 'global',
label: '全局参数',
children: params.map((item) => ({
key: item.param_name,
label: item.param_name,
})),
},
...nodes,
];
}

function parseJsonText(text?: string | null): any | null {
if (!text) {
return null;
}
try {
return JSON.parse(text);
} catch (error) {
return null;
}
}

+ 1
- 267
react-ui/src/pages/User/Login/index.tsx View File

@@ -222,12 +222,7 @@ const Login: React.FC = () => {
getCaptchaCode();
}
} catch (error) {
const defaultLoginFailureMessage = intl.formatMessage({
id: 'pages.login.failure',
defaultMessage: '登录失败,请重试!',
});
console.log(error);
message.error(defaultLoginFailureMessage);
getCaptchaCode();
}
};
const { code } = userLoginState;
@@ -502,267 +497,6 @@ const Login: React.FC = () => {
</div>
</div>
</div>
{/* <Helmet>
<title>
{intl.formatMessage({
id: 'menu.login',
defaultMessage: '登录页',
})}
- {Settings.title}
</title>
</Helmet>
<Lang />
<div
style={{
flex: '1',
padding: '32px 0',
}}
>
<LoginForm
contentStyle={{
minWidth: 280,
maxWidth: '75vw',
}}
logo={<img alt="logo" src="/logo.svg" />}
title="Ant Design"
subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
initialValues={{
autoLogin: true,
}}
actions={[
<FormattedMessage
key="loginWith"
id="pages.login.loginWith"
defaultMessage="其他登录方式"
/>,
<ActionIcons key="icons" />,
]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
<Tabs
activeKey={type}
onChange={setType}
centered
items={[
{
key: 'account',
label: intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: '账户密码登录',
}),
},
{
key: 'mobile',
label: intl.formatMessage({
id: 'pages.login.phoneLogin.tab',
defaultMessage: '手机号登录',
}),
},
]}
/>

{code !== 200 && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/admin123)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
initialValue="admin"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
initialValue="admin123"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: admin123',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
/>
<Row>
<Col flex={3}>
<ProFormText
style={{
float: 'right',
}}
name="code"
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="请输入验证啊"
/>
),
},
]}
/>
</Col>
<Col flex={2}>
<Image
src={captchaCode}
alt="验证码"
style={{
display: 'inline-block',
verticalAlign: 'top',
cursor: 'pointer',
paddingLeft: '10px',
width: '100px',
}}
preview={false}
onClick={() => getCaptchaCode()}
/>
</Col>
</Row>
</>
)}

{code !== 200 && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功!验证码为:1234');
}}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
</ProFormCheckbox>
<a
style={{
float: 'right',
}}
>
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
</a>
</div>
</LoginForm>
</div>
<Footer /> */}
</div>
);
};


+ 0
- 0
react-ui/src/utils/formRules.ts View File


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

@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-03-25 13:52:54
* @Description:
* @Description: 工具类
*/
export function s8() {
return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);


+ 6
- 0
react-ui/src/utils/menuRender.tsx View File

@@ -1,3 +1,9 @@
/*
* @Author: 赵伟
* @Date: 2024-05-11 15:40:58
* @Description: 自定义菜单项
*/

import KFIcon from '@/components/KFIcon';
import { MenuDataItem } from '@ant-design/pro-components';
import { Link } from '@umijs/max';


Loading…
Cancel
Save