diff --git a/front-end/src/API.js b/front-end/src/API.js index e75e5e6..04f8043 100644 --- a/front-end/src/API.js +++ b/front-end/src/API.js @@ -118,4 +118,33 @@ export async function uploadWorkflow(formData) { body: formData }; return fetchWrapper("/workflow/open", options); -} \ No newline at end of file +} + + +async function handleEdge(link, method) { + const sourceId = link.getSourcePort().getNode().options.id; + const targetId = link.getTargetPort().getNode().options.id; + return fetchWrapper( + `/node/edge/${sourceId}/${targetId}`, + {method: method}); +} + + +/** + * Add edge to server-side workflow + * @param {VPLinkModel} link - JS edge to create + * @returns {Promise} - server response + */ +export async function addEdge(link) { + return handleEdge(link, "POST"); +} + + +/** + * Delete edge from server-side workflow + * @param {VPLinkModel} link - JS edge to delete + * @returns {Promise} - server response + */ +export async function deleteEdge(link) { + return handleEdge(link, "DELETE"); +} diff --git a/front-end/src/components/CustomLink/CustomLinkFactory.js b/front-end/src/components/CustomLink/CustomLinkFactory.js deleted file mode 100644 index f4be4e9..0000000 --- a/front-end/src/components/CustomLink/CustomLinkFactory.js +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import { CustomLinkModel } from './CustomLinkModel'; -import { CustomLinkWidget } from './CustomLinkWidget'; -import { DefaultLinkFactory } from '@projectstorm/react-diagrams'; - -export class CustomLinkFactory extends DefaultLinkFactory { - constructor() { - super('advanced'); - } - - generateModel() { - return new CustomLinkModel(); - } - - generateLinkSegment(model, selected, path) { - return ( - - - - ); - } -} diff --git a/front-end/src/components/CustomLink/CustomLinkModel.js b/front-end/src/components/CustomLink/CustomLinkModel.js deleted file mode 100644 index 51f7245..0000000 --- a/front-end/src/components/CustomLink/CustomLinkModel.js +++ /dev/null @@ -1,22 +0,0 @@ -import { DefaultLinkModel } from '@projectstorm/react-diagrams'; - -export class CustomLinkModel extends DefaultLinkModel { - constructor() { - super({ - type: 'advanced', - width: 5 - }); - } - - getSVGPath() { - if (this.isLastPositionDefault()) { - return; - } - - return super.getSVGPath(); - } - - isLastPositionDefault() { - return this.getLastPoint().getX() === 0 && this.getLastPoint().getY() === 0; - } -} diff --git a/front-end/src/components/CustomLink/CustomLinkWidget.js b/front-end/src/components/CustomLink/CustomLinkWidget.js deleted file mode 100644 index 65bb035..0000000 --- a/front-end/src/components/CustomLink/CustomLinkWidget.js +++ /dev/null @@ -1,51 +0,0 @@ -import * as React from 'react'; - -export class CustomLinkWidget extends React.Component { - - path; - - constructor(props) { - super(props); - this.percent = 0; - } - - componentDidMount() { - this.mounted = true; - this.callback = () => { - if (!this.path) { - return; - } - - this.percent += 2; - if (this.percent > 100) { - this.percent = 0; - } - - if (this.mounted) { - requestAnimationFrame(this.callback); - } - }; - requestAnimationFrame(this.callback); - } - - componentWillUnmount() { - this.mounted = false; - } - - render() { - return ( - <> - { - this.path = ref; - }} - strokeWidth={this.props.model.getOptions().width} - stroke="rgba(255,0,0,0.5)" - d={this.props.path} - /> - - ); - } - -} diff --git a/front-end/src/components/CustomNode/CustomNodeFactory.js b/front-end/src/components/CustomNode/CustomNodeFactory.js index 30da6a8..a7a64eb 100644 --- a/front-end/src/components/CustomNode/CustomNodeFactory.js +++ b/front-end/src/components/CustomNode/CustomNodeFactory.js @@ -1,9 +1,9 @@ import * as React from 'react'; -import { CustomNodeModel } from './CustomNodeModel'; -import { CustomNodeWidget } from './CustomNodeWidget'; import { AbstractReactFactory } from '@projectstorm/react-canvas-core'; +import CustomNodeModel from './CustomNodeModel'; +import CustomNodeWidget from './CustomNodeWidget'; -export class CustomNodeFactory extends AbstractReactFactory { +export default class CustomNodeFactory extends AbstractReactFactory { constructor() { super('custom-node'); } diff --git a/front-end/src/components/CustomNode/CustomNodeModel.js b/front-end/src/components/CustomNode/CustomNodeModel.js index 3b84d5e..7403630 100644 --- a/front-end/src/components/CustomNode/CustomNodeModel.js +++ b/front-end/src/components/CustomNode/CustomNodeModel.js @@ -1,7 +1,7 @@ import { NodeModel } from '@projectstorm/react-diagrams'; -import { VPPortModel } from '../VPPort/VPPortModel'; +import VPPortModel from '../VPPort/VPPortModel'; -export class CustomNodeModel extends NodeModel { +export default class CustomNodeModel extends NodeModel { constructor(options = {}, config = {}) { super({ diff --git a/front-end/src/components/CustomNode/CustomNodeWidget.js b/front-end/src/components/CustomNode/CustomNodeWidget.js index 0baeae0..b1e38d5 100644 --- a/front-end/src/components/CustomNode/CustomNodeWidget.js +++ b/front-end/src/components/CustomNode/CustomNodeWidget.js @@ -7,7 +7,7 @@ import NodeConfig from './NodeConfig'; import '../../styles/CustomNode.css'; import * as API from '../../API'; -export class CustomNodeWidget extends React.Component { +export default class CustomNodeWidget extends React.Component { constructor(props) { super(props); diff --git a/front-end/src/components/CustomPort/CustomPortModel.js b/front-end/src/components/CustomPort/CustomPortModel.js deleted file mode 100644 index 1199224..0000000 --- a/front-end/src/components/CustomPort/CustomPortModel.js +++ /dev/null @@ -1,12 +0,0 @@ -import { DefaultPortModel } from '@projectstorm/react-diagrams'; -import { CustomLinkModel } from '../CustomLink/CustomLinkModel'; - -export class CustomPortModel extends DefaultPortModel { - createLinkModel() { - return new CustomLinkModel(); - } - - canLinkToPort(port) { - return port instanceof CustomPortModel; - } -} diff --git a/front-end/src/components/VPLink/VPLinkFactory.js b/front-end/src/components/VPLink/VPLinkFactory.js index 84e4908..8b493aa 100644 --- a/front-end/src/components/VPLink/VPLinkFactory.js +++ b/front-end/src/components/VPLink/VPLinkFactory.js @@ -1,9 +1,9 @@ -import { VPLinkModel } from './VPLinkModel'; import { DefaultLinkFactory } from '@projectstorm/react-diagrams'; +import VPLinkModel from './VPLinkModel'; -export class VPLinkFactory extends DefaultLinkFactory { +export default class VPLinkFactory extends DefaultLinkFactory { generateModel() { - return new VPLinkModel(); + return new VPLinkModel(); } } diff --git a/front-end/src/components/VPLink/VPLinkModel.js b/front-end/src/components/VPLink/VPLinkModel.js index 309d77c..a29e2bb 100644 --- a/front-end/src/components/VPLink/VPLinkModel.js +++ b/front-end/src/components/VPLink/VPLinkModel.js @@ -1,12 +1,18 @@ import { DefaultLinkModel } from '@projectstorm/react-diagrams'; +import * as API from '../../API'; -export class VPLinkModel extends DefaultLinkModel { +export default class VPLinkModel extends DefaultLinkModel { constructor() { super({ type: 'default', width: 5, color: 'orange' }); + this.registerListener({ + targetPortChanged: event => { + API.addEdge(this).catch(() => {}); + }, + }) } getSVGPath() { @@ -25,11 +31,8 @@ export class VPLinkModel extends DefaultLinkModel { * TODO: Notify backend the link has been removed */ remove() { - const sourcePort = this.getSourcePort(); // PortModel - const sourceNode = sourcePort.getNode(); // NodeModel - const targetPort = this.getTargetPort(); // PortModel - const targetNode = targetPort.getNode(); // NodeModel - - super.remove(); + super.remove(); + API.deleteEdge(this) + .catch(() => {}); } } diff --git a/front-end/src/components/VPLink/VPLinkWidget.js b/front-end/src/components/VPLink/VPLinkWidget.js index c58b599..f441160 100644 --- a/front-end/src/components/VPLink/VPLinkWidget.js +++ b/front-end/src/components/VPLink/VPLinkWidget.js @@ -1,5 +1,5 @@ import { DefaultLinkWidget } from '@projectstorm/react-diagrams'; -export class VPLinkWidget extends DefaultLinkWidget { +export default class VPLinkWidget extends DefaultLinkWidget { } diff --git a/front-end/src/components/VPPort/VPPortFactory.js b/front-end/src/components/VPPort/VPPortFactory.js index e67210f..292a0c2 100644 --- a/front-end/src/components/VPPort/VPPortFactory.js +++ b/front-end/src/components/VPPort/VPPortFactory.js @@ -1,12 +1,13 @@ -import { VPPortModel } from './VPPortModel'; -import { DefaultPortFactory } from '@projectstorm/react-diagrams'; +import { AbstractModelFactory } from '@projectstorm/react-canvas-core'; +import VPPortModel from './VPPortModel'; -export class VPPortFactory extends DefaultPortFactory { +export default class VPPortFactory extends AbstractModelFactory { - getType() { - return "vp-port"; + constructor() { + super("vp-port"); } - generateModel(event) { + + generateModel() { return new VPPortModel({name: 'vp-port-name'}); } } diff --git a/front-end/src/components/VPPort/VPPortModel.js b/front-end/src/components/VPPort/VPPortModel.js index ca80e88..4c0897a 100644 --- a/front-end/src/components/VPPort/VPPortModel.js +++ b/front-end/src/components/VPPort/VPPortModel.js @@ -1,12 +1,16 @@ import { DefaultPortModel } from '@projectstorm/react-diagrams'; -import { VPLinkModel } from '../VPLink/VPLinkModel'; +import VPLinkFactory from '../VPLink/VPLinkFactory'; + +export default class VPPortModel extends DefaultPortModel { -export class VPPortModel extends DefaultPortModel { createLinkModel() { - return new VPLinkModel(); + const factory = new VPLinkFactory(); + return factory.generateModel(); } canLinkToPort(port) { - return port instanceof VPPortModel; + // can't both be in or out ports + return port instanceof VPPortModel + && this.options.in !== port.options.in; } } diff --git a/front-end/src/components/Workspace.js b/front-end/src/components/Workspace.js index 2f7017f..6a4924f 100644 --- a/front-end/src/components/Workspace.js +++ b/front-end/src/components/Workspace.js @@ -2,10 +2,10 @@ import React, { useRef } from 'react'; import { Row, Col, Button } from 'react-bootstrap'; import createEngine, { DiagramModel } from '@projectstorm/react-diagrams'; import { CanvasWidget } from '@projectstorm/react-canvas-core'; -import { VPLinkFactory } from './VPLink/VPLinkFactory'; -import { CustomNodeModel } from './CustomNode/CustomNodeModel'; -import { CustomNodeFactory } from './CustomNode/CustomNodeFactory'; -import { VPPortFactory } from './VPPort/VPPortFactory'; +import VPLinkFactory from './VPLink/VPLinkFactory'; +import CustomNodeModel from './CustomNode/CustomNodeModel'; +import CustomNodeFactory from './CustomNode/CustomNodeFactory'; +import VPPortFactory from './VPPort/VPPortFactory'; import * as API from '../API'; import NodeMenu from './NodeMenu'; import '../styles/Workspace.css'; @@ -57,8 +57,9 @@ class Workspace extends React.Component { // takes data from node drop and creates node on server and in diagram handleNodeCreation(event) { - const data = JSON.parse(event.dataTransfer.getData('storm-diagram-node')); - if (!data) return; + const evtData = event.dataTransfer.getData("storm-diagram-node"); + if (!evtData) return; + const data = JSON.parse(evtData); const node = new CustomNodeModel(data.nodeInfo, data.config), point = this.engine.getRelativeMousePoint(event); node.setPosition(point);