mirror of https://github.com/kubevela/velaux.git
Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
|
51eb6063a4 |
12
package.json
12
package.json
|
@ -42,10 +42,6 @@
|
||||||
"@alifd/meet-react": "^2.0.0",
|
"@alifd/meet-react": "^2.0.0",
|
||||||
"@antv/g6": "4.3.11",
|
"@antv/g6": "4.3.11",
|
||||||
"@b-design/ui": "^1.0.63",
|
"@b-design/ui": "^1.0.63",
|
||||||
"@types/js-yaml": "^4.0.1",
|
|
||||||
"@types/lodash": "^4.14.176",
|
|
||||||
"@types/react": "^16.3.0",
|
|
||||||
"@types/react-cookies": "^0.1.0",
|
|
||||||
"ansi-to-react": "^6.1.6",
|
"ansi-to-react": "^6.1.6",
|
||||||
"axios": "0.24.0",
|
"axios": "0.24.0",
|
||||||
"diagram-maker": "^1.3.0",
|
"diagram-maker": "^1.3.0",
|
||||||
|
@ -72,7 +68,8 @@
|
||||||
"redux": "4.1.2",
|
"redux": "4.1.2",
|
||||||
"remark-gfm": "3.0.1",
|
"remark-gfm": "3.0.1",
|
||||||
"tiny-pubsub": "^1.1.0",
|
"tiny-pubsub": "^1.1.0",
|
||||||
"tsx-control-statements": "4.1.1"
|
"tsx-control-statements": "4.1.1",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
|
@ -87,6 +84,11 @@
|
||||||
"@types/jest": "^26.0.24",
|
"@types/jest": "^26.0.24",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.2",
|
"@types/react-copy-to-clipboard": "^5.0.2",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
|
"@types/js-yaml": "^4.0.1",
|
||||||
|
"@types/lodash": "^4.14.176",
|
||||||
|
"@types/react": "^16.3.0",
|
||||||
|
"@types/react-cookies": "^0.1.0",
|
||||||
|
"@types/uuid": "^8.3.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.0.0",
|
"@typescript-eslint/eslint-plugin": "^4.0.0",
|
||||||
"@typescript-eslint/parser": "^4.0.0",
|
"@typescript-eslint/parser": "^4.0.0",
|
||||||
"@umijs/fabric": "2.8.1",
|
"@umijs/fabric": "2.8.1",
|
||||||
|
|
|
@ -196,6 +196,7 @@ class UISchema extends Component<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
id={switchResult.id}
|
id={switchResult.id}
|
||||||
onChange={switchResult.onChange}
|
onChange={switchResult.onChange}
|
||||||
|
size="medium"
|
||||||
checked={switchResult.value ? true : false}
|
checked={switchResult.value ? true : false}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
|
@ -260,3 +260,10 @@ export interface Trigger {
|
||||||
createTime?: string;
|
createTime?: string;
|
||||||
updateTime?: string;
|
updateTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkflowStep {
|
||||||
|
name: string;
|
||||||
|
alias: string;
|
||||||
|
description?: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class TopBar extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.loadSystemInfo();
|
//this.loadSystemInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSystemInfo = () => {
|
loadSystemInfo = () => {
|
||||||
|
@ -183,13 +183,13 @@ class TopBar extends Component<Props, State> {
|
||||||
<Icon size={14} type="help1" />
|
<Icon size={14} type="help1" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="vela-item">
|
{/* <div className="vela-item">
|
||||||
<Icon
|
<Icon
|
||||||
onClick={this.showUserExperienceImprovementPlan}
|
onClick={this.showUserExperienceImprovementPlan}
|
||||||
size={14}
|
size={14}
|
||||||
type="exclamation-circle"
|
type="exclamation-circle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
<Dialog
|
<Dialog
|
||||||
|
|
|
@ -105,29 +105,34 @@ export default {
|
||||||
workflow.default = option.default;
|
workflow.default = option.default;
|
||||||
const { nodes, edges } = data;
|
const { nodes, edges } = data;
|
||||||
const nodeIndex = {};
|
const nodeIndex = {};
|
||||||
let index = 0;
|
Object.keys(nodes).map((key) => {
|
||||||
const steps = Object.keys(nodes).map((key) => {
|
|
||||||
if (nodes[key]) {
|
if (nodes[key]) {
|
||||||
nodeIndex[nodes[key].id] = index;
|
let nodeConfig = Object.assign({}, nodes[key].consumerData);
|
||||||
index++;
|
|
||||||
const nodeConfig = nodes[key].consumerData;
|
|
||||||
if (nodeConfig && nodeConfig.properties && typeof nodeConfig.properties != 'string') {
|
if (nodeConfig && nodeConfig.properties && typeof nodeConfig.properties != 'string') {
|
||||||
return Object.assign(nodeConfig, { properties: JSON.stringify(nodeConfig.properties) });
|
nodeConfig = Object.assign(nodeConfig, {
|
||||||
|
properties: JSON.stringify(nodeConfig.properties),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return nodeConfig;
|
nodeIndex[nodes[key].id] = nodeConfig;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let next = edges.prev;
|
||||||
|
let steps = [];
|
||||||
|
let srcMap = {};
|
||||||
Object.keys(edges).map((key) => {
|
Object.keys(edges).map((key) => {
|
||||||
const edge = edges[key];
|
if (edges[key].src == 'prev') {
|
||||||
if (nodeIndex[edge.src] > nodeIndex[edge.dest]) {
|
next = edges[key];
|
||||||
const i = steps[nodeIndex[edge.src]];
|
|
||||||
const oldIndex = nodeIndex[edge.src];
|
|
||||||
steps[nodeIndex[edge.src]] = steps[nodeIndex[edge.dest]];
|
|
||||||
steps[nodeIndex[edge.dest]] = i;
|
|
||||||
nodeIndex[edge.src] = nodeIndex[edge.dest];
|
|
||||||
nodeIndex[edge.dest] = oldIndex;
|
|
||||||
}
|
}
|
||||||
|
srcMap[edges[key].src] = edges[key];
|
||||||
});
|
});
|
||||||
|
while (next != undefined) {
|
||||||
|
if (next.dest && next.dest != 'next') {
|
||||||
|
steps.push(nodeIndex[next.dest]);
|
||||||
|
next = srcMap[next.dest];
|
||||||
|
} else {
|
||||||
|
next = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
workflow.steps = steps;
|
workflow.steps = steps;
|
||||||
yield call(createWorkFlow, workflow);
|
yield call(createWorkFlow, workflow);
|
||||||
if (action.callback) {
|
if (action.callback) {
|
||||||
|
@ -141,7 +146,7 @@ function transData(workflowList = [], appName) {
|
||||||
const newWorkflows = _.cloneDeep(workflowList);
|
const newWorkflows = _.cloneDeep(workflowList);
|
||||||
if (newWorkflows && newWorkflows.length != 0) {
|
if (newWorkflows && newWorkflows.length != 0) {
|
||||||
newWorkflows.forEach((workflow) => {
|
newWorkflows.forEach((workflow) => {
|
||||||
convertWorkflowStep(workflow, appName, 32);
|
convertWorkflowStep(workflow, appName, 0);
|
||||||
});
|
});
|
||||||
return newWorkflows;
|
return newWorkflows;
|
||||||
} else {
|
} else {
|
||||||
|
@ -149,18 +154,39 @@ function transData(workflowList = [], appName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertWorkflowStep(workflow, appName, initPosition = 32) {
|
export function convertWorkflowStep(workflow, appName, initPosition = 32, edit = false) {
|
||||||
const nodeWidth = 140;
|
const nodeWidth = 200;
|
||||||
const nodeHeight = 40;
|
const nodeHeight = 80;
|
||||||
const nodeInterval = 80;
|
const nodeInterval = 120;
|
||||||
const nodes = {};
|
const nodes = {};
|
||||||
const edges = {};
|
const edges = {};
|
||||||
let position = initPosition;
|
let position = initPosition;
|
||||||
|
if (edit) {
|
||||||
|
nodes.prev = {
|
||||||
|
id: 'prev',
|
||||||
|
typeId: 'prev',
|
||||||
|
diagramMakerData: {
|
||||||
|
position: {
|
||||||
|
x: position,
|
||||||
|
y: 130,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
width: nodeWidth,
|
||||||
|
height: nodeHeight,
|
||||||
|
},
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
position += nodeWidth + nodeInterval;
|
||||||
|
}
|
||||||
if (workflow.steps) {
|
if (workflow.steps) {
|
||||||
workflow.steps.forEach((item, index, array) => {
|
workflow.steps.forEach((item, index, array) => {
|
||||||
edges[item.name] = {};
|
edges[item.name] = {};
|
||||||
edges[item.name].dest =
|
if (workflow.steps && workflow.steps[index + 1]) {
|
||||||
workflow.steps && workflow.steps[index + 1] && workflow.steps[index + 1].name;
|
edges[item.name].dest = workflow.steps[index + 1].name;
|
||||||
|
} else if (edit) {
|
||||||
|
edges[item.name].dest = 'next';
|
||||||
|
}
|
||||||
edges[item.name].diagramMakerData = {
|
edges[item.name].diagramMakerData = {
|
||||||
selected: false,
|
selected: false,
|
||||||
};
|
};
|
||||||
|
@ -169,7 +195,7 @@ export function convertWorkflowStep(workflow, appName, initPosition = 32) {
|
||||||
|
|
||||||
nodes[item.name] = {};
|
nodes[item.name] = {};
|
||||||
nodes[item.name].id = item.name;
|
nodes[item.name].id = item.name;
|
||||||
nodes[item.name].typeId = item.type;
|
nodes[item.name].typeId = 'common';
|
||||||
nodes[item.name].consumerData = {
|
nodes[item.name].consumerData = {
|
||||||
alias: item.alias || '',
|
alias: item.alias || '',
|
||||||
dependsOn: null,
|
dependsOn: null,
|
||||||
|
@ -191,8 +217,32 @@ export function convertWorkflowStep(workflow, appName, initPosition = 32) {
|
||||||
};
|
};
|
||||||
position += nodeWidth + nodeInterval;
|
position += nodeWidth + nodeInterval;
|
||||||
});
|
});
|
||||||
|
edges.prev = {
|
||||||
|
dest: workflow.steps[0].name,
|
||||||
|
src: 'prev',
|
||||||
|
id: 'prev',
|
||||||
|
diagramMakerData: {
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (edit) {
|
||||||
|
nodes.next = {
|
||||||
|
id: 'next',
|
||||||
|
typeId: 'next',
|
||||||
|
diagramMakerData: {
|
||||||
|
position: {
|
||||||
|
x: position,
|
||||||
|
y: 130,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
width: nodeWidth,
|
||||||
|
height: nodeHeight,
|
||||||
|
},
|
||||||
|
selected: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow.appName = appName;
|
workflow.appName = appName;
|
||||||
workflow.option = {
|
workflow.option = {
|
||||||
edit: false,
|
edit: false,
|
||||||
|
|
|
@ -2,31 +2,6 @@ import type { DiagramMakerNodes, DiagramMakerEdges } from 'diagram-maker';
|
||||||
|
|
||||||
export const WORFLOW_NODE_WIDTH = 120;
|
export const WORFLOW_NODE_WIDTH = 120;
|
||||||
|
|
||||||
export const WORKFLOW_COMMON_PANNEL = {
|
|
||||||
p1: {
|
|
||||||
id: 'p1',
|
|
||||||
position: {
|
|
||||||
x: 10,
|
|
||||||
y: 10,
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
width: 230,
|
|
||||||
height: 280,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
p2: {
|
|
||||||
id: 'p2',
|
|
||||||
position: {
|
|
||||||
x: 10,
|
|
||||||
y: 10,
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
width: 420,
|
|
||||||
height: 40,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkFlowOption = {
|
export type WorkFlowOption = {
|
||||||
default: boolean;
|
default: boolean;
|
||||||
edit: boolean;
|
edit: boolean;
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
import { Button } from '@b-design/ui';
|
|
||||||
import { connect } from 'dva';
|
import { connect } from 'dva';
|
||||||
import WrokflowComponent from './workflow-component';
|
import WorkflowComponent from './workflow-component';
|
||||||
import type { WorkFlowData } from './entity';
|
import type { WorkFlowData } from './entity';
|
||||||
import { getWorkFlowDefinitions } from '../../api/workflows';
|
import { getWorkFlowDefinitions } from '../../api/workflows';
|
||||||
|
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import Translation from '../../components/Translation';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
workflowList: WorkFlowData[];
|
workflowList: WorkFlowData[];
|
||||||
|
@ -72,19 +70,19 @@ class Workflow extends Component<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '100%' }} className="workflow-wraper">
|
<div style={{ height: '100%' }} className="workflow-wraper">
|
||||||
<If condition={workflowList.length === 0}>
|
<If condition={workflowList.length === 0}>
|
||||||
<div className="empty-container">
|
{/* <div className="empty-container">
|
||||||
<div className="empty-word">
|
<div className="empty-word">
|
||||||
<Translation>Please create workflow</Translation>
|
<Translation>Please create workflow</Translation>
|
||||||
</div>
|
</div>
|
||||||
<Button type="primary" onClick={this.addWrokflow}>
|
<Button type="primary" onClick={this.addWrokflow}>
|
||||||
<Translation>New Workflow</Translation>
|
<Translation>New Workflow</Translation>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div> */}
|
||||||
</If>
|
</If>
|
||||||
<If condition={workflowList.length > 0}>
|
<If condition={workflowList.length > 0}>
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{workflowList.map((workflow: WorkFlowData) => (
|
{workflowList.map((workflow: WorkFlowData) => (
|
||||||
<WrokflowComponent
|
<WorkflowComponent
|
||||||
key={workflow.name + params.appName + workflow.steps}
|
key={workflow.name + params.appName + workflow.steps}
|
||||||
appName={params.appName}
|
appName={params.appName}
|
||||||
data={workflow}
|
data={workflow}
|
||||||
|
|
|
@ -62,12 +62,11 @@ export type NodeItem = {
|
||||||
typeId: string;
|
typeId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WorkFlowComponent extends Component<Props, State> {
|
class WorkflowComponent extends Component<Props, State> {
|
||||||
field;
|
field;
|
||||||
workflowItem: any;
|
workflowItem: any;
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
errorFocus: false,
|
errorFocus: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -115,33 +114,52 @@ class WorkFlowComponent extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
const { data } = this.props;
|
const { data } = this.props;
|
||||||
const workflowData = this.workflowItem.getValues();
|
const workflowData = this.workflowItem.getValues();
|
||||||
const { nodes } = workflowData;
|
const { nodes, edges } = workflowData;
|
||||||
if (nodes && Object.keys(nodes).length === 0) {
|
if (edges && !edges.prev) {
|
||||||
Message.error('plase add workflow item');
|
let next = undefined;
|
||||||
|
Object.keys(edges).map((key) => {
|
||||||
|
if (edges[key].src == 'prev') {
|
||||||
|
next = edges[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!next) {
|
||||||
|
Message.warning('Please specify the first step');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const reallyNodes: any = {};
|
||||||
|
Object.keys(nodes).map((nodeKey) => {
|
||||||
|
if (nodes[nodeKey].typeId !== 'next' && nodes[nodeKey].typeId !== 'prev') {
|
||||||
|
reallyNodes[nodeKey] = nodes[nodeKey];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (reallyNodes && Object.keys(reallyNodes).length === 0) {
|
||||||
|
Message.warning('Please add at least one workflow step');
|
||||||
this.setState({
|
this.setState({
|
||||||
errorFocus: true,
|
errorFocus: true,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeArr: NodeItem[] = Object.values(nodes);
|
const nodeArr: NodeItem[] = Object.values(reallyNodes);
|
||||||
const find = nodeArr.find((item) => !item.consumerData);
|
const find = nodeArr.find((item) => !item.consumerData || item.consumerData.name == '');
|
||||||
|
|
||||||
if (find) {
|
if (find) {
|
||||||
return Message.error('please enter workflow step name and type');
|
return Message.warning('Please set the workflow step name and type');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
const { name, alias, description } = values;
|
const { name, alias, description } = values;
|
||||||
data.appName = data.appName || this.props.appName;
|
data.appName = data.appName || this.props.appName;
|
||||||
data.name = name;
|
data.name = name;
|
||||||
data.alias = alias;
|
data.alias = alias;
|
||||||
data.description = description;
|
data.description = description;
|
||||||
data.data = workflowData;
|
data.data = Object.assign(workflowData, { nodes: reallyNodes });
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'workflow/saveWorkflow',
|
type: 'workflow/saveWorkflow',
|
||||||
payload: data,
|
payload: data,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
Message.success('save workflow success');
|
Message.success('Save the workflow success');
|
||||||
this.props.getWorkflow();
|
this.props.getWorkflow();
|
||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
},
|
},
|
||||||
|
@ -170,14 +188,14 @@ class WorkFlowComponent extends Component<Props, State> {
|
||||||
<Translation>{option.default ? 'Cancel Default' : 'Set As Default'}</Translation>
|
<Translation>{option.default ? 'Cancel Default' : 'Set As Default'}</Translation>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</If>
|
</If>
|
||||||
<Menu.Item onClick={() => this.deleteWorkflow(data.name)}>
|
{/* <Menu.Item onClick={() => this.deleteWorkflow(data.name)}>
|
||||||
<Translation>Remove</Translation>
|
<Translation>Remove</Translation>
|
||||||
</Menu.Item>
|
</Menu.Item> */}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
const { init } = this.field;
|
const { init } = this.field;
|
||||||
const newData = _.cloneDeep(data);
|
const newData = _.cloneDeep(data);
|
||||||
convertWorkflowStep(newData, data.appName, option.edit ? 250 : 32);
|
convertWorkflowStep(newData, data.appName, 32, option.edit);
|
||||||
const workflowData = newData.data || { nodes: {}, edges: {} };
|
const workflowData = newData.data || { nodes: {}, edges: {} };
|
||||||
return (
|
return (
|
||||||
<Loading visible={loading} style={{ width: '100%' }}>
|
<Loading visible={loading} style={{ width: '100%' }}>
|
||||||
|
@ -266,13 +284,15 @@ class WorkFlowComponent extends Component<Props, State> {
|
||||||
</a>
|
</a>
|
||||||
</If>
|
</If>
|
||||||
<div className="option-item">
|
<div className="option-item">
|
||||||
<Dropdown
|
<If condition={option.edit}>
|
||||||
trigger={<Icon type="ellipsis" className="options-icon" />}
|
<Dropdown
|
||||||
triggerType={['click']}
|
trigger={<Icon type="ellipsis" className="options-icon" />}
|
||||||
className="workflow-more"
|
triggerType={['click']}
|
||||||
>
|
className="workflow-more"
|
||||||
{menu}
|
>
|
||||||
</Dropdown>
|
{menu}
|
||||||
|
</Dropdown>
|
||||||
|
</If>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -292,4 +312,4 @@ class WorkFlowComponent extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WorkFlowComponent;
|
export default WorkflowComponent;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
.workflow-edge-container {
|
.workflow-edge-container {
|
||||||
// height: 10px;
|
width: 14px;
|
||||||
// background-color: green;
|
height: 14px;
|
||||||
// width: 10px;
|
color: #fff;
|
||||||
// line-height: 10px;
|
line-height: 14px;
|
||||||
color: white;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
background-color: #1b58f4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
import { Balloon } from '@b-design/ui';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Translation from '../../../components/Translation';
|
||||||
|
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
export interface EdgeData {
|
||||||
|
dest: string;
|
||||||
|
id: string;
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
data?: any;
|
data: EdgeData;
|
||||||
|
editMode?: boolean;
|
||||||
|
addNode: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {};
|
type State = {};
|
||||||
|
@ -12,14 +21,27 @@ type State = {};
|
||||||
class WorkFlowEdge extends Component<Props, State> {
|
class WorkFlowEdge extends Component<Props, State> {
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {}
|
componentDidMount() {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div className="workflow-edge-container">{/* + */}</div>;
|
const { editMode } = this.props;
|
||||||
|
if (editMode) {
|
||||||
|
return (
|
||||||
|
<Balloon
|
||||||
|
trigger={
|
||||||
|
<div onClick={this.props.addNode} className="workflow-edge-container">
|
||||||
|
+
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Translation>Click to add Workflow Step</Translation>
|
||||||
|
</Balloon>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <div />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { Message } from '@b-design/ui';
|
import { Message } from '@b-design/ui';
|
||||||
import type {
|
import type { DiagramMakerData, DiagramMakerNode, DiagramMakerEdge } from 'diagram-maker';
|
||||||
DiagramMakerData,
|
|
||||||
DiagramMakerNode,
|
|
||||||
DiagramMakerEdge,
|
|
||||||
DiagramMakerPanel,
|
|
||||||
} from 'diagram-maker';
|
|
||||||
import {
|
import {
|
||||||
DiagramMaker,
|
DiagramMaker,
|
||||||
ConnectorPlacement,
|
ConnectorPlacement,
|
||||||
|
@ -17,17 +13,15 @@ import {
|
||||||
NodeActions,
|
NodeActions,
|
||||||
} from 'diagram-maker';
|
} from 'diagram-maker';
|
||||||
import WorkFlowNode from '../workflow-node';
|
import WorkFlowNode from '../workflow-node';
|
||||||
|
import type { EdgeData } from '../workflow-edge';
|
||||||
import WorkFlowEdge from '../workflow-edge';
|
import WorkFlowEdge from '../workflow-edge';
|
||||||
import WorkFlowPannel from '../workflow-panel';
|
|
||||||
import WorkFlowToolTip from '../workflow-tooltip';
|
|
||||||
import type { EdgesAndNodes, WorkFlowNodeType, WorkFlowEdgeType } from '../entity';
|
import type { EdgesAndNodes, WorkFlowNodeType, WorkFlowEdgeType } from '../entity';
|
||||||
import { WORKFLOW_COMMON_PANNEL } from '../entity';
|
|
||||||
import WorkflowForm from './workflow-form';
|
import WorkflowForm from './workflow-form';
|
||||||
import 'diagram-maker/dist/diagramMaker.css';
|
import 'diagram-maker/dist/diagramMaker.css';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
import type { NodeItem } from '../workflow-component';
|
import type { NodeItem } from '../workflow-component';
|
||||||
import type { Definition } from '../../../interface/addon';
|
import type { WorkflowStep } from '../../../interface/application';
|
||||||
|
|
||||||
type WorkFlowItemProps = {
|
type WorkFlowItemProps = {
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
|
@ -57,9 +51,9 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
}
|
}
|
||||||
const { data, edit } = this.props;
|
const { data, edit } = this.props;
|
||||||
const containerWidth = this.container.clientWidth;
|
const containerWidth = this.container.clientWidth;
|
||||||
const nodeWidth = Object.keys(data.nodes).length * 200 + 300;
|
const nodeWidth = Object.keys(data.nodes).length * 360;
|
||||||
const basicePlatformConfig = {
|
const basicPlatformConfig = {
|
||||||
panels: WORKFLOW_COMMON_PANNEL,
|
panels: {},
|
||||||
workspace: {
|
workspace: {
|
||||||
position: {
|
position: {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -82,20 +76,31 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
const initialData: DiagramMakerData<WorkFlowNodeType, WorkFlowEdgeType> = Object.assign(
|
const initialData: DiagramMakerData<WorkFlowNodeType, WorkFlowEdgeType> = Object.assign(
|
||||||
{},
|
{},
|
||||||
data,
|
data,
|
||||||
basicePlatformConfig,
|
basicPlatformConfig,
|
||||||
);
|
);
|
||||||
const { workFlowDefinitions } = this.props;
|
const nodeTypeConfigs: any = {
|
||||||
const nodeTypeConfigs: any = {};
|
prev: {
|
||||||
workFlowDefinitions.map((definition: Definition) => {
|
|
||||||
nodeTypeConfigs[definition.name] = {
|
|
||||||
size: {
|
size: {
|
||||||
width: 140,
|
width: 200,
|
||||||
height: 40,
|
height: 80,
|
||||||
|
},
|
||||||
|
visibleConnectorTypes: VisibleConnectorTypes.OUTPUT_ONLY,
|
||||||
|
},
|
||||||
|
next: {
|
||||||
|
size: {
|
||||||
|
width: 200,
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
visibleConnectorTypes: VisibleConnectorTypes.INPUT_ONLY,
|
||||||
|
},
|
||||||
|
common: {
|
||||||
|
size: {
|
||||||
|
width: 200,
|
||||||
|
height: 80,
|
||||||
},
|
},
|
||||||
definition: definition,
|
|
||||||
visibleConnectorTypes: VisibleConnectorTypes.BOTH,
|
visibleConnectorTypes: VisibleConnectorTypes.BOTH,
|
||||||
};
|
},
|
||||||
});
|
};
|
||||||
this.diagramMaker = new DiagramMaker(
|
this.diagramMaker = new DiagramMaker(
|
||||||
this.container,
|
this.container,
|
||||||
{
|
{
|
||||||
|
@ -108,24 +113,34 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<WorkFlowNode
|
<WorkFlowNode
|
||||||
id={node.id}
|
id={node.id}
|
||||||
data={node.consumerData}
|
data={node.consumerData as WorkflowStep}
|
||||||
selected={node.diagramMakerData.selected}
|
selected={node.diagramMakerData.selected}
|
||||||
workflowId={this.props.workflowId}
|
workflowId={this.props.workflowId}
|
||||||
|
showDetail={this.showStepDetail}
|
||||||
|
editMode={edit}
|
||||||
|
deleteNode={this.deleteNode}
|
||||||
typeId={node.typeId}
|
typeId={node.typeId}
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
edge: (edge: DiagramMakerEdge<{}>, container: HTMLElement) => {
|
edge: (edge: DiagramMakerEdge<{}>, container: HTMLElement) => {
|
||||||
ReactDOM.render(<WorkFlowEdge id={edge.id} data={edge.consumerData} />, container);
|
ReactDOM.render(
|
||||||
|
<WorkFlowEdge
|
||||||
|
editMode={edit}
|
||||||
|
id={edge.id}
|
||||||
|
addNode={() => {
|
||||||
|
this.newNode(edge.src);
|
||||||
|
}}
|
||||||
|
data={edge as EdgeData}
|
||||||
|
/>,
|
||||||
|
container,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
destroy: (container: HTMLElement) => {
|
destroy: (container: HTMLElement) => {
|
||||||
ReactDOM.unmountComponentAtNode(container);
|
ReactDOM.unmountComponentAtNode(container);
|
||||||
},
|
},
|
||||||
panels: {
|
panels: {},
|
||||||
p1: this.renderLeftPannel,
|
|
||||||
p2: this.renderTopPannel,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
nodeTypeConfig: nodeTypeConfigs,
|
nodeTypeConfig: nodeTypeConfigs,
|
||||||
actionInterceptor: (action: any, dispatch, getState) => {
|
actionInterceptor: (action: any, dispatch, getState) => {
|
||||||
|
@ -144,27 +159,34 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dispatch(action);
|
if (action.type == NodeActions.NODE_DRAG) {
|
||||||
if (action.type == 'NODE_CREATE') {
|
if (action.payload.workspaceRectangle.size.height > 400) {
|
||||||
this.setState({
|
this.diagramMaker.api.resetZoom();
|
||||||
currentSelectedNodeData: Object.assign(action.payload, {
|
}
|
||||||
consumerData: { type: action.payload.typeId },
|
|
||||||
}),
|
|
||||||
visible: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (action.type == 'DELETE_ITEMS') {
|
||||||
|
if (Array.isArray(action.payload.edgeIds) && action.payload.edgeIds.length > 0) {
|
||||||
|
Message.warning(
|
||||||
|
'If remove the edge and save the workflow, the nodes that after this edge will be removed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch(action);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
initialData,
|
initialData,
|
||||||
consumerRootReducer: (state: any, action: any) => {
|
consumerRootReducer: (state: any, action: any) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'UPDATENODE':
|
case 'UPDATE_NODE':
|
||||||
const newNode: any = {};
|
const newNode: any = {};
|
||||||
newNode[action.payload.id] = action.payload;
|
newNode[action.payload.id] = action.payload;
|
||||||
const newNodes = Object.assign({}, state.nodes, newNode);
|
const newNodes = Object.assign({}, state.nodes, newNode);
|
||||||
const newState = Object.assign({}, state, { nodes: newNodes });
|
return Object.assign({}, state, { nodes: newNodes });
|
||||||
return newState;
|
case 'UPDATE_NODES':
|
||||||
|
return Object.assign({}, state, { nodes: action.payload });
|
||||||
|
case 'UPDATE_EDGES':
|
||||||
|
return Object.assign({}, state, { edges: action.payload });
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -172,24 +194,6 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
eventListener: () => {},
|
eventListener: () => {},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.diagramMaker.store.subscribe(() => {
|
|
||||||
const { nodes } = this.diagramMaker.store.getState();
|
|
||||||
let currentNode: any = null;
|
|
||||||
Object.keys(nodes).forEach((key) => {
|
|
||||||
const obj = nodes[key];
|
|
||||||
if (obj && obj.diagramMakerData && obj.diagramMakerData.selected) {
|
|
||||||
currentNode = obj;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const { visible } = this.state;
|
|
||||||
if (currentNode && !visible) {
|
|
||||||
this.setState({
|
|
||||||
currentSelectedNodeData: currentNode,
|
|
||||||
visible: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fit = () => {
|
fit = () => {
|
||||||
|
@ -204,66 +208,6 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
undo = () => {
|
|
||||||
this.diagramMaker.api.undo();
|
|
||||||
};
|
|
||||||
|
|
||||||
redo = () => {
|
|
||||||
this.diagramMaker.api.redo();
|
|
||||||
};
|
|
||||||
|
|
||||||
zoomIn = () => {
|
|
||||||
this.diagramMaker.api.zoomIn();
|
|
||||||
};
|
|
||||||
|
|
||||||
zoomOut = () => {
|
|
||||||
this.diagramMaker.api.zoomOut();
|
|
||||||
};
|
|
||||||
|
|
||||||
renderLeftPannel = (
|
|
||||||
panel: DiagramMakerPanel,
|
|
||||||
state: DiagramMakerData<WorkFlowNodeType, WorkFlowEdgeType>,
|
|
||||||
diagramMakerContainer: HTMLElement,
|
|
||||||
) => {
|
|
||||||
const { workFlowDefinitions, edit } = this.props;
|
|
||||||
const parentContainer = diagramMakerContainer.parentElement;
|
|
||||||
if (parentContainer) {
|
|
||||||
parentContainer.style.display = 'block';
|
|
||||||
}
|
|
||||||
if (!edit && parentContainer) {
|
|
||||||
parentContainer.style.display = 'none';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ReactDOM.render(
|
|
||||||
<WorkFlowPannel
|
|
||||||
definitions={workFlowDefinitions}
|
|
||||||
id={panel.id}
|
|
||||||
workflowId={this.props.workflowId}
|
|
||||||
/>,
|
|
||||||
diagramMakerContainer,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderTopPannel = (
|
|
||||||
panel: DiagramMakerPanel,
|
|
||||||
state: DiagramMakerData<WorkFlowNodeType, WorkFlowEdgeType>,
|
|
||||||
diagramMakerContainer: HTMLElement,
|
|
||||||
) => {
|
|
||||||
ReactDOM.render(
|
|
||||||
<WorkFlowToolTip
|
|
||||||
id={panel.id}
|
|
||||||
edit={this.props.edit}
|
|
||||||
undo={this.undo}
|
|
||||||
redo={this.redo}
|
|
||||||
autoLayout={this.autoLayout}
|
|
||||||
zoomIn={this.zoomIn}
|
|
||||||
zoomOut={this.zoomOut}
|
|
||||||
fit={this.fit}
|
|
||||||
/>,
|
|
||||||
diagramMakerContainer,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillReceiveProps = (nextProps: WorkFlowItemProps) => {
|
componentWillReceiveProps = (nextProps: WorkFlowItemProps) => {
|
||||||
if (nextProps.edit !== this.props.edit) {
|
if (nextProps.edit !== this.props.edit) {
|
||||||
if (nextProps.edit) {
|
if (nextProps.edit) {
|
||||||
|
@ -278,6 +222,142 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
return { edges, nodes };
|
return { edges, nodes };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deleteNode = (id: string) => {
|
||||||
|
const { edges, nodes } = this.diagramMaker.store.getState();
|
||||||
|
const newNodes: any = {};
|
||||||
|
const deleteNode = nodes[id];
|
||||||
|
if (!deleteNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object.keys(nodes).map((key: string) => {
|
||||||
|
if (key == id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const step: NodeItem = nodes[key];
|
||||||
|
let stepNew: NodeItem = Object.assign({}, step);
|
||||||
|
if (stepNew.diagramMakerData.position.x >= deleteNode.diagramMakerData.position.x) {
|
||||||
|
stepNew = Object.assign(stepNew, {
|
||||||
|
diagramMakerData: {
|
||||||
|
selected: stepNew.diagramMakerData.selected,
|
||||||
|
size: stepNew.diagramMakerData.size,
|
||||||
|
position: {
|
||||||
|
x: stepNew.diagramMakerData.position.x - 320,
|
||||||
|
y: stepNew.diagramMakerData.position.y,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
newNodes[stepNew.id] = stepNew;
|
||||||
|
});
|
||||||
|
const newEdges: any = {};
|
||||||
|
let preEdge: EdgeData = { id: '', dest: '', src: '' };
|
||||||
|
let dest = '';
|
||||||
|
Object.keys(edges).map((key: string) => {
|
||||||
|
const edge: EdgeData = edges[key];
|
||||||
|
if (edge.src == id) {
|
||||||
|
dest = edge.dest;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (edge.dest == id) {
|
||||||
|
preEdge = Object.assign({}, edge);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newEdges[key] = edge;
|
||||||
|
});
|
||||||
|
preEdge.dest = dest;
|
||||||
|
newEdges[preEdge.id] = preEdge;
|
||||||
|
this.diagramMaker.store.dispatch({
|
||||||
|
type: 'UPDATE_NODES',
|
||||||
|
payload: newNodes,
|
||||||
|
});
|
||||||
|
this.diagramMaker.store.dispatch({
|
||||||
|
type: 'UPDATE_EDGES',
|
||||||
|
payload: newEdges,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
newNode = (source: string) => {
|
||||||
|
const { nodes, edges } = this.diagramMaker.store.getState();
|
||||||
|
const sourceNode = nodes[source];
|
||||||
|
let newNode: NodeItem = Object.assign({}, sourceNode);
|
||||||
|
newNode = Object.assign(newNode, {
|
||||||
|
consumerData: { name: '', properties: '', type: '' },
|
||||||
|
id: uuid(),
|
||||||
|
typeId: 'common',
|
||||||
|
diagramMakerData: {
|
||||||
|
selected: newNode.diagramMakerData.selected,
|
||||||
|
size: newNode.diagramMakerData.size,
|
||||||
|
position: {
|
||||||
|
x: newNode.diagramMakerData.position.x + 320,
|
||||||
|
y: newNode.diagramMakerData.position.y,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const newNodes: any = {};
|
||||||
|
Object.keys(nodes).map((key: string) => {
|
||||||
|
const step: NodeItem = nodes[key];
|
||||||
|
let stepNew: NodeItem = Object.assign({}, step);
|
||||||
|
if (stepNew.diagramMakerData.position.x >= newNode.diagramMakerData.position.x) {
|
||||||
|
stepNew = Object.assign(stepNew, {
|
||||||
|
diagramMakerData: {
|
||||||
|
selected: stepNew.diagramMakerData.selected,
|
||||||
|
size: stepNew.diagramMakerData.size,
|
||||||
|
position: {
|
||||||
|
x: stepNew.diagramMakerData.position.x + 320,
|
||||||
|
y: stepNew.diagramMakerData.position.y,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
newNodes[stepNew.id] = stepNew;
|
||||||
|
});
|
||||||
|
newNodes[newNode.id] = newNode;
|
||||||
|
|
||||||
|
const newEdges: any = {};
|
||||||
|
Object.keys(edges).map((key: string) => {
|
||||||
|
const edge: EdgeData = edges[key];
|
||||||
|
if (edge.src == source) {
|
||||||
|
const pre = Object.assign({}, edge);
|
||||||
|
const next = Object.assign({}, edge);
|
||||||
|
pre.dest = newNode.id;
|
||||||
|
pre.id = pre.src;
|
||||||
|
next.src = newNode.id;
|
||||||
|
next.id = next.src;
|
||||||
|
newEdges[pre.id] = pre;
|
||||||
|
newEdges[next.id] = next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newEdges[key] = edge;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.diagramMaker.store.dispatch({
|
||||||
|
type: 'UPDATE_NODES',
|
||||||
|
payload: newNodes,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.diagramMaker.store.dispatch({
|
||||||
|
type: 'UPDATE_EDGES',
|
||||||
|
payload: newEdges,
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
currentSelectedNodeData: newNode,
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
showStepDetail = (id: string) => {
|
||||||
|
const { edit } = this.props;
|
||||||
|
if (!edit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { nodes } = this.diagramMaker.store.getState();
|
||||||
|
const consumerData: NodeItem = nodes[id];
|
||||||
|
this.setState({
|
||||||
|
currentSelectedNodeData: consumerData,
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
openDrawer = () => {
|
openDrawer = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
visible: true,
|
visible: true,
|
||||||
|
@ -296,20 +376,24 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
createOrUpdateNode = (values: any) => {
|
createOrUpdateNode = (values: any) => {
|
||||||
const { nodes } = this.diagramMaker.store.getState();
|
const { nodes } = this.diagramMaker.store.getState();
|
||||||
const { currentSelectedNodeData } = this.state;
|
const { currentSelectedNodeData } = this.state;
|
||||||
let consumerData: NodeItem = nodes[currentSelectedNodeData.id];
|
if (currentSelectedNodeData) {
|
||||||
consumerData = Object.assign({}, consumerData, {
|
let consumerData: NodeItem = nodes[currentSelectedNodeData.id];
|
||||||
consumerData: values,
|
if (consumerData) {
|
||||||
diagramMakerData: {
|
consumerData = Object.assign({}, consumerData, {
|
||||||
selected: false,
|
consumerData: values,
|
||||||
size: consumerData.diagramMakerData.size,
|
diagramMakerData: {
|
||||||
position: consumerData.diagramMakerData.position,
|
selected: false,
|
||||||
},
|
size: consumerData.diagramMakerData.size,
|
||||||
});
|
position: consumerData.diagramMakerData.position,
|
||||||
this.diagramMaker.store.dispatch({
|
},
|
||||||
type: 'UPDATENODE',
|
});
|
||||||
payload: consumerData,
|
this.diagramMaker.store.dispatch({
|
||||||
});
|
type: 'UPDATE_NODE',
|
||||||
this.closeDrawer();
|
payload: consumerData,
|
||||||
|
});
|
||||||
|
this.closeDrawer();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onDelete = (values: NodeItem) => {
|
onDelete = (values: NodeItem) => {
|
||||||
|
@ -335,7 +419,6 @@ class WorkFlowItem extends Component<WorkFlowItemProps, State> {
|
||||||
/>
|
/>
|
||||||
<If condition={visible}>
|
<If condition={visible}>
|
||||||
<WorkflowForm
|
<WorkflowForm
|
||||||
onDelete={() => this.onDelete(currentSelectedNodeData)}
|
|
||||||
createOrUpdateNode={this.createOrUpdateNode}
|
createOrUpdateNode={this.createOrUpdateNode}
|
||||||
data={currentSelectedNodeData}
|
data={currentSelectedNodeData}
|
||||||
checkStepName={(name: string) => {
|
checkStepName={(name: string) => {
|
||||||
|
|
|
@ -21,13 +21,12 @@ import locale from '../../../utils/locale';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
createOrUpdateNode: (data: any) => void;
|
createOrUpdateNode: (data: any) => void;
|
||||||
data: DiagramMakerNode<WorkFlowNodeType>;
|
data?: DiagramMakerNode<WorkFlowNodeType>;
|
||||||
workFlowDefinitions: [];
|
workFlowDefinitions: [];
|
||||||
appName?: string;
|
appName?: string;
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
closeDrawer: () => void;
|
closeDrawer: () => void;
|
||||||
checkStepName: (name: string) => boolean;
|
checkStepName: (name: string) => boolean;
|
||||||
onDelete: () => void;
|
|
||||||
dispatch?: ({}) => {};
|
dispatch?: ({}) => {};
|
||||||
t: (key: string) => {};
|
t: (key: string) => {};
|
||||||
};
|
};
|
||||||
|
@ -56,14 +55,16 @@ class WorkflowForm extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
const { consumerData } = this.props.data;
|
if (this.props.data) {
|
||||||
this.field.setValues(consumerData || '');
|
const { consumerData } = this.props.data;
|
||||||
let properties = consumerData && consumerData.properties;
|
this.field.setValues(consumerData || '');
|
||||||
if (properties && typeof properties === 'string') {
|
let properties = consumerData && consumerData.properties;
|
||||||
properties = JSON.parse(properties);
|
if (properties && typeof properties === 'string') {
|
||||||
|
properties = JSON.parse(properties);
|
||||||
|
}
|
||||||
|
this.field.setValues({ properties: properties });
|
||||||
|
this.onDetailsComponeDefinition((consumerData && consumerData.type) || '');
|
||||||
}
|
}
|
||||||
this.field.setValues({ properties: properties });
|
|
||||||
this.onDetailsComponeDefinition((consumerData && consumerData.type) || '');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setValues = (values: any | null) => {
|
setValues = (values: any | null) => {
|
||||||
|
@ -83,13 +84,6 @@ class WorkflowForm extends Component<Props, State> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onDelete = () => {
|
|
||||||
const { onDelete } = this.props;
|
|
||||||
if (onDelete) {
|
|
||||||
onDelete();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
transDefinitions() {
|
transDefinitions() {
|
||||||
const { workFlowDefinitions } = this.props;
|
const { workFlowDefinitions } = this.props;
|
||||||
return (workFlowDefinitions || []).map((item: { name: string }) => ({
|
return (workFlowDefinitions || []).map((item: { name: string }) => ({
|
||||||
|
@ -129,20 +123,22 @@ class WorkflowForm extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkWorkflowStepName = (rule: Rule, value: any, callback: (error?: string) => void) => {
|
const checkWorkflowStepName = (rule: Rule, value: any, callback: (error?: string) => void) => {
|
||||||
const { consumerData } = this.props.data;
|
if (data) {
|
||||||
if (checkStepName(value)) {
|
const { consumerData } = data;
|
||||||
if (consumerData?.name && value == consumerData?.name) {
|
if (checkStepName(value)) {
|
||||||
callback();
|
if (consumerData?.name && value == consumerData?.name) {
|
||||||
return;
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback('name is exist');
|
||||||
}
|
}
|
||||||
callback('name is exist');
|
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
|
const edit = data && data.consumerData?.name != undefined && data.consumerData?.name != '';
|
||||||
return (
|
return (
|
||||||
<DrawerWithFooter
|
<DrawerWithFooter
|
||||||
title={<Translation>Edit Workflow Step</Translation>}
|
title={<Translation>{edit ? 'Edit Workflow Step' : 'Add Workflow Step'}</Translation>}
|
||||||
placement="right"
|
placement="right"
|
||||||
width={800}
|
width={800}
|
||||||
onClose={closeDrawer}
|
onClose={closeDrawer}
|
||||||
|
@ -151,26 +147,12 @@ class WorkflowForm extends Component<Props, State> {
|
||||||
<Button key={'cancel'} style={{ marginRight: '16px' }} onClick={closeDrawer}>
|
<Button key={'cancel'} style={{ marginRight: '16px' }} onClick={closeDrawer}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>,
|
</Button>,
|
||||||
<Button
|
|
||||||
key={'delete'}
|
|
||||||
style={{ marginRight: '16px' }}
|
|
||||||
onClick={() => {
|
|
||||||
this.onDelete();
|
|
||||||
}}
|
|
||||||
title="Delete this step"
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</Button>,
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Form field={this.field}>
|
<Form field={this.field}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={24} style={{ padding: '0 8px' }}>
|
<Col span={24} style={{ padding: '0 8px' }}>
|
||||||
<FormItem
|
<FormItem label={<Translation>Workflow Type</Translation>} required disabled={edit}>
|
||||||
label={<Translation>Workflow Type</Translation>}
|
|
||||||
required
|
|
||||||
disabled={this.field.getValue('type')}
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
locale={locale.Select}
|
locale={locale.Select}
|
||||||
className="select"
|
className="select"
|
||||||
|
@ -202,7 +184,7 @@ class WorkflowForm extends Component<Props, State> {
|
||||||
maxLength={32}
|
maxLength={32}
|
||||||
placeholder={t('Please enter').toString()}
|
placeholder={t('Please enter').toString()}
|
||||||
{...init('name', {
|
{...init('name', {
|
||||||
initValue: data.consumerData?.type,
|
initValue: data && data.consumerData?.type,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|
|
@ -1,63 +1,27 @@
|
||||||
@primarycolor: #1b58f4;
|
@primarycolor: #1b58f4;
|
||||||
.workflow-node-container {
|
.workflow-node-container {
|
||||||
width: auto;
|
width: 200px;
|
||||||
height: 40px;
|
height: 80px;
|
||||||
|
padding: 16px;
|
||||||
color: black;
|
color: black;
|
||||||
line-height: 40px;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
cursor: pointer;
|
|
||||||
&.active {
|
&.active {
|
||||||
border: 1px solid @primarycolor;
|
border: 1px solid @primarycolor;
|
||||||
}
|
}
|
||||||
}
|
.workflow-step-type {
|
||||||
|
padding-top: 8px;
|
||||||
.workflow-switch-node-container {
|
color: #a6a6a6;
|
||||||
position: relative;
|
}
|
||||||
width: 80px;
|
.workflow-step-delete {
|
||||||
height: 80px;
|
position: absolute;
|
||||||
border: none;
|
top: 8px;
|
||||||
&.active {
|
right: 8px;
|
||||||
border: none;
|
:hover {
|
||||||
.rhombus-container {
|
color: @primarycolor;
|
||||||
border: 1px solid @primarycolor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.rhombus-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 11px;
|
|
||||||
left: 11px;
|
|
||||||
width: 57px;
|
|
||||||
height: 57px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.start-connector {
|
|
||||||
position: absolute;
|
|
||||||
top: 31px;
|
|
||||||
left: -4px;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
background-color: blue;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
.end-connector {
|
|
||||||
position: absolute;
|
|
||||||
top: 31px;
|
|
||||||
right: -4px;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
background-color: blue;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { DiagramMakerComponents } from 'diagram-maker';
|
import { DiagramMakerComponents } from 'diagram-maker';
|
||||||
import { Icon } from '@b-design/ui';
|
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import type { WorkflowStep } from '../../../interface/application';
|
||||||
|
import { Balloon, Icon } from '@b-design/ui';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
import Translation from '../../../components/Translation';
|
import Translation from '../../../components/Translation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
typeId?: string;
|
typeId?: string;
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
data?: any;
|
showDetail: (id: string) => void;
|
||||||
|
deleteNode: (id: string) => void;
|
||||||
|
data?: WorkflowStep;
|
||||||
|
editMode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {};
|
type State = {};
|
||||||
|
@ -17,69 +22,66 @@ type State = {};
|
||||||
class WorkFlowNode extends Component<Props, State> {
|
class WorkFlowNode extends Component<Props, State> {
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {}
|
componentDidMount() {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { data = {}, selected, id, workflowId, typeId } = this.props;
|
const { data, selected, id, workflowId, editMode, typeId } = this.props;
|
||||||
|
const showName =
|
||||||
|
data && data.name ? (
|
||||||
|
data.alias || data.name
|
||||||
|
) : (
|
||||||
|
<Translation>Click to config Workflow Step</Translation>
|
||||||
|
);
|
||||||
|
if (typeId == 'prev' || typeId == 'next') {
|
||||||
|
return <React.Fragment />;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<If condition={typeId !== 'switch'}>
|
<div
|
||||||
<div
|
className={selected ? 'workflow-node-container active' : 'workflow-node-container'}
|
||||||
className={selected ? 'workflow-node-container active' : 'workflow-node-container'}
|
id={id}
|
||||||
id={id}
|
style={{
|
||||||
workflow-id={workflowId}
|
cursor: editMode ? 'pointer' : 'auto',
|
||||||
>
|
}}
|
||||||
{data.alias || data.name || <Translation>Click Edit</Translation>}
|
onClick={() => this.props.showDetail(id)}
|
||||||
<div
|
workflow-id={workflowId}
|
||||||
data-event-target="true"
|
>
|
||||||
data-dropzone="true"
|
<If condition={editMode}>
|
||||||
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
<div className="workflow-step-delete">
|
||||||
data-id={id}
|
<Balloon
|
||||||
/>
|
trigger={
|
||||||
<div
|
<Icon
|
||||||
data-event-target="true"
|
size={14}
|
||||||
data-draggable="true"
|
onClick={(event: any) => {
|
||||||
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
event.stopPropagation();
|
||||||
data-id={id}
|
this.props.deleteNode(id);
|
||||||
/>
|
}}
|
||||||
</div>
|
type="delete"
|
||||||
</If>
|
/>
|
||||||
<If condition={typeId === 'switch'}>
|
}
|
||||||
<div
|
>
|
||||||
className={
|
<Translation>Click to remove Workflow Step</Translation>
|
||||||
selected
|
</Balloon>
|
||||||
? 'workflow-node-container workflow-switch-node-container active'
|
|
||||||
: 'workflow-node-container workflow-switch-node-container'
|
|
||||||
}
|
|
||||||
id={id}
|
|
||||||
workflow-id={workflowId}
|
|
||||||
title={data.text}
|
|
||||||
>
|
|
||||||
<div className="rhombus-container" />
|
|
||||||
<div className="content">
|
|
||||||
{data.text || <Translation>Click Edit</Translation>}
|
|
||||||
<Icon type="ashbin1" />
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
</If>
|
||||||
className="start-connector"
|
{showName}
|
||||||
data-event-target="true"
|
<div className="workflow-step-type">{data?.type}</div>
|
||||||
data-dropzone="true"
|
<div
|
||||||
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
data-event-target="true"
|
||||||
data-id={id}
|
data-dropzone="false"
|
||||||
/>
|
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
||||||
<div
|
data-id={id}
|
||||||
className="end-connector"
|
/>
|
||||||
data-event-target="true"
|
<div
|
||||||
data-draggable="true"
|
data-event-target="true"
|
||||||
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
data-draggable="false"
|
||||||
data-id={id}
|
data-type={DiagramMakerComponents.NODE_CONNECTOR}
|
||||||
/>
|
data-id={id}
|
||||||
</div>
|
/>
|
||||||
</If>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1993,6 +1993,11 @@
|
||||||
resolved "https://registry.nlark.com/@types/unist/download/@types/unist-2.0.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Funist%2Fdownload%2F%40types%2Funist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
|
resolved "https://registry.nlark.com/@types/unist/download/@types/unist-2.0.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Funist%2Fdownload%2F%40types%2Funist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
|
||||||
integrity sha1-JQp7FsO5H2cqJFUuxkZ47rHToI0=
|
integrity sha1-JQp7FsO5H2cqJFUuxkZ47rHToI0=
|
||||||
|
|
||||||
|
"@types/uuid@^8.3.4":
|
||||||
|
version "8.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
|
||||||
|
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
|
||||||
|
|
||||||
"@types/webpack-sources@*":
|
"@types/webpack-sources@*":
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.nlark.com/@types/webpack-sources/download/@types/webpack-sources-3.2.0.tgz?cache=0&sync_timestamp=1629709718286&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b"
|
resolved "https://registry.nlark.com/@types/webpack-sources/download/@types/webpack-sources-3.2.0.tgz?cache=0&sync_timestamp=1629709718286&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fwebpack-sources%2Fdownload%2F%40types%2Fwebpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b"
|
||||||
|
@ -12210,6 +12215,11 @@ uuid@^3.3.2, uuid@^3.4.0:
|
||||||
resolved "https://registry.npmmirror.com/uuid/download/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.npmmirror.com/uuid/download/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=
|
integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=
|
||||||
|
|
||||||
|
uuid@^8.3.2:
|
||||||
|
version "8.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||||
|
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||||
|
|
||||||
uvu@^0.5.0:
|
uvu@^0.5.0:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.npmmirror.com/uvu/download/uvu-0.5.2.tgz#c145e7f4b5becf80099cf22fd8a4a05f0112b2c0"
|
resolved "https://registry.npmmirror.com/uvu/download/uvu-0.5.2.tgz#c145e7f4b5becf80099cf22fd8a4a05f0112b2c0"
|
||||||
|
|
Loading…
Reference in New Issue