add in memory web api to mock backend rest api to save and load workflow definition.
Issue-ID: SDC-257
Change-Id: Ibedcbe5db5706773de9f6d1093babbcbd7b73297
Signed-off-by: Lvbo163 <lv.bo163@zte.com.cn>
{
"name": "workflow-designer",
- "version": "0.0.0",
+ "version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
+ "angular-in-memory-web-api": {
+ "version": "0.3.2",
+ "resolved": "http://10.75.8.148/repository/npm-pub/angular-in-memory-web-api/-/angular-in-memory-web-api-0.3.2.tgz",
+ "integrity": "sha1-iDbZ4lNNN7co88taHK9v4ef7vs0="
+ },
"ansi-escapes": {
"version": "2.0.0",
"resolved": "http://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-2.0.0.tgz",
"@angular/platform-browser": "^4.2.4",
"@angular/platform-browser-dynamic": "^4.2.4",
"@angular/router": "^4.2.4",
+ "angular-in-memory-web-api": "^0.3.2",
"core-js": "^2.4.1",
"jsplumb": "2.5.0",
"rxjs": "^5.4.2",
<b4t-toolbar></b4t-toolbar>
<div id="container" class="container">
- <b4t-node *ngFor="let node of getNodes(); let last = last;" [node]="node" [last]="last"></b4t-node>
+ <b4t-node *ngFor="let node of getWorkflow()?.nodes; let last = last;" [node]="node" [last]="last"></b4t-node>
</div>
* ZTE - initial API and implementation and/or initial documentation
*/
-import { Component, AfterViewInit } from '@angular/core';
+import { Component, AfterViewInit, OnInit } from '@angular/core';
import { JsPlumbService } from "./services/jsplumb.service";
import { WorkflowService } from "./services/workflow.service";
import { WorkflowNode } from "./model/workflow-node";
+import { Workflow } from "./model/workflow";
+import { DataAccessService } from "./services/data-access/data-access.service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
-export class AppComponent implements AfterViewInit {
- constructor(private jsplumbService: JsPlumbService, private workflowService: WorkflowService) {}
+export class AppComponent implements AfterViewInit, OnInit {
+ constructor(private jsplumbService: JsPlumbService,
+ private dataAccessService: DataAccessService,
+ private workflowService: WorkflowService) {}
- public getNodes(): WorkflowNode[] {
- return this.workflowService.getNodes();
+ ngOnInit(): void {
+ this.dataAccessService.catalogService.loadWorkflow('workflow1').subscribe(workflow => {
+ this.workflowService.workflow = workflow;
+ });
+ }
+
+ public getWorkflow(): Workflow {
+ return this.workflowService.workflow;
}
ngAfterViewInit(): void {
import { NodeComponent } from "./components/node/node.component";
import { ToolbarComponent } from "./components/toolbar/toolbar.component";
import { WorkflowService } from "./services/workflow.service";
+import { DataAccessService } from "./services/data-access/data-access.service";
+import { HttpService } from "./util/http.service";
+import { SharedModule } from "./shared/shared.module";
+import { InMemoryWebApiModule } from "angular-in-memory-web-api";
+import { InMemoryDataService } from "./services/data-access/in-memory-data.service";
+import { HttpModule } from "@angular/http";
@NgModule({
declarations: [
ToolbarComponent,
],
imports: [
- BrowserModule
+ BrowserModule,
+ HttpModule,
+ InMemoryWebApiModule.forRoot(InMemoryDataService),
+ SharedModule,
+ ],
+ providers: [
+ DataAccessService,
+ HttpService,
+ JsPlumbService,
+ WorkflowService
],
- providers: [JsPlumbService, WorkflowService],
bootstrap: [AppComponent]
})
export class AppModule { }
<button type="button" class="btn btn-secondary item ui-draggable" [attr.nodeType]="'endEvent'">\r
<span>endEvent</span>\r
</button>\r
+\r
+ <button type="button" class="btn btn-success" (click)="save()">Save</button>\r
</div>\r
</div>\r
import { AfterViewInit, Component } from '@angular/core';\r
\r
import { JsPlumbService } from '../../services/jsplumb.service';\r
+import { WorkflowService } from "../../services/workflow.service";\r
\r
/**\r
* toolbar component contains some basic operations(save) and all of the supported workflow nodes.\r
})\r
export class ToolbarComponent implements AfterViewInit {\r
\r
- constructor(private jsPlumbService: JsPlumbService) {\r
+ constructor(private jsPlumbService: JsPlumbService, private workflowService: WorkflowService) {\r
}\r
\r
public ngAfterViewInit() {\r
this.jsPlumbService.buttonDraggable();\r
}\r
\r
+ public save() {\r
+ this.workflowService.save().subscribe(success => {\r
+ if(success) {\r
+ console.log(`save workflow success`);\r
+ } else {\r
+ console.log(`save workflow failed`);\r
+ }\r
+ });\r
+ }\r
+\r
}\r
--- /dev/null
+/**\r
+ * Copyright (c) 2017 ZTE Corporation.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * and the Apache License 2.0 which both accompany this distribution,\r
+ * and are available at http://www.eclipse.org/legal/epl-v10.html\r
+ * and http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Contributors:\r
+ * ZTE - initial API and implementation and/or initial documentation\r
+ */\r
+\r
+import { Injectable } from '@angular/core';\r
+import { WorkflowNode } from "./workflow-node";\r
+\r
+/**\r
+ * Workflow\r
+ */\r
+export class Workflow {\r
+ constructor(public id: string, public name: string, public nodes: WorkflowNode[]) {}\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (c) 2017 ZTE Corporation.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * and the Apache License 2.0 which both accompany this distribution,\r
+ * and are available at http://www.eclipse.org/legal/epl-v10.html\r
+ * and http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Contributors:\r
+ * ZTE - initial API and implementation and/or initial documentation\r
+ */\r
+\r
+import { Injectable } from '@angular/core';\r
+import { WorkflowNode } from "../../model/workflow-node";\r
+import { Observable } from "rxjs/Observable";\r
+import { HttpService } from "../../util/http.service";\r
+import { Workflow } from "../../model/workflow";\r
+\r
+/**\r
+ * CatalogService\r
+ * provides data access from backend\r
+ */\r
+@Injectable()\r
+export abstract class CatalogService {\r
+\r
+ constructor(protected httpService: HttpService) {}\r
+\r
+ public abstract loadWorkflow(workflowId: string): Observable<Workflow>;\r
+\r
+ public abstract saveWorkflow(workflow: Workflow): Observable<boolean>;\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (c) 2017 ZTE Corporation.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * and the Apache License 2.0 which both accompany this distribution,\r
+ * and are available at http://www.eclipse.org/legal/epl-v10.html\r
+ * and http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Contributors:\r
+ * ZTE - initial API and implementation and/or initial documentation\r
+ */\r
+\r
+import { Injectable } from '@angular/core';\r
+import { CatalogService } from "./catalog.service";\r
+import { SdcService } from "./sdc.service";\r
+import { HttpService } from "../../util/http.service";\r
+\r
+/**\r
+ * DataAccessService\r
+ * provides data access from backend\r
+ */\r
+@Injectable()\r
+export class DataAccessService {\r
+ constructor(private httpService: HttpService) {}\r
+\r
+ public catalogService: CatalogService = new SdcService(this.httpService);\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (c) 2017 ZTE Corporation.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * and the Apache License 2.0 which both accompany this distribution,\r
+ * and are available at http://www.eclipse.org/legal/epl-v10.html\r
+ * and http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Contributors:\r
+ * ZTE - initial API and implementation and/or initial documentation\r
+ */\r
+\r
+import { Injectable } from '@angular/core';\r
+import { InMemoryDbService } from 'angular-in-memory-web-api';\r
+/**\r
+ * InMemeoryDataService\r
+ * Mock backend data\r
+ */\r
+export class InMemoryDataService implements InMemoryDbService {\r
+ createDb() {\r
+ const workflows = [{\r
+ id: 'workflow1',\r
+ name:'workflow1',\r
+ nodes: []\r
+ },{\r
+ id:'workflow2',\r
+ name: 'workflow2',\r
+ nodes: []\r
+ }\r
+ ];\r
+ return {workflows};\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (c) 2017 ZTE Corporation.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * and the Apache License 2.0 which both accompany this distribution,\r
+ * and are available at http://www.eclipse.org/legal/epl-v10.html\r
+ * and http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Contributors:\r
+ * ZTE - initial API and implementation and/or initial documentation\r
+ */\r
+\r
+import { Injectable } from '@angular/core';\r
+import { CatalogService } from "./catalog.service";\r
+import { Observable } from "rxjs/Observable";\r
+import { WorkflowNode } from "../../model/workflow-node";\r
+import { HttpService } from "../../util/http.service";\r
+import { Workflow } from "../../model/workflow";\r
+\r
+/**\r
+ * SdcService\r
+ * provides data access from sdc\r
+ */\r
+@Injectable()\r
+export class SdcService extends CatalogService {\r
+\r
+ constructor(protected httpService: HttpService) {\r
+ super(httpService);\r
+ }\r
+\r
+ public loadWorkflows(): Observable<WorkflowNode[]> {\r
+ // TODO load data from sdc\r
+ const url = 'api/workflows';\r
+ return this.httpService.get(url);\r
+ }\r
+\r
+ public loadWorkflow(workflowId: string): Observable<Workflow> {\r
+ // TODO load data from sdc\r
+ const url = `api/workflows/${workflowId}`;\r
+ return this.httpService.get(url).map(response => response.data);\r
+ }\r
+\r
+ public saveWorkflow(workflow: Workflow): Observable<boolean> {\r
+ // TODO save workflow design to sdc\r
+ const url = `api/workflows/${workflow.id}`;\r
+ return this.httpService.put(url, JSON.stringify(workflow)).map(() => true);\r
+ }\r
+\r
+}\r
\r
import { Injectable } from '@angular/core';\r
import { WorkflowNode } from "../model/workflow-node";\r
+import { DataAccessService } from "./data-access/data-access.service";\r
+import { Observable } from "rxjs/Observable";\r
+import { Workflow } from "../model/workflow";\r
\r
/**\r
* WorkflowService\r
*/\r
@Injectable()\r
export class WorkflowService {\r
- public nodes: WorkflowNode[] = [];\r
\r
- public getNodes(): WorkflowNode[] {\r
- return this.nodes;\r
+ public workflow: Workflow;\r
+\r
+ constructor(private dataAccessService: DataAccessService) {\r
+\r
+ }\r
+\r
+ public save(): Observable<boolean> {\r
+ return this.dataAccessService.catalogService.saveWorkflow(this.workflow);\r
}\r
\r
- public addNode(name: string, type: string, top: number, left: number) {\r
- this.nodes.push(new WorkflowNode(this.createId(), name, type, top, left));\r
+ public addNode(name: string, type: string, top: number, left: number): WorkflowNode {\r
+ const node = new WorkflowNode(this.createId(), name, type, top, left);\r
+ this.workflow.nodes.push(node);\r
+ return node;\r
}\r
\r
public deleteNode(nodeId: string): WorkflowNode {\r
// delete current node\r
- const index = this.nodes.findIndex(node => node.id === nodeId);\r
+ const index = this.workflow.nodes.findIndex(node => node.id === nodeId);\r
if (index !== -1) {\r
- const node = this.nodes.splice(index, 1)[0];\r
+ const node = this.workflow.nodes.splice(index, 1)[0];\r
return node;\r
}\r
\r
return undefined;\r
}\r
\r
- public getNode(sourceId: string): WorkflowNode {\r
- return this.nodes.find(node => node.id === sourceId);\r
+ public getNodeById(sourceId: string): WorkflowNode {\r
+ return this.workflow.nodes.find(node => node.id === sourceId);\r
}\r
\r
private createId() {\r
const idSet = new Set();\r
- this.nodes.forEach(node => idSet.add(node.id));\r
+ this.workflow.nodes.forEach(node => idSet.add(node.id));\r
\r
for (let i = 0; i < idSet.size; i++) {\r
if (!idSet.has('node' + i)) {\r
--- /dev/null
+/**
+ * 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 { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { HttpModule } from '@angular/http';
+import { RouterModule } from '@angular/router';
+
+const module = [
+ CommonModule,
+ FormsModule,
+ RouterModule,
+];
+
+@NgModule({
+ imports: module,
+ exports: module,
+})
+
+export class SharedModule {
+}
--- /dev/null
+/**
+ * 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 './rxjs-operators';
+
+@Injectable()
+export class HttpService {
+ constructor(private http: Http) {}
+
+ public get(uri: string): Observable<any> {
+ return this.getHttp('get', uri);
+ }
+
+ public post(uri: string, data: any): Observable<any> {
+ return this.getHttp('post', uri, data);
+ }
+
+ public put(uri: string, data: any, options?: RequestOptionsArgs): Observable<any> {
+ return this.getHttp('put', uri, data, options);
+ }
+
+ public delete(uri: string): Observable<any> {
+ return this.getHttp('delete', uri);
+ }
+
+ public getHttp(type: string, uri: string, data?: any, options?: RequestOptionsArgs): Observable<any> {
+ if (data) {
+ return this.http[type](uri, data, options)
+ .map(response =>
+ response.json()
+ )
+ .catch(this.handleError);
+ } else {
+ return this.http[type](uri, options)
+ .map(response =>
+ response.json()
+ )
+ .catch(this.handleError);
+ }
+ }
+
+ private handleError(error: any) {
+ const errMsg = (error.message) ? error.message :
+ error.status ? `${error.status}-${error.statusText}` : 'Server error';
+ return Observable.throw(errMsg);
+ }
+}
--- /dev/null
+/**
+ * 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 'rxjs/add/observable/throw';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/debounceTime';
+import 'rxjs/add/operator/distinctUntilChanged';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/switchMap';
+import 'rxjs/add/operator/toPromise';
<head>
<meta charset="utf-8">
<title>Workflow Designer</title>
- <base href="/lvbo">
+ <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>