aboutsummaryrefslogtreecommitdiffstats
path: root/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services
diff options
context:
space:
mode:
authorvempo <vitaliy.emporopulo@amdocs.com>2018-07-24 17:34:04 +0300
committervempo <vitaliy.emporopulo@amdocs.com>2018-07-25 11:39:10 +0300
commita52d50e788792a63e97a9176ab319d53db7a2853 (patch)
treeb1c2222cacf4b8192aea16d1e0315b1f005c5347 /deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services
parent3c2665debb400aef7f0ed9e235698d2ff9f859db (diff)
Replaced old implementation at root
Old project files and directories has been moved under 'deprecated-workflow-designer'. The old project is not built by the CI anymore, but can be still built manually. New modules/directories have been moved up and integrated with the CI system. Change-Id: I1528c792bcbcce9e50bfc294a1328a20e72c91cf Issue-ID: SDC-1559 Signed-off-by: vempo <vitaliy.emporopulo@amdocs.com>
Diffstat (limited to 'deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services')
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.spec.ts26
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.ts65
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts75
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/display-info.service.ts27
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.spec.ts26
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.ts53
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts581
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/model.service.ts625
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/node-type.service.ts68
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/notice.service.ts54
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/rest.service.ts151
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.spec.ts26
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.ts31
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/swagger-tree-converter.service.ts244
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.spec.ts26
-rw-r--r--deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.ts153
16 files changed, 2231 insertions, 0 deletions
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.spec.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.spec.ts
new file mode 100644
index 00000000..9bd500ef
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.spec.ts
@@ -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
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { AuthService } from './auth.service';
+
+describe('AuthService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [AuthService]
+ });
+ });
+
+ it('should be created', inject([AuthService], (service: AuthService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.ts
new file mode 100644
index 00000000..a8e60753
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/auth.service.ts
@@ -0,0 +1,65 @@
+/**
+ * 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 } from '@angular/http';
+import { BroadcastService } from './broadcast.service';
+
+@Injectable()
+export class AuthService {
+ private static AuthUrl = "/api/oauth2/v1/perms/user/operations";
+ private static AllOperations = ["operation.apds.create", "operation.apds.delete", "operation.apds.modify",
+ "operation.apds.view", "operation.apds.import", "operation.apds.export", "operation.apds.deploy",
+ "operation.apds.test"];
+ private static ModifyOperation = 'operation.apds.modify';
+
+ constructor(private http: Http, private broadcastService: BroadcastService) {
+ this.checkRights();
+ // keep alive
+ // setInterval(() => {
+ // console.log(`Keep session alive. Request per 3 minutes. ${new Date()}`);
+ // this.checkRights();
+ // }, 180000);
+ }
+ public checkRights() {
+ // let data = { operations: AuthService.AllOperations };
+ // this.http.post(AuthService.AuthUrl, data).subscribe(res => {
+ // let hasRightOP = res.json().operations;
+ // if (hasRightOP.length > 0) {
+ // this.broadcastService.broadcast(this.broadcastService.openRight, true);
+ // if (hasRightOP.indexOf(AuthService.ModifyOperation) > -1) {
+ // this.broadcastService.broadcast(this.broadcastService.saveRight, true);
+ // } else {
+ // this.broadcastService.broadcast(this.broadcastService.saveRight, false);
+ // }
+ // } else {
+ // this.broadcastService.broadcast(this.broadcastService.openRight, false);
+ // this.broadcastService.broadcast(this.broadcastService.saveRight, false);
+ // }
+ // }, error => {
+ // switch (error.status) {
+ // // Incase oauth service not exists or operation set not exists
+ // case 404:
+ // case 501:
+ // case 502:
+ // this.broadcastService.broadcast(this.broadcastService.openRight, true);
+ // this.broadcastService.broadcast(this.broadcastService.saveRight, true);
+ // break;
+ // default:
+ // this.broadcastService.broadcast(this.broadcastService.openRight, false);
+ // this.broadcastService.broadcast(this.broadcastService.saveRight, false);
+ // break;
+ // }
+ // });
+ this.broadcastService.broadcast(this.broadcastService.openRight, true);
+ this.broadcastService.broadcast(this.broadcastService.saveRight, true);
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts
new file mode 100644
index 00000000..410ae9b0
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/broadcast.service.ts
@@ -0,0 +1,75 @@
+/**
+ * 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 { Subject } from 'rxjs/Subject';
+
+import { PlanModel } from '../model/plan-model';
+import { RestConfig } from '../model/rest-config';
+import { Swagger } from '../model/swagger';
+import { SequenceFlow } from '../model/workflow/sequence-flow';
+import { WorkflowNode } from '../model/workflow/workflow-node';
+import { WorkflowElement } from '../model/workflow/workflow-element';
+
+/**
+ * BroadcastService
+ * All of the observable subject should be registered to this service.
+ * It provider a broadcast method to broadcast data. the broadcast method would catch error while broadcasting.
+ */
+@Injectable()
+export class BroadcastService {
+ public openRight = new Subject<boolean>();
+ public openRight$ = this.openRight.asObservable();
+
+ public saveRight = new Subject<boolean>();
+ public saveRight$ = this.saveRight.asObservable();
+
+ public initModel = new Subject<PlanModel>();
+ public initModel$ = this.initModel.asObservable();
+
+ public showProperty = new Subject<WorkflowElement>();
+ public showProperty$ = this.showProperty.asObservable();
+
+ public planModel = new Subject<PlanModel>();
+ public planModel$ = this.planModel.asObservable();
+
+ public updateModelToscaConfig = new Subject<any[]>();
+ public updateModelToscaConfig$ = this.updateModelToscaConfig.asObservable();
+
+ public updateModelRestConfig = new Subject<RestConfig[]>();
+ public updateModelRestConfig$ = this.updateModelRestConfig.asObservable();
+
+ public updateNodeTypeConfig = new Subject<any[]>();
+ public updateNodeTypeConfig$ = this.updateNodeTypeConfig.asObservable();
+
+ public saveEvent = new Subject<PlanModel>();
+ public saveEvent$ = this.saveEvent.asObservable();
+
+ public selectedElement = new Subject<WorkflowElement[]>();
+ public selectedElement$ = this.selectedElement.asObservable();
+
+ public swagger = new Subject<any>();
+ public swagger$ = this.swagger.asObservable();
+
+ /**
+ * broadcast datas
+ * this method will catch the exceptions for the broadcast
+ * @param subject will broadcast data
+ * @param data will be broadcasted
+ */
+ public broadcast(subject: Subject<any>, data: any) {
+ try {
+ subject.next(data);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/display-info.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/display-info.service.ts
new file mode 100644
index 00000000..f7c55e0e
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/display-info.service.ts
@@ -0,0 +1,27 @@
+/**
+ * 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 { HttpService } from "../util/http.service";
+import { Observable } from "rxjs";
+import { ModelService } from "./model.service";
+
+@Injectable()
+export class DisplayInfoService {
+ private displayInfoUrl = '/api/workflow-modeler/v1/ext-activities/displayInfo?scene=';
+
+ constructor(private modelService: ModelService, private httpService: HttpService) {
+ }
+
+ public getDisplayInfo(): Observable<any> {
+ return this.httpService.get(this.displayInfoUrl + this.modelService.getPlanModel().scene);
+ }
+} \ No newline at end of file
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.spec.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.spec.ts
new file mode 100644
index 00000000..0aeb3f52
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.spec.ts
@@ -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
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { InterfaceService } from './interface.service';
+
+describe('PersistenceService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [InterfaceService]
+ });
+ });
+
+ it('should be created', inject([InterfaceService], (service: InterfaceService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.ts
new file mode 100644
index 00000000..9dcafe96
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/interface.service.ts
@@ -0,0 +1,53 @@
+/**
+ * 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 { ActivatedRoute } from '@angular/router/';
+
+import { Observable } from 'rxjs/Observable';
+import { TranslateService } from '@ngx-translate/core';
+
+import { HttpService } from '../util/http.service';
+import { BroadcastService } from './broadcast.service';
+import { NoticeService } from './notice.service';
+import { PlanModel } from '../model/plan-model';
+
+@Injectable()
+export class InterfaceService {
+ private static ModelUrl = '/api/workflow-modeler/v1/models/';
+ constructor(private activatedRoute: ActivatedRoute, private http: HttpService,
+ private broadcast: BroadcastService, private notice: NoticeService, private translate: TranslateService) {
+ this.getModelData();
+ }
+
+ public getModelData() {
+ this.activatedRoute.queryParams.subscribe(queryParams => {
+ let modelId = queryParams.hasOwnProperty("id") ? queryParams.id : "";
+ let name = queryParams.hasOwnProperty("name") ? queryParams.name : "";
+ let uuid = queryParams.hasOwnProperty("uuid") ? queryParams.uuid :"";
+ let operationId = queryParams.hasOwnProperty("operationId") ? queryParams.operationId : "";
+
+ this.http.get(InterfaceService.ModelUrl + modelId
+ + "?name=" + name + "&uuid=" + uuid
+ + "&operationId=" + operationId).subscribe(data => {
+ this.broadcast.broadcast(this.broadcast.initModel, data);
+ }, error => {
+ this.translate.get('WORKFLOW.MSG.LOAD_FAIL').subscribe((res: string) => {
+ this.notice.error(res);
+ });
+ });
+ });
+ }
+
+ public saveModelData(planModel: PlanModel): Observable<PlanModel> {
+ return this.http.put(InterfaceService.ModelUrl + planModel.id, planModel);
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
new file mode 100644
index 00000000..0cf93efe
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
@@ -0,0 +1,581 @@
+/**
+ * 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 * as jsp from 'jsplumb';
+
+import {Subscription} from 'rxjs/Subscription';
+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
+ * provides all of the operations about jsplumb plugin.
+ */
+@Injectable()
+export class JsPlumbService {
+ public jsplumbInstanceMap = new Map<string, any>();
+ public subscriptionMap = new Map<string, Subscription>();
+
+ 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);
+ }
+ }
+ }
+ });
+ }
+
+ 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();
+
+ jsplumbInstance.importDefaults({
+ Anchor: "Continuous",
+ Endpoint: "Blank",
+ Container: "pallete",
+ ReattachConnections: true,
+ Connector: ['Flowchart', {
+ stub: [0, 0],
+ cornerRadius: 5,
+ alwaysRespectStubs: true
+ }],
+ PaintStyle: {
+ stroke: "#7D8695",
+ strokeWidth: 1,
+ radius: 1,
+ outlineStroke: "transform",
+ outlineWidth: 4
+ },
+ 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
+ jsplumbInstance.bind('connection', info => {
+ this.modelService.addConnection(info.connection.sourceId, info.connection.targetId);
+
+ this.subscribe4Connection(info.connection);
+
+ 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 => {
+ 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) {
+ const pre = connection.sourceId + connection.targetId;
+ let sequenceFlowSubscription = this.subscriptionMap.get(pre + 'sequenceFlowSubscription');
+ if (sequenceFlowSubscription && !sequenceFlowSubscription.closed) {
+ sequenceFlowSubscription.unsubscribe();
+ }
+
+ 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: '#7D8695',
+ strokeWidth: 1,
+ radius: 1,
+ outlineStroke: "transform",
+ outlineWidth: 4
+ });
+ }
+ });
+ this.subscriptionMap.set(pre + 'sequenceFlowSubscription', sequenceFlowSubscription);
+ }
+
+ private unsubscription4Connection(connectionSelection: any) {
+ connectionSelection.each(connection => {
+ const pre = connection.sourceId + connection.targetId;
+ this.subscriptionMap.get(pre + 'sequenceFlowSubscription').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 getParentNodeId(id: string): string {
+ const nodeElement = jsp.jsPlumb.getSelector('#' + id);
+ const parentNode = this.getParentNodeEl(nodeElement[0]);
+
+ return parentNode ? parentNode.id : null;
+ }
+
+ 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 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;
+ },
+ });
+ }
+
+ private isChildNode(childElement, parentElement) {
+ while (childElement !== parentElement) {
+ childElement = childElement.parentNode;
+ if (childElement.classList.contains('canvas')) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private drop(event) {
+ const dragEl = event.drag.el;
+ const dropEl = event.drop.el;
+ console.log(this.modelService.getNodes());
+
+
+ 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
+ const nameHeight = this.getNodeNameHeight(dragEl);
+ this.modelService.updatePosition(dragEl.id, left, top, dragEl.getBoundingClientRect().width, dragEl.getBoundingClientRect().height - nameHeight);
+
+ 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);
+ }
+
+ private getNodeNameHeight(element: any): number {
+ const children = element.children;
+ if (children && children.length) {
+ const nameElement = children[0];
+ if (nameElement && nameElement.className === 'name') {
+ return nameElement.getBoundingClientRect().height;
+ }
+ }
+ return 0;
+ }
+
+ private changeParent(id: string, originalParentNodeId: string, targetParentNodeId: string) {
+ if (originalParentNodeId !== targetParentNodeId) {
+ this.jsplumbInstanceMap.get(originalParentNodeId).removeAllEndpoints(id);
+ this.modelService.changeParent(id, originalParentNodeId, targetParentNodeId);
+ }
+ }
+
+ private getParentNodeEl(element) {
+ while (!(element.parentNode.classList.contains('node') || element.parentNode.classList.contains('canvas'))) {
+ element = element.parentNode;
+ }
+
+ 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 jsplumbInstance = this.jsplumbInstanceMap.get(this.modelService.rootNodeId);
+ const selector = jsplumbInstance.getSelector('.item');
+ jsplumbInstance.draggable(selector, {
+ scope: 'btn',
+ clone: true
+ });
+ }
+
+ public buttonDroppable() {
+ 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 = jsplumbInstance.getSelector(event.drag.el);
+ const type = el.attributes.nodeType.value;
+ let typeId = null;
+ if (el.attributes.nodeTypeId && el.attributes.nodeTypeId.value) {
+ typeId = el.attributes.nodeTypeId.value;
+ }
+ // 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 = el.attributes.name.value;
+ this.modelService.addNode(type, typeId, name, 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();
+ const nameHeight = this.getNodeNameHeight(parentElement);
+ this.modelService.updatePosition(parentElement.id,
+ parentElement.offsetLeft,
+ parentElement.offsetTop,
+ // title height
+ rect.width, rect.height - nameHeight);
+ }
+ 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 === 'wfm-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/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/model.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/model.service.ts
new file mode 100644
index 00000000..8cb7b86a
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/model.service.ts
@@ -0,0 +1,625 @@
+/**
+ * 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 { isNullOrUndefined } from 'util';
+
+import { PlanModel } from '../model/plan-model';
+import { PlanTreeviewItem } from '../model/plan-treeview-item';
+import { RestConfig } from '../model/rest-config';
+import {
+ Swagger,
+ SwaggerModel,
+ SwaggerModelSimple,
+ SwaggerPrimitiveObject,
+ SwaggerReferenceObject
+} from '../model/swagger';
+import { ErrorEvent } from '../model/workflow/error-event';
+import { IntermediateCatchEvent } from '../model/workflow/intermediate-catch-event';
+import { NodeType } from '../model/workflow/node-type.enum';
+import { Parameter } from '../model/workflow/parameter';
+import { Position } from '../model/workflow/position';
+import { RestTask } from '../model/workflow/rest-task';
+import { SequenceFlow } from '../model/workflow/sequence-flow';
+import { StartEvent } from '../model/workflow/start-event';
+import { SubProcess } from '../model/workflow/sub-process';
+import { ToscaNodeTask } from '../model/workflow/tosca-node-task';
+import { WorkflowNode } from '../model/workflow/workflow-node';
+import { NodeTemplate } from '../model/topology/node-template';
+import { ValueSource } from '../model/value-source.enum';
+import { BroadcastService } from './broadcast.service';
+import { RestService } from './rest.service';
+import { SwaggerTreeConverterService } from './swagger-tree-converter.service';
+import { TimerEventDefinition, TimerEventDefinitionType } from "../model/workflow/timer-event-definition";
+import { InterfaceService } from './interface.service';
+import { ServiceTask } from '../model/workflow/service-task';
+import { NodeTypeService } from './node-type.service';
+import { WorkflowUtil } from '../util/workflow-util';
+import { TranslateService } from '@ngx-translate/core';
+import { NoticeService } from './notice.service';
+
+/**
+ * ModelService
+ * provides all operations about plan model.
+ */
+@Injectable()
+export class ModelService {
+ public rootNodeId = 'root';
+
+ private planModel: PlanModel = new PlanModel();
+ private tempPlanModel: PlanModel = new PlanModel();
+
+ constructor(private interfaceService: InterfaceService, private broadcastService: BroadcastService,
+ private restService: RestService, private nodeTypeService: NodeTypeService,
+ private translate: TranslateService, private notice: NoticeService) {
+ this.broadcastService.initModel$.subscribe(planModel => {
+ planModel.data.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 = planModel;
+ this.tempPlanModel = WorkflowUtil.deepClone(this.planModel);
+ });
+ // Do not use restConfig property.
+ // this.broadcastService.updateModelRestConfig$.subscribe(restConfigs => {
+ // this.updateRestConfig(restConfigs);
+ // });
+ }
+
+ public getPlanModel(): PlanModel {
+ return this.planModel;
+ }
+
+ public getChildrenNodes(parentId: string): WorkflowNode[] {
+ if (!parentId || parentId === this.rootNodeId) {
+ return this.planModel.data.nodes;
+ } else {
+ const node = this.getNodeMap().get(parentId);
+ if (node.type === 'subProcess') {
+ return (<SubProcess>node).children;
+ } else {
+ return [];
+ }
+ }
+ }
+
+ public getNodes(): WorkflowNode[] {
+ return this.planModel.data.nodes;
+ }
+
+ public getSequenceFlow(sourceRef: string, targetRef: string): SequenceFlow {
+ const node = this.getNodeMap().get(sourceRef);
+ if (node) {
+ const sequenceFlow = node.connection.find(tmp => tmp.targetRef === targetRef);
+ return sequenceFlow;
+ } else {
+ return null;
+ }
+ }
+
+ public addNode(type: string, typeId: string, name: string, left: number, top: number) {
+ const id = this.generateNodeProperty('id', type);
+ const nodeName = this.generateNodeProperty('name', name);
+ const workflowPos = new Position(left, top);
+ let node;
+ if ('serviceTask' === type || 'scriptTask' === type || 'restTask' === type) {
+ node = this.createNodeByTypeId(id, nodeName, type, typeId, workflowPos);
+ } else {
+ node = this.createNodeByType(id, nodeName, type, workflowPos);
+ }
+ this.planModel.data.nodes.push(node);
+ }
+
+ private generateNodeProperty(key: string, type: string): string {
+ let nodeProperty = type;
+ const nodes = this.getNodes();
+ console.log(nodes);
+ const existNode = nodes.find(node => node[key] === nodeProperty);
+ if (existNode) {
+ let count = 2;
+ do {
+ nodeProperty = type + '_' + count;
+ count++;
+ } while (nodes.find(node => node[key] === nodeProperty))
+ }
+ return nodeProperty;
+ }
+
+ private generateNodeName(typeId: string): string {
+ const language = this.translate.currentLang.indexOf('en') > -1 ? 'en_US' : 'zh_CN';
+ const nodeType = this.nodeTypeService.getNodeDataTypeById(typeId);
+ let displayName;
+ if (nodeType.displayName && nodeType.displayName[language]) {
+ displayName = nodeType.displayName[language];
+ } else {
+ displayName = nodeType.type;
+ }
+ return this.generateNodeProperty('name', displayName);
+ }
+
+ public createNodeByTypeId(id: string, name: string, type: string, typeId: string, position: Position): WorkflowNode {
+ const nodeDataType = this.nodeTypeService.getNodeDataTypeById(typeId);
+ const initPosition = new Position(position.left, position.top, nodeDataType.icon.width, nodeDataType.icon.height);
+ // switch (type) {
+ // case NodeType[NodeType.serviceTask]:
+ // let serviceTask: ServiceTask = {
+ // id: id, type: type, name: name, parentId: this.rootNodeId,
+ // position: initPosition, connection: [], class: nodeDataType.activity.class,
+ // input: nodeDataType.activity.input, output: nodeDataType.activity.output
+ // };
+ // return serviceTask;
+ // case NodeType[NodeType.scriptTask]:
+ // let scriptTask: ScriptTask = {
+ // id: id, type: type, name: name, parentId: this.rootNodeId,
+ // position: initPosition, connection: [], scriptFormat: nodeDataType.activity.scriptFormat,
+ // script: nodeDataType.activity.script
+ // };
+ // return scriptTask;
+ // case NodeType[NodeType.restTask]:
+ // let restTaskNode: RestTask = {
+ // id: id, type: type, name: name, parentId: this.rootNodeId,
+ // position: initPosition, connection: [], produces: [], consumes: [], parameters: [], responses: []
+ // };
+ // return restTaskNode;
+ // default:
+ let node: WorkflowNode = {
+ id: id, type: type, typeId: nodeDataType.id, icon: nodeDataType.icon.name, name: name,
+ parentId: this.rootNodeId, position: initPosition, connection: []
+ };
+ return 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.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: <TimerEventDefinition>{ type: TimerEventDefinitionType[TimerEventDefinitionType.timeDuration] }
+ };
+ return intermediateCatchEvent;
+ 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 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.data.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 updateRestConfig(restConfigs: RestConfig[]): void {
+ this.planModel.data.configs = { restConfigs: restConfigs };
+ // console.log(this.planModel.configs);
+ }
+
+ public getNodeMap(): Map<string, WorkflowNode> {
+ const map = new Map<string, WorkflowNode>();
+ this.toNodeMap(this.planModel.data.nodes, map);
+ return map;
+ }
+
+ public getAncestors(id: string): WorkflowNode[] {
+ const nodeMap = this.getNodeMap();
+ const ancestors = [];
+
+ let ancestor = nodeMap.get(id);
+ do {
+ ancestor = this.getParentNode(ancestor.id, nodeMap);
+ if (ancestor && ancestor.id !== id) {
+ ancestors.push(ancestor);
+ }
+ } while (ancestor);
+
+ return ancestors;
+ }
+
+ private getParentNode(id: string, nodeMap: Map<string, WorkflowNode>): WorkflowNode {
+ let parentNode;
+ nodeMap.forEach((node, key) => {
+ if (NodeType[NodeType.subProcess] === node.type) {
+ const childNode = (<SubProcess>node).children.find(child => child.id === id);
+ if (childNode) {
+ parentNode = node;
+ }
+ }
+
+ });
+
+ return parentNode;
+ }
+
+ public isDescendantNode(node: WorkflowNode, descendantId: string): boolean {
+ if (NodeType[NodeType.subProcess] !== node.type) {
+ return false;
+ }
+ const tmp = (<SubProcess>node).children.find(child => {
+ return child.id === descendantId || (NodeType[NodeType.subProcess] === child.type && this.isDescendantNode(<SubProcess>child, descendantId));
+ });
+
+ return tmp !== undefined;
+ }
+
+ private toNodeMap(nodes: WorkflowNode[], map: Map<string, WorkflowNode>) {
+ nodes.forEach(node => {
+ if (node.type === 'subProcess') {
+ this.toNodeMap((<SubProcess>node).children, map);
+ }
+ map.set(node.id, node);
+ });
+ }
+
+ 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);
+ }
+ }
+ }
+
+ 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(parentId: string, nodeId: string): WorkflowNode {
+ const nodeMap = this.getNodeMap();
+
+ const nodes = this.getChildrenNodes(parentId);
+
+ // delete related connections
+ nodes.forEach(node => this.deleteConnection(node.id, nodeId));
+
+ // delete current node
+ const index = nodes.findIndex(node => node.id === nodeId);
+ if (index !== -1) {
+ const node = nodes.splice(index, 1)[0];
+ node.connection = [];
+ return node;
+ }
+
+ return null;
+ }
+
+ 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 getPlanParameters(nodeId: string): PlanTreeviewItem[] {
+ const preNodeList = new Array<WorkflowNode>();
+ this.getPreNodes(nodeId, this.getNodeMap(), preNodeList);
+
+ return this.loadNodeOutputs(preNodeList);
+ }
+
+ private loadNodeOutputs(nodes: WorkflowNode[]): PlanTreeviewItem[] {
+ const params = new Array<PlanTreeviewItem>();
+ nodes.forEach(node => {
+ switch (node.type) {
+ case NodeType[NodeType.startEvent]:
+ params.push(this.loadOutput4StartEvent(<StartEvent>node));
+ break;
+ case NodeType[NodeType.toscaNodeManagementTask]:
+ params.push(this.loadOutput4ToscaNodeTask(<ToscaNodeTask>node));
+ break;
+ case NodeType[NodeType.restTask]:
+ params.push(this.loadOutput4RestTask(<RestTask>node));
+ break;
+ default:
+ break;
+ }
+ });
+
+ return params;
+ }
+
+ private loadOutput4StartEvent(node: StartEvent): PlanTreeviewItem {
+ 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}]`, [], false);
+ item.children.push(this.createStatusCodeTreeViewItem(node.id));
+
+ if (node.responses && 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.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 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) {
+ // 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, nodeMap: Map<string, WorkflowNode>, preNodes: WorkflowNode[]) {
+ const preNode4CurrentNode = [];
+ nodeMap.forEach(node => {
+ if (this.isPreNode(node, nodeId)) {
+ const existNode = preNodes.find(tmpNode => tmpNode.id === node.id);
+ if (existNode) {
+ // current node already exists. this could avoid loop circle.
+ } else {
+ preNode4CurrentNode.push(node);
+ preNodes.push(node);
+ }
+ }
+ });
+
+ preNode4CurrentNode.forEach(node => this.getPreNodes(node.id, nodeMap, preNodes));
+ }
+
+ public isPreNode(preNode: WorkflowNode, id: string): boolean {
+ const targetNode = preNode.connection.find(connection => connection.targetRef === id);
+ return targetNode !== undefined;
+ }
+
+ public save(callback?: Function) {
+ console.log('****************** save data *********************');
+ console.log(JSON.stringify(this.planModel));
+ // Check data
+ if(!this.checkData()){
+ return;
+ }
+ this.interfaceService.saveModelData(this.planModel).subscribe(response => {
+ this.translate.get('WORKFLOW.MSG.SAVE_SUCCESS').subscribe((res: string) => {
+ this.notice.success(res);
+ // Update the cache.
+ this.tempPlanModel = WorkflowUtil.deepClone(this.planModel);
+ if (callback) {
+ callback();
+ }
+ });
+ }, error => {
+ this.translate.get('WORKFLOW.MSG.SAVE_FAIL').subscribe((res: string) => {
+ this.notice.error(res);
+ });
+ });
+ ;
+ }
+
+ private createId() {
+ const nodeMap = this.getNodeMap();
+
+ for (let i = 0; i < nodeMap.size; i++) {
+ const key = 'node' + i;
+ if (!nodeMap.get(key)) {
+ return key;
+ }
+ }
+
+ return 'node' + nodeMap.size;
+ }
+
+ public isModify(): boolean {
+ // Compare the cache.
+ return JSON.stringify(this.planModel) != JSON.stringify(this.tempPlanModel);
+ }
+
+ private checkData(): boolean {
+ if (this.planModel && this.planModel.data && this.planModel.data.nodes) {
+ let nodes = this.planModel.data.nodes;
+ for (let index = 0; index < nodes.length; index++) {
+ const node = nodes[index];
+ if (NodeType[NodeType.startEvent] === node.type) {
+ let startEvent = node as StartEvent;
+ if (startEvent.parameters) {
+ for (let i = 0; i < startEvent.parameters.length; i++) {
+ const parameter = startEvent.parameters[i];
+ if (!parameter.name) {
+ this.translate.get('WORKFLOW.MSG.PROCESS_VARIABLE_EMPTY').subscribe((res: string) => {
+ this.notice.error(res);
+ });
+ return false;
+ }
+ if(i + 1 < startEvent.parameters.length){
+ for (let j = i + 1; j < startEvent.parameters.length; j++) {
+ const param = startEvent.parameters[j];
+ if(parameter.name === param.name){
+ this.translate.get('WORKFLOW.MSG.PROCESS_VARIABLE_SAME').subscribe((res: string) => {
+ this.notice.error(res);
+ });
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/node-type.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/node-type.service.ts
new file mode 100644
index 00000000..4c66db18
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/node-type.service.ts
@@ -0,0 +1,68 @@
+/**
+ * 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 { HttpService } from "../util/http.service";
+import { BroadcastService } from "./broadcast.service";
+import { NodeDataType } from "../model/node-data-type/node-data-type";
+import { Parameter } from "../model/workflow/parameter";
+import { TranslateService } from "@ngx-translate/core";
+
+@Injectable()
+export class NodeTypeService {
+ private nodeDataTypes: NodeDataType[] = [];
+ private nodeDataTypeUrl = '/api/workflow-modeler/v1/ext-activities?sence=test';
+
+ constructor(private httpService: HttpService, private translateService: TranslateService,
+ private broadcastService: BroadcastService) {
+ this.initNodeDataTypes();
+ }
+
+ private initNodeDataTypes(): void {
+ this.httpService.get(this.nodeDataTypeUrl)
+ .toPromise()
+ .then(resp => {
+ if (resp && 0 < resp.length) {
+ this.nodeDataTypes = resp;
+ }
+ this.broadcastService.broadcast(this.broadcastService.updateNodeTypeConfig, null);
+ });
+ }
+
+ public getAllNodeDataTypes(): NodeDataType[] {
+ return this.nodeDataTypes;
+ }
+
+ public getNodeDataTypeById(id: string): NodeDataType | null {
+ return this.nodeDataTypes.find(nodeDataType => nodeDataType.id === id);
+ }
+
+ public GetI18nName(key: string, displayName: any): string {
+ //todo: add logic
+ let name = key;
+ if (displayName) {
+ let language = 'zh_CN';
+ if (this.translateService.currentLang.indexOf('en') > -1) {
+ language = 'en_US';
+ }
+ if (displayName.language && '' != displayName.language) {
+ name = displayName.language;
+ }
+ }
+ return name;
+ }
+
+ public static GetParameterByDataType(nodeDataType: any): Parameter {
+ //todo: add logic
+ let param = new Parameter('', '', '');
+ return param;
+ }
+} \ No newline at end of file
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/notice.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/notice.service.ts
new file mode 100644
index 00000000..ea081e96
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/notice.service.ts
@@ -0,0 +1,54 @@
+/**
+ * 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 { Subject } from 'rxjs/Subject';
+
+import { Notice } from '../model/notice';
+import { NoticeType } from '../model/notice-type.enum';
+
+/**
+ * NotifyService
+ * display notify infos.
+ */
+@Injectable()
+export class NoticeService {
+ public showNotice = new Subject<Notice>();
+ public showNotice$ = this.showNotice.asObservable();
+ constructor() { }
+
+ public success(content: string, timeout: number = 5000) {
+ this.addNotice(NoticeType.success, content, timeout);
+ }
+
+ public info(content: string, timeout: number = 10000) {
+ this.addNotice(NoticeType.info, content, timeout);
+ }
+
+ public warn(content: string, timeout: number = 30000) {
+ this.addNotice(NoticeType.warning, content, timeout);
+ }
+
+ public error(content: string, timeout: number = 0) {
+ this.addNotice(NoticeType.danger, content, timeout);
+ }
+
+ /**
+ * showNotify
+ * @param type
+ * @param content
+ */
+ private addNotice(type: NoticeType, content: string, timeout: number = 0): void {
+ const notice = new Notice(type, content, timeout);
+ this.showNotice.next(notice);
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/rest.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/rest.service.ts
new file mode 100644
index 00000000..e3bde51b
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/rest.service.ts
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * 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 { SwaggerResponseClass } from '../model/swagger';
+import { Swagger, SwaggerSchemaObject } from '../model/swagger';
+import { RestConfig } from '../model/rest-config';
+import { BroadcastService } from './broadcast.service';
+import { NoticeService } from './notice.service';
+import { SettingService } from './setting.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,
+ private noticeService: NoticeService, private settgingService: SettingService) {
+ this.settgingService.getSetting().subscribe(setting => {
+ if (true === setting.supportRestNode) {
+ this.initSwaggerInfo();
+ } else {
+ this.broadcastService.broadcast(this.broadcastService.updateModelRestConfig, null);
+ }
+ });
+ }
+
+ public getRestConfigs(): RestConfig[] {
+ return this.restConfigs;
+ }
+
+ public getRestConfig(id: string): RestConfig {
+ return this.restConfigs.find(tmp => tmp.id === id);
+ }
+
+ 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): SwaggerResponseClass[] {
+ const path = swagger.paths[interfaceUrl];
+ const method: SwaggerMethod = path[operation];
+ let responses: SwaggerResponseClass[] = [];
+
+ for (const key of Object.keys(method.responses)) {
+ if (key.startsWith('20') && method.responses[key].schema && method.responses[key].schema.$ref) {
+ let response: SwaggerResponseClass = 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 initSwaggerInfo(): void {
+ this.http.get(this.runtimeURL).subscribe(runtimeResponse => {
+ const tenant = runtimeResponse.json().tenant;
+ console.log('Current namespace is:' + tenant);
+ this.initSwaggerInfoByTenant(tenant);
+ }, error => {
+ console.warn('No tenant interface!');
+ this.initSwaggerInfoByTenant('');
+ });
+ }
+
+ private initSwaggerInfoByTenant(tenant: string): void {
+ 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<any>[] = [];
+ 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;
+ this.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';
+ }
+ const options: any = {
+ headers: {
+ Accept: 'application/json',
+ }
+ };
+ swaggerObservableArray.push(this.http.get(swaggerUrl, options).timeout(5000).catch((error): Observable<any> => {
+ 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();
+ this.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 => {
+ this.restConfigs.splice(deleteIndex, 1);
+ });
+ this.broadcastService.broadcast(this.broadcastService.updateModelRestConfig, this.restConfigs);
+ console.log('Load all swagger finished.');
+ }
+ );
+ });
+
+ }
+}
+
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.spec.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.spec.ts
new file mode 100644
index 00000000..a85d2c27
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.spec.ts
@@ -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
+ *******************************************************************************/
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SettingService } from './setting.service';
+
+describe('SettingService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [SettingService]
+ });
+ });
+
+ it('should be created', inject([SettingService], (service: SettingService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.ts
new file mode 100644
index 00000000..266c5533
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/setting.service.ts
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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 { Observable } from "rxjs/Rx";
+
+import { HttpService } from '../util/http.service';
+
+@Injectable()
+export class SettingService {
+
+ constructor(private http: HttpService) { }
+
+ public getSetting(): Observable<any> {
+ const options: any = {
+ headers: {
+ Accept: 'application/json',
+ }
+ };
+ return this.http.get('assets/global-setting.json', options);
+ }
+
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/swagger-tree-converter.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/swagger-tree-converter.service.ts
new file mode 100644
index 00000000..8128b44c
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/swagger-tree-converter.service.ts
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * 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 { TreeNode } from 'primeng/primeng';
+
+import { ValueSource } from '../model/value-source.enum';
+import { WorkflowUtil } from '../util/workflow-util';
+import { RestService } from './rest.service';
+import { Swagger } from "../model/swagger";
+import { ValueObject } from '../model/value-object';
+import { ValueType } from '../model/value-type.enum';
+
+@Injectable()
+export class SwaggerTreeConverterService {
+
+ private swagger: Swagger;
+
+ constructor(private restService: RestService) { }
+
+ public schema2TreeNode(swagger: Swagger, key: string | number, schema: any, value?: any): any {
+ this.swagger = swagger;
+ if (schema.$ref) {
+ const treeNode = this.getTreeNodeBySwaggerDefinition(key, schema, value);
+ return treeNode;
+ } else {
+ value = this.getInitValue4Param(schema, value);
+ return this.parameter2TreeNode(key, schema, value);
+ }
+ }
+
+ private getTreeNodeBySwaggerDefinition(key: string | number, schema: any, value: any): TreeNode {
+ const swaggerDefinition = this.restService.getDefinition(this.swagger, schema.$ref);
+
+ const definitionCopy = WorkflowUtil.deepClone(swaggerDefinition);
+
+ value = this.getInitValue4Param(definitionCopy, value);
+
+ return this.schema2TreeNode(this.swagger, key, definitionCopy, value);
+ }
+
+ private getInitValue4Param(definition: any, value: any) {
+ if (definition.$ref) {
+ definition = this.restService.getDefinition(this.swagger, definition.$ref);
+ }
+ let valueObject: ValueObject = { valueSource: ValueSource[ValueSource.string] };
+ if (undefined == value) {
+ valueObject.value = definition.default;
+ if (ValueType[ValueType.array] === definition.type || ValueType[ValueType.object] === definition.type) {
+ valueObject.valueSource = ValueSource[ValueSource.Definition];
+ } else {
+ valueObject.valueSource = definition.type;
+ }
+ } else {
+ valueObject.valueSource = value.valueSource;
+ valueObject.value = undefined === value.value ? definition.default : value.value;
+ }
+ if (definition.type === 'object') {
+ // if (undefined == value) {
+ // valueObject.value = definition.default;
+ // if (ValueType[ValueType.array] === definition.type || ValueType[ValueType.object] === definition.type) {
+ // valueObject.valueSource = ValueSource[ValueSource.Definition];
+ // } else {
+ // valueObject.valueSource = definition.type;
+ // }
+ // } else {
+ // valueObject.valueSource = value.valueSource;
+ // valueObject.value = undefined === value.value ? definition.default : value.value;
+ // }
+ return this.getInitValue4Object(valueObject);
+ } else if (definition.type === 'array') {
+ return this.getInitValue4Array(valueObject);
+ } else { // primary type
+ // valueObject.value = undefined === value ? definition.default : value;
+ // valueObject.valueSource = definition.type;
+ return this.getInitValue4Primary(valueObject);
+ }
+ }
+
+ private getInitValue4Object(value: any) {
+ const newValue = {
+ value: {},
+ valueSource: ValueSource[ValueSource.Definition]
+ };
+
+ if (!value || '' === value) {
+ return newValue;
+ } else {
+ if (value.valueSource !== ValueSource[ValueSource.Definition]) {
+ return value;
+ } else {
+ if (typeof value.value !== 'object') {
+ value.value = {};
+ }
+ return value;
+ }
+ }
+ }
+
+ private getInitValue4Array(value: any) {
+ const newValue = {
+ value: [],
+ valueSource: ValueSource[ValueSource.Definition]
+ };
+
+ if (!value || '' === value) {
+ return newValue;
+ } else {
+ if (value.valueSource !== ValueSource[ValueSource.Definition]) {
+ return value;
+ } else {
+ if (!(value.value instanceof Array)) {
+ value.value = [];
+ }
+ return value;
+ }
+ }
+ }
+
+ private getInitValue4Primary(value: any) {
+ const newValue = {
+ value: '',
+ valueSource: ValueSource[ValueSource.string]
+ };
+
+ if (!value) {
+ return newValue;
+ } else {
+ if (typeof value.value === 'object') {
+ value.value = '';
+ }
+ return value;
+ }
+ }
+
+ private parameter2TreeNode(name: string | number, definition: any, value: any): any {
+ const nodeType = this.getTreeNodeType(definition);
+
+ const node = {
+ label: name,
+ type: nodeType,
+ required: definition.required,
+ children: [],
+ definition: definition,
+ value: value,
+ };
+
+ if (value.valueSource === ValueSource[ValueSource.Definition]) {
+ if (definition.type === 'object') {
+ node.children = this.getPropertyFromObject(definition, value.value);
+ } else if (definition.type === 'array') {
+ node.children = this.setChildrenForArray(definition, value.value);
+ }
+ }
+
+ return node;
+ }
+
+ private getTreeNodeType(param: any): string {
+ const type = param.type;
+ if (type === 'array') {
+ return 'array';
+ } else if (type === 'object') {
+ if (param.additionalProperties) {
+ return 'map';
+ } else {
+ return 'object';
+ }
+ } else {
+ return 'default';
+ }
+ }
+
+ private setChildrenForArray(definition: any, value: any[]): any[] {
+ const children = [];
+ value.forEach((itemValue, index) => {
+ const itemCopy = WorkflowUtil.deepClone(definition.items);
+ children.push(this.schema2TreeNode(this.swagger, index, itemCopy, itemValue));
+ });
+
+ return children;
+ }
+
+ private getPropertyFromObject(definition: any, value: any): TreeNode[] {
+ if (definition.properties) {
+ return this.getPropertyFromSimpleObject(definition.properties, value, definition.required);
+ } else if (definition.additionalProperties) {
+ return this.getPropertyFromMapOrDictionary(definition.additionalProperties, value);
+ } else {
+ console.log('getPropertyFromObject() return [], param is:' + JSON.stringify(definition));
+ return [];
+ }
+
+ }
+
+ private getPropertyFromSimpleObject(properties: any, objectValue: any, required: string[]): TreeNode[] {
+ const treeNodes: TreeNode[] = [];
+ for (const key in properties) {
+ let property = properties[key];
+ // init required property
+ property.required = false;
+ if (Array.isArray(required)) {
+ for (let index = 0; index < required.length; index++) {
+ if (required[index] === key) {
+ property.required = true;
+ break;
+ }
+ }
+ }
+
+ objectValue[key] = this.getInitValue4Param(property, objectValue[key]);
+
+ const treeNode = this.schema2TreeNode(this.swagger, key, property, objectValue[key]);
+ treeNodes.push(treeNode);
+ }
+ return treeNodes;
+ }
+
+ private getPropertyFromMapOrDictionary(additionalProperties: any, mapOrDictionary: any): TreeNode[] {
+ const treeNodes: TreeNode[] = [];
+ for (const key in mapOrDictionary) {
+ const propertyCopy = WorkflowUtil.deepClone(additionalProperties);
+ propertyCopy.value = mapOrDictionary[key];
+
+ const treeNode = this.schema2TreeNode(this.swagger, key, propertyCopy, propertyCopy.value);
+ treeNode.keyEditable = true;
+ treeNodes.push(treeNode);
+
+ if (mapOrDictionary[key] !== propertyCopy.value) {
+ mapOrDictionary[key] = propertyCopy.value;
+ }
+ }
+ return treeNodes;
+ }
+}
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.spec.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.spec.ts
new file mode 100644
index 00000000..a54fba63
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.spec.ts
@@ -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
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ToscaService } from './tosca.service';
+
+describe('ToscaService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [ToscaService]
+ });
+ });
+
+ it('should be created', inject([ToscaService], (service: ToscaService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.ts b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.ts
new file mode 100644
index 00000000..dd62a717
--- /dev/null
+++ b/deprecated-workflow-designer/sdc-workflow-designer-ui/src/app/services/tosca.service.ts
@@ -0,0 +1,153 @@
+/**
+ * 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 { Observable } from "rxjs/Rx";
+
+import { NodeTemplate } from '../model/topology/node-template';
+import { SettingService } from './setting.service';
+import { HttpService } from '../util/http.service';
+import { BroadcastService } from './broadcast.service';
+
+@Injectable()
+export class ToscaService {
+ private nodeTemplate: NodeTemplate[] = [];
+ private topologyProperties: {
+ name: string;
+ value: string;
+ }[] = [];
+ private namespace;
+ private serviceTemplateId;
+ private repositoryURL;
+ constructor(private settingService: SettingService, private httpService: HttpService,
+ private broadcastService: BroadcastService) {
+ this.settingService.getSetting().subscribe(setting => {
+ if (true === setting.supportToscaNode) {
+ // todo: need to load tosca interface and tosca properties
+ this.initTOSCAInfo();
+ } else {
+ this.broadcastService.broadcast(this.broadcastService.updateModelToscaConfig, null);
+ }
+ });
+ }
+
+ public getNodeTemplate(): NodeTemplate[] {
+ return this.nodeTemplate;
+ }
+
+ public getTopologyProperties() {
+ return this.topologyProperties;
+ }
+
+ public initTOSCAInfo() {
+ this.getNodeTemplates().subscribe(nodes => {
+ if (0 === nodes.length) {
+ return;
+ }
+
+ const subscribes = nodes.map(node => this.loadTopologyProperties(node));
+ Observable.forkJoin(subscribes).map(nodesProperties => {
+ const allProperties: { name: string, value: string }[] = [];
+ nodesProperties.forEach((properties, index) => {
+ properties.forEach(property => {
+ // allProperties.push(nodes[index].name + '.' + property);
+ const propertyOption = {
+ name: `${nodes[index].name}.${property}`,
+ value: `[${nodes[index].name}].[${property}]`
+ };
+ allProperties.push(propertyOption);
+ });
+ });
+ return allProperties;
+ }).subscribe(allProperties => {
+ this.topologyProperties = allProperties;
+ this.broadcastService.broadcast(this.broadcastService.updateModelToscaConfig, this.topologyProperties);
+ });
+ });
+ }
+
+ public getNodeTemplates(): Observable<NodeTemplate[]> {
+ const url = 'servicetemplates/' + this.encode(this.namespace)
+ + '/' + this.encode(this.serviceTemplateId) + '/topologytemplate/';
+
+ return this.httpService.get(this.getFullUrl(url)).map(response => {
+ const nodeTemplates = [];
+ for (const key in response.nodeTemplates) {
+ if (response.nodeTemplates.hasOwnProperty(key)) {
+ const nodeTemplate = response.nodeTemplates[key];
+ nodeTemplates.push({
+ id: nodeTemplate.id,
+ type: nodeTemplate.type.replace(/^\{(.+)\}(.+)/, '$2'),
+ name: nodeTemplate.name,
+ namespace: nodeTemplate.type.replace(/^\{(.+)\}(.+)/, '$1'),
+ });
+ }
+ }
+ return nodeTemplates;
+ });
+ }
+
+ public loadTopologyProperties(nodeTemplate: NodeTemplate): Observable<string[]> {
+ const url = 'nodetypes/' + this.encode(nodeTemplate.namespace)
+ + '/' + this.encode(nodeTemplate.type) + '/propertiesdefinition/winery/list/';
+
+ return this.httpService.get(this.getFullUrl(url)).map(properties =>
+ properties.map(property => property.key));
+ }
+
+ public loadNodeTemplateInterfaces(nodeTemplate: NodeTemplate): Observable<string[]> {
+ const url = 'nodetypes/' + this.encode(nodeTemplate.namespace)
+ + '/' + this.encode(nodeTemplate.type) + '/interfaces/';
+
+ return this.httpService.get(this.getFullUrl(url));
+ }
+ public loadNodeTemplateOperations(nodeTemplate: NodeTemplate,
+ interfaceName: string): Observable<string[]> {
+ const url = 'nodetypes/' + this.encode(nodeTemplate.namespace)
+ + '/' + this.encode(nodeTemplate.type) + '/interfaces/' + this.encode(interfaceName) + '/operations/';
+
+ return this.httpService.get(this.getFullUrl(url));
+ }
+
+ public loadNodeTemplateOperationParameter(nodeTemplate: NodeTemplate,
+ interfaceName: string,
+ operation: string): Observable<any> {
+ const relativePath = 'nodetypes/' + this.encode(nodeTemplate.namespace) + '/' + this.encode(nodeTemplate.type)
+ + '/interfaces/' + this.encode(interfaceName) + '/operations/' + this.encode(operation) + '/';
+
+ // input parameters
+ const inputObservable = this.httpService
+ .get(this.getFullUrl(relativePath + 'inputparameters'));
+
+ // output parameters
+ const outputObservable = this.httpService
+ .get(this.getFullUrl(relativePath + 'outputparameters'));
+
+ return Observable.forkJoin([inputObservable, outputObservable]).map(params => {
+ return {
+ input: params[0],
+ output: params[1],
+ };
+ });
+ }
+
+ private decode(param: string): string {
+ return decodeURIComponent(decodeURIComponent(param));
+ }
+
+ private encode(param: string): string {
+ return encodeURIComponent(encodeURIComponent(param));
+ }
+
+ private getFullUrl(relativePath: string) {
+ return this.repositoryURL + relativePath;
+ }
+}