Browse Source

Merge remote-tracking branch 'origin/dev' into dev

pull/83/head
西大锐 1 year ago
parent
commit
7beadd4132
13 changed files with 211 additions and 181 deletions
  1. +1
    -1
      react-ui/config/routes.ts
  2. +3
    -3
      react-ui/src/locales/zh-CN/pages.ts
  3. +3
    -3
      react-ui/src/locales/zh-TW/pages.ts
  4. +1
    -1
      react-ui/src/pages/Experiment/index.jsx
  5. +15
    -41
      react-ui/src/pages/Experiment/training/index.jsx
  6. +19
    -8
      react-ui/src/pages/Model/components/ModelEvolution/index.tsx
  7. +17
    -13
      react-ui/src/pages/Model/components/ModelEvolution/utils.tsx
  8. +9
    -5
      react-ui/src/pages/Model/components/NodeTooltips/index.tsx
  9. +99
    -73
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  10. +6
    -8
      react-ui/src/pages/Pipeline/index.jsx
  11. +2
    -2
      react-ui/src/pages/User/Login/index.tsx
  12. +32
    -19
      react-ui/src/requestConfig.ts
  13. +4
    -4
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java

+ 1
- 1
react-ui/config/routes.ts View File

@@ -77,7 +77,7 @@ export default [
},
{
name: '流水线详情',
path: ':id/:name',
path: ':id',
component: './Pipeline/editPipeline/index',
},
],


+ 3
- 3
react-ui/src/locales/zh-CN/pages.ts View File

@@ -1,12 +1,12 @@
export default {
'pages.layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范',
'pages.login.accountLogin.tab': '账户密码登录',
'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/admin123)',
'pages.login.accountLogin.errorMessage': '错误的用户名和密码',
'pages.login.failure': '登录失败,请重试!',
'pages.login.success': '登录成功!',
'pages.login.username.placeholder': '用户名: admin',
'pages.login.username.placeholder': '用户名',
'pages.login.username.required': '用户名是必填项!',
'pages.login.password.placeholder': '密码: admin123',
'pages.login.password.placeholder': '密码',
'pages.login.password.required': '密码是必填项!',
'pages.login.phoneLogin.tab': '手机号登录',
'pages.login.phoneLogin.errorMessage': '验证码错误',


+ 3
- 3
react-ui/src/locales/zh-TW/pages.ts View File

@@ -1,12 +1,12 @@
export default {
'pages.layouts.userLayout.title': 'Ant Design 是西湖區最具影響力的 Web 設計規範',
'pages.login.accountLogin.tab': '賬戶密碼登錄',
'pages.login.accountLogin.errorMessage': '錯誤的用戶名和密碼(admin/admin123)',
'pages.login.accountLogin.errorMessage': '錯誤的用戶名和密碼',
'pages.login.failure': '登錄失敗,請重試!',
'pages.login.success': '登錄成功!',
'pages.login.username.placeholder': '用戶名: admin',
'pages.login.username.placeholder': '用戶名',
'pages.login.username.required': '用戶名是必填項!',
'pages.login.password.placeholder': '密碼: admin123',
'pages.login.password.placeholder': '密碼',
'pages.login.password.required': '密碼是必填項!',
'pages.login.phoneLogin.tab': '手機號登錄',
'pages.login.phoneLogin.errorMessage': '驗證碼錯誤',


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

@@ -198,7 +198,7 @@ function Experiment() {
};
const routeToEdit = (e, record) => {
e.stopPropagation();
navgite({ pathname: `/pipeline/template/${record.workflow_id}/${record.workflow_name}` });
navgite({ pathname: `/pipeline/template/${record.workflow_id}` });
};
// 创建或者编辑实验接口请求
const handleAddExperiment = async (values) => {


+ 15
- 41
react-ui/src/pages/Experiment/training/index.jsx View File

@@ -23,24 +23,12 @@ function ExperimentText() {
const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false);

const graphRef = useRef();
// const onDragEnd = (val) => {
// console.log(val, 'eee');
// const _x = val.x;
// const _y = val.y;
// const point = graph.getPointByClient(_x, _y);
// let model = {};
// // 元模型
// model = {
// ...val,
// x: point.x,
// y: point.y,
// id: val.component_name + '-' + s8(),
// isCluster: false,
// };
// graph.addItem('node', model, true);
// };
const getGraphData = (data) => {
if (graph) {
// 修改历史数据有蓝色边框的问题
data.nodes.forEach((item) => {
item.style.stroke = '#fff';
});
graph.data(data);
graph.render();
} else {
@@ -92,9 +80,11 @@ function ExperimentText() {
getAnchorPoints(cfg) {
return (
cfg.anchorPoints || [
// 上下各3,左右各1
// 四个,上下左右
[0.5, 0],
[0.5, 1],
[0, 0.5],
[1, 0.5],
]
);
},
@@ -120,6 +110,7 @@ function ExperimentText() {
textAlign: 'left',
textBaseline: 'middle',
fill: '#000',
cursor: 'pointer',
},
name: 'text-shape',
draggable: true,
@@ -166,8 +157,12 @@ function ExperimentText() {
width: graphRef.current.clientWidth || 500,
height: graphRef.current.clientHeight || 760,
animate: false,
groupByTypes: false,
enabledStack: true,
groupByTypes: true,
enabledStack: false,
fitView: true,
minZoom: 0.5,
maxZoom: 5,
fitViewPadding: 300,
modes: {
default: [
// config the shouldBegin for drag-node to avoid node moving while dragging on the anchor-point circles
@@ -181,15 +176,6 @@ function ExperimentText() {
// config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles
'drag-canvas',
'zoom-canvas',
// 'brush-select',
'drag-combo',
],
altSelect: [
{
type: 'brush-select',
trigger: 'drag',
},
'drag-node',
],
},

@@ -217,7 +203,7 @@ function ExperimentText() {
},
defaultEdge: {
// type: 'quadratic',
type: 'cubic-vertical',
// type: 'cubic-vertical',

style: {
endArrow: {
@@ -232,15 +218,8 @@ function ExperimentText() {
stroke: '#a2a6b5',
radius: 1,
},
nodeStateStyle: {
hover: {
opacity: 1,
stroke: '#8fe8ff',
},
},
labelCfg: {
autoRotate: true,
// refY: 10,
style: {
fontSize: 10,
fill: '#FFF',
@@ -257,11 +236,6 @@ function ExperimentText() {
cursor: 'pointer',
},
},
// linkCenter: true,
fitView: true,
minZoom: 0.5,
maxZoom: 5,
fitViewPadding: 300,
});
graph.on('node:click', (e) => {
if (e.target.get('name') !== 'anchor-point' && e.item) {


+ 19
- 8
react-ui/src/pages/Model/components/ModelEvolution/index.tsx View File

@@ -12,7 +12,14 @@ import GraphLegend from '../GraphLegend';
import NodeTooltips from '../NodeTooltips';
import styles from './index.less';
import type { ModelDepsData, ProjectDependency, TrainDataset } from './utils';
import { NodeType, getGraphData, nodeHeight, nodeWidth, normalizeTreeData } from './utils';
import {
NodeType,
getGraphData,
nodeFontSize,
nodeHeight,
nodeWidth,
normalizeTreeData,
} from './utils';

type modeModelEvolutionProps = {
resourceId: number;
@@ -73,7 +80,7 @@ function ModelEvolution({
width: graphRef.current!.clientWidth,
height: graphRef.current!.clientHeight,
fitView: true,
fitViewPadding: [50, 100, 50, 100],
fitViewPadding: [100, 100, 100, 100],
minZoom: 0.5,
maxZoom: 5,
defaultNode: {
@@ -95,7 +102,7 @@ function ModelEvolution({
position: 'center',
style: {
fill: '#ffffff',
fontSize: 8,
fontSize: nodeFontSize,
textAlign: 'center',
cursor: 'pointer',
},
@@ -107,7 +114,7 @@ function ModelEvolution({
autoRotate: true,
},
style: {
stroke: '#a2c1ff',
stroke: '#DEE0E5',
lineWidth: 1,
},
},
@@ -163,28 +170,32 @@ function ModelEvolution({

graph.on('node:click', (e: G6GraphEvent) => {
const nodeItem = e.item;
const model = nodeItem.getModel();
const model = nodeItem.getModel() as ModelDepsData | ProjectDependency | TrainDataset;
const { model_type } = model;
const { origin } = location;
let url: string = '';
switch (model_type) {
case NodeType.children:
case NodeType.parent: {
const { current_model_id, version } = model as ModelDepsData;
const { current_model_id, version } = model;
url = `${origin}/dataset/model/${current_model_id}?tab=${ResourceInfoTabKeys.Evolution}&version=${version}`;
break;
}
case NodeType.project: {
const { url: projectUrl } = model as ProjectDependency;
const { url: projectUrl } = model;
url = projectUrl;
break;
}
case NodeType.trainDataset:
case NodeType.testDataset: {
const { dataset_id, dataset_version } = model as TrainDataset;
const { dataset_id, dataset_version } = model;
url = `${origin}/dataset/dataset/${dataset_id}?tab=${ResourceInfoTabKeys.Version}&version=${dataset_version}`;
break;
}
case NodeType.current: {
// TODO: 隐藏数据集和项目
break;
}
default:
break;
}


+ 17
- 13
react-ui/src/pages/Model/components/ModelEvolution/utils.tsx View File

@@ -6,8 +6,10 @@ import Hierarchy from '@antv/hierarchy';
export const nodeWidth = 110;
export const nodeHeight = 50;
export const vGap = nodeHeight + 20;
export const hGap = nodeHeight + 20;
export const hGap = nodeWidth;
export const ellipseWidth = nodeWidth;
export const labelPadding = 30;
export const nodeFontSize = 8;

// 数据集节点
const datasetNodes: NodeConfig[] = [];
@@ -38,14 +40,14 @@ export interface TrainDataset extends NodeConfig {
dataset_id: number;
dataset_name: string;
dataset_version: string;
model_type: NodeType;
model_type: NodeType.testDataset | NodeType.trainDataset;
}

export interface ProjectDependency extends NodeConfig {
url: string;
name: string;
branch: string;
model_type: NodeType;
model_type: NodeType.project;
}

export type ModalDetail = {
@@ -63,7 +65,7 @@ export interface ModelDepsAPIData {
current_model_id: number;
version: string;
exp_ins_id: number;
model_type: NodeType;
model_type: NodeType.children | NodeType.current | NodeType.parent;
current_model_name: string;
project_dependency: ProjectDependency;
test_dataset: TrainDataset[];
@@ -94,9 +96,13 @@ export function normalizeChildren(data: ModelDepsData[]) {
// 获取 label
export function getLabel(node: ModelDepsData | ModelDepsAPIData) {
return (
fittingString(`${node.model_version_dependcy_vo.name ?? ''}`, nodeWidth - 12, 8) +
fittingString(
`${node.model_version_dependcy_vo.name ?? ''}`,
nodeWidth - labelPadding,
nodeFontSize,
) +
'\n' +
fittingString(`${node.version}`, nodeWidth - 12, 8)
fittingString(`${node.version}`, nodeWidth - labelPadding, nodeFontSize)
);
}

@@ -231,12 +237,12 @@ const addDatasetDependency = (
node.type = 'ellipse';
node.size = [ellipseWidth, nodeHeight];
node.label =
fittingString(node.dataset_name, ellipseWidth - 12, 8) +
fittingString(node.dataset_name, ellipseWidth - labelPadding, nodeFontSize) +
'\n' +
fittingString(node.dataset_version, ellipseWidth - 12, 8);
fittingString(node.dataset_version, ellipseWidth - labelPadding, nodeFontSize);

const half = len / 2 - 0.5;
node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap / 2);
node.x = currentNode.x! - (half - index) * (ellipseWidth + 20);
node.y = currentNode.y! - nodeHeight - vGap;
nodes.push(node);
datasetNodes.push(node);
@@ -263,7 +269,7 @@ const addProjectDependency = (
node.id = `$P_${node.url}_${node.branch}`;
node.model_type = NodeType.project;
node.type = 'rect';
node.label = fittingString(node.name, nodeWidth - 12, 8);
node.label = fittingString(node.name, nodeWidth - labelPadding, nodeFontSize);
node.style = getStyle(NodeType.project);
node.style.radius = nodeHeight / 2;
node.x = currentNode.x;
@@ -311,15 +317,13 @@ function adjustDatasetPosition(node: NodeConfig) {
};
const overlapRect = isChildrenOverlapDataset(datasetNodes, nodeRect);
if (overlapRect) {
console.log(node);

const adjustRect = {
x: overlapRect.x - nodeWidth - hGap / 2,
y: overlapRect.y,
width: overlapRect.width,
height: overlapRect.height,
};
const lastNode = datasetNodes[datasetNodes.length - 1] as NodeConfig;
const lastNode = datasetNodes[datasetNodes.length - 1];
const distance = lastNode.x! - adjustRect.x;
datasetNodes.forEach((item) => {
item.x = item.x! - distance;


+ 9
- 5
react-ui/src/pages/Model/components/NodeTooltips/index.tsx View File

@@ -118,14 +118,18 @@ function ProjectInfo({ data }: { data: ProjectDependency }) {

function NodeTooltips({ data, x, y, onMouseEnter, onMouseLeave }: NodeTooltipsProps) {
if (!data) return null;
let Component;
let Component = null;
const { model_type } = data;
if (model_type === NodeType.testDataset || model_type === NodeType.trainDataset) {
Component = <DatasetInfo data={data as TrainDataset} />;
Component = <DatasetInfo data={data} />;
} else if (model_type === NodeType.project) {
Component = <ProjectInfo data={data as ProjectDependency} />;
} else {
Component = <ModelInfo data={data as ModelDepsData} />;
Component = <ProjectInfo data={data} />;
} else if (
model_type === NodeType.children ||
model_type === NodeType.parent ||
model_type === NodeType.current
) {
Component = <ModelInfo data={data} />;
}
return (
<div


+ 99
- 73
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -27,7 +27,8 @@ const EditPipeline = () => {
const [paramsDrawerOpen, openParamsDrawer, closeParamsDrawer] = useVisible(false);
const [globalParam, setGlobalParam, globalParamRef] = useStateRef([]);
const { message } = App.useApp();
let sourceAnchorIdx, targetAnchorIdx;
let sourceAnchorIdx, targetAnchorIdx, dropAnchorIdx;
let dragSourceNode;

useEffect(() => {
initMenu();
@@ -35,9 +36,8 @@ const EditPipeline = () => {
}, []);

const onDragEnd = (val) => {
const _x = val.x;
const _y = val.y;
const point = graph.getPointByClient(_x, _y);
const { x, y } = val;
const point = graph.getPointByClient(x, y);
// 元模型
const model = {
...val,
@@ -46,8 +46,8 @@ const EditPipeline = () => {
id: val.component_name + '-' + s8(),
isCluster: false,
};
console.log('model', model);
graph.addItem('node', model, true);
// console.log('model', model);
graph.addItem('node', model, false);
};
const formChange = (val) => {
if (graph) {
@@ -83,11 +83,11 @@ const EditPipeline = () => {
return;
}

const [propsRes, propsError] = await to(propsRef.current.getFieldsValue());
if (propsError) {
message.error('基本信息必填项需配置');
return;
}
// const [propsRes, propsError] = await to(propsRef.current.getFieldsValue());
// if (propsError) {
// message.error('基本信息必填项需配置');
// return;
// }
propsRef.current.propClose();
setTimeout(() => {
const data = graph.save();
@@ -110,6 +110,10 @@ const EditPipeline = () => {
};
const getGraphData = (data) => {
if (graph) {
// 修改历史数据有蓝色边框的问题
data.nodes.forEach((item) => {
item.style.stroke = '#fff';
});
graph.data(data);
graph.render();
} else {
@@ -118,7 +122,6 @@ const EditPipeline = () => {
}, 500);
}
};

const processParallelEdgesOnAnchorPoint = (
edges,
offsetDiff = 15,
@@ -230,6 +233,15 @@ const EditPipeline = () => {
}
return edges;
};
// 判断两个节点之间是否有边
const hasEdge = (source, target) => {
const neighbors = source.getNeighbors();
for (const node of neighbors) {
// 新建边的时候,获取的 neighbors 的数据有问题,不全是 INode 类型,可能没有 getID 方法
if (node.getID?.() === target.getID?.()) return true;
}
return false;
};
const cloneElement = (item) => {
console.log(item);
let data = graph.save();
@@ -254,15 +266,13 @@ const EditPipeline = () => {
}
});
};
const handlerContextMenu = (e) => {
e.stopPropagation();
// this.menuType = e.item._cfg.type;
};
// 上下文菜单
const initMenu = () => {
// const selectedNodes = this.selectedNodes;
contextMenu = new G6.Menu({
getContent(evt) {
const type = evt.item.getType();
const cloneDisplay = type === 'node' ? 'block' : 'none';
return `
<ul style="position: absolute;
width: 100px;
@@ -276,8 +286,7 @@ const EditPipeline = () => {
font-size: 14px;
color: #333333;
overflow-y: auto;">
<li style="padding: 10px 20px;cursor: pointer;" code="clone">复制</li>
<li style="padding: 10px 20px;cursor: pointer; display: ${cloneDisplay}" code="clone">复制</li>
<li style="padding: 10px 20px;cursor: pointer;" code="delete">删除</li>
</ul>`;
},
@@ -314,11 +323,11 @@ const EditPipeline = () => {
getAnchorPoints(cfg) {
return (
cfg.anchorPoints || [
// 四个
// 四个,上下左右
[0.5, 0],
[0.5, 1],
// [0, 0.5],
// [1, 0.5],
[0, 0.5],
[1, 0.5],
]
);
},
@@ -344,6 +353,7 @@ const EditPipeline = () => {
textAlign: 'left',
textBaseline: 'middle',
fill: '#000',
cursor: 'pointer',
},
name: 'text-shape',
draggable: true,
@@ -360,6 +370,7 @@ const EditPipeline = () => {
fill: '#fff',
stroke: '#a4a4a5',
cursor: 'crosshair',
lineWidth: 1,
},
name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point')
anchorPointIdx: i, // flag the idx of the anchor-point circle
@@ -380,10 +391,9 @@ const EditPipeline = () => {
// if (value || point.get('links') > 0) point.show();
// else point.hide();
// });

const group = item.getContainer();
const shape = group.get('children')[0];
const anchorPoints = group.findAll((ele) => ele.get('name') === 'anchor-point');
const anchorPoints = group.findAll((item) => item.get('name') === 'anchor-point');
if (name === 'hover') {
if (value) {
shape.attr('stroke', themes['primaryColor']);
@@ -396,6 +406,18 @@ const EditPipeline = () => {
point.hide();
});
}
} else if (name === 'drag') {
if (sourceAnchorIdx !== null && sourceAnchorIdx !== undefined) {
const anchorPoint = anchorPoints[sourceAnchorIdx];
anchorPoint.attr('stroke', value ? themes['primaryColor'] : '#a4a4a5');
anchorPoint.attr('lineWidth', value ? 2 : 1);
}
} else if (name === 'drop') {
if (dropAnchorIdx !== null && dropAnchorIdx !== undefined) {
const anchorPoint = anchorPoints[dropAnchorIdx];
anchorPoint.attr('stroke', value ? themes['primaryColor'] : '#a4a4a5');
anchorPoint.attr('lineWidth', value ? 2 : 1);
}
}
},
},
@@ -407,10 +429,14 @@ const EditPipeline = () => {
width: graphRef.current.clientWidth || 500,
height: graphRef.current.clientHeight || '100%',
animate: false,
groupByTypes: false,
groupByTypes: true,
fitView: true,
plugins: [contextMenu],
enabledStack: true,
enabledStack: false,
fitView: true,
minZoom: 0.5,
maxZoom: 5,
fitViewPadding: 300,
modes: {
default: [
// config the shouldBegin for drag-node to avoid node moving while dragging on the anchor-point circles
@@ -420,10 +446,6 @@ const EditPipeline = () => {
if (e.target.get('name') === 'anchor-point') return false;
return true;
},
// shouldEnd: e => {
// console.log(e);
// return false;
// },
},
// config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles
{
@@ -434,11 +456,17 @@ const EditPipeline = () => {
if (e.target && e.target.get('name') !== 'anchor-point') return false;
sourceAnchorIdx = e.target.get('anchorPointIdx');
e.target.set('links', e.target.get('links') + 1); // cache the number of edge connected to this anchor-point circle
dragSourceNode = e.item;
return true;
},
shouldEnd: (e) => {
// avoid ending at other shapes on the node
if (e.target && e.target.get('name') !== 'anchor-point') return false;
if (!dragSourceNode || !e.item) return false;
// 不允许连接自己
if (dragSourceNode.getID() === e.item.getID()) return false;
// 两个节点不允许多条边
if (hasEdge(dragSourceNode, e.item)) return false;
if (e.target) {
targetAnchorIdx = e.target.get('anchorPointIdx');
e.target.set('links', e.target.get('links') + 1); // cache the number of edge connected to this anchor-point circle
@@ -450,22 +478,11 @@ const EditPipeline = () => {
},
'drag-canvas',
'zoom-canvas',
// 'brush-select',
'drag-combo',
],
altSelect: [
{
type: 'brush-select',
trigger: 'drag',
},
'drag-node',
],
},

defaultNode: {
type: 'rect-node',
size: [110, 36],

labelCfg: {
style: {
fill: 'transparent',
@@ -488,8 +505,7 @@ const EditPipeline = () => {
},
},
defaultEdge: {
//type: 'cubic-vertical',

// type: 'cubic-vertical',
style: {
endArrow: {
// 设置终点箭头
@@ -503,15 +519,8 @@ const EditPipeline = () => {
stroke: '#CDD0DC',
radius: 1,
},
nodeStateStyle: {
hover: {
opacity: 1,
stroke: '#8fe8ff',
},
},
labelCfg: {
autoRotate: true,
// refY: 10,
style: {
fontSize: 10,
fill: '#FFF',
@@ -528,20 +537,16 @@ const EditPipeline = () => {
cursor: 'pointer',
},
},
// linkCenter: true,
fitView: true,
minZoom: 0.5,
maxZoom: 5,
fitViewPadding: 300,
});
graph.on('node:click', (e) => {
e.stopPropagation();
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);
}
});
@@ -550,23 +555,26 @@ const EditPipeline = () => {
graph.updateItem(e.edge, {
sourceAnchor: sourceAnchorIdx,
targetAnchor: targetAnchorIdx,
type:
targetAnchorIdx === 0 || targetAnchorIdx === 1 ? 'cubic-vertical' : 'cubic-horizontal',
});

// update the curveOffset for parallel edges
const edges = graph.save().edges;
processParallelEdgesOnAnchorPoint(edges);
graph.getEdges().forEach((edge, i) => {
graph.updateItem(edge, {
curveOffset: edges[i].curveOffset,
curvePosition: edges[i].curvePosition,
});
});
// const edges = graph.save().edges;
// processParallelEdgesOnAnchorPoint(edges);
// graph.getEdges().forEach((edge, i) => {
// graph.updateItem(edge, {
// curveOffset: edges[i].curveOffset,
// curvePosition: edges[i].curvePosition,
// });
// });
});
// 删除边时,修改 anchor-point 的 links 值
graph.on('afterremoveitem', (e) => {
if (e.item && e.item.source && e.item.target) {
const sourceNode = graph.findById(e.item.source);
const targetNode = graph.findById(e.item.target);
const { sourceAnchor, targetAnchor } = e.item;
const { source, target, sourceAnchor, targetAnchor } = e.item;
const sourceNode = graph.findById(source);
const targetNode = graph.findById(target);
if (sourceNode && !isNaN(sourceAnchor)) {
const sourceAnchorShape = sourceNode
.getContainer()
@@ -587,9 +595,10 @@ const EditPipeline = () => {
}
}
});
// after clicking on the first node, the edge is created, update the sourceAnchor
// after drag on the first node, the edge is created, update the sourceAnchor
graph.on('afteradditem', (e) => {
if (e.item && e.item.getType() === 'edge') {
const sourceAnchor = e.item.getModel().sourceAnchor;
if (e.item && e.item.getType() === 'edge' && !sourceAnchor) {
graph.updateItem(e.item, {
sourceAnchor: sourceAnchorIdx,
});
@@ -601,17 +610,34 @@ const EditPipeline = () => {
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item, 'hover', false);
});
graph.on('node:dragenter', (e) => {
graph.on('node:dragstart', (e) => {
graph.setItemState(e.item, 'hover', true);
graph.setItemState(e.item, 'drag', true);
});
graph.on('node:dragleave', (e) => {
graph.on('node:dragend', (e) => {
graph.setItemState(e.item, 'hover', false);
graph.setItemState(e.item, 'drag', false);
});
graph.on('node:dragstart', (e) => {
graph.on('node:dragenter', (e) => {
if (e.item?.getID() === dragSourceNode?.getID()) return;
graph.setItemState(e.item, 'hover', true);
if (e.target.get('name') === 'anchor-point') {
dropAnchorIdx = e.target.get('anchorPointIdx');
graph.setItemState(e.item, 'drop', true);
} else {
graph.setItemState(e.item, 'drop', false);
}
});
graph.on('node:drag', (e) => {
graph.setItemState(e.item, 'hover', true);
graph.on('node:dragleave', (e) => {
if (e.item?.getID() === dragSourceNode?.getID()) return;
graph.setItemState(e.item, 'hover', false);
graph.setItemState(e.item, 'drop', false);
dropAnchorIdx = undefined;
});
graph.on('node:drop', (e) => {
graph.setItemState(e.item, 'hover', false);
graph.setItemState(e.item, 'drop', false);
dropAnchorIdx = undefined;
});
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;


+ 6
- 8
react-ui/src/pages/Pipeline/index.jsx View File

@@ -43,32 +43,30 @@ const Pipeline = () => {
};
const routeToEdit = (e, record) => {
e.stopPropagation();
navgite({ pathname: `/pipeline/template/${record.id}/${record.name}` });
navgite({ pathname: `/pipeline/template/${record.id}` });
};
const showModal = () => {
form.resetFields();
setFormId(null);
setDialogTitle('新建流水线');
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onFinish = (values) => {
if (formId) {
editWorkflow({ ...values, id: formId }).then((ret) => {
setIsModalOpen(false);
message.success('编辑成功');
getList();
setIsModalOpen(false);
});
} else {
addWorkflow(values).then((ret) => {
console.log(ret);
setIsModalOpen(false);
message.success('新建成功');
if (ret.code === 200) {
navgite({ pathname: `/pipeline/template/${ret.data.id}/${ret.data.name}` });
navgite({ pathname: `/pipeline/template/${ret.data.id}` });
}
});
}


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

@@ -344,7 +344,7 @@ const Login: React.FC = () => {
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: admin123',
defaultMessage: '请输入密码',
})}
rules={[
{
@@ -374,7 +374,7 @@ const Login: React.FC = () => {
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
id="pages.login.captcha.placeholder"
defaultMessage="请输入验证啊"
/>
),


+ 32
- 19
react-ui/src/requestConfig.ts View File

@@ -9,12 +9,19 @@ import { clearSessionToken, getAccessToken } from './access';
import { setRemoteMenu } from './services/session';
import { gotoLoginPage } from './utils/ui';

// [antd: Notification] You are calling notice in render which will break in React 18 concurrent mode. Please trigger in effect instead.
const popupError = (error: string) => {
// 直接调用 message.error 有时候不弹出来
setTimeout(() => {
message.error(error);
}, 100);
};

/**
* Umi Max 网络请求配置
* @doc https://umijs.org/docs/max/request#配置
*/
export const requestConfig: RequestConfig = {
errorConfig: {},
requestInterceptors: [
(url: string, options: AxiosRequestConfig) => {
const headers = options.headers ?? {};
@@ -30,26 +37,32 @@ export const requestConfig: RequestConfig = {
},
],
responseInterceptors: [
(response: AxiosResponse) => {
const { status, data } = response || {};
if (status >= 200 && status < 300) {
if (data && (data instanceof Blob || data.code === 200)) {
return response;
} else if (data && data.code === 401) {
clearSessionToken();
setRemoteMenu(null);
gotoLoginPage(false);
message.error('请重新登录');
return Promise.reject(response);
[
(response: AxiosResponse) => {
const { status, data } = response || {};
console.log(message, data);
if (status >= 200 && status < 300) {
if (data && (data instanceof Blob || data.code === 200)) {
return response;
} else if (data && data.code === 401) {
clearSessionToken();
setRemoteMenu(null);
gotoLoginPage(false);
popupError('请重新登录');
return Promise.reject(response);
} else {
popupError(data?.msg ?? '请求失败');
return Promise.reject(response);
}
} else {
console.log(message, data);
message.error(data?.msg ?? '请求失败');
popupError('请求失败');
return Promise.reject(response);
}
} else {
message.error('请求失败');
return Promise.reject(response);
}
},
},
(error: Error) => {
popupError(error.message ?? '请求失败');
return Promise.reject(error);
},
],
],
};

+ 4
- 4
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java View File

@@ -34,7 +34,7 @@ public class ExperimentInstanceStatusTask {
private ModelDependencyDao modelDependencyDao;
private List<Integer> experimentIds = new ArrayList<>();

@Scheduled(cron = "0/30 * * * * ?") // 每30S执行一次
@Scheduled(cron = "0/14 * * * * ?") // 每30S执行一次
public void executeExperimentInsStatus() throws IOException {
// 首先查到所有非终止态的实验实例
List<ExperimentIns> experimentInsList = experimentInsService.queryByExperimentIsNotTerminated();
@@ -49,7 +49,7 @@ public class ExperimentInstanceStatusTask {
}catch (Exception e){
experimentIns.setStatus("Failed");
}
if (!StringUtils.equals(oldStatus,experimentIns.getStatus())){
// if (!StringUtils.equals(oldStatus,experimentIns.getStatus())){
experimentIns.setUpdateTime(new Date());
// 线程安全的添加操作
synchronized (experimentIds) {
@@ -57,7 +57,7 @@ public class ExperimentInstanceStatusTask {
}
updateList.add(experimentIns);

}
// }
// experimentInsDao.update(experimentIns);
}

@@ -105,7 +105,7 @@ public class ExperimentInstanceStatusTask {
}

}
@Scheduled(cron = "0/30 * * * * ?") // / 每30S执行一次
@Scheduled(cron = "0/17 * * * * ?") // / 每30S执行一次
public void executeExperimentStatus() throws IOException {
if (experimentIds.size()==0){
return;


Loading…
Cancel
Save