summaryrefslogtreecommitdiffstats
path: root/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate
diff options
context:
space:
mode:
authorIttay Stern <ittay.stern@att.com>2018-08-29 17:01:32 +0300
committerIttay Stern <ittay.stern@att.com>2019-02-18 18:35:30 +0200
commit6f900cc45d7dd7f97430812b86b5c1d1693c8ae3 (patch)
tree936005c364dc5a7264d6304d4777c3d83494db22 /vid-webpack-master/src/app/drawingBoard/service-planning/duplicate
parent67d99f816cc583643c35193197594cf78d8ce60a (diff)
merge from ecomp a88f0072 - Modern UI
Issue-ID: VID-378 Change-Id: Ibcb23dd27f550cf32ce2fe0239f0f496ae014ff6 Signed-off-by: Ittay Stern <ittay.stern@att.com>
Diffstat (limited to 'vid-webpack-master/src/app/drawingBoard/service-planning/duplicate')
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.html19
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.scss9
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.ts25
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.spec.ts449
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.ts189
5 files changed, 691 insertions, 0 deletions
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.html b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.html
new file mode 100644
index 000000000..c5f43b9c8
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.html
@@ -0,0 +1,19 @@
+<div>
+ <div>
+ <span style="font-weight: bold;">
+ Please select the number of additional instances you want to add of this node.
+ </span>
+ </div>
+ <div>
+ <span style="font-weight: bold;">
+ Important: VID will duplicate this node including its children.
+ </span>
+ </div>
+
+ <div class="duplicate-number">
+ <select class="quantity-select" [(ngModel)]="duplicateNumber" name="duplicate" [attr.data-tests-id]="'duplicate-amount-vfmodules'" id="duplicate-select" (change)="onDuplicateNumberChange()">
+ <option *ngFor="let item of duplicateOptions" [value]="item">{{item}}</option>
+ </select>
+ </div>
+ <!--TODO max -->
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.scss
new file mode 100644
index 000000000..f5b566d0b
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.scss
@@ -0,0 +1,9 @@
+.quantity-select {
+ width: 100%;
+ font-family: inherit;
+ font-size: inherit;
+ border: 1px solid #009FDB;
+ margin-top: 10px;
+ padding-left: 7px;
+ height: 30px;
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.ts
new file mode 100644
index 000000000..e1c5d7296
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate-vnf.component.ts
@@ -0,0 +1,25 @@
+import { Component } from '@angular/core';
+import * as _ from 'lodash';
+import {DuplicateService} from "./duplicate.service";
+
+@Component({
+ selector: 'duplicate-vnf',
+ templateUrl : './duplicate-vnf.component.html',
+ styleUrls : ['./duplicate-vnf.component.scss']
+})
+export class DuplicateVnfComponent {
+ duplicateNumber : number = 1;
+ duplicateOptions : number[] = [];
+ duplicateService:DuplicateService;
+ constructor( private _duplicateService: DuplicateService ){
+ this.duplicateService = _duplicateService;
+ this.duplicateOptions = _.range(1, this._duplicateService.maxNumberOfDuplicate + 1);
+ this.onDuplicateNumberChange();
+ }
+
+ onDuplicateNumberChange() {
+ this.duplicateService.setNumberOfDuplicates(+this.duplicateNumber);
+ }
+
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.spec.ts
new file mode 100644
index 000000000..81251cb1a
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.spec.ts
@@ -0,0 +1,449 @@
+import { DuplicateService } from './duplicate.service';
+import { LogService } from '../../../shared/utils/log/log.service';
+import { NgRedux } from '@angular-redux/store';
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import { SdcUiServices} from "onap-ui-angular";
+import {IModalConfig} from "onap-ui-angular/dist/components/common";
+import {AppState} from "../../../shared/store/reducers";
+import {getTestBed, TestBed} from "@angular/core/testing";
+
+class MockAppStore<T> {
+ getState(){
+ return {
+ getState() {
+ return {
+ service : {
+ serviceHierarchy: {
+ "serviceId" : {
+ vnfs : {
+ "vnfModelName" : {
+ properties : {
+ max_instances : 2
+ }
+ },
+ "vnfModelName2" : {
+ properties : {
+ max_instances : 2
+ }
+ },
+ "vnfModelName3" : {
+ properties : {
+ }
+ }
+ }
+ }
+ },
+ serviceInstance : {
+ "serviceId" : {
+ existingVNFCounterMap : {
+ "vnfModelId" : 1,
+ "vnfModelId2" : 2,
+ "vnfModelId3" : 0
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+class MockModalService<T> {}
+
+describe('Drawing board tree service', () => {
+ let injector;
+ let service: DuplicateService;
+ let store : NgRedux<AppState>;
+ beforeAll(done => (async () => {
+ TestBed.configureTestingModule({
+ providers : [
+ DuplicateService,
+ LogService,
+ {provide: NgRedux, useClass: MockAppStore},
+ {provide: SdcUiServices.ModalService, useClass: MockModalService}
+ ]
+ });
+ await TestBed.compileComponents();
+
+ injector = getTestBed();
+ service = injector.get(DuplicateService);
+ store = injector.get(NgRedux);
+
+ })().then(done).catch(done.fail));
+
+
+ test('setNumberOfDuplicates should set number of duplicates', ()=>{
+ service.setNumberOfDuplicates(10);
+ expect(service.numberOfDuplicates).toEqual(10);
+ });
+
+ test('isEnabled should return false if type is VNF and has missing data', ()=>{
+ let node = {
+ data : {
+ type : 'VF',
+ menuActions : {
+ duplicate : () => {
+
+ }
+ }
+ }
+ };
+ spyOn(node.data.menuActions, 'duplicate').and.returnValue(true);
+ spyOn(service, 'hasMissingData').and.returnValue(true);
+ let result : boolean = service.isEnabled(<any>node, null, null);
+ expect(result).toBeFalsy();
+ });
+
+ test('openDuplicateModal', ()=>{
+ spyOn(service, 'getRemainsInstance').and.returnValue(1);
+ let result : IModalConfig = service.openDuplicateModal(
+ 'currentServiceId',
+ 'currentServiceId',
+ 'currentId',
+ 'storeKey',
+ 2,
+ null,null);
+ expect(result.title).toEqual('Duplicate Node');
+ });
+
+ test('openDuplicateModal should call getRemainsInstance with correct parameters', ()=>{
+ spyOn(service, 'getRemainsInstance');
+ service.openDuplicateModal(
+ 'currentServiceId',
+ 'currentServiceId',
+ 'currentId',
+ 'storeKey',
+ 2,
+ null,null);
+ expect(service.getRemainsInstance).toHaveBeenCalledWith('currentServiceId', 'currentId', 'currentServiceId', null, null);
+ });
+
+ test('canDuplicate VNF should return true', () => {
+ sessionStorage.setItem('reduxState' , JSON.stringify({global : { flags : {FLAG_DUPLICATE_VNF : true}}}));
+ let node : ITreeNode = <any> {data : {type : 'VF'}};
+
+ let result = service.canDuplicate(node);
+ expect(result).toBeTruthy();
+ });
+
+ test('canDuplicate Network should return true', () => {
+ sessionStorage.setItem('reduxState' , JSON.stringify({global : { flags : {FLAG_DUPLICATE_VNF : true}}}));
+ let node : ITreeNode = <any> {data : {type : 'VL'}};
+
+ let result = service.canDuplicate(node);
+ expect(result).toBeTruthy();
+ });
+
+ test('canDuplicate VFModule should return false', () => {
+ sessionStorage.setItem('reduxState' , JSON.stringify({global : { flags : {FLAG_DUPLICATE_VNF : true}}}));
+ let node : ITreeNode = <any> {data : {type : 'VFModule'}};
+
+ let result = service.canDuplicate(node);
+ expect(result).toBeFalsy();
+ });
+
+ test('Drawing board tree service should be defined', () => {
+ expect(service).toBeDefined();
+ });
+
+ test('DrawingBoardDuplicateService should be defined', () => {
+ expect(service).toBeDefined();
+ });
+
+ test('Duplicate multi vnfs should save multi vnfs in redux', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "rrr": "",
+ "ttt": ""
+ };
+ let newVnfs = service.cloneVnf(<any>{
+ "vfModules": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi": {
+ "instanceName": "rrr",
+ "volumeGroupName": "ttt"
+ }
+ }
+ },
+ "originalName": null,
+ "trackById": "pfs1f0len3",
+ "instanceName": "2017488_ADIODvPE"
+ }, "2017-488_ADIOD-vPE 0");
+
+ expect(newVnfs.instanceName).toBe("2017488_ADIODvPE_001");
+ expect(newVnfs.vfModules['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2']['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi'].instanceName).toBe("rrr_001");
+ expect(newVnfs.vfModules['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2']['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi'].volumeGroupName).toBe("ttt_001");
+
+ newVnfs = service.cloneVnf(<any>{
+ "vfModules": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi": {
+ "instanceName": "rrr",
+ "volumeGroupName": "ttt"
+ }
+ }
+ },
+ "originalName": null,
+ "trackById": "pfs1f0len3",
+ "instanceName": "2017488_ADIODvPE"
+ }, "2017-488_ADIOD-vPE 0");
+
+ expect(newVnfs.instanceName).toBe("2017488_ADIODvPE_002");
+ expect(newVnfs.vfModules['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2']['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi'].instanceName).toBe("rrr_002");
+ expect(newVnfs.vfModules['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2']['2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2mtlfi'].volumeGroupName).toBe("ttt_002");
+ });
+
+ test('ensure name is unique - send new name - shouldn\'t change name', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "uniqueinstancename": ""
+ };
+ const name = "uniqueInstanceName-1";
+ let uniqueName: string = service.ensureUniqueNameOrGenerateOne(name);
+ expect(uniqueName).toEqual(name);
+ });
+
+ test('ensure name is unique send existing name should change name', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "uniqueinstancename-1": ""
+ };
+ const name = "uniqueInstanceName-1";
+ let uniqueName: string = service.ensureUniqueNameOrGenerateOne(name);
+ expect(uniqueName).toEqual(name + "_001");
+ });
+
+ test('isAlreadyExist - send new name should return false', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "uniqueinstancename": ""
+ };
+ const name = "uniqueinstancename-1";
+ let isExist: boolean = service.isAlreadyExists(name, service.existingNames);
+ expect(isExist).toBeFalsy();
+ });
+
+ test('isAlreadyExist - send existing name should return true', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "uniqueinstancename-1": ""
+ };
+ const name = "uniqueinstancename-1";
+ let isExist: boolean = service.isAlreadyExists(name, service.existingNames);
+ expect(isExist).toBeTruthy();
+ });
+
+ test('isAlreadyExist - send existing name case insensitive should return true', () => {
+ service.existingNames = {
+ "2017488_adiodvpe": "",
+ "uniqueinstancename-1": ""
+ };
+ const name = "uniqueInstanceName-1";
+ let isExist: boolean = service.isAlreadyExists(name, service.existingNames);
+ expect(isExist).toBeTruthy();
+ });
+
+ test('getNumberAsPaddingString should return 001 if padding is 000 and val is 1 string', () => {
+ let paddingNumber: string = service.getNumberAsPaddingString(1, '0000');
+ expect(paddingNumber).toEqual('0001');
+ });
+
+ test('getNumberAsPaddingString should return 010 if padding is 000 and val is 10 string', () => {
+ let paddingNumber: string = service.getNumberAsPaddingString(10, '0000');
+ expect(paddingNumber).toEqual('0010');
+ });
+
+ test('generateVNFUniqueName should return the next free number', () => {
+ const vnfName: string = "VF_vMee 0";
+ let result: string = service.generateUniqueStoreKey(
+ "6e59c5de-f052-46fa-aa7e-2fca9d674c44",
+ vnfName,
+ getExistingVNFs(),
+ {}
+ );
+
+ expect(result).toEqual(vnfName + ":0003");
+ });
+
+ test('generateVNFUniqueName on duplicate multi vnfs should return the next free number', () => {
+ spyOn(service, 'openDuplicateModal');
+ service.openDuplicateModal(null, null, null,null, 2, null, null);
+
+ expect(service.openDuplicateModal).toHaveBeenCalledWith(null, null, null,null, 2, null, null);
+ });
+
+
+ test('isEnabled should return false if node has missing data', () => {
+ let node = {
+ data : {
+ missingData: true,
+ menuActions : {
+ duplicate : () => {
+
+ }
+ }
+ }
+ };
+ let result : boolean = service.isEnabled(<any>node, null, null);
+ expect(result).toBeFalsy();
+ });
+
+ test('isEnabled should return true if not reach to max', () => {
+ let node = {
+ data : {
+ missingData: false, modelName : "vnfModelName" , modelId : "vnfModelId", type : "VF", children: [], modelCustomizationId : "vnfModelId",modelUniqueId: "vnfModelId",
+ menuActions : {
+ duplicate : () => {
+
+ }
+ }
+ }
+ };
+ let result : boolean = service.isEnabled(<any>node, <any>getStoreState(), "serviceId");
+ expect(result).toBeTruthy();
+ });
+
+ test('isEnabled should return false if reach to max', () => {
+ let node = {
+ data : {
+ missingData: false, modelName : "vnfModelName2" , modelId : "vnfModelId2", type : "VF" ,children: [],
+ menuActions : {
+ duplicate : () => {
+
+ }
+ }
+ }
+ };
+ let result : boolean = service.isEnabled(<any>node, <any>getStoreState(), "serviceId");
+ expect(result).toBeFalsy();
+ });
+
+ test('isEnabled should return true if max is null', () => {
+ let node = {
+ data : {
+ missingData: false, modelName : "vnfModelName3" , modelId : "vnfModelId3",type : "VF", children: [], modelUniqueId: "vnfModelId3",
+ menuActions : {
+ duplicate : () => {
+
+ }
+ }
+ }
+ };
+ let result : boolean = service.isEnabled(<any>node, <any>getStoreState(), "serviceId");
+ expect(result).toBeTruthy();
+ });
+
+ test('isEnabled should return false if type is vf module', () => {
+ let node = {
+ data : {
+ missingData: false, modelName : "vnfModelName3" , modelId : "vnfModelId3",type : "VFModule", children: [],
+ menuActions : {
+ }
+ }
+ };
+ let result : boolean = service.isEnabled(<any>node, <any>getStoreState(), "serviceId");
+ expect(result).toBeFalsy();
+ });
+
+ test('getRemainsVNFinstance should return the remains 1 VNF', () => {
+ let result : number = service.getRemainsInstance("vnfModelId", "vnfModelName" , "serviceId" , <any>getStoreState(), <any>{data : {type : 'VF'}});
+ expect(result).toBe(1);
+ });
+
+ test('getRemainsVNFinstance should return the remains 0 VNF', () => {
+ let result : number = service.getRemainsInstance("vnfModelId2", "vnfModelName2" , "serviceId" , <any>getStoreState(),<any>{data : {type : 'VF'}});
+ expect(result).toBe(0);
+ });
+
+ test('isVNFChildrensHasMissingData should return true if vnf missing data = true', () => {
+ let result : boolean = service.hasMissingData(<any>getTreeNode(true,false));
+ expect(result).toBeTruthy();
+ });
+
+ test('isVNFChildrensHasMissingData return should false if vnf missing data = false', () => {
+ let result : boolean = service.hasMissingData(<any>getTreeNode(false,false));
+ expect(result).toBeFalsy();
+ });
+
+ test('isVNFChildrensHasMissingData should return true if vfModule missing data = true', () => {
+ let result : boolean = service.hasMissingData(<any>getTreeNode(false,true));
+ expect(result).toBeTruthy();
+ });
+
+ test('isVNFChildrensHasMissingData should return false if no children and vfModule missing data = false', () => {
+ let node = <any>getTreeNode(false,false);
+ node.data.children = [];
+ let result : boolean = service.hasMissingData(node);
+ expect(result).toBeFalsy();
+ });
+
+ function getExistingVNFs(){
+ return {"VF_vMee 0":{"rollbackOnFailure":"true","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"vf_vmee0..VfVmee..vmme_vlc..module-1dgbxq":{"modelInfo":{"modelInvariantId":"98a7c88b-b577-476a-90e4-e25a5871e02b","modelVersionId":"522159d5-d6e0-4c2a-aa44-5a542a12a830","modelName":"VfVmee..vmme_vlc..module-1","modelVersion":"2","modelCustomizationId":"55b1be94-671a-403e-a26c-667e9c47d091","modelCustomizationName":"VfVmee..vmme_vlc..module-1"},"instanceParams":[{}]}}},"productFamilyId":"17cc1042-527b-11e6-beb8-9e71128cae77","lcpCloudRegionId":"hvf6","tenantId":"bae71557c5bb4d5aac6743a4e5f1d054","lineOfBusiness":"ONAP","platformName":"platform","modelInfo":{"modelInvariantId":"4160458e-f648-4b30-a176-43881ffffe9e","modelVersionId":"d6557200-ecf2-4641-8094-5393ae3aae60","modelName":"VF_vMee","modelVersion":"2.0","modelCustomizationId":"91415b44-753d-494c-926a-456a9172bbb9","modelCustomizationName":"VF_vMee 0"}},"VF_vMee 0:0001":{"rollbackOnFailure":"true","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"vf_vmee0..VfVmee..vmme_vlc..module-1dgbxq":{"modelInfo":{"modelInvariantId":"98a7c88b-b577-476a-90e4-e25a5871e02b","modelVersionId":"522159d5-d6e0-4c2a-aa44-5a542a12a830","modelName":"VfVmee..vmme_vlc..module-1","modelVersion":"2","modelCustomizationId":"55b1be94-671a-403e-a26c-667e9c47d091","modelCustomizationName":"VfVmee..vmme_vlc..module-1"},"instanceParams":[{}]}}},"productFamilyId":"17cc1042-527b-11e6-beb8-9e71128cae77","lcpCloudRegionId":"hvf6","tenantId":"bae71557c5bb4d5aac6743a4e5f1d054","lineOfBusiness":"ONAP","platformName":"platform","modelInfo":{"modelInvariantId":"4160458e-f648-4b30-a176-43881ffffe9e","modelVersionId":"d6557200-ecf2-4641-8094-5393ae3aae60","modelName":"VF_vMee","modelVersion":"2.0","modelCustomizationId":"91415b44-753d-494c-926a-456a9172bbb9","modelCustomizationName":"VF_vMee 0"},"originalName":"VF_vMee 0"},"VF_vMee 0:0002":{"rollbackOnFailure":"true","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"vf_vmee0..VfVmee..vmme_vlc..module-1dgbxq":{"modelInfo":{"modelInvariantId":"98a7c88b-b577-476a-90e4-e25a5871e02b","modelVersionId":"522159d5-d6e0-4c2a-aa44-5a542a12a830","modelName":"VfVmee..vmme_vlc..module-1","modelVersion":"2","modelCustomizationId":"55b1be94-671a-403e-a26c-667e9c47d091","modelCustomizationName":"VfVmee..vmme_vlc..module-1"},"instanceParams":[{}]}}},"productFamilyId":"17cc1042-527b-11e6-beb8-9e71128cae77","lcpCloudRegionId":"hvf6","tenantId":"bae71557c5bb4d5aac6743a4e5f1d054","lineOfBusiness":"ONAP","platformName":"platform","modelInfo":{"modelInvariantId":"4160458e-f648-4b30-a176-43881ffffe9e","modelVersionId":"d6557200-ecf2-4641-8094-5393ae3aae60","modelName":"VF_vMee","modelVersion":"2.0","modelCustomizationId":"91415b44-753d-494c-926a-456a9172bbb9","modelCustomizationName":"VF_vMee 0"},"originalName":"VF_vMee 0"}}
+ }
+
+ function getStoreState(){
+ return {
+ getState() {
+ return {
+ service : {
+ serviceHierarchy: {
+ "serviceId" : {
+ vnfs : {
+ "vnfModelName" : {
+ properties : {
+ ecomp_generated_naming: "false",
+ max_instances : 2
+ }
+ },
+ "vnfModelName2" : {
+ properties : {
+ ecomp_generated_naming: "false",
+ max_instances : 2
+ }
+ },
+ "vnfModelName3" : {
+ properties : {
+ ecomp_generated_naming: "false",
+ }
+ }
+ }
+ }
+ },
+ serviceInstance : {
+ "serviceId" : {
+ existingVNFCounterMap : {
+ "vnfModelId" : 1,
+ "vnfModelId2" : 2,
+ "vnfModelId3" : 0
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ function getTreeNode(VNfMissingData : boolean, vfModuleMissingData : boolean){
+ return {
+ data : {
+ children : vfModuleMissingData ?
+ [{
+ missingData : true
+ }] :
+ [{
+ missingData : false
+ }
+ ],
+ missingData : VNfMissingData
+ }
+ }
+ }
+});
+
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.ts
new file mode 100644
index 000000000..e695edf86
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/duplicate/duplicate.service.ts
@@ -0,0 +1,189 @@
+import { Injectable } from '@angular/core';
+import { ITreeNode } from 'angular-tree-component/dist/defs/api';
+import { AppState } from '../../../shared/store/reducers';
+import { LogService } from '../../../shared/utils/log/log.service';
+import { NgRedux } from '@angular-redux/store';
+import {VnfInstance} from "../../../shared/models/vnfInstance";
+import {VfModuleMap} from "../../../shared/models/vfModulesMap";
+import * as _ from "lodash";
+import {DefaultDataGeneratorService} from "../../../shared/services/defaultDataServiceGenerator/default.data.generator.service";
+import {TypeNodeInformation} from "../typeNodeInformation.model";
+import { SdcUiServices} from "onap-ui-angular";
+import { SdcUiCommon} from "onap-ui-angular";
+import {changeInstanceCounter, duplicateBulkInstances} from "../../../shared/storeUtil/utils/general/general.actions";
+import {IModalConfig} from "onap-ui-angular/dist/modals/models/modal-config";
+
+@Injectable()
+export class DuplicateService {
+
+ constructor(private _logService : LogService, private _store: NgRedux<AppState>, modalService: SdcUiServices.ModalService) {
+ this.modalService = modalService;
+ }
+
+ numberOfDuplicates:number;
+ setNumberOfDuplicates(numberOfDuplicates: number) {
+ this.numberOfDuplicates = numberOfDuplicates;
+ }
+
+ currentInstanceId: string = null;
+ currentServiceId: string = null;
+ maxNumberOfDuplicate: number = 0;
+ storeKey: string = null;
+ padding = '0000';
+ modalService: SdcUiServices.ModalService;
+ store : NgRedux<AppState>;
+ existingNames : {[key: string] : any};
+ currentNode : ITreeNode = null;
+
+
+
+ canDuplicate(node: ITreeNode): boolean {
+ let reduxState = <AppState>JSON.parse(sessionStorage.getItem('reduxState'));
+ return reduxState.global.flags['FLAG_DUPLICATE_VNF'] && (node.data.type === 'VF' || node.data.type === 'VL');
+ }
+
+ isEnabled(node: ITreeNode, store: NgRedux<AppState>, serviceId : string): boolean {
+ if(!_.isNil(node) && !_.isNil(node.data.menuActions['duplicate'])){
+ if(this.hasMissingData(node)) return false;
+ const typeNodeInformation : TypeNodeInformation = new TypeNodeInformation(node);
+ const max : number = store.getState().service.serviceHierarchy[serviceId][typeNodeInformation.hierarchyName][node.data.modelName].properties['max_instances'] || 1;
+ const currentExisting: number = store.getState().service.serviceInstance[serviceId][typeNodeInformation.existingMappingCounterName][node.data.modelUniqueId];
+
+ return max - currentExisting > 0;
+ }else {
+ return false;
+ }
+ }
+
+ hasMissingData(node : ITreeNode): boolean {
+ if(!_.isNil(node)){
+ if(node.data.missingData) return true;
+ if(!_.isNil(node.data.children)){
+ for(let child of node.data.children) {
+ if(child.missingData){
+ return true;
+ }
+ }
+ }
+
+ }
+ return false;
+ }
+
+ getRemainsInstance(modelId : string, modelName : string, serviceId : string, store: NgRedux<AppState>, node : ITreeNode) : number {
+ const typeNodeInformation : TypeNodeInformation = new TypeNodeInformation(node);
+ const properties = store.getState().service.serviceHierarchy[serviceId][typeNodeInformation.hierarchyName][modelName].properties;
+ const currentExisting : number = store.getState().service.serviceInstance[serviceId][typeNodeInformation.existingMappingCounterName][modelId];
+ return (!_.isNil(properties) && !_.isNil(properties['max_instances'])) ? properties['max_instances'] - currentExisting : null;
+ }
+
+
+
+ openDuplicateModal(currentServiceId: string, currentUuid: string, currentId: string, storeKey : string, numberOfDuplicate: number, _store : NgRedux<AppState>, node: ITreeNode): IModalConfig {
+ this.currentInstanceId = currentId;
+ this.currentServiceId = currentServiceId;
+ this.maxNumberOfDuplicate = this.getRemainsInstance(currentUuid, currentId, currentServiceId, _store, node);
+ this.storeKey = storeKey;
+ this.store = _store;
+ this.currentNode = node;
+
+
+ return {
+ size: SdcUiCommon.ModalSize.medium,
+ title: 'Duplicate Node',
+ type: SdcUiCommon.ModalType.custom,
+ buttons: [
+ {text: 'Duplicate', callback: this.duplicate.bind(this, this.currentNode), closeModal: true},
+ {text: 'Cancel', closeModal: true}
+ ]
+ };
+ }
+
+ duplicate(node : ITreeNode): void {
+ const typeNodeInformation : TypeNodeInformation = new TypeNodeInformation(node);
+ this.existingNames = this.store.getState().service.serviceInstance[this.currentServiceId].existingNames;
+ const toClone = this.store.getState().service.serviceInstance[this.currentServiceId][typeNodeInformation.hierarchyName][this.storeKey];
+ let newObjects = {};
+ for(let i = 0; i < this.numberOfDuplicates; i++) {
+ const uniqueStoreKey = this.generateUniqueStoreKey(this.currentServiceId, this.currentInstanceId, this.store.getState().service.serviceInstance[this.currentServiceId][typeNodeInformation.hierarchyName], newObjects);
+ const clone = this.cloneVnf(toClone, this.currentInstanceId);
+ newObjects[uniqueStoreKey] = clone;
+ }
+ this.store.dispatch(duplicateBulkInstances(this.currentServiceId, newObjects, this.existingNames, node));
+ this.store.dispatch(changeInstanceCounter(toClone.modelInfo.modelUniqueId, this.currentServiceId, this.numberOfDuplicates, node));
+ this._logService.info("Duplicate " + this.storeKey + " serviceId: " + this.currentServiceId + "number of duplicate: " + this.numberOfDuplicates, toClone);
+ }
+
+
+ cloneVnf(vnf : VnfInstance, originalName: string): VnfInstance {
+ let newUniqueVnf : VnfInstance = _.cloneDeep(vnf);
+
+ newUniqueVnf.originalName = originalName;
+ newUniqueVnf.trackById = DefaultDataGeneratorService.createRandomTrackById();
+ if (!_.isNil(vnf.instanceName)){
+ newUniqueVnf.instanceName = this.ensureUniqueNameOrGenerateOne(vnf.instanceName);
+ }
+
+ for (let vf_module_model_name in vnf.vfModules) {
+ const vfModuleModel: VfModuleMap = vnf.vfModules[vf_module_model_name];
+ for (let vfModule in vfModuleModel) {
+ newUniqueVnf.vfModules[vf_module_model_name][vfModule].trackById = DefaultDataGeneratorService.createRandomTrackById();
+ if (!_.isNil(vfModuleModel[vfModule].instanceName)){
+ newUniqueVnf.vfModules[vf_module_model_name][vfModule].instanceName = this.ensureUniqueNameOrGenerateOne(vfModuleModel[vfModule].instanceName);
+ }
+ if (!_.isNil(vfModuleModel[vfModule].volumeGroupName)){
+ newUniqueVnf.vfModules[vf_module_model_name][vfModule].volumeGroupName = this.ensureUniqueNameOrGenerateOne(vfModuleModel[vfModule].volumeGroupName);
+ }
+ }
+ }
+ return newUniqueVnf;
+ }
+
+ ensureUniqueNameOrGenerateOne(instanceName){
+ let uniqueInstanceName = instanceName;
+ if (this.isAlreadyExists(instanceName, this.existingNames)) {
+ uniqueInstanceName = this.generateNextUniqueName(instanceName, this.existingNames);
+ this.existingNames[uniqueInstanceName.toLowerCase()] = "";
+ }
+ return uniqueInstanceName;
+ }
+
+
+ isAlreadyExists(name : string, existingNames : {[key: string] : any}){
+ return _.has(existingNames, name.toLowerCase());
+ }
+
+ generateNextUniqueName(name : string, existingNames : {[key: string] : any}) :string{
+ let suffix = "000";
+ let counter = 1;
+ if (name.match(/^.*_[\d]{3}$/)){
+ name = name.substring(0, name.length - 4);
+ }
+
+ while(true){
+ let paddingNumber : string = this.getNumberAsPaddingString(counter, suffix);
+ let candidateUniqueName = name + '_' + paddingNumber;
+ if(!this.isAlreadyExists(candidateUniqueName, existingNames)){
+ return candidateUniqueName;
+ }
+ counter++;
+ }
+ }
+
+ generateUniqueStoreKey(serviceId : string, objectName : string, existing : any, newObjects: any) : string {
+ let counter = 1;
+ while(true){
+ let paddingNumber : string = this.getNumberAsPaddingString(counter, this.padding);
+ const name = objectName + ':' + paddingNumber;
+ if(_.isNil(existing[name]) && _.isNil(newObjects[name])){
+ return name;
+ }
+ counter++;
+ }
+ }
+
+ getNumberAsPaddingString(val: number, padding: string): string {
+ const str = "" + val;
+ return padding.substring(0, padding.length - str.length) + str;
+ }
+}