From 1f2a2947990034b9162d386884f1e79892a87976 Mon Sep 17 00:00:00 2001 From: Yoav Schneiderman Date: Mon, 9 Dec 2019 16:42:21 +0200 Subject: [PATCH] Adding unlimited max value to VNF, NETWORK Issue-ID: VID-726 Signed-off-by: Yoav Schneiderman Change-Id: I0c3d503c8e4f6cb14081de8f6a619a67eee080b7 Signed-off-by: Yoav Schneiderman --- features.properties.md | 5 + .../java/org/onap/vid/properties/Features.java | 1 + .../integration/iFrames/drawingBoard.e2e.ts | 1 + .../iFrames/viewOnlyDrawingBoard.e2e.ts | 2 +- .../jsonBuilders/mocks/jsons/flags.cypress.json | 1 + .../duplicate/duplicate.service.spec.ts | 17 +- .../duplicate/duplicate.service.ts | 108 +++++----- .../models/network/network.model.info.spec.ts | 232 +++++++++++---------- .../models/network/network.model.info.ts | 8 +- .../models/vfModule/vfModule.model.info.spec.ts | 13 +- .../models/vfModule/vfModule.model.info.ts | 2 +- .../models/vnf/vnf.model.info.spec.ts | 11 +- .../objectsToTree/models/vnf/vnf.model.info.ts | 24 ++- .../objectsToTree/models/vrf/vrf.model.info.ts | 4 +- .../objectToModelTree/objectToModelTree.service.ts | 53 +++-- .../objectsToTree/objectToTree.service.ts | 8 +- .../objectsToTree/shared.tree.service.ts | 11 + .../genericFormServices/basic.popup.service.ts | 6 +- .../src/app/shared/models/networkModel.ts | 13 +- .../src/app/shared/models/vnfModel.ts | 13 +- .../services/featureFlag/feature-flags.service.ts | 8 + vid-webpack-master/src/app/shared/utils/utils.ts | 8 + 22 files changed, 330 insertions(+), 219 deletions(-) diff --git a/features.properties.md b/features.properties.md index 8b80184e3..62ab55ef6 100644 --- a/features.properties.md +++ b/features.properties.md @@ -195,3 +195,8 @@ This option is enabled only for instantiate jobs. IF the user click on this option, the previous instantiation is opened in drawing board, and the user can create another one from this template. + +* FLAG_2002_UNLIMITED_MAX + when flag is true and max_instances is not declare than user can add unlimited VND, NETWORK, VFMODULE, + User can duplicate up to 10 record in single time. + If the flag is false and max_instances is not declare the max will be 1 else max_instances value. diff --git a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java index 26bfec52f..990ec60c9 100644 --- a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java +++ b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java @@ -82,6 +82,7 @@ public enum Features implements Feature { FLAG_2004_INSTANTIATION_STATUS_FILTER, FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE, FLAG_2004_TEMP_BUTTON_TO_INSTANTIATION_STATUS_FILTER, + FLAG_2002_UNLIMITED_MAX, ; diff --git a/vid-webpack-master/cypress/integration/iFrames/drawingBoard.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/drawingBoard.e2e.ts index 0049a427f..b678702ff 100644 --- a/vid-webpack-master/cypress/integration/iFrames/drawingBoard.e2e.ts +++ b/vid-webpack-master/cypress/integration/iFrames/drawingBoard.e2e.ts @@ -584,6 +584,7 @@ describe('Drawing board', function () { "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_1906_COMPONENT_INFO" : false, "FLAG_2002_VNF_PLATFORM_MULTI_SELECT" : false, + "FLAG_2002_UNLIMITED_MAX" : true }, "type": "[FLAGS] Update" }, diff --git a/vid-webpack-master/cypress/integration/iFrames/viewOnlyDrawingBoard.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/viewOnlyDrawingBoard.e2e.ts index 688d42e94..d77460a69 100644 --- a/vid-webpack-master/cypress/integration/iFrames/viewOnlyDrawingBoard.e2e.ts +++ b/vid-webpack-master/cypress/integration/iFrames/viewOnlyDrawingBoard.e2e.ts @@ -331,7 +331,7 @@ describe('View only drawing board', function () { ['Model version', '2.0'], ['Model customization ID', '91415b44-753d-494c-926a-456a9172bbb9'], ['Min instances', '0'], - ['Max instances', '1'] + //['Max instances', '1'] ]; const extraLabelsAndValuesForInstance = [['Instance type', 'VNF2_INSTANCE_TYPE'],['In maintenance','true'], ['Instance ID', 'VNF2_INSTANCE_ID']]; testComponentInfoByType('node-VF_vGeraldine 0', labelsAndValuesForModel,'VNF INFO', diff --git a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json index 5e92e4f4b..531bad3b4 100644 --- a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json +++ b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json @@ -22,5 +22,6 @@ "FLAG_2004_TEMP_BUTTON_TO_INSTANTIATION_STATUS_FILTER": true, "FLAG_2004_INSTANTIATION_STATUS_FILTER": true, "FLAG_2004_INSTANTIATION_TEMPLATES_POPUP" : false, + "FLAG_2002_UNLIMITED_MAX" : true, "FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE": true } 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 index 3483885b5..50bfa936e 100644 --- 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 @@ -3,9 +3,10 @@ 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 {IModalConfig} from 'onap-ui-angular/dist/components/common'; import {AppState} from "../../../shared/store/reducers"; import {getTestBed, TestBed} from "@angular/core/testing"; +import {FeatureFlagsService} from "../../../shared/services/featureFlag/feature-flags.service"; class MockAppStore { getState(){ @@ -52,15 +53,23 @@ class MockAppStore { class MockModalService {} +class MockFeatureFlagsService extends FeatureFlagsService{ + getAllFlags(): { [p: string]: boolean } { + return {}; + } +} + describe('Drawing board tree service', () => { let injector; let service: DuplicateService; let store : NgRedux; + let featureFlagsService : FeatureFlagsService; beforeAll(done => (async () => { TestBed.configureTestingModule({ providers : [ DuplicateService, LogService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, {provide: NgRedux, useClass: MockAppStore}, {provide: SdcUiServices.ModalService, useClass: MockModalService} ] @@ -70,6 +79,7 @@ describe('Drawing board tree service', () => { injector = getTestBed(); service = injector.get(DuplicateService); store = injector.get(NgRedux); + featureFlagsService = injector.get(FeatureFlagsService); })().then(done).catch(done.fail)); @@ -417,6 +427,11 @@ describe('Drawing board tree service', () => { } } + } + }, + global : { + flags : { + } } } 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 index 5fb5f0b15..847790de9 100644 --- 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 @@ -11,15 +11,18 @@ import {TypeNodeInformation} from "../typeNodeInformation.model"; import {SdcUiCommon, SdcUiServices} 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"; +import {FeatureFlagsService} from "../../../shared/services/featureFlag/feature-flags.service"; +import {Utils} from "../../../shared/utils/utils"; @Injectable() export class DuplicateService { - constructor(private _logService : LogService, private _store: NgRedux, modalService: SdcUiServices.ModalService) { + constructor(private _logService: LogService, private _store: NgRedux, modalService: SdcUiServices.ModalService) { this.modalService = modalService; } - numberOfDuplicates:number; + numberOfDuplicates: number; + setNumberOfDuplicates(numberOfDuplicates: number) { this.numberOfDuplicates = numberOfDuplicates; } @@ -30,10 +33,9 @@ export class DuplicateService { storeKey: string = null; padding = '0000'; modalService: SdcUiServices.ModalService; - store : NgRedux; - existingNames : {[key: string] : any}; - currentNode : ITreeNode = null; - + store: NgRedux; + existingNames: { [key: string]: any }; + currentNode: ITreeNode = null; canDuplicate(node: ITreeNode): boolean { @@ -41,25 +43,31 @@ export class DuplicateService { return node.data.type === 'VF' || node.data.type === 'VL'; } - isEnabled(node: ITreeNode, store: NgRedux, 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; + isEnabled(node: ITreeNode, store: NgRedux, serviceId: string): boolean { + if (!_.isNil(node) && !_.isNil(node.data.menuActions['duplicate'])) { + if (this.hasMissingData(node)) return false; + const typeNodeInformation: TypeNodeInformation = new TypeNodeInformation(node); + const flags = FeatureFlagsService.getAllFlags(store); + const currentExisting: number = store.getState().service.serviceInstance[serviceId][typeNodeInformation.existingMappingCounterName][node.data.modelUniqueId]; + const maxInstances = Utils.getMaxFirstLevel(store.getState().service.serviceHierarchy[serviceId][typeNodeInformation.hierarchyName][node.data.modelName].properties, flags); + if (_.isNil(maxInstances)) { + return true; + } else { + return maxInstances - currentExisting > 0; + } - return max - currentExisting > 0; - }else { + } 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){ + 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; } } @@ -69,16 +77,22 @@ export class DuplicateService { return false; } - getRemainsInstance(modelId : string, modelName : string, serviceId : string, store: NgRedux, 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; + getRemainsInstance(modelId: string, modelName: string, serviceId: string, store: NgRedux, 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]; + + const flags = FeatureFlagsService.getAllFlags(store); + const maxInstances = Utils.getMaxFirstLevel(properties, flags); + if (_.isNil(maxInstances)) { + return 10; + } else { + return maxInstances - currentExisting; + } } - - openDuplicateModal(currentServiceId: string, currentUuid: string, currentId: string, storeKey : string, numberOfDuplicate: number, _store : NgRedux, node: ITreeNode): IModalConfig { + openDuplicateModal(currentServiceId: string, currentUuid: string, currentId: string, storeKey: string, numberOfDuplicate: number, _store: NgRedux, node: ITreeNode): IModalConfig { this.currentInstanceId = currentId; this.currentServiceId = currentServiceId; this.maxNumberOfDuplicate = this.getRemainsInstance(currentUuid, currentId, currentServiceId, _store, node); @@ -87,7 +101,7 @@ export class DuplicateService { this.currentNode = node; - return { + return { size: SdcUiCommon.ModalSize.medium, title: 'Duplicate Node', type: SdcUiCommon.ModalType.custom, @@ -98,12 +112,12 @@ export class DuplicateService { }; } - duplicate(node : ITreeNode): void { - const typeNodeInformation : TypeNodeInformation = new TypeNodeInformation(node); + 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]; + const toClone = this.store.getState().service.serviceInstance[this.currentServiceId][typeNodeInformation.hierarchyName][this.storeKey]; let newObjects = {}; - for(let i = 0; i < this.numberOfDuplicates; i++) { + 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; @@ -114,12 +128,12 @@ export class DuplicateService { } - cloneVnf(vnf : VnfInstance, originalName: string): VnfInstance { - let newUniqueVnf : VnfInstance = _.cloneDeep(vnf); + cloneVnf(vnf: VnfInstance, originalName: string): VnfInstance { + let newUniqueVnf: VnfInstance = _.cloneDeep(vnf); newUniqueVnf.originalName = originalName; newUniqueVnf.trackById = DefaultDataGeneratorService.createRandomTrackById(); - if (!_.isNil(vnf.instanceName)){ + if (!_.isNil(vnf.instanceName)) { newUniqueVnf.instanceName = this.ensureUniqueNameOrGenerateOne(vnf.instanceName); } @@ -127,10 +141,10 @@ export class DuplicateService { 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)){ + if (!_.isNil(vfModuleModel[vfModule].instanceName)) { newUniqueVnf.vfModules[vf_module_model_name][vfModule].instanceName = this.ensureUniqueNameOrGenerateOne(vfModuleModel[vfModule].instanceName); } - if (!_.isNil(vfModuleModel[vfModule].volumeGroupName)){ + if (!_.isNil(vfModuleModel[vfModule].volumeGroupName)) { newUniqueVnf.vfModules[vf_module_model_name][vfModule].volumeGroupName = this.ensureUniqueNameOrGenerateOne(vfModuleModel[vfModule].volumeGroupName); } } @@ -138,7 +152,7 @@ export class DuplicateService { return newUniqueVnf; } - ensureUniqueNameOrGenerateOne(instanceName){ + ensureUniqueNameOrGenerateOne(instanceName) { let uniqueInstanceName = instanceName; if (this.isAlreadyExists(instanceName, this.existingNames)) { uniqueInstanceName = this.generateNextUniqueName(instanceName, this.existingNames); @@ -148,33 +162,33 @@ export class DuplicateService { } - isAlreadyExists(name : string, existingNames : {[key: string] : any}){ + isAlreadyExists(name: string, existingNames: { [key: string]: any }) { return _.has(existingNames, name.toLowerCase()); } - generateNextUniqueName(name : string, existingNames : {[key: string] : any}) :string{ + generateNextUniqueName(name: string, existingNames: { [key: string]: any }): string { let suffix = "000"; let counter = 1; - if (name.match(/^.*_[\d]{3}$/)){ + if (name.match(/^.*_[\d]{3}$/)) { name = name.substring(0, name.length - 4); } - while(true){ - let paddingNumber : string = this.getNumberAsPaddingString(counter, suffix); + while (true) { + let paddingNumber: string = this.getNumberAsPaddingString(counter, suffix); let candidateUniqueName = name + '_' + paddingNumber; - if(!this.isAlreadyExists(candidateUniqueName, existingNames)){ + if (!this.isAlreadyExists(candidateUniqueName, existingNames)) { return candidateUniqueName; } counter++; } } - generateUniqueStoreKey(serviceId : string, objectName : string, existing : any, newObjects: any) : string { + generateUniqueStoreKey(serviceId: string, objectName: string, existing: any, newObjects: any): string { let counter = 1; - while(true){ - let paddingNumber : string = this.getNumberAsPaddingString(counter, this.padding); + while (true) { + let paddingNumber: string = this.getNumberAsPaddingString(counter, this.padding); const name = objectName + ':' + paddingNumber; - if(_.isNil(existing[name]) && _.isNil(newObjects[name])){ + if (_.isNil(existing[name]) && _.isNil(newObjects[name])) { return name; } counter++; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.spec.ts index 10c13661f..089f812a7 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.spec.ts @@ -12,6 +12,7 @@ import {DrawingBoardModes} from "../../../drawing-board.modes"; import {IframeService} from "../../../../../shared/utils/iframe.service"; import {DuplicateService} from "../../../duplicate/duplicate.service"; import {ModelInformationItem} from "../../../../../shared/components/model-information/model-information.component"; +import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; class MockAppStore { getState() { @@ -19,27 +20,27 @@ class MockAppStore { global: { 'drawingBoardStatus': DrawingBoardModes.CREATE }, - service : { - serviceHierarchy : { - 'servicedId' : { - 'networks' : { - 'networkName' : { - 'properties' : { - 'max_instances' : 1 + service: { + serviceHierarchy: { + 'servicedId': { + 'networks': { + 'networkName': { + 'properties': { + 'max_instances': 1 } } } } }, - serviceInstance : { - 'servicedId' : { - 'existingNetworksCounterMap' : { - 'networkId' : 1 + serviceInstance: { + 'servicedId': { + 'existingNetworksCounterMap': { + 'networkId': 1 }, - 'networks' : { - 'networkName' :{ + 'networks': { + 'networkName': { 'action': 'Create', - 'originalName' : 'networkName' + 'originalName': 'networkName' } } } @@ -48,15 +49,24 @@ class MockAppStore { } } } + +class MockFeatureFlagsService extends FeatureFlagsService { + getAllFlags(): { [p: string]: boolean } { + return {}; + } +} + + describe('Network Model Info', () => { let injector; - let _dynamicInputsService : DynamicInputsService; - let _sharedTreeService : SharedTreeService; + let _dynamicInputsService: DynamicInputsService; + let _sharedTreeService: SharedTreeService; let networkModel: NetworkModelInfo; - let _dialogService : DialogService; - let _networkPopupService : NetworkPopupService; - let _duplicateService : DuplicateService; - let _iframeService : IframeService; + let _dialogService: DialogService; + let _networkPopupService: NetworkPopupService; + let _duplicateService: DuplicateService; + let _iframeService: IframeService; + let _featureFlagsService: FeatureFlagsService; beforeAll(done => (async () => { TestBed.configureTestingModule({ @@ -69,13 +79,16 @@ describe('Network Model Info', () => { IframeService, DuplicateService, {provide: NgRedux, useClass: MockAppStore}, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, MockNgRedux] }); await TestBed.compileComponents(); injector = getTestBed(); _sharedTreeService = injector.get(SharedTreeService); - networkModel = new NetworkModelInfo(_dynamicInputsService, _sharedTreeService, _dialogService, _networkPopupService, _duplicateService, null, _iframeService, MockNgRedux.getInstance()); + _featureFlagsService = injector.get(FeatureFlagsService); + + networkModel = new NetworkModelInfo(_dynamicInputsService, _sharedTreeService, _dialogService, _networkPopupService, _duplicateService, null, _iframeService, _featureFlagsService, MockNgRedux.getInstance()); })().then(done).catch(done.fail)); test('NetworkModelInfo should be defined', () => { @@ -137,39 +150,37 @@ describe('Network Model Info', () => { expect(model.type).toEqual('VL'); }); - test('showNodeIcons should return false if reachLimit of max', ()=>{ - let serviceId : string = 'servicedId'; + test('showNodeIcons should return false if reachLimit of max', () => { + let serviceId: string = 'servicedId'; let node = { - data : { - id : 'networkId', - name : 'networkName', - modelCustomizationId : 'modelCustomizationId' + data: { + id: 'networkId', + name: 'networkName', + modelCustomizationId: 'modelCustomizationId' } }; jest.spyOn(_sharedTreeService, 'getExistingInstancesWithDeleteMode').mockReturnValue(0); jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ - global : {}, - service : { - serviceHierarchy : { - 'servicedId' : { - 'networks' : { - 'networkName' : { - 'properties' : { - 'max_instances' : 1 + global: {}, + service: { + serviceHierarchy: { + 'servicedId': { + 'networks': { + 'networkName': { + 'properties': { + 'max_instances': 1 } } } } }, - serviceInstance : { - 'servicedId' : { - 'existingNetworksCounterMap' : { - 'modelCustomizationId' : 1 + serviceInstance: { + 'servicedId': { + 'existingNetworksCounterMap': { + 'modelCustomizationId': 1 }, - 'networks' : { - 'networkName' :{ - - } + 'networks': { + 'networkName': {} } } } @@ -177,41 +188,39 @@ describe('Network Model Info', () => { }); let result = networkModel.showNodeIcons(node, serviceId); - expect(result).toEqual(new AvailableNodeIcons(true , false)); + expect(result).toEqual(new AvailableNodeIcons(true, false)); }); - test('showNodeIcons should return true if not reachLimit of max', ()=>{ - let serviceId : string = 'servicedId'; + test('showNodeIcons should return true if not reachLimit of max', () => { + let serviceId: string = 'servicedId'; let node = { - data : { - id : 'networkId', - name : 'networkName' + data: { + id: 'networkId', + name: 'networkName' } }; jest.spyOn(_sharedTreeService, 'getExistingInstancesWithDeleteMode').mockReturnValue(0); jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ - global : {}, - service : { - serviceHierarchy : { - 'servicedId' : { - 'networks' : { - 'networkName' : { - 'properties' : { - 'max_instances' : 2 + global: {}, + service: { + serviceHierarchy: { + 'servicedId': { + 'networks': { + 'networkName': { + 'properties': { + 'max_instances': 2 } } } } }, - serviceInstance : { - 'servicedId' : { - 'existingNetworksCounterMap' : { - 'networkId' : 1 + serviceInstance: { + 'servicedId': { + 'existingNetworksCounterMap': { + 'networkId': 1 }, - 'networks' : { - 'networkName' :{ - - } + 'networks': { + 'networkName': {} } } } @@ -219,34 +228,34 @@ describe('Network Model Info', () => { }); let result = networkModel.showNodeIcons(node, serviceId); - expect(result).toEqual(new AvailableNodeIcons(true , false)); + expect(result).toEqual(new AvailableNodeIcons(true, false)); }); - test('getNodeCount should return number of nodes', ()=>{ - let serviceId : string = 'servicedId'; + test('getNodeCount should return number of nodes', () => { + let serviceId: string = 'servicedId'; jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ - global : {}, - service : { - serviceHierarchy : { - 'servicedId' : { - 'networks' : { - 'networkName' : { - 'properties' : { - 'max_instances' : 1 + global: {}, + service: { + serviceHierarchy: { + 'servicedId': { + 'networks': { + 'networkName': { + 'properties': { + 'max_instances': 1 } } } } }, - serviceInstance : { - 'servicedId' : { - 'existingNetworksCounterMap' : { - 'modelCustomizationId' : 1 + serviceInstance: { + 'servicedId': { + 'existingNetworksCounterMap': { + 'modelCustomizationId': 1 }, - 'networks' : { - 'networkName' :{ + 'networks': { + 'networkName': { 'action': 'Create', - 'originalName' : 'networkName' + 'originalName': 'networkName' } } } @@ -255,24 +264,24 @@ describe('Network Model Info', () => { }); let node = { - data : { - id : 'networkId', - name : 'networkName', + data: { + id: 'networkId', + name: 'networkName', action: 'Create', - modelCustomizationId : "modelCustomizationId", + modelCustomizationId: "modelCustomizationId", modelUniqueId: "modelCustomizationId" } }; - let result = networkModel.getNodeCount(node , serviceId); + let result = networkModel.getNodeCount(node, serviceId); expect(result).toEqual(1); node.data.modelCustomizationId = 'networkId_notExist'; node.data.modelUniqueId = 'networkId_notExist'; - result = networkModel.getNodeCount(node , serviceId); + result = networkModel.getNodeCount(node, serviceId); expect(result).toEqual(0); }); - test('getMenuAction: showAuditInfoNetwork', ()=>{ + test('getMenuAction: showAuditInfoNetwork', () => { jest.spyOn(MockNgRedux.getInstance(), 'getState').mockReturnValue({ global: { @@ -281,7 +290,7 @@ describe('Network Model Info', () => { }); jest.spyOn(_sharedTreeService, 'isRetryMode').mockReturnValue(true); let node = { - data : { + data: { "modelId": "6b528779-44a3-4472-bdff-9cd15ec93450", "action": "Create", "isFailed": true, @@ -300,7 +309,7 @@ describe('Network Model Info', () => { test('Info for network should be correct', () => { const model = getNetworkModel(); const instance = getNetworkInstance(); - let actualNetworkInfo = networkModel.getInfo(model,instance); + let actualNetworkInfo = networkModel.getInfo(model, instance); let expectedNetworkInfo = [ ModelInformationItem.createInstance('Network role', "network role 1, network role 2"), ModelInformationItem.createInstance("Route target id", null), @@ -309,26 +318,27 @@ describe('Network Model Info', () => { expect(actualNetworkInfo).toEqual(expectedNetworkInfo); }); - function getNetworkModel(){ + function getNetworkModel() { return { - "customizationUuid":"94fdd893-4a36-4d70-b16a-ec29c54c184f", - "name":"ExtVL", - "version":"37.0", - "description":"ECOMP generic virtual link (network) base type for all other service-level and global networks", - "uuid":"ddc3f20c-08b5-40fd-af72-c6d14636b986", - "invariantUuid":"379f816b-a7aa-422f-be30-17114ff50b7c", - "max":1, - "min":0, - "isEcompGeneratedNaming":false, - "type":"VL", - "modelCustomizationName":"ExtVL 0", - "roles":["network role 1"," network role 2"], - "properties":{ - "network_role":"network role 1, network role 2", + "customizationUuid": "94fdd893-4a36-4d70-b16a-ec29c54c184f", + "name": "ExtVL", + "version": "37.0", + "description": "ECOMP generic virtual link (network) base type for all other service-level and global networks", + "uuid": "ddc3f20c-08b5-40fd-af72-c6d14636b986", + "invariantUuid": "379f816b-a7aa-422f-be30-17114ff50b7c", + "max": 1, + "min": 0, + "isEcompGeneratedNaming": false, + "type": "VL", + "modelCustomizationName": "ExtVL 0", + "roles": ["network role 1", " network role 2"], + "properties": { + "network_role": "network role 1, network role 2", "network_assignments": "{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}", - "exVL_naming":"{ecomp_generated_naming=true}","network_flows":"{is_network_policy=false, is_bound_to_vpn=false}", - "network_homing":"{ecomp_selected_instance_node_target=false}" + "exVL_naming": "{ecomp_generated_naming=true}", + "network_flows": "{is_network_policy=false, is_bound_to_vpn=false}", + "network_homing": "{ecomp_selected_instance_node_target=false}" } }; @@ -370,9 +380,7 @@ describe('Network Model Info', () => { } - - - function getServiceHierarchy(){ + function getServiceHierarchy() { return { "service": { "uuid": "6b528779-44a3-4472-bdff-9cd15ec93450", diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts index 3ed40cd5f..3ba4a2c4b 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/network/network.model.info.ts @@ -30,6 +30,7 @@ import { import {IModalConfig} from "onap-ui-angular/dist/modals/models/modal-config"; import {ComponentInfoType} from "../../../component-info/component-info-model"; import {ModelInformationItem} from "../../../../../shared/components/model-information/model-information.component"; +import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; export class NetworkModelInfo implements ILevelNodeInfo { constructor(private _dynamicInputsService: DynamicInputsService, @@ -39,6 +40,7 @@ export class NetworkModelInfo implements ILevelNodeInfo { private _duplicateService: DuplicateService, private modalService: SdcUiServices.ModalService, private _iframeService: IframeService, + private _featureFlagsService: FeatureFlagsService, private _store: NgRedux) { } @@ -70,7 +72,7 @@ export class NetworkModelInfo implements ILevelNodeInfo { ************************************************************/ getModel = (networkModelId: string, instance: NetworkInstance, serviceHierarchy): NetworkModel => { const originalModelName = instance.originalName ? instance.originalName : networkModelId; - return new NetworkModel(serviceHierarchy[this.name][originalModelName]); + return new NetworkModel(serviceHierarchy[this.name][originalModelName], this._featureFlagsService.getAllFlags()); }; @@ -164,8 +166,8 @@ export class NetworkModelInfo implements ILevelNodeInfo { counter -= this._sharedTreeService.getExistingInstancesWithDeleteMode(node, serviceModelId, 'networks'); const properties = this._store.getState().service.serviceHierarchy[serviceModelId].networks[node.data.name].properties; - const maxInstances: number = !_.isNil(properties) ? (properties.max_instances || 1) : 1; - const isReachedLimit = !(maxInstances > counter); + const flags = FeatureFlagsService.getAllFlags(this._store); + const isReachedLimit: boolean = this._sharedTreeService.isReachedToMaxInstances(properties, counter, flags); const showAddIcon = this._sharedTreeService.shouldShowAddIcon() && !isReachedLimit; return new AvailableNodeIcons(showAddIcon, isReachedLimit) diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts index eb9902f7c..225d84b4c 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.spec.ts @@ -28,6 +28,12 @@ class MockAppStore { } } +class MockFeatureFlagsService extends FeatureFlagsService{ + getAllFlags(): { [p: string]: boolean } { + return {}; + } +} + describe('VFModule Model Info', () => { let injector; let _dynamicInputsService : DynamicInputsService; @@ -38,6 +44,8 @@ describe('VFModule Model Info', () => { let _vfModuleUpgradePopupService : VfModuleUpgradePopupService; let _iframeService : IframeService; let _componentInfoService : ComponentInfoService; + let _featureFlagsService : FeatureFlagsService; + beforeAll(done => (async () => { TestBed.configureTestingModule({ @@ -54,7 +62,7 @@ describe('VFModule Model Info', () => { AaiService, HttpClient, HttpHandler, - FeatureFlagsService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, ComponentInfoService ] }); @@ -63,7 +71,8 @@ describe('VFModule Model Info', () => { injector = getTestBed(); _sharedTreeService = injector.get(SharedTreeService); _componentInfoService = injector.get(ComponentInfoService) - vfModuleModel = new VFModuleModelInfo(_dynamicInputsService, _sharedTreeService, _dialogService, _vfModulePopupService, _vfModuleUpgradePopupService, _iframeService, MockNgRedux.getInstance(),_componentInfoService); + _featureFlagsService = injector.get(FeatureFlagsService); + vfModuleModel = new VFModuleModelInfo(_dynamicInputsService, _sharedTreeService, _dialogService, _vfModulePopupService, _vfModuleUpgradePopupService, _iframeService,_featureFlagsService, MockNgRedux.getInstance(),_componentInfoService); })().then(done).catch(done.fail)); diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts index 5e14586c5..e182b8a6f 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vfModule/vfModule.model.info.ts @@ -40,6 +40,7 @@ export class VFModuleModelInfo implements ILevelNodeInfo { private _vfModulePopupService: VfModulePopuopService, private _vfModuleUpgradePopupService: VfModuleUpgradePopupService, private _iframeService: IframeService, + private _featureFlagsService: FeatureFlagsService, private _store: NgRedux, private _componentInfoService: ComponentInfoService) { } @@ -306,7 +307,6 @@ export class VFModuleModelInfo implements ILevelNodeInfo { maxNodes = vnfModules[node.data.name].properties.maxCountInstances || 1; } return !(maxNodes > currentNodeCount); - } getMenuAction(node: ITreeNode, serviceModelId: string): { [methodName: string]: { method: Function, visible: Function, enable: Function } } { diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.spec.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.spec.ts index 3af42884d..d89280f0a 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.spec.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.spec.ts @@ -23,6 +23,11 @@ import {AaiService} from "../../../../../shared/services/aaiService/aai.service" import {HttpClient, HttpHandler} from "@angular/common/http"; import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; import {VfModuleUpgradePopupService} from "../../../../../shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service"; +class MockFeatureFlagsService extends FeatureFlagsService{ + getAllFlags(): { [p: string]: boolean } { + return {}; + } +} describe('Vnf Model Info', () => { let injector; @@ -38,6 +43,7 @@ describe('Vnf Model Info', () => { let _duplicateService : DuplicateService; let _iframeService : IframeService; let _componentInfoService : ComponentInfoService; + let _featureFlagsService : FeatureFlagsService; let _store : NgRedux; let vnfModel: VnfModelInfo; @@ -57,7 +63,7 @@ describe('Vnf Model Info', () => { AaiService, HttpClient, HttpHandler, - FeatureFlagsService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, ComponentInfoService, IframeService] }).compileComponents(); @@ -65,7 +71,7 @@ describe('Vnf Model Info', () => { injector = getTestBed(); _sharedTreeService = injector.get(SharedTreeService); _store = injector.get(NgRedux); - _componentInfoService = injector.get(ComponentInfoService); + _featureFlagsService = injector.get(FeatureFlagsService); vnfModel = new VnfModelInfo( _dynamicInputsService, @@ -79,6 +85,7 @@ describe('Vnf Model Info', () => { null, _iframeService, _componentInfoService, + _featureFlagsService, _store); diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts index 05d4af18d..c1255f57c 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vnf/vnf.model.info.ts @@ -39,6 +39,7 @@ import {ComponentInfoType} from "../../../component-info/component-info-model"; import {ComponentInfoService} from "../../../component-info/component-info.service"; import {ModelInformationItem} from "../../../../../shared/components/model-information/model-information.component"; import {VfModuleUpgradePopupService} from "../../../../../shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service"; +import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; export class VnfModelInfo implements ILevelNodeInfo { constructor(private _dynamicInputsService: DynamicInputsService, @@ -47,11 +48,12 @@ export class VnfModelInfo implements ILevelNodeInfo { private _dialogService: DialogService, private _vnfPopupService: VnfPopupService, private _vfModulePopupService: VfModulePopuopService, - private _vfModuleUpgradePopupService : VfModuleUpgradePopupService, + private _vfModuleUpgradePopupService: VfModuleUpgradePopupService, private _duplicateService: DuplicateService, private modalService: SdcUiServices.ModalService, private _iframeService: IframeService, private _componentInfoService: ComponentInfoService, + private _featureFlagsService: FeatureFlagsService, private _store: NgRedux) { } @@ -87,7 +89,7 @@ export class VnfModelInfo implements ILevelNodeInfo { ************************************************************/ getModel = (vnfModelId: string, instance: VnfInstance, serviceHierarchy): VNFModel => { const originalModelName = instance.originalName ? instance.originalName : vnfModelId; - return new VNFModel(serviceHierarchy[this.name][originalModelName]); + return new VNFModel(serviceHierarchy[this.name][originalModelName], this._featureFlagsService.getAllFlags()); }; @@ -104,7 +106,7 @@ export class VnfModelInfo implements ILevelNodeInfo { node.typeName = this.typeName; node.menuActions = this.getMenuAction(node, model.uuid); node.isFailed = _.isNil(instance.isFailed) ? false : instance.isFailed; - node.statusMessage = !_.isNil(instance.statusMessage) ? instance.statusMessage: ""; + node.statusMessage = !_.isNil(instance.statusMessage) ? instance.statusMessage : ""; node = this._sharedTreeService.addingStatusProperty(node); return node; }; @@ -113,7 +115,7 @@ export class VnfModelInfo implements ILevelNodeInfo { * return next level object (VFModule) ************************************************************/ getNextLevelObject = (): VFModuleModelInfo => { - return new VFModuleModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._vfModulePopupService, this._vfModuleUpgradePopupService, this._iframeService, this._store, this._componentInfoService); + return new VFModuleModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._vfModulePopupService, this._vfModuleUpgradePopupService, this._iframeService, this._featureFlagsService, this._store, this._componentInfoService); }; /*********************************************************** @@ -181,8 +183,8 @@ export class VnfModelInfo implements ILevelNodeInfo { counter -= this._sharedTreeService.getExistingInstancesWithDeleteMode(node, serviceModelId, 'vnfs'); const properties = this._store.getState().service.serviceHierarchy[serviceModelId].vnfs[node.data.name].properties; - const maxInstances: number = !_.isNil(properties) ? (properties.max_instances || 1) : 1; - const isReachedLimit = !(maxInstances > counter); + const flags = FeatureFlagsService.getAllFlags(this._store); + const isReachedLimit: boolean = this._sharedTreeService.isReachedToMaxInstances(properties, counter, flags); const showAddIcon = this._sharedTreeService.shouldShowAddIcon() && !isReachedLimit; return new AvailableNodeIcons(showAddIcon, isReachedLimit) } @@ -211,9 +213,9 @@ export class VnfModelInfo implements ILevelNodeInfo { }, showAuditInfo: { method: (node, serviceModelId) => { - const instance = this._store.getState().service.serviceInstance[serviceModelId].vnfs[node.data.vnfStoreKey]; - this._sharedTreeService.openAuditInfoModal(node, serviceModelId, instance, 'VNF', this); - }, + const instance = this._store.getState().service.serviceInstance[serviceModelId].vnfs[node.data.vnfStoreKey]; + this._sharedTreeService.openAuditInfoModal(node, serviceModelId, instance, 'VNF', this); + }, visible: (node) => this._sharedTreeService.shouldShowAuditInfo(node), enable: (node) => this._sharedTreeService.shouldShowAuditInfo(node) }, @@ -324,8 +326,8 @@ export class VnfModelInfo implements ILevelNodeInfo { getInfo(model, instance): ModelInformationItem[] { const modelInformation = !_.isEmpty(model) ? [ - ModelInformationItem.createInstance("Min instances", !_.isNull(model.min)? String(model.min): null), - ModelInformationItem.createInstance("Max instances", !_.isNull(model.max)? String(model.max): null) + ModelInformationItem.createInstance("Min instances", !_.isNull(model.min) ? String(model.min) : null), + ModelInformationItem.createInstance("Max instances", !_.isNull(model.max) ? String(model.max) : null) ] : []; const instanceInfo = !_.isEmpty(instance) ? [ diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrf.model.info.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrf.model.info.ts index 4c779a313..3dbc60adb 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrf.model.info.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/models/vrf/vrf.model.info.ts @@ -26,12 +26,14 @@ import { undoDeleteActionVrfInstance } from "../../../../../shared/storeUtil/utils/vrf/vrf.actions"; import * as _ from "lodash"; +import {FeatureFlagsService} from "../../../../../shared/services/featureFlag/feature-flags.service"; export class VrfModelInfo implements ILevelNodeInfo { constructor(private _store: NgRedux, private _sharedTreeService: SharedTreeService, private _dialogService: DialogService, private _iframeService: IframeService, + private _featureFlagsService : FeatureFlagsService, private _networkStepService: NetworkStepService, private _vpnStepService: VpnStepService) { } @@ -70,7 +72,7 @@ export class VrfModelInfo implements ILevelNodeInfo { return new VpnModelInfo(this._store, this._sharedTreeService); } else { if (nextLevelType === 'networks') { - return new NetworkModelInfo(null, this._sharedTreeService, null, null, null, null, null, this._store); + return new NetworkModelInfo(null, this._sharedTreeService, null, null, null, null, null,this._featureFlagsService, this._store); } } }; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.ts index c101f44e9..75ae1e149 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToModelTree/objectToModelTree.service.ts @@ -3,11 +3,13 @@ import {ILevelNodeInfo} from "../models/basic.model.info"; import {ObjectToTreeService} from "../objectToTree.service"; import * as _ from "lodash"; import {IModelTreeNodeModel} from "../../../objectsToTree/objectToModelTree/modelTreeNode.model"; +import {FeatureFlagsService} from "../../../../shared/services/featureFlag/feature-flags.service"; @Injectable() export class ObjectToModelTreeService { numberOfPlusButton: number; - constructor(private _objectToTreeService: ObjectToTreeService) { + + constructor(private _objectToTreeService: ObjectToTreeService, private _featureFlagsService: FeatureFlagsService) { } /*********************************************************** @@ -18,9 +20,10 @@ export class ObjectToModelTreeService { let _this = this; const firstLevelOptions: ILevelNodeInfo[] = _this._objectToTreeService.getFirstLevelOptions(); let nodes = []; + let flags = this._featureFlagsService.getAllFlags(); for (let option of firstLevelOptions) { _.forOwn(serviceModel[option.name], function (item, key) { - nodes.push(_this.addFirstLevelModel(serviceModel.service.uuid, key, item, item.type, serviceModel, option)); + nodes.push(_this.addFirstLevelModel(serviceModel.service.uuid, key, item, item.type, serviceModel, option, flags)); }); } @@ -30,10 +33,10 @@ export class ObjectToModelTreeService { return nodes; } - calculateNumberOfNodesWithPlusIcon(serviceModel, nodes) : void { - this.numberOfPlusButton = nodes.reduce((sum, node)=>{ - let showNodeIconResult = node.showNodeIcons({data : node}, serviceModel.service.uuid); - return (!_.isNil(showNodeIconResult) && showNodeIconResult.addIcon && !showNodeIconResult.vIcon) ? sum + 1 : sum; + calculateNumberOfNodesWithPlusIcon(serviceModel, nodes): void { + this.numberOfPlusButton = nodes.reduce((sum, node) => { + let showNodeIconResult = node.showNodeIcons({data: node}, serviceModel.service.uuid); + return (!_.isNil(showNodeIconResult) && showNodeIconResult.addIcon && !showNodeIconResult.vIcon) ? sum + 1 : sum; }, 0); } @@ -47,9 +50,9 @@ export class ObjectToModelTreeService { * @param parentModel - current parent Model object * @param levelNodeInfo - current level node information ************************************************************/ - private addFirstLevelModel(serviceId: string, name, currentModel, type, parentModel, levelNodeInfo: ILevelNodeInfo) { - let node = ObjectToModelTreeService.convertItemToTreeNode(serviceId, name, currentModel, type, null, levelNodeInfo); - node.children = this.addNextLevelNodes(serviceId, currentModel, parentModel, levelNodeInfo, node); + private addFirstLevelModel(serviceId: string, name, currentModel, type, parentModel, levelNodeInfo: ILevelNodeInfo, flags?: { [key: string]: boolean }) { + let node = ObjectToModelTreeService.convertItemToTreeNode(serviceId, name, currentModel, type, null, levelNodeInfo, flags); + node.children = this.addNextLevelNodes(serviceId, currentModel, parentModel, levelNodeInfo, node, flags); return node; } @@ -61,13 +64,13 @@ export class ObjectToModelTreeService { * @param levelNodeInfo - current level node information * @param parentNode - parent node. ************************************************************/ - addNextLevelNodes(serviceId: string, currentModel, parentModel, levelNodeInfo: ILevelNodeInfo, parentNode): any[] { + addNextLevelNodes(serviceId: string, currentModel, parentModel, levelNodeInfo: ILevelNodeInfo, parentNode, flags?: { [key: string]: boolean }): any[] { if (!_.isNil(levelNodeInfo.childNames) && levelNodeInfo.childNames.length > 0) { levelNodeInfo.childNames.forEach(function (childName) { if (!_.isNil(currentModel[childName])) { let nextLevelNodeInfo = levelNodeInfo.getNextLevelObject.apply(this, [childName]); parentNode.children = Object.keys(currentModel[childName]).map((key) => - ObjectToModelTreeService.convertItemToTreeNode(serviceId, key, currentModel[childName][key], childName, currentModel, nextLevelNodeInfo)); + ObjectToModelTreeService.convertItemToTreeNode(serviceId, key, currentModel[childName][key], childName, currentModel, nextLevelNodeInfo, flags)); } }) } @@ -84,17 +87,18 @@ export class ObjectToModelTreeService { * @param parentModel - current parent model * @param levelNodeInfo - current levelNodeInfo object ************************************************************/ - static convertItemToTreeNode(serviceId: string, name: string, currentModel: any, valueType: string, parentModel: string, levelNodeInfo: ILevelNodeInfo) { - let node : IModelTreeNodeModel = { + static convertItemToTreeNode(serviceId: string, name: string, currentModel: any, valueType: string, parentModel: string, levelNodeInfo: ILevelNodeInfo, flags?: { [key: string]: boolean }) { + const type: string = levelNodeInfo.getType(); + let node: IModelTreeNodeModel = { id: currentModel.customizationUuid || currentModel.uuid, - modelCustomizationId : currentModel.customizationUuid, - modelVersionId: currentModel.uuid, - modelUniqueId : currentModel.customizationUuid || currentModel.uuid, + modelCustomizationId: currentModel.customizationUuid, + modelVersionId: currentModel.uuid, + modelUniqueId: currentModel.customizationUuid || currentModel.uuid, name: name, tooltip: levelNodeInfo.getTooltip(), - type: levelNodeInfo.getType(), + type, count: currentModel.count || 0, - max: currentModel.max || 1, + max: ObjectToModelTreeService.getMax(currentModel, type, flags), children: [], disabled: false, dynamicInputs: levelNodeInfo.updateDynamicInputsDataFromModel(currentModel), @@ -105,15 +109,24 @@ export class ObjectToModelTreeService { return node; } + static getMax(currentModel, type, flags: { [key: string]: boolean }) { + if (flags && !!flags['FLAG_2002_UNLIMITED_MAX'] && (type === 'VF' || type === 'Network' || type === 'VFmodule')) { + return !_.isNil(currentModel.max) ? currentModel.max : null; + } else { + return currentModel.max || 1 + } + } - static addExtraFunctionality(node, serviceId: string, name: string, currentModel: any, valueType: string, parentModel: string, levelNodeInfo: ILevelNodeInfo){ + + static addExtraFunctionality(node, serviceId: string, name: string, currentModel: any, valueType: string, parentModel: string, levelNodeInfo: ILevelNodeInfo) { node.onAddClick = (node, serviceId) => levelNodeInfo.onClickAdd(node, serviceId); node.getNodeCount = (node, serviceId) => levelNodeInfo.getNodeCount(node, serviceId); node.getMenuAction = (node, serviceId) => levelNodeInfo.getMenuAction(node, serviceId); node.showNodeIcons = (node, serviceId) => levelNodeInfo.showNodeIcons(node, serviceId); node.typeName = levelNodeInfo.typeName; node.getModel = levelNodeInfo.getModel.bind(levelNodeInfo); - node.getInfo = !_.isNil(levelNodeInfo.getInfo) ? levelNodeInfo.getInfo.bind(levelNodeInfo) : ()=>{}; + node.getInfo = !_.isNil(levelNodeInfo.getInfo) ? levelNodeInfo.getInfo.bind(levelNodeInfo) : () => { + }; node.componentInfoType = levelNodeInfo.componentInfoType; return node; } diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts index 443741ff9..1e6825130 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/objectToTree.service.ts @@ -25,6 +25,7 @@ import {VrfModelInfo} from "./models/vrf/vrf.model.info"; import {NetworkStepService} from "./models/vrf/vrfModal/networkStep/network.step.service"; import {VpnStepService} from "./models/vrf/vrfModal/vpnStep/vpn.step.service"; import { VfModuleUpgradePopupService } from "../../../shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service"; +import {FeatureFlagsService} from "../../../shared/services/featureFlag/feature-flags.service"; @Injectable() export class ObjectToTreeService { @@ -44,6 +45,7 @@ export class ObjectToTreeService { private _networkStepService : NetworkStepService, private _vpnStepService : VpnStepService, private _aaiService : AaiService, + private _featureFlagsService: FeatureFlagsService, private _store : NgRedux) { } @@ -54,10 +56,10 @@ export class ObjectToTreeService { * return all first optional first level of the model tree ************************************************************/ getFirstLevelOptions(): ILevelNodeInfo[] { - return [new VnfModelInfo(this._dynamicInputsService, this._sharedTreeService, this._defaultDataGeneratorService, this._dialogService, this._vnfPopupService, this._vfModulePopupService, this._vfModuleUpgradePopupService,this._duplicateService, this._modalService, this._iframeService, this._componentInfoService, this._store) - , new NetworkModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._networkPopupService, this._duplicateService, this._modalService, this._iframeService, this._store), + return [new VnfModelInfo(this._dynamicInputsService, this._sharedTreeService, this._defaultDataGeneratorService, this._dialogService, this._vnfPopupService, this._vfModulePopupService, this._vfModuleUpgradePopupService,this._duplicateService, this._modalService, this._iframeService, this._componentInfoService, this._featureFlagsService, this._store) + , new NetworkModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._networkPopupService, this._duplicateService, this._modalService, this._iframeService, this._featureFlagsService, this._store), new PnfModelInfo(), - new VrfModelInfo(this._store, this._sharedTreeService, this._dialogService, this._iframeService, this._networkStepService, this._vpnStepService), + new VrfModelInfo(this._store, this._sharedTreeService, this._dialogService, this._iframeService, this._featureFlagsService, this._networkStepService, this._vpnStepService), new CollectionResourceModelInfo(this._store, this._sharedTreeService), new ConfigurationModelInfo(this._dynamicInputsService, this._sharedTreeService), new VnfGroupingModelInfo(this._dynamicInputsService, this._sharedTreeService, this._dialogService, this._vnfGroupPopupService, this._iframeService, this._aaiService, this._store)]; diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts index c56cc4999..b8eddbbf7 100644 --- a/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts +++ b/vid-webpack-master/src/app/drawingBoard/service-planning/objectsToTree/shared.tree.service.ts @@ -13,6 +13,7 @@ import {ModelInformationItem} from "../../../shared/components/model-information import {undoUpgradeService, upgradeService} from "../../../shared/storeUtil/utils/service/service.actions"; import {VNFMethods} from "../../../shared/storeUtil/utils/vnf/vnf.actions"; import {FeatureFlagsService, Features} from "../../../shared/services/featureFlag/feature-flags.service"; +import {Utils} from "../../../shared/utils/utils"; @Injectable() export class SharedTreeService { @@ -239,6 +240,16 @@ export class SharedTreeService { const mode = this._store.getState().global.drawingBoardStatus; return mode === DrawingBoardModes.EDIT || mode=== DrawingBoardModes.CREATE; } + + + isReachedToMaxInstances(properties, counter, flags): boolean{ + let maxInstances = Utils.getMaxFirstLevel(properties, flags); + if(_.isNil(maxInstances)){ + return false; + }else { + return !(maxInstances > counter); + } + } /************************************************ return number of instances with action Delete @type: vnfs networks, vngGroups (not vfModule) diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.ts index 5d4d16567..c18b20d7e 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.ts @@ -10,6 +10,7 @@ import * as _ from 'lodash'; import {VfModule} from "../../../models/vfModule"; import {VNFModel} from "../../../models/vnfModel"; import {VnfGroupModel} from "../../../models/vnfGroupModel"; +import {FeatureFlagsService} from "../../../services/featureFlag/feature-flags.service"; @Injectable() export class BasicPopupService { @@ -29,17 +30,18 @@ export class BasicPopupService { } getModelFromResponse(result: any, modelType: string, modelName: string) { + let flags = FeatureFlagsService.getAllFlags(this._store); let rawModel = result[modelType][modelName]; if (!rawModel) return; switch (modelType){ case 'vnfs' : { - return new VNFModel(rawModel); + return new VNFModel(rawModel, flags); } case 'vfModules' : { return new VfModule(rawModel); } case 'networks' : { - return new NetworkModel(rawModel); + return new NetworkModel(rawModel, flags); } case 'vnfGroups' : { return new VnfGroupModel(rawModel); diff --git a/vid-webpack-master/src/app/shared/models/networkModel.ts b/vid-webpack-master/src/app/shared/models/networkModel.ts index 03f118eb7..b4879a59d 100644 --- a/vid-webpack-master/src/app/shared/models/networkModel.ts +++ b/vid-webpack-master/src/app/shared/models/networkModel.ts @@ -2,29 +2,30 @@ import { Level1Model, Level1ModelProperties, Level1ModelResponseInterface } from "./nodeModel"; -import {VfcInstanceGroupMap} from "./vfcInstanceGroupMap"; +import {Utils} from "../utils/utils"; -export interface NetworkProperties extends Level1ModelProperties{ +export interface NetworkProperties extends Level1ModelProperties { ecomp_generated_naming: string; network_role: string; } -export interface NetworkModelResponseInterface extends Level1ModelResponseInterface{ +export interface NetworkModelResponseInterface extends Level1ModelResponseInterface { properties: NetworkProperties; } -export class NetworkModel extends Level1Model{ +export class NetworkModel extends Level1Model { roles: string[] = []; properties: NetworkProperties; - constructor(networkJson?: NetworkModelResponseInterface){ + constructor(networkJson?: NetworkModelResponseInterface, flags?: { [key: string]: boolean }) { super(networkJson); - if(networkJson && networkJson.properties){ + if (networkJson && networkJson.properties) { this.properties = networkJson.properties; // expecting network_role to be a comma-saparated list this.roles = networkJson.properties.network_role ? networkJson.properties.network_role.split(',') : []; + this.max = Utils.getMaxFirstLevel(this.properties, flags); } } diff --git a/vid-webpack-master/src/app/shared/models/vnfModel.ts b/vid-webpack-master/src/app/shared/models/vnfModel.ts index 8389606b6..220dc0fc5 100644 --- a/vid-webpack-master/src/app/shared/models/vnfModel.ts +++ b/vid-webpack-master/src/app/shared/models/vnfModel.ts @@ -3,25 +3,24 @@ import { Level1ModelProperties, Level1ModelResponseInterface } from "./nodeModel"; +import {Utils} from "../utils/utils"; - - -export interface VnfProperties extends Level1ModelProperties{ +export interface VnfProperties extends Level1ModelProperties { ecomp_generated_naming: string; } -export interface VNFModelResponseInterface extends Level1ModelResponseInterface{ +export interface VNFModelResponseInterface extends Level1ModelResponseInterface { properties: VnfProperties; } -export class VNFModel extends Level1Model{ +export class VNFModel extends Level1Model { properties: VnfProperties; - constructor(vnfJson?: VNFModelResponseInterface) { + constructor(vnfJson?: VNFModelResponseInterface, flags?: { [key: string]: boolean }) { super(vnfJson); if (vnfJson) { this.properties = vnfJson.properties; + this.max = Utils.getMaxFirstLevel(this.properties, flags); } } - } diff --git a/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts b/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts index 7e0575b68..74fcd8f87 100644 --- a/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts +++ b/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts @@ -27,6 +27,14 @@ export class FeatureFlagsService { return FeatureFlagsService.getFlagState(flag, this.store); } + public getAllFlags(): { [key: string]: boolean}{ + return this.store.getState().global.flags; + } + + public static getAllFlags(store: NgRedux): { [key: string]: boolean}{ + return store.getState().global.flags; + } + /*static method for easy refactoring of code, so no injection of FeatureFlagsService is needed*/ public static getFlagState(flag: Features, store: NgRedux):boolean { let storeStateGlobalFields = store.getState().global; diff --git a/vid-webpack-master/src/app/shared/utils/utils.ts b/vid-webpack-master/src/app/shared/utils/utils.ts index cb5e1a1c8..cd7ebdff6 100644 --- a/vid-webpack-master/src/app/shared/utils/utils.ts +++ b/vid-webpack-master/src/app/shared/utils/utils.ts @@ -2,6 +2,14 @@ import * as _ from 'lodash' export class Utils { + static getMaxFirstLevel(properties, flags: { [key: string]: boolean }) : number | null{ + if (flags && !!flags['FLAG_2002_UNLIMITED_MAX']) { + return !_.isNil(properties) && !_.isNil(properties.max_instances) ? properties.max_instances : null; + } else { + return properties.max_instances || 1; + } + } + public static clampNumber = (number, min, max) => { return Math.max(min, Math.min(number, max)); }; -- 2.16.6