support quote output of rest task
rest task's parameters can quote output parameter of previous rest tasks.
Issue-ID: SDC-121
Change-Id: I94f2058f7b8b2ad600ffb99c8838b37da5bb5b9d
Signed-off-by: Lvbo163 <lv.bo163@zte.com.cn>
diff --git a/sdc-workflow-designer-ui/src/app/app.module.ts b/sdc-workflow-designer-ui/src/app/app.module.ts
index 0bf4b14..047f468 100644
--- a/sdc-workflow-designer-ui/src/app/app.module.ts
+++ b/sdc-workflow-designer-ui/src/app/app.module.ts
@@ -42,6 +42,7 @@
import { ParameterTreeComponent } from "./components/parameter-tree/parameter-tree.component";
import { EditablePropertyComponent } from "./components/editable-property/editable-property.component";
import { SwaggerTreeConverterService } from "./services/swagger-tree-converter.service";
+import { WorkflowProcessService } from "./services/workflow-process.service";
@NgModule({
declarations: [
@@ -85,6 +86,7 @@
JsPlumbService,
SwaggerTreeConverterService,
WorkflowConfigService,
+ WorkflowProcessService,
WorkflowService
],
bootstrap: [AppComponent]
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 d0e04e3..0de35b9 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
@@ -186,7 +186,6 @@
}
private formatParam(params: any[]): void {
- console.log(params);
params.forEach(param => this.initParam(param));
}
diff --git a/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts b/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
index 2cd5a0f..3539c8f 100644
--- a/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
+++ b/sdc-workflow-designer-ui/src/app/components/parameter/parameter.component.ts
@@ -45,7 +45,6 @@
constructor(private dataAccessService: DataAccessService) { }
public ngOnInit(): void {
- console.log(this.planItems);
if (1 === this.valueSource.length) {
this.showValueSource = false;
}
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 f3f784a..2aa552e 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
@@ -15,8 +15,8 @@
import { WorkflowNode } from '../../model/workflow/workflow-node';
import { BroadcastService } from '../../services/broadcast.service';
import { JsPlumbService } from '../../services/jsplumb.service';
-import { WorkflowService } from '../../services/workflow.service';
import { PlanTreeviewItem } from "../../model/plan-treeview-item";
+import { WorkflowProcessService } from "../../services/workflow-process.service";
/**
* property component presents information of a workflow node.
@@ -36,7 +36,7 @@
constructor(private broadcastService: BroadcastService,
private jsPlumnService: JsPlumbService,
- private workflowService: WorkflowService) {
+ private processService: WorkflowProcessService) {
}
@@ -44,7 +44,7 @@
this.broadcastService.showProperty$.subscribe(show => this.show = show);
this.broadcastService.nodeProperty$.subscribe(node => {
this.node = node;
- this.planItems = this.workflowService.getPlanParameters(this.node.id);
+ this.planItems = this.processService.getPlanParameters(this.node.id);
});
}
@@ -57,6 +57,6 @@
this.show = false;
this.jsPlumnService.remove(this.node.id);
- this.workflowService.deleteNode(this.node.id);
+ this.processService.deleteNode(this.node.id);
}
}
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 ffd00c6..543b09f 100644
--- a/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
+++ b/sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
@@ -12,7 +12,7 @@
import { Injectable } from '@angular/core';
import * as jsp from 'jsplumb';
-import { WorkflowService } from "./workflow.service";
+import { WorkflowProcessService } from "./workflow-process.service";
/**
* JsPlumbService
@@ -22,7 +22,7 @@
export class JsPlumbService {
public jsplumbInstance;
- constructor(private workflowService: WorkflowService) {
+ constructor(private processService: WorkflowProcessService) {
this.initJsPlumbInstance();
}
@@ -58,11 +58,11 @@
// add connection to model data while a new connection is build
this.jsplumbInstance.bind('connection', info => {
- this.workflowService.addSequenceFlow(info.connection.sourceId, info.connection.targetId);
+ this.processService.addSequenceFlow(info.connection.sourceId, info.connection.targetId);
info.connection.bind('click', connection => {
this.jsplumbInstance.select({ connections: [connection] }).delete();
- this.workflowService.deleteSequenceFlow(connection.sourceId, connection.targetId);
+ this.processService.deleteSequenceFlow(connection.sourceId, connection.targetId);
});
});
@@ -117,7 +117,7 @@
const left = event.e.clientX - 220 - (event.e.offsetX / 2);
const top = event.e.clientY - 70 - (event.e.offsetY / 2);
- this.workflowService.addNode(type, type, top, left);
+ this.processService.addNode(type, type, top, left);
},
});
}
diff --git a/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts b/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts
new file mode 100644
index 0000000..4c701ec
--- /dev/null
+++ b/sdc-workflow-designer-ui/src/app/services/workflow-process.service.ts
@@ -0,0 +1,206 @@
+/**
+ * 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 { WorkflowNode } from "../model/workflow/workflow-node";
+import { Workflow } from "../model/workflow/workflow";
+import { Position } from "../model/workflow/position";
+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 { PlanTreeviewItem } from "../model/plan-treeview-item";
+import { WorkflowConfigService } from "./workflow-config.service";
+import { Swagger, SwaggerModelSimple, SwaggerReferenceObject } from "../model/swagger";
+import { WorkflowService } from "./workflow.service";
+
+/**
+ * WorkflowService
+ * provides all of the operations about workflow operations.
+ */
+@Injectable()
+export class WorkflowProcessService {
+
+ constructor(private workflowService: WorkflowService, private configService: WorkflowConfigService) {
+
+ }
+
+ public getProcess(): WorkflowNode[] {
+ return this.workflowService.workflow.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;
+ default:
+ node = new WorkflowNode(this.createId(), name, type, new Position(top, left), []);
+ break;
+ }
+
+ this.getProcess().push(node);
+ return node;
+ }
+
+ public deleteNode(nodeId: string): WorkflowNode {
+ // delete related connections
+ this.getProcess().forEach(node => this.deleteSequenceFlow(node.id, nodeId));
+
+ // delete current node
+ const index = this.getProcess().findIndex(node => node.id === nodeId);
+ if (index !== -1) {
+ const node = this.getProcess().splice(index, 1)[0];
+ node.sequenceFlows = [];
+ return node;
+ }
+
+ return undefined;
+ }
+
+ 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 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 getPlanParameters(nodeId: string): PlanTreeviewItem[] {
+ const preNodeList = new Array<WorkflowNode>();
+ this.getPreNodes(nodeId, 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.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}]`, []);
+ node.parameters.map(param =>
+ startItem.children.push(new PlanTreeviewItem(param.name, `[${param.name}]`, [])));
+ return startItem;
+ }
+
+ private loadOutput4RestTask(node: RestTask): PlanTreeviewItem {
+ const item = new PlanTreeviewItem(node.name, `[${node.id}]`, []);
+ 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);
+ 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, <SwaggerModelSimple>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) {
+ 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);
+
+ if (property instanceof SwaggerReferenceObject) {
+ const propertyDefinition = this.configService.getDefinition(swagger, property.$ref);
+ this.loadParamsBySwaggerDefinition(propertyItem, swagger,
+ <SwaggerModelSimple>propertyDefinition);
+ }
+
+ return propertyItem;
+ });
+ }
+
+ public getPreNodes(nodeId: string, preNodes: WorkflowNode[]) {
+ const preNode4CurrentNode = [];
+ this.getProcess().forEach(node => {
+ if (this.isPreNode(node, nodeId)) {
+ const existNode = preNodes.find(tmpNode => tmpNode.id === node.id);
+ if (existNode) {
+ // current node already exists in preNodes. this could avoid loop circle.
+ } else {
+ preNode4CurrentNode.push(node);
+ preNodes.push(node);
+ }
+ }
+ });
+
+ preNode4CurrentNode.forEach(node => this.getPreNodes(node.id, preNodes));
+ }
+
+ public isPreNode(preNode: WorkflowNode, id: string): boolean {
+ const targetNode = preNode.sequenceFlows.find(connection => connection.targetRef === id);
+ return targetNode !== undefined;
+ }
+
+ public getNodeById(sourceId: string): WorkflowNode {
+ return this.getProcess().find(node => node.id === sourceId);
+ }
+
+ private createId() {
+ const idSet = new Set();
+ this.getProcess().forEach(node => idSet.add(node.id));
+
+ for (let i = 0; i < idSet.size; i++) {
+ if (!idSet.has('node' + i)) {
+ return 'node' + i;
+ }
+ }
+
+ return 'node' + idSet.size;
+ }
+}
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 4bcd43b..7d75192 100644
--- a/sdc-workflow-designer-ui/src/app/services/workflow.service.ts
+++ b/sdc-workflow-designer-ui/src/app/services/workflow.service.ts
@@ -11,16 +11,9 @@
*/
import { Injectable } from '@angular/core';
-import { WorkflowNode } from "../model/workflow/workflow-node";
import { DataAccessService } from "./data-access/data-access.service";
import { Observable } from "rxjs/Observable";
import { Workflow } from "../model/workflow/workflow";
-import { Position } from "../model/workflow/position";
-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 { PlanTreeviewItem } from "../model/plan-treeview-item";
/**
* WorkflowService
@@ -39,128 +32,4 @@
console.log(this.workflow);
return this.dataAccessService.catalogService.saveWorkflow(this.workflow);
}
-
- 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;
- default:
- node = new WorkflowNode(this.createId(), name, type, new Position(top, left), []);
- break;
- }
-
- this.workflow.nodes.push(node);
- return node;
- }
-
- public deleteNode(nodeId: string): WorkflowNode {
- // delete related connections
- this.workflow.nodes.forEach(node => this.deleteSequenceFlow(node.id, nodeId));
-
- // delete current node
- const index = this.workflow.nodes.findIndex(node => node.id === nodeId);
- if (index !== -1) {
- const node = this.workflow.nodes.splice(index, 1)[0];
- node.sequenceFlows = [];
- return node;
- }
-
- return undefined;
- }
-
- 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 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 getPlanParameters(nodeId: string): PlanTreeviewItem[] {
- const preNodeList = new Array<WorkflowNode>();
- this.getPreNodes(nodeId, 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.restTask]:
- // TODO for rest task
- break;
- default:
- break;
- }
- });
-
- return params;
- }
-
- private loadOutput4StartEvent(node: StartEvent): PlanTreeviewItem {
- const startItem = new PlanTreeviewItem(node.name, `[${node.id}]`, []);
- node.parameters.map(param =>
- startItem.children.push(new PlanTreeviewItem(param.name, `[${param.name}]`, [])));
- return startItem;
- }
-
- public getPreNodes(nodeId: string, preNodes: WorkflowNode[]) {
- const preNode4CurrentNode = [];
- this.workflow.nodes.forEach(node => {
- if (this.isPreNode(node, nodeId)) {
- const existNode = preNodes.find(tmpNode => tmpNode.id === node.id);
- if (existNode) {
- // current node already exists in preNodes. this could avoid loop circle.
- } else {
- preNode4CurrentNode.push(node);
- preNodes.push(node);
- }
- }
- });
-
- preNode4CurrentNode.forEach(node => this.getPreNodes(node.id, preNodes));
- }
-
- public isPreNode(preNode: WorkflowNode, id: string): boolean {
- const targetNode = preNode.sequenceFlows.find(connection => connection.targetRef === id);
- return targetNode !== undefined;
- }
-
- public getNodeById(sourceId: string): WorkflowNode {
- return this.workflow.nodes.find(node => node.id === sourceId);
- }
-
- private createId() {
- const idSet = new Set();
- this.workflow.nodes.forEach(node => idSet.add(node.id));
-
- for (let i = 0; i < idSet.size; i++) {
- if (!idSet.has('node' + i)) {
- return 'node' + i;
- }
- }
-
- return 'node' + idSet.size;
- }
}