merge from ecomp a88f0072 - Modern UI

Issue-ID: VID-378
Change-Id: Ibcb23dd27f550cf32ce2fe0239f0f496ae014ff6
Signed-off-by: Ittay Stern <ittay.stern@att.com>
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.html b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.html
new file mode 100644
index 0000000..f02ed62
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.html
@@ -0,0 +1,78 @@
+<div class="drawing-board-header">
+  <div class="left-header">
+    <span class="vid-logo-small"></span>
+    <span class="icon-back">
+      <svg-icon
+        (click)="closePage()"
+        [testId]="'backBtn'"
+        [size]="'large'"
+        [name]="'navigation-arrow-back'">
+              </svg-icon>
+    </span>
+
+    <div class="header-col middleDetails" style="padding-top: 5px;padding-left: 13px;line-height: 100%;" *ngIf="isServiceFailed">
+      <custom-popover class="failed-popover-wrap" [value]= "serviceStatusMessage" [placement]="'bottom'" [popoverType]="'error'">
+        <span [attr.data-tests-id]="'service-failed-msg'" class="failed-msg labelPosition" >Failed</span>
+      </custom-popover>
+    </div>
+    <div class="header-col middleDetails" style="padding-top: 0px;padding-left: 13px;line-height: 100%;padding-right: 50px;">
+      <span [attr.data-tests-id]="'serviceInstance'" class="service-instance-label labelPosition">Service instance:</span>
+      <span [attr.data-tests-id]="'serviceName'" [ngClass]="{'deleted' : isDeleted}" class="service-instance-name">{{serviceName}}</span>
+    </div>
+    <div class="header-col middleDetails notShowOnCreateMode"
+         style="padding-top: 0px;padding-left: 13px;line-height: 100%;">
+      <span [attr.data-tests-id]="'orchStatusLabel'" class="service-instance-label labelPosition">Orch Status:</span>
+      <span [attr.data-tests-id]="'orchStatusValue'" class="orch-status-value">{{serviceOrchStatus}}</span>
+    </div>
+    <div class="quantity-container header-col middleDetails"
+         style="padding-top: 0px;padding-left: 13px;line-height: 100%;"
+         tooltip="Number of services to instantiate including all their objects as defined below">
+      <span [attr.data-tests-id]="'quantityLabel'" class="quantity-instance-label labelPosition">Scale Times:</span>
+      <span [attr.data-tests-id]="'servicesQuantity'" class="scale-value"
+            style="font-family: OpenSans-Semibold;font-size: 13px;"> {{numServicesToDeploy}} </span>
+    </div>
+
+    <span [attr.data-tests-id]="'serviceStatus'" class="status" tooltip="{{status}}"></span>
+    <span [attr.data-tests-id]="'isViewOnly-status-test'" class="service-instance-label purple">{{getModeName()}}</span>
+  </div>
+
+
+  <div class="right-header">
+    <span class="menu-container notShowOnViewMode notShowOnRetryMode">
+      <span [attr.data-tests-id]="'openMenuBtn'" class="icon-browse" (click)="onContextMenu($event)"></span>
+      <context-menu>
+        <ng-template *ngIf="drawingBoardHeaderService?.showEditService(mode, serviceModelId)" contextMenuItem (execute)="editService()">
+          <div [attr.data-tests-id]="'context-menu-header-edit-item'">
+            <span class="icon-edit"></span>Edit</div>
+        </ng-template>
+        <ng-template *ngIf="mode === 'EDIT'" contextMenuItem
+                     (execute)="isDeleted=!isDeleted; drawingBoardHeaderService.deleteService(serviceModelId,isDeleted)">
+          <div [attr.data-tests-id]="'context-menu-header-delete-item'"><span class="icon-trash"></span>{{isDeleted ? 'Undo delete': 'Delete'}}</div>
+        </ng-template>
+        <ng-template *ngIf="mode !== 'CREATE'" contextMenuItem
+                     (execute)="drawingBoardHeaderService.showAuditInfo(serviceModelId)">
+          <div  [attr.data-tests-id]="'context-menu-header-audit-item'" style="float: left;margin-top: 8px;">
+                  <svg-icon
+                    [ngClass]="'eye-o'"
+                    class="eye-o"
+                    [size]="'small'"
+                    [name]="'eye-o'">
+                </svg-icon></div>
+                <div style="padding-left: 12px;">Show Audit Info</div>
+        </ng-template>
+      </context-menu>
+    </span>
+    <button [disabled]="drawingBoardHeaderService?.deployShouldBeDisabled(serviceModelId, mode)"
+            *ngIf="mode !== 'VIEW' && mode !== 'RETRY'; else viewEditButton"
+            [attr.data-tests-id]="'deployBtn'"
+            (click)="deployService()"
+            class="deploy-btn">{{drawingBoardHeaderService?.getModeButton(mode)}}</button>
+    <ng-template #viewEditButton>
+      <button [disabled]="!isPermitted()"
+        [attr.data-tests-id]="'editBtn'"
+        (click)="editViewEdit()"
+        class="deploy-btn">{{drawingBoardHeaderService?.getButtonText(mode)}}
+      </button>
+    </ng-template>
+  </div>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.scss
new file mode 100644
index 0000000..1242f94
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.scss
@@ -0,0 +1,176 @@
+.drawing-board-header {
+  height: 60px;
+  font-family: OpenSans-Regular;
+  display: flex;
+  justify-content: space-between;
+  font-size: 14px;
+  box-shadow: 2px 2px 6px #D2D2D2;
+  color: #191919;
+  z-index: 1;
+  position: relative;
+    [class^="icon-"] {
+      height: 60px;
+      width: 60px;
+      display: flex;
+      align-items: center;
+      text-align: center;
+      color: #5A5A5A;
+      cursor: pointer;
+      &:before {
+        font-size: 18px;
+        width: 100%;
+      }
+      &:hover:before {
+        color: #009FDB;
+      }
+    }
+  .left-header {
+      display: flex;
+      align-items: center;
+      .icon-back {
+        justify-content: center;
+        border-right: 1px solid #EAEAEA;
+      }
+      .vid-logo-small{
+        background: url('../../../../assets/img/vid-logo.jpg') no-repeat;
+        width: 60px;
+        height: 60px;
+      }
+      .status{
+        background: url('../../../../assets/img/indesign.svg') no-repeat  center;
+        width: 24px;
+        height: 24px;
+        margin-left: 20px;
+      }
+      .header-col {
+        border-right: 1px solid #d2d2d2;
+        padding-right: 15px;
+        margin-left: 15px;
+        span{
+          display: block;
+        }
+        &:after{
+          content: "";
+          background: #D2D2D2;
+          height: 35px;
+          width: 1px;
+        }
+      }
+      .service-instance-label {
+        font-family: OpenSans-Semibold;
+        font-size: 13px;
+        color: #5A5A5A;
+      }
+      .quantity-instance-label {
+        font-family: OpenSans-Regular;
+        font-size: 13px;
+        color: #5A5A5A;
+      }
+
+      .labelPosition {
+        margin-top: 4px;
+        margin-bottom: 6px;
+        font-size: 12px;
+      }
+      .service-instance-name {
+        font-family: OpenSans-Semibold;
+        color: #191919;
+        background-color: white;
+        font-size: 14px;
+        &.deleted{
+          text-decoration: line-through;
+        }
+      }
+      .orch-status-value {
+        font-family: OpenSans-Regular;
+        font-size: 14px;
+        color: #191919;
+      }
+      .scale-value {
+        font-family: OpenSans-Regular;
+        font-size: 14px;
+        color: #191919;
+      }
+      .status {
+        font-family: OpenSans-Semibold;
+        line-height: 14px;
+        font-size: 14px;
+        text-align: center;
+        width: 30px;
+        margin-left: 13px;
+        margin-right: 3px;
+      }
+
+      .purple {
+        color: #9063CD;
+      }
+
+      .middleDetails {
+        border-right: 1px solid #EAEAEA;
+        margin-left: 0;
+        height: 45px;
+      }
+    }
+    .right-header {
+      display: flex;
+      align-items: center;
+      .quantity-container {
+        .quantity-label {
+          padding-left: 10px;
+          font-family: OpenSans-Semibold;
+          font-size: 12px;
+        }
+        .quantity {
+          padding: 5px 10px 5px 0;
+          font-family: OpenSans-Semibold;
+          font-size: 18px;
+        }
+      }
+      .scale-container {
+        .scale-label {
+          padding-left: 10px;
+          font-family: OpenSans-Semibold;
+          font-size: 12px;
+        }
+        .scale {
+          padding: 5px 10px 5px 0;
+          font-family: OpenSans-Semibold;
+          font-size: 18px;
+        }
+      }
+      [class^="icon-"] {
+        border-left: 1px solid #EAEAEA;
+      }
+      .menu-container {
+        height: 100%;
+        display: flex;
+        background: none;
+        border: none;
+        padding: 0;
+        outline: none;
+        justify-content: center;
+        flex-direction: column;
+        text-align: center;
+        cursor: pointer;
+      }
+      .icon-browse:before {
+        content: '\e924';
+        display: inline-block;
+        font-size: 24px;
+      }
+      .deploy-btn {
+        color: #FFFFFF ;
+        background: #009fdb;
+        width: 128px;
+        height: 100%;
+        border: none;
+        &[disabled] {
+          cursor: not-allowed;
+          opacity: .65;
+          color: #99d6ec;
+        }
+      }
+    }
+  }
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.ts
new file mode 100644
index 0000000..6e43915
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.component.ts
@@ -0,0 +1,187 @@
+import {Component, ViewChild} from '@angular/core';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {MsoService} from '../../../shared/services/msoService/mso.service'
+import * as _ from 'lodash';
+import {ActivatedRoute} from '@angular/router';
+import {ServiceInstance} from "../../../shared/models/serviceInstance";
+import {OwningEntity} from "../../../shared/models/owningEntity";
+import {MessageBoxData} from "../../../shared/components/messageBox/messageBox.data";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../../shared/store/reducers";
+import {IframeService} from "../../../shared/utils/iframe.service";
+import {
+  GenericFormPopupComponent,
+  PopupType
+} from "../../../shared/components/genericFormPopup/generic-form-popup.component";
+import {ServicePopupService} from "../../../shared/components/genericFormPopup/genericFormServices/service/service.popup.service";
+import {SdcUiCommon} from "onap-ui-angular";
+import {DrawingBoardModes} from "../drawing-board.modes";
+import {DrawingBoardHeaderService} from "./drawing-board-header.service";
+import {ServiceInstanceActions} from "../../../shared/models/serviceInstanceActions";
+import {DrawingBoardPermissions} from "../../guards/servicePlanningGuard/drawingBoardGuard";
+import {MessageBoxService} from "../../../shared/components/messageBox/messageBox.service";
+
+@Component({
+  selector: 'drawing-board-header',
+  providers: [MsoService],
+  templateUrl: './drawing-board-header.component.html',
+  styleUrls: ['./drawing-board-header.component.scss']
+})
+
+export class DrawingBoardHeader {
+  serviceName: string;
+  numServicesToDeploy: number;
+  status: string = 'Designing a new service';
+  serviceModelId: string;
+  jobId: string;
+  parentElementClassName = 'content';
+  mode : DrawingBoardModes = DrawingBoardModes.CREATE;
+  serviceOrchStatus: string;
+  isDeleted: boolean = false;
+  store : NgRedux<AppState>;
+  drawingBoardPermissions : DrawingBoardPermissions;
+  drawingBoardHeaderService : DrawingBoardHeaderService;
+  isServiceFailed: boolean;
+  serviceStatusMessage: string;
+  constructor(private _contextMenuService: ContextMenuService, private dialogService: DialogService,
+              private _iframeService : IframeService,
+              private route: ActivatedRoute, private msoService: MsoService,
+              private _servicePopupService : ServicePopupService,
+              private _drawingBoardHeaderService : DrawingBoardHeaderService,
+              private _store: NgRedux<AppState>,
+              private _drawingBoardPermissions : DrawingBoardPermissions) {
+    this.store = _store;
+    this.drawingBoardPermissions = _drawingBoardPermissions;
+    this.drawingBoardHeaderService = _drawingBoardHeaderService;
+    this.mode = (!_.isNil(this.route.routeConfig.path) && this.route.routeConfig.path !== "") ?   this.route.routeConfig.path as DrawingBoardModes : DrawingBoardModes.CREATE;
+    this.route
+      .queryParams
+      .subscribe((params) => {
+        this.serviceModelId = params['serviceModelId'];
+        this.jobId = params['jobId'];
+        if (_.has(this.store.getState().service.serviceHierarchy, this.serviceModelId)) {
+          this.setValuesFromStore();
+          this.store.subscribe(() => {
+            this.setValuesFromStore();
+          });
+        }
+      });
+  }
+
+
+  @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+  editViewEdit(): void {
+     window.parent.location.assign(this._drawingBoardHeaderService.generateOldViewEditPath());
+  }
+
+  isPermitted() : boolean {
+    return this.drawingBoardPermissions.isEditPermitted;
+}
+
+  getModeName():string {
+    switch (this.mode) {
+      case DrawingBoardModes.CREATE:
+        return 'IN DESIGN';
+      case DrawingBoardModes.VIEW:
+      case DrawingBoardModes.RETRY:
+        return 'VIEW ONLY';
+      case DrawingBoardModes.EDIT:
+      case DrawingBoardModes.RETRY_EDIT:
+        return 'IN EDITING';
+      default:
+        return 'IN DESIGN';
+    }
+
+  }
+  public onContextMenu($event: MouseEvent, item: any): void {
+    this._contextMenuService.show.next({
+      contextMenu: this.contextMenu,
+      event: $event,
+      item: item,
+    });
+    $event.preventDefault();
+    $event.stopPropagation();
+  }
+
+  private setValuesFromStore() {
+    if(!_.isNil(this.store.getState().service.serviceInstance) && !_.isNil(this.store.getState().service.serviceInstance[this.serviceModelId])){
+      const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+      this.numServicesToDeploy = serviceInstance.bulkSize;
+      this.serviceName = serviceInstance.instanceName || '<Automatically Assigned>';
+      this.serviceOrchStatus =  serviceInstance.orchStatus || "";
+      this.isServiceFailed = serviceInstance.isFailed;
+      this.serviceStatusMessage = serviceInstance.statusMessage;
+    }
+  }
+
+  public editService(): void {
+    this._iframeService.addClassOpenModal(this.parentElementClassName);
+    this.dialogService.addDialog(GenericFormPopupComponent, {
+      type: PopupType.SERVICE,
+      uuidData: <any>{
+        type : PopupType.SERVICE,
+        isMacro : this.store.getState().service.serviceHierarchy[this.serviceModelId].service.instantiationType === 'Macro',
+        serviceId: this.serviceModelId,
+        popupService: this._servicePopupService
+      },
+      isUpdateMode: true
+    });
+  }
+
+  extractOwningEntityNameAccordingtoId(id:String): string {
+    let owningEntityName;
+    _.forEach(this.store.getState().service.categoryParameters.owningEntityList,(owningEntity: OwningEntity) => {
+      if (owningEntity.id === id) {
+        owningEntityName = owningEntity.name;
+
+      }});
+    return owningEntityName;
+  }
+
+  extractServiceFields(): any {
+    let instanceFields : ServiceInstance;
+    instanceFields = this.store.getState().service.serviceInstance[this.serviceModelId];
+    if (instanceFields.action === ServiceInstanceActions.Create) {
+      instanceFields.subscriberName = this.store.getState().service.subscribers.find(sub => sub.id === instanceFields.globalSubscriberId).name;
+      instanceFields.owningEntityName = this.extractOwningEntityNameAccordingtoId(instanceFields.owningEntityId);
+    }
+    return _.omit(instanceFields,'optionalGroupMembersMap');
+  }
+
+
+  public deployService(): void {
+      let instanceFields = this.extractServiceFields();
+      if (this.mode !== DrawingBoardModes.RETRY_EDIT) {
+        instanceFields.rollbackOnFailure = instanceFields.rollbackOnFailure === 'true';
+        this.msoService.submitMsoTask(instanceFields).subscribe((result) => {
+          window.parent.postMessage("navigateToInstantiationStatus", '*');
+        });
+      } else {
+        this.msoService.retryBulkMsoTask(this.jobId, instanceFields).subscribe((result) => {
+          window.parent.postMessage("navigateToInstantiationStatus", '*');
+        });
+      }
+  }
+
+  closePage() {
+    let messageBoxData : MessageBoxData = new MessageBoxData(
+         "Delete Instantiation",  // modal title
+      "You are about to stop the instantiation process of this service. \nAll data will be lost. Are you sure you want to stop?",
+      SdcUiCommon.ModalType.warning,
+      SdcUiCommon.ModalSize.medium,
+             [
+      {text:"Stop Instantiation", size:"large",  callback: this.navigate.bind(this), closeModal:true},
+      {text:"Cancel", size:"medium", closeModal:true}
+    ]);
+
+    MessageBoxService.openModal.next(messageBoxData);
+  }
+
+
+
+  navigate(){
+    window.parent.postMessage("navigateTo", "*");
+  }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.spec.ts
new file mode 100644
index 0000000..bcf6753
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.spec.ts
@@ -0,0 +1,184 @@
+import {getTestBed, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
+import {DefaultDataGeneratorService} from "../../../shared/services/defaultDataServiceGenerator/default.data.generator.service";
+import {MockNgRedux, NgReduxTestingModule} from "@angular-redux/store/testing";
+import {DrawingBoardHeaderService} from "./drawing-board-header.service";
+import {ActivatedRoute} from '@angular/router';
+import {ServiceInstanceActions} from "../../../shared/models/serviceInstanceActions";
+import {AppState} from "../../../shared/store/reducers";
+import {NgRedux} from "@angular-redux/store";
+import {addServiceAction} from "../../../shared/storeUtil/utils/service/service.actions";
+import {ErrorMsgService} from "../../../shared/components/error-msg/error-msg.service";
+import {DrawingBoardModes} from "../drawing-board.modes";
+import each from "jest-each";
+
+class MockAppStore<T>{
+  getState()  {
+    return {
+      service : {
+        serviceInstance : {
+          "serviceInstanceId" : {
+            action: 'None'
+          }
+        }
+      }
+    }
+  }
+}
+
+describe('Generate path to old View/Edit ', () => {
+  let injector;
+  let service: DrawingBoardHeaderService;
+  let httpMock: HttpTestingController;
+  let store :  NgRedux<AppState>;
+
+  beforeAll(done => (async () => {
+    TestBed.configureTestingModule({
+      imports: [HttpClientTestingModule, NgReduxTestingModule],
+      providers: [
+        DrawingBoardHeaderService,
+        DefaultDataGeneratorService,
+        MockNgRedux,
+        ErrorMsgService,
+        {
+          provide: ActivatedRoute,
+          useValue: {
+            snapshot : {
+              queryParams:{
+                'subscriberId' : 'subscriberId',
+                'subscriberName' : 'subscriberName',
+                'serviceType' : 'serviceType',
+                'serviceInstanceId' : 'serviceInstanceId'
+              }
+            }
+          },
+        }]
+    });
+    await TestBed.compileComponents();
+
+    injector = getTestBed();
+    service = injector.get(DrawingBoardHeaderService);
+    httpMock = injector.get(HttpTestingController);
+    store = injector.get(NgRedux);
+
+  })().then(done).catch(done.fail));
+
+
+  test('should generate url to old view/edit ', () => {
+    const query: string = 'subscriberId=subscriberId&subscriberName=subscriberName&serviceType=serviceType&serviceInstanceId=serviceInstanceId';
+    const path =  '../../serviceModels.htm#/instantiate?' + query;
+    let result = service.generateOldViewEditPath();
+   expect(result).toEqual(path);
+  });
+
+  test('should call update action for Delete',()=>{
+
+    jest.spyOn(store, 'dispatch');
+    service.deleteService("serviceInstanceId", true);
+    expect(store.dispatch).toHaveBeenCalledWith(addServiceAction("serviceInstanceId", ServiceInstanceActions.Delete));
+  });
+
+  test('should call update action for undo delete',()=>{
+    jest.spyOn(store, 'dispatch');
+    service.deleteService("serviceInstanceId", false);
+    expect(store.dispatch).toHaveBeenCalledWith(addServiceAction("serviceInstanceId", ServiceInstanceActions.None));
+  });
+
+  test('deployShouldBeDisabled with validationCounter greater then 0',()=>{
+    jest.spyOn(store, 'getState').mockReturnValue({
+      service: {
+        serviceInstance : {
+          'serviceInstanceId' : {
+            validationCounter : 1
+          }
+        }
+      }
+    });
+    let result = service.deployShouldBeDisabled("serviceInstanceId");
+    expect(result).toBeTruthy();
+  });
+
+  test('deployShouldBeDisabled with validationCounter is 0 and not dirty',()=>{
+    jest.spyOn(store, 'getState').mockReturnValue({
+      service: {
+        serviceInstance : {
+          'serviceInstanceId' : {
+            validationCounter : 0,
+            isDirty : false
+          }
+        }
+      }
+    });
+    let result = service.deployShouldBeDisabled("serviceInstanceId");
+    expect(result).toBeFalsy();
+  });
+
+  test('deployShouldBeDisabled with validationCounter is 0 and dirty',()=>{
+    jest.spyOn(store, 'getState').mockReturnValue({
+      service: {
+        serviceInstance : {
+          'serviceInstanceId' : {
+            validationCounter : 0,
+            action : 'None',
+            isDirty : true
+          }
+        }
+      }
+    });
+    let result = service.deployShouldBeDisabled("serviceInstanceId");
+    expect(result).not.toBeTruthy();
+  });
+
+  test('deployShouldBeDisabled with validationCounter is 0 and not and action is None and dirty',()=>{
+    jest.spyOn(store, 'getState').mockReturnValue({
+      service: {
+        serviceInstance : {
+          'serviceInstanceId' : {
+            validationCounter : 0,
+            action : ServiceInstanceActions.None,
+            isDirty : true
+          }
+        }
+      }
+    });
+    let result = service.deployShouldBeDisabled("serviceInstanceId");
+    expect(result).not.toBeTruthy();
+  });
+
+
+  test('getModeButton',()=>{
+    let result : string = service.getModeButton("EDIT");
+    expect(result).toEqual('UPDATE');
+
+    result  = service.getModeButton("");
+    expect(result).toEqual('DEPLOY');
+
+    result  = service.getModeButton("RETRY_EDIT");
+    expect(result).toEqual('REDEPLOY');
+  });
+  test('getButtonText',()=>{
+    expect(service.getButtonText("VIEW")).toEqual('EDIT');
+    expect(service.getButtonText("RETRY")).toEqual('REDEPLOY');
+
+  });
+  const showEditServiceDataProvider = [
+    ['Create action CREATE mode', DrawingBoardModes.CREATE ,ServiceInstanceActions.Create, true],
+    ['Create action RETRY_EDIT mode',DrawingBoardModes.RETRY_EDIT,  ServiceInstanceActions.Create,  true],
+    ['Create action EDIT mode',DrawingBoardModes.EDIT, ServiceInstanceActions.Create,  true],
+    ['Create action RETRY mode',DrawingBoardModes.RETRY, ServiceInstanceActions.Create,  false],
+    ['None action EDIT mode',DrawingBoardModes.EDIT,  ServiceInstanceActions.None, false],
+    ['None action RETRY_EDIT mode', DrawingBoardModes.RETRY_EDIT, ServiceInstanceActions.None, false]];
+  each(showEditServiceDataProvider).test('showEditService service with %s', (description, mode, action, enabled) => {
+    jest.spyOn(store, 'getState').mockReturnValue({
+      service: {
+        serviceInstance : {
+          'serviceInstanceId' : {
+            action : action
+          }
+        }
+      }
+    });
+    expect(service.showEditService(mode, 'serviceInstanceId')).toBe(enabled);
+
+  });
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.ts
new file mode 100644
index 0000000..946c5ca
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/drawing-board-header.service.ts
@@ -0,0 +1,86 @@
+import {Injectable} from "@angular/core";
+import {ActivatedRoute} from "@angular/router";
+import {addServiceAction} from "../../../shared/storeUtil/utils/service/service.actions";
+import {ServiceInstanceActions} from "../../../shared/models/serviceInstanceActions";
+import {AppState} from "../../../shared/store/reducers";
+import {DrawingBoardTreeComponent} from "../drawing-board-tree/drawing-board-tree.component";
+import {AuditInfoModalComponent} from "../../../shared/components/auditInfoModal/auditInfoModal.component";
+import {ServiceModel} from "../../../shared/models/serviceModel";
+import {NgRedux} from "@angular-redux/store";
+import * as _ from 'lodash';
+import {ErrorMsgService} from "../../../shared/components/error-msg/error-msg.service";
+import {DrawingBoardModes} from "../drawing-board.modes";
+import {ServiceInstance} from "../../../shared/models/serviceInstance";
+
+@Injectable()
+export class DrawingBoardHeaderService{
+
+  constructor(private route: ActivatedRoute, private store: NgRedux<AppState>, private errorMsgService: ErrorMsgService){}
+  generateOldViewEditPath(): string{
+    let query: string =
+      `subscriberId=${this.route.snapshot.queryParams['subscriberId']}&` +
+      `subscriberName=${this.route.snapshot.queryParams['subscriberName']}&` +
+      `serviceType=${this.route.snapshot.queryParams['serviceType']}&` +
+      `serviceInstanceId=${this.route.snapshot.queryParams['serviceInstanceId']}`;
+    return '../../serviceModels.htm#/instantiate?' + query;
+  }
+
+  deleteService(serviceModelId: string, isDeleted: boolean ) {
+    if(isDeleted){
+      this.store.dispatch(addServiceAction(serviceModelId, ServiceInstanceActions.Delete));
+      DrawingBoardTreeComponent.triggerDeleteActionService.next(serviceModelId);
+    } else{
+      this.store.dispatch(addServiceAction(serviceModelId, ServiceInstanceActions.None));
+      DrawingBoardTreeComponent.triggerUndoDeleteActionService.next(serviceModelId);
+    }
+  }
+
+  showAuditInfo(serviceModelId) : void {
+    let instance: ServiceInstance = this.store.getState().service.serviceInstance[serviceModelId];
+    let model =  new ServiceModel(this.store.getState().service.serviceHierarchy[serviceModelId]);
+    AuditInfoModalComponent.openInstanceAuditInfoModal.next({instanceId : serviceModelId , type : 'SERVICE', model : model , instance : instance, trackById: instance.trackById});
+  }
+
+
+  /*************************************************
+    should return true if deploy should be disabled
+   *************************************************/
+  deployShouldBeDisabled(serviceInstanceId: string, mode : string) : boolean {
+    const serviceInstance = this.store.getState().service.serviceInstance[serviceInstanceId];
+    if(!_.isNil(serviceInstance)){
+      const validationCounter = serviceInstance.validationCounter;
+      if (!_.isNil(this.errorMsgService.errorMsgObject)&& mode !== DrawingBoardModes.RETRY_EDIT) return true;
+      if(validationCounter > 0) return true;
+      if(serviceInstance.action !== ServiceInstanceActions.None) return false;
+      if(mode === DrawingBoardModes.RETRY_EDIT) return false;
+      return !serviceInstance.isDirty;
+    }
+    return true;
+  }
+
+  getModeButton(mode : string) : string {
+    switch (mode) {
+      case DrawingBoardModes.EDIT:
+        return 'UPDATE';
+      case DrawingBoardModes.RETRY_EDIT:
+        return 'REDEPLOY';
+      default: return 'DEPLOY';
+    }
+  }
+  getButtonText(mode : DrawingBoardModes) : string {
+    switch (mode) {
+      case DrawingBoardModes.EDIT:
+      case DrawingBoardModes.VIEW:
+        return 'EDIT';
+      case DrawingBoardModes.RETRY_EDIT:
+      case DrawingBoardModes.RETRY:
+        return 'REDEPLOY';
+    }
+  }
+
+  showEditService(mode: DrawingBoardModes, serviceModelId: string): boolean{
+    const serviceInstance = this.store.getState().service.serviceInstance;
+    return mode === DrawingBoardModes.CREATE || ((mode === DrawingBoardModes.RETRY_EDIT || mode === DrawingBoardModes.EDIT)&&
+      !_.isNil(serviceInstance) && !_.isNil(serviceInstance[serviceModelId])&& serviceInstance[serviceModelId].action === ServiceInstanceActions.Create);
+  }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/tmp_instansiate_request.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/tmp_instansiate_request.ts
new file mode 100644
index 0000000..d57e020
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/drawing-board-header/tmp_instansiate_request.ts
@@ -0,0 +1,52 @@
+export default
+  {
+    "modelInfo": {
+      "modelType": "service",
+      "modelInvariantId": "5d48acb5-097d-4982-aeb2-f4a3bd87d31b",
+      "modelVersionId": "3c40d244-808e-42ca-b09a-256d83d19d0a",
+      "modelName": "MOW AVPN vMX BV vPE 1 Service",
+      "modelVersion": "10.0"
+    },
+    "owningEntityId": "038d99af-0427-42c2-9d15-971b99b9b489",
+    "owningEntityName": "JULIO ERICKSON",
+    "projectName": "{some project name}",
+    "globalSubscriberId": "{some subscriber id}",
+    "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+    "instanceName": "vPE_Service",
+    "subscriptionServiceType": "VMX",
+    "lcpCloudRegionId": "mdt1",
+    "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+    "vnfs": [
+      {
+        "modelInfo": {
+          "modelName": "2016-73_MOW-AVPN-vPE-BV-L",
+          "modelVersionId": "7f40c192-f63c-463e-ba94-286933b895f8",
+          "modelCustomizationName": "2016-73_MOW-AVPN-vPE-BV-L 0",
+          "modelCustomizationId": "ab153b6e-c364-44c0-bef6-1f2982117f04"
+        },
+        "lcpCloudRegionId": "mdt1",
+        "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+        "platformName": "test",
+        "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+        "instanceName": "vmxnjr001",
+        "instanceParams": [],
+        "vfModules": [
+          {
+            "modelInfo": {
+              "modelType": "vfModule",
+              "modelName": "201673MowAvpnVpeBvL..AVPN_base_vPE_BV..module-0",
+              "modelVersionId": "4c75f813-fa91-45a4-89d0-790ff5f1ae79",
+              "modelCustomizationId": "a25e8e8c-58b8-4eec-810c-97dcc1f5cb7f"
+            },
+            "instanceName": "vmxnjr001_AVPN_base_vPE_BV_base_001",
+            "instanceParams": [
+              {
+                "vmx_int_net_len": "24"
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  }
+