From 38dfd59a8b5d05266e5567f79dcf30fd10ef7c54 Mon Sep 17 00:00:00 2001 From: Lvbo163 Date: Wed, 10 Jan 2018 15:05:39 +0800 Subject: split element by type split elements by type in toolbar Issue-ID: SDC-895 Change-Id: I0254c9c5f938df80942d60ffefe4b8577c788233 Signed-off-by: Lvbo163 --- sdc-workflow-designer-ui/src/app/app.component.css | 73 ++- .../src/app/app.component.html | 9 +- sdc-workflow-designer-ui/src/app/app.module.ts | 17 +- .../src/app/components/canvas/canvas.component.css | 26 - .../app/components/canvas/canvas.component.html | 16 - .../src/app/components/canvas/canvas.component.ts | 84 --- .../components/container/container.component.css | 26 + .../components/container/container.component.html | 22 + .../components/container/container.component.ts | 164 ++++++ .../editable-property.component.css | 26 + .../editable-property.component.html | 30 +- .../editable-property.component.ts | 47 +- .../src/app/components/menu/menu.component.css | 23 - .../src/app/components/menu/menu.component.html | 31 -- .../src/app/components/menu/menu.component.spec.ts | 36 -- .../src/app/components/menu/menu.component.ts | 91 ---- .../src/app/components/menu/menus.component.css | 23 + .../src/app/components/menu/menus.component.html | 31 ++ .../app/components/menu/menus.component.spec.ts | 36 ++ .../src/app/components/menu/menus.component.ts | 92 ++++ .../src/app/components/node/node.component.css | 170 ++---- .../src/app/components/node/node.component.html | 134 ++++- .../src/app/components/node/node.component.ts | 105 ++-- .../parameter-tree/parameter-tree.component.ts | 6 +- .../components/property/properties.component.html | 11 +- .../components/property/properties.component.ts | 17 +- .../rest-task-parameters.component.ts | 5 +- .../property/rest-task/rest-task.component.ts | 93 +--- .../sequence-flow/sequence-flow.component.ts | 2 +- .../app/components/toolbar/toolbar.component.css | 120 ++--- .../app/components/toolbar/toolbar.component.html | 191 ++++++- .../app/components/toolbar/toolbar.component.ts | 33 +- .../directive/drag-select/drag-select.directive.ts | 134 ----- .../directive/resizeable/resizable.directive.ts | 42 ++ .../src/app/model/rest-config.ts | 17 + .../src/app/model/topology/node-template.ts | 18 + .../src/app/model/value-source.enum.ts | 2 +- .../src/app/model/workflow/end-event.ts | 4 +- .../src/app/model/workflow/error-event.ts | 18 + .../app/model/workflow/intermediate-catch-event.ts | 5 +- .../src/app/model/workflow/node-type.enum.ts | 8 +- .../src/app/model/workflow/parameter.ts | 2 +- .../src/app/model/workflow/rest-parameter.ts | 4 +- .../src/app/model/workflow/rest-task.ts | 20 +- .../src/app/model/workflow/script-task.ts | 13 +- .../src/app/model/workflow/start-event.ts | 4 +- .../src/app/model/workflow/sub-process.ts | 15 + .../app/model/workflow/timer-event-definition.ts | 12 +- .../src/app/model/workflow/tosca-node-task.ts | 22 + .../src/app/model/workflow/workflow-element.ts | 14 + .../src/app/model/workflow/workflow-node.ts | 10 +- .../src/app/services/broadcast.service.ts | 12 +- .../src/app/services/data-access/mockdata.ts | 2 +- .../src/app/services/jsplumb.service.ts | 589 ++++++++++++++++----- .../src/app/services/model.service.ts | 366 ++++++++++--- .../src/app/services/rest.service.ts | 168 ++++++ .../src/app/services/workflow.service.ts | 2 +- 57 files changed, 2172 insertions(+), 1121 deletions(-) delete mode 100644 sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.css delete mode 100644 sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.html delete mode 100644 sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.ts create mode 100644 sdc-workflow-designer-ui/src/app/components/container/container.component.css create mode 100644 sdc-workflow-designer-ui/src/app/components/container/container.component.html create mode 100644 sdc-workflow-designer-ui/src/app/components/container/container.component.ts create mode 100644 sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.css delete mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menu.component.css delete mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menu.component.html delete mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menu.component.spec.ts delete mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menu.component.ts create mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menus.component.css create mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menus.component.html create mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menus.component.spec.ts create mode 100644 sdc-workflow-designer-ui/src/app/components/menu/menus.component.ts delete mode 100644 sdc-workflow-designer-ui/src/app/directive/drag-select/drag-select.directive.ts create mode 100644 sdc-workflow-designer-ui/src/app/directive/resizeable/resizable.directive.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/rest-config.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/topology/node-template.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/workflow/error-event.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/workflow/sub-process.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/workflow/tosca-node-task.ts create mode 100644 sdc-workflow-designer-ui/src/app/model/workflow/workflow-element.ts create mode 100644 sdc-workflow-designer-ui/src/app/services/rest.service.ts (limited to 'sdc-workflow-designer-ui/src') diff --git a/sdc-workflow-designer-ui/src/app/app.component.css b/sdc-workflow-designer-ui/src/app/app.component.css index fdafa45c..95166937 100644 --- a/sdc-workflow-designer-ui/src/app/app.component.css +++ b/sdc-workflow-designer-ui/src/app/app.component.css @@ -9,19 +9,86 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ - .main-content-wrapper{ + .loading-div{ + position: absolute; + top: 0; + width: 100%; + height: 100%; + background-color: white; +} + +.loading-div div{ + position: relative; + top: calc(50% - 36px); + left: calc(50% - 36px); +} + +.loading-div div:not(:required) { + -moz-animation: three-quarters-loader 1.5s infinite linear; + -webkit-animation: three-quarters-loader 1.5s infinite linear; + animation: three-quarters-loader 1.5s infinite linear; + box-sizing: border-box; + display: inline-block; + overflow: hidden; + text-indent: -9999px; + border: 5px solid #1dadfc; + border-right-color: transparent; + border-radius: 36px; + width: 72px; + height: 72px; +} + +@-moz-keyframes three-quarters-loader { + 0% { + -moz-transform: rotate(0deg); + transform: rotate(0deg) + } + to { + -moz-transform: rotate(1turn); + transform: rotate(1turn) + } +} + +@-webkit-keyframes three-quarters-loader { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg) + } + to { + -webkit-transform: rotate(1turn); + transform: rotate(1turn) + } +} + +@keyframes three-quarters-loader { + 0% { + -moz-transform: rotate(0deg); + -ms-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg) + } + to { + -moz-transform: rotate(1turn); + -ms-transform: rotate(1turn); + -webkit-transform: rotate(1turn); + transform: rotate(1turn) + } +} + +.main-content-wrapper{ height: 100%; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTEgMTEiPjxkZWZzPjxzdHlsZT4uY2xzLTF7aXNvbGF0aW9uOmlzb2xhdGU7fS5jbHMtMntmaWxsOiNmYWZiZmQ7fS5jbHMtM3tmaWxsOiNlY2VkZWY7ZmlsbC1ydWxlOmV2ZW5vZGQ7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5iYWNrZ3JvdW5kLWltYWdlc192MjwvdGl0bGU+PGc+PGltYWdlIHdpZHRoPSIxMSIgaGVpZ2h0PSIxMSIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFBc0FBQUFMQ0FJQUFBQW16dUJ4QUFBQUNYQklXWE1BQUFzU0FBQUxFZ0hTM1g3OEFBQUFFMGxFUVZRWVYyUDRUd2d3RUZJd3FvSmtGUUF3eFdtbDRtUGRyd0FBQUFCSlJVNUVya0pnZ2c9PSIvPjwvZz48ZyBpZD0i55+p5b2iXzEiIGRhdGEtbmFtZT0i55+p5b2iIDEiIGNsYXNzPSJjbHMtMSI+PGcgaWQ9IuefqeW9ol8xLTIiIGRhdGEtbmFtZT0i55+p5b2iIDEiPjxyZWN0IGNsYXNzPSJjbHMtMiIgd2lkdGg9IjExIiBoZWlnaHQ9IjExIi8+PC9nPjwvZz48ZyBjbGFzcz0iY2xzLTEiPjxnPjxwb2x5Z29uIGNsYXNzPSJjbHMtMyIgcG9pbnRzPSIxMCAwIDEwIDEwIDAgMTAgMCAxMSAxMCAxMSAxMC45MiAxMSAxMC45MiAwIDEwIDAiLz48L2c+PC9nPjwvc3ZnPg==); background-size: 11px; } -.toolbar{ +.tool-bar{ position: fixed; top: 0px; left: 0px; width: 200px; height: 100%; background-color: white; + overflow-y: auto; } .design-area{ @@ -32,7 +99,7 @@ padding: 20px; } -.design-menu{ +.design-menus{ display: block; height: 30px; margin-bottom: 10px; diff --git a/sdc-workflow-designer-ui/src/app/app.component.html b/sdc-workflow-designer-ui/src/app/app.component.html index 1917b835..9f0e5cf2 100644 --- a/sdc-workflow-designer-ui/src/app/app.component.html +++ b/sdc-workflow-designer-ui/src/app/app.component.html @@ -11,13 +11,10 @@ * ZTE - initial API and implementation and/or initial documentation */ --> -
- +
- - + +
- -
diff --git a/sdc-workflow-designer-ui/src/app/app.module.ts b/sdc-workflow-designer-ui/src/app/app.module.ts index 199bfcdf..07ccebc0 100644 --- a/sdc-workflow-designer-ui/src/app/app.module.ts +++ b/sdc-workflow-designer-ui/src/app/app.module.ts @@ -15,6 +15,8 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { NgxTreeSelectModule } from 'ngx-tree-select'; +import { AccordionModule } from 'ngx-bootstrap/accordion'; + import { AppComponent } from './app.component'; import { JsPlumbService } from "./services/jsplumb.service"; import { NodeComponent } from "./components/node/node.component"; @@ -29,10 +31,9 @@ import { HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; import { BroadcastService } from "./services/broadcast.service"; import { PropertiesComponent } from "./components/property/properties.component"; -import { CanvasComponent } from "./components/canvas/canvas.component"; import { StartEventParametersComponent } from "./components/property/start-event-parameters/start-event-parameters.component"; import { ParameterComponent } from "./components/parameter/parameter.component"; -import { MenuComponent } from "./components/menu/menu.component"; +import { MenusComponent } from "./components/menu/menus.component"; import { MicroserviceDetailComponent } from "./components/menu/microservice/microservice-detail/microservice-detail.component"; import { MicroserviceComponent } from "./components/menu/microservice/microservice.component"; import { MicroserviceListComponent } from "./components/menu/microservice/microservice-list/microservice-list.component"; @@ -46,18 +47,20 @@ import { SwaggerTreeConverterService } from "./services/swagger-tree-converter.s import { IntermediateCatchEventComponent } from "./components/property/intermediate-catch-event/intermediate-catch-event.component"; import { SequenceFlowComponent } from "./components/sequence-flow/sequence-flow.component"; import { ScriptTaskComponent } from "./components/property/script-task/script-task.component"; -import { DragSelectDirective } from "./directive/drag-select/drag-select.directive"; import { WorkflowsComponent } from "./components/menu/workflows/workflows.component"; import { ModelService } from './services/model.service'; +import { ContainerComponent } from './components/container/container.component'; +import { RestService } from './services/rest.service'; +import { ResizableDirective } from './directive/resizeable/resizable.directive'; @NgModule({ declarations: [ AppComponent, - CanvasComponent, - DragSelectDirective, + ContainerComponent, + ResizableDirective, EditablePropertyComponent, IntermediateCatchEventComponent, - MenuComponent, + MenusComponent, MicroserviceComponent, MicroserviceDetailComponent, MicroserviceListComponent, @@ -74,6 +77,7 @@ import { ModelService } from './services/model.service'; WorkflowsComponent, ], imports: [ + AccordionModule.forRoot(), BrowserAnimationsModule, BrowserModule, HttpModule, @@ -96,6 +100,7 @@ import { ModelService } from './services/model.service'; DataAccessService, HttpService, JsPlumbService, + RestService, SwaggerTreeConverterService, WorkflowConfigService, ModelService, diff --git a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.css b/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.css deleted file mode 100644 index bc889652..00000000 --- a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.css +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ - -.canvas { - -webkit-overflow-scrolling: touch; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - height: 100%; - position: relative; - overflow: scroll; - z-index: 0; - background-color: white; -} diff --git a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.html b/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.html deleted file mode 100644 index daf26bc1..00000000 --- a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.html +++ /dev/null @@ -1,16 +0,0 @@ - -
- -
diff --git a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.ts b/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.ts deleted file mode 100644 index 1cf197df..00000000 --- a/sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ - -import { AfterViewInit, Component, HostListener } from '@angular/core'; - -import { BroadcastService } from '../../services/broadcast.service'; -import { JsPlumbService } from '../../services/jsplumb.service'; -import { ActivatedRoute } from "@angular/router"; -import { DataAccessService } from "../../services/data-access/data-access.service"; -import { WorkflowService } from "../../services/workflow.service"; -import { PlanModel } from "../../model/workflow/plan-model"; -import { ModelService } from "../../services/model.service"; -import { SequenceFlow } from "../../model/workflow/sequence-flow"; -import { WorkflowNode } from "../../model/workflow/workflow-node"; - -/** - * main canvas, it contains two parts: canvas and node property component - * bpmn task nodes can be dropped into this canvas, and then the workflow can be edit - */ -@Component({ - selector: 'b4t-canvas', - styleUrls: ['./canvas.component.css'], - templateUrl: 'canvas.component.html', -}) -export class CanvasComponent implements AfterViewInit { - private currentType: string; // WorkflowNode, SequenceFlow - private currentWorkflowNode: WorkflowNode; - private currentSequenceFlow: SequenceFlow; - - - constructor(private broadcastService: BroadcastService, - private dataAccessService: DataAccessService, - private jsPlumbService: JsPlumbService, - private route: ActivatedRoute, - private workflowService: WorkflowService, - private processService: ModelService) { - } - - ngOnInit(): void { - // this.route.queryParams.subscribe(params => { - // if (params.id) { - // this.dataAccessService.catalogService.loadWorkflow(params.id).subscribe(workflow => { - // this.workflowService.workflow = workflow; - // }); - // } - // }); - } - - public ngAfterViewInit() { - this.jsPlumbService.buttonDroppable(); - this.broadcastService.currentSequenceFlow$.subscribe(sequenceFlow => this.currentSequenceFlow = sequenceFlow); - this.broadcastService.currentWorkflowNode$.subscribe(workflowNode => this.currentWorkflowNode = workflowNode); - this.broadcastService.currentType$.subscribe(type => this.currentType = type); - } - - public canvasClick() { - this.broadcastService.broadcast(this.broadcastService.showProperty, false); - this.broadcastService.broadcast(this.broadcastService.showSequenceFlow, false); - } - - @HostListener('window:keyup.delete', ['$event']) ondelete(event: KeyboardEvent) { - if (this.currentType === 'WorkflowNode') { - this.jsPlumbService.remove(this.currentWorkflowNode.id); - this.processService.deleteNode(this.currentWorkflowNode.id); - } else if (this.currentType === 'SequenceFlow') { - this.processService.deleteSequenceFlow(this.currentSequenceFlow.sourceRef, this.currentSequenceFlow.targetRef); - this.jsPlumbService.deleteConnect(this.currentSequenceFlow.sourceRef, this.currentSequenceFlow.targetRef); - } - } - - - public getWorkflow(): PlanModel { - return this.workflowService.planModel; - } -} diff --git a/sdc-workflow-designer-ui/src/app/components/container/container.component.css b/sdc-workflow-designer-ui/src/app/components/container/container.component.css new file mode 100644 index 00000000..bc889652 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/container/container.component.css @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +.canvas { + -webkit-overflow-scrolling: touch; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + height: 100%; + position: relative; + overflow: scroll; + z-index: 0; + background-color: white; +} diff --git a/sdc-workflow-designer-ui/src/app/components/container/container.component.html b/sdc-workflow-designer-ui/src/app/components/container/container.component.html new file mode 100644 index 00000000..0d9c5222 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/container/container.component.html @@ -0,0 +1,22 @@ + + +
+
+ +
+ + + + diff --git a/sdc-workflow-designer-ui/src/app/components/container/container.component.ts b/sdc-workflow-designer-ui/src/app/components/container/container.component.ts new file mode 100644 index 00000000..f35c2482 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/container/container.component.ts @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +import { AfterViewChecked, AfterViewInit, Component, ElementRef, HostListener, OnInit, OnDestroy, ViewChild } from '@angular/core'; + +import { SequenceFlow } from '../../model/workflow/sequence-flow'; +import { WorkflowElement } from '../../model/workflow/workflow-element'; +import { WorkflowNode } from '../../model/workflow/workflow-node'; +import { BroadcastService } from '../../services/broadcast.service'; +import { JsPlumbService } from '../../services/jsplumb.service'; +import { ModelService } from '../../services/model.service'; + +/** + * main canvas, it contains two parts: canvas and node property component + * bpmn task nodes can be dropped into this canvas, and then the workflow can be edit + */ +@Component({ + selector: 'b4t-container', + templateUrl: 'container.component.html', + styleUrls: ['./container.component.css'] +}) +export class ContainerComponent implements AfterViewChecked, AfterViewInit, OnInit, OnDestroy { + public allNotes: WorkflowNode[]; + @ViewChild('nodeSelector') nodeSelector: ElementRef; + @ViewChild('mainContainer') mainContainer: ElementRef; + + private isSelecting = false; + private selectedElements: WorkflowElement[] = []; + private showProperties = false; + private needInitSequence = false; + + constructor(private broadcastService: BroadcastService, private jsPlumbService: JsPlumbService, + public modelService: ModelService) { + } + + @HostListener('window:keyup.delete', ['$event']) ondelete(event: KeyboardEvent) { + if (this.showProperties || 0 >= this.selectedElements.length) { + return; + } + this.selectedElements.forEach(element => { + if (this.modelService.isNode(element)) { + let selectNode = element as WorkflowNode; + const parentId = this.jsPlumbService.getParentNodeId(selectNode.id); + this.jsPlumbService.remove(selectNode); + this.modelService.deleteNode(parentId, selectNode.id); + } else { + let sequenceFlow = element as SequenceFlow; + this.modelService.deleteConnection(sequenceFlow.sourceRef, sequenceFlow.targetRef); + this.jsPlumbService.deleteConnect(sequenceFlow.sourceRef, sequenceFlow.targetRef); + } + }); + this.selectedElements = []; + } + + @HostListener('document:mouseup', ['$event']) onmouseup() { + if (this.isSelecting) { + this.nodeSelector.nativeElement.style.display = 'none'; + this.mainContainer.nativeElement.onmousemove = null; + this.isSelecting = false; + this.broadcastService.broadcast(this.broadcastService.showProperty, null); + this.broadcastService.broadcast(this.broadcastService.selectedElement, this.selectedElements); + } + } + + public ngOnInit() { + this.jsPlumbService.initJsPlumbInstance(this.modelService.rootNodeId); + this.broadcastService.planModel$.subscribe(() => { + this.needInitSequence = true; + }); + this.broadcastService.showProperty$.subscribe(element=>{ + this.showProperties = null !== element; + }); + } + + public ngAfterViewInit() { + this.jsPlumbService.canvasDroppable(); + this.broadcastService.selectedElement$.subscribe(elements => { + if (elements) { + this.selectedElements = elements; + } else { + this.selectedElements = []; + } + }); + } + + public ngAfterViewChecked() { + if (this.needInitSequence) { + this.needInitSequence = false; + // Add the connection + this.jsPlumbService.connectChildrenNodes(this.modelService.rootNodeId); + } + } + + public ngOnDestroy() { + if (this.mainContainer.nativeElement.onmousemove) { + this.mainContainer.nativeElement.document.onmousemove = null; + } + } + + public canvasMouseDown(event) { + this.selectedElements = []; + this.isSelecting = true; + let posx = event.clientX + this.mainContainer.nativeElement.scrollLeft; + posx = 220 > posx ? 0 : posx - 220; + let posy = event.clientY + this.mainContainer.nativeElement.scrollTop; + posy = 60 > posy ? 0 : posy - 60; + let element = this.nodeSelector.nativeElement; + element.style.left = posx + "px"; + element.style.top = posy + "px"; + element.style.width = '0px'; + element.style.height = '0px'; + element.style.display = 'block'; + let curThis = this; + this.mainContainer.nativeElement.onmousemove = function (moveEvent) { + let movePosx = moveEvent.clientX + curThis.mainContainer.nativeElement.scrollLeft; + movePosx = 220 > movePosx ? 0 : movePosx - 220; + let movePosy = moveEvent.clientY + curThis.mainContainer.nativeElement.scrollTop; + movePosy = 60 > movePosy ? 0 : movePosy - 60; + const left = Math.min(movePosx, posx); + const top = Math.min(movePosy, posy); + const width = Math.abs(posx - movePosx); + const height = Math.abs(posy - movePosy); + element.style.left = left + "px"; + element.style.top = top + "px"; + element.style.width = width + "px"; + element.style.height = height + "px"; + curThis.selectNodes(left, top, width, height); + }; + } + + private selectNodes(left: number, top: number, width: number, height: number) { + this.selectedElements = []; + const allNodes = this.modelService.getNodes(); + allNodes.forEach(node => { + const np = node.position; + let selected = false; + if (left < np.left) { + if ((top < np.top && left + width > np.left && top + height > np.top) + || (top >= np.top && top < np.top + np.height && left + width > np.left)) { + selected = true; + } + } else if (left < np.left + np.width) { + if ((top < np.top && top + height > np.top) + || (top >= np.top && top < np.top + np.height)) { + selected = true; + } + } + if (selected) { + this.selectedElements.push(node); + } + }); + this.broadcastService.broadcast(this.broadcastService.selectedElement, this.selectedElements); + } + +} diff --git a/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.css b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.css new file mode 100644 index 00000000..78475cfa --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.css @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + + .edit{ + font-size: 24px; + width: 300px; + height: 30px; + border: 1px solid #fff; +} + +.edit:hover{ + border-color: #80bdff; +} + +.edit:focus{ + border-color: #80bdff; +} diff --git a/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.html b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.html index a2d9fd51..8dde9f1c 100644 --- a/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.html +++ b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.html @@ -1,25 +1,5 @@ - - - {{parameter.value}} - - - - - - - - - - + + diff --git a/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.ts b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.ts index 719d2a60..ea965755 100644 --- a/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/editable-property/editable-property.component.ts @@ -10,41 +10,44 @@ * ZTE - initial API and implementation and/or initial documentation */ -import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; - -import { ValueSource } from '../../model/value-source.enum'; -import { ValueType } from '../../model/value-type.enum'; -import { Parameter} from '../../model/workflow/parameter'; -import { PlanTreeviewItem } from "../../model/plan-treeview-item"; +import { Component, EventEmitter, Input, Output } from '@angular/core'; /** - * property component presents information of a workflow node. - * the presented information can be edit in this component. - * it may load information dynamically. the content may be different for different node type. + * node or workflow-line name */ @Component({ selector: 'b4t-editable-property', templateUrl: 'editable-property.component.html', + styleUrls: ['./editable-property.component.css'] }) export class EditablePropertyComponent { - @Input() public parameter: Parameter; - @Input() public planItems: PlanTreeviewItem[]; - @Input() public showLabel: boolean; - @Input() public valueSource: ValueSource[]; - @Output() public parameterChange = new EventEmitter(); + @Input() public name: string; + @Output() public nameChange = new EventEmitter(); + + public showEdit = false; + public isEditing = false; - private editing = false; + public showEditComponent(isShow: boolean): void { + if(isShow){ + this.showEdit = isShow; + }else{ + if(!this.isEditing){ + this.showEdit = false; + } + } + } - public isEditing(): boolean { - return this.editing; + public startEdit(): void { + this.isEditing = true; } - public startEdit() { - this.editing = true; + public stopEdit(): void { + this.isEditing = false; + this.showEdit = false; } - public completeEdit() { - this.editing = false; - this.parameterChange.emit(this.parameter); + public change(newName: string) { + this.name = newName; + this.nameChange.emit(this.name); } } diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.css b/sdc-workflow-designer-ui/src/app/components/menu/menu.component.css deleted file mode 100644 index 6ba4133b..00000000 --- a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.css +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ - -.btn-right{ - float: right; -} - -.btn-left{ - float: left; -} - -button i{ - padding-right: 3px; -} diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.html b/sdc-workflow-designer-ui/src/app/components/menu/menu.component.html deleted file mode 100644 index 8cf9dc57..00000000 --- a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
- -
-
- - - - -
- - diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.spec.ts b/sdc-workflow-designer-ui/src/app/components/menu/menu.component.spec.ts deleted file mode 100644 index b80edce7..00000000 --- a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MenuComponent } from './menu.component'; - -describe('MenuComponent', () => { - let component: MenuComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [MenuComponent] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MenuComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.ts b/sdc-workflow-designer-ui/src/app/components/menu/menu.component.ts deleted file mode 100644 index adad16c1..00000000 --- a/sdc-workflow-designer-ui/src/app/components/menu/menu.component.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ -import { Component, OnInit, ViewChild } from '@angular/core'; - -import { WorkflowService } from '../../services/workflow.service'; -import { MicroserviceComponent } from "./microservice/microservice.component"; -import { WorkflowsComponent } from "./workflows/workflows.component"; -import { BroadcastService } from "../../services/broadcast.service"; -import { PlanModel } from "../../model/workflow/plan-model"; - -@Component({ - selector: 'b4t-menu', - templateUrl: './menu.component.html', - styleUrls: ['./menu.component.css'] -}) -export class MenuComponent { - @ViewChild(MicroserviceComponent) public microserviceComponent: MicroserviceComponent; - @ViewChild(WorkflowsComponent) public workflowsComponent: WorkflowsComponent; - public currentWorkflow = 'Workflows'; - public workflows = []; - - constructor(private broadcastService: BroadcastService, private workflowService: WorkflowService) { - this.broadcastService.workflows.subscribe(wfs => { - this.workflows.splice(0, this.workflows.length); - if(wfs) { - wfs.forEach((value, key, map) => { - this.workflows.push({label: value.planName, command: () => { - this.workflowSelected(value.planName, value.plan); - }}); - }); - } - }); - } - - public save(): void { - this.workflowService.save(); - } - - public showMicroserviceModal(): void { - this.microserviceComponent.show(); - } - - public test() { - } - - public showWorkflows() { - this.workflowsComponent.show(); - } - - public getWorkflows() { - const workflows = this.workflowService.getWorkflows(); - if(workflows) { - const options = []; - workflows.forEach((value, key, map) => { - options.push({label: value.planName, command: () => { - this.workflowSelected(value.planName, value.plan); - }}); - }); - return options; - } else { - return []; - } - } - - public workflowSelected(planName: string, workflow: PlanModel) { - this.currentWorkflow = planName; - this.broadcastService.broadcast(this.broadcastService.workflow, workflow); - } - - public download() { - const filename = this.currentWorkflow + '.json'; - const content = JSON.stringify(this.workflowService.planModel); - var eleLink = document.createElement('a'); - eleLink.download = filename; - eleLink.style.display = 'none'; - var blob = new Blob([content]); - eleLink.href = URL.createObjectURL(blob); - document.body.appendChild(eleLink); - eleLink.click(); - document.body.removeChild(eleLink); - } -} diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menus.component.css b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.css new file mode 100644 index 00000000..6ba4133b --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.css @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +.btn-right{ + float: right; +} + +.btn-left{ + float: left; +} + +button i{ + padding-right: 3px; +} diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menus.component.html b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.html new file mode 100644 index 00000000..8cf9dc57 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.html @@ -0,0 +1,31 @@ + + +
+ +
+
+ + + + +
+ + diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menus.component.spec.ts b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.spec.ts new file mode 100644 index 00000000..b80edce7 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.spec.ts @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MenuComponent } from './menu.component'; + +describe('MenuComponent', () => { + let component: MenuComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [MenuComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/sdc-workflow-designer-ui/src/app/components/menu/menus.component.ts b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.ts new file mode 100644 index 00000000..6932e764 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/components/menu/menus.component.ts @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { Component, OnInit, ViewChild } from '@angular/core'; + +import { WorkflowService } from '../../services/workflow.service'; +import { MicroserviceComponent } from "./microservice/microservice.component"; +import { WorkflowsComponent } from "./workflows/workflows.component"; +import { BroadcastService } from "../../services/broadcast.service"; +import { PlanModel } from "../../model/workflow/plan-model"; + +@Component({ + selector: 'menus', + templateUrl: './menus.component.html', + styleUrls: ['./menus.component.css'] +}) +export class MenusComponent { + @ViewChild(MicroserviceComponent) public microserviceComponent: MicroserviceComponent; + @ViewChild(WorkflowsComponent) public workflowsComponent: WorkflowsComponent; + public currentWorkflow = 'Workflows'; + public workflows = []; + + constructor(private broadcastService: BroadcastService, private workflowService: WorkflowService) { + this.broadcastService.workflows.subscribe(wfs => { + this.workflows.splice(0, this.workflows.length); + if(wfs) { + wfs.forEach((value, key, map) => { + this.workflows.push({label: value.planName, command: () => { + this.workflowSelected(value.planName, value.plan); + }}); + }); + } + }); + } + + public save(): void { + this.workflowService.save(); + } + + public showMicroserviceModal(): void { + this.microserviceComponent.show(); + } + + public test() { + } + + public showWorkflows() { + this.workflowsComponent.show(); + } + + public getWorkflows() { + const workflows = this.workflowService.getWorkflows(); + if(workflows) { + const options = []; + workflows.forEach((value, key, map) => { + options.push({label: value.planName, command: () => { + console.log(`${value.planName} selected`); + this.workflowSelected(value.planName, value.plan); + }}); + }); + return options; + } else { + return []; + } + } + + public workflowSelected(planName: string, workflow: PlanModel) { + this.currentWorkflow = planName; + this.broadcastService.broadcast(this.broadcastService.planModel, workflow); + } + + public download() { + const filename = this.currentWorkflow + '.json'; + const content = JSON.stringify(this.workflowService.planModel); + var eleLink = document.createElement('a'); + eleLink.download = filename; + eleLink.style.display = 'none'; + var blob = new Blob([content]); + eleLink.href = URL.createObjectURL(blob); + document.body.appendChild(eleLink); + eleLink.click(); + document.body.removeChild(eleLink); + } +} diff --git a/sdc-workflow-designer-ui/src/app/components/node/node.component.css b/sdc-workflow-designer-ui/src/app/components/node/node.component.css index 093892e4..af1ce88e 100644 --- a/sdc-workflow-designer-ui/src/app/components/node/node.component.css +++ b/sdc-workflow-designer-ui/src/app/components/node/node.component.css @@ -11,30 +11,23 @@ */ .node { - border: 1px solid transparent; cursor: pointer; display: inline-block; position: absolute; z-index: 2; } +.node-icon{ + border-radius: 4px; +} -.node.active { - border: 2px solid red !important; - box-shadow: 2px 2px 19px #444; - -o-box-shadow: 2px 2px 19px #444; - -webkit-box-shadow: 2px 2px 19px #444; - -moz-box-shadow: 2px 2px 19px #fff; - opacity: 0.9; +.node-icon svg{ + display: block; + fill: #00ABFF; } -.node:hover { - border: 1px solid #123456; - box-shadow: 2px 2px 19px #444; - -o-box-shadow: 2px 2px 19px #444; - -webkit-box-shadow: 2px 2px 19px #444; - -moz-box-shadow: 2px 2px 19px #fff; - opacity: 0.9; +.active { + outline: 1px solid #00ABFF; } /** @@ -43,11 +36,10 @@ .anchors { position: absolute; border-radius: 1em; - z-index: 20; display: none; - background-color: black; - width: 0; - height: 0; + background-color: #2e6f9a; + width: 12px; + height: 12px; cursor: pointer; -ms-transition: all 0.15s ease-in-out; transition: all 0.15s ease-in-out; @@ -56,35 +48,31 @@ -o-transition: all 0.15s ease-in-out; } -.node:hover .anchors { - background-color: black; +.node-icon:hover > .anchors { display: inline-block; - width: 12px; - height: 12px; - z-index: 20; } .anchor-left { - left: -5px; - top: 40%; + left: -6px; + top: calc(50%); } .anchor-right { - right: -5px; - top: 40%; + right: -6px; + top: calc(50%); } .anchor-top { - top: -5px; - left: 40%; + top: -6px; + left: calc(50% - 6px); } .anchor-bottom { - bottom: -5px; - left: 40%; + bottom: -6px; + left: calc(50% - 6px); } -/*right-arrow*/ +/*right arrow*/ .right { width: 10px; height: 10px; @@ -104,7 +92,7 @@ border-top: 5px transparent dashed; border-right: 5px transparent dashed; border-bottom: 5px transparent dashed; - border-left: 5px black solid; + border-left: 5px #2e6f9a solid; overflow: hidden; } @@ -117,7 +105,7 @@ left: -2px; } -/*left-arrow*/ +/*left arrow */ .left { width: 10px; height: 10px; @@ -134,11 +122,11 @@ position: absolute; left: 0; top: 0; - z-index: 5; + z-index: 5; /*ie8-*/ border-top: 5px transparent dashed; border-left: 5px transparent dashed; border-bottom: 5px transparent dashed; - border-right: 5px black solid; + border-right: 5px #2e6f9a solid; overflow: hidden; } @@ -150,10 +138,10 @@ left: 2px; } -/*top-arrow*/ +/*top arrow*/ .top { - width: 9px; - height: 9px; + width: 10px; + height: 10px; position: absolute; left: 1px; z-index: 2; @@ -167,7 +155,7 @@ left: 0; top: 0; z-index: 5; - border-bottom: 5px black solid; + border-bottom: 5px #2e6f9a solid; border-left: 5px transparent dashed; border-right: 5px transparent dashed; border-top: 5px transparent dashed; @@ -180,13 +168,13 @@ .top-arrow2 { top: -2px; - border-bottom: 4px white solid; + border-bottom: 5px white solid; } -/*bottom-arrow*/ +/*bottom arrow*/ .bottom { - width: 9px; - height: 9px; + width: 10px; + height: 10px; position: absolute; left: 1px; top: 4px; @@ -201,10 +189,10 @@ left: 0; top: 0; z-index: 5; - border-bottom: 4px transparent dashed; - border-left: 4px transparent dashed; - border-right: 4px transparent dashed; - border-top: 4px black solid; + border-bottom: 5px transparent dashed; + border-left: 5px transparent dashed; + border-right: 5px transparent dashed; + border-top: 5px #2e6f9a solid; overflow: hidden; } @@ -214,77 +202,27 @@ } .bottom-arrow2 { - border-top: 4px white solid; + border-top: 5px white solid; } +/** + * Anchors End + */ .node .name { - padding: 10px 15px; -} - -.node:hover { - border: 1px dotted #000; -} - -.node.focus { - border: 1px dotted red; -} - -.startEvent { - border-radius: 30px; - border: 1px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - /*background-image: url("data:image/png;base64,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");*/ -} - -.endEvent { - border-radius: 30px; - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - /*background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAQFJREFUeNrs2MENgyAUxvFn0wUcwRHeAuoKjuAIbiBOpCO4gU6hR5yAHkgaoxUsBWOa7x2VwC//i8RIKUX3mwfdcsACCyywwAILLD1Pw7umaQKdmud5mqamFep42raN49i7iZmnaVLGIfNrKWVRFB5NdV2rE2NiLcviMRszD8OgN5zn2Z2VJEnf916yrSMJIYQQ7iy9Y1VVv2RbRxrHkZmJyAOLiJyzbSK9n/thOWT7GCkI63y2o0ihWNZs5khhWUfZrJGCs/bZpJTWSBexNtmska5j6SnLsus6a6SrWd+OlYVrIFi4y68/bYFOzbLMvCDCT0qwwAILLLDAAutfWK8BANHUM0rzFI9RAAAAAElFTkSuQmCC");*/ -} - -.intermediateCatchEvent { - border-radius: 30px; - border: 1px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - background-image: url("data:image/svg+xml;utf8, "); -} - - -.scriptTask { - border-radius: 8px; - border: 2px solid rgb(0, 0, 0); - height: 60px; - width: 80px; - background-image: url("data:image/svg+xml;utf8, "); -} - -.restTask { - border-radius: 8px; - border: 2px solid rgb(0, 0, 0); - font-size: 10px; + width: 55px; + height: 12px; + text-align: center; + white-space: nowrap; + color: #5c6d90; + line-height: 12px; + cursor: pointer; + font-family: Arial; + font-size: 12px; } -.parallelGateway { - transform: rotate(45deg); - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuND6NzHYAAAEASURBVGhD7ZXRDcIwDEQ7AiMwQkdiQ0ZgBEbpCCWRiBRVob5zbaDSIeUD9WzfvSruNOknAiIgAiIgAiIgAiIgAiLwQwKXMvtezkx48NQQ7XFpNfIsZy1nAUN4anBHhLI3UgMgITw1hCVOOjKzF4LVc26catQUqnPaOFZmmbOeH5seVL1nsl3ydk+QuxJki2vzKURv/G/Nt6hWCHTVcuiC1df3St2Sr/9vwbPC2536DVjm0Y9dOFWk4am3kLXnrecIoDQNag7VpRkdNWZNsfr0MCND1p731KQG6Q1Z5kcfO7QmPcSjTJiJKTU4W0O0l1QEREAEREAEREAEREAEvkHgBRtRrTMkpctqAAAAAElFTkSuQmCC"); +.resizeable { + background-color: darkolivegreen; + border:1px solid blue; + margin: 10px; } -.exclusiveGateway { - transform: rotate(45deg); - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuND6NzHYAAAC4SURBVGhD7ZXRCcAgEEMdpSN0hI7WTTpKR+hIrZ9yIBi4SIUn+CGc0bwoVwoDAhCAAAQgAAEIQMBB4K6i7dwdhzg13yrezsN5mEMbAw6qiiYJKLQctSTgoKpokoBCS6mNHba3jgk8oTP39tk7drxY9tresbMvPP2vLG/grG95ZEaj1+C+TfmQztrpTyPbDAayiap6JKASy64ngWyiqh4JqMSy62O3/k2HzTaKHgQgAAEIQAACyxL4AOr3u2BKXQ3gAAAAAElFTkSuQmCC"); -} diff --git a/sdc-workflow-designer-ui/src/app/components/node/node.component.html b/sdc-workflow-designer-ui/src/app/components/node/node.component.html index d4c59d68..1832944b 100644 --- a/sdc-workflow-designer-ui/src/app/components/node/node.component.html +++ b/sdc-workflow-designer-ui/src/app/components/node/node.component.html @@ -11,15 +11,15 @@ * ZTE - initial API and implementation and/or initial documentation */ --> -
-
- {{getDisplayName()}} -
+
+ +
{{node.name}}
+
+
@@ -32,16 +32,118 @@
-
- - - +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
-
- - - +
+ + +
+
diff --git a/sdc-workflow-designer-ui/src/app/components/node/node.component.ts b/sdc-workflow-designer-ui/src/app/components/node/node.component.ts index 5fe189db..e688e973 100644 --- a/sdc-workflow-designer-ui/src/app/components/node/node.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/node/node.component.ts @@ -9,16 +9,19 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ +import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core'; -import { Component, AfterViewInit, Input, OnDestroy } from '@angular/core'; - +import { Subscription } from 'rxjs/Subscription'; +import { SubProcess } from '../../model/workflow/sub-process'; +import { WorkflowNode } from '../../model/workflow/workflow-node'; +import { BroadcastService } from '../../services/broadcast.service'; import { JsPlumbService } from '../../services/jsplumb.service'; -import { BroadcastService } from "../../services/broadcast.service"; -import { WorkflowNode } from "../../model/workflow/workflow-node"; -import { Subscription } from "rxjs/Subscription"; +import { ModelService } from '../../services/model.service'; +import { NodeType } from '../../model/workflow/node-type.enum'; /** - * workflow node component + * node component represent a single workflow node. + * every node would be rendered on the container component */ @Component({ selector: 'b4t-node', @@ -26,61 +29,85 @@ import { Subscription } from "rxjs/Subscription"; templateUrl: 'node.component.html', }) export class NodeComponent implements AfterViewInit, OnDestroy { - @Input() public node: WorkflowNode; - @Input() public last: boolean; + @Input() public rank: number; + @ViewChild('nodeItem') nodeItem: ElementRef; + public nodeType = NodeType; public active = false; - private currentTypeSubscription: Subscription; private currentWorkflowSubscription: Subscription; + private isMoving = false; - constructor(private broadcastService: BroadcastService, - private jsPlumbService: JsPlumbService) { - + constructor(private jsPlumbService: JsPlumbService, + private modelService: ModelService, + private broadcastService: BroadcastService) { } - ngAfterViewInit(): void { - if(this.last) { - this.jsPlumbService.initNode(); - this.jsPlumbService.connectNodes(); - } + public ngAfterViewInit() { + this.jsPlumbService.initJsPlumbInstance(this.node.parentId); + this.jsPlumbService.initNode(this.node); - this.currentTypeSubscription = this.broadcastService.currentType$.subscribe(type => { - if (type === 'SequenceFlow') { - this.active = false; - } - }); + if (this.canHaveChildren()) { + this.jsPlumbService.nodeDroppable(this.node, this.rank); + this.jsPlumbService.connectChildrenNodes(this.node.id); + } - this.currentWorkflowSubscription = this.broadcastService.currentWorkflowNode$.subscribe(activeNode => { - if (activeNode.id === this.node.id) { - this.active = true; - } else { - this.active = false; + this.currentWorkflowSubscription = this.broadcastService.selectedElement$.subscribe(activeNodes => { + let active = false; + for (let index = 0; index < activeNodes.length; index++) { + let activeNode = activeNodes[index] as WorkflowNode; + if (activeNode.id === this.node.id) { + active = true; + break; + } } + this.active = active; }); } public ngOnDestroy() { - this.currentTypeSubscription.unsubscribe(); this.currentWorkflowSubscription.unsubscribe(); + if (this.nodeItem.nativeElement.onmousemove) { + this.nodeItem.nativeElement.onmousemove = null; + } } - public showProperties() { - this.broadcastService.broadcast(this.broadcastService.nodeProperty, this.node); - this.broadcastService.broadcast(this.broadcastService.showProperty, true); + public onMousedown() { + let currentThis = this; + this.nodeItem.nativeElement.onmousemove = function () { + currentThis.isMoving = true; + }; } - public getDisplayName(): string { - if (this.node.type === 'restTask' || this.node.type === 'toscaTask') { - return this.node.name; - } else { - return ' '; + public onClick(event) { + if (this.nodeItem.nativeElement.onmousemove) { + this.nodeItem.nativeElement.onmousemove = null; + } + if (this.isMoving && this.active) { + this.isMoving = false; + return; } + event.stopPropagation(); + this.broadcastService.broadcast(this.broadcastService.showProperty, null); + this.broadcastService.broadcast(this.broadcastService.selectedElement, [this.node]); + } + + public canHaveChildren(): boolean { + return this.node.type === 'subProcess'; } - public onSelected() { - this.broadcastService.broadcast(this.broadcastService.currentWorkflowNode, this.node); - this.broadcastService.broadcast(this.broadcastService.currentType, 'WorkflowNode'); + public onMouseOut(event, target) { + event.stopPropagation(); + target.classList.remove('hover'); } + public onMouseOver(event, target) { + event.stopPropagation(); + target.classList.add('hover'); + } + + public showProperties(event) { + event.stopPropagation(); + this.broadcastService.broadcast(this.broadcastService.showProperty, this.node); + } } diff --git a/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts b/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts index 9271dac8..77da46b7 100644 --- a/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/parameter-tree/parameter-tree.component.ts @@ -22,6 +22,7 @@ import { SwaggerTreeConverterService } from '../../services/swagger-tree-convert import { WorkflowUtil } from '../../util/workflow-util'; import { Swagger } from "../../model/swagger"; import { WorkflowConfigService } from "../../services/workflow-config.service"; +import { RestService } from '../../services/rest.service'; /** * parameter tree presents parameter of task node's input and output parameters. @@ -37,8 +38,9 @@ export class ParameterTreeComponent implements OnChanges { @Input() public defaultValueSource: string; @Input() public valueSource: ValueSource[]; @Input() public planItems: PlanTreeviewItem[]; + @Input() public restConfigId: string; - constructor(private restService: WorkflowConfigService, private swaggerTreeConverterService: SwaggerTreeConverterService) { } + constructor(private restService: RestService, private swaggerTreeConverterService: SwaggerTreeConverterService) { } public ngOnChanges(changes: SimpleChanges) { // const changeParameters = changes['parameters']; @@ -81,7 +83,7 @@ export class ParameterTreeComponent implements OnChanges { } private getSwagger(): Swagger { - return this.restService.getSwaggerInfo(this.task.serviceName, this.task.serviceVersion); + return this.restService.getSwaggerInfo(this.restConfigId); } public getKeyParameter(node: any) { diff --git a/sdc-workflow-designer-ui/src/app/components/property/properties.component.html b/sdc-workflow-designer-ui/src/app/components/property/properties.component.html index 2870a4b1..19d0dce1 100644 --- a/sdc-workflow-designer-ui/src/app/components/property/properties.component.html +++ b/sdc-workflow-designer-ui/src/app/components/property/properties.component.html @@ -14,19 +14,12 @@
-
-

{{node.name}}

-
-
- -
- +
-
-

diff --git a/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts b/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts index 2091d83c..d3a6a416 100644 --- a/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/property/properties.component.ts @@ -35,8 +35,8 @@ export class PropertiesComponent implements AfterViewInit { public planItems: PlanTreeviewItem[]; constructor(private broadcastService: BroadcastService, - private jsPlumnService: JsPlumbService, - private processService: ModelService) { + private jsPlumbService: JsPlumbService, + private modelService: ModelService) { } @@ -44,19 +44,14 @@ export class PropertiesComponent implements AfterViewInit { this.broadcastService.showProperty$.subscribe(show => this.show = show); this.broadcastService.nodeProperty$.subscribe(node => { this.node = node; - this.planItems = this.processService.getPlanParameters(this.node.id); + this.planItems = this.modelService.getPlanParameters(this.node.id); }); } - public nodeNameChanged() { - this.titleEditing = !this.titleEditing; - this.jsPlumnService.jsplumbInstance.repaintEverything(); - } - public deleteNode() { this.show = false; - - this.jsPlumnService.remove(this.node.id); - this.processService.deleteNode(this.node.id); + const parentId = this.jsPlumbService.getParentNodeId(this.node.id); + this.jsPlumbService.remove(this.node); + this.modelService.deleteNode(parentId, this.node.id); } } diff --git a/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task-parameters/rest-task-parameters.component.ts b/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task-parameters/rest-task-parameters.component.ts index 7f8bbf43..8e8cc94f 100644 --- a/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task-parameters/rest-task-parameters.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task-parameters/rest-task-parameters.component.ts @@ -21,6 +21,7 @@ import { ValueSource } from "../../../../model/value-source.enum"; import { SwaggerTreeConverterService } from "../../../../services/swagger-tree-converter.service"; import { PlanTreeviewItem } from "../../../../model/plan-treeview-item"; import { WorkflowConfigService } from "../../../../services/workflow-config.service"; +import { RestService } from '../../../../services/rest.service'; /** * property component presents information of a workflow node. @@ -44,7 +45,7 @@ export class RestTaskParametersComponent implements OnInit { private index = 1; constructor(private broadcastService: BroadcastService, - private workflowConfigService: WorkflowConfigService, + private restService: RestService, private swaggerTreeConverterService: SwaggerTreeConverterService) { } @@ -62,7 +63,7 @@ export class RestTaskParametersComponent implements OnInit { this.task.parameters.forEach(param => { if (param.position === 'body') { const requestTreeNode = this.swaggerTreeConverterService - .schema2TreeNode(this.workflowConfigService.getSwaggerInfo(this.task.serviceName, this.task.serviceVersion), 'Request Param', param.schema, param.value); + .schema2TreeNode(this.restService.getSwaggerInfo(this.task.restConfigId), 'Request Param', param.schema, param.value); param.value = requestTreeNode.value; param.value = param.schema.value; this.bodyParameter.push(requestTreeNode); diff --git a/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task.component.ts b/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task.component.ts index d0c92dfd..eb1c81bd 100644 --- a/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/property/rest-task/rest-task.component.ts @@ -9,91 +9,61 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation *******************************************************************************/ -import { AfterViewInit, Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { Subscription } from 'rxjs/Subscription'; +import { PlanTreeviewItem } from '../../../model/plan-treeview-item'; import { Swagger, SwaggerMethod, SwaggerParameter, SwaggerResponse } from '../../../model/swagger'; import { ValueSource } from '../../../model/value-source.enum'; import { ValueType } from '../../../model/value-type.enum'; +import { RestParameter } from '../../../model/workflow/rest-parameter'; import { RestTask } from '../../../model/workflow/rest-task'; import { BroadcastService } from '../../../services/broadcast.service'; -import { WorkflowConfigService } from '../../../services/workflow-config.service'; -import { Microservice } from "../../../model/workflow/microservice"; -import { WorkflowUtil } from "../../../util/workflow-util"; -import { RestParameter } from "../../../model/workflow/rest-parameter"; -import { PlanTreeviewItem } from "../../../model/plan-treeview-item"; +import { RestService } from '../../../services/rest.service'; +import { WorkflowUtil } from '../../../util/workflow-util'; @Component({ selector: 'b4t-rest-task', templateUrl: 'rest-task.component.html', }) -export class RestTaskComponent implements AfterViewInit, OnInit { +export class RestTaskComponent implements OnInit { @Input() public node: RestTask; @Input() public planItems: PlanTreeviewItem[]; - public swaggerJson: any = {}; public restInterfaces: any[]; public restOperations: any = []; - public microservices: Microservice[]; - public selectedMicroservice: Microservice; private swagger: Swagger; - constructor(private broadcastService: BroadcastService, - private configService: WorkflowConfigService) { } - - ngOnInit(): void { - this.microservices = this.configService.getMicroservices(); - this.selectedMicroservice = this.microservices.find(service => - (this.node.serviceName === service.name && this.node.serviceVersion === service.version)); - } - public ngAfterViewInit() { - setTimeout(() => { - this.loadInterfaces(); - this.notifyTaskChanged(); - }, 0); - } - - private notifyTaskChanged() { - this.broadcastService.broadcast(this.broadcastService.nodeTaskChange, this.node); - } + constructor(private broadcastService: BroadcastService, public restService: RestService) { } - public getText4Microservice(microservice: Microservice): string { - return `${microservice.name} [${microservice.version}] `; + public ngOnInit() { + this.loadInterfaces(); } - public serviceChanged(service: Microservice) { - this.selectedMicroservice = service; - this.node.serviceName = service.name; - this.node.serviceVersion = service.version; - this.urlChanged(''); + public serviceChanged(configId: string) { + this.node.restConfigId = configId; + this.pathChanged(''); this.loadInterfaces(); } - public urlChanged(url: string) { - this.node.url = url; - + public pathChanged(path: string) { + this.node.path = path; this.node.consumes = []; this.node.produces = []; this.methodChanged(''); - this.loadOperations(); } public methodChanged(method: string) { this.node.method = method; - this.node.parameters = []; this.node.responses = []; - this.updateMethodInfo(); - - this.notifyTaskChanged(); } - private loadInterfaces() { - if (this.node.serviceName && this.node.serviceVersion) { - this.swagger = this.configService.getSwaggerInfo(this.node.serviceName, this.node.serviceVersion); + if (this.node.restConfigId) { + this.swagger = this.restService.getSwaggerInfo(this.node.restConfigId); if (this.swagger) { this.restInterfaces = []; @@ -101,15 +71,13 @@ export class RestTaskComponent implements AfterViewInit, OnInit { this.restInterfaces.push(key); } this.loadOperations(); - } else { - // TODO error handler } } } private loadOperations() { - if (this.node.url) { - const swaggerPath: any = this.swagger.paths[this.node.url]; + if (this.node.path) { + const swaggerPath: any = this.swagger.paths[this.node.path]; this.restOperations = []; for (const key of Object.keys(swaggerPath)) { @@ -120,34 +88,23 @@ export class RestTaskComponent implements AfterViewInit, OnInit { private updateMethodInfo() { if (this.node.method) { - const path: any = this.swagger.paths[this.node.url]; + const path: any = this.swagger.paths[this.node.path]; const method: SwaggerMethod = path[this.node.method]; this.node.consumes = WorkflowUtil.deepClone(method.consumes); this.node.produces = WorkflowUtil.deepClone(method.produces); - // request parameters + let tempParameters: RestParameter[] = []; method.parameters.forEach(param => { const nodeParam = new RestParameter(param.name, '', ValueSource[ValueSource.String], - param.type, param.position, param.schema); - this.node.parameters.push(nodeParam); + ValueType[ValueType.String], param.position, param.schema, param.required); + tempParameters.push(WorkflowUtil.deepClone(nodeParam)); }); + this.node.parameters = tempParameters; - // response parameters - const responseParams = this.getResponseParameters(method.responses); + const responseParams = this.restService.getResponseParameters( + this.swagger, this.node.path, this.node.method); this.node.responses = responseParams.map(param => WorkflowUtil.deepClone(param)); } } - - private getResponseParameters(responses: any) { - let response: SwaggerResponse = null; - - for (const key of Object.keys(responses)) { - if (key.startsWith('20')) { - response = responses[key]; - } - } - - return [response]; - } } diff --git a/sdc-workflow-designer-ui/src/app/components/sequence-flow/sequence-flow.component.ts b/sdc-workflow-designer-ui/src/app/components/sequence-flow/sequence-flow.component.ts index c4a70ec9..b114d0ae 100644 --- a/sdc-workflow-designer-ui/src/app/components/sequence-flow/sequence-flow.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/sequence-flow/sequence-flow.component.ts @@ -51,7 +51,7 @@ export class SequenceFlowComponent implements AfterViewInit { public delete() { this.show = false; - this.processService.deleteSequenceFlow(this.sequenceFlow.sourceRef, this.sequenceFlow.targetRef); + this.processService.deleteConnection(this.sequenceFlow.sourceRef, this.sequenceFlow.targetRef); this.jsPlumbService.deleteConnect(this.sequenceFlow.sourceRef, this.sequenceFlow.targetRef); } } diff --git a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.css b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.css index 3edffd66..1d119530 100644 --- a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.css +++ b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.css @@ -9,106 +9,54 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ - - .toolbar{ - padding: 20px 10px; -} - -.row{ - margin: 0; -} - -button { - min-width: 40px; - width: 60px; - height: 60px; - transition: all 0s; - margin: 10px; - padding: 0; -} - -button div{ - left: 0; - right: 0; - margin: auto; - width: 40px; - height: 40px; -} - -button span{ - padding: 0; - font-size: 10px; - letter-spacing: 0px; - color: black; + .toolbar-head{ + color:#404040; + font-size: 14px; } -.subProcess { - border-radius: 8px; - border: 2px solid rgb(0, 0, 0); - font-size: 10px; +.toolbar-head:hover{ + cursor: pointer; } -.parallelGateway { - transform: rotate(45deg); - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px !important; - width: 30px !important; - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuND6NzHYAAAEASURBVGhD7ZXRDcIwDEQ7AiMwQkdiQ0ZgBEbpCCWRiBRVob5zbaDSIeUD9WzfvSruNOknAiIgAiIgAiIgAiIgAiLwQwKXMvtezkx48NQQ7XFpNfIsZy1nAUN4anBHhLI3UgMgITw1hCVOOjKzF4LVc26catQUqnPaOFZmmbOeH5seVL1nsl3ydk+QuxJki2vzKURv/G/Nt6hWCHTVcuiC1df3St2Sr/9vwbPC2536DVjm0Y9dOFWk4am3kLXnrecIoDQNag7VpRkdNWZNsfr0MCND1p731KQG6Q1Z5kcfO7QmPcSjTJiJKTU4W0O0l1QEREAEREAEREAEREAEvkHgBRtRrTMkpctqAAAAAElFTkSuQmCC"); +.fold-icon{ + width: 15px; + font-size: 8px; + color: #00abff; } -.exclusiveGateway { - transform: rotate(45deg); - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px !important; - width: 30px !important; - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwQAADsEBuJFr7QAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuND6NzHYAAAC4SURBVGhD7ZXRCcAgEEMdpSN0hI7WTTpKR+hIrZ9yIBi4SIUn+CGc0bwoVwoDAhCAAAQgAAEIQMBB4K6i7dwdhzg13yrezsN5mEMbAw6qiiYJKLQctSTgoKpokoBCS6mNHba3jgk8oTP39tk7drxY9tresbMvPP2vLG/grG95ZEaj1+C+TfmQztrpTyPbDAayiap6JKASy64ngWyiqh4JqMSy62O3/k2HzTaKHgQgAAEIQAACyxL4AOr3u2BKXQ3gAAAAAElFTkSuQmCC"); +.item{ + width: 50px; + height: 50px; + text-align: center; + float: left; + margin-left: 6px; + margin-bottom: 10px; } -.startEvent { - border-radius: 30px; - border: 1px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - /*background-image: url("data:image/png;base64,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");*/ +.item:hover{ + cursor: pointer; } -.endEvent { - border-radius: 30px; - border: 2px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - /*background-image: url("data:image/png;base64,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");*/ +.item svg{ + width:24px; + height:24px; + margin: 4px 13px; + display: block; + /* fill: #A9B2BA; */ + fill: #00ABFF; } -.intermediateCatchEvent { - border-radius: 30px; - border: 1px solid rgb(0, 0, 0); - background-size: cover; - height: 30px; - width: 30px; - background-image: url("data:image/svg+xml;utf8, "); +.item span{ + font-size: 12px; + color: #595959; + display: block; } - -.scriptTask { - background-size: cover; - height: 30px; - width: 30px; - background-image: url("data:image/svg+xml;utf8, "); +.getway{ + padding-top: 5px; } -.toscaTask { - border-radius: 8px; - border: 2px solid rgb(0, 0, 0); - font-size: 10px; -} - -.restTask { - border-radius: 8px; - border: 2px solid rgb(0, 0, 0); - font-size: 10px; +.getway div{ + width: 30px !important; + height: 30px !important; } diff --git a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.html b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.html index bb52644f..382e195e 100644 --- a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.html +++ b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.html @@ -11,13 +11,184 @@ * ZTE - initial API and implementation and/or initial documentation */ --> -
-
- -
-
+ + +
+ + + EVENT +
+
+ + + + + + Start +
+
+ + + + + + End +
+
+ + + + + + + Timer +
+ +
+ +
+ + + Task +
+
+ + + + + + + + + + TOSCA +
+
+ + + + + + + + + + Rest +
+
+ + + + + + + + + Script +
+
+ +
+ + + Gateway +
+
+ + + + + + + EXCLUSIVE +
+
+ + + + + + + PARALLEL +
+
+ +
diff --git a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.ts b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.ts index 71bf02ab..c204a19b 100644 --- a/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.ts +++ b/sdc-workflow-designer-ui/src/app/components/toolbar/toolbar.component.ts @@ -10,10 +10,10 @@ * ZTE - initial API and implementation and/or initial documentation */ -import { AfterViewInit, Component, OnInit } from '@angular/core'; +import { AfterViewChecked, Component, OnInit } from '@angular/core'; +import { BroadcastService } from '../../services/broadcast.service'; import { JsPlumbService } from '../../services/jsplumb.service'; -import { NodeType } from "../../model/workflow/node-type.enum"; /** * toolbar component contains some basic operations(save) and all of the supported workflow nodes. @@ -24,29 +24,20 @@ import { NodeType } from "../../model/workflow/node-type.enum"; templateUrl: 'toolbar.component.html', styleUrls: ['./toolbar.component.css'] }) -export class ToolbarComponent implements AfterViewInit, OnInit { - public nodeTypes = []; +export class ToolbarComponent implements AfterViewChecked, OnInit { + public isCatalog = true; + private needInitButton = true; - constructor(private jsPlumbService: JsPlumbService) { - } - - public ngAfterViewInit() { - this.jsPlumbService.buttonDraggable(); - } + constructor(private jsPlumbService: JsPlumbService, private broadcastService: BroadcastService) { } - ngOnInit(): void { - this.getNodeTypes(); + public ngOnInit() { } - private getNodeTypes() { - for(let key in NodeType) { - if (typeof NodeType[key] === 'number') { - this.nodeTypes.push(key); - } + public ngAfterViewChecked() { + if (this.needInitButton) { + this.jsPlumbService.buttonDraggable(); + this.jsPlumbService.buttonDroppable(); + this.needInitButton = false; } } - - public getNameByType(type:string):string{ - return type.replace(type.charAt(0), type.charAt(0).toUpperCase()); - } } diff --git a/sdc-workflow-designer-ui/src/app/directive/drag-select/drag-select.directive.ts b/sdc-workflow-designer-ui/src/app/directive/drag-select/drag-select.directive.ts deleted file mode 100644 index 395cf040..00000000 --- a/sdc-workflow-designer-ui/src/app/directive/drag-select/drag-select.directive.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2017 ZTE Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and the Apache License 2.0 which both accompany this distribution, - * and are available at http://www.eclipse.org/legal/epl-v10.html - * and http://www.apache.org/licenses/LICENSE-2.0 - * - * Contributors: - * ZTE - initial API and implementation and/or initial documentation - */ - -import { AfterViewInit, Directive, ElementRef } from '@angular/core'; -import { JsPlumbService } from "../../services/jsplumb.service"; - -@Directive({ - selector: '[b4tDragSelect]' -}) -export class DragSelectDirective implements AfterViewInit { - private selectBox: any; - public selecting = false; - - public relatvieX: number; - public relatvieY: number; - - public startX: number; - public startY: number; - public endX: number; - public endY: number; - - public left: number = 0; - public top: number = 0; - public width: number = 0; - public height: number = 0; - - constructor(private el: ElementRef, private jsPlumbService: JsPlumbService) { } - - public ngAfterViewInit(): void { - this.selectBox = document.createElement('div'); - const selectArea = this.el.nativeElement.appendChild(this.selectBox); - this.el.nativeElement.addEventListener("mousedown", (event: MouseEvent) => this.mouseDown(event)); - this.el.nativeElement.addEventListener("mousemove", (event: MouseEvent) => this.mouseMove(event)); - this.el.nativeElement.addEventListener("mouseup", (event: MouseEvent) => this.mouseUp(event)); - } - - public mouseDown(event: MouseEvent) { - this.relatvieX = event.clientX - event.offsetX; - this.relatvieY = event.clientY - event.offsetY; - - this.width = 0; - this.height = 0; - this.startX = event.clientX; - this.startY = event.clientY; - this.endX = this.startX; - this.endY = this.startY; - this.selecting = true; - this.updateSelectArea(); - } - - public mouseMove(event: MouseEvent) { - this.endX = event.clientX; - this.endY = event.clientY; - - this.updateSelectArea(); - } - - public mouseUp(event: MouseEvent) { - this.selecting = false; - this.updateSelectArea(); - } - - private updateSelectArea() { - if (this.selecting) { - this.selectBox.className = 'selecting'; - } else { - this.selectBox.className = ''; - return; - } - - this.getAllSelectedNodes(); - - const leftTmp = this.startX >= this.endX ? this.endX : this.startX; - const topTmp = this.startY >= this.endY ? this.endY : this.startY; - - this.left = leftTmp - this.relatvieX; - this.top = topTmp - this.relatvieY; - - this.width = Math.abs(this.startX - this.endX); - this.height = Math.abs(this.endY - this.startY); - - this.selectBox.style.top = this.top + 'px'; - this.selectBox.style.left = this.left + 'px'; - this.selectBox.style.width = this.width + 'px'; - this.selectBox.style.height = this.height + 'px'; - } - - public getAllSelectedNodes() { - if(!this.selecting) { - return; - } - const selectedNodes = []; - - const nodes = this.el.nativeElement.querySelectorAll('div.node'); - nodes.forEach(node => { - if(this.checkNodeSelected(node)) { - selectedNodes.push(node); - } - }); - - this.jsPlumbService.jsplumbInstance.clearDragSelection(); - this.jsPlumbService.jsplumbInstance.addToDragSelection(selectedNodes); - - } - - private checkNodeSelected(node: any): boolean { - const nodeLeft = node.offsetLeft; - const nodeTop = node.offsetTop; - const nodeRigth = nodeLeft + node.clientWidth; - const nodeBottom = nodeTop + node.clientHeight; - - const selectedRight = this.left + this.width; - const selectedBottom = this.top + this.height; - - return this.between(nodeLeft, this.left, selectedRight) - && this.between(nodeRigth, this.left, selectedRight) - && this.between(nodeTop, this.top, selectedBottom) - && this.between(nodeBottom, this.top, selectedBottom); - } - - private between(value, min, max): boolean { - return min <= value && value <= max; - } - -} diff --git a/sdc-workflow-designer-ui/src/app/directive/resizeable/resizable.directive.ts b/sdc-workflow-designer-ui/src/app/directive/resizeable/resizable.directive.ts new file mode 100644 index 00000000..f591fe6f --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/directive/resizeable/resizable.directive.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +import { AfterViewInit, Directive, ElementRef } from '@angular/core'; +import * as $ from 'jquery'; + +import { JsPlumbService } from '../../services/jsplumb.service'; +import { ModelService } from '../../services/model.service'; + +@Directive({ selector: '[b4tResizable]' }) +export class ResizableDirective implements AfterViewInit { + + constructor(private el: ElementRef, + private jsPlumbService: JsPlumbService, + private planModelService: ModelService) { + } + + public ngAfterViewInit() { + console.log('init resizble.'); + + $(this.el.nativeElement).resizable({ + handles: 'all', + resize: (event, ui) => { + const element = ui.helper[0]; + this.planModelService.updatePosition(element.id, + element.offsetLeft, element.offsetTop, element.offsetWidth, element.offsetHeight - 12); + this.jsPlumbService.resizeParent(element, element.parentNode); + const node = this.planModelService.getNodeMap().get(element.id); + this.jsPlumbService.jsplumbInstanceMap.get(node.parentId).revalidate(element.id); + }, + }); + } +} diff --git a/sdc-workflow-designer-ui/src/app/model/rest-config.ts b/sdc-workflow-designer-ui/src/app/model/rest-config.ts new file mode 100644 index 00000000..42dc46b9 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/rest-config.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { Swagger } from './swagger'; + +export class RestConfig { + constructor(public id: string, public name: string, public version: string, public url: string, + public swagger?: Swagger) { } +} diff --git a/sdc-workflow-designer-ui/src/app/model/topology/node-template.ts b/sdc-workflow-designer-ui/src/app/model/topology/node-template.ts new file mode 100644 index 00000000..721ae604 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/topology/node-template.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +export class NodeTemplate { + public id: string; + public name: string; + public type: string; + public namespace: string; +} diff --git a/sdc-workflow-designer-ui/src/app/model/value-source.enum.ts b/sdc-workflow-designer-ui/src/app/model/value-source.enum.ts index fd08c8de..f76f6591 100644 --- a/sdc-workflow-designer-ui/src/app/model/value-source.enum.ts +++ b/sdc-workflow-designer-ui/src/app/model/value-source.enum.ts @@ -13,7 +13,7 @@ export enum ValueSource { String, Plan, + Topology, Variable, Definition, - // Topology, // TODO implement Topology properties in R2 } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/end-event.ts b/sdc-workflow-designer-ui/src/app/model/workflow/end-event.ts index 300af898..e3fbcad3 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/end-event.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/end-event.ts @@ -1,4 +1,3 @@ -import {WorkflowNode} from './workflow-node'; /** * Copyright (c) 2017 ZTE Corporation. * All rights reserved. This program and the accompanying materials @@ -10,6 +9,7 @@ import {WorkflowNode} from './workflow-node'; * Contributors: * ZTE - initial API and implementation and/or initial documentation */ +import {WorkflowNode} from './workflow-node'; -export class EndEvent extends WorkflowNode { +export interface EndEvent extends WorkflowNode { } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/error-event.ts b/sdc-workflow-designer-ui/src/app/model/workflow/error-event.ts new file mode 100644 index 00000000..7285402a --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/workflow/error-event.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { ValueSource } from '../value-source.enum'; +import { Parameter } from './parameter'; +import { WorkflowNode } from './workflow-node'; + +export interface ErrorEvent extends WorkflowNode { + parameter?: Parameter; +} diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/intermediate-catch-event.ts b/sdc-workflow-designer-ui/src/app/model/workflow/intermediate-catch-event.ts index 13a3d1e0..653e627f 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/intermediate-catch-event.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/intermediate-catch-event.ts @@ -12,7 +12,6 @@ import { TimerEventDefinition, TimerEventDefinitionType } from './timer-event-definition'; import { WorkflowNode } from './workflow-node'; -export class IntermediateCatchEvent extends WorkflowNode { - public timerEventDefinition: TimerEventDefinition = - new TimerEventDefinition(TimerEventDefinitionType[TimerEventDefinitionType.timeDuration]); +export interface IntermediateCatchEvent extends WorkflowNode { + timerEventDefinition?: TimerEventDefinition; } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/node-type.enum.ts b/sdc-workflow-designer-ui/src/app/model/workflow/node-type.enum.ts index 2481cdbb..22170c16 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/node-type.enum.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/node-type.enum.ts @@ -13,9 +13,13 @@ export enum NodeType { startEvent, endEvent, + errorStartEvent, + errorEndEvent, + toscaNodeManagementTask, restTask, - intermediateCatchEvent, exclusiveGateway, parallelGateway, - scriptTask, + subProcess, + intermediateCatchEvent, + scriptTask } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/parameter.ts b/sdc-workflow-designer-ui/src/app/model/workflow/parameter.ts index cc87a6fa..67ca7f3f 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/parameter.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/parameter.ts @@ -15,6 +15,6 @@ import { ValueType } from '../value-type.enum'; export class Parameter { constructor(public name: string, public value: string, public valueSource: string, - public type: string = ValueType[ValueType.String]) { + public type: string = ValueType[ValueType.String], public required: boolean = false) { } } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/rest-parameter.ts b/sdc-workflow-designer-ui/src/app/model/workflow/rest-parameter.ts index ecea3541..a7e4eeea 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/rest-parameter.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/rest-parameter.ts @@ -14,7 +14,7 @@ import { WorkflowNode } from './workflow-node'; export class RestParameter extends Parameter { constructor(name: string, value: string, valueSource: string, type: string, - public position: string, public schema: any) { - super(name, value, valueSource, type); + public position: string, public schema: any, public required: boolean) { + super(name, value, valueSource, type, required); } } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/rest-task.ts b/sdc-workflow-designer-ui/src/app/model/workflow/rest-task.ts index 2b3045df..12637d01 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/rest-task.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/rest-task.ts @@ -9,17 +9,17 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ +import { SwaggerResponse } from "../swagger"; import { RestParameter } from './rest-parameter'; import { WorkflowNode } from './workflow-node'; -export class RestTask extends WorkflowNode { - public serviceName: string; - public serviceVersion: string; - public url: string; - public method: string; - public operationId: string; - public produces: string[] = []; - public consumes: string[] = []; - public parameters: RestParameter[] = []; - public responses: any[] = []; +export interface RestTask extends WorkflowNode { + restConfigId?: string; + path?: string; + method?: string; + operationId?: string; + produces?: string[]; + consumes?: string[]; + parameters?: RestParameter[]; + responses?: SwaggerResponse[]; } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/script-task.ts b/sdc-workflow-designer-ui/src/app/model/workflow/script-task.ts index 3772226c..392376ad 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/script-task.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/script-task.ts @@ -9,16 +9,9 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ -import { Position } from './position'; import { WorkflowNode } from './workflow-node'; -import { SequenceFlow } from "./sequence-flow"; - -export class ScriptTask extends WorkflowNode { - public scriptFormat: string; - public script: string; - - public constructor(public id: string, public name: string, public type: string, public position: Position, public sequenceFlows: SequenceFlow[]) { - super(id, name, type, position, sequenceFlows); - } +export interface ScriptTask extends WorkflowNode { + scriptFormat: string; + script?: string; } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/start-event.ts b/sdc-workflow-designer-ui/src/app/model/workflow/start-event.ts index d609f7ca..a8f6444c 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/start-event.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/start-event.ts @@ -12,6 +12,6 @@ import { Parameter } from './parameter'; import { WorkflowNode } from './workflow-node'; -export class StartEvent extends WorkflowNode { - public parameters: Parameter[] = []; +export interface StartEvent extends WorkflowNode { + parameters?: Parameter[]; } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/sub-process.ts b/sdc-workflow-designer-ui/src/app/model/workflow/sub-process.ts new file mode 100644 index 00000000..0da453e4 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/workflow/sub-process.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { WorkflowNode } from './workflow-node'; +export interface SubProcess extends WorkflowNode { + children?: WorkflowNode[]; +} diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/timer-event-definition.ts b/sdc-workflow-designer-ui/src/app/model/workflow/timer-event-definition.ts index f78d3973..101ef46c 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/timer-event-definition.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/timer-event-definition.ts @@ -17,11 +17,9 @@ export enum TimerEventDefinitionType { timeCycle, } -export class TimerEventDefinition { - constructor(public type: string, // 'timeDate', 'timeCycle', 'timeDuration' - public timeDate?: string, // 10/10/2099 00:00:00 - public timeDuration?: string, // ISO 8601 P1Y3M5DT6H7M30S - public timeCycle?: string) { // ISO 8601 P1Y3M5DT6H7M30S - - } +export interface TimerEventDefinition extends WorkflowNode { + type: string; // 'timeDate', 'timeCycle', 'timeDuration' + timeDate?: string; // 2007-04-05T12:30-02:00 + timeDuration?: string; // ISO 8601 P1Y3M5DT6H7M30S + timeCycle?: string; // ISO 8601 R5/P1Y2M10DT2H30M } diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/tosca-node-task.ts b/sdc-workflow-designer-ui/src/app/model/workflow/tosca-node-task.ts new file mode 100644 index 00000000..986f0188 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/workflow/tosca-node-task.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ +import { NodeTemplate } from '../topology/node-template'; +import { Parameter } from './parameter'; +import { WorkflowNode } from './workflow-node'; + +export interface ToscaNodeTask extends WorkflowNode { + input?: Parameter[]; + output?: Parameter[]; + nodeInterface?: string; + operation?: string; + template?: NodeTemplate; +} diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/workflow-element.ts b/sdc-workflow-designer-ui/src/app/model/workflow/workflow-element.ts new file mode 100644 index 00000000..9b0e2fe0 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/model/workflow/workflow-element.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + */ + +export interface WorkflowElement { +} diff --git a/sdc-workflow-designer-ui/src/app/model/workflow/workflow-node.ts b/sdc-workflow-designer-ui/src/app/model/workflow/workflow-node.ts index 9e54be13..628148a4 100644 --- a/sdc-workflow-designer-ui/src/app/model/workflow/workflow-node.ts +++ b/sdc-workflow-designer-ui/src/app/model/workflow/workflow-node.ts @@ -9,9 +9,15 @@ * Contributors: * ZTE - initial API and implementation and/or initial documentation */ +import { WorkflowElement } from './workflow-element'; import { Position } from './position'; import { SequenceFlow } from './sequence-flow'; -export class WorkflowNode { - public constructor(public id: string, public name: string, public type: string, public position: Position, public sequenceFlows: SequenceFlow[]) {} +export interface WorkflowNode extends WorkflowElement { + connection: SequenceFlow[]; + id: string; + name: string; + parentId: string; + position: Position; + type: string; } diff --git a/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts b/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts index dd75c45c..544c2a70 100644 --- a/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts +++ b/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts @@ -15,6 +15,8 @@ import { Subject } from 'rxjs/Subject'; import { WorkflowNode } from '../model/workflow/workflow-node'; import { SequenceFlow } from "../model/workflow/sequence-flow"; import { PlanModel } from "../model/workflow/plan-model"; +import { WorkflowElement } from '../model/workflow/workflow-element'; +import { RestConfig } from '../model/rest-config'; /** * BroadcastService @@ -30,15 +32,21 @@ export class BroadcastService { public workflows = new Subject>(); public workflows$ = this.workflows.asObservable(); - public workflow = new Subject(); - public workflow$ = this.workflow.asObservable(); + public planModel = new Subject(); + public planModel$ = this.planModel.asObservable(); public showProperty = new Subject(); public showProperty$ = this.showProperty.asObservable(); + public updateModelRestConfig = new Subject(); + public updateModelRestConfig$ = this.updateModelRestConfig.asObservable(); + public saveEvent = new Subject(); public saveEvent$ = this.saveEvent.asObservable(); + public selectedElement = new Subject(); + public selectedElement$ = this.selectedElement.asObservable(); + public nodeProperty = new Subject(); public nodeProperty$ = this.nodeProperty.asObservable(); diff --git a/sdc-workflow-designer-ui/src/app/services/data-access/mockdata.ts b/sdc-workflow-designer-ui/src/app/services/data-access/mockdata.ts index 084c0551..5b2750b1 100644 --- a/sdc-workflow-designer-ui/src/app/services/data-access/mockdata.ts +++ b/sdc-workflow-designer-ui/src/app/services/data-access/mockdata.ts @@ -1,2 +1,2 @@ -export const workflowFJH = {"id":"fjh","name":"fjh","nodes":[{"id":"node0","name":"startEvent","type":"startEvent","position":{"top":31,"left":31,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node0","targetRef":"node23"}],"parameters":[{"name":"vlCount","value":"","valueSource":"String","type":"String"},{"name":"vnfCount","value":"","valueSource":"String","type":"String"},{"name":"sfcCount","value":"","valueSource":"String","type":"String"},{"name":"object_context","value":"","valueSource":"String","type":"String"},{"name":"nsInstanceId","value":"","valueSource":"String","type":"String"},{"name":"object_additionalParamForNs","value":"","valueSource":"String","type":"String"},{"name":"object_additionalParamForVnf","value":"","valueSource":"String","type":"String"},{"name":"jobId","value":"","valueSource":"String","type":"String"},{"name":"sdnControllerId","value":"","valueSource":"String","type":"String"},{"name":"templateid","value":"","valueSource":"String","type":"String"},{"name":"instanceid","value":"","valueSource":"String","type":"String"},{"name":"sdnolcmurl","value":"","valueSource":"String","type":"String"},{"name":"statusurl","value":"","valueSource":"String","type":"String"}]},{"id":"node1","name":"endEvent","type":"endEvent","position":{"top":668,"left":955,"width":200,"height":100},"sequenceFlows":[]},{"id":"node2","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":120,"left":169,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node2","targetRef":"node3","condition":"${ vl_index <= vlCount and vl_status='active' }","name":"未完成"},{"sourceRef":"node2","targetRef":"node4","condition":"!( vl_index <= vlCount and vl_status='active' )","name":"创建完成"}]},{"id":"node3","name":"createVL","type":"restTask","position":{"top":213,"left":142,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node3","targetRef":"node11"}],"produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"body","valueSource":"String","type":"String","position":"body","schema":{"$ref":"#/definitions/VlPostRequest"}}],"responses":[{"description":"","schema":{"$ref":"#/definitions/VlPostResponse"}}],"serviceName":"nslcm","serviceVersion":"v1","url":"/ns/vls","method":"post"},{"id":"node4","name":"restTask","type":"restTask","position":{"top":115,"left":358,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node4","targetRef":"node5"}],"produces":[],"consumes":[],"parameters":[],"responses":[],"serviceName":"nslcm","serviceVersion":"v1","url":"","method":""},{"id":"node5","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":212,"left":383,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node5","targetRef":"node6","condition":"未完成"},{"sourceRef":"node5","targetRef":"node12","condition":"创建完成"}]},{"id":"node6","name":"createVNF","type":"restTask","position":{"top":306,"left":352,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node6","targetRef":"node7"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node7","name":"intermediateCatchEvent","type":"intermediateCatchEvent","position":{"top":558,"left":443,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node7","targetRef":"node8"}],"timerEventDefinition":{"type":"timeDuration"}},{"id":"node8","name":"query_vnf nslcm","type":"restTask","position":{"top":639,"left":216,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node8","targetRef":"node9"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node9","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":539,"left":264,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node9","targetRef":"node7","condition":"未完成"},{"sourceRef":"node9","targetRef":"node10","condition":"已完成"}]},{"id":"node10","name":"scriptTask","type":"scriptTask","position":{"top":303,"left":239,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node10","targetRef":"node5"}]},{"id":"node11","name":"scriptTask","type":"scriptTask","position":{"top":207,"left":34,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node11","targetRef":"node2"}]},{"id":"node12","name":"restTask","type":"restTask","position":{"top":205,"left":732,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node12","targetRef":"node13"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node13","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":287,"left":757,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node13","targetRef":"node14","condition":"未结束"},{"sourceRef":"node13","targetRef":"node18","condition":"已结束"}]},{"id":"node14","name":"createSfc","type":"restTask","position":{"top":440,"left":726,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node14","targetRef":"node15"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node15","name":"intermediateCatchEvent","type":"intermediateCatchEvent","position":{"top":551,"left":754,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node15","targetRef":"node16"}],"timerEventDefinition":{"type":"timeDuration"}},{"id":"node16","name":"restTask","type":"restTask","position":{"top":642,"left":589,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node16","targetRef":"node17"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node17","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":551,"left":614,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node17","targetRef":"node15","condition":"未结束"},{"sourceRef":"node17","targetRef":"node19","condition":"已结束"}]},{"id":"node18","name":"restTask","type":"restTask","position":{"top":282,"left":927,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node18","targetRef":"node20"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node19","name":"scriptTask","type":"scriptTask","position":{"top":275,"left":588,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node19","targetRef":"node13"}]},{"id":"node20","name":"Assign_all_status","type":"scriptTask","position":{"top":380,"left":928,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node20","targetRef":"node21"}]},{"id":"node21","name":"post_do","type":"restTask","position":{"top":497,"left":929,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node21","targetRef":"node22"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node22","name":"jobstatus","type":"restTask","position":{"top":586,"left":927,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node22","targetRef":"node1"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node23","name":"scriptTask","type":"scriptTask","position":{"top":16,"left":143,"width":200,"height":100},"sequenceFlows":[{"sourceRef":"node23","targetRef":"node2"}],"scriptFormate":"javascript","script":"execution.setVariable(\"vl_index\", 1);\nexecution.setVariable(\"vl_status\", \"active\");"}],"configs":{"microservices":[{"name":"nslcm","version":"v1","swaggerJson":"{\"info\":{\"version\":\"1.0.0\",\"contact\":{\"url\":\"https://gerrit.onap.org/r/#/admin/projects/vfc/nfvo/lcm\",\"name\":\"ONAP VFC team\",\"email\":\"onap-discuss@lists.onap.org\"},\"description\":\"VFC Network Service Lifecycle Management Rest API.\",\"title\":\"ONAP VFC Network Service Lifecycle Management API\"},\"paths\":{\"/ns/sfcs/{sfcInstId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteResponse\"}},\"404\":{\"description\":\"the sfc instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"sfcInstId\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"delete sfc\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_sfc\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/SfcInfo\"}},\"404\":{\"description\":\"the sfc instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"sfc instance id\",\"required\":true,\"type\":\"string\",\"name\":\"sfcInstId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"query the specified sfc info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_sfc\"}},\"/ns/{nsInstanceId}/postdeal\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NSInstPostDetailRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"postdeal\"],\"summary\":\"ns postdeal\",\"consumes\":[\"application/json\"],\"operationId\":\"ns_postdeal\"}},\"/ns/vnfs\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/VnfPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/VnfPostRequest\"},\"description\":\"instantiate request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"vnf create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_vnf\"}},\"/ns/{ns_instance_id}/heal\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"},{\"schema\":{\"$ref\":\"#/definitions/NsHealRequest\"},\"description\":\"healVnfData\",\"required\":true,\"name\":\"healVnfData\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns heal\",\"summary\":\"ns heal\",\"operationId\":\"ns_heal\"}},\"/jobs/{jobId}\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"jobId\"},{\"schema\":{\"$ref\":\"#/definitions/JobProgressRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"tags\":[\"job\"],\"description\":\"\",\"summary\":\"jobstatus\",\"operationId\":\"post_jobprogress\"},\"get\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobDetailInfo\"}}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"job Id\",\"in\":\"path\",\"name\":\"jobId\"},{\"required\":true,\"type\":\"string\",\"description\":\"job response message id\",\"in\":\"query\",\"name\":\"responseId\"}],\"tags\":[\"job\"],\"description\":\"\",\"summary\":\"jobstatus\",\"operationId\":\"get_jobstatus\"}},\"/ns/vls/{vlId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteVlResponse\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"vlId\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"delete vl\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_vl\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/VlInfo\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"vl instance id\",\"required\":true,\"type\":\"string\",\"name\":\"vlId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"query the specified vl info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_vl\"}},\"/ns/vls\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/VlPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/VlPostRequest\"},\"description\":\"instantiate request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"vl create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_vl\"}},\"/ns/sfcs\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/SfcPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/SfcPostRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"sfc create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_sfc\"}},\"/ns/{ns_instance_id}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"The NS instance resource and the associated NS identifier were deleted successfully.\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"}],\"tags\":[\"ns\"],\"description\":\"ns delete\",\"summary\":\"ns delete\",\"operationId\":\"ns_delete\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsInstanceInfo\"}}},\"parameters\":[],\"tags\":[\"ns\"],\"description\":\"ns get\",\"summary\":\"ns get\",\"operationId\":\"ns_instance_get\"}},\"/ns/vnfs/{vnfInstId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteResponse\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"vnfInstId\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"delete vnf\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_vnf\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/VnfInfo\"}},\"404\":{\"description\":\"the vnf instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"vnf instance id\",\"required\":true,\"type\":\"string\",\"name\":\"vnfInstId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"query the specified vnf info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_vnf\"}},\"/ns\":{\"post\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsCreateResponse\"}}},\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/NsCreateRequest\"},\"description\":\"NS Instance Create Request\",\"required\":true,\"name\":\"NSCreateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns create\",\"summary\":\"ns create\",\"operationId\":\"ns_create\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsInstancesInfo\"}}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"job response message id\",\"in\":\"query\",\"name\":\"csarId\"}],\"tags\":[\"ns\"],\"description\":\"ns get\",\"summary\":\"ns get\",\"operationId\":\"ns_instantces_get\"}},\"/ns/{ns_instance_id}/terminate\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"},{\"schema\":{\"$ref\":\"#/definitions/NsTerminateRequest\"},\"description\":\"NsTerminateRequest\",\"required\":true,\"name\":\"NsTerminateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns terminate\",\"summary\":\"ns terminate\",\"operationId\":\"ns_terminate\"}},\"/ns/{nsInstanceId}/scale\":{\"post\":{\"responses\":{\"200\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"201\":{\"description\":\"Invalid Request\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NsScaleRequest\"},\"description\":\"Scale NS Request Body\",\"required\":true,\"name\":\"ScaleNSRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns scale\",\"summary\":\"ns scale\",\"operationId\":\"ns_scale\"}},\"/mandb/{modelName}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"The tables were deleted successfully.\"}},\"description\":\"ns table delete\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"model Name.\",\"in\":\"path\",\"name\":\"modelName\"}],\"produces\":[\"application/json\"],\"tags\":[\"db\"],\"summary\":\"ns table delete\",\"consumes\":[\"application/json\"],\"operationId\":\"ns_table_delete\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/TableInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"query ns table info\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"model Name.\",\"in\":\"path\",\"name\":\"modelName\"}],\"produces\":[\"application/json\"],\"tags\":[\"db\"],\"summary\":\"query ns table info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_ns_table\"}},\"/ns/{nsInstanceId}/Instantiate\":{\"post\":{\"responses\":{\"200\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"201\":{\"description\":\"Invalid Request\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NsInstantiateRequest\"},\"description\":\"NS Instantiate Request Body\",\"required\":true,\"name\":\"NSInstantiateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns Instantiate\",\"summary\":\"ns Instantiate\",\"operationId\":\"ns_Instantiate\"}}},\"schemes\":[\"http\",\"https\"],\"produces\":[\"application/json\"],\"basePath\":\"/api/nslcm/v1\",\"definitions\":{\"NsInstanceInfo\":{\"type\":\"object\",\"properties\":{\"nsState\":{\"type\":\"string\"},\"vnfInfo\":{\"items\":{\"$ref\":\"#/definitions/vnfInfo\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"nsdId\":{\"type\":\"string\"},\"vlInfo\":{\"items\":{\"$ref\":\"#/definitions/vlInfo\"},\"type\":\"array\"},\"nsName\":{\"type\":\"string\"},\"vnffgInfo\":{\"items\":{\"$ref\":\"#/definitions/vnffgInfo\"},\"type\":\"array\"},\"description\":{\"type\":\"string\"}}},\"JobDetailInfo\":{\"type\":\"object\",\"properties\":{\"responseDescriptor\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"},\"responseHistoryList\":{\"items\":{\"$ref\":\"#/definitions/jobResponseInfo\"},\"type\":\"array\"},\"responseId\":{\"type\":\"string\"},\"errorCode\":{\"type\":\"string\"},\"progress\":{\"type\":\"string\"},\"statusDescription\":{\"type\":\"string\"}}},\"jobId\":{\"type\":\"string\"}}},\"VnfInfo\":{\"type\":\"object\",\"properties\":{\"vnfInstId\":{\"type\":\"string\"},\"vnfName\":{\"type\":\"string\"},\"vnfStatus\":{\"type\":\"string\"}}},\"DeleteResponse\":{\"type\":\"object\",\"properties\":{\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"NsHealRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceId\":{\"type\":\"string\"},\"cause\":{\"type\":\"string\"},\"additionalParams\":{\"type\":\"object\",\"properties\":{\"action\":{\"type\":\"string\"},\"actionvminfo\":{\"type\":\"object\",\"properties\":{\"vmname\":{\"type\":\"string\"},\"vmid\":{\"type\":\"string\"}}}}}}},\"NsScaleRequest\":{\"type\":\"object\",\"properties\":{\"scaleNsByStepsData\":{\"$ref\":\"#/definitions/NsScaleByStepsData\"},\"scaleType\":{\"type\":\"string\"}}},\"jobResponseInfo\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"},\"progress\":{\"type\":\"string\"},\"responseId\":{\"type\":\"string\"},\"statusDescription\":{\"type\":\"string\"},\"errorCode\":{\"type\":\"string\"}}},\"NSInstPostDetailRequest\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"}}},\"VlInfo\":{\"type\":\"object\",\"properties\":{\"vlId\":{\"type\":\"string\"},\"vlStatus\":{\"type\":\"string\"},\"vlName\":{\"type\":\"string\"}}},\"VnfPostResponse\":{\"type\":\"object\",\"properties\":{\"vnfInstId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"}}},\"NsCreateRequest\":{\"type\":\"object\",\"properties\":{\"nsName\":{\"type\":\"string\"},\"csarId\":{\"type\":\"string\",\"description\":\"the NS package ID\"},\"description\":{\"type\":\"string\"}}},\"VlPostResponse\":{\"type\":\"object\",\"properties\":{\"vlId\":{\"type\":\"string\"},\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"SfcPostRequest\":{\"type\":\"object\",\"properties\":{\"sdnControllerId\":{\"type\":\"string\"},\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"fpindex\":{\"type\":\"string\"}}},\"NsTerminateRequest\":{\"type\":\"object\",\"properties\":{\"gracefulTerminationTimeout\":{\"type\":\"string\"},\"terminationType\":{\"type\":\"string\"}}},\"JobProgressRequest\":{\"type\":\"object\",\"properties\":{\"progress\":{\"type\":\"string\"},\"errcode\":{\"type\":\"string\"},\"desc\":{\"type\":\"string\"}}},\"SfcInfo\":{\"type\":\"object\",\"properties\":{\"sfcName\":{\"type\":\"string\"},\"sfcInstId\":{\"type\":\"string\"},\"sfcStatus\":{\"type\":\"string\"}}},\"vnfInfo\":{\"type\":\"object\",\"properties\":{\"vnfInstanceId\":{\"type\":\"string\"},\"vnfdId\":{\"type\":\"string\"},\"vnfInstanceName\":{\"type\":\"string\"}}},\"LocationConstraint\":{\"type\":\"object\",\"properties\":{\"locationConstraints\":{\"type\":\"object\",\"properties\":{\"vimid\":{\"type\":\"string\"}}},\"vnfProfileId\":{\"type\":\"string\"}}},\"NsCreateResponse\":{\"type\":\"object\",\"properties\":{\"nsInstanceId\":{\"type\":\"string\"}}},\"VlPostRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"flavourId\":{\"type\":\"string\"},\"pnfInfo\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"extNSVirtualLink\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nestedNsInstanceId\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"jobId\":{\"type\":\"string\"},\"locationConstraints\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"vlIndex\":{\"type\":\"string\"}}},\"VnfPostRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"vnfIndex\":{\"type\":\"string\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"flavourId\":{\"type\":\"string\"},\"pnfInfo\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"extNSVirtualLink\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nestedNsInstanceId\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"jobId\":{\"type\":\"string\"},\"locationConstraints\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"}}},\"DeleteVlResponse\":{\"type\":\"object\",\"properties\":{\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"vlInfo\":{\"type\":\"object\",\"properties\":{\"vldId\":{\"type\":\"string\"},\"vlInstanceName\":{\"type\":\"string\"},\"vlInstanceId\":{\"type\":\"string\"},\"relatedCpInstanceId\":{\"items\":{\"$ref\":\"#/definitions/cpInfo\"},\"type\":\"array\"}}},\"cpInfo\":{\"type\":\"object\",\"properties\":{\"cpInstanceId\":{\"type\":\"string\"},\"cpdId\":{\"type\":\"string\"},\"cpInstanceName\":{\"type\":\"string\"}}},\"SfcPostResponse\":{\"type\":\"object\",\"properties\":{\"sfcInstId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"}}},\"NsInstantiateRequest\":{\"type\":\"object\",\"properties\":{\"additionalParamForNs\":{\"type\":\"string\"},\"LocationConstraints\":{\"items\":{\"$ref\":\"#/definitions/LocationConstraint\"},\"type\":\"array\"}}},\"JobInfo\":{\"type\":\"object\",\"properties\":{\"jobId\":{\"type\":\"string\"}}},\"NsInstancesInfo\":{\"items\":{\"$ref\":\"#/definitions/NsInstanceInfo\"},\"type\":\"array\"},\"NsScaleByStepsData\":{\"type\":\"object\",\"properties\":{\"numberOfSteps\":{\"type\":\"integer\"},\"scalingDirection\":{\"type\":\"string\"},\"aspectId\":{\"type\":\"string\"}}},\"vnffgInfo\":{\"type\":\"object\",\"properties\":{\"cpId\":{\"type\":\"string\"},\"virtualLinkId\":{\"type\":\"string\"},\"vnfId\":{\"type\":\"string\"},\"pnfId\":{\"type\":\"string\"},\"nfp\":{\"type\":\"string\"},\"vnffgInstanceId\":{\"type\":\"string\"}}},\"TableInfo\":{\"type\":\"object\",\"properties\":{\"count\":{\"type\":\"string\"}}}},\"swagger\":\"2.0\",\"consumes\":[\"application/json\"]}","definition":""}]}}; +export const workflowFJH = {"id":"fjh","name":"fjh","nodes":[{"id":"node0","name":"startEvent","type":"startEvent","position":{"top":31,"left":31,"width":200,"height":100},"connection":[{"sourceRef":"node0","targetRef":"node23"}],"parameters":[{"name":"vlCount","value":"","valueSource":"String","type":"String"},{"name":"vnfCount","value":"","valueSource":"String","type":"String"},{"name":"sfcCount","value":"","valueSource":"String","type":"String"},{"name":"object_context","value":"","valueSource":"String","type":"String"},{"name":"nsInstanceId","value":"","valueSource":"String","type":"String"},{"name":"object_additionalParamForNs","value":"","valueSource":"String","type":"String"},{"name":"object_additionalParamForVnf","value":"","valueSource":"String","type":"String"},{"name":"jobId","value":"","valueSource":"String","type":"String"},{"name":"sdnControllerId","value":"","valueSource":"String","type":"String"},{"name":"templateid","value":"","valueSource":"String","type":"String"},{"name":"instanceid","value":"","valueSource":"String","type":"String"},{"name":"sdnolcmurl","value":"","valueSource":"String","type":"String"},{"name":"statusurl","value":"","valueSource":"String","type":"String"}]},{"id":"node1","name":"endEvent","type":"endEvent","position":{"top":668,"left":955,"width":200,"height":100},"connection":[]},{"id":"node2","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":120,"left":169,"width":200,"height":100},"connection":[{"sourceRef":"node2","targetRef":"node3","condition":"${ vl_index <= vlCount and vl_status='active' }","name":"未完成"},{"sourceRef":"node2","targetRef":"node4","condition":"!( vl_index <= vlCount and vl_status='active' )","name":"创建完成"}]},{"id":"node3","name":"createVL","type":"restTask","position":{"top":213,"left":142,"width":200,"height":100},"connection":[{"sourceRef":"node3","targetRef":"node11"}],"produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"body","valueSource":"String","type":"String","position":"body","schema":{"$ref":"#/definitions/VlPostRequest"}}],"responses":[{"description":"","schema":{"$ref":"#/definitions/VlPostResponse"}}],"restConfigId":"nslcm","path":"/ns/vls","method":"post"},{"id":"node4","name":"restTask","type":"restTask","position":{"top":115,"left":358,"width":200,"height":100},"connection":[{"sourceRef":"node4","targetRef":"node5"}],"produces":[],"consumes":[],"parameters":[],"responses":[],"restConfigId":"nslcm","path":"","method":""},{"id":"node5","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":212,"left":383,"width":200,"height":100},"connection":[{"sourceRef":"node5","targetRef":"node6","condition":"未完成"},{"sourceRef":"node5","targetRef":"node12","condition":"创建完成"}]},{"id":"node6","name":"createVNF","type":"restTask","position":{"top":306,"left":352,"width":200,"height":100},"connection":[{"sourceRef":"node6","targetRef":"node7"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node7","name":"intermediateCatchEvent","type":"intermediateCatchEvent","position":{"top":558,"left":443,"width":200,"height":100},"connection":[{"sourceRef":"node7","targetRef":"node8"}],"timerEventDefinition":{"type":"timeDuration"}},{"id":"node8","name":"query_vnf nslcm","type":"restTask","position":{"top":639,"left":216,"width":200,"height":100},"connection":[{"sourceRef":"node8","targetRef":"node9"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node9","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":539,"left":264,"width":200,"height":100},"connection":[{"sourceRef":"node9","targetRef":"node7","condition":"未完成"},{"sourceRef":"node9","targetRef":"node10","condition":"已完成"}]},{"id":"node10","name":"scriptTask","type":"scriptTask","position":{"top":303,"left":239,"width":200,"height":100},"connection":[{"sourceRef":"node10","targetRef":"node5"}]},{"id":"node11","name":"scriptTask","type":"scriptTask","position":{"top":207,"left":34,"width":200,"height":100},"connection":[{"sourceRef":"node11","targetRef":"node2"}]},{"id":"node12","name":"restTask","type":"restTask","position":{"top":205,"left":732,"width":200,"height":100},"connection":[{"sourceRef":"node12","targetRef":"node13"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node13","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":287,"left":757,"width":200,"height":100},"connection":[{"sourceRef":"node13","targetRef":"node14","condition":"未结束"},{"sourceRef":"node13","targetRef":"node18","condition":"已结束"}]},{"id":"node14","name":"createSfc","type":"restTask","position":{"top":440,"left":726,"width":200,"height":100},"connection":[{"sourceRef":"node14","targetRef":"node15"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node15","name":"intermediateCatchEvent","type":"intermediateCatchEvent","position":{"top":551,"left":754,"width":200,"height":100},"connection":[{"sourceRef":"node15","targetRef":"node16"}],"timerEventDefinition":{"type":"timeDuration"}},{"id":"node16","name":"restTask","type":"restTask","position":{"top":642,"left":589,"width":200,"height":100},"connection":[{"sourceRef":"node16","targetRef":"node17"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node17","name":"exclusiveGateway","type":"exclusiveGateway","position":{"top":551,"left":614,"width":200,"height":100},"connection":[{"sourceRef":"node17","targetRef":"node15","condition":"未结束"},{"sourceRef":"node17","targetRef":"node19","condition":"已结束"}]},{"id":"node18","name":"restTask","type":"restTask","position":{"top":282,"left":927,"width":200,"height":100},"connection":[{"sourceRef":"node18","targetRef":"node20"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node19","name":"scriptTask","type":"scriptTask","position":{"top":275,"left":588,"width":200,"height":100},"connection":[{"sourceRef":"node19","targetRef":"node13"}]},{"id":"node20","name":"Assign_all_status","type":"scriptTask","position":{"top":380,"left":928,"width":200,"height":100},"connection":[{"sourceRef":"node20","targetRef":"node21"}]},{"id":"node21","name":"post_do","type":"restTask","position":{"top":497,"left":929,"width":200,"height":100},"connection":[{"sourceRef":"node21","targetRef":"node22"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node22","name":"jobstatus","type":"restTask","position":{"top":586,"left":927,"width":200,"height":100},"connection":[{"sourceRef":"node22","targetRef":"node1"}],"produces":[],"consumes":[],"parameters":[],"responses":[]},{"id":"node23","name":"scriptTask","type":"scriptTask","position":{"top":16,"left":143,"width":200,"height":100},"connection":[{"sourceRef":"node23","targetRef":"node2"}],"scriptFormate":"javascript","script":"execution.setVariable(\"vl_index\", 1);\nexecution.setVariable(\"vl_status\", \"active\");"}],"configs":{"microservices":[{"name":"nslcm","version":"v1","swaggerJson":"{\"info\":{\"version\":\"1.0.0\",\"contact\":{\"url\":\"https://gerrit.onap.org/r/#/admin/projects/vfc/nfvo/lcm\",\"name\":\"ONAP VFC team\",\"email\":\"onap-discuss@lists.onap.org\"},\"description\":\"VFC Network Service Lifecycle Management Rest API.\",\"title\":\"ONAP VFC Network Service Lifecycle Management API\"},\"paths\":{\"/ns/sfcs/{sfcInstId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteResponse\"}},\"404\":{\"description\":\"the sfc instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"sfcInstId\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"delete sfc\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_sfc\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/SfcInfo\"}},\"404\":{\"description\":\"the sfc instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"sfc instance id\",\"required\":true,\"type\":\"string\",\"name\":\"sfcInstId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"query the specified sfc info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_sfc\"}},\"/ns/{nsInstanceId}/postdeal\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NSInstPostDetailRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"postdeal\"],\"summary\":\"ns postdeal\",\"consumes\":[\"application/json\"],\"operationId\":\"ns_postdeal\"}},\"/ns/vnfs\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/VnfPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/VnfPostRequest\"},\"description\":\"instantiate request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"vnf create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_vnf\"}},\"/ns/{ns_instance_id}/heal\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"},{\"schema\":{\"$ref\":\"#/definitions/NsHealRequest\"},\"description\":\"healVnfData\",\"required\":true,\"name\":\"healVnfData\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns heal\",\"summary\":\"ns heal\",\"operationId\":\"ns_heal\"}},\"/jobs/{jobId}\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"jobId\"},{\"schema\":{\"$ref\":\"#/definitions/JobProgressRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"tags\":[\"job\"],\"description\":\"\",\"summary\":\"jobstatus\",\"operationId\":\"post_jobprogress\"},\"get\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobDetailInfo\"}}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"job Id\",\"in\":\"path\",\"name\":\"jobId\"},{\"required\":true,\"type\":\"string\",\"description\":\"job response message id\",\"in\":\"query\",\"name\":\"responseId\"}],\"tags\":[\"job\"],\"description\":\"\",\"summary\":\"jobstatus\",\"operationId\":\"get_jobstatus\"}},\"/ns/vls/{vlId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteVlResponse\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"vlId\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"delete vl\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_vl\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/VlInfo\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"vl instance id\",\"required\":true,\"type\":\"string\",\"name\":\"vlId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"query the specified vl info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_vl\"}},\"/ns/vls\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/VlPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/VlPostRequest\"},\"description\":\"instantiate request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"vl\"],\"summary\":\"vl create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_vl\"}},\"/ns/sfcs\":{\"post\":{\"responses\":{\"201\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/SfcPostResponse\"}}},\"description\":\"\",\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/SfcPostRequest\"},\"description\":\"request param\",\"required\":true,\"name\":\"body\",\"in\":\"body\"}],\"produces\":[\"application/json\"],\"tags\":[\"sfc\"],\"summary\":\"sfc create\",\"consumes\":[\"application/json\"],\"operationId\":\"create_sfc\"}},\"/ns/{ns_instance_id}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"The NS instance resource and the associated NS identifier were deleted successfully.\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"}],\"tags\":[\"ns\"],\"description\":\"ns delete\",\"summary\":\"ns delete\",\"operationId\":\"ns_delete\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsInstanceInfo\"}}},\"parameters\":[],\"tags\":[\"ns\"],\"description\":\"ns get\",\"summary\":\"ns get\",\"operationId\":\"ns_instance_get\"}},\"/ns/vnfs/{vnfInstId}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/DeleteResponse\"}},\"404\":{\"description\":\"the vl instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"vnfInstId\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"delete vnf\",\"consumes\":[\"application/json\"],\"operationId\":\"delete_vnf\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/VnfInfo\"}},\"404\":{\"description\":\"the vnf instance id is wrong\"},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"\",\"parameters\":[{\"description\":\"vnf instance id\",\"required\":true,\"type\":\"string\",\"name\":\"vnfInstId\",\"in\":\"path\"}],\"produces\":[\"application/json\"],\"tags\":[\"vnf\"],\"summary\":\"query the specified vnf info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_vnf\"}},\"/ns\":{\"post\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsCreateResponse\"}}},\"parameters\":[{\"schema\":{\"$ref\":\"#/definitions/NsCreateRequest\"},\"description\":\"NS Instance Create Request\",\"required\":true,\"name\":\"NSCreateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns create\",\"summary\":\"ns create\",\"operationId\":\"ns_create\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/NsInstancesInfo\"}}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"job response message id\",\"in\":\"query\",\"name\":\"csarId\"}],\"tags\":[\"ns\"],\"description\":\"ns get\",\"summary\":\"ns get\",\"operationId\":\"ns_instantces_get\"}},\"/ns/{ns_instance_id}/terminate\":{\"post\":{\"responses\":{\"202\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"Identifier of the NS instance.\",\"in\":\"path\",\"name\":\"ns_instance_id\"},{\"schema\":{\"$ref\":\"#/definitions/NsTerminateRequest\"},\"description\":\"NsTerminateRequest\",\"required\":true,\"name\":\"NsTerminateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns terminate\",\"summary\":\"ns terminate\",\"operationId\":\"ns_terminate\"}},\"/ns/{nsInstanceId}/scale\":{\"post\":{\"responses\":{\"200\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"201\":{\"description\":\"Invalid Request\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NsScaleRequest\"},\"description\":\"Scale NS Request Body\",\"required\":true,\"name\":\"ScaleNSRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns scale\",\"summary\":\"ns scale\",\"operationId\":\"ns_scale\"}},\"/mandb/{modelName}\":{\"delete\":{\"responses\":{\"204\":{\"description\":\"The tables were deleted successfully.\"}},\"description\":\"ns table delete\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"model Name.\",\"in\":\"path\",\"name\":\"modelName\"}],\"produces\":[\"application/json\"],\"tags\":[\"db\"],\"summary\":\"ns table delete\",\"consumes\":[\"application/json\"],\"operationId\":\"ns_table_delete\"},\"get\":{\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$ref\":\"#/definitions/TableInfo\"}},\"500\":{\"description\":\"the url is invalid\"}},\"description\":\"query ns table info\",\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"model Name.\",\"in\":\"path\",\"name\":\"modelName\"}],\"produces\":[\"application/json\"],\"tags\":[\"db\"],\"summary\":\"query ns table info\",\"consumes\":[\"application/json\"],\"operationId\":\"query_ns_table\"}},\"/ns/{nsInstanceId}/Instantiate\":{\"post\":{\"responses\":{\"200\":{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/JobInfo\"}},\"201\":{\"description\":\"Invalid Request\"}},\"parameters\":[{\"required\":true,\"type\":\"string\",\"description\":\"\",\"in\":\"path\",\"name\":\"nsInstanceId\"},{\"schema\":{\"$ref\":\"#/definitions/NsInstantiateRequest\"},\"description\":\"NS Instantiate Request Body\",\"required\":true,\"name\":\"NSInstantiateRequest\",\"in\":\"body\"}],\"tags\":[\"ns\"],\"description\":\"ns Instantiate\",\"summary\":\"ns Instantiate\",\"operationId\":\"ns_Instantiate\"}}},\"schemes\":[\"http\",\"https\"],\"produces\":[\"application/json\"],\"basePath\":\"/api/nslcm/v1\",\"definitions\":{\"NsInstanceInfo\":{\"type\":\"object\",\"properties\":{\"nsState\":{\"type\":\"string\"},\"vnfInfo\":{\"items\":{\"$ref\":\"#/definitions/vnfInfo\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"nsdId\":{\"type\":\"string\"},\"vlInfo\":{\"items\":{\"$ref\":\"#/definitions/vlInfo\"},\"type\":\"array\"},\"nsName\":{\"type\":\"string\"},\"vnffgInfo\":{\"items\":{\"$ref\":\"#/definitions/vnffgInfo\"},\"type\":\"array\"},\"description\":{\"type\":\"string\"}}},\"JobDetailInfo\":{\"type\":\"object\",\"properties\":{\"responseDescriptor\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"},\"responseHistoryList\":{\"items\":{\"$ref\":\"#/definitions/jobResponseInfo\"},\"type\":\"array\"},\"responseId\":{\"type\":\"string\"},\"errorCode\":{\"type\":\"string\"},\"progress\":{\"type\":\"string\"},\"statusDescription\":{\"type\":\"string\"}}},\"jobId\":{\"type\":\"string\"}}},\"VnfInfo\":{\"type\":\"object\",\"properties\":{\"vnfInstId\":{\"type\":\"string\"},\"vnfName\":{\"type\":\"string\"},\"vnfStatus\":{\"type\":\"string\"}}},\"DeleteResponse\":{\"type\":\"object\",\"properties\":{\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"NsHealRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceId\":{\"type\":\"string\"},\"cause\":{\"type\":\"string\"},\"additionalParams\":{\"type\":\"object\",\"properties\":{\"action\":{\"type\":\"string\"},\"actionvminfo\":{\"type\":\"object\",\"properties\":{\"vmname\":{\"type\":\"string\"},\"vmid\":{\"type\":\"string\"}}}}}}},\"NsScaleRequest\":{\"type\":\"object\",\"properties\":{\"scaleNsByStepsData\":{\"$ref\":\"#/definitions/NsScaleByStepsData\"},\"scaleType\":{\"type\":\"string\"}}},\"jobResponseInfo\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"},\"progress\":{\"type\":\"string\"},\"responseId\":{\"type\":\"string\"},\"statusDescription\":{\"type\":\"string\"},\"errorCode\":{\"type\":\"string\"}}},\"NSInstPostDetailRequest\":{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"}}},\"VlInfo\":{\"type\":\"object\",\"properties\":{\"vlId\":{\"type\":\"string\"},\"vlStatus\":{\"type\":\"string\"},\"vlName\":{\"type\":\"string\"}}},\"VnfPostResponse\":{\"type\":\"object\",\"properties\":{\"vnfInstId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"}}},\"NsCreateRequest\":{\"type\":\"object\",\"properties\":{\"nsName\":{\"type\":\"string\"},\"csarId\":{\"type\":\"string\",\"description\":\"the NS package ID\"},\"description\":{\"type\":\"string\"}}},\"VlPostResponse\":{\"type\":\"object\",\"properties\":{\"vlId\":{\"type\":\"string\"},\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"SfcPostRequest\":{\"type\":\"object\",\"properties\":{\"sdnControllerId\":{\"type\":\"string\"},\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"fpindex\":{\"type\":\"string\"}}},\"NsTerminateRequest\":{\"type\":\"object\",\"properties\":{\"gracefulTerminationTimeout\":{\"type\":\"string\"},\"terminationType\":{\"type\":\"string\"}}},\"JobProgressRequest\":{\"type\":\"object\",\"properties\":{\"progress\":{\"type\":\"string\"},\"errcode\":{\"type\":\"string\"},\"desc\":{\"type\":\"string\"}}},\"SfcInfo\":{\"type\":\"object\",\"properties\":{\"sfcName\":{\"type\":\"string\"},\"sfcInstId\":{\"type\":\"string\"},\"sfcStatus\":{\"type\":\"string\"}}},\"vnfInfo\":{\"type\":\"object\",\"properties\":{\"vnfInstanceId\":{\"type\":\"string\"},\"vnfdId\":{\"type\":\"string\"},\"vnfInstanceName\":{\"type\":\"string\"}}},\"LocationConstraint\":{\"type\":\"object\",\"properties\":{\"locationConstraints\":{\"type\":\"object\",\"properties\":{\"vimid\":{\"type\":\"string\"}}},\"vnfProfileId\":{\"type\":\"string\"}}},\"NsCreateResponse\":{\"type\":\"object\",\"properties\":{\"nsInstanceId\":{\"type\":\"string\"}}},\"VlPostRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"flavourId\":{\"type\":\"string\"},\"pnfInfo\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"extNSVirtualLink\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nestedNsInstanceId\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"jobId\":{\"type\":\"string\"},\"locationConstraints\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"vlIndex\":{\"type\":\"string\"}}},\"VnfPostRequest\":{\"type\":\"object\",\"properties\":{\"vnfInstanceData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"vnfIndex\":{\"type\":\"string\"},\"additionalParamForVnf\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nsInstanceId\":{\"type\":\"string\"},\"flavourId\":{\"type\":\"string\"},\"pnfInfo\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"extNSVirtualLink\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"additionalParamForNs\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"context\":{\"type\":\"string\"},\"sapData\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"nestedNsInstanceId\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"},\"jobId\":{\"type\":\"string\"},\"locationConstraints\":{\"items\":{\"type\":\"object\"},\"type\":\"array\"}}},\"DeleteVlResponse\":{\"type\":\"object\",\"properties\":{\"result\":{\"enum\":[0,1],\"type\":\"integer\"},\"detail\":{\"type\":\"string\"}}},\"vlInfo\":{\"type\":\"object\",\"properties\":{\"vldId\":{\"type\":\"string\"},\"vlInstanceName\":{\"type\":\"string\"},\"vlInstanceId\":{\"type\":\"string\"},\"relatedCpInstanceId\":{\"items\":{\"$ref\":\"#/definitions/cpInfo\"},\"type\":\"array\"}}},\"cpInfo\":{\"type\":\"object\",\"properties\":{\"cpInstanceId\":{\"type\":\"string\"},\"cpdId\":{\"type\":\"string\"},\"cpInstanceName\":{\"type\":\"string\"}}},\"SfcPostResponse\":{\"type\":\"object\",\"properties\":{\"sfcInstId\":{\"type\":\"string\"},\"jobId\":{\"type\":\"string\"}}},\"NsInstantiateRequest\":{\"type\":\"object\",\"properties\":{\"additionalParamForNs\":{\"type\":\"string\"},\"LocationConstraints\":{\"items\":{\"$ref\":\"#/definitions/LocationConstraint\"},\"type\":\"array\"}}},\"JobInfo\":{\"type\":\"object\",\"properties\":{\"jobId\":{\"type\":\"string\"}}},\"NsInstancesInfo\":{\"items\":{\"$ref\":\"#/definitions/NsInstanceInfo\"},\"type\":\"array\"},\"NsScaleByStepsData\":{\"type\":\"object\",\"properties\":{\"numberOfSteps\":{\"type\":\"integer\"},\"scalingDirection\":{\"type\":\"string\"},\"aspectId\":{\"type\":\"string\"}}},\"vnffgInfo\":{\"type\":\"object\",\"properties\":{\"cpId\":{\"type\":\"string\"},\"virtualLinkId\":{\"type\":\"string\"},\"vnfId\":{\"type\":\"string\"},\"pnfId\":{\"type\":\"string\"},\"nfp\":{\"type\":\"string\"},\"vnffgInstanceId\":{\"type\":\"string\"}}},\"TableInfo\":{\"type\":\"object\",\"properties\":{\"count\":{\"type\":\"string\"}}}},\"swagger\":\"2.0\",\"consumes\":[\"application/json\"]}","definition":""}]}}; diff --git a/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts b/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts index f0013bc5..c6cf60a8 100644 --- a/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts +++ b/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts @@ -12,10 +12,13 @@ import { Injectable } from '@angular/core'; import * as jsp from 'jsplumb'; -import { ModelService } from "./model.service"; -import { BroadcastService } from "./broadcast.service"; + import { Subscription } from 'rxjs/Subscription'; -import { WorkflowNode } from "../model/workflow/workflow-node"; +import { WorkflowNode } from '../model/workflow/workflow-node'; +import { BroadcastService } from './broadcast.service'; +import { ModelService } from './model.service'; +import { SequenceFlow } from '../model/workflow/sequence-flow'; +import { Position } from '../model/workflow/position'; /** * JsPlumbService @@ -23,68 +26,120 @@ import { WorkflowNode } from "../model/workflow/workflow-node"; */ @Injectable() export class JsPlumbService { - public jsplumbInstance; + public jsplumbInstanceMap = new Map(); public subscriptionMap = new Map(); - constructor(private processService: ModelService, private broadcastService: BroadcastService) { - this.jsplumbInstance = jsp.jsPlumb.getInstance({ - Container: 'canvas' + private padding = 20; + private rootClass = 'canvas'; + private selectNodes: WorkflowNode[] = []; + + constructor(private modelService: ModelService, private broadcastService: BroadcastService) { + this.broadcastService.selectedElement$.subscribe(elements => { + this.selectNodes = []; + if (elements && 0 < elements.length) { + for (let index = 0; index < elements.length; index++) { + let element = elements[index]; + if (this.modelService.isNode(element)) { + let node = element as WorkflowNode; + this.selectNodes.push(node); + } + } + } }); - this.initJsPlumbInstance(); - this.broadcastService.workflow.subscribe(Workflow => { - this.jsplumbInstance.reset(); - this.unsubscriptionAll(); - this.initJsPlumbInstance(); - this.buttonDraggable(); - this.buttonDroppable(); + } + + public connectChildrenNodes(parentNodeId: string) { + const jsplumbInstance = this.jsplumbInstanceMap.get(parentNodeId); + + const nodes: WorkflowNode[] = this.modelService.getChildrenNodes(parentNodeId); + nodes.forEach(node => this.connect4OneNode(node, jsplumbInstance)); + } + + public connect4OneNode(node: WorkflowNode, jsplumbInstance: any) { + node.connection.forEach(sequenceFlow => { + const connection = jsplumbInstance.connect({ + source: sequenceFlow.sourceRef, + target: sequenceFlow.targetRef, + }); + if (sequenceFlow.name) { + connection.setLabel(sequenceFlow.name); + } }); } + public initJsPlumbInstance(id: string) { + if (this.jsplumbInstanceMap.get(id)) { + return; + } + const jsplumbInstance = jsp.jsPlumb.getInstance(); - public initJsPlumbInstance() { - this.jsplumbInstance.importDefaults({ - Anchor: ['Top', 'RightMiddle', 'LeftMiddle', 'Bottom'], - Connector: [ - 'Flowchart', - { cornerRadius: 0, stub: 0, gap: 3 }, - ], - ConnectionOverlays: [ - [ - 'Arrow', - { direction: 1, foldback: 1, location: 1, width: 10, length: 10 }, - ], - ['Label', { label: '', id: 'label', cssClass: 'aLabel' }], - ], - Endpoint: 'Blank', + jsplumbInstance.importDefaults({ + Anchor: "Continuous", + Endpoint: "Blank", + Container: "pallete", + ReattachConnections: true, + Connector: ['Flowchart', { + stub: [0, 0], + cornerRadius: 5, + alwaysRespectStubs: true + }], PaintStyle: { - strokeWidth: 4, - stroke: 'black', + stroke: "#7D8695", + strokeWidth: 1, + radius: 1, + outlineStroke: "transform", + outlineWidth: 4 }, - HoverPaintStyle: { - strokeWidth: 4, - stroke: 'blue', + ConnectorStyle: { + stroke: "#7D8695", + strokeWidth: 1, + outlineStroke: "transform", + outlineWidth: 4 }, + ConnectorHoverStyle: { + stroke: "#00ABFF", + strokeWidth: 2, + outlineStroke: "transform", + outlineWidth: 4 + }, + ConnectionOverlays: [ + ['Arrow', { + location: 1, + id: 'arrow', + cssClass: 'icon-port', + width: 11, + length: 12 + }], + ['Label', { label: '', id: 'label' }] + ] }); // add connection to model data while a new connection is build - this.jsplumbInstance.bind('connection', info => { - this.processService.addSequenceFlow(info.connection.sourceId, info.connection.targetId); + jsplumbInstance.bind('connection', info => { + this.modelService.addConnection(info.connection.sourceId, info.connection.targetId); this.subscribe4Connection(info.connection); - info.connection.bind('click', connection => { - const sequenceFlow = this.processService.getSequenceFlow(connection.sourceId, connection.targetId); - this.broadcastService.broadcast(this.broadcastService.currentSequenceFlow, sequenceFlow); - this.broadcastService.broadcast(this.broadcastService.currentType, 'SequenceFlow'); + info.connection.bind('click', (connection, event) => { + if ('Label' === connection.type) { + return; + } + event.stopPropagation(); + const sequenceFlow = this.modelService.getSequenceFlow(connection.sourceId, connection.targetId); + this.broadcastService.broadcast(this.broadcastService.showProperty, null); + this.broadcastService.broadcast(this.broadcastService.selectedElement, [sequenceFlow]); }); info.connection.bind('dblclick', connection => { - const sequenceFlow = this.processService.getSequenceFlow(connection.sourceId, connection.targetId); - this.broadcastService.broadcast(this.broadcastService.sequenceFlow, sequenceFlow); - this.broadcastService.broadcast(this.broadcastService.showSequenceFlow, true); + if ('Label' === connection.type) { + return; + } + const sequenceFlow = this.modelService.getSequenceFlow(connection.sourceId, connection.targetId); + this.broadcastService.broadcast(this.broadcastService.showProperty, sequenceFlow); }); }); + this.jsplumbInstanceMap.set(id, jsplumbInstance); } private subscribe4Connection(connection: any) { @@ -94,128 +149,414 @@ export class JsPlumbService { sequenceFlowSubscription.unsubscribe(); } - sequenceFlowSubscription = this.broadcastService.currentSequenceFlow$.subscribe(currentSequenceFlow => { - if (currentSequenceFlow.sourceRef === connection.sourceId - && currentSequenceFlow.targetRef === connection.targetId) { - connection.setPaintStyle({ stroke: 'red' }); + let currentThis = this; + sequenceFlowSubscription = this.broadcastService.selectedElement$.subscribe(elements => { + let selected = false; + if (elements && 0 < elements.length) { + for (let index = 0; index < elements.length; index++) { + let element = elements[index]; + if (!this.modelService.isNode(element)) { + let sequence = element as SequenceFlow; + if (sequence.sourceRef === connection.sourceId + && sequence.targetRef === connection.targetId) { + selected = true; + } + } + } + } + if (selected) { + connection.setPaintStyle({ + stroke: '#00ABFF', + strokeWidth: 1, + radius: 1, + outlineStroke: "transform", + outlineWidth: 4 + }); } else { - connection.setPaintStyle({ stroke: 'black' }); + connection.setPaintStyle({ + stroke: '#7D8695', + strokeWidth: 1, + radius: 1, + outlineStroke: "transform", + outlineWidth: 4 + }); } }); - this.subscriptionMap.set(pre + 'sequenceFlowSubscription', sequenceFlowSubscription); - - let typeSubscription = this.subscriptionMap.get(pre + 'typeSubscription'); - if (typeSubscription && !typeSubscription.closed) { - typeSubscription.unsubscribe(); - } - typeSubscription = this.broadcastService.currentType$.subscribe(type => { - if (type === 'WorkflowNode') { - connection.setPaintStyle({ stroke: 'black' }); - } - }); - this.subscriptionMap.set(pre + 'typeSubscription', typeSubscription); } private unsubscription4Connection(connectionSelection: any) { connectionSelection.each(connection => { const pre = connection.sourceId + connection.targetId; this.subscriptionMap.get(pre + 'sequenceFlowSubscription').unsubscribe(); - this.subscriptionMap.get(pre + 'typeSubscription').unsubscribe(); }); } - private unsubscriptionAll() { - this.subscriptionMap.forEach(subscription => subscription.unsubscribe()); + public deleteConnect(sourceId: string, targetId: string) { + const sourceNode = this.modelService.getNodeMap().get(sourceId); + const jsplumbInstance = this.jsplumbInstanceMap.get(sourceNode.parentId); + const connectionSelection = jsplumbInstance.select({ source: sourceId, target: targetId }); + this.unsubscription4Connection(connectionSelection); + connectionSelection.delete(); + } + + public setLabel(sourceId: string, targetId: string, label: string) { + const sourceNode = this.modelService.getNodeMap().get(sourceId); + const jsplumbInstance = this.jsplumbInstanceMap.get(sourceNode.parentId); + const connections = jsplumbInstance.select({ source: sourceId, target: targetId }); + connections.setLabel(label); } - public initNode() { - this.processService.getProcess().forEach(node => { - this.jsplumbInstance.draggable(node.id, { - stop: event => { - node.position.left = event.pos[0]; - node.position.top = event.pos[1]; - }, - }); + public getParentNodeId(id: string): string { + const nodeElement = jsp.jsPlumb.getSelector('#' + id); + const parentNode = this.getParentNodeEl(nodeElement[0]); - this.jsplumbInstance.makeTarget(node.id, { - detachable: false, - isTarget: true, - maxConnections: -1, - }); + return parentNode ? parentNode.id : null; + } - this.jsplumbInstance.makeSource(node.id, { - filter: '.anchor, .anchor *', - detachable: false, - isSource: true, - maxConnections: -1, - }); + public initNode(node: WorkflowNode) { + const jsplumbInstance = this.jsplumbInstanceMap.get(node.parentId); + + this.jsplumbInstanceMap.get(this.modelService.rootNodeId).draggable(node.id, { + scope: 'node', + filter: '.ui-resizable-handle', + classes: { + 'ui-draggable': 'dragging' + }, + // grid: [5, 5], + drag: event => { + // out of container edge, reset to minimal value. + if (0 > event.pos[0]) { + event.el.style.left = '0px'; + } + if (0 > event.pos[1]) { + event.el.style.top = '0px'; + } + + if (0 < this.selectNodes.length) { + let moveAll = false; + this.selectNodes.forEach(element => { + if (element.id === event.el.id) { + moveAll = true; + } + }); + if (moveAll) { + this.selectNodes.forEach(selectNode => { + if (selectNode.id !== event.el.id) { + selectNode.position.left += event.e.movementX; + selectNode.position.left = 0 > selectNode.position.left ? 0 : selectNode.position.left; + selectNode.position.top += event.e.movementY; + selectNode.position.top = 0 > selectNode.position.top ? 0 : selectNode.position.top; + } + jsplumbInstance.revalidate(jsplumbInstance.getSelector('#' + selectNode.id)); + }); + } + } + }, + stop: event => { + this.selectNodes.forEach(selectNode => { + jsplumbInstance.revalidate(jsplumbInstance.getSelector('#' + selectNode.id)); + }); + } + }); + + jsplumbInstance.makeTarget(node.id, { + maxConnections: -1, + beforeDrop: function (info) { + const sourceId = info.sourceId; + const targetId = info.targetId; + if (sourceId === targetId) { + return false; + } + const sameConnections = this.instance.getConnections({ source: sourceId, target: targetId }); + if (sameConnections && 0 < sameConnections.length) { + return false; + } + return true; + } + + }); + + jsplumbInstance.makeSource(node.id, { + filter: '.anchor, .anchor *', + maxConnections: -1, }); } - public connectNodes() { - const nodes: WorkflowNode[] = this.processService.getProcess(); - nodes.forEach(node => this.connect4OneNode(node)); + public nodeDroppable(node: WorkflowNode, rank: number) { + const jsplumbInstance = this.jsplumbInstanceMap.get(node.parentId); + + const selector = jsplumbInstance.getSelector('#' + node.id); + this.jsplumbInstanceMap.get(this.modelService.rootNodeId).droppable(selector, { + scope: 'node', + rank, + tolerance: 'pointer', + drop: event => { + if (!this.isChildNode(event.drop.el, event.drag.el)) { + this.drop(event); + } + return true; + }, + canDrop: drag => { + const nodeMap = this.modelService.getNodeMap(); + const ancestorNode = nodeMap.get(drag.el.id); + + const isAncestor = this.modelService.isDescendantNode(ancestorNode, node.id); + return !isAncestor; + }, + }); } - public connect4OneNode(node: WorkflowNode) { - node.sequenceFlows.forEach(sequenceFlow => { - const connection = this.jsplumbInstance.connect({ - source: sequenceFlow.sourceRef, - target: sequenceFlow.targetRef, - }); - if (sequenceFlow.name) { - connection.setLabel(sequenceFlow.name); + private isChildNode(childElement, parentElement) { + while (childElement !== parentElement) { + childElement = childElement.parentNode; + if (childElement.classList.contains('canvas')) { + return false; } - }); + } + + return true; } - public setLabel(sourceId: string, targetId: string, label: string) { - const sourceNode = this.processService.getNodeById(sourceId); - const connections = this.jsplumbInstance.select({ source: sourceId, target: targetId }); - connections.setLabel(label); + private drop(event) { + const dragEl = event.drag.el; + const dropEl = event.drop.el; + + this.resizeParent(dragEl, dropEl); + + const nodeLeft = dragEl.getBoundingClientRect().left; + const nodeTop = dragEl.getBoundingClientRect().top; + const parentLeft = dropEl.getBoundingClientRect().left; + const parentTop = dropEl.getBoundingClientRect().top; + const left = nodeLeft - parentLeft + dropEl.scrollLeft; + const top = nodeTop - parentTop + dropEl.scrollTop; + dragEl.style.top = top + 'px'; + dragEl.style.left = left + 'px'; + + // 12 is title height + this.modelService.updatePosition(dragEl.id, left, top, dragEl.getBoundingClientRect().width, dragEl.getBoundingClientRect().height - 12); + + const originalParentNode = this.getParentNodeEl(dragEl); + const originalParentNodeId = originalParentNode ? originalParentNode.id : this.modelService.rootNodeId; + + const targetParentNodeId = dropEl.classList.contains('node') ? dropEl.id : this.modelService.rootNodeId; + this.changeParent(dragEl.id, originalParentNodeId, targetParentNodeId); } - public deleteConnect(sourceId: string, targetId: string) { - const sourceNode = this.processService.getNodeById(sourceId); - const connectionSelection = this.jsplumbInstance.select({ source: sourceId, target: targetId }); - this.unsubscription4Connection(connectionSelection); - connectionSelection.delete(); + private changeParent(id: string, originalParentNodeId: string, targetParentNodeId: string) { + if (originalParentNodeId !== targetParentNodeId) { + this.jsplumbInstanceMap.get(originalParentNodeId).removeAllEndpoints(id); + this.modelService.changeParent(id, originalParentNodeId, targetParentNodeId); + } } - public remove(nodeId: string) { - // unsubscription4Connection - const connectionsAsSource = this.jsplumbInstance.select({ source: nodeId }); - this.unsubscription4Connection(connectionsAsSource); - const connectionsAsTarget = this.jsplumbInstance.select({ target: nodeId }); - this.unsubscription4Connection(connectionsAsTarget); + private getParentNodeEl(element) { + while (!(element.parentNode.classList.contains('node') || element.parentNode.classList.contains('canvas'))) { + element = element.parentNode; + } - this.jsplumbInstance.remove(nodeId); + if (element.parentNode.classList.contains('canvas')) { // top level node + return null; + } else { + return element.parentNode; + } + } + + public canvasDroppable() { + const jsplumbInstance = this.jsplumbInstanceMap.get(this.modelService.rootNodeId); + const canvasSelector = jsplumbInstance.getSelector('.canvas'); + jsplumbInstance.droppable(canvasSelector, { + scope: 'node', + rank: 0, + grid: [5, 5], + drop: event => this.drop(event), + }); } public buttonDraggable() { - const selector = this.jsplumbInstance.getSelector('.toolbar .item'); - this.jsplumbInstance.draggable(selector, - { - scope: 'btn', - clone: true, - }); + const jsplumbInstance = this.jsplumbInstanceMap.get(this.modelService.rootNodeId); + const selector = jsplumbInstance.getSelector('.item'); + jsplumbInstance.draggable(selector, { + scope: 'btn', + clone: true + }); } public buttonDroppable() { - const selector = this.jsplumbInstance.getSelector('.canvas'); - this.jsplumbInstance.droppable(selector, { + const jsplumbInstance = this.jsplumbInstanceMap.get(this.modelService.rootNodeId); + const selector = jsplumbInstance.getSelector('.canvas'); + jsplumbInstance.droppable(selector, { scope: 'btn', + // grid: [5, 5], drop: event => { - const el = this.jsplumbInstance.getSelector(event.drag.el); + const el = jsplumbInstance.getSelector(event.drag.el); const type = el.attributes.nodeType.value; - // Mouse position minus drop canvas start position and minus icon half size - const left = event.e.clientX - 220 - (event.e.offsetX / 2); - const top = event.e.clientY - 70 - (event.e.offsetY / 2); - - this.processService.addNode(type, type, top, left); + // Mouse position minus drop canvas start position plus scroll position. + let left = event.e.x - event.drop.pagePosition[0] + event.drop.el.scrollLeft; + let top = event.e.y - event.drop.pagePosition[1] + event.drop.el.scrollTop; + if (0 > left) { + left = 0; + } + if (0 > top) { + top = 0; + } + const name = event.drag.el.children[1].innerText; + this.modelService.addNode(name, type, left, top); }, }); } + public remove(node: WorkflowNode) { + const jsplumbInstance = this.jsplumbInstanceMap.get(node.parentId); + + // unsubscription4Connection + const connectionsAsSource = jsplumbInstance.select({ source: node.id }); + this.unsubscription4Connection(connectionsAsSource); + const connectionsAsTarget = jsplumbInstance.select({ target: node.id }); + this.unsubscription4Connection(connectionsAsTarget); + + jsplumbInstance.remove(node.id); + } + + public resizeParent(element: any, parentElement: any) { + if (parentElement.classList.contains(this.rootClass)) { + return; + } + + if (!parentElement.classList.contains('node')) { + this.resizeParent(element, parentElement.parentNode); + return; + } + + const leftResized = this.resizeParentLeft(element, parentElement); + const rightResized = this.resizeParentRight(element, parentElement); + const topResized = this.resizeParentTop(element, parentElement); + const bottomResized = this.resizeParentBottom(element, parentElement); + + if (leftResized || rightResized || topResized || bottomResized) { + if (parentElement.classList.contains('node')) { + const rect = parentElement.getBoundingClientRect(); + this.modelService.updatePosition(parentElement.id, + parentElement.offsetLeft, + parentElement.offsetTop, + // title height + rect.width, rect.height - 12); + } + this.resizeParent(parentElement, parentElement.parentNode); + } + } + + private resizeParentLeft(element: any, parentElement: any): boolean { + let resized = false; + + const actualLeft = element.getBoundingClientRect().left; + const actualParentLeft = parentElement.getBoundingClientRect().left; + + if (actualLeft - this.padding < actualParentLeft) { + const width = actualParentLeft - actualLeft + this.padding; + + this.translateElement(parentElement, -width, 0, width, 0); + this.translateChildren(parentElement, element, width, 0); + resized = true; + } + + return resized; + } + + private resizeParentRight(element: any, parentElement: any): boolean { + let resized = false; + + const actualLeft = element.getBoundingClientRect().left; + const actualRight = actualLeft + element.offsetWidth; + + const actualParentLeft = parentElement.getBoundingClientRect().left; + + if ((actualParentLeft + parentElement.offsetWidth) < actualRight + this.padding) { + this.setElementWidth(parentElement, actualRight + this.padding - actualParentLeft); + resized = true; + } + + return resized; + } + + private resizeParentBottom(element: any, parentElement: any): boolean { + let resized = false; + + const actualTop = element.getBoundingClientRect().top; + const actualBottom = actualTop + element.offsetHeight; + + const actualParentTop = parentElement.getBoundingClientRect().top; + const actualParentBottom = actualParentTop + parentElement.offsetHeight; + + if (actualParentBottom < actualBottom + this.padding) { + this.setElementHeight(parentElement, actualBottom + this.padding - actualParentTop); + resized = true; + } + + return resized; + } + + private resizeParentTop(element: any, parentElement: any): boolean { + let resized = false; + + const actualTop = element.getBoundingClientRect().top; + const actualParentTop = parentElement.getBoundingClientRect().top; + + if (actualTop - this.padding < actualParentTop) { + const height = actualParentTop - actualTop + this.padding; + + this.translateElement(parentElement, 0, -height, 0, height); + this.translateChildren(parentElement, element, 0, height); + resized = true; + } + + return resized; + } + + private translateElement(element, left: number, top: number, width: number, height: number) { + const offsetLeft = element.offsetLeft + left; + element.style.left = offsetLeft + 'px'; + + const offsetTop = element.offsetTop + top; + element.style.top = offsetTop + 'px'; + + const offsetWidth = element.offsetWidth + width; + element.style.width = offsetWidth + 'px'; + + const offsetHeight = element.offsetHeight + height; + element.style.height = offsetHeight + 'px'; + + if (element.classList.contains('node')) { + const node = this.modelService.getNodeMap().get(element.id); + this.jsplumbInstanceMap.get(node.parentId).revalidate(element.id); + } + } + + private translateChildren(parentElment, excludeElement, left: number, top: number) { + const len = parentElment.children.length; + for (let i = 0; i < len; i++) { + const childElment = parentElment.children[i]; + if (childElment.localName === 'b4t-node') { + this.translateElement(childElment.children[0], left, top, 0, 0); + } + } + } + + private setElementHeight(element, height: number) { + element.style.height = height + 'px'; + } + + private setElementWidth(element, width: number) { + element.style.width = width + 'px'; + } + + private getActualPosition(element, offset: string) { + let actualPosition = element[offset]; + let current = element.offsetParent; + while (current !== null) { + actualPosition += element[offset]; + current = current.offsetParent; + } + return actualPosition; + } } diff --git a/sdc-workflow-designer-ui/src/app/services/model.service.ts b/sdc-workflow-designer-ui/src/app/services/model.service.ts index 6ce49d04..65d3e490 100644 --- a/sdc-workflow-designer-ui/src/app/services/model.service.ts +++ b/sdc-workflow-designer-ui/src/app/services/model.service.ts @@ -18,12 +18,22 @@ import { NodeType } from "../model/workflow/node-type.enum"; import { StartEvent } from "../model/workflow/start-event"; import { SequenceFlow } from "../model/workflow/sequence-flow"; import { RestTask } from "../model/workflow/rest-task"; +import { ErrorEvent } from "../model/workflow/error-event"; import { PlanTreeviewItem } from "../model/plan-treeview-item"; import { WorkflowConfigService } from "./workflow-config.service"; import { Swagger, SwaggerModelSimple, SwaggerReferenceObject } from "../model/swagger"; import { WorkflowService } from "./workflow.service"; import { IntermediateCatchEvent } from "../model/workflow/intermediate-catch-event"; import { ScriptTask } from "../model/workflow/script-task"; +import { ToscaNodeTask } from '../model/workflow/tosca-node-task'; +import { NodeTemplate } from '../model/topology/node-template'; +import { SubProcess } from '../model/workflow/sub-process'; +import { TimerEventDefinition, TimerEventDefinitionType } from '../model/workflow/timer-event-definition'; +import { Parameter } from '../model/workflow/parameter'; +import { ValueSource } from '../model/value-source.enum'; +import { RestService } from './rest.service'; +import { BroadcastService } from './broadcast.service'; +import { RestConfig } from '../model/rest-config'; /** * WorkflowService @@ -31,78 +41,231 @@ import { ScriptTask } from "../model/workflow/script-task"; */ @Injectable() export class ModelService { - - constructor(private workflowService: WorkflowService, private configService: WorkflowConfigService) { - + public rootNodeId = 'root'; + + private planModel: PlanModel = new PlanModel(); + + constructor(private broadcastService: BroadcastService, private restService: RestService, private workflowService: WorkflowService, private configService: WorkflowConfigService) { + this.broadcastService.planModel$.subscribe(plan => { + plan.nodes.forEach(node => { + switch (node.type) { + case NodeType[NodeType.startEvent]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.endEvent]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.restTask]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.errorStartEvent]: + case NodeType[NodeType.errorEndEvent]: + node.position.width = 26; + node.position.height = 26; + break; + case NodeType[NodeType.toscaNodeManagementTask]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.subProcess]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.intermediateCatchEvent]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.scriptTask]: + node.position.width = 56; + node.position.height = 56; + break; + case NodeType[NodeType.exclusiveGateway]: + case NodeType[NodeType.parallelGateway]: + node.position.width = 26; + node.position.height = 26; + break; + default: + node.position.width = 56; + node.position.height = 56; + break; + } + }); + this.planModel = plan; + }); + this.broadcastService.updateModelRestConfig$.subscribe(restConfigs => { + this.updateRestConfig(restConfigs); + }); } public getProcess(): WorkflowNode[] { return this.workflowService.planModel.nodes; } - public addNode(name: string, type: string, top: number, left: number): WorkflowNode { - let node: WorkflowNode; - switch (type) { - case NodeType[NodeType.startEvent]: - node = new StartEvent(this.createId(), name, type, new Position(top, left), []); - break; - case NodeType[NodeType.restTask]: - node = new RestTask(this.createId(), name, type, new Position(top, left), []); - break; - case NodeType[NodeType.intermediateCatchEvent]: - node = new IntermediateCatchEvent(this.createId(), name, type, new Position(top, left), []); - break; - case NodeType[NodeType.scriptTask]: - node = new ScriptTask(this.createId(), name, type, new Position(top, left), []); - break; - default: - node = new WorkflowNode(this.createId(), name, type, new Position(top, left), []); - break; + public getNodes(): WorkflowNode[] { + return this.planModel.nodes; + } + + public addConnection(sourceId: string, targetId: string) { + const node = this.getNodeMap().get(sourceId); + if (node) { + const index = node.connection.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId); + if (index === -1) { + const sequenceFlow: SequenceFlow = { sourceRef: sourceId, targetRef: targetId }; + node.connection.push(sequenceFlow); + } } + } - this.getProcess().push(node); - return node; + public deleteConnection(sourceId: string, targetId: string) { + const node = this.getNodeMap().get(sourceId); + if (node) { + const index = node.connection.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId); + if (index !== -1) { + node.connection.splice(index, 1); + } + } } - public deleteNode(nodeId: string): WorkflowNode { + public deleteNode(parentId: string, nodeId: string): WorkflowNode { + const nodeMap = this.getNodeMap(); + + const nodes = this.getChildrenNodes(parentId); + // delete related connections - this.getProcess().forEach(node => this.deleteSequenceFlow(node.id, nodeId)); + nodes.forEach(node => this.deleteConnection(node.id, nodeId)); // delete current node - const index = this.getProcess().findIndex(node => node.id === nodeId); + const index = nodes.findIndex(node => node.id === nodeId); if (index !== -1) { - const node = this.getProcess().splice(index, 1)[0]; - node.sequenceFlows = []; + const node = nodes.splice(index, 1)[0]; + node.connection = []; return node; } - return undefined; + return null; } - public addSequenceFlow(sourceId: string, targetId: string) { - const node = this.getNodeById(sourceId); - if (node) { - const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId); - if (index === -1) { - node.sequenceFlows.push(new SequenceFlow(sourceId, targetId)); - } + public addChild(parentId: string, child: WorkflowNode) { + this.getChildrenNodes(parentId).push(child); + } + + public deleteChild(node: SubProcess, id: string): WorkflowNode { + const index = node.children.findIndex(child => child.id === id); + if (index !== -1) { + const deletedNode = node.children.splice(index, 1); + return deletedNode[0]; } + + return null; } - public deleteSequenceFlow(sourceId: string, targetId: string) { - const node = this.getNodeById(sourceId); - if (node) { - const index = node.sequenceFlows.findIndex(sequenceFlow => sequenceFlow.targetRef === targetId); - if (index !== -1) { - node.sequenceFlows.splice(index, 1); + public updateRestConfig(restConfigs: RestConfig[]): void { + this.planModel.configs = { restConfigs: restConfigs }; + // console.log(this.planModel.configs); + } + + public getNodeMap(): Map { + const map = new Map(); + this.toNodeMap(this.planModel.nodes, map); + return map; + } + + private toNodeMap(nodes: WorkflowNode[], map: Map) { + nodes.forEach(node => { + if (node.type === 'subProcess') { + this.toNodeMap((node).children, map); } + map.set(node.id, node); + }); + } + + public addNode(name: string, type: string, left: number, top: number) { + const id = this.createId(); + const workflowPos = new Position(left, top); + const node = this.createNodeByType(id, name, type, workflowPos); + this.planModel.nodes.push(node); + } + + private createNodeByType(id: string, name: string, type: string, position: Position): WorkflowNode { + const bigPosition = new Position(position.left, position.top, 56, 56); + const smallPosition = new Position(position.left, position.top, 26, 26); + switch (type) { + case NodeType[NodeType.startEvent]: + let startEventNode: StartEvent = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], parameters: [] + }; + return startEventNode; + case NodeType[NodeType.endEvent]: + let endEventNode: WorkflowNode = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [] + }; + return endEventNode; + case NodeType[NodeType.restTask]: + let restTaskNode: RestTask = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], produces: [], consumes: [], parameters: [], responses: [] + }; + return restTaskNode; + case NodeType[NodeType.errorStartEvent]: + case NodeType[NodeType.errorEndEvent]: + let errorEventNode: ErrorEvent = { + id: id, type: type, name: '', parentId: this.rootNodeId, + position: smallPosition, connection: [], parameter: new Parameter('errorRef', '', ValueSource[ValueSource.String]) + }; + return errorEventNode; + case NodeType[NodeType.toscaNodeManagementTask]: + let toscaNodeTask: ToscaNodeTask = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], input: [], output: [], template: new NodeTemplate() + }; + return toscaNodeTask; + case NodeType[NodeType.subProcess]: + let subProcess: SubProcess = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], children: [] + }; + return subProcess; + case NodeType[NodeType.intermediateCatchEvent]: + let intermediateCatchEvent: IntermediateCatchEvent = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], timerEventDefinition: { type: TimerEventDefinitionType[TimerEventDefinitionType.timeDuration] } + }; + return intermediateCatchEvent; + case NodeType[NodeType.scriptTask]: + let scriptTask: ScriptTask = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [], scriptFormat: 'JavaScript' + }; + return scriptTask; + case NodeType[NodeType.exclusiveGateway]: + case NodeType[NodeType.parallelGateway]: + let getway: WorkflowNode = { + id: id, type: type, name: '', parentId: this.rootNodeId, + position: smallPosition, connection: [] + }; + return getway; + default: + let node: WorkflowNode = { + id: id, type: type, name: name, parentId: this.rootNodeId, + position: bigPosition, connection: [] + }; + return node; } } + public isNode(object: any): boolean { + return undefined !== object.type; + } + public getSequenceFlow(sourceRef: string, targetRef: string): SequenceFlow { const node = this.getNodeById(sourceRef); if (node) { - const sequenceFlow = node.sequenceFlows.find(tmp => tmp.targetRef === targetRef); + const sequenceFlow = node.connection.find(tmp => tmp.targetRef === targetRef); return sequenceFlow; } else { return undefined; @@ -123,6 +286,9 @@ export class ModelService { case NodeType[NodeType.startEvent]: params.push(this.loadOutput4StartEvent(node)); break; + case NodeType[NodeType.toscaNodeManagementTask]: + params.push(this.loadOutput4ToscaNodeTask(node)); + break; case NodeType[NodeType.restTask]: params.push(this.loadOutput4RestTask(node)); break; @@ -135,54 +301,73 @@ export class ModelService { } private loadOutput4StartEvent(node: StartEvent): PlanTreeviewItem { - const startItem = new PlanTreeviewItem(node.name, `[${node.id}]`, []); + const startItem = new PlanTreeviewItem(node.name, `[${node.id}]`, [], false); node.parameters.map(param => startItem.children.push(new PlanTreeviewItem(param.name, `[${param.name}]`, []))); return startItem; } + private loadOutput4ToscaNodeTask(node: ToscaNodeTask): PlanTreeviewItem { + const item = new PlanTreeviewItem(node.name, `[${node.id}]`, [], false); + item.children.push(this.createStatusCodeTreeViewItem(node.id)); + const responseItem = this.createResponseTreeViewItem(node.id); + item.children.push(responseItem); + + node.output.map(param => + responseItem.children.push(new PlanTreeviewItem(param.name, `${responseItem.value}.[${param.name}]`, []))); + return item; + } + private loadOutput4RestTask(node: RestTask): PlanTreeviewItem { - const item = new PlanTreeviewItem(node.name, `[${node.id}]`, []); + const item = new PlanTreeviewItem(node.name, `[${node.id}]`, [], false); item.children.push(this.createStatusCodeTreeViewItem(node.id)); if (node.responses.length !== 0) { // load rest responses const responseItem = this.createResponseTreeViewItem(node.id); item.children.push(responseItem); + // todo: should list all available response or only the first one? if (node.responses[0]) { - const swagger = this.configService.getSwaggerInfo(node.serviceName, node.serviceVersion); - const swaggerDefinition = this.configService.getDefinition(swagger, node.responses[0].schema.$ref); - this.loadParamsBySwaggerDefinition(responseItem, swagger, swaggerDefinition); + const swagger = this.restService.getSwaggerInfo(node.restConfigId); + const SwaggerReferenceObject = node.responses[0].schema as SwaggerReferenceObject; + const swaggerDefinition = this.restService.getDefinition(swagger, SwaggerReferenceObject.$ref); + this.loadParamsBySwaggerDefinition(responseItem, swagger, swaggerDefinition); } } return item; } - private createStatusCodeTreeViewItem(nodeId: string): PlanTreeviewItem { - return new PlanTreeviewItem('statusCode', `[${nodeId}].[statusCode]`, []); - } - - private createResponseTreeViewItem(nodeId: string): PlanTreeviewItem { - return new PlanTreeviewItem('response', `[${nodeId}].[responseBody]`, []); - } - - private loadParamsBySwaggerDefinition(parentItem: PlanTreeviewItem, swagger: Swagger, definition: SwaggerModelSimple) { + private loadParamsBySwaggerDefinition(parentItem: PlanTreeviewItem, swagger: Swagger, definition: any) { Object.getOwnPropertyNames(definition.properties).map(key => { const property = definition.properties[key]; const value = `${parentItem.value}.[${key}]`; const propertyItem = new PlanTreeviewItem(key, value, []); parentItem.children.push(propertyItem); + // reference to swagger.ts function getSchemaObject() if (property instanceof SwaggerReferenceObject) { - const propertyDefinition = this.configService.getDefinition(swagger, property.$ref); - this.loadParamsBySwaggerDefinition(propertyItem, swagger, - propertyDefinition); + // handle reference parameter. + const propertyDefinition = this.restService.getDefinition(swagger, property.$ref); + this.loadParamsBySwaggerDefinition(propertyItem, swagger, propertyDefinition); + } else if (property instanceof SwaggerModelSimple) { + // handle object parameter. + this.loadParamsBySwaggerDefinition(propertyItem, swagger, property); + } else { + // skip } return propertyItem; }); } + private createStatusCodeTreeViewItem(nodeId: string): PlanTreeviewItem { + return new PlanTreeviewItem('statusCode', `[${nodeId}].[statusCode]`, []); + } + + private createResponseTreeViewItem(nodeId: string): PlanTreeviewItem { + return new PlanTreeviewItem('response', `[${nodeId}].[responseBody]`, []); + } + public getPreNodes(nodeId: string, preNodes: WorkflowNode[]) { const preNode4CurrentNode = []; this.getProcess().forEach(node => { @@ -201,7 +386,7 @@ export class ModelService { } public isPreNode(preNode: WorkflowNode, id: string): boolean { - const targetNode = preNode.sequenceFlows.find(connection => connection.targetRef === id); + const targetNode = preNode.connection.find(connection => connection.targetRef === id); return targetNode !== undefined; } @@ -210,15 +395,62 @@ export class ModelService { } private createId() { - const idSet = new Set(); - this.getProcess().forEach(node => idSet.add(node.id)); + const nodeMap = this.getNodeMap(); - for (let i = 0; i < idSet.size; i++) { - if (!idSet.has('node' + i)) { - return 'node' + i; + for (let i = 0; i < nodeMap.size; i++) { + const key = 'node' + i; + if (!nodeMap.get(key)) { + return key; } } - return 'node' + idSet.size; + return 'node' + nodeMap.size; + } + + public getChildrenNodes(parentId: string): WorkflowNode[] { + if (!parentId || parentId === this.rootNodeId) { + return this.planModel.nodes; + } else { + const node = this.getNodeMap().get(parentId); + if (node.type === 'subProcess') { + return (node).children; + } else { + return []; + } + } + } + + public changeParent(id: string, originalParentId: string, targetParentId: string) { + if (originalParentId === targetParentId) { + return; + } + + const node: WorkflowNode = this.deleteNode(originalParentId, id); + node.parentId = targetParentId; + + if (targetParentId) { + this.addChild(targetParentId, node); + } else { + this.planModel.nodes.push(node); + } + } + + public updatePosition(id: string, left: number, top: number, width: number, height: number) { + const node = this.getNodeMap().get(id); + node.position.left = left; + node.position.top = top; + node.position.width = width; + node.position.height = height; + } + + public isDescendantNode(node: WorkflowNode, descendantId: string): boolean { + if (NodeType[NodeType.subProcess] !== node.type) { + return false; + } + const tmp = (node).children.find(child => { + return child.id === descendantId || (NodeType[NodeType.subProcess] === child.type && this.isDescendantNode(child, descendantId)); + }); + + return tmp !== undefined; } } diff --git a/sdc-workflow-designer-ui/src/app/services/rest.service.ts b/sdc-workflow-designer-ui/src/app/services/rest.service.ts new file mode 100644 index 00000000..db69d78b --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/services/rest.service.ts @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2017 ZTE Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * ZTE - initial API and implementation and/or initial documentation + *******************************************************************************/ + +import { Injectable } from '@angular/core'; +import { Http, RequestOptionsArgs } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; +import { isNullOrUndefined } from 'util'; + +import { SwaggerMethod } from '../model/swagger'; +import { SwaggerResponse } from '../model/swagger'; +import { Swagger, SwaggerSchemaObject } from '../model/swagger'; +import { RestConfig } from '../model/rest-config'; +import { HttpService } from '../util/http.service'; +import { BroadcastService } from './broadcast.service'; + +@Injectable() +export class RestService { + + private restConfigs: RestConfig[] = []; + private runtimeURL = '/openoapi/catalog/v1/sys/config'; + private msbPublishServiceURL = '/api/msdiscover/v1/publishservicelist'; + + constructor(private broadcastService: BroadcastService, private http: Http) { + // this.initSwaggerInfoByMSB(); + } + + // public addRestConfig(): RestConfig { + // let index = 0; + // this.restConfigs.forEach(config => { + // const currentId = parseInt(config.id); + // if (currentId > index) { + // index = currentId; + // } + // }); + + // index += 1; + + // const restConfig = new RestConfig(index.toString(), 'new Config', '', '', false); + // this.restConfigs.push(restConfig); + + // return restConfig; + // } + + // public initSwaggerInfo(restConfig: RestConfig) { + // if (restConfig.dynamic && restConfig.definition) { + // this.getDynamicSwaggerInfo(restConfig.definition).subscribe(response => restConfig.swagger = new Swagger(response)); + // } else { + // restConfig.swagger = new Swagger(restConfig.swagger); + // } + // } + + public getRestConfigs() { + return this.restConfigs; + } + + // public getDynamicSwaggerInfo(url: string): Observable { + // const options: any = { + // headers: { + // Accept: 'application/json', + // }, + // }; + // return this.httpService.get(url, options); + // } + + public getSwaggerInfo(id: string): Swagger { + const restConfig = this.restConfigs.find(tmp => tmp.id === id); + return restConfig === undefined ? undefined : restConfig.swagger; + } + + public getResponseParameters(swagger: Swagger, interfaceUrl: string, operation: string): SwaggerResponse[] { + const path = swagger.paths[interfaceUrl]; + const method: SwaggerMethod = path[operation]; + let responses: SwaggerResponse[] = []; + + for (const key of Object.keys(method.responses)) { + if (key.startsWith('20') && method.responses[key].schema && method.responses[key].schema.$ref) { + let response: SwaggerResponse = method.responses[key]; + responses.push(response); + } + } + + return responses; + } + + public getDefinition(swagger: Swagger, position: string): SwaggerSchemaObject { + const definitionName = position.substring('#/definitions/'.length); + + return swagger.definitions[definitionName]; + } + + private initSwaggerInfoByMSB(): void { + const options: any = { + headers: { + Accept: 'application/json', + } + }; + let restConfigs = this.restConfigs; + this.http.get(this.runtimeURL).subscribe(runtimeResponse => { + const tenant = runtimeResponse.json().tenant; + console.log('Current namespace is:' + tenant); + this.http.get(this.msbPublishServiceURL, { params: { namespace: tenant } }).subscribe(serviceResponse => { + if (!Array.isArray(serviceResponse.json())) { + return; + } + const services = serviceResponse.json(); + const protocel = location.protocol.slice(0, location.protocol.length - 1); + const swaggerObservableArray: Observable[] = []; + services.forEach(serviceInfo => { + if ('REST' === serviceInfo.protocol && protocel === serviceInfo.publish_protocol) { + // this service don't have sawgger file. + if ('/activiti-rest' !== serviceInfo.publish_url) { + const id = serviceInfo.serviceName + '.' + serviceInfo.version; + restConfigs.push(new RestConfig(id, serviceInfo.serviceName, serviceInfo.version, serviceInfo.publish_url)); + let swaggerUrl = ''; + if (undefined !== serviceInfo.swagger_url && '' !== serviceInfo.swagger_url) { + swaggerUrl = serviceInfo.publish_url + '/' + serviceInfo.swagger_url; + } else { + // default swagger url is: '/swagger.json' + swaggerUrl = serviceInfo.publish_url + '/swagger.json'; + } + swaggerObservableArray.push(this.http.get(swaggerUrl, options).timeout(5000).catch((error): Observable => { + console.log('Request swagger from:"' + swaggerUrl + '" faild!'); + return Observable.of(null); + })); + } + } + }); + Observable.forkJoin(swaggerObservableArray).subscribe( + responses => { + let deleteArray: number[] = []; + responses.forEach((response, index) => { + // mark http get failed request index or set the swagger into restConfigs + if (null === response) { + deleteArray.push(index); + } else { + try { + const swagger = response.json(); + restConfigs[index].swagger = new Swagger(swagger); + } catch (e) { + deleteArray.push(index); + console.warn('Do not support this sawgger file format:' + response.text()); + } + } + }); + console.log('Get all swagger file finish.'); + // delete failed request from all restConfigs array + deleteArray.reverse(); + deleteArray.forEach(deleteIndex => { + restConfigs.splice(deleteIndex, 1); + }); + this.broadcastService.broadcast(this.broadcastService.updateModelRestConfig, restConfigs); + console.log('Load all swagger finished.'); + } + ); + }); + }); + } +} + diff --git a/sdc-workflow-designer-ui/src/app/services/workflow.service.ts b/sdc-workflow-designer-ui/src/app/services/workflow.service.ts index aba8aa21..75382269 100644 --- a/sdc-workflow-designer-ui/src/app/services/workflow.service.ts +++ b/sdc-workflow-designer-ui/src/app/services/workflow.service.ts @@ -41,7 +41,7 @@ export class WorkflowService { } this.broadcastWorkflows(); }); - this.broadcastService.workflow.subscribe(workflow => this.planModel = workflow); + this.broadcastService.planModel.subscribe(workflow => this.planModel = workflow); } public save(): Observable { -- cgit 1.2.3-korg