New Angular UI from 1806

Change-Id: I39c160db0e0a6ec2e587ccf007ee1b23c6a08666
Issue-ID: VID-208
Signed-off-by: Sonsino, Ofir (os0695) <os0695@intl.att.com>
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
new file mode 100644
index 0000000..921c923
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {DynamicInput, DynamicMultiSelect, DynamicNumber, DynamicSelect} from "../../shared/models/dynamicInput";
+
+@Component({
+  selector: 'dynamic-inputs',
+  templateUrl: './dynamic-inputs.html',
+  styleUrls: ['./dynamic-inputs.scss']
+})
+
+export class DynamicInputsComponent implements OnInit{
+  @Input() public list:any[] = [];
+  @Input() public group: FormGroup;
+
+  private dynamicList:DynamicInput<any>[] = [];
+
+  isDynamicNumber(item: any): item is DynamicNumber {
+    return item;
+  }
+
+  buildValidators(item: DynamicInput<any>) {
+    let validatorArr = [];
+    item.maxLength && validatorArr.push(Validators.maxLength(item.maxLength));
+    item.minLength && validatorArr.push(Validators.minLength(item.minLength));
+    if(this.isDynamicNumber(item)) {
+      item.max && validatorArr.push(Validators.max(item.max));
+      item.min && validatorArr.push(Validators.min(item.min));
+    }
+    return Validators.compose(validatorArr);
+  }
+
+  ngOnInit(): void {
+    this.list.forEach((item)=> {
+      let dynamicItem: DynamicInput<any>;
+      switch (item.type) {
+        case 'multi_select':
+          item.optionList.forEach(function(option) { option.id = option.id||option.name;
+          option.itemName = option.name;});
+          item.settings = {
+            disabled: !item.isEnabled,
+            text: item.prompt,
+          };
+          dynamicItem = new DynamicMultiSelect(item);
+          break;
+        case 'select':
+          let defaultValue:any = item.optionList.find((option) => option.isDataLoading && option.name);
+          item.value = defaultValue && defaultValue.id;
+          dynamicItem = new DynamicSelect(item);
+          break;
+        case 'boolean':
+          item.value = item.value || false;
+          item.optionList = [{name: true, isPermitted: true, isDataLoading: item.value}, {name: false, isPermitted: true, isDataLoading: !item.value}];
+
+          dynamicItem = new DynamicSelect(item);
+          break;
+        case 'number':
+          dynamicItem = new DynamicNumber(item);
+          break;
+        case 'file':
+          dynamicItem = new DynamicInput<any>(item);
+          break;
+        case 'checkbox':
+          dynamicItem = new DynamicInput<boolean>(item);
+          break;
+        case 'map':
+          item.prompt = "{<key1>: <value1>,\.\.\.,<keyN>: <valueN>}";
+          dynamicItem = new DynamicInput<string>(item);
+          break;
+        case 'list':
+          item.prompt = "[<value1>,...,<valueN>]";
+          dynamicItem = new DynamicInput<string>(item);
+          break;
+        default: dynamicItem = new DynamicInput<string>(item);
+      }
+      this.dynamicList.push(dynamicItem);
+      this.group.addControl(dynamicItem.name, new FormControl({value: dynamicItem.value, disabled: !dynamicItem.isEnabled}, this.buildValidators(dynamicItem)));
+    })
+  }
+
+}
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
new file mode 100644
index 0000000..a933364
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
@@ -0,0 +1,22 @@
+<div *ngFor="let item of dynamicList">
+  <div id="{{item.id}}" class="details-item" [ngSwitch]="item.type" [formGroup]="group" [hidden]="!item.isVisible">
+    <label>{{item.name | dynamicInputLabel }}</label>
+    <select *ngSwitchCase="item.type === 'select'|| item.type === 'boolean'? item.type: ''" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" title="{{item.description}}" [required]="item.isRequired && item.isVisible"  maxlength="{{item.maxLength}}" minlength="{{item.minLength}}">
+      <option value="null" [selected]="item.value == null || item.value == undefined" hidden disabled>{{item.prompt}}</option>
+      <option *ngFor="let option of item.optionList" [ngValue]="option.id || option.name" [disabled]="!option.isPermitted" [selected]="option.isDataLoading">{{option.name}}</option>
+    </select>
+    <angular2-multiselect *ngSwitchCase="'multi_select'" [formControlName]="item.name" [(ngModel)]="item.selectedItems" [data]="item.optionList" [settings]="item.settings" title="{{item.description}}" [required]="item.isRequired && item.isVisible"></angular2-multiselect>
+    <input *ngSwitchCase="'number'"  name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="number" placeholder="{{item.prompt}}" title="{{item.description}}" min="{{item.min}}" max="{{item.max}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+    <div *ngSwitchCase="'file'">
+
+      <label class="dynamicFileName" for="dynamicFileInput-{{item.name}}">
+        <input id="dynamicFileInput-{{item.name}}"  name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="file" placeholder="{{item.prompt}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+        <label for="dynamicFileInput-{{item.name}}" class="labelForImage">
+          <span class="icon-browse"></span>
+        </label>
+      </label>
+    </div>
+    <input *ngSwitchCase="'checkbox'"  name="{{item.name}}" [formControlName]="item.name" type="checkbox"  data-toggle="toggle" title="{{item.description}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+    <input *ngSwitchDefault name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" placeholder="{{item.prompt}}" title="{{item.description}}" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible"/>
+  </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
new file mode 100644
index 0000000..11a1414
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
@@ -0,0 +1,58 @@
+input[type=file] {
+  opacity: 0;
+  position: relative;
+  z-index: 1;
+  width: 0.5px;
+  height: 0.5px;
+  display: inline-block;
+  input {
+    display: none;
+  }
+}
+
+.dynamicFileName {
+  width: 100%;
+  height: 34px;
+  background: #FFFFFF;
+  border: 1px solid #D2D2D2;
+  border-radius: 2px;
+  display: inline-block;
+  line-height: 34px;
+  font-weight: normal !important;
+  padding-left: 3px;
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+
+.labelForImage {
+  background: #F2F2F2;
+  border-left: 1px solid #D2D2D2;
+  float: right;
+  height: 32px;
+}
+
+.icon-browse:before {
+  content: "\e90d";
+  color: #5A5A5A;
+  font-size: 15px;
+  cursor: pointer;
+  width: 34px;
+  height: 100%;
+  line-height: 34px;
+  text-align: center;
+  display: inline-block;
+  vertical-align: super;
+  border-radius: 2px;
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+
+.icon-browse:hover::before {
+  background-color: #E6F6FB;
+  color: #009FDB;
+}
+
+.icon-browse:active::before {
+  background-color: #E6F6FB;
+  color: #009FDB;
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.component.ts b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
new file mode 100644
index 0000000..e71c444
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import { NgRedux, select } from '@angular-redux/store';
+import { Observable } from "rxjs/Observable";
+import { updateProductFamilies } from "../../service.actions";
+import { AppState } from "../../store/reducers";
+import {
+  loadProductFamiliesAction, loadLcpTenant, loadAicZones,
+  loadCategoryParameters
+} from '../../services/aaiService/aai.actions';
+import { LcpRegionsAndTenants } from "../../shared/models/lcpRegionsAndTenants";
+import {NgForm} from "@angular/forms";
+import {SelectOption} from "../../shared/models/selectOption";
+import {VNFModel} from "../../shared/models/vnfModel";
+
+@Component({
+  selector: "formasync",
+  templateUrl: "form-async.template.html",
+  styleUrls: ["form-async.style.scss"],
+
+})
+
+export class formasync implements OnInit {
+
+  constructor(private store: NgRedux<AppState>) { }
+
+  @ViewChild('form') form: NgForm;
+
+  @Input()
+  set model(model: VNFModel) {
+    if (model) {
+      this.isUserProvidedNaming = model.isUserProvidedNaming;
+    }
+  };
+
+  @select(['service', 'productFamilies'])
+  readonly productFamilies: Observable<any>;
+
+  @select(['service', 'lcpRegionsAndTenants'])
+  readonly lcpRegionsAndTenants: Observable<any>;
+
+  @select(['service', 'lcpRegionsAndTenants', 'lcpRegionList'])
+  readonly lcpRegions: Observable<any>;
+
+  @select(['service', 'aicZones'])
+  readonly aicZones: Observable<any>;
+
+  @select(['service', 'categoryParameters', 'platformList'])
+  readonly platformList: Observable<any>;
+
+  @select(['service', 'categoryParameters', 'lineOfBusinessList'])
+  readonly lineOfBusinessList: Observable<any>;
+
+  rollbackOnFailure = [
+    new SelectOption({id: 'true', name: 'Rollback'}),
+    new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+  ];
+  tenants = [];
+
+  serviceInstance: any = {
+    rollback:'true'
+  };
+
+  isUserProvidedNaming: boolean = false;
+
+  onLcpSelect(newValue: string) {
+    let value: LcpRegionsAndTenants = undefined;
+    this.lcpRegionsAndTenants.subscribe(data => value = data);
+    this.tenants = value.lcpRegionsTenantsMap[newValue];
+  }
+
+  ngOnInit() {
+    this.store.dispatch(loadProductFamiliesAction());
+    this.store.dispatch(loadLcpTenant());
+    this.store.dispatch(loadAicZones());
+    this.store.dispatch(loadCategoryParameters());
+  }
+}
+
+
+
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.style.scss b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
new file mode 100644
index 0000000..e6c89bc
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
@@ -0,0 +1,15 @@
+.form-wrapper{
+  width:640px;
+  padding-left: 50px;
+  padding-top: 50px;
+  .details-item{
+    padding-bottom: 30px;
+  }
+  .details-item {
+    select {
+      font-family: OpenSans-Italic;
+      font-size: 14px;
+      color: #959595 !important;
+    }
+  }
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.template.html b/vid-webpack-master/src/app/components/form-async/form-async.template.html
new file mode 100644
index 0000000..c63a7be
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.template.html
@@ -0,0 +1,67 @@
+<div class="content">
+  <form #form="ngForm" name="networkNodeForm" class="form-wrapper">
+    <div *ngIf="isUserProvidedNaming" class="details-item">
+      <label class="placeholder">Instance name*</label>
+      <input [attr.data-tests-id]="'instanceName'" id="instance-name" [(ngModel)]="serviceInstance.instanceName" name="instance-name"
+        class="form-control input-text" placeholder="Type Instance Name" type="text" required>
+    </div>
+
+    <div class="details-item">
+      <label>Product family</label>
+      <select class="form-control input-text" [(ngModel)]="serviceInstance.productFamily" data-tests-id="productFamily" id="product-family-select"
+        name="product-family-select">
+        <option class="placeholder" [value]="undefined" disabled>Select Product Family</option>
+        <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id" [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+      </select>
+    </div>
+
+    <div class="details-item">
+      <label>LCP region:*</label>
+      <select (change)="onLcpSelect($event.target.value)" class="form-control input-text" [(ngModel)]="serviceInstance.lcpRegion"
+        name="lcpRegion" id="lcpRegion-select" data-tests-id="lcpRegion" required>
+        <option class="placeholder1" [value]="undefined" disabled>Select LCP Region</option>
+        <option *ngFor="let lcpRegion of lcpRegions | async" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+      </select>
+    </div>
+    <div class="details-item">
+      <label>Tenant:*</label>
+      <select class="form-control input-text" [(ngModel)]="serviceInstance.tenantId" name="tenant" id="tenant-select" data-tests-id="tenant"
+        required>
+        <option class="placeholder1" [value]="undefined" disabled>Select Tenant</option>
+        <option *ngFor="let tenant of tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+      </select>
+    </div>
+
+    <div class="details-item">
+      <label>AIC Zone:</label>
+      <select class="form-control input-text" name="aicZone" id="aicZone-select" data-tests-id="aic_zone" [(ngModel)]="serviceInstance.aicZone">
+        <option class="placeholder1" [value]="undefined" disabled>Select AIC Zone</option>
+        <option class="aicZoneOption" *ngFor="let aicZone of aicZones | async" [value]="aicZone.id">{{aicZone.name}}</option>
+      </select>
+    </div>
+    <div class="details-item">
+      <label>Platform:</label>
+      <select data-tests-id="platform" class="form-control input-text" name="platform" id="platform" [(ngModel)]="serviceInstance.platformName">
+        <option class="placeholder1" [value]="undefined" disabled>Select Platform</option>
+        <option *ngFor="let platform of platformList | async" [value]="platform.id">{{platform.name}}</option>
+      </select>
+    </div>
+
+    <div class="details-item">
+      <label>Line Of Business:*</label>
+      <select data-tests-id="lineOfBusiness" class="form-control input-text" [(ngModel)]="serviceInstance.lineOfBusiness"
+        name="owningEntity" id="owningEntity" required>
+        <option class="placeholder1" [value]="undefined" disabled>Select Line Of Business</option>
+        <option *ngFor="let lineOfBusiness of lineOfBusinessList | async" [value]="lineOfBusiness.id">{{lineOfBusiness.name}}</option>
+      </select>
+    </div>
+    <div class="details-item">
+      <label>Rollback On Failure:</label>
+      <select data-tests-id="suppressRollback" class="form-control input-text" name="rollbackOnFailure" id="rollbackOnFailure" [(ngModel)]="serviceInstance.rollback">
+        <option *ngFor="let option of rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+      </select>
+    </div>
+  </form>
+
+</div>
+
diff --git a/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
new file mode 100644
index 0000000..b8ce613
--- /dev/null
+++ b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
@@ -0,0 +1,9 @@
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+
+
+export interface InstancePopup {
+  onCancelClick():void;
+  createModelInformationItems(): Array<ModelInformationItem>;
+  getModelName():string;
+}
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
new file mode 100644
index 0000000..b6a2e39
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
@@ -0,0 +1,238 @@
+import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {ServicePopupDataModel} from './servicePopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import {updateServiceInstance} from "../../../service.actions";
+import * as _ from 'lodash';
+import {ServiceModel} from "../../../shared/models/serviceModel";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {Observable} from "rxjs/Observable";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {isNullOrUndefined} from 'util';
+import {ServiceInstanceDetailsService} from './service-instance-details.service';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {DefaultDataGeneratorService} from '../../../shared/services/defaultDataServiceGenerator/default.data.generator.service';
+
+
+@Component({
+  selector: 'service-instance-details',
+  templateUrl: 'service-instance-details.html',
+  styleUrls: ['service-instance-details.scss'],
+  providers: [AaiService]
+})
+
+export class ServiceInstanceDetailsComponent implements OnInit, OnChanges {
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes["serviceInstance"] !== undefined && changes["serviceInstance"].currentValue !== changes["serviceInstance"].previousValue && changes["serviceInstance"].currentValue !== null) {
+      this.oldServiceInstance = Object.assign({}, this.serviceInstance);
+    }
+  }
+  _serviceModel: ServiceModel;
+  @Input () serviceInstance: any;
+  @Input () dynamicInputs;
+  @Input () servicesQty: number;
+  @Input ()
+  set serviceModel(serviceModel: ServiceModel) {
+    this._serviceModel = serviceModel;
+    this.updateFormGroupControlsWithServiceModel(serviceModel);
+  }
+  @ViewChild('serviceForm') serviceForm: 'ServiceForm';
+  @Output() closePopup : EventEmitter<any> = new EventEmitter<any>();
+  @Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+  oldServiceInstance = {};
+
+  //todo: implement Epics and use @select to fetch the rest of the form's data as done with productFamilies.
+  //that way we can loose the updateFormData function and the subscription to store in the constructor.
+  @select(['service','productFamilies'])
+  readonly productFamilies : Observable<SelectOptionInterface[]>;
+  serviceDetails:any = {
+
+  };
+  servicePopupDataModel: ServicePopupDataModel = new ServicePopupDataModel();
+  serviceInstanceDetailsFormGroup: FormGroup;
+  serviceInstanceDetailsService : ServiceInstanceDetailsService;
+
+  constructor(private _aaiService: AaiService, private store: NgRedux<AppState>, private _serviceInstanceDetailsService : ServiceInstanceDetailsService, private _defaultDataGeneratorService : DefaultDataGeneratorService) {
+    this.store.subscribe(() => {this.updateFormData()});
+    this.serviceInstanceDetailsService = this._serviceInstanceDetailsService;
+    this.serviceInstanceDetailsFormGroup = this.createFormGroup();
+
+    this.serviceInstanceDetailsFormGroup.valueChanges.subscribe(()=> {
+      this.onDataChanged.next();
+    })
+  }
+
+  ngOnInit() {
+    this.subscribeToFormChanges();
+    this._aaiService.getSubscribers().subscribe();
+    this._aaiService.getCategoryParameters(null).subscribe();
+    this._aaiService.getAicZones().subscribe();
+    this.store.dispatch(loadProductFamiliesAction());
+  }
+
+
+  createFormGroup(): FormGroup {
+    const formGroup = new FormGroup({
+      globalSubscriberId: new FormControl(
+        Validators.compose([Validators.required])
+      ),
+      productFamilyId: new FormControl(),
+      subscriptionServiceType: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      lcpCloudRegionId: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      tenantId: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      aicZoneId: new FormControl(),
+      projectName: new FormControl(),
+      owningEntityId: new FormControl(Validators.compose([Validators.required])),
+      rollbackOnFailure: new FormControl(null, Validators.required),
+    });
+
+    return formGroup;
+  }
+
+  updateFormGroupControlsWithServiceModel(serviceModel: ServiceModel) {
+    this.serviceInstanceDetailsFormGroup.markAsUntouched();
+
+    if (serviceModel) {
+      this.serviceDetails.isUserProvidedNaming = serviceModel.isUserProvidedNaming;
+      if (serviceModel.isUserProvidedNaming) {
+        this.serviceInstanceDetailsFormGroup.addControl('instanceName', new FormControl('', Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+      }else{
+        this.serviceInstanceDetailsFormGroup.removeControl('instanceName');
+      }
+
+      if (serviceModel.isMultiStepDesign) {
+        this.serviceInstanceDetailsFormGroup.addControl('pause', new FormControl(true));
+      }else{
+        this.serviceInstanceDetailsFormGroup.removeControl('pause');
+      }
+    }
+  }
+
+  updateFormData() {
+    let service = this.store.getState().service;
+    this.servicePopupDataModel.subscribers = service.subscribers;
+    this.servicePopupDataModel.serviceTypes = service.serviceTypes[this.servicePopupDataModel.globalCustomerId];
+    this.servicePopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+    if (this.serviceInstance) {
+      this.servicePopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.serviceInstance.lcpCloudRegionId];
+    }
+    this.servicePopupDataModel.aicZones = service.aicZones;
+    this.servicePopupDataModel.owningEntities = _.get(service.categoryParameters, 'owningEntityList');
+    this.servicePopupDataModel.projects = _.get(service.categoryParameters, 'projectList');
+    this.onDataChanged.next();
+  }
+
+  subscribeToFormChanges(): void {
+    this.serviceInstanceDetailsFormGroup.get('globalSubscriberId').valueChanges.subscribe(val => {
+      this.updateServiceTypes(val);
+      this.setDisabledState(val, 'subscriptionServiceType');
+
+    });
+    this.serviceInstanceDetailsFormGroup.get('subscriptionServiceType').valueChanges.subscribe(val => {
+      this.getTenants(val);
+      this.setDisabledState(val, 'lcpCloudRegionId');
+
+    });
+    this.serviceInstanceDetailsFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+      this.setDisabledState(val, 'tenantId');
+      this.updateTenantList(val);
+
+    });
+
+    this.serviceInstanceDetailsFormGroup.get('tenantId').valueChanges.subscribe(val => {
+      this.serviceDetails.tenantName = this.getNameFromListById(this.servicePopupDataModel.tenants, val);
+      this.onDataChanged.next();
+    });
+
+    this.serviceInstanceDetailsFormGroup.get('aicZoneId').valueChanges.subscribe(val => {
+      this.serviceDetails.aicZoneName = this.getNameFromListById(this.servicePopupDataModel.aicZones, val);
+      this.onDataChanged.next();
+    });
+  }
+
+  getNameFromListById(list, id:string ) {
+    if(list && id) {
+      let filterItem = list.filter(item => {
+        return item.id == id;
+      })
+      return filterItem && filterItem[0].name;
+    }
+    return null;
+  }
+
+  setDisabledState(val, field: string): void {
+    if(val) {
+      this.serviceInstanceDetailsFormGroup.controls[field].enable();
+    } else {
+      this.serviceInstanceDetailsFormGroup.controls[field].disable();
+    }
+  }
+
+  isShowingNotificationArea(): boolean {
+    return this.servicesQty > 1;
+  }
+
+  updateServiceTypes(subscriberId) {
+    if (subscriberId) {
+      this.servicePopupDataModel.globalCustomerId = subscriberId;
+      this._aaiService.getServiceTypes(subscriberId).subscribe(() => {
+        this.updateFormData();
+        this.onDataChanged.next();
+      }, (error) => {
+
+      });
+    }
+  }
+
+  updateTenantList(cloudRegionId) {
+    this.servicePopupDataModel.tenants = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+    this.onDataChanged.next();
+  }
+
+  getTenants(serviceType) {
+    if (serviceType) {
+      this._aaiService.getLcpRegionsAndTenants(this.servicePopupDataModel.globalCustomerId, serviceType).subscribe(()=>{
+        this.onDataChanged.next();
+      });
+    }
+  }
+
+  onSubmit(formValues): void {
+    formValues.bulkSize = this.servicesQty;
+    let dynamicFields: { [dynamicField: string] : string; };
+    dynamicFields = {};
+    this.dynamicInputs.map(function (x) {
+      let dynamicField: string = x.id;
+      dynamicFields[dynamicField] = formValues[dynamicField];
+      delete formValues[dynamicField];
+    });
+    formValues.instanceParams = [];
+    formValues.instanceParams.push(dynamicFields);
+    formValues.modelInfo = new ModelInfo(this._serviceModel);
+    Object.assign(formValues, this.serviceDetails);
+    this.store.dispatch(updateServiceInstance(formValues, this._serviceModel.uuid));
+    if (this.store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD']){
+      this._defaultDataGeneratorService.updateReduxOnFirstSet(this._serviceModel.uuid,formValues);
+    }
+    window.parent.postMessage( {
+      eventId: 'submitIframe',
+      data: {
+        serviceModelId: this._serviceModel.uuid
+      }
+    }, "*");
+    this.closePopup.emit(this._serviceModel.uuid);
+  }
+
+  hasApiError(controlName : string, data : Array<any>){
+    if(!isNullOrUndefined(this.servicePopupDataModel) && !isNullOrUndefined(data)){
+      if(!this.serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0){
+          return true;
+      }
+    }
+    return false;
+  }
+
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
new file mode 100644
index 0000000..3d632bd
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
@@ -0,0 +1,168 @@
+
+<div id="service-instance-details">
+  <form id="serviceForm" #serviceForm="ngForm" (ngSubmit)="onSubmit(serviceForm.value)" [formGroup]="serviceInstanceDetailsFormGroup">
+    <!--We can't use [hidden] since bootstrap.css label has display: inline-block. -->
+    <!--see https://stackoverflow.com/questions/34650410/angular-2-hidden-does-not-seem-to-be-working-->
+    <label id="notification-area" *ngIf="isShowingNotificationArea()">Data entered will apply to all service instances</label>
+
+    <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('instanceName')">
+      <label class="required">Instance name:</label>
+      <input patternInput
+             pattern="^[a-zA-Z0-9_]*$"
+             [attr.data-tests-id]="'instanceName'"
+             id="instance-name"
+             name="instance-name"
+             [ngClass]="{'error-style' :(serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null)}"
+             [formControlName]="'instanceName'"
+             class="form-control input-text"
+             placeholder="Type Instance Name"
+             type="text"
+             [(ngModel)]="serviceInstance.instanceName" required>
+      <form-control-error
+        *ngIf="serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null"
+        [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+
+    </div>
+
+    <div class="details-item">
+      <label class="required">Subscriber name:</label>
+      <select class="subscriber form-control input-text" id="subscriber-name-select" data-tests-id="subscriberName"
+              name="subscriber-name-select" [formControlName]="'globalSubscriberId'"
+              [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)}"
+              [(ngModel)]="serviceInstance.globalSubscriberId"
+              required>
+        <option [value]="undefined" disabled>Select Subscriber Name</option>
+        <option class="subscriberNameOption" *ngFor="let subscriber of servicePopupDataModel.subscribers"
+                [value]="subscriber.id" [disabled]="!subscriber.isPermitted">{{subscriber.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+    </div>
+
+    <div class="details-item">
+      <label class="required">Service type:</label>
+      <select class="form-control input-text"
+              [(ngModel)]="serviceInstance.subscriptionServiceType"
+              [formControlName]="'subscriptionServiceType'"
+              [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)}"
+              data-tests-id="serviceType" id="service-type-select"
+              name="service-type" required>
+        <option [value]="undefined" disabled>Select Service Type</option>
+        <option *ngFor="let serviceType of servicePopupDataModel.serviceTypes" class="serviceTypeOption" [value]="serviceType.name" [disabled]="!serviceType.isPermitted">{{serviceType.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div class="details-item">
+      <label class="required">Product family:</label>
+      <select class="form-control input-text"
+              data-tests-id="productFamily"
+              id="product-family-select"
+              [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)}"
+              [formControlName]="'productFamilyId'"
+              [(ngModel)]="serviceInstance.productFamilyId"
+              name="product-family-select" required>
+        <option [value]="undefined" disabled>Select Product Family</option>
+        <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+                [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div class="details-item">
+      <label class="required">LCP region:</label>
+      <select
+        class="form-control input-text"
+        [formControlName]="'lcpCloudRegionId'"
+        [(ngModel)]="serviceInstance.lcpCloudRegionId"
+        [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)}"
+        name="lcpRegion"
+        id="lcpRegion-select"
+        data-tests-id="lcpRegion"
+        required>
+        <option [value]="undefined" disabled>Select LCP Region</option>
+        <option *ngFor="let lcpRegion of servicePopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div class="details-item">
+      <label class="required">Tenant:</label>
+      <select class="form-control input-text"
+              [formControlName]="'tenantId'"
+              [(ngModel)]="serviceInstance.tenantId"
+              name="tenant" id="tenant-select"
+              [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)}"
+              data-tests-id="tenant" required>
+        <option [value]="undefined" disabled>Select Tenant</option>
+        <option *ngFor="let tenant of servicePopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div class="details-item">
+      <label>AIC Zone:</label>
+      <select
+        class="form-control input-text"
+        name="aicZone" id="aicZone-select"
+        data-tests-id="aic_zone"
+        [formControlName]="'aicZoneId'"
+        [ngClass]="{'error-style ' : servicePopupDataModel?.aicZones?.length == 0 && serviceInstanceDetailsFormGroup.controls['aicZoneId'].disabled == false}"
+        [(ngModel)]="serviceInstance.aicZoneId" >
+        <option [value]="undefined" disabled>Select AIC Zone</option>
+        <option class="aicZoneOption" *ngFor="let aicZone of servicePopupDataModel.aicZones" [value]="aicZone.id">{{aicZone.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('aicZoneId',servicePopupDataModel?.aicZones ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+    </div>
+
+    <div class="details-item">
+      <label>Project:</label>
+      <select
+        [attr.data-tests-id]="'project'"
+        class="form-control input-text"
+        [ngClass]="{'error-style ' : servicePopupDataModel?.projects?.length == 0 && serviceInstanceDetailsFormGroup.controls['projectName'].disabled == false}"
+        name="project" id="project"
+        [formControlName]="'projectName'"
+        [(ngModel)]="serviceInstance.projectName" >
+        <option [value]="undefined" disabled>Select Project</option>
+        <option *ngFor="let project of servicePopupDataModel.projects" [value]="project.id">{{project.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('projectName',servicePopupDataModel?.projects ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+    </div>
+
+    <div class="details-item">
+      <label class="required">Owning entity:</label>
+      <select [attr.data-tests-id]="'owningEntity'"
+              class="form-control input-text"
+              [formControlName]="'owningEntityId'"
+              [(ngModel)]="serviceInstance.owningEntityId"
+              name="owningEntity" id="owningEntity"
+              [ngClass]="{'error-style ' : servicePopupDataModel?.owningEntities?.length == 0 && serviceInstanceDetailsFormGroup.controls['owningEntityId'].disabled == false}"
+              required>
+        <option [value]="undefined" disabled>Select Owning Entity</option>
+        <option *ngFor="let owningEntity of servicePopupDataModel.owningEntities" [value]="owningEntity.id">{{owningEntity.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('owningEntityId',servicePopupDataModel?.owningEntities ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+    <div class="details-item">
+      <label class="required">Rollback On Failure:</label>
+      <select [attr.data-tests-id]="'rollback'"
+              [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)}"
+              class="form-control input-text"
+              [(ngModel)]="serviceInstance.rollbackOnFailure"
+              [formControlName]="'rollbackOnFailure'" name="rollbackOnFailure" id="rollbackOnFailure">
+        <option *ngFor="let option of servicePopupDataModel.rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+      </select>
+      <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+    <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('pause')">
+      <input  #pause id="pause" [formControlName]="'pause'" [(ngModel)]="serviceInstance.pause" type="checkbox" name="pause" data-toggle="toggle">
+      <label class="checkbox-label" for="pause">Pause on pause points:</label>
+    </div>
+
+
+    <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="serviceInstanceDetailsFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+  </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
new file mode 100644
index 0000000..928343d
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
@@ -0,0 +1,64 @@
+#service-instance-details {
+  position: relative;
+
+  #notification-area {
+    color: #959595;
+    font-size: 12px;
+    position: absolute;
+    top: 3px;
+    left: 30px;
+  }
+
+  height: 100%;
+  overflow: auto;
+  padding: 30px;
+
+  /deep/ {
+    .form-control {
+      border-radius: 2px;
+      box-shadow: none;
+      border-color: #D2D2D2;
+    }
+
+    label {
+      font-family: OpenSans-Semibold;
+      font-size: 12px;
+    }
+
+    select {
+      @extend .form-control;
+      -webkit-appearance: none;
+      -moz-appearance: none;
+      appearance: none;
+      background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+      background-size: 24px;
+      background-position-x: right;
+      background-position-y: center;
+      font-family: OpenSans-Italic;
+      font-size: 14px;
+      color: #959595;
+      height: 38px;
+    }
+
+    input:not([type='checkbox']) {
+      @extend .form-control;
+      height: 38px;
+    }
+
+    .form-control[disabled], fieldset[disabled] .form-control {
+      opacity: 0.5;
+    }
+    .input-text {
+      border: 1px solid #D2D2D2;
+      border-radius: 2px;
+    }
+
+    .details-item {
+      margin-bottom: 20px;
+    }
+  }
+
+    .checkbox-label {
+      font-family: OpenSans-Regular;
+    }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
new file mode 100644
index 0000000..605653b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
@@ -0,0 +1,26 @@
+import { getTestBed, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { ServiceInstanceDetailsService } from './service-instance-details.service';
+import { NgRedux } from '@angular-redux/store';
+
+export class MockAppStore<T> {}
+
+describe('Service instance details service', () => {
+  let injector;
+  let service: ServiceInstanceDetailsService;
+  let httpMock: HttpTestingController;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [HttpClientTestingModule],
+      providers: [ServiceInstanceDetailsService,
+        {provide: NgRedux, useClass: MockAppStore}]
+    });
+
+    injector = getTestBed();
+    service = injector.get(ServiceInstanceDetailsService);
+    httpMock = injector.get(HttpTestingController);
+  });
+});
+
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
new file mode 100644
index 0000000..99b390d
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from 'util';
+import { FormGroup } from '@angular/forms';
+import * as _ from 'lodash';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import { NgRedux } from '@angular-redux/store';
+import { AppState } from '../../../store/reducers';
+
+@Injectable()
+export class ServiceInstanceDetailsService {
+  static controlsFieldsStatus = {};
+
+  constructor(private store: NgRedux<AppState>) { }
+  hasApiError(controlName: string, data: Array<any>, serviceInstanceDetailsFormGroup: FormGroup) {
+    if (!isNullOrUndefined(data)) {
+      if (!serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0) {
+          return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
new file mode 100644
index 0000000..c7894e2
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
@@ -0,0 +1,32 @@
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class ServicePopupDataModel {
+  subscribers: SelectOptionInterface[];
+  serviceTypes: SelectOptionInterface[];
+  aicZones: SelectOptionInterface[];
+  lcpRegions: SelectOptionInterface[];
+  productFamilies: SelectOptionInterface[];
+  lcpRegionsTenantsMap: object;
+  tenants: SelectOptionInterface[];
+  projects: SelectOptionInterface[];
+  owningEntities: SelectOptionInterface[];
+  globalCustomerId: string;
+  rollbackOnFailure: SelectOptionInterface[];
+
+
+  constructor(){
+    this.subscribers = null;
+    this.serviceTypes = null;
+    this.aicZones = null;
+    this.lcpRegions = null;
+    this.lcpRegionsTenantsMap = {};
+    this.tenants = null;
+    this.productFamilies = null;
+    this.projects = null;
+    this.owningEntities = null;
+    this.rollbackOnFailure = [
+      new SelectOption({id: 'true', name: 'Rollback'}),
+      new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+    ];
+  }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
new file mode 100644
index 0000000..908ae4a
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
@@ -0,0 +1,144 @@
+import {Component, ViewChild} from '@angular/core';
+import {DialogComponent, DialogService} from 'ng2-bootstrap-modal';
+import {ServiceModel} from '../../shared/models/serviceModel';
+import {Constants} from '../../shared/utils/constants';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {ActivatedRoute} from "@angular/router";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {Utils} from "../../utils/utils";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import * as _ from 'lodash';
+import {ModelInformationItem} from '../../shared/components/model-information/model-information.component';
+import {deleteServiceInstance} from '../../service.actions';
+
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ServicePopupService} from './service-popup.service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface ServicePopupModel {
+  serviceModel: ServiceModel
+}
+
+@Component({
+  selector: 'service-popup',
+  templateUrl: 'service-popup.html',
+  styleUrls: ['service-popup.scss'],
+  providers: [AaiService, ServicePopupService]
+})
+
+export class ServicePopupComponent extends DialogComponent<ServicePopupModel, boolean>
+                                    implements ServicePopupModel, InstancePopup{
+  @ViewChild(ServiceInstanceDetailsComponent) serviceInstanceDetails: ServiceInstanceDetailsComponent;
+
+  serviceModel: ServiceModel;
+  serviceModelId: string;
+  serviceInstance: any = {
+    'rollbackOnFailure' : 'false'
+  };
+  title: string = Constants.ServicePopup.TITLE;
+  dynamicInputs: any[] = null;
+
+  maxServiceQty:number = 50;
+  minServiceQty:number = 1;
+  servicesQty = 1; //default
+  quantityOptions = this.getQuantityOptions();
+
+  modelInformationItems: Array<ModelInformationItem> = [];
+  hasGeneralApiError : boolean = false;
+  parentElementClassName = 'content';
+
+  constructor(dialogService: DialogService, private route: ActivatedRoute, private _aaiService: AaiService,
+              private _iframeService : IframeService,
+              private _servicePlanningService: ServicePlanningService, private store: NgRedux<AppState>, private _servicePopupService : ServicePopupService) {
+    super(dialogService);
+    this.title = Constants.ServicePopup.TITLE;
+  }
+
+  updateGeneralErrorSection() : void {
+    this.hasGeneralApiError = this._servicePopupService.onControlError(this.serviceInstanceDetails, this.serviceInstanceDetails.serviceInstanceDetailsFormGroup);
+  }
+
+
+  ngOnInit() {
+    this.route
+      .queryParams
+      .subscribe(params => {
+        this.serviceModelId = params['serviceModelId'];
+        if(params['isCreate']=="true") {
+          this.store.dispatch(deleteServiceInstance(this.serviceModelId));
+        }
+        this.updateServiceModelById(this.serviceModelId);
+        this.updateInstanceFromStore();
+      });
+  }
+
+  updateInstanceFromStore() {
+    let serviceInstance;
+    if (_.has(this.store.getState().service.serviceInstance, this.serviceModelId)) {
+      serviceInstance = Object.assign({}, this.store.getState().service.serviceInstance[this.serviceModelId]);
+    }
+
+    this.serviceInstance = serviceInstance ? serviceInstance : this.serviceInstance;
+    this.servicesQty = serviceInstance ? serviceInstance.bulkSize : 1;
+    if (serviceInstance && serviceInstance.instanceParams && serviceInstance.instanceParams[0]) {
+      this.dynamicInputs = this.dynamicInputs.map(function (x) {
+        x.value = (serviceInstance.instanceParams[0][x.id]) ? serviceInstance.instanceParams[0][x.id] : x.value;
+        return x;
+      });
+    }
+  }
+
+  updateServiceModelById(serviceModelId) {
+    this._aaiService.getServiceModelById(serviceModelId).subscribe(
+      value => {
+        const convertedModel = Utils.convertModel(value);
+        this.serviceModel = new ServiceModel(convertedModel);
+        let displayInputs = Object.assign({},convertedModel.service.inputs);
+        this.dynamicInputs = _.isEmpty(displayInputs)? [] : this._servicePlanningService.getArbitraryInputs(displayInputs);
+        this.modelInformationItems = this.createModelInformationItems();
+      },
+      error => {console.log('error is ', error)},
+      () => {console.log('completed')}
+    );
+  }
+
+  createModelInformationItems() : Array<ModelInformationItem> {
+     return [
+      new ModelInformationItem("Model version", "modelVersion", [this.serviceModel.version], "", true),
+      new ModelInformationItem("Description", "description", [this.serviceModel.description]),
+      new ModelInformationItem("Category", "category", [this.serviceModel.category]),
+      new ModelInformationItem("UUID", "uuid", [this.serviceModel.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+      new ModelInformationItem("Invariant UUID", "invariantUuid", [this.serviceModel.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+      new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+      new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole])
+    ];
+  }
+
+  onCancelClick() {
+    this._iframeService.removeClassCloseModal(this.parentElementClassName);
+    this.dialogService.removeDialog(this);
+    this.serviceInstance = this.serviceInstanceDetails.oldServiceInstance;
+
+    this._servicePopupService.resetDynamicInputs(this.serviceInstanceDetails, this.dynamicInputs);
+    // Delaying the iframe close in few milliseconds.
+    // This should workaround a problem in Selenium tests' that
+    // blocks after click because the iframe goes out before
+    // the driver understands it was clicked. Similar bug is
+    // described here:
+    //  - https://github.com/mozilla/geckodriver/issues/611
+    //  - https://bugzilla.mozilla.org/show_bug.cgi?id=1223277
+    setTimeout(() => {
+      window.parent.postMessage("closeIframe", "*");
+    }, 15);
+  }
+
+  getModelName(): string {
+    return (this.serviceModel && this.serviceModel.name) || "";
+  }
+
+  getQuantityOptions(){
+    return _.range(this.minServiceQty, this.maxServiceQty + 1);
+  }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.html b/vid-webpack-master/src/app/components/service-popup/service-popup.html
new file mode 100644
index 0000000..e967daa
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.html
@@ -0,0 +1,52 @@
+<div id="service-popup" class="modal-dialog">
+  <div class="modal-content">
+    <div class="modal-header">
+      <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+      <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">{{title}}</span>
+    </div>
+    <div class="modal-body popup-content">
+
+      <div class="header-left">
+        <div>SERVICE MODEL: <span>"{{getModelName()}}"</span></div>
+      </div>
+
+      <div class="header-right">
+        Service Instance Details
+      </div>
+
+      <label class="quantity-label">Qty:</label>
+      <div class="quantity">
+        <select class="quantity-select" [(ngModel)]="servicesQty" name="quantity" id="quantity-select" required>
+          <option *ngFor="let qty of quantityOptions" [value]="qty">{{qty}}</option>
+        </select>
+      </div>
+
+      <div class="service-model">
+
+        <model-information [modelInformationItems]="modelInformationItems"></model-information>
+      </div>
+
+      <div class="service-instance">
+        <service-instance-details [dynamicInputs]="dynamicInputs"
+                                  [serviceInstance]="serviceInstance"
+                                  [serviceModel]="serviceModel"
+                                  [servicesQty]="servicesQty"
+                                  (onDataChanged)="updateGeneralErrorSection()"
+                                  (closePopup)="onCancelClick($event)"></service-instance-details>
+      </div>
+
+    </div>
+    <div class="modal-footer row" style="padding: 0">
+      <div class="col-md-6">
+        <div *ngIf="hasGeneralApiError == true">
+          <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+        </div>
+      </div>
+      <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+        <button [attr.data-tests-id]="'cancelButton'"  type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+        <input type="submit" value="Set" form="serviceForm"  data-tests-id="service-form-set"
+               class="btn btn-success submit" [disabled]="!serviceInstanceDetails?.serviceForm?.valid">
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.scss b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
new file mode 100644
index 0000000..aa4552d
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#service-popup {
+  color: #191919;
+
+  .left-panel {
+    background: #f2f2f2;
+    border-right: $grid-border;
+  }
+
+  .header-common {
+    height: 100%;
+    align-items: center;
+    display: flex;
+    font-family: OpenSans-Semibold;
+    font-size: 12px;
+  }
+
+  .header-text {
+    padding-left: 30px;
+    @extend .header-common;
+  }
+
+  .header-left {
+    grid-area: header-left;
+    @extend .header-text;
+    @extend .left-panel;
+    border-bottom: $grid-border;
+
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+    };
+  }
+
+  .header-right {
+    grid-area: header-right;
+
+    @extend .header-text;
+    border-bottom: $grid-border;
+  }
+
+  .quantity-label {
+    grid-area: quantity-label;
+    @extend .header-common;
+    border-bottom: $grid-border;
+    height: 100%;
+    font-family: OpenSans-Regular;
+  }
+
+  .quantity {
+    grid-area: quantity;
+    border-left: $grid-border;
+    border-bottom: $grid-border;
+    border-top-style: none;
+    font-family: OpenSans-Semibold;
+    text-align: start;
+    text-indent: 10px;
+  }
+
+  .quantity-select {
+    width: 78px;
+    height: 100%;
+    border: 0;
+    background: white;
+    outline: none;
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    appearance: none;
+    background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+    background-size: 24px;
+    background-position-x: right;
+    background-position-y: center;
+  }
+  input[type="number"]:hover::-webkit-inner-spin-button {
+    height: 20px;
+  }
+
+  .service-model {
+    grid-area: service-model;
+
+    padding: 30px;
+    overflow: auto;
+    @extend .left-panel;
+  }
+
+  .service-instance {
+    grid-area: service-instance;
+  }
+
+  .popup-content {
+    display: grid;
+    grid-template-columns: 400px auto 30px 93px;
+    grid-template-rows: 50px calc(100vh - 180px);
+    grid-template-areas:
+      "header-left header-right quantity-label quantity"
+      "service-model service-instance service-instance service-instance";
+    padding: 0;
+  }
+}
+
+.modal {
+  background-color: #191919;
+  opacity: 0.8;
+}
+
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 0;
+}
+@media (min-width: 1150px) {
+  .popup-content {
+    grid-template-rows: 30px 680px;
+  }
+}
+
+.modal-content {
+  border-radius: 0;
+  box-shadow: none;
+  border: none;
+}
+
+.modal-footer {
+  .cancel {
+    width: 120px;
+    height: 36px;
+    background: #ffffff;
+    border: 1px solid  #009fdb;
+    border-radius: 2px;
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+      color: #009fdb;
+      line-height: 16px;
+    }
+  }
+
+  .submit {
+    width: 120px;
+    height: 36px;
+    background: #009fdb;
+    border-radius: 2px;
+    border-color: #009fdb;
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+      color: #FFFFFF;
+      line-height: 16px;
+    }
+  }
+}
+
+.modal-header {
+  background-color: #009fdb;
+
+  padding-bottom: 13px;
+  padding-top: 13px;
+  padding-left: 29px;
+  padding-right: 21px;
+
+  .close {
+    font-size: 32px;
+    font-weight: 200;
+    color: #d8d8d8;
+    text-shadow: none;
+    filter: none;
+    opacity: 1;
+  }
+
+  .modal-title {
+    font-family: OpenSans-Regular;
+    font-size: 24px;
+    color: #fff;
+    line-height: 34px;
+  }
+}
+//
+//@media (min-width: 1200px) {
+//  .service-model,
+//  .service-instance {
+//    width: 1050px;
+//    margin: 30px auto;
+//  }
+//}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
new file mode 100644
index 0000000..cddc640
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
@@ -0,0 +1,138 @@
+
+import { TestBed, getTestBed} from '@angular/core/testing';
+import {
+  HttpClientTestingModule,
+  HttpTestingController
+} from '@angular/common/http/testing';
+import { ServicePopupService } from './service-popup.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Service Popup Service', () => {
+  let injector;
+  let service: ServicePopupService;
+  let httpMock: HttpTestingController;
+  let form : FormGroup;
+  let servicePopupDataModel;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [HttpClientTestingModule],
+      providers: [ServicePopupService]
+    });
+
+    injector = getTestBed();
+    service = injector.get(ServicePopupService);
+    httpMock = injector.get(HttpTestingController);
+
+    form  = generateFormGroup();
+    servicePopupDataModel =  generateServicePopupDataModel();
+  });
+
+  describe('#resetDynamicInputs', () => {
+    it('resetDynamicInputs should reset dymanic fields',(done: DoneFn) => {
+      const dynamicInputs = generateDynamicInputs();
+      let serviceForm = generateFormGroup();
+      serviceForm.addControl(dynamicInputs[0].name, new FormControl({value: dynamicInputs[0].value, disabled: false}));
+
+      serviceForm.controls[dynamicInputs[0].name].setValue("diffValue");
+      service.resetDynamicInputs({
+        serviceInstanceDetailsFormGroup : serviceForm,
+        dynamicInputs : dynamicInputs
+      }, dynamicInputs);
+
+      expect(serviceForm.controls[dynamicInputs[0].name].value).toEqual(dynamicInputs[0].value);
+      done();
+    })
+  });
+
+  describe('#onControlError', () => {
+
+    it('should return true if instanceName is illegal', (done: DoneFn) => {
+      form.controls['instanceName'].setValue("illegal - illegal");
+
+      let result : boolean = service.onControlError(<any>servicePopupDataModel, form);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('should return false if instanceName is legal', (done: DoneFn) => {
+
+      form.controls['instanceName'].setValue("legal");
+      let result  = service.onControlError(<any>servicePopupDataModel, form);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('should return false if lcpRegions is empty and is disabled', (done: DoneFn) => {
+      servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+      let result  = service.onControlError(<any>servicePopupDataModel, form);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('should return true if lcpRegions is empty', (done: DoneFn) => {
+      servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+      form.controls['lcpCloudRegionId'].enable();
+      let result  = service.onControlError(<any>servicePopupDataModel, form);
+      expect(result).toBeTruthy();
+      done()
+    });
+  });
+
+
+  function generateDynamicInputs(){
+    return JSON.parse('[{"id":"2017488_adiodvpe0_ASN","type":"string","name":"2017488_adiodvpe0_ASN","value":"AV_vPE","isRequired":true,"description":"AV/PE"}]');
+  }
+
+
+  function generateServicePopupDataModel() {
+    return {
+      "servicePopupDataModel" : JSON.parse('{"subscribers":[{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb","name":"Mobility","isPermitted":false},{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fc","name":"PACKET CORE","isPermitted":false},{"id":"e433710f-9217-458d-a79d-1c7aff376d89","name":"USP VOICE","isPermitted":true}],"serviceTypes":[{"id":"0","name":"vFlowLogic","isPermitted":false},{"id":"1","name":"VIRTUAL USP","isPermitted":true},{"id":"2","name":"Mobility","isPermitted":false},{"id":"3","name":"vBNG","isPermitted":false},{"id":"4","name":"vVoiceMail","isPermitted":false},{"id":"5","name":"Nimbus","isPermitted":false},{"id":"6","name":"vSEGW","isPermitted":false},{"id":"7","name":"vVM","isPermitted":false},{"id":"8","name":"vOTA","isPermitted":false},{"id":"9","name":"vMME","isPermitted":false},{"id":"10","name":"vMNS","isPermitted":false},{"id":"11","name":"vSCP","isPermitted":false},{"id":"12","name":"VPMS","isPermitted":false},{"id":"13","name":"vMMSC","isPermitted":false},{"id":"14","name":"SSD","isPermitted":false},{"id":"15","name":"vMOG","isPermitted":false},{"id":"16","name":"FIRSTNET","isPermitted":false},{"id":"17","name":"ACTIVE_CHARGE","isPermitted":false},{"id":"18","name":"vHSS","isPermitted":false}],"aicZones":[{"id":"NFT1","name":"NFTJSSSS-NFT1"},{"id":"JAG1","name":"YUDFJULP-JAG1"},{"id":"YYY1","name":"UUUAIAAI-YYY1"},{"id":"BAN1","name":"VSDKYUTP-BAN1"},{"id":"DKJ1","name":"DKJSJDKA-DKJ1"},{"id":"MCS1","name":"ASACMAMS-MCS1"},{"id":"UIO1","name":"uioclli1-UIO1"},{"id":"RAJ1","name":"YGBIJNLQ-RAJ1"},{"id":"OPA1","name":"opaclli1-OPA1"},{"id":"SDE1","name":"ZXCVBNMA-SDE1"},{"id":"VEN2","name":"FGHJUHIL-VEN2"},{"id":"ORL1","name":"ORLDFLMA-ORL1"},{"id":"JAD1","name":"JADECLLI-JAD1"},{"id":"ZXL1","name":"LWLWCANN-ZXL1"},{"id":"CKL1","name":"CLKSKCKK-CKL1"},{"id":"SDF1","name":"sdfclli1-SDF1"},{"id":"RAD1","name":"RADICAL1-RAD1"},{"id":"KIT1","name":"BHYJFGLN-KIT1"},{"id":"REL1","name":"INGERFGT-REL1"},{"id":"JNL1","name":"CJALSDAC-JNL1"},{"id":"OLK1","name":"OLKOLKLS-OLK1"},{"id":"CHI1","name":"CHILLIWE-CHI1"},{"id":"UUU4","name":"UUUAAAUU-UUU4"},{"id":"TUF1","name":"TUFCLLI1-TUF1"},{"id":"KJN1","name":"CKALDKSA-KJN1"},{"id":"SAM1","name":"SNDGCA64-SAN1"},{"id":"SCK1","name":"SCKSCKSK-SCK1"},{"id":"HJH1","name":"AOEEQQQD-HJH1"},{"id":"HGD1","name":"SDFQWHGD-HGD1"},{"id":"KOR1","name":"HYFLNBVT-KOR1"},{"id":"ATL43","name":"AICLOCID-ATL43"},{"id":"ATL54","name":"AICFTAAI-ATL54"},{"id":"ATL66","name":"CLLIAAII-ATL66"},{"id":"VEL1","name":"BNMLKUIK-VEL1"},{"id":"ICC1","name":"SANJITAT-ICC1"},{"id":"MNT11","name":"WSXEFBTH-MNT11"},{"id":"DEF2","name":"WSBHGTYL-DEF2"},{"id":"MAD11","name":"SDFQWGKL-MAD11"},{"id":"OLG1","name":"OLHOLHOL-OLG1"},{"id":"GAR1","name":"NGFVSJKO-GAR1"},{"id":"SAN22","name":"GNVLSCTL-SAN22"},{"id":"HRG1","name":"HRGHRGGS-HRG1"},{"id":"JCS1","name":"JCSJSCJS-JCS1"},{"id":"DHA12","name":"WSXEDECF-DHA12"},{"id":"HJE1","name":"AOEEWWWD-HJE1"},{"id":"NCA1","name":"NCANCANN-NCA1"},{"id":"IOP1","name":"iopclli1-IOP1"},{"id":"RTY1","name":"rtyclli1-RTY1"},{"id":"KAP1","name":"HIOUYTRQ-KAP1"},{"id":"ZEN1","name":"ZENCLLI1-ZEN1"},{"id":"HKA1","name":"JAKHLASS-HKA1"},{"id":"CQK1","name":"CQKSCAKK-CQK1"},{"id":"SAI1","name":"UBEKQLPD-SAI1"},{"id":"ERT1","name":"ertclli1-ERT1"},{"id":"IBB1","name":"PLMKOIJU-IBB1"},{"id":"TIR2","name":"PLKINHYI-TIR2"},{"id":"HSD1","name":"CHASKCDS-HSD1"},{"id":"SLF78","name":"SDCTLFN1-SLF78"},{"id":"SEE78","name":"SDCTEEE4-SEE78"},{"id":"SAN13","name":"TOKYJPFA-SAN13"},{"id":"SAA78","name":"SDCTAAA1-SAA78"},{"id":"LUC1","name":"ATLDFGYC-LUC1"},{"id":"AMD13","name":"MEMATLAN-AMD13"},{"id":"TOR1","name":"TOROONXN-TOR1"},{"id":"QWE1","name":"QWECLLI1-QWE1"},{"id":"ZOG1","name":"ZOGASTRO-ZOG1"},{"id":"CAL33","name":"CALIFORN-CAL33"},{"id":"SHH78","name":"SDIT1HHH-SHH78"},{"id":"DSA1","name":"LKJHGFDS-DSA1"},{"id":"CLG1","name":"CLGRABAD-CLG1"},{"id":"BNA1","name":"BNARAGBK-BNA1"},{"id":"ATL84","name":"CANTTCOC-ATL84"},{"id":"APP1","name":"WBHGTYUI-APP1"},{"id":"RJN1","name":"RJNRBZAW-RJN1"},{"id":"EHH78","name":"SDCSHHH5-EHH78"},{"id":"mac10","name":"PKGTESTF-mac10"},{"id":"SXB78","name":"SDCTGXB1-SXB78"},{"id":"SAX78","name":"SDCTAXG1-SAX78"},{"id":"SYD1","name":"SYDNAUBV-SYD1"},{"id":"TOK1","name":"TOKYJPFA-TOK1"},{"id":"KGM2","name":"KGMTNC20-KGM2"},{"id":"DCC1b","name":"POIUYTGH-DCC1b"},{"id":"SKK78","name":"SDCTKKK1-SKK78"},{"id":"SGG78","name":"SDCTGGG1-SGG78"},{"id":"SJJ78","name":"SDCTJJJ1-SJJ78"},{"id":"SBX78","name":"SDCTBXG1-SBX78"},{"id":"LAG1","name":"LARGIZON-LAG1"},{"id":"IAA1","name":"QAZXSWED-IAA1"},{"id":"POI1","name":"PLMNJKIU-POI1"},{"id":"LAG1a","name":"LARGIZON-LAG1a"},{"id":"PBL1","name":"PBLAPBAI-PBL1"},{"id":"LAG45","name":"LARGIZON-LAG1a"},{"id":"MAR1","name":"MNBVCXZM-MAR1"},{"id":"HST70","name":"HSTNTX70-HST70"},{"id":"DCC1a","name":"POIUYTGH-DCC1a"},{"id":"TOL1","name":"TOLDOH21-TOL1"},{"id":"LON1","name":"LONEENCO-LON1"},{"id":"SJU78","name":"SDIT1JUB-SJU78"},{"id":"STN27","name":"HSTNTX01-STN27"},{"id":"SSW56","name":"ss8126GT-SSW56"},{"id":"SBB78","name":"SDIT1BBB-SBB78"},{"id":"DCC3","name":"POIUYTGH-DCC3"},{"id":"GNV1","name":"GNVLSCTL-GNV1"},{"id":"WAS1","name":"WASHDCSW-WAS1"},{"id":"TOY1","name":"TORYONNZ-TOY1"},{"id":"STT1","name":"STTLWA02-STT1"},{"id":"STG1","name":"STTGGE62-STG1"},{"id":"SLL78","name":"SDCTLLL1-SLL78"},{"id":"SBU78","name":"SDIT1BUB-SBU78"},{"id":"ATL2","name":"ATLNGANW-ATL2"},{"id":"BOT1","name":"BOTHWAKY-BOT1"},{"id":"SNG1","name":"SNGPSIAU-SNG1"},{"id":"NYC1","name":"NYCMNY54-NYC1"},{"id":"LAG1b","name":"LARGIZON-LAG1b"},{"id":"AMD15","name":"AMDFAA01-AMD15"},{"id":"SNA1","name":"SNANTXCA-SNA1"},{"id":"PLT1","name":"PLTNCA60-PLT1"},{"id":"TLP1","name":"TLPNXM18-TLP1"},{"id":"SDD81","name":"SAIT1DD6-SDD81"},{"id":"DCC1","name":"POIUYTGH-DCC1"},{"id":"DCC2","name":"POIUYTGH-DCC2"},{"id":"OKC1","name":"OKCBOK55-OKC1"},{"id":"PAR1","name":"PARSFRCG-PAR1"},{"id":"TES36","name":"ABCEETES-TES36"},{"id":"COM1","name":"PLMKOPIU-COM1"},{"id":"ANI1","name":"ATLNGTRE-ANI1"},{"id":"SDG78","name":"SDIT1BDG-SDG78"},{"id":"mac20","name":"PKGTESTF-mac20"},{"id":"DSF45","name":"DSFBG123-DSF45"},{"id":"HST25","name":"HSTNTX01-HST25"},{"id":"AMD18","name":"AUDIMA01-AMD18"},{"id":"SAA80","name":"SAIT9AA3-SAA80"},{"id":"SSA56","name":"SSIT2AA7-SSA56"},{"id":"SDD82","name":"SAIT1DD9-SDD82"},{"id":"JCV1","name":"JCVLFLBW-JCV1"},{"id":"SUL2","name":"WERTYUJK-SUL2"},{"id":"PUR1","name":"purelyde-PUR1"},{"id":"FDE55","name":"FDERT555-FDE55"},{"id":"SITE","name":"LONEENCO-SITE"},{"id":"ATL1","name":"ATLNGAMA-ATL1"},{"id":"JUL1","name":"ZXCVBNMM-JUL1"},{"id":"TAT34","name":"TESAAISB-TAT34"},{"id":"XCP12","name":"CHKGH123-XCP12"},{"id":"RAI1","name":"poiuytre-RAI1"},{"id":"HPO1","name":"ATLNGAUP-HPO1"},{"id":"KJF12","name":"KJFDH123-KJF12"},{"id":"SCC80","name":"SAIT9CC3-SCC80"},{"id":"SAA12","name":"SAIT9AF8-SAA12"},{"id":"SAA14","name":"SAIT1AA9-SAA14"},{"id":"ATL35","name":"TTESSAAI-ATL35"},{"id":"CWY1","name":"CWYMOWBS-CWY1"},{"id":"ATL76","name":"TELEPAAI-ATL76"},{"id":"DSL12","name":"DSLFK242-DSL12"},{"id":"ATL53","name":"AAIATLTE-ATL53"},{"id":"SAA11","name":"SAIT9AA2-SAA11"},{"id":"ATL62","name":"TESSASCH-ATL62"},{"id":"AUG1","name":"ASDFGHJK-AUG1"},{"id":"POI22","name":"POIUY123-POI22"},{"id":"SAA13","name":"SAIT1AA9-SAA13"},{"id":"BHY17","name":"BHYTFRF3-BHY17"},{"id":"LIS1","name":"HOSTPROF-LIS1"},{"id":"SIP1","name":"ZXCVBNMK-SIP1"},{"id":"ATL99","name":"TEESTAAI-ATL43"},{"id":"ATL64","name":"FORLOAAJ-ATL64"},{"id":"TAT33","name":"TESAAISA-TAT33"},{"id":"RAD10","name":"INDIPUNE-RAD10"},{"id":"RTW5","name":"BHYTFRY4-RTW5"},{"id":"JGS1","name":"KSJKKKKK-JGS1"},{"id":"ATL98","name":"TEESTAAI-ATL43"},{"id":"WAN1","name":"LEIWANGW-WAN1"},{"id":"ATL44","name":"ATLSANAB-ATL44"},{"id":"RTD2","name":"BHYTFRk4-RTD2"},{"id":"NIR1","name":"ORFLMANA-NIR1"},{"id":"ATL75","name":"SANAAIRE-ATL75"},{"id":"NUM1","name":"QWERTYUI-NUM1"},{"id":"MTN32","name":"MDTWNJ21-MTN32"},{"id":"RTZ4","name":"BHYTFRZ6-RTZ4"},{"id":"ATL56","name":"ATLSANAC-ATL56"},{"id":"AMS1","name":"AMSTNLBW-AMS1"},{"id":"RCT1","name":"AMSTERNL-RCT1"},{"id":"JAN1","name":"ORFLMATT-JAN1"},{"id":"ABC14","name":"TESAAISA-ABC14"},{"id":"TAT37","name":"TESAAISD-TAT37"},{"id":"MIC54","name":"MICHIGAN-MIC54"},{"id":"ABC11","name":"ATLSANAI-ABC11"},{"id":"AMF11","name":"AMDOCS01-AMF11"},{"id":"ATL63","name":"ATLSANEW-ATL63"},{"id":"ABC12","name":"ATLSECIA-ABC12"},{"id":"MTN20","name":"MDTWNJ21-MTN20"},{"id":"ABC15","name":"AAITESAN-ABC15"},{"id":"AVT1","name":"AVTRFLHD-AVT1"},{"id":"ATL34","name":"ATLSANAI-ATL34"}],"lcpRegions":[{"id":"AAIAIC25","name":"AAIAIC25","isPermitted":true},{"id":"mtn6","name":"mtn6","isPermitted":true}],"lcpRegionsTenantsMap":{},"tenants":[{"id":"bae71557c5bb4d5aac6743a4e5f1d054","name":"AIN Web Tool-15-D-testgamma","isPermitted":true},{"id":"229bcdc6eaeb4ca59d55221141d01f8e","name":"AIN Web Tool-15-D-STTest2","isPermitted":true},{"id":"1178612d2b394be4834ad77f567c0af2","name":"AIN Web Tool-15-D-SSPtestcustome","isPermitted":true},{"id":"19c5ade915eb461e8af52fb2fd8cd1f2","name":"AIN Web Tool-15-D-UncheckedEcopm","isPermitted":true},{"id":"de007636e25249238447264a988a927b","name":"AIN Web Tool-15-D-dfsdf","isPermitted":true},{"id":"62f29b3613634ca6a3065cbe0e020c44","name":"AIN/SMS-16-D-Multiservices1","isPermitted":true},{"id":"649289e30d3244e0b48098114d63c2aa","name":"AIN Web Tool-15-D-SSPST66","isPermitted":true},{"id":"3f21eeea6c2c486bba31dab816c05a32","name":"AIN Web Tool-15-D-ASSPST47","isPermitted":true},{"id":"f60ce21d3ee6427586cff0d22b03b773","name":"CESAR-100-D-sspjg67246","isPermitted":true},{"id":"8774659e425f479895ae091bb5d46560","name":"CESAR-100-D-sspjg68359","isPermitted":true},{"id":"624eb554b0d147c19ff8885341760481","name":"AINWebTool-15-D-iftach","isPermitted":true},{"id":"214f55f5fc414c678059c383b03e4962","name":"CESAR-100-D-sspjg612401","isPermitted":true},{"id":"c90666c291664841bb98e4d981ff1db5","name":"CESAR-100-D-sspjg621340","isPermitted":true},{"id":"ce5b6bc5c7b348e1bf4b91ac9a174278","name":"sspjg621351cloned","isPermitted":true},{"id":"b386b768a3f24c8e953abbe0b3488c02","name":"AINWebTool-15-D-eteancomp","isPermitted":true},{"id":"dc6c4dbfd225474e9deaadd34968646c","name":"AINWebTool-15-T-SPFET","isPermitted":true},{"id":"02cb5030e9914aa4be120bd9ed1e19eb","name":"AINWebTool-15-X-eeweww","isPermitted":true},{"id":"f2f3830e4c984d45bcd00e1a04158a79","name":"CESAR-100-D-spjg61909","isPermitted":true},{"id":"05b91bd5137f4929878edd965755c06d","name":"CESAR-100-D-sspjg621512cloned","isPermitted":true},{"id":"7002fbe8482d4a989ddf445b1ce336e0","name":"AINWebTool-15-X-vdr","isPermitted":true},{"id":"4008522be43741dcb1f5422022a2aa0b","name":"AINWebTool-15-D-ssasa","isPermitted":true},{"id":"f44e2e96a1b6476abfda2fa407b00169","name":"AINWebTool-15-D-PFNPT","isPermitted":true},{"id":"b69a52bec8a84669a37a1e8b72708be7","name":"AINWebTool-15-X-vdre","isPermitted":true},{"id":"fac7d9fd56154caeb9332202dcf2969f","name":"AINWebTool-15-X-NONPODECOMP","isPermitted":true},{"id":"2d34d8396e194eb49969fd61ffbff961","name":"DN5242-Nov16-T5","isPermitted":true},{"id":"cb42a77ff45b48a8b8deb83bb64acc74","name":"ro-T11","isPermitted":true},{"id":"fa45ca53c80b492fa8be5477cd84fc2b","name":"ro-T112","isPermitted":true},{"id":"4914ab0ab3a743e58f0eefdacc1dde77","name":"DN5242-Nov21-T1","isPermitted":true},{"id":"d0a3e3f2964542259d155a81c41aadc3","name":"test-mtn6-09","isPermitted":true},{"id":"cbb99fe4ada84631b7baf046b6fd2044","name":"DN5242-Nov16-T3","isPermitted":true}],"productFamilies":null,"projects":[{"id":"DFW","name":"DFW"},{"id":"x1","name":"x1"},{"id":"yyy1","name":"yyy1"}],"owningEntities":[{"id":"aaa1","name":"aaa1"},{"id":"d61e6f2d-12fa-4cc2-91df-7c244011d6fc","name":"MetroPacketCore"},{"id":"Wireline","name":"Wireline"}],"globalCustomerId":"e433710f-9217-458d-a79d-1c7aff376d89"}')}
+  }
+
+  function generateFormGroup(){
+    return new FormGroup({
+      globalSubscriberId: new FormControl(
+        Validators.compose([Validators.required])
+      ),
+      productFamilyId: new FormControl(),
+      subscriptionServiceType: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      lcpCloudRegionId: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      tenantId: new FormControl({value: null,  disabled: true}, Validators.compose([Validators.required])),
+      aicZoneId: new FormControl(),
+      projectName: new FormControl(),
+      owningEntityId: new FormControl(Validators.compose([Validators.required])),
+      instanceName : new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+    });
+  }
+
+
+  function generateServiceInstanceDetails(){
+    return {
+      servicePopupDataModel : {
+        "productFamilies" : []
+      },
+      serviceInstanceDetailsFormGroup : {
+        controls : {
+          productFamilyId : {
+            disabled : false
+          }
+        }
+      }
+    }
+  }
+
+  function generateLegalServiceInstance(){
+    return {
+      instanceName : "legalInstanceName"
+    }
+  }
+
+  function generateIllegalServiceInstance(){
+    return {
+      instanceName : "illegalInstanceName"
+    }
+  }
+
+});
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
new file mode 100644
index 0000000..f6efd35
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
@@ -0,0 +1,33 @@
+import {Injectable} from '@angular/core';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {FormGroup} from '@angular/forms';
+import * as _ from "lodash";
+
+@Injectable()
+export class ServicePopupService {
+  onControlError(serviceInstanceDetails : ServiceInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup) : boolean{
+    if(!isNullOrUndefined(serviceInstanceDetailsFormGroup) && !isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+      return true;
+    }
+
+    const controlName : Array<string> =  ['productFamilyId', 'lcpCloudRegionId', 'tenantId', 'owningEntityId', 'projectName', 'aicZoneId', 'subscriptionServiceType', 'globalSubscriberId',  'rollbackOnFailure'];
+    const selectDataName : Array<string> = ['productFamilies', 'lcpRegions', 'tenants', 'owningEntities', 'projects', 'aicZones', 'serviceTypes', 'subscribers', 'rollbackOnFailure'];
+    for(let i = 0 ; i < controlName.length ; i++){
+      if (!isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel) && !isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel[selectDataName[i]])) {
+        if (!serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && serviceInstanceDetails.servicePopupDataModel[selectDataName[i]].length === 0) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  resetDynamicInputs(serviceInstance : any, defaultDynamicInputs : any) : void {
+    for(let dynamicInput of serviceInstance.dynamicInputs){
+      const defaultDymanicInput = _.find(defaultDynamicInputs, {name:dynamicInput.name});
+      serviceInstance.serviceInstanceDetailsFormGroup.controls[dynamicInput.name].setValue(defaultDymanicInput.value);
+    }
+  }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
new file mode 100644
index 0000000..725e442
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
@@ -0,0 +1,275 @@
+import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {VNFPopupDataModel} from './vnfPopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import {VnfInstance} from "../../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../../shared/models/serviceInstance";
+import {VNFModel} from "../../../shared/models/vnfModel";
+import {InputType} from "../../../shared/models/inputTypes";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {VfModuleInstance} from "../../../shared/models/vfModuleInstance";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {Observable} from "rxjs/Observable";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {VnfInstanceDetailsService} from "./vnf-instance-details.service";
+import {isNullOrUndefined} from 'util';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import * as _ from "lodash";
+import {ServiceNodeTypes} from "../../../shared/models/ServiceNodeTypes";
+
+@Component({
+  selector: 'vnf-instance-details',
+  templateUrl: 'vnf-instance-details.html',
+  styleUrls: ['vnf-instance-details.scss'],
+  providers: [AaiService]
+})
+
+export class VnfInstanceDetailsComponent implements OnInit {
+  @ViewChild('vnfForm') vnfForm: 'VnfForm';
+  _vnfModel: VNFModel;
+  @Input ()
+  set vnfModel(vnfModel: VNFModel) {
+    this._vnfModel = vnfModel;
+    this.updateFormGroupControlsFromVNFModel();
+  }
+  @Input() vnfInstance: any;
+  @Input() serviceInstance: ServiceInstance;
+  @Input() dynamicInputs;
+  @Input() modelName: string;
+  @Input() serviceUuid: string;
+  @Input() userProvidedNaming: boolean;
+  _modelType: string;
+  @Input()
+  set modelType(modelType: string) {
+    this._modelType = modelType;
+    this.updateFormGroupControlsFromVNFModel();
+  }
+
+  @Input() parentModelName: string;
+  @Input() isNewVfModule : boolean;
+
+
+  @Output() onSubmitClick: EventEmitter<any> = new EventEmitter<any>();
+  @Output() onServiceInstanceNameChanged :  EventEmitter<boolean> = new EventEmitter<boolean>();
+  @Output() onVolumeGroupNameChanged :  EventEmitter<boolean> = new EventEmitter<boolean>();
+
+@Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+  @select(['service','productFamilies'])
+  readonly productFamilies : Observable<SelectOptionInterface[]>;
+
+  vnfPopupDataModel: VNFPopupDataModel = new VNFPopupDataModel();
+  lcpRegionsThatEnableLegacyRegionField = ['AAIAIC25', 'rdm3', 'rdm5a'];
+  shouldShowLegacyRegion: boolean;
+  instanceFormGroup: FormGroup = null;
+  inputType = InputType;
+  isNotUniqueInstanceName : boolean = false;
+  isNotUniqueVolumeGroupName : boolean = false;
+
+  constructor(private _aaiService: AaiService, private store: NgRedux<AppState>,
+              private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+    this.store.subscribe(() => {
+      this.updateFormData()
+    });
+  }
+
+  ngOnInit() {
+    this.updateFormGroup();
+    this.subscribeToFormChanges();
+    this._aaiService.getCategoryParameters(null).subscribe();
+    this._aaiService.getLcpRegionsAndTenants(this.serviceInstance.globalSubscriberId, this.serviceInstance.subscriptionServiceType).subscribe();
+    this.updateLegacyRegionVisibility();
+    this.store.dispatch(loadProductFamiliesAction());
+  }
+
+  isInputShouldBeShown(inputType: any) {
+    let vnfInputs = [InputType.LCP_REGION, InputType.LOB, InputType.TENANT, InputType.PRODUCT_FAMILY, InputType.PLATFORM, InputType.ROLLBACK];
+    let vfInputs = [InputType.VG];
+    let exist = false;
+    if (this._modelType === 'VF') {
+      exist = vnfInputs.indexOf(inputType) > -1;
+    }
+    else {
+      exist = vfInputs.indexOf(inputType) > -1;
+    }
+    return exist;
+  }
+
+  updateFormGroupControlsFromVNFModel() {
+    if (this._vnfModel && this._modelType) {
+      if (this._modelType === ServiceNodeTypes.VF) {
+        const vnfInstance = <VnfInstance>this.vnfInstance;
+        if (this.instanceFormGroup && this.userProvidedNaming
+          && !this.instanceFormGroup.get('instanceName')) {
+          const initialInstanceName = vnfInstance.instanceName || (!isNullOrUndefined(this._vnfModel.name) ? this._vnfModel.name.replace(/[-]/g, "") : this._vnfModel.name);
+          this.instanceFormGroup.addControl('instanceName', new FormControl(initialInstanceName, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+        }
+      }
+      else if (this._modelType === ServiceNodeTypes.VFmodule) {
+        const vfInstance = <VfModuleInstance>this.vnfInstance;
+        if (this.instanceFormGroup && this.userProvidedNaming && !this.instanceFormGroup.get('instanceName')) {
+          this.instanceFormGroup.addControl('instanceName', new FormControl(vfInstance.instanceName, Validators.required));
+
+          let vfModule = this.extractVfAccordingToVfModuleUuid(this.store.getState(), this._vnfModel.uuid);
+          if (vfModule.volumeGroupAllowed && !this.instanceFormGroup.get('volumeGroupName')) {
+            this.instanceFormGroup.addControl('volumeGroupName', new FormControl(vfInstance.volumeGroupName));
+          }
+        }
+      }
+    }
+  }
+
+  updateFormGroup() {
+    const tenantDisabled = !this.vnfInstance.lcpCloudRegionId;
+
+    if (this._modelType === ServiceNodeTypes.VF) {
+      const vnfInstance = <VnfInstance>this.vnfInstance;
+      this.instanceFormGroup = new FormGroup({
+        productFamilyId: new FormControl(vnfInstance.productFamilyId),
+        lcpCloudRegionId: new FormControl(vnfInstance.lcpCloudRegionId, Validators.required),
+        tenantId: new FormControl({value: vnfInstance.tenantId, disabled: tenantDisabled}, Validators.required),
+        legacyRegion: new FormControl(vnfInstance.legacyRegion),
+        lineOfBusiness: new FormControl(vnfInstance.lineOfBusiness),
+        platformName: new FormControl(vnfInstance.platformName, Validators.required),
+      });
+    }
+    else if (this._modelType === ServiceNodeTypes.VFmodule) {
+      const vfInstance = <VfModuleInstance>this.vnfInstance;
+      this.instanceFormGroup = new FormGroup({
+      });
+    }
+
+    this.instanceFormGroup.valueChanges.subscribe(()=> {
+      this.checkForUniqueInstanceName();
+      this.onDataChanged.next();
+    });
+
+    this.updateFormGroupControlsFromVNFModel();
+  }
+
+  private getParentVnfModel(): VNFModel {
+    const rawModel = _.get(this.store.getState().service.serviceHierarchy[this.serviceUuid], ['vnfs', this.parentModelName]);
+    return new VNFModel(rawModel);
+  }
+
+  extractVfAccordingToVfModuleUuid(state : any,vfModuleUuid : string) {
+    const vnfs = this.store.getState().service.serviceHierarchy[this.serviceUuid].vnfs;
+    const vnfsArray = Object.values(vnfs);
+    for (let i = 0; i<vnfsArray.length;i++){
+      let vfModules = Object.values(vnfsArray[i].vfModules);
+      for (let j = 0; j<vfModules.length;j++){
+        if (vfModules[j].uuid === vfModuleUuid){
+          return vfModules[j];
+        }
+      }
+    }
+  }
+
+  updateFormData() {
+    let service = this.store.getState().service;
+    this.vnfPopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+    if (this.vnfInstance && this.vnfInstance.lcpCloudRegionId) {
+      this.vnfPopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.vnfInstance.lcpCloudRegionId];
+      console.log('setting vnf instances tenant: ' + JSON.stringify(this.vnfPopupDataModel.tenants));
+    }
+    this.vnfPopupDataModel.platforms = service.categoryParameters.platformList;
+    this.vnfPopupDataModel.lineOfBusinesses = service.categoryParameters.lineOfBusinessList;
+    this.onDataChanged.next();
+  }
+
+  subscribeToFormChanges(): void {
+    if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+      this.instanceFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+        this.setDisabledState(val, 'tenantId');
+        this.updateTenantList(val);
+        this.updateLegacyRegionVisibility();
+        this.onDataChanged.next();
+      });
+    }
+  }
+
+  setDisabledState(val, field: string): void {
+    if (val) {
+      this.instanceFormGroup.controls[field].enable();
+    }
+  }
+
+  updateLegacyRegionVisibility() {
+    if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+      this.shouldShowLegacyRegion = this.lcpRegionsThatEnableLegacyRegionField.indexOf(this.instanceFormGroup.get('lcpCloudRegionId').value) > -1;
+      if (!this.shouldShowLegacyRegion) {
+        this.instanceFormGroup.controls.legacyRegion.setValue(undefined);
+      }
+    }
+  }
+
+  updateTenantList(cloudRegionId) {
+    this.resetTenantSelection();
+    const tenantsForCloudRegionId = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+    console.log('tenants for selected cloud region id: ' + JSON.stringify(tenantsForCloudRegionId));
+    this.vnfPopupDataModel.tenants = tenantsForCloudRegionId;
+  }
+
+  resetTenantSelection() {
+    this.instanceFormGroup.controls.tenantId.setValue(undefined);
+  }
+
+  checkForUniqueInstanceName() {
+    let currentName = !isNullOrUndefined(this.instanceFormGroup.get('instanceName')) ? this.instanceFormGroup.get('instanceName').value : null;
+
+    if(currentName && !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance.instanceName) && this.userProvidedNaming){
+      this.isNotUniqueInstanceName = true;
+      this.onServiceInstanceNameChanged.emit(true);
+    }else {
+      this.isNotUniqueInstanceName = false;
+      this.onServiceInstanceNameChanged.emit(false);
+    }
+  }
+
+  checkForUniqueGroupName(){
+    let currentName = this.instanceFormGroup.get('volumeGroupName').value;
+    if( !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance['volumeGroupName'])){
+      this.isNotUniqueVolumeGroupName = true;
+      this.onVolumeGroupNameChanged.emit(true);
+    }else {
+      this.isNotUniqueVolumeGroupName = false;
+      this.onVolumeGroupNameChanged.emit(false);
+    }
+  }
+
+  onSubmit(formValues): void {
+    formValues.modelInfo = new ModelInfo(this._vnfModel);
+    if (this._modelType === 'VFmodule') {
+      let dynamicFields: { [dynamicField: string]: string; };
+      dynamicFields = {};
+      if(!_.isEmpty(this.dynamicInputs)) {
+        this.dynamicInputs.map(function (x) {
+          let dynamicField: string = x.id;
+          dynamicFields[dynamicField] = formValues[dynamicField];
+          delete formValues[dynamicField];
+        });
+      }
+      formValues.instanceParams = [];
+      formValues.instanceParams.push(dynamicFields);
+      if(this.isNewVfModule){
+        this.store.dispatch(createVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+      }else {
+        this.store.dispatch(updateVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+      }
+
+    }
+    else {
+      formValues.isUserProvidedNaming = this.userProvidedNaming;
+      this.store.dispatch(updateVNFInstance(formValues, this.modelName, this.serviceUuid));
+    }
+    window.parent.postMessage({
+      eventId: 'submitIframe',
+      data: {
+        serviceModelId: this.serviceUuid
+      }
+    }, "*");
+    this.onSubmitClick.emit(this.serviceUuid);
+  }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
new file mode 100644
index 0000000..ccdaac5
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
@@ -0,0 +1,114 @@
+
+<div id="vnf-instance-details">
+  <form id="vnfForm" #vnfForm="ngForm" (ngSubmit)="onSubmit(vnfForm.value)" [formGroup]="instanceFormGroup">
+
+    <div class="details-item" *ngIf="instanceFormGroup.get('instanceName')">
+      <label class="required">Instance name:</label>
+      <input patternInput
+             pattern="^[a-zA-Z0-9_]*$"
+            [attr.data-tests-id]="'instanceName'"
+             [ngClass]="{'error-style' : _vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup) || _vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)}"
+             id="instance-name" name="instance-name"
+             [formControlName]="'instanceName'"
+             class="form-control input-text"
+             placeholder="Type Instance Name"
+             type="text"
+             (blur)="checkForUniqueInstanceName()">
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)" [message]="'Instance name is already in use, please pick another name.'"></form-control-error>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup)" [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+    </div>
+
+    <div *ngIf="isInputShouldBeShown(inputType.PRODUCT_FAMILY)" class="details-item">
+      <label>Product family:</label>
+      <select class="form-control input-text"
+              [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)}"
+              data-tests-id="productFamily"
+              id="product-family-select"
+              [formControlName]="'productFamilyId'"
+              name="product-family-select" >
+        <option [value]="null" disabled>Select Product Family</option>
+        <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+                [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+      </select>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div *ngIf="isInputShouldBeShown(inputType.LCP_REGION)" class="details-item">
+      <label class="required">LCP region:</label>
+      <select
+        [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)}"
+        class="form-control input-text"
+        [formControlName]="'lcpCloudRegionId'"
+        name="lcpRegion" id="lcpRegion-select"
+        data-tests-id="lcpRegion">
+        <option [value]="null" disabled>Select LCP Region</option>
+        <option *ngFor="let lcpRegion of vnfPopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+      </select>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div class="details-item" *ngIf="shouldShowLegacyRegion">
+      <label>Legacy Region:</label>
+      <input
+        [attr.data-tests-id]="'lcpRegionText'"
+        id="legacy-region"
+        name="legacy-region"
+        [formControlName]="'legacyRegion'"
+        class="form-control input-text"
+             placeholder="Type Legacy Region" type="text">
+    </div>
+
+    <div *ngIf="isInputShouldBeShown(inputType.TENANT)" class="details-item">
+      <label class="required">Tenant:</label>
+      <select class="form-control input-text"
+              [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)}"
+              [formControlName]="'tenantId'"
+              name="tenant" id="tenant-select" data-tests-id="tenant">
+        <option [value]="undefined" disabled>Select Tenant</option>
+        <option *ngFor="let tenant of vnfPopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+      </select>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div *ngIf="isInputShouldBeShown(inputType.LOB)"  class="details-item">
+      <label>Line of business:</label>
+      <select [attr.data-tests-id]="'lineOfBusiness'"
+              class="form-control input-text"
+              [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)}"
+              name="lineOfBusiness" id="lineOfBusiness"
+              [formControlName]="'lineOfBusiness'">
+        <option [value]="null" disabled>Select Line Of Business</option>
+        <option *ngFor="let project of vnfPopupDataModel.lineOfBusinesses" [value]="project.id">{{project.name}}</option>
+      </select>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+    <div *ngIf="isInputShouldBeShown(inputType.PLATFORM)" class="details-item">
+      <label class="required">Platform:</label>
+      <select
+        [attr.data-tests-id]="'platform'"
+        [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)}"
+        class="form-control input-text"
+        [formControlName]="'platformName'"
+        name="platform" id="platform">
+        <option [value]="null" disabled>Select Platform</option>
+        <option *ngFor="let platform of vnfPopupDataModel.platforms" [value]="platform.id">{{platform.name}}</option>
+      </select>
+      <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+    </div>
+
+
+    <div *ngIf="isInputShouldBeShown(inputType.VG) && instanceFormGroup.get('volumeGroupName')" class="details-item" >
+      <label class="required">Volume Group Name:</label>
+      <input [attr.data-tests-id]="'volumeGroupName'"
+             id="vgName" name="vgName"
+             [ngClass]="{'error-style' :isNotUniqueVolumeGroupName}"
+             [formControlName]="'volumeGroupName'"
+             class="form-control input-text"
+             placeholder="Type Instance Name" type="text" (blur)="checkForUniqueGroupName()">
+      <form-control-error *ngIf="isNotUniqueVolumeGroupName" [message]="'Volume Group instance name is already in use, please pick another name.'"></form-control-error>
+    </div>
+
+    <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="instanceFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+  </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
new file mode 100644
index 0000000..080540a
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
@@ -0,0 +1,64 @@
+#vnf-instance-details {
+  position: relative;
+
+  #notification-area {
+    color: #959595;
+    font-size: 12px;
+    position: absolute;
+    top: 3px;
+    left: 30px;
+  }
+
+  height: 100%;
+  overflow: auto;
+  padding: 30px;
+
+  /deep/ {
+    .form-control {
+      border-radius: 2px;
+      box-shadow: none;
+      border-color: #D2D2D2;
+    }
+
+    label {
+      font-family: OpenSans-Semibold;
+      font-size: 12px;
+    }
+
+    select {
+      @extend .form-control;
+      -webkit-appearance: none;
+      -moz-appearance: none;
+      appearance: none;
+      background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+      background-size: 24px;
+      background-position-x: right;
+      background-position-y: center;
+      font-family: OpenSans-Italic;
+      font-size: 14px;
+      color: #959595;
+      height: 38px;
+    }
+
+    input:not([type='checkbox']) {
+      @extend .form-control;
+      height: 38px;
+    }
+
+    .form-control[disabled], fieldset[disabled] .form-control {
+      opacity: 0.5;
+    }
+    .input-text {
+      border: 1px solid #D2D2D2;
+      border-radius: 2px;
+    }
+
+    .details-item {
+      margin-bottom: 20px;
+    }
+  }
+
+    .checkbox-label {
+      font-family: OpenSans-Regular;
+    }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
new file mode 100644
index 0000000..41ddb43
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
@@ -0,0 +1,241 @@
+import { TestBed, getTestBed } from '@angular/core/testing';
+import {
+  HttpClientTestingModule,
+  HttpTestingController
+} from '@angular/common/http/testing';
+import { VnfInstanceDetailsService } from './vnf-instance-details.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Vnf Instance Details Service', () => {
+  let injector;
+  let service: VnfInstanceDetailsService;
+  let httpMock: HttpTestingController;
+
+  let SERVICE_ID: string = '1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd';
+  let serviceHierarchy;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [HttpClientTestingModule],
+      providers: [VnfInstanceDetailsService]
+    });
+
+    injector = getTestBed();
+    service = injector.get(VnfInstanceDetailsService);
+    httpMock = injector.get(HttpTestingController);
+    serviceHierarchy = getServiceServiceHierarchy();
+  });
+
+
+  describe('#hasInstanceNameError', ()=> {
+    it('hasInstanceNameError should return true if instanceName is illegal and enabled', (done: DoneFn) => {
+      let form = generateFormGroup();
+      form.controls['instanceName'].setValue('----');
+      form.controls['instanceName'].setErrors({
+        pattern : true
+      });
+      form.controls['instanceName'].markAsTouched();
+      let result = service.hasInstanceNameError(form);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('hasInstanceNameError should return false if instanceName is illegal and enabled and pattern is ok', (done: DoneFn) => {
+      let form = generateFormGroup();
+      form.controls['instanceName'].setValue('----');
+      form.controls['instanceName'].setErrors({
+        otherError : true
+      });
+      form.controls['instanceName'].markAsTouched();
+      let result = service.hasInstanceNameError(form);
+      expect(result).toBeFalsy();
+      done();
+    });
+  });
+
+  describe('#isUnique', () => {
+    it('Create Mode: should return false if instanceName exist', (done: DoneFn) => {
+      serviceHierarchy = getServiceServiceHierarchy();
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', false);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('Update Mode: should return true if instanceName exist once', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', true);
+      expect(result).toBeTruthy()
+      done();
+    });
+
+    it('Create Mode: should return true if instanceName not exist', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameNotExist', false);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('Create Mode: should return false if instanceName exist inside vf modules', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', false);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('Update Mode: should return true if instanceName  exist once inside vf modules', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', true);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('Create Mode: should return true if instanceName is not exist at vf modules and vnfs', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModuleNotExist', false);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('Create Mode: should return false if instanceName exist service name', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'Instance-Name', false);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('Create Mode: should return false if volumeGroupName exist service name', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameExist', false);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('Create Mode: should return true if volumeGroupName not exist service name', (done: DoneFn) => {
+      let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameNotExist', false);
+      expect(result).toBeTruthy();
+      done();
+    });
+  });
+
+  function getServiceServiceHierarchy() {
+    return JSON.parse(JSON.stringify(
+      {
+        "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd": {
+          "vnfs": {
+            "2017-388_ADIOD-vPE 1": {
+              "rollbackOnFailure": "true",
+              "vfModules": {},
+              "instanceParams": [
+                {}
+              ],
+              "productFamilyId": "a4f6f2ae-9bf5-4ed7-b904-06b2099c4bd7",
+              "lcpCloudRegionId": "AAIAIC25",
+              "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+              "lineOfBusiness": "zzz1",
+              "platformName": "platform",
+              "instanceName": "uniqueInstanceName",
+              "modelInfo": {
+                "modelInvariantId": "00beb8f9-6d39-452f-816d-c709b9cbb87d",
+                "modelVersionId": "0903e1c0-8e03-4936-b5c2-260653b96413",
+                "modelName": "2017-388_ADIOD-vPE",
+                "modelVersion": "1.0",
+                "modelCustomizationId": "280dec31-f16d-488b-9668-4aae55d6648a",
+                "modelCustomizationName": "2017-388_ADIOD-vPE 1"
+              },
+              "isUserProvidedNaming": true
+            },
+            "2017-388_ADIOD-vPE 0": {
+              "rollbackOnFailure": "true",
+              "vfModules": {},
+              "instanceParams": [
+                {}
+              ],
+              "productFamilyId": null,
+              "lcpCloudRegionId": "mtn6",
+              "tenantId": "1178612d2b394be4834ad77f567c0af2",
+              "lineOfBusiness": "ECOMP",
+              "platformName": "xxx1",
+              "instanceName": "blaaa",
+              "modelInfo": {
+                "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+                "modelVersionId": "afacccf6-397d-45d6-b5ae-94c39734b168",
+                "modelName": "2017-388_ADIOD-vPE",
+                "modelVersion": "4.0",
+                "modelCustomizationId": "b3c76f73-eeb5-4fb6-9d31-72a889f1811c",
+                "modelCustomizationName": "2017-388_ADIOD-vPE 0"
+              },
+              "isUserProvidedNaming": true
+            },
+            "2017488_ADIODvPE 0": {
+              "rollbackOnFailure": "true",
+              "vfModules": {
+                "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+                  "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+                    "rollbackOnFailure": "true",
+                    "instanceName": "uniqueInstanceNameVfModule",
+                    "volumeGroupName": "volumeGroupNameExist",
+                    "modelInfo": {
+                      "modelInvariantId": "7253ff5c-97f0-4b8b-937c-77aeb4d79aa1",
+                      "modelVersionId": "25284168-24bb-4698-8cb4-3f509146eca5",
+                      "modelName": "2017488AdiodVpe..ADIOD_vRE_BV..module-1",
+                      "modelVersion": "6"
+                    }
+                  }
+                }
+              },
+              "instanceParams": [
+                {}
+              ],
+              "productFamilyId": "ebc3bc3d-62fd-4a3f-a037-f619df4ff034",
+              "lcpCloudRegionId": "mtn6",
+              "tenantId": "19c5ade915eb461e8af52fb2fd8cd1f2",
+              "lineOfBusiness": "zzz1",
+              "platformName": "platform",
+              "instanceName": "2017488_ADIODvPE",
+              "modelInfo": {
+                "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+                "modelVersionId": "69e09f68-8b63-4cc9-b9ff-860960b5db09",
+                "modelName": "2017488_ADIODvPE",
+                "modelVersion": "5.0",
+                "modelCustomizationId": "1da7b585-5e61-4993-b95e-8e6606c81e45",
+                "modelCustomizationName": "2017488_ADIODvPE 0"
+              },
+              "isUserProvidedNaming": true
+            }
+          },
+          "instanceParams": [
+            {}
+          ],
+          "globalSubscriberId": "e433710f-9217-458d-a79d-1c7aff376d89",
+          "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77",
+          "subscriptionServiceType": "VIRTUAL USP",
+          "lcpCloudRegionId": "AAIAIC25",
+          "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+          "aicZoneId": "DKJ1",
+          "projectName": "DFW",
+          "owningEntityId": "aaa1",
+          "instanceName": "Instance-Name",
+          "bulkSize": 1,
+          "modelInfo": {
+            "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0",
+            "modelVersionId": "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd",
+            "modelName": "action-data",
+            "modelVersion": "1.0"
+          },
+          "tenantName": "USP-SIP-IC-24335-T-01",
+          "aicZoneName": "DKJSJDKA-DKJ1",
+          "isUserProvidedNaming": true
+        }
+      }
+    ));
+  }
+
+  function generateFormGroup() {
+    return new FormGroup({
+      productFamilyId: new FormControl(),
+      lcpCloudRegionId: new FormControl(Validators.required),
+      tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+      legacyRegion: new FormControl(),
+      lineOfBusiness: new FormControl(),
+      platformName: new FormControl(Validators.required),
+      rollbackOnFailure: new FormControl(Validators.required),
+      instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+
+    });
+  }
+
+});
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
new file mode 100644
index 0000000..677895e
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
@@ -0,0 +1,64 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from "util";
+import { FormGroup } from '@angular/forms';
+@Injectable()
+export class VnfInstanceDetailsService {
+  isUnique(serviceInstance : any, serviceId : string, name: string, isEqualToOriginalInstanceName : boolean) : boolean {
+    const service = serviceInstance[serviceId];
+    let countInstanceName = 0;
+    let countVolumeGroupName = 0;
+    if(service){
+      if(service.instanceName === name) return false;
+      if(service.vnfs){
+        for(let key in service.vnfs){
+          if(service.vnfs[key].instanceName === name) {
+            countInstanceName++;
+            if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+          }
+          if(service.vnfs[key].vfModules){
+            for(let vfModule in service.vnfs[key].vfModules){
+              if(service.vnfs[key].vfModules[vfModule]) {
+                for(let module in service.vnfs[key].vfModules[vfModule]){
+                  if(service.vnfs[key].vfModules[vfModule][module].instanceName === name ) {
+                    countInstanceName++;
+                    if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+                  }
+
+                  if(service.vnfs[key].vfModules[vfModule][module].volumeGroupName === name ) {
+                    countVolumeGroupName++;
+                    if((isEqualToOriginalInstanceName && countVolumeGroupName > 1) || (!isEqualToOriginalInstanceName)) return false;
+                  }
+                }
+              }
+            }
+          }
+
+        }
+      }
+    }
+    return true;
+  }
+
+  hasApiError(controlName: string, data: Array<any>, form: FormGroup) {
+    if (!isNullOrUndefined(data)) {
+      if (!form.controls[controlName].disabled && data.length === 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  hasInstanceNameError(form : FormGroup) : boolean {
+    if(!isNullOrUndefined(form) && !isNullOrUndefined(form.controls['instanceName'])){
+      if (form.controls['instanceName'].touched && form.controls['instanceName'].errors && form.controls['instanceName'].errors.pattern) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  hasUniqueError(isNotUniqueInstanceName) : boolean {
+    return isNotUniqueInstanceName;
+  }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
new file mode 100644
index 0000000..9a2694c
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
@@ -0,0 +1,26 @@
+import {Project} from "../../../shared/models/project";
+import {LcpRegion} from "../../../shared/models/lcpRegion";
+import {Tenant} from "../../../shared/models/tenant";
+import {ProductFamily} from "../../../shared/models/productFamily";
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class VNFPopupDataModel {
+  productFamilies: ProductFamily[];
+  lcpRegions: LcpRegion[];
+  lcpRegionsTenantsMap: any;
+  tenants: Tenant[];
+  projects: Project[];
+  lineOfBusinesses: SelectOption[];
+  platforms: SelectOptionInterface[];
+  globalCustomerId: string;
+
+
+  constructor(){
+      this.lcpRegions = [];
+      this.lcpRegionsTenantsMap = {};
+      this.tenants = [];
+      this.productFamilies = [];
+      this.lineOfBusinesses = [];
+      this.platforms = [];
+  }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
new file mode 100644
index 0000000..7dbe9b1
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
@@ -0,0 +1,55 @@
+import {Injectable} from "@angular/core";
+import {ServiceNodeTypeToModelKeyMapper} from "../../shared/models/serviceNodeTypeToModelKeyMapper";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {VfModule} from "../../shared/models/vfModule";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {VNFModel} from "../../shared/models/vnfModel";
+import * as _ from 'lodash';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {FormGroup} from '@angular/forms';
+import {VnfInstanceDetailsComponent} from './vnf-instance-details/vnf-instance-details.component';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+
+@Injectable()
+export class VnfPopupService {
+
+  constructor(private _servicePlanningService : ServicePlanningService, private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+  }
+
+  public getModelFromResponse(result : any, modelType : string, modelName:string) {
+    let model = null;
+    let rawModel = _.get(result, [ServiceNodeTypeToModelKeyMapper[modelType], modelName]);
+    if (!rawModel) return;
+
+    if (modelType === ServiceNodeTypes.VFmodule) {
+      model = new VfModule(rawModel);
+    }
+    else {
+      model = new VNFModel(rawModel);
+    }
+    return model;
+  }
+
+  onControlError(servicePopupDataModel : VnfInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup, isNotUniqueInstanceName : boolean, isNotUniqueVolumeGroupName : boolean) : boolean{
+    if(this._vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName) || isNotUniqueVolumeGroupName){
+      return true;
+    }
+    if(!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+      return true;
+    }
+
+    const controlName : Array<string> =  ['lcpCloudRegionId', 'tenantId', 'lineOfBusiness', 'platformName'];
+    const selectDataName : Array<string> = ['lcpRegions', 'tenants', 'lineOfBusinesses', 'platforms', 'projects'];
+
+    for(let i = 0 ; i < controlName.length ; i++){
+      if (!isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel) && !isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel[selectDataName[i]])) {
+        if (!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls[controlName[i]]) && !serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && servicePopupDataModel.vnfPopupDataModel[selectDataName[i]].length === 0) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
new file mode 100644
index 0000000..26e667d
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
@@ -0,0 +1,190 @@
+import {Component, OnInit, ViewChild} from "@angular/core";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+import {ActivatedRoute} from "@angular/router";
+import {DialogComponent, DialogService} from "ng2-bootstrap-modal";
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {ServiceModel} from "../../shared/models/serviceModel";
+import {Constants} from "../../shared/utils/constants";
+import * as _ from "lodash";
+import {VnfInstance} from "../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../shared/models/serviceInstance";
+import {VnfInstanceDetailsComponent} from "./vnf-instance-details/vnf-instance-details.component";
+import {Subscriber} from "../../shared/models/subscriber";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {AppState} from "../../store/reducers";
+import {NgRedux} from "@angular-redux/store";
+import {VfModuleInstance} from "../../shared/models/vfModuleInstance";
+import {VnfPopupService} from './vnf-popup-service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface VnfPopupModel {
+  serviceModelId: string;
+  modelName: string;
+  parentModelName: string;
+  modelType: string;
+  dynamicInputs: any;
+  userProvidedNaming: boolean;
+  isNewVfModule : boolean;
+}
+
+@Component({
+  selector: 'vnf-popup',
+  templateUrl: 'vnf-popup.html',
+  styleUrls: ['vnf-popup.scss'],
+  providers: [AaiService, VnfPopupService]
+})
+
+export class VnfPopupComponent extends DialogComponent<VnfPopupModel, boolean> implements VnfPopupModel, InstancePopup, OnInit {
+
+  @ViewChild(VnfInstanceDetailsComponent) vnfInstanceDetails: VnfInstanceDetailsComponent;
+
+  serviceModelId: string;
+  modelName: string;
+  parentModelName: string;
+  modelType: string;
+  isNewVfModule : boolean;
+  model: any;
+  serviceModel: ServiceModel;
+  popupTypeName: string;
+  serviceInstance: ServiceInstance;
+  vnfInstance: VnfInstance;
+  dynamicInputs;
+  userProvidedNaming: boolean;
+  typeMapperForTitle = {
+    VF: "VNF",
+    VFmodule: "Module (Heat stack)"
+  };
+
+  modelInformationItems: Array<ModelInformationItem> = [];
+  isNotUniqueInstanceName : boolean = false;
+  isNotUniqueVolumeGroupName : boolean = false;
+  hasGeneralApiError : boolean = false;
+
+  parentElementClassName = 'content';
+
+  constructor(dialogService: DialogService, protected route: ActivatedRoute, protected _aaiService: AaiService,
+              private store: NgRedux<AppState>,
+              private _iframeService : IframeService,
+              private _vnfPopupService: VnfPopupService) {
+    super(dialogService);
+    this.vnfInstance = new VnfInstance();
+  }
+
+  updateGeneralErrorSection() : void {
+    this.hasGeneralApiError = this._vnfPopupService.onControlError(
+      this.vnfInstanceDetails,
+      this.vnfInstanceDetails.instanceFormGroup,
+      this.vnfInstanceDetails.isNotUniqueInstanceName,
+      this.vnfInstanceDetails.isNotUniqueVolumeGroupName);
+  }
+
+  ngOnInit(): void {
+    this.updateServiceModelById();
+    this.popupTypeName = this.getModelTypeForPopupTitle();
+    this.updateServiceModelById();
+    this.updateInstanceFromStore();
+  }
+
+  onCancelClick() {
+    this._iframeService.removeClassCloseModal(this.parentElementClassName);
+    super.close();
+  }
+
+  onServiceInstanceNameChanged(isNotUniqueInstanceName: boolean) : void {
+    this.isNotUniqueInstanceName = isNotUniqueInstanceName;
+  }
+
+  onVolumeGroupNameChanged(isNotUniqueVolumeGroupName: boolean) : void {
+    this.isNotUniqueVolumeGroupName = isNotUniqueVolumeGroupName;
+  }
+
+  onSetClick() {
+      this._iframeService.removeClassCloseModal(this.parentElementClassName);
+      this.result = true;
+      super.close();
+  }
+
+  updateServiceModelById() {
+    this._aaiService.getServiceModelById(this.serviceModelId).subscribe(
+      result => {
+        this.serviceModel = new ServiceModel(result);
+        this.model = this._vnfPopupService.getModelFromResponse(result, this.modelType, this.modelName);
+        this.modelInformationItems = this.createModelInformationItems();
+      },
+      error => {
+        console.log('error is ', error)
+      }
+    );
+  }
+
+  updateInstanceFromStore() {
+    let instance;
+    const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+    if (this.modelType === ServiceNodeTypes.VF) {
+      instance = serviceInstance.vnfs[this.modelName] || new VnfInstance();
+    } else {
+      instance = new VfModuleInstance();
+    }
+
+    if (instance.instanceParams && instance.instanceParams[0]) {
+      this.dynamicInputs = this.dynamicInputs.map(x => {
+        x.value = (instance.instanceParams[0][x.id]) ? instance.instanceParams[0][x.id] : x.value;
+        return x;
+      });
+    }
+    this.vnfInstance = instance;
+  }
+
+  getModelName(): string {
+    return this.modelName;
+  }
+
+  getModelTypeForPopupTitle(): string {
+    if (_.has(this.typeMapperForTitle, this.modelType)) {
+      return this.typeMapperForTitle[this.modelType];
+    }
+    return this.modelType;
+  }
+
+  extractSubscriberNameBySubscriberId(subsriberId: string) {
+    var result: string = null;
+    var filteredArray: any = _.filter(this.store.getState().service.subscribers, function (o: Subscriber) {
+      return o.id === subsriberId
+    })
+    if (filteredArray.length > 0) {
+      result = filteredArray[0].name;
+    }
+    return result;
+  }
+
+  createModelInformationItems(): Array<ModelInformationItem> {
+    var serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+
+    let items = [
+      new ModelInformationItem("Subscriber Name", "subscriberName", [this.extractSubscriberNameBySubscriberId(serviceInstance.globalSubscriberId)], "", true),
+      new ModelInformationItem("Service Name", "serviceModelName", [this.serviceModel.name], "", true),
+
+      new ModelInformationItem("Service Instance Name", "serviceName", [serviceInstance.instanceName], "", false),
+      new ModelInformationItem("Model Name", "modelName", [this.model.name], "", true),
+      new ModelInformationItem("Model version", "modelVersion", [this.model.version], "", true),
+      new ModelInformationItem("Description", "description", [this.model.description]),
+      new ModelInformationItem("Category", "category", [this.model.category]),
+      new ModelInformationItem("Sub Category", "subCategory",[this.model.subCategory]),
+      new ModelInformationItem("UUID", "uuid", [this.model.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+      new ModelInformationItem("Invariant UUID", "invariantUuid", [this.model.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+      new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+      new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole]),
+
+
+    ];
+    if (this.modelType === 'VFmodule') {
+      items.push(new ModelInformationItem("Minimum to instantiate", "min", [this.model.min], "", true),
+        new ModelInformationItem("Maximum to instantiate", "max", this.model.max == undefined ? [1] : [this.model.max], "", true),
+        new ModelInformationItem("Recommended to instantiate", "initial", [this.model.initial]));
+
+    }
+
+    return items;
+  }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
new file mode 100644
index 0000000..d2e043b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
@@ -0,0 +1,54 @@
+<div id="instance-popup" class="modal-dialog">
+  <div class="modal-content">
+    <div class="modal-header">
+      <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+      <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">Set a new {{popupTypeName}}</span>
+    </div>
+    <div class="modal-body popup-content">
+
+      <div class="header-left">
+        <div>MODEL: <span>"{{popupTypeName}}"</span></div>
+      </div>
+
+      <div class="header-right">
+        {{getModelTypeForPopupTitle()}} Instance Details
+      </div>
+
+      <div class="model-information">
+        <model-information [modelInformationItems]="modelInformationItems"></model-information>
+      </div>
+
+      <div class="instance-form">
+        <vnf-instance-details [dynamicInputs]="dynamicInputs"
+                              [vnfModel]="model"
+                              [modelType]="modelType"
+                              [modelName]="modelName"
+                              [parentModelName]="parentModelName"
+                              [isNewVfModule]="isNewVfModule"
+                              [serviceInstance]="vnfInstance"
+                              [vnfInstance]="vnfInstance"
+                              [serviceUuid]="serviceModelId"
+                              [userProvidedNaming]="userProvidedNaming"
+                              (onSubmitClick)="onSetClick($event)"
+                              (onDataChanged)="updateGeneralErrorSection()"
+                              (onServiceInstanceNameChanged)="onServiceInstanceNameChanged($event)"
+                              (onVolumeGroupNameChanged)="onVolumeGroupNameChanged($event)"
+
+                              ></vnf-instance-details>
+      </div>
+
+    </div>
+    <div class="modal-footer row" style="padding: 0">
+      <div class="col-md-6">
+        <div *ngIf="hasGeneralApiError == true">
+          <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+        </div>
+      </div>
+      <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+        <button [attr.data-tests-id]="'cancelButton'"  type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+        <input type="submit" value="Set" form="vnfForm" data-tests-id="vnf-form-set"
+               class="btn btn-success submit" [disabled]="!vnfInstanceDetails?.vnfForm?.valid || isNotUniqueInstanceName || isNotUniqueVolumeGroupName">
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
new file mode 100644
index 0000000..6e606db
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#instance-popup {
+  color: #191919;
+
+  .left-panel {
+    background: #f2f2f2;
+    border-right: $grid-border;
+  }
+
+  .header-common {
+    height: 100%;
+    align-items: center;
+    display: flex;
+    font-family: OpenSans-Semibold;
+    font-size: 12px;
+  }
+
+  .header-text {
+    padding-left: 30px;
+    @extend .header-common;
+  }
+
+  .header-left {
+    grid-area: header-left;
+    @extend .header-text;
+    @extend .left-panel;
+    border-bottom: $grid-border;
+
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+    };
+  }
+
+  .header-right {
+    grid-area: header-right;
+
+    @extend .header-text;
+    border-bottom: $grid-border;
+  }
+
+  .quantity-label {
+    grid-area: quantity-label;
+    @extend .header-common;
+    border-bottom: $grid-border;
+    height: 100%;
+    font-family: OpenSans-Regular;
+  }
+
+  .quantity {
+    grid-area: quantity;
+    border-left: $grid-border;
+    border-bottom: $grid-border;
+    border-top-style: none;
+    font-family: OpenSans-Semibold;
+    text-align: start;
+    text-indent: 10px;
+  }
+
+  .quantity-select {
+    width: 78px;
+    height: 100%;
+    border: 0;
+    background: white;
+    outline: none;
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    appearance: none;
+    background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+    background-size: 24px;
+    background-position-x: right;
+    background-position-y: center;
+  }
+  input[type="number"]:hover::-webkit-inner-spin-button {
+    height: 20px;
+  }
+
+  .model-information {
+    grid-area: model-information;
+
+    padding: 30px;
+    overflow: auto;
+    @extend .left-panel;
+  }
+
+  .instance-form {
+    grid-area: instance-form;
+  }
+
+  .popup-content {
+    display: grid;
+    grid-template-columns: 400px auto 30px 93px;
+    grid-template-rows: 50px calc(100vh - 180px);
+    grid-template-areas:
+      "header-left header-right header-right header-right"
+      "model-information instance-form instance-form instance-form";
+    padding: 0;
+  }
+}
+
+.modal {
+  background-color: #191919;
+  opacity: 0.8;
+}
+
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 0;
+}
+@media (min-width: 1150px) {
+  .popup-content {
+    grid-template-rows: 30px 680px;
+  }
+}
+
+.modal-content {
+  border-radius: 0;
+  box-shadow: none;
+  border: none;
+}
+
+.modal-footer {
+  .cancel {
+    width: 120px;
+    height: 36px;
+    background: #ffffff;
+    border: 1px solid  #009fdb;
+    border-radius: 2px;
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+      color: #009fdb;
+      line-height: 16px;
+    }
+  }
+
+  .submit {
+    width: 120px;
+    height: 36px;
+    background: #009fdb;
+    border-radius: 2px;
+    border-color: #009fdb;
+    span {
+      font-family: OpenSans-Regular;
+      font-size: 14px;
+      color: #FFFFFF;
+      line-height: 16px;
+    }
+  }
+}
+
+.modal-header {
+  background-color: #009fdb;
+
+  padding-bottom: 13px;
+  padding-top: 13px;
+  padding-left: 29px;
+  padding-right: 21px;
+
+  .close {
+    font-size: 32px;
+    font-weight: 200;
+    color: #d8d8d8;
+    text-shadow: none;
+    filter: none;
+    opacity: 1;
+  }
+
+  .modal-title {
+    font-family: OpenSans-Regular;
+    font-size: 24px;
+    color: #fff;
+    line-height: 34px;
+  }
+}
+//
+//@media (min-width: 1200px) {
+//  .service-model,
+//  .service-instance {
+//    width: 1050px;
+//    margin: 30px auto;
+//  }
+//}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
new file mode 100644
index 0000000..02296f7
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
@@ -0,0 +1,827 @@
+import {VnfPopupService} from './vnf-popup-service';
+import {ServicePlanningService} from '../../services/service-planning.service';
+import {ServiceNodeTypes} from '../../shared/models/ServiceNodeTypes';
+import {NgRedux} from '@angular-redux/store';
+import {VNFModel} from '../../shared/models/vnfModel';
+import {VfModule} from '../../shared/models/vfModule';
+import {FormControl, FormGroup, Validators} from '@angular/forms';
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+import {ReflectiveInjector} from '@angular/core';
+
+export class MockAppStore<T> {
+}
+
+describe('Vnf popup service', () => {
+  let injector;
+  let service: VnfPopupService;
+  let fg: FormGroup;
+  let data = generateModelData();
+  let servicePopupDataModel = generateServicePopupDataModel();
+  let form: FormGroup = generateFormGroup();
+  beforeEach(() => {
+
+    let injector = ReflectiveInjector.resolveAndCreate([
+      VnfPopupService,
+      ServicePlanningService,
+      VnfInstanceDetailsService,
+      {provide: FormGroup, useClass: MockAppStore},
+      {provide: NgRedux, useClass: MockAppStore}
+    ]);
+
+    service = injector.get(VnfPopupService);
+    fg = injector.get(FormGroup);
+  });
+
+  describe('#updateVnfDataFromModel', () => {
+    it('update vnf data from model should return new vnf', (done: DoneFn) => {
+      let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 1');
+
+      expect(vnf).toEqual(jasmine.any(VNFModel));
+      done();
+    });
+
+    it('update wrong vnf data from model should be undefined', (done: DoneFn) => {
+      let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 3');
+
+      expect(vnf).toBeUndefined();
+      done();
+    });
+
+    it('update vfModule data from model should return new vfModule', (done: DoneFn) => {
+      let vfModule: VfModule = service.getModelFromResponse(data, ServiceNodeTypes.VFmodule, '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1');
+
+      expect(vfModule).toEqual(jasmine.any(VfModule));
+      done();
+    });
+
+  });
+
+
+  describe('#onControlError', () => {
+    it('onControlError should return true if instanceName is not legal', (done: DoneFn) => {
+      form.controls['instanceName'].setValue('aaaa - aaa');
+
+      let result: boolean = service.onControlError(<any>servicePopupDataModel, form, false, false);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('onControlError should return false if instanceName is legal', (done: DoneFn) => {
+
+      form.controls['instanceName'].setValue('aaaa');
+      let result = service.onControlError(<any>servicePopupDataModel, form, false, false);
+      expect(result).toBeFalsy();
+      done();
+    });
+
+    it('onControlError should return true if instanceName is not unique', (done: DoneFn) => {
+
+      form.controls['instanceName'].setValue('aaaa');
+      let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('onControlError should return true if lcpRegions is empty', (done: DoneFn) => {
+      servicePopupDataModel.vnfPopupDataModel['lcpRegions'] = [];
+      let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+      expect(result).toBeTruthy();
+      done();
+    });
+
+    it('onControlError should return true if isNotUniqueVolumeGroupName is true', (done: DoneFn) => {
+      let result = service.onControlError(<any>servicePopupDataModel, form, true, true);
+      expect(result).toBeTruthy();
+      done();
+    })
+  });
+
+
+  function generateServicePopupDataModel() {
+    return {
+      'vnfPopupDataModel': JSON.parse('{"tenants" : [1,2,3],"lcpRegions":[1,2,3],"lcpRegionsTenantsMap":{},"productFamilies":[1,2,3],"lineOfBusinesses":[{"id":"ECOMP","name":"ECOMP"},{"id":"zzz1","name":"zzz1"}],"platforms":[{"id":"platform","name":"platform"},{"id":"xxx1","name":"xxx1"}],"rollbackOnFailure":[{"id":"true","name":"Rollback"}]}')
+    }
+  }
+
+  function generateFormGroup() {
+    return new FormGroup({
+      productFamilyId: new FormControl(),
+      lcpCloudRegionId: new FormControl(Validators.required),
+      tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+      legacyRegion: new FormControl(),
+      lineOfBusiness: new FormControl(),
+      platformName: new FormControl(Validators.required),
+      instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+    });
+  }
+
+  function generateModelData() {
+    return JSON.parse(JSON.stringify(
+      {
+      'service': {
+        'uuid': '2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd',
+        'invariantUuid': 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0',
+        'name': 'action-data',
+        'version': '1.0',
+        'toscaModelURL': null,
+        'category': '',
+        'serviceType': '',
+        'serviceRole': '',
+        'description': '',
+        'serviceEcompNaming': 'true',
+        'instantiationType': 'ClientConfig',
+        'inputs': {
+          '2017488_adiodvpe0_ASN': {
+            'type': 'string',
+            'description': 'AV/PE',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': 'AV_vPE'
+          },
+          'adiodvpe0_bandwidth': {
+            'type': 'string',
+            'description': 'Requested VPE bandwidth',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': '10'
+          },
+          '2017488_adiodvpe0_vnf_instance_name': {
+            'type': 'string',
+            'description': 'The hostname assigned to the vpe.',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': 'mtnj309me6'
+          },
+          '2017488_adiodvpe0_vnf_config_template_version': {
+            'type': 'string',
+            'description': 'VPE Software Version',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': '17.2'
+          },
+          '2017488_adiodvpe0_AIC_CLLI': {
+            'type': 'string',
+            'description': 'AIC Site CLLI',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': 'ATLMY8GA'
+          },
+          'adiodvpe0_bandwidth_units': {
+            'type': 'string',
+            'description': 'Units of bandwidth',
+            'entry_schema': null,
+            'constraints': [],
+            'required': true,
+            'default': 'Gbps'
+          }
+        }
+      },
+      'vnfs': {
+        '2017-388_ADIOD-vPE 1': {
+          'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+          'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+          'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+          'name': '2017-388_ADIOD-vPE',
+          'version': '1.0',
+          'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+          'inputs': {
+            'vnf_config_template_version': {
+              'type': 'string',
+              'description': 'VPE Software Version',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '17.2'
+            },
+            'bandwidth_units': {
+              'type': 'string',
+              'description': 'Units of bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'Gbps'
+            },
+            'bandwidth': {
+              'type': 'string',
+              'description': 'Requested VPE bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '10'
+            },
+            'AIC_CLLI': {
+              'type': 'string',
+              'description': 'AIC Site CLLI',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'ATLMY8GA'
+            },
+            'ASN': {
+              'type': 'string',
+              'description': 'AV/PE',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'AV_vPE'
+            },
+            'vnf_instance_name': {
+              'type': 'string',
+              'description': 'The hostname assigned to the vpe.',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'mtnj309me6'
+            }
+          },
+          'commands': {
+            'vnf_config_template_version': {
+              'displayName': 'vnf_config_template_version',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+            },
+            'bandwidth_units': {
+              'displayName': 'bandwidth_units',
+              'command': 'get_input',
+              'inputName': 'adiodvpe0_bandwidth_units'
+            },
+            'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+            'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+            'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+            'vnf_instance_name': {
+              'displayName': 'vnf_instance_name',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_instance_name'
+            }
+          },
+          'properties': {
+            'vmxvre_retype': 'RE-VMX',
+            'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+            'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+            'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+            'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+            'int_ctl_net_name': 'VMX-INTXI',
+            'vmx_int_ctl_prefix': '128.0.0.0',
+            'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+            'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+            'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+            'nf_type': 'vPE',
+            'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+            'is_AVPN_service': 'false',
+            'vmx_RSG_name': 'vREXI-affinity',
+            'vmx_int_ctl_forwarding': 'l2',
+            'vmxvre_oam_ip_0': '10.40.123.5',
+            'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+            'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+            'vmxvre_instance': '0',
+            'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+            'vmxvpfe_volume_size_0': '40.0',
+            'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+            'nf_naming': '{ecomp_generated_naming=true}',
+            'nf_naming_code': 'Navneet',
+            'vmxvre_name_0': 'vREXI',
+            'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+            'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+            'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+            'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+            'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+            'vmxvre_console': 'vidconsole',
+            'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+            'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+            'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+            'vf_module_id': '123',
+            'nf_function': 'JAI',
+            'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+            'vmxvre_int_ctl_ip_0': '128.0.0.1',
+            'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+            'vnf_name': 'mtnj309me6vre',
+            'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+            'vmxvre_volume_type_1': 'HITACHI',
+            'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+            'vmxvre_volume_type_0': 'HITACHI',
+            'vmxvpfe_volume_type_0': 'HITACHI',
+            'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+            'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+            'vnf_id': '123',
+            'vmxvre_oam_prefix': '24',
+            'availability_zone_0': 'mtpocfo-kvm-az01',
+            'ASN': 'get_input:2017488_adiodvpe0_ASN',
+            'vmxvre_chassis_i2cid': '161',
+            'vmxvpfe_name_0': 'vPFEXI',
+            'bandwidth': 'get_input:adiodvpe0_bandwidth',
+            'availability_zone_max_count': '1',
+            'vmxvre_volume_size_0': '45.0',
+            'vmxvre_volume_size_1': '50.0',
+            'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+            'vmxvre_oam_gateway': '10.40.123.1',
+            'vmxvre_volume_name_1': 'vREXI_FAVolume',
+            'vmxvre_ore_present': '0',
+            'vmxvre_volume_name_0': 'vREXI_FBVolume',
+            'vmxvre_type': '0',
+            'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+            'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+            'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+            'vmx_int_ctl_len': '24',
+            'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+            'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+            'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+            'nf_role': 'Testing',
+            'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+            'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+          },
+          'type': 'VF',
+          'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+          'vfModules': {},
+          'volumeGroups': {}
+        },
+        '2017-388_ADIOD-vPE 0': {
+          'uuid': 'afacccf6-397d-45d6-b5ae-94c39734b168',
+          'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+          'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+          'name': '2017-388_ADIOD-vPE',
+          'version': '4.0',
+          'customizationUuid': 'b3c76f73-eeb5-4fb6-9d31-72a889f1811c',
+          'inputs': {
+            'vnf_config_template_version': {
+              'type': 'string',
+              'description': 'VPE Software Version',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '17.2'
+            },
+            'bandwidth_units': {
+              'type': 'string',
+              'description': 'Units of bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'Gbps'
+            },
+            'bandwidth': {
+              'type': 'string',
+              'description': 'Requested VPE bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '10'
+            },
+            'AIC_CLLI': {
+              'type': 'string',
+              'description': 'AIC Site CLLI',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'ATLMY8GA'
+            },
+            'ASN': {
+              'type': 'string',
+              'description': 'AV/PE',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'AV_vPE'
+            },
+            'vnf_instance_name': {
+              'type': 'string',
+              'description': 'The hostname assigned to the vpe.',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'mtnj309me6'
+            }
+          },
+          'commands': {
+            'vnf_config_template_version': {
+              'displayName': 'vnf_config_template_version',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+            },
+            'bandwidth_units': {
+              'displayName': 'bandwidth_units',
+              'command': 'get_input',
+              'inputName': 'adiodvpe0_bandwidth_units'
+            },
+            'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+            'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+            'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+            'vnf_instance_name': {
+              'displayName': 'vnf_instance_name',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_instance_name'
+            }
+          },
+          'properties': {
+            'vmxvre_retype': 'RE-VMX',
+            'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+            'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+            'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+            'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+            'int_ctl_net_name': 'VMX-INTXI',
+            'vmx_int_ctl_prefix': '128.0.0.0',
+            'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+            'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+            'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+            'nf_type': 'vPE',
+            'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+            'is_AVPN_service': 'false',
+            'vmx_RSG_name': 'vREXI-affinity',
+            'vmx_int_ctl_forwarding': 'l2',
+            'vmxvre_oam_ip_0': '10.40.123.5',
+            'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+            'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+            'vmxvre_instance': '0',
+            'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+            'vmxvpfe_volume_size_0': '40.0',
+            'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+            'nf_naming': '{ecomp_generated_naming=true}',
+            'nf_naming_code': 'Navneet',
+            'vmxvre_name_0': 'vREXI',
+            'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+            'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+            'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+            'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+            'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+            'vmxvre_console': 'vidconsole',
+            'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+            'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+            'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+            'vf_module_id': '123',
+            'nf_function': 'JAI',
+            'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+            'vmxvre_int_ctl_ip_0': '128.0.0.1',
+            'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+            'vnf_name': 'mtnj309me6vre',
+            'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+            'vmxvre_volume_type_1': 'HITACHI',
+            'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+            'vmxvre_volume_type_0': 'HITACHI',
+            'vmxvpfe_volume_type_0': 'HITACHI',
+            'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+            'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+            'vnf_id': '123',
+            'vmxvre_oam_prefix': '24',
+            'availability_zone_0': 'mtpocfo-kvm-az01',
+            'ASN': 'get_input:2017488_adiodvpe0_ASN',
+            'vmxvre_chassis_i2cid': '161',
+            'vmxvpfe_name_0': 'vPFEXI',
+            'bandwidth': 'get_input:adiodvpe0_bandwidth',
+            'availability_zone_max_count': '1',
+            'vmxvre_volume_size_0': '45.0',
+            'vmxvre_volume_size_1': '50.0',
+            'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+            'vmxvre_oam_gateway': '10.40.123.1',
+            'vmxvre_volume_name_1': 'vREXI_FAVolume',
+            'vmxvre_ore_present': '0',
+            'vmxvre_volume_name_0': 'vREXI_FBVolume',
+            'vmxvre_type': '0',
+            'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+            'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+            'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+            'vmx_int_ctl_len': '24',
+            'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+            'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+            'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+            'nf_role': 'Testing',
+            'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+            'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+          },
+          'type': 'VF',
+          'modelCustomizationName': '2017-388_ADIOD-vPE 0',
+          'vfModules': {},
+          'volumeGroups': {}
+        },
+        '2017488_ADIODvPE 0': {
+          'uuid': '69e09f68-8b63-4cc9-b9ff-860960b5db09',
+          'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+          'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+          'name': '2017488_ADIODvPE',
+          'version': '5.0',
+          'customizationUuid': '1da7b585-5e61-4993-b95e-8e6606c81e45',
+          'inputs': {
+            'vnf_config_template_version': {
+              'type': 'string',
+              'description': 'VPE Software Version',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '17.2'
+            },
+            'bandwidth_units': {
+              'type': 'string',
+              'description': 'Units of bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'Gbps'
+            },
+            'bandwidth': {
+              'type': 'string',
+              'description': 'Requested VPE bandwidth',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': '10'
+            },
+            'AIC_CLLI': {
+              'type': 'string',
+              'description': 'AIC Site CLLI',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'ATLMY8GA'
+            },
+            'ASN': {
+              'type': 'string',
+              'description': 'AV/PE',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'AV_vPE'
+            },
+            'vnf_instance_name': {
+              'type': 'string',
+              'description': 'The hostname assigned to the vpe.',
+              'entry_schema': null,
+              'constraints': [],
+              'required': true,
+              'default': 'mtnj309me6'
+            }
+          },
+          'commands': {
+            'vnf_config_template_version': {
+              'displayName': 'vnf_config_template_version',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+            },
+            'bandwidth_units': {
+              'displayName': 'bandwidth_units',
+              'command': 'get_input',
+              'inputName': 'adiodvpe0_bandwidth_units'
+            },
+            'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+            'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+            'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+            'vnf_instance_name': {
+              'displayName': 'vnf_instance_name',
+              'command': 'get_input',
+              'inputName': '2017488_adiodvpe0_vnf_instance_name'
+            }
+          },
+          'properties': {
+            'vmxvre_retype': 'RE-VMX',
+            'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+            'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+            'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+            'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+            'int_ctl_net_name': 'VMX-INTXI',
+            'vmx_int_ctl_prefix': '128.0.0.0',
+            'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+            'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+            'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+            'nf_type': 'vPE',
+            'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+            'is_AVPN_service': 'false',
+            'vmx_RSG_name': 'vREXI-affinity',
+            'vmx_int_ctl_forwarding': 'l2',
+            'vmxvre_oam_ip_0': '10.40.123.5',
+            'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+            'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+            'vmxvre_instance': '0',
+            'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+            'vmxvpfe_volume_size_0': '40.0',
+            'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+            'nf_naming': '{ecomp_generated_naming=true}',
+            'nf_naming_code': 'Navneet',
+            'vmxvre_name_0': 'vREXI',
+            'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+            'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+            'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+            'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+            'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+            'vmxvre_console': 'vidconsole',
+            'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+            'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+            'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+            'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+            'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+            'vf_module_id': '123',
+            'nf_function': 'JAI',
+            'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+            'vmxvre_int_ctl_ip_0': '128.0.0.1',
+            'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+            'vnf_name': 'mtnj309me6vre',
+            'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+            'vmxvre_volume_type_1': 'HITACHI',
+            'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+            'vmxvre_volume_type_0': 'HITACHI',
+            'vmxvpfe_volume_type_0': 'HITACHI',
+            'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+            'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+            'vnf_id': '123',
+            'vmxvre_oam_prefix': '24',
+            'availability_zone_0': 'mtpocfo-kvm-az01',
+            'ASN': 'get_input:2017488_adiodvpe0_ASN',
+            'vmxvre_chassis_i2cid': '161',
+            'vmxvpfe_name_0': 'vPFEXI',
+            'bandwidth': 'get_input:adiodvpe0_bandwidth',
+            'availability_zone_max_count': '1',
+            'vmxvre_volume_size_0': '45.0',
+            'vmxvre_volume_size_1': '50.0',
+            'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+            'vmxvre_oam_gateway': '10.40.123.1',
+            'vmxvre_volume_name_1': 'vREXI_FAVolume',
+            'vmxvre_ore_present': '0',
+            'vmxvre_volume_name_0': 'vREXI_FBVolume',
+            'vmxvre_type': '0',
+            'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+            'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+            'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+            'vmx_int_ctl_len': '24',
+            'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+            'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+            'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+            'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+            'nf_role': 'Testing',
+            'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+            'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+            'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+          },
+          'type': 'VF',
+          'modelCustomizationName': '2017488_ADIODvPE 0',
+          'vfModules': {
+            '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+              'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+              'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+              'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+              'description': null,
+              'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+              'version': '6',
+              'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+              'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+              'commands': {},
+              'volumeGroupAllowed': true,
+              'inputs': {
+                '2017488_adiodvpe0_vnf_config_template_version': {
+                  'type': 'string',
+                  'description': 'VPE Software Version',
+                  'entry_schema': null,
+                  'constraints': [],
+                  'required': true,
+                  'default': '17.2'
+                },
+                '2017488_adiodvpe0_AIC_CLLI': {
+                  'type': 'string',
+                  'description': 'AIC Site CLLI',
+                  'entry_schema': null,
+                  'constraints': [],
+                  'required': true,
+                  'default': 'ATLMY8GA'
+                }
+              }
+            },
+            '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+              'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+              'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+              'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+              'description': null,
+              'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+              'version': '5',
+              'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+              'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+              'commands': {},
+              'volumeGroupAllowed': false,
+              'inputs': {
+                '2017488_adiodvpe0_ASN': {
+                  'type': 'string',
+                  'description': 'AV/PE',
+                  'entry_schema': null,
+                  'constraints': [],
+                  'required': true,
+                  'default': 'AV_vPE'
+                },
+                'adiodvpe0_bandwidth': {
+                  'type': 'string',
+                  'description': 'Requested VPE bandwidth',
+                  'entry_schema': null,
+                  'constraints': [],
+                  'required': true,
+                  'default': '10'
+                }
+              }
+            },
+            '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+              'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+              'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+              'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+              'description': null,
+              'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+              'version': '6',
+              'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+              'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+              'commands': {},
+              'volumeGroupAllowed': true,
+              'inputs': {}
+            }
+          },
+          'volumeGroups': {
+            '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+              'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+              'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+              'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+              'description': null,
+              'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+              'version': '6',
+              'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+              'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+            },
+            '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+              'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+              'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+              'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+              'description': null,
+              'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+              'version': '6',
+              'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+              'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+            }
+          }
+        }
+      },
+      'vfModules': {
+        '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+          'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+          'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+          'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+          'description': null,
+          'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+          'version': '6',
+          'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+          'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+          'commands': {},
+          'volumeGroupAllowed': true
+        },
+        '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+          'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+          'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+          'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+          'description': null,
+          'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+          'version': '5',
+          'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+          'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+          'commands': {},
+          'volumeGroupAllowed': false
+        },
+        '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+          'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+          'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+          'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+          'description': null,
+          'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+          'version': '6',
+          'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+          'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+          'commands': {},
+          'volumeGroupAllowed': true
+        }
+      },
+      'networks': {},
+      'collectionResource': {},
+      'configurations': {},
+      'serviceProxies': {},
+      'pnfs': {}
+    }
+    ))
+  }
+
+});