Add CRUD operation for workflows 89/12889/1
authorLvbo163 <lv.bo163@zte.com.cn>
Sun, 17 Sep 2017 06:54:05 +0000 (14:54 +0800)
committerLvbo163 <lv.bo163@zte.com.cn>
Sun, 17 Sep 2017 06:54:05 +0000 (14:54 +0800)
Add CRUD and export operation for workflows.

Issue-ID: SDC-72

Change-Id: Ie2ef818a6979cc13b9e2dad7cea3b3121727146f
Signed-off-by: Lvbo163 <lv.bo163@zte.com.cn>
13 files changed:
sdc-workflow-designer-ui/src/app/app.module.ts
sdc-workflow-designer-ui/src/app/components/canvas/canvas.component.ts
sdc-workflow-designer-ui/src/app/components/menu/menu.component.html
sdc-workflow-designer-ui/src/app/components/menu/menu.component.ts
sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.html [new file with mode: 0644]
sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.ts [new file with mode: 0644]
sdc-workflow-designer-ui/src/app/services/broadcast.service.ts
sdc-workflow-designer-ui/src/app/services/data-access/catalog.service.ts
sdc-workflow-designer-ui/src/app/services/data-access/sdc.service.ts
sdc-workflow-designer-ui/src/app/services/jsplumb.service.ts
sdc-workflow-designer-ui/src/app/services/workflow.service.ts
sdc-workflow-designer-ui/src/app/shared/shared.module.ts
sdc-workflow-designer-ui/src/ngict-component.css

index b2bcb74..4ce9eed 100644 (file)
@@ -10,6 +10,7 @@
  *     ZTE - initial API and implementation and/or initial documentation
  */
 
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
 import { NgxTreeSelectModule } from 'ngx-tree-select';
@@ -47,6 +48,7 @@ import { IntermediateCatchEventComponent } from "./components/property/intermedi
 import { SequenceFlowComponent } from "./components/sequence-flow/sequence-flow.component";
 import { ScriptTaskComponent } from "./components/property/script-task/script-task.component";
 import { DragSelectDirective } from "./directive/drag-select/drag-select.directive";
+import { WorkflowsComponent } from "./components/menu/workflows/workflows.component";
 
 @NgModule({
     declarations: [
@@ -69,8 +71,10 @@ import { DragSelectDirective } from "./directive/drag-select/drag-select.directi
         SequenceFlowComponent,
         StartEventParametersComponent,
         ToolbarComponent,
+        WorkflowsComponent,
     ],
     imports: [
+        BrowserAnimationsModule,
         BrowserModule,
         HttpModule,
         InMemoryWebApiModule.forRoot(InMemoryDataService),
index 5016b50..f5ccbc9 100644 (file)
@@ -46,13 +46,13 @@ export class CanvasComponent implements AfterViewInit {
     }
 
     ngOnInit(): void {
-        this.route.queryParams.subscribe(params => {
-            if (params.id) {
-                this.dataAccessService.catalogService.loadWorkflow(params.id).subscribe(workflow => {
-                    this.workflowService.workflow = workflow;
-                });
-            }
-        });
+        // this.route.queryParams.subscribe(params => {
+        //     if (params.id) {
+        //         this.dataAccessService.catalogService.loadWorkflow(params.id).subscribe(workflow => {
+        //             this.workflowService.workflow = workflow;
+        //         });
+        //     }
+        // });
     }
 
     public ngAfterViewInit() {
index 1623489..e54dd4e 100644 (file)
 -->
 
 <div class="btn-right">
+    <p-splitButton label="Workflows" icon="fa-check" (onClick)="showWorkflows()" [model]="getWorkflows()"></p-splitButton>
     <button type="button" class="btn white" (click)="save()">
         <i class="fa fa-save"></i>Save
     </button>
     <button type="button" class="btn white" (click)="showMicroserviceModal()">
         <i class="fa fa-cog"></i>Setting
     </button>
+    <button type="button" class="btn white" (click)="download()">
+            <i class="fa fa-download"></i>Download
+        </button>
     <!-- <button type="button" class="btn white" (click)="test()">test</button> -->
 </div>
 <b4t-microservice></b4t-microservice>
+<b4t-workflows></b4t-workflows>
index 2c03cbf..4183391 100644 (file)
@@ -13,6 +13,9 @@ import { Component, OnInit, ViewChild } from '@angular/core';
 
 import { WorkflowService } from '../../services/workflow.service';
 import { MicroserviceComponent } from "./microservice/microservice.component";
+import { WorkflowsComponent } from "./workflows/workflows.component";
+import { BroadcastService } from "../../services/broadcast.service";
+import { Workflow } from "../../model/workflow/workflow";
 
 @Component({
     selector: 'b4t-menu',
@@ -21,8 +24,10 @@ import { MicroserviceComponent } from "./microservice/microservice.component";
 })
 export class MenuComponent {
     @ViewChild(MicroserviceComponent) public microserviceComponent: MicroserviceComponent;
+    @ViewChild(WorkflowsComponent) public workflowsComponent: WorkflowsComponent;
 
-    constructor(private workflowService: WorkflowService) { }
+    constructor(private broadcastService: BroadcastService, private workflowService: WorkflowService) {
+    }
 
     public save(): void {
         this.workflowService.save();
@@ -34,4 +39,42 @@ export class MenuComponent {
 
     public test() {
     }
+
+    public showWorkflows() {
+        this.workflowsComponent.show();
+    }
+
+    public getWorkflows(workflow: Workflow) {
+        const workflows = this.workflowService.getWorkflows();
+        if(workflows) {
+            return workflows.map(workflow => {
+                return {label: workflow.name, command: () => {
+                    this.workflowSelected(workflow);
+                }};
+            });
+        } else {
+            return [];
+        }
+    }
+
+    public workflowSelected(workflow: Workflow) {
+        this.broadcastService.broadcast(this.broadcastService.workflow, workflow);
+    }
+
+    public download() {
+        const filename = this.workflowService.workflow.name + '.json';
+        const content = JSON.stringify(this.workflowService.workflow);
+        // 创建隐藏的可下载链接
+        var eleLink = document.createElement('a');
+        eleLink.download = filename;
+        eleLink.style.display = 'none';
+        // 字符内容转变成blob地址
+        var blob = new Blob([content]);
+        eleLink.href = URL.createObjectURL(blob);
+        // 触发点击
+        document.body.appendChild(eleLink);
+        eleLink.click();
+        // 然后移除
+        document.body.removeChild(eleLink);
+    }
 }
diff --git a/sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.html b/sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.html
new file mode 100644 (file)
index 0000000..0a3b51b
--- /dev/null
@@ -0,0 +1,41 @@
+<!--\r
+/**\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
+<div class="modal fade" bsModal #workflowsModal="bs-modal" [config]="{backdrop: 'static'}"\r
+tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">\r
+    <div class="modal-dialog">\r
+    <div class="modal-content">\r
+        <div class="modal-header">\r
+            <h4 class="modal-title pull-left">Workflows</h4>\r
+            <button type="button" class="close pull-right" aria-label="Close" (click)="workflowsModal.hide()">\r
+                <span aria-hidden="true">&times;</span>\r
+            </button>\r
+        </div>\r
+        <div class="modal-body">\r
+            <ul class="list-group">\r
+                    <li class="list-group-item d-flex justify-content-between align-items-center"\r
+                        *ngFor="let workflow of workflows">\r
+                        <div style="width:380px"><input class="form-control" [(ngModel)]="workflow.name"></div>\r
+                        <div class="badge badge-danger badge-pill" (click)="deleteWorkflow(workflow)">\r
+                            <i class="fa fa-minus"></i>\r
+                        </div>\r
+                    </li>\r
+                </ul>\r
+        </div>\r
+        <div class="modal-footer">\r
+            <button type="button" class="btn over-grey" (click)="addWorkflow()">Add</button>\r
+            <button type="button" class="btn over-grey" (click)="workflowsModal.hide()">close</button>\r
+        </div>\r
+    </div>\r
+    </div>\r
+</div>\r
diff --git a/sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.ts b/sdc-workflow-designer-ui/src/app/components/menu/workflows/workflows.component.ts
new file mode 100644 (file)
index 0000000..dff7300
--- /dev/null
@@ -0,0 +1,48 @@
+/**\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 { AfterViewInit, Component, ViewChild } from '@angular/core';\r
+import { ModalDirective } from 'ngx-bootstrap/modal';\r
+\r
+import { WorkflowService } from "../../../services/workflow.service";\r
+import { Workflow } from "../../../model/workflow/workflow";\r
+\r
+/**\r
+ * workflows component\r
+ * open a model to set workflow info\r
+ */\r
+@Component({\r
+    selector: 'b4t-workflows',\r
+    templateUrl: 'workflows.component.html',\r
+})\r
+export class WorkflowsComponent {\r
+    @ViewChild('workflowsModal') public workflowsModal: ModalDirective;\r
+\r
+    public workflows: Workflow[];\r
+\r
+    constructor(private workflowService: WorkflowService) {\r
+    }\r
+\r
+    public show() {\r
+        this.workflows = this.workflowService.getWorkflows();\r
+        this.workflowsModal.show();\r
+    }\r
+\r
+    public deleteWorkflow(workflow: Workflow) {\r
+        this.workflowService.deleteWorkflow(workflow.name);\r
+    }\r
+\r
+    public addWorkflow() {\r
+        this.workflowService.addWorkflow();\r
+    }\r
+\r
+}\r
index ec182b3..dbf52f9 100644 (file)
@@ -14,6 +14,7 @@ import { Subject } from 'rxjs/Subject';
 
 import { WorkflowNode } from '../model/workflow/workflow-node';
 import { SequenceFlow } from "../model/workflow/sequence-flow";
+import { Workflow } from "../model/workflow/workflow";
 
 /**
  * BroadcastService
@@ -26,6 +27,12 @@ export class BroadcastService {
     public jsPlumbInstance = new Subject<any>();
     public jsPlumbInstance$ = this.jsPlumbInstance.asObservable();
 
+    public workflows = new Subject<Workflow[]>();
+    public workflows$ = this.workflows.asObservable();
+
+    public workflow = new Subject<Workflow>();
+    public workflow$ = this.workflow.asObservable();
+
     public showProperty = new Subject<boolean>();
     public showProperty$ = this.showProperty.asObservable();
 
index abd7355..d5d998f 100644 (file)
@@ -26,6 +26,7 @@ export abstract class CatalogService {
     constructor(protected httpService: HttpService) {}\r
 \r
     public abstract loadWorkflow(workflowId: string): Observable<Workflow>;\r
+    public abstract loadWorkflows(): Observable<Workflow[]>;\r
 \r
     public abstract saveWorkflow(workflow: Workflow): Observable<boolean>;\r
 }\r
index 02ade95..81efbed 100644 (file)
@@ -28,10 +28,10 @@ export class SdcService extends CatalogService {
         super(httpService);\r
     }\r
 \r
-    public loadWorkflows(): Observable<WorkflowNode[]> {\r
+    public loadWorkflows(): Observable<Workflow[]> {\r
         // TODO load data from sdc\r
         const url = 'api/workflows';\r
-        return this.httpService.get(url);\r
+        return this.httpService.get(url).map(response => response.data);\r
     }\r
 \r
     public loadWorkflow(workflowId: string): Observable<Workflow> {\r
index 6aa5028..bf7a690 100644 (file)
@@ -27,15 +27,21 @@ export class JsPlumbService {
     public subscriptionMap = new Map<string, Subscription>();\r
 \r
     constructor(private processService: WorkflowProcessService, private broadcastService: BroadcastService) {\r
+        this.jsplumbInstance = jsp.jsPlumb.getInstance({\r
+            Container: 'canvas'\r
+        });\r
         this.initJsPlumbInstance();\r
+        this.broadcastService.workflow.subscribe(Workflow => {\r
+            this.jsplumbInstance.reset();\r
+            this.unsubscriptionAll();\r
+            this.initJsPlumbInstance();\r
+            this.buttonDraggable();\r
+            this.buttonDroppable();\r
+        });\r
     }\r
 \r
 \r
     public initJsPlumbInstance() {\r
-        this.jsplumbInstance = jsp.jsPlumb.getInstance({\r
-            Container: 'canvas'\r
-        });\r
-\r
         this.jsplumbInstance.importDefaults({\r
             Anchor: ['Top', 'RightMiddle', 'LeftMiddle', 'Bottom'],\r
             Connector: [\r
@@ -119,6 +125,10 @@ export class JsPlumbService {
         });\r
     }\r
 \r
+    private unsubscriptionAll() {\r
+        this.subscriptionMap.forEach(subscription => subscription.unsubscribe());\r
+    }\r
+\r
     public initNode() {\r
         this.processService.getProcess().forEach(node => {\r
             this.jsplumbInstance.draggable(node.id, {\r
@@ -154,8 +164,8 @@ export class JsPlumbService {
                 source: sequenceFlow.sourceRef,\r
                 target: sequenceFlow.targetRef,\r
             });\r
-            if (sequenceFlow.condition) {\r
-                connection.setLabel(sequenceFlow.condition);\r
+            if (sequenceFlow.name) {\r
+                connection.setLabel(sequenceFlow.name);\r
             }\r
         });\r
     }\r
index c1eed4a..3f42fa2 100644 (file)
@@ -14,6 +14,8 @@ import { Injectable } from '@angular/core';
 import { DataAccessService } from "./data-access/data-access.service";\r
 import { Observable } from "rxjs/Observable";\r
 import { Workflow } from "../model/workflow/workflow";\r
+import { Configs } from "../model/workflow/configs";\r
+import { BroadcastService } from "./broadcast.service";\r
 \r
 /**\r
  * WorkflowService\r
@@ -22,10 +24,16 @@ import { Workflow } from "../model/workflow/workflow";
 @Injectable()\r
 export class WorkflowService {\r
 \r
+    public workflows: Workflow[];\r
     public workflow: Workflow;\r
+    public workflowIndex = 0;\r
 \r
-    constructor(private dataAccessService: DataAccessService) {\r
-\r
+    constructor(private broadcastService: BroadcastService, private dataAccessService: DataAccessService) {\r
+        this.dataAccessService.catalogService.loadWorkflows().subscribe(workflows => {\r
+            this.workflows = workflows;\r
+            this.broadcastWorkflows();\r
+        });\r
+        this.broadcastService.workflow.subscribe(workflow => this.workflow = workflow);\r
     }\r
 \r
     public save(): Observable<boolean> {\r
@@ -33,4 +41,28 @@ export class WorkflowService {
         console.log(JSON.stringify(this.workflow));\r
         return this.dataAccessService.catalogService.saveWorkflow(this.workflow);\r
     }\r
+\r
+    public getWorkflows(): Workflow[] {\r
+        return this.workflows;\r
+    }\r
+\r
+    public addWorkflow() {\r
+        this.workflows.push(new Workflow('wf' + this.workflowIndex, '', [], new Configs([])));\r
+        this.workflowIndex++;\r
+        this.broadcastWorkflows();\r
+    }\r
+\r
+    public deleteWorkflow(workflowName: string): Workflow {\r
+        const index = this.workflows.findIndex(workflow => (workflow.name === workflowName));\r
+        if(index !== -1) {\r
+            return this.workflows.splice(index, 1)[0];\r
+        }\r
+        this.broadcastWorkflows();\r
+\r
+        return undefined;\r
+    }\r
+\r
+    public broadcastWorkflows() {\r
+        this.broadcastService.broadcast(this.broadcastService.workflows, this.workflows);\r
+    }\r
 }\r
index faa4d7d..448edc6 100644 (file)
@@ -13,7 +13,7 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 import { HttpModule } from '@angular/http';
-import { RadioButtonModule, TreeModule } from 'primeng/primeng';
+import { RadioButtonModule, SplitButtonModule, TreeModule } from 'primeng/primeng';
 import { RouterModule } from '@angular/router';
 
 const module = [
@@ -21,6 +21,7 @@ const module = [
     FormsModule,
     RadioButtonModule,
     RouterModule,
+    SplitButtonModule,
     TreeModule,
 ];
 
index 32582bb..f02922f 100644 (file)
@@ -900,7 +900,7 @@ input::-webkit-input-placeholder {
   left: 6px;
 }
 /*.input-group .form-control {
-    height: 26px !important;   
+    height: 26px !important;
 }*/
 .input-group {
   /* width:400px;*/
@@ -1411,29 +1411,29 @@ button {
   -moz-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
   box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
 }
-/*     
+/*
 .alert-success {
     color: #fff;
-    background-color: #73cf22;   
+    background-color: #73cf22;
     border-color:#73cf22;
 }
 
 .alert-info {
     color: #fff;
-    background-color: #00abff;   
-       border-color:#00abff;   
+    background-color: #00abff;
+       border-color:#00abff;
 }
 
 .alert-warning {
     color: #fff;
-    background-color: #f7c515; 
-       border-color:#f7c515;           
+    background-color: #f7c515;
+       border-color:#f7c515;
 }
 
 .alert-danger {
     color: #fff;
     background-color: #ff5b55;
-       border-color:#ff5b55;   
+       border-color:#ff5b55;
 }*/
 .close {
   color: #f2f2f2;
@@ -1514,7 +1514,7 @@ button {
   z-index: 10000;
 }
 .modal .modal-dialog {
-  max-width: 1000px;
+  /* max-width: 1000px; */
 }
 .modal .close {
   color: #bbb;