diff options
author | Sonsino, Ofir (os0695) <os0695@intl.att.com> | 2018-07-10 15:57:37 +0300 |
---|---|---|
committer | Sonsino, Ofir (os0695) <os0695@intl.att.com> | 2018-07-10 15:57:37 +0300 |
commit | ff76b5ed0aa91d5fdf9dc4f95e8b20f91ed9d072 (patch) | |
tree | aae42404a93fdffdd16ff050eaa28129959f7577 /vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details | |
parent | c72d565bb58226b20625b2bce5f0019046bee649 (diff) |
New Angular UI from 1806
Change-Id: I39c160db0e0a6ec2e587ccf007ee1b23c6a08666
Issue-ID: VID-208
Signed-off-by: Sonsino, Ofir (os0695) <os0695@intl.att.com>
Diffstat (limited to 'vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details')
6 files changed, 784 insertions, 0 deletions
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 000000000..725e44293 --- /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 000000000..ccdaac53b --- /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 000000000..080540a57 --- /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 000000000..41ddb4372 --- /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 000000000..677895e72 --- /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 000000000..9a2694c70 --- /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 = []; + } +} |