diff options
Diffstat (limited to 'vid-webpack-master/src/app/shared')
70 files changed, 2585 insertions, 717 deletions
diff --git a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts index 07f4d481b..a7b8ac744 100644 --- a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts +++ b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts @@ -3,18 +3,20 @@ import {HighlightPipe} from "../../pipes/highlight/highlight-filter.pipe"; import * as _ from 'lodash'; @Component({ - selector : 'custom-ellipsis', + selector: 'custom-ellipsis', template: ` <span - sdc-tooltip - class="ellipsis" - id="{{id}}" - [innerHtml]="displayValue | safe : 'html'" - [ngClass]="{'breakWord' : breakWord == true}" - [tooltip-text]="value"> + sdc-tooltip + class="ellipsis" + [attr.data-tests-id]="dataTestId" + id="{{id}}" + [innerHtml]="displayValue | safe : 'html'" + [ngStyle]="{'white-space' : showDots ? 'nowrap' : 'initial'}" + [ngClass]="{'breakWord' : breakWord == true}" + [tooltip-text]="value"> </span>`, - styles : [ - ` + styles: [ + ` .ellipsis { white-space: nowrap; overflow: hidden; @@ -23,30 +25,33 @@ import * as _ from 'lodash'; width: 99%; text-align: left; } - + .breakWord { word-wrap: break-word; white-space: normal; } ` ], - providers : [HighlightPipe] + providers: [HighlightPipe] }) -export class EllipsisComponent implements OnChanges{ - @Input() value : string; - @Input() id : string; - @Input() hightlight : string; - @Input() breakWord : boolean = false; +export class EllipsisComponent implements OnChanges { + @Input() value: string; + @Input() id: string; + @Input() hightlight: string; + @Input() breakWord: boolean = false; + @Input() dataTestId: string; + @Input() showDots: boolean = false; + + displayValue: string; - displayValue : string; - constructor(private _highlightPipe : HighlightPipe){ + constructor(private _highlightPipe: HighlightPipe) { this.displayValue = this.value; } ngOnChanges(changes: SimpleChanges): void { this.displayValue = this.value; - if(!_.isNil(this.hightlight)){ - this.displayValue = this._highlightPipe.transform(this.value ,this.hightlight ? this.hightlight : ''); + if (!_.isNil(this.hightlight)) { + this.displayValue = this._highlightPipe.transform(this.value, this.hightlight ? this.hightlight : ''); } } } diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.html b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.html index f7c4894b2..f205259e4 100644 --- a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.html +++ b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.html @@ -1,16 +1,26 @@ -<div> - <div class="details-item" *ngIf="data != null && form != null"> - <label [ngClass]="{'required': data.isRequired()}" - for="{{data?.dataTestId}}">{{data?.displayName}}:</label> - <angular2-multiselect id="{{data?.dataTestId}}" - [attr.data-tests-id]="data?.dataTestId" - [formControl]="form.controls[data.controlName]" - [(ngModel)]="data.selectedItems" - [data]="data?.options$" - [settings]="data?.settings" - title="{{data.tooltip}}" - [ngClass]="{'error-style' : form?.controls[data?.controlName]?.touched && form?.controls[data?.controlName]?.errors}"> - </angular2-multiselect> - </div> -</div> +<div class="details-item" *ngIf="data != null && form != null"> + <label [ngClass]="{'required': data.isRequired()}" + for="{{data?.dataTestId}}-select">{{data?.displayName}}:</label> + + <angular2-multiselect + [attr.data-tests-id]="data?.dataTestId" + [data]="options" + [(ngModel)]="selectedItems" + [settings]="dropdownSettings" + (onSelect)="onItemSelect($event)" + (onDeSelect)="OnItemDeSelect($event)" + (onSelectAll)="onSelectAll($event)" + (onDeSelectAll)="onDeSelectAll($event)">> + <c-item> + <ng-template let-item="item"> + <label + [attr.data-tests-id]="data.dataTestId + '-' + item?.itemName" + style="color: #333;min-width: 150px;">{{item?.itemName}}</label> + </ng-template> + </c-item> + </angular2-multiselect> + + <form-control-error *ngIf="data?.hasEmptyOptions && data?.isRequired()" + [message]="'No results for this request. Please change criteria.'"></form-control-error> +</div> diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.spec.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.spec.ts deleted file mode 100644 index 81c8d4679..000000000 --- a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core' -import {CommonModule} from "@angular/common"; -import {FormBuilder, FormControl, ReactiveFormsModule, Validators} from "@angular/forms"; -import { - ValidatorModel, - ValidatorOptions -} from "../../../../models/formControlModels/formControl.model"; -import {FormControlMessageErrorComponent} from "../../errorMessage/formControlMessageError.component"; -import {BrowserModule} from "@angular/platform-browser"; -import {MultiselectFormControlComponent} from "./multiselect.formControl.component"; -import {MultiselectFormControl} from "../../../../models/formControlModels/multiselectFormControl.model"; -import { of } from "rxjs"; -describe('Dropdown Form Control Component', () => { - let component: MultiselectFormControlComponent; - let fixture: ComponentFixture<MultiselectFormControlComponent>; - let fb: FormBuilder; - - beforeAll(done => (async () => { - TestBed.configureTestingModule({ - imports: [CommonModule, BrowserModule, ReactiveFormsModule], - providers: [FormBuilder], - declarations: [MultiselectFormControlComponent, FormControlMessageErrorComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }); - await TestBed.compileComponents(); - - fixture = TestBed.createComponent(MultiselectFormControlComponent); - component = fixture.componentInstance; - fb = TestBed.get(FormBuilder); - - })().then(done).catch(done.fail)); - - test('component should initialize basic parameters', () => { - component.data = new MultiselectFormControl({ - displayName: "display Name", - validations: [new ValidatorModel(ValidatorOptions.required, 'is required')], - dataTestId: "data-test-id", - placeHolder: "place holder", - controlName: 'testDropdown', - options: of([ - 'option1', - 'option2', - 'option3', - 'onBlur' - ]) - }); - - component.data.hasErrors = function () { - return this.formGroup.controls[this.controlName].touched && this.formGroup.controls[this.controlName].errors ? ['error-style'] : []; - }; - - component.data.onBlur = function () { - component.form.controls['testDropdown'].setValue('onBlur'); - }; - - component.form = fb.group({ - 'testDropdown': new FormControl({ - value: component.data.value, - disabled: false - }, Validators.compose(component.data.validations.map(item => item.validator))) - }); - - component.form.controls['testDropdown'].setValue(''); - expect(component.form.controls['testDropdown'].errors.required).toBeTruthy(); - component.form.controls['testDropdown'].setValue('option2'); - expect(component.form.controls['testDropdown'].errors).toBeFalsy(); - component.data.onBlur(); - expect(component.form.controls['testDropdown'].value).toEqual('onBlur'); - expect(component.form.controls['testDropdown'].errors).toBeFalsy(); - } - ) -}); - diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.ts index 4b98c7e26..26a55e9d2 100644 --- a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.ts +++ b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.ts @@ -1,6 +1,8 @@ import {Component, Input, OnChanges, SimpleChanges} from "@angular/core"; import {FormGroup} from "@angular/forms"; import {MultiselectFormControl} from "../../../../models/formControlModels/multiselectFormControl.model"; +import {MultiselectFormControlService} from "./multiselect.formControl.service"; +import {MultiSelectItem} from "./multiselect.model"; @Component({ selector: 'multiselect-form-control', @@ -8,13 +10,54 @@ import {MultiselectFormControl} from "../../../../models/formControlModels/multi }) export class MultiselectFormControlComponent implements OnChanges{ @Input() data: MultiselectFormControl = null; + @Input() multiselectOptions: [] = null; + @Input() selectedItems = []; @Input() form: FormGroup = null; - ngOnChanges(changes: SimpleChanges): void { + + multiselectFormControlService : MultiselectFormControlService; + constructor(private _multiselectFormControlService : MultiselectFormControlService){ + this.multiselectFormControlService = _multiselectFormControlService; + } + + dropdownSettings = { + singleSelection : false, + limitSelection : 1000 + }; + + options : MultiSelectItem[]; + + + + async ngOnChanges(changes: SimpleChanges) { + if(this.data.options$){ + this._multiselectFormControlService.convertOriginalItems(this.data).then((options)=>{ + this.options = options; + this._multiselectFormControlService.convertSelectedItems(this.data).then((res)=> { + this.selectedItems = res; + this.form.controls[this.data.controlName].setValue(this.selectedItems); + }) + }); + } if (changes["data"] !== undefined && changes["data"].currentValue !== changes["data"].previousValue && changes["data"].firstChange) { - if(this.data.onInit){ + if (this.data.onInit) { + this.dropdownSettings.limitSelection = this.data.limitSelection; this.data.onInit(this.data, this.form); } } } + + onItemSelect(item:any){ + this.data.onChange(this.selectedItems ,this.form); + } + OnItemDeSelect(item:any){ + this.data.onChange(this.selectedItems ,this.form); + } + onSelectAll(items: any){ + this.data.onChange(this.selectedItems ,this.form); + } + onDeSelectAll(items: any){ + this.data.onChange(this.selectedItems ,this.form); + } } + diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.spec.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.spec.ts new file mode 100644 index 000000000..3c3c344a3 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.spec.ts @@ -0,0 +1,159 @@ +import {async, getTestBed, TestBed} from '@angular/core/testing'; +import {MultiselectFormControlService} from "./multiselect.formControl.service"; +import {MultiselectFormControl} from "../../../../models/formControlModels/multiselectFormControl.model"; +import {MultiSelectItem} from "./multiselect.model"; + +describe('Multi Select Form Control Service', () => { + + let injector; + let service: MultiselectFormControlService; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [], + providers: [MultiselectFormControlService] + }); + await TestBed.compileComponents(); + injector = getTestBed(); + service = injector.get(MultiselectFormControlService); + })().then(done).catch(done.fail)); + + + const options = [ + { + id: 'A', + name: 'a' + }, + { + id: 'B', + name: 'b', + keepMe: -42 + }, + { + id: 'C', + name: 'c' + } + ], + selectedFieldName = 'name', + ngValue = 'id'; + + + test('convertOriginalItems should convert options array to <MultiSelectItem> list', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: options + }; + + service.convertOriginalItems(control).then((result: MultiSelectItem[]) => { + expect(result).toEqual([ + {"id": 1, "itemId": 'A', "itemName": 'a'}, + {"id": 2, "itemId": 'B', "itemName": 'b'}, + {"id": 3, "itemId": 'C', "itemName": 'c'} + ]); + }); + })); + + test('convertOriginalItems should return empty list when options list is empty', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: [] + }; + + service.convertOriginalItems(control).then((result) => { + expect(result).toEqual([]); + }); + })); + + test('convertOptionsToHashMap - should convert any object to hash map with ngValue', async(() => { + + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: options + }; + + let map = service.convertOptionsToHashMap(control); + + expect(Object.keys(map)).toHaveLength(3); + expect(map).toEqual({ + 'A': { + id: 'A', + name: 'a', + index: 1 + }, + 'B': { + id: 'B', + name: 'b', + keepMe: -42, + index: 2 + }, + 'C': { + id: 'C', + name: 'c', + index: 3 + } + + }) + })); + + test('convertOptionsToHashMap - should convert any object to hash map with ngValue: empty options', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: [] + }; + + let map = service.convertOptionsToHashMap(control); + + expect(Object.keys(map)).toHaveLength(0) + })); + + test('convertSelectedItems - should convert select item to multi select list', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: options, + value: ['A', 'C'] + }; + + service.convertSelectedItems(control).then((selectedOptions) => { + expect(selectedOptions).toHaveLength(2); + expect(selectedOptions[0].itemName).toEqual('a'); + expect(selectedOptions[1].itemName).toEqual('c'); + }) + })); + + test('convertSelectedItems - should convert select item to multi select list with special convert function', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: options, + value: 'A,C', + convertOriginalDataToArray: (value) => { + return value.split(','); + } + }; + + service.convertSelectedItems(control).then((selectedOptions) => { + expect(selectedOptions).toHaveLength(2); + expect(selectedOptions[0].itemName).toEqual('a'); + expect(selectedOptions[1].itemName).toEqual('c'); + }) + })); + + + test('convertSelectedItems - should return empty list iof value is empty list', async(() => { + let control: MultiselectFormControl = <any>{ + ngValue, + selectedFieldName, + options$: options, + value: [] + }; + + service.convertSelectedItems(control).then((selectedOptions) => { + expect(selectedOptions).toHaveLength(0); + }) + })); +}); diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.ts new file mode 100644 index 000000000..0b50f4d28 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.ts @@ -0,0 +1,50 @@ +import {Injectable} from "@angular/core"; +import {MultiselectFormControl} from "../../../../models/formControlModels/multiselectFormControl.model"; +import {MultiSelectItem} from "./multiselect.model"; +import * as _ from "lodash"; + + +@Injectable() +export class MultiselectFormControlService { + + convertOriginalItems = (control : MultiselectFormControl) : Promise<MultiSelectItem[]> => { + return new Promise<MultiSelectItem[]>((resolve) =>{ + let result: MultiSelectItem[] = []; + if(control.options$) { + let index: number = 1; + control.options$.map((originalItems: any) => { + result.push(new MultiSelectItem(index, originalItems[control.ngValue], originalItems[control.selectedFieldName])); + index++; + }); + } + resolve(result); + }) + }; + + + convertOptionsToHashMap = (config : MultiselectFormControl) => { + let index = 1; + return _.reduce(config.options$ , (obj, param: any ) => { + param.index = index; + index++; + obj[param[config.ngValue]] = param; + return obj; + }, {}); + }; + + convertSelectedItems(control : MultiselectFormControl) : Promise<MultiSelectItem[]>{ + return new Promise<MultiSelectItem[]>((resolve) =>{ + let result: MultiSelectItem[] = []; + const hashMap = this.convertOptionsToHashMap(control); + + if(control.options$ && control.value) { + const convertArray = control.convertOriginalDataToArray ? control.convertOriginalDataToArray(control.value) : control.value; + convertArray.map((itemId) => { + const uniqueIdentifier = itemId.trim(); + result.push(new MultiSelectItem(hashMap[uniqueIdentifier].index, hashMap[uniqueIdentifier][control.ngValue], hashMap[uniqueIdentifier][control.selectedFieldName])); + }); + } + resolve(result); + }); + } +} diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.model.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.model.ts new file mode 100644 index 000000000..a495211d4 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.model.ts @@ -0,0 +1,11 @@ +export class MultiSelectItem { + id : number; + itemId : number; + itemName : string; + + constructor(genericId: number, itemId : number, itemName : string){ + this.id = genericId; + this.itemId = itemId; + this.itemName = itemName; + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.spec.ts index fc2eed4ae..077d849e6 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.spec.ts @@ -5,6 +5,7 @@ import {FeatureFlagsService} from "../../../services/featureFlag/feature-flags.s import {BasicControlGenerator} from "./basic.control.generator"; import {NgRedux} from '@angular-redux/store'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; +import {FileFormControl} from "../../../models/formControlModels/fileFormControl.model"; class MockAppStore<T> {} @@ -44,5 +45,41 @@ describe('Basic Control Generator', () => { const legacyRegionControl: FormControlModel = service.getLegacyRegion(instance); expect(legacyRegionControl.isVisible).toBeFalsy(); }); + + test('sdn-preload checkbox is visible', () => { + const instance = {}; + const sdncPreload: FormControlModel = service.getSDNCControl(instance); + expect (sdncPreload.displayName).toEqual('SDN-C pre-load'); + expect (sdncPreload.value).toBeFalsy(); + }); + + test('given instance, get supp file from getSupplementaryFile ', () => { + const instance = {}; + const suppFileForInstance: FileFormControl = service.getSupplementaryFile(instance); + expect(suppFileForInstance.isVisible).toBeTruthy(); + expect(suppFileForInstance.hiddenFile.length).toBeGreaterThanOrEqual(1); + expect(suppFileForInstance.hiddenFile[0].validations[0].validatorName).toEqual("isFileTooBig"); + }); + + test('concatSupplementaryFile add SupplementaryFile control and hidden file', () => { + + //given + const instance = {}; + const controls = [service.getLegacyRegion(instance)]; + expect(controls).toHaveLength(1); + + //when + const result = service.concatSupplementaryFile(controls, instance); + + //then + expect(controls).toHaveLength(1); //original controls remain the same + + expect(result.map((control) => {return control.controlName})).toEqual([ + "legacyRegion", + "supplementaryFile", + "supplementaryFile_hidden", + "supplementaryFile_hidden_content" + ]); + }); }); diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.ts index cbbff3c39..7ab64753a 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/basic.control.generator.ts @@ -1,12 +1,7 @@ import {Injectable} from "@angular/core"; import {DropdownFormControl} from "../../../models/formControlModels/dropdownFormControl.model"; import {FormGroup} from "@angular/forms"; -import { - CustomValidatorOptions, - FormControlModel, - ValidatorModel, - ValidatorOptions -} from "../../../models/formControlModels/formControl.model"; +import {CustomValidatorOptions, FormControlModel, ValidatorModel, ValidatorOptions} from "../../../models/formControlModels/formControl.model"; import {InputFormControl} from "../../../models/formControlModels/inputFormControl.model"; import {AppState} from "../../../store/reducers"; import {NgRedux} from "@angular-redux/store"; @@ -21,7 +16,11 @@ import {FormGeneralErrorsService} from "../../formGeneralErrors/formGeneralError import {Observable, of} from "rxjs"; import {NodeModel} from "../../../models/nodeModel"; import {Constants} from "../../../utils/constants"; +import {FileUnit} from "../../formControls/component/file/fileUnit.enum"; +import {CheckboxFormControl} from "../../../models/formControlModels/checkboxFormControl.model"; +export const SUPPLEMENTARY_FILE = 'supplementaryFile'; +export const SDN_C_PRE_LOAD = 'sdncPreLoad'; @Injectable() export class BasicControlGenerator { @@ -237,4 +236,71 @@ export class BasicControlGenerator { return initialInstanceName; } + concatSupplementaryFile(originalArray: FormControlModel[], vfModuleInstance): FormControlModel[] { + let suppFileInput: FileFormControl = <FileFormControl>(this.getSupplementaryFile(vfModuleInstance)); + return originalArray.concat([suppFileInput], suppFileInput.hiddenFile); + } + + getSDNCControl = (instance: any): FormControlModel => { + return new CheckboxFormControl({ + controlName: SDN_C_PRE_LOAD, + displayName: 'SDN-C pre-load', + dataTestId: 'sdncPreLoad', + value: instance ? instance.sdncPreLoad : false, + validations: [new ValidatorModel(ValidatorOptions.required, 'is required')] + }) + }; + + getSupplementaryFile(instance: any): FileFormControl { + return new FileFormControl({ + controlName: SUPPLEMENTARY_FILE, + displayName: 'Supplementary Data File (JSON format)', + dataTestId: 'SupplementaryFile', + placeHolder: 'Choose file', + selectedFile: !_.isNil(instance) ? instance.supplementaryFileName: null, + isVisible: true, + acceptedExtentions: "application/json", + hiddenFile : [new InputFormControl({ + controlName: SUPPLEMENTARY_FILE + "_hidden", + isVisible: false, + validations: [new ValidatorModel(CustomValidatorOptions.isFileTooBig, "File size exceeds 5MB.", [FileUnit.MB, 5])] + }), + new InputFormControl({ + controlName: SUPPLEMENTARY_FILE + "_hidden_content", + isVisible: false, + validations: [new ValidatorModel(CustomValidatorOptions.isValidJson, + "File is invalid, please make sure a legal JSON file is uploaded using name:value pairs.",[]), + new ValidatorModel(CustomValidatorOptions.isStringContainTags, + "File is invalid, please remove tags <>.",[])], + value: !_.isNil(instance) ? (instance.supplementaryFile_hidden_content): null, + }) + ], + onDelete : this.getOnDeleteForSupplementaryFile(), + onChange : this.getOnChangeForSupplementaryFile() + }) + }; + + private getOnDeleteForSupplementaryFile() { + return (form: FormGroup) => { + form.controls[SUPPLEMENTARY_FILE + "_hidden"].setValue(null); + form.controls[SUPPLEMENTARY_FILE + "_hidden_content"].setValue(null); + }; + } + + private getOnChangeForSupplementaryFile() { + return (files: FileList, form: FormGroup) => { + if (files.length > 0) { + const file = files.item(0); + let reader = new FileReader(); + reader.onload = function (event) { + form.controls[SUPPLEMENTARY_FILE + "_hidden_content"].setValue(reader.result); + form.controls[SUPPLEMENTARY_FILE + "_hidden"].setValue(file); + }; + reader.readAsText(file); + } else { + form.controls[SUPPLEMENTARY_FILE + "_hidden"].setValue(null); + form.controls[SUPPLEMENTARY_FILE + "_hidden_content"].setValue(null); + } + }; + } } diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/networkGenerator/network.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/networkGenerator/network.control.generator.spec.ts index 5b64aea9b..0bb278a8e 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/networkGenerator/network.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/networkGenerator/network.control.generator.spec.ts @@ -7,11 +7,7 @@ import {GenericFormService} from "../../generic-form.service"; import {FormBuilder} from "@angular/forms"; import {LogService} from "../../../../utils/log/log.service"; import {FormControlNames, NetworkControlGenerator} from "./network.control.generator"; -import { - FormControlModel, - ValidatorModel, - ValidatorOptions -} from "../../../../models/formControlModels/formControl.model"; +import {FormControlModel, ValidatorModel, ValidatorOptions} from "../../../../models/formControlModels/formControl.model"; import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; class MockAppStore<T> { @@ -25,9 +21,6 @@ class MockAppStore<T> { "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/service.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/service.control.generator.spec.ts index a6a29d1df..6bcec09c4 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/service.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/service.control.generator.spec.ts @@ -25,9 +25,6 @@ class MockAppStore<T> { "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts index 351f8393c..deb1a784a 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts @@ -1,18 +1,16 @@ import {getTestBed, TestBed} from '@angular/core/testing'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; import {NgRedux} from '@angular-redux/store'; -import {BasicControlGenerator} from "../basic.control.generator"; +import {BasicControlGenerator, SDN_C_PRE_LOAD} from "../basic.control.generator"; import {AaiService} from "../../../../services/aaiService/aai.service"; import {GenericFormService} from "../../generic-form.service"; import {FormBuilder} from "@angular/forms"; import {LogService} from "../../../../utils/log/log.service"; -import { - FormControlModel, - ValidatorModel, - ValidatorOptions -} from "../../../../models/formControlModels/formControl.model"; +import {FormControlModel, ValidatorModel, ValidatorOptions} from "../../../../models/formControlModels/formControl.model"; import {FormControlNames, VfModuleControlGenerator} from "./vfModule.control.generator"; import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; +import {VfModuleInstance} from "../../../../models/vfModuleInstance"; +import {VfModule} from "../../../../models/vfModule"; class MockAppStore<T> { getState() { @@ -25,9 +23,6 @@ class MockAppStore<T> { "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -978,6 +973,46 @@ describe('VFModule Control Generator', () => { } }); + + const cases = [ + [true, true, true, null, true, true], + [true, true, false, null, true, false], //Scenario to check that UI field doesn't appear. + [false, true, false, "vf_vgeraldine0..VfVgeraldine..base_vflorence..module-0_vol", true, true], + [false, true, true, "vf_vgeraldine0..VfVgeraldine..base_vflorence..module-0_vol", true, true], + [false, false, true, null, false, false], + ]; + + test.each(cases)('Given Ecomp Gen Name: %p and VG Name %p , ' + + 'is A La Carte %p - expect the name value for VG to be %p , ' + + 'VG Name should be defined: %p , and should the field be visible: %p', + (ecomGenName, vGName, isALaCarte, expectedName, shouldWeVerifyDefinitionOfField, isVisible) => { + const moduleName = "vf_vgeraldine0..VfVgeraldine..base_vflorence..module-0"; + service.vfModuleModel = new VfModule(); + service.vfModuleModel.name = moduleName; + service.vfModuleModel.volumeGroupAllowed = vGName; + let vnf : Object = {isEcompGeneratedNaming: ecomGenName}; + const serviceId: string = "6e59c5de-f052-46fa-aa7e-2fca9d674c44"; + const vnfStoreKey: string = 'VF_vGeraldine 0'; + const uuidData: Object = { + modelName : moduleName, + vFModuleStoreKey : "vf_vgeraldine0..VfVgeraldine..base_vflorence..module-0vmvzo", + }; + const vfModuleModel :VfModuleInstance = service.getVfModuleInstance(serviceId, vnfStoreKey, uuidData,true); + let existingMatchingFieldInForm = buildVfModuleFormControlModel(vfModuleModel ,serviceId, vnf, isALaCarte); + if (shouldWeVerifyDefinitionOfField) { + expect(existingMatchingFieldInForm).toBeDefined(); + expect(existingMatchingFieldInForm.value).toEqual(expectedName); + expect(existingMatchingFieldInForm.isVisible).toEqual(isVisible); + } else { + expect(existingMatchingFieldInForm).toBeUndefined(); + } + }); + + let buildVfModuleFormControlModel = function(vfModuleModel :any, serviceId: string, vnf, isALaCarte) :FormControlModel { + let controls: FormControlModel[] = service.pushInstanceAndVGToForm([], vfModuleModel, serviceId, vnf, isALaCarte); + return controls.find(ctrl => ctrl.controlName === FormControlNames.VOLUME_GROUP_NAME); + }; + test('getMacroFormControls check for mandatory controls', () => { const serviceId: string = "6e59c5de-f052-46fa-aa7e-2fca9d674c44"; const vnfStoreKey: string = 'VF_vGeraldine 0'; @@ -1022,7 +1057,7 @@ describe('VFModule Control Generator', () => { FormControlNames.LEGACY_REGION, FormControlNames.TENANT_ID, FormControlNames.ROLLBACK_ON_FAILURE, - FormControlNames.SDN_C_PRE_LOAD + SDN_C_PRE_LOAD, ]; expect(controls.length).toEqual(7); @@ -1057,7 +1092,7 @@ describe('VFModule Control Generator', () => { FormControlNames.TENANT_ID, // TENANT_ID must be after LEGACY_REGION FormControlNames.LEGACY_REGION, FormControlNames.ROLLBACK_ON_FAILURE, - FormControlNames.SDN_C_PRE_LOAD + SDN_C_PRE_LOAD, ]; for(let i = 0 ; i < orderedControls.length ; i++) { @@ -1114,7 +1149,7 @@ describe('VFModule Control Generator', () => { FormControlNames.LEGACY_REGION, FormControlNames.TENANT_ID, FormControlNames.ROLLBACK_ON_FAILURE, - FormControlNames.SDN_C_PRE_LOAD + SDN_C_PRE_LOAD, ]; for(let i = 0 ; i < orderedControls.length ; i++) { diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts index 3012c139c..8919c0419 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts @@ -37,8 +37,6 @@ export enum FormControlNames { LEGACY_REGION = 'legacyRegion', TENANT_ID = 'tenantId', ROLLBACK_ON_FAILURE = 'rollbackOnFailure', - SDN_C_PRE_LOAD = 'sdncPreLoad', - SUPPLEMENTARY_FILE = 'supplementaryFile' } @@ -46,7 +44,6 @@ export enum FormControlNames { export class VfModuleControlGenerator { aaiService: AaiService; vfModuleModel: VfModule; - vfModuleName : string; isUpdateMode : boolean; constructor(private genericFormService: GenericFormService, @@ -63,7 +60,6 @@ export class VfModuleControlGenerator { const vfModulesKeys = Object.keys(vfModules); for(let key of vfModulesKeys){ if(vfModules[key].uuid === vfModuleUuid){ - this.vfModuleName = key; return; } } @@ -105,15 +101,18 @@ export class VfModuleControlGenerator { let result: FormControlModel[] = []; if (!_.isNil(vfModuleModel)) { - result.push(this.getInstanceName(vfModuleInstance, serviceId, vnfModel.isEcompGeneratedNaming)); - if (this.vfModuleModel.volumeGroupAllowed) { - result.push(this.getVolumeGroupName(vfModuleInstance, serviceId, vnfStoreKey, vfModuleInstance && vfModuleInstance.volumeGroupName, vnfModel.isEcompGeneratedNaming)); - } + result = this.pushInstanceAndVGToForm(result, vfModuleInstance, serviceId, vnfModel, false); } if(this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { - let suppFileInput:FileFormControl = <FileFormControl>(this.getSupplementaryFile(vfModuleInstance)); - result.push(suppFileInput); - result = result.concat(suppFileInput.hiddenFile); + result = this._basicControlGenerator.concatSupplementaryFile(result, vfModuleInstance); + } + return result; + } + + pushInstanceAndVGToForm(result: FormControlModel[], vfModuleElement: any, serviceId: string, vnfModel: any, isALaCarte: boolean) :FormControlModel[]{ + result.push(this.getInstanceName(vfModuleElement, serviceId, vnfModel.isEcompGeneratedNaming)); + if (this.vfModuleModel.volumeGroupAllowed) { + result.push(this.getVolumeGroupData(vfModuleElement, serviceId, vnfModel.isEcompGeneratedNaming, isALaCarte)); } return result; } @@ -133,23 +132,16 @@ export class VfModuleControlGenerator { const vfModuleInstance = this.getVfModuleInstance(serviceId, vnfStoreKey, uuidData, isUpdateMode); let result: FormControlModel[] = []; - result.push(this.getInstanceName(vfModuleInstance, serviceId, vnfModel.isEcompGeneratedNaming)); - - if (this.vfModuleModel.volumeGroupAllowed) { - result.push(this.getVolumeGroupName(vfModuleInstance, serviceId, vnfStoreKey, this.vfModuleName, vnfModel.isEcompGeneratedNaming)); - } + this.pushInstanceAndVGToForm(result, vfModuleInstance, serviceId, vnfModel, true); result.push(this.getLcpRegionControl(serviceId, vfModuleInstance, result)); result.push(this._basicControlGenerator.getLegacyRegion(vfModuleInstance)); result.push(this.getTenantControl(serviceId, vfModuleInstance, result)); result.push(this.getRollbackOnFailureControl(vfModuleInstance, result)); - result.push(this.getSDNCControl(vfModuleInstance, result)); + result.push(this._basicControlGenerator.getSDNCControl(vfModuleInstance)); if(this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { - let suppFileInput:FileFormControl = <FileFormControl>(this.getSupplementaryFile(vfModuleInstance)); - result.push(suppFileInput); - result = result.concat(suppFileInput.hiddenFile); + result = this._basicControlGenerator.concatSupplementaryFile(result, vfModuleInstance); } return result; - } getInstanceName(instance: any, serviceId: string, isEcompGeneratedNaming: boolean): FormControlModel { @@ -163,7 +155,7 @@ export class VfModuleControlGenerator { return formControlModel; } - getDefaultVolumeGroupName(instance: any, vfModuleName: string, isEcompGeneratedNaming: boolean): string { + getDefaultVolumeGroupName(instance: any, isEcompGeneratedNaming: boolean): string { if ((!_.isNil(instance) && instance.volumeGroupName)) { return instance.volumeGroupName; } @@ -173,7 +165,7 @@ export class VfModuleControlGenerator { return this._basicControlGenerator.getDefaultInstanceName(instance, this.vfModuleModel) + "_vol"; } - getVolumeGroupName(instance: any, serviceId: string, vnfStoreKey: string, vfModuleName: string, isEcompGeneratedNaming: boolean): FormControlModel { + getVolumeGroupData(instance: any, serviceId: string, isEcompGeneratedNaming: boolean, isALaCarte: boolean): FormControlModel { let validations: ValidatorModel[] = [ new ValidatorModel(ValidatorOptions.pattern, 'Instance name may include only alphanumeric characters and underscore.', BasicControlGenerator.INSTANCE_NAME_REG_EX), new ValidatorModel(CustomValidatorOptions.uniqueInstanceNameValidator, 'Volume Group instance name is already in use, please pick another name', [this.store, serviceId, instance && instance.volumeGroupName]) @@ -190,8 +182,8 @@ export class VfModuleControlGenerator { validations: validations, tooltip : 'When filled, VID will create a Volume Group by this name and associate with this module.\n' + 'When empty, the module is created without a Volume Group.', - isVisible: true, - value: this.getDefaultVolumeGroupName(instance, vfModuleName, isEcompGeneratedNaming), + isVisible: this.shouldVGNameBeVisible(isEcompGeneratedNaming,isALaCarte), + value: this.getDefaultVolumeGroupName(instance, isEcompGeneratedNaming), onKeypress: (event) => { const pattern:RegExp = BasicControlGenerator.INSTANCE_NAME_REG_EX; if (pattern) { @@ -204,51 +196,13 @@ export class VfModuleControlGenerator { }); } - getSupplementaryFile(instance: any): FormControlModel { - return new FileFormControl({ - controlName: FormControlNames.SUPPLEMENTARY_FILE, - displayName: 'Supplementary Data File (JSON format)', - dataTestId: 'SupplementaryFile', - placeHolder: 'Choose file', - selectedFile: !_.isNil(instance) ? instance.supplementaryFileName: null, - isVisible: true, - acceptedExtentions: "application/json", - hiddenFile : [new InputFormControl({ - controlName: FormControlNames.SUPPLEMENTARY_FILE + "_hidden", - isVisible: false, - validations: [new ValidatorModel(CustomValidatorOptions.isFileTooBig, "File size exceeds 5MB.", [FileUnit.MB, 5])] - }), - new InputFormControl({ - controlName: FormControlNames.SUPPLEMENTARY_FILE + "_hidden_content", - isVisible: false, - validations: [new ValidatorModel(CustomValidatorOptions.isValidJson, - "File is invalid, please make sure a legal JSON file is uploaded using name:value pairs.",[]), - new ValidatorModel(CustomValidatorOptions.isStringContainTags, - "File is invalid, please remove tags <>.",[])], - value: !_.isNil(instance) ? (instance.supplementaryFile_hidden_content): null, - }) - ], - onDelete : (form : FormGroup) => { - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden"].setValue(null); - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden_content"].setValue(null); - }, - onChange : (files: FileList, form : FormGroup) => { - if (files.length > 0) { - const file = files.item(0); - let reader = new FileReader(); - reader.onload = function(event) { - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden_content"].setValue(reader.result); - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden"].setValue(file); - }; - reader.readAsText(file); - } - else { - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden"].setValue(null); - form.controls[FormControlNames.SUPPLEMENTARY_FILE + "_hidden_content"].setValue(null); - } - } - }) - }; + private shouldVGNameBeVisible(isEcompGeneratedNaming: boolean, isALaCarte: boolean) { + if((!isALaCarte && !isEcompGeneratedNaming) || isALaCarte){ + return true; + } + return false; + + } getTenantControl = (serviceId: string, instance: any, controls: FormControlModel[]): DropdownFormControl => { const service = this.store.getState().service.serviceInstance[serviceId]; @@ -316,17 +270,6 @@ export class VfModuleControlGenerator { }) }; - getSDNCControl = (instance: any, controls: FormControlModel[]): CheckboxFormControl => { - return new CheckboxFormControl({ - type: FormControlType.CHECKBOX, - controlName: 'sdncPreLoad', - displayName: 'SDN-C pre-load', - dataTestId: 'sdncPreLoad', - value: instance ? instance.sdncPreLoad : false, - validations: [new ValidatorModel(ValidatorOptions.required, 'is required')] - }) - }; - getRollbackOnFailureControl = (instance: any, controls: FormControlModel[]): DropdownFormControl => { return new DropdownFormControl({ type: FormControlType.DROPDOWN, diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts index 66afac9ad..28d49d51b 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts @@ -6,16 +6,13 @@ import {BasicControlGenerator} from "../basic.control.generator"; import {AaiService} from "../../../../services/aaiService/aai.service"; import {GenericFormService} from "../../generic-form.service"; import {FormBuilder} from "@angular/forms"; -import { - FormControlModel, - ValidatorModel, - ValidatorOptions -} from "../../../../models/formControlModels/formControl.model"; +import {FormControlModel, ValidatorModel, ValidatorOptions} from "../../../../models/formControlModels/formControl.model"; import {LogService} from "../../../../utils/log/log.service"; import {VnfControlGenerator} from "./vnf.control.generator"; import {Observable} from "rxjs"; import {SelectOption} from "../../../../models/selectOption"; import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; +import {FormControlType} from "../../../../models/formControlModels/formControlTypes.enum"; class MockAppStore<T> { getState(){ @@ -28,9 +25,6 @@ class MockAppStore<T> { "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -941,6 +935,18 @@ describe('VNF Control Generator', () => { })().then(done).catch(done.fail)); + test('should generate platform multi select control', ()=>{ + const control = service.getPlatformMultiselectControl(null, [],false); + expect(control.type).toEqual(FormControlType.MULTI_SELECT); + expect(control.controlName).toEqual('platformName'); + expect(control.displayName).toEqual('Platform'); + expect(control.dataTestId).toEqual('multi-selectPlatform'); + expect(control.selectedFieldName).toEqual('name'); + expect(control.value).toEqual(''); + expect(control.onChange).toBeDefined(); + expect(control.convertOriginalDataToArray).toBeDefined(); + }); + test('getMacroFormControls check for mandatory controls', () => { const serviceId : string = "6e59c5de-f052-46fa-aa7e-2fca9d674c44"; const vnfName : string = "VF_vGeraldine 0"; diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.ts index 7760ba8ad..ff0a525b5 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.ts @@ -15,11 +15,12 @@ import {AppState} from "../../../../store/reducers"; import {FormGroup} from "@angular/forms"; import {DropdownFormControl} from "../../../../models/formControlModels/dropdownFormControl.model"; import {FormControlType} from "../../../../models/formControlModels/formControlTypes.enum"; -import {InputFormControl} from "../../../../models/formControlModels/inputFormControl.model"; import {Observable, of} from "rxjs"; import {SelectOption} from "../../../../models/selectOption"; import * as _ from 'lodash'; import {Constants} from "../../../../utils/constants"; +import {MultiselectFormControl} from "../../../../models/formControlModels/multiselectFormControl.model"; +import {MultiSelectItem} from "../../../formControls/component/multiselect/multiselect.model"; export enum FormControlNames { INSTANCE_NAME = 'instanceName', @@ -76,6 +77,7 @@ export class VnfControlGenerator { const vnfInstance = this.getVnfInstance(serviceId, vnfStoreKey); const vnfModel = new VNFModel(this.store.getState().service.serviceHierarchy[serviceId].vnfs[vnfName]); let result: FormControlModel[] = []; + const flags = this.store.getState().global.flags; if (!_.isNil(vnfModel)) { result.push(this.getInstanceName(vnfInstance, serviceId, vnfName, vnfModel.isEcompGeneratedNaming)); @@ -83,7 +85,7 @@ export class VnfControlGenerator { result.push(this.getLcpRegionControl(serviceId, vnfInstance, result)); result.push(this._basicControlGenerator.getLegacyRegion(vnfInstance)); result.push(this.getTenantControl(serviceId, vnfInstance, result)); - result.push(this.getPlatformControl(vnfInstance, result)); + result.push(this.getPlatformMultiselectControl(vnfInstance, result, flags['FLAG_2002_VNF_PLATFORM_MULTI_SELECT'])); result.push(this.getLineOfBusinessControl(vnfInstance, result)); } return result; @@ -101,12 +103,13 @@ export class VnfControlGenerator { const vnfModel = new VNFModel(this.store.getState().service.serviceHierarchy[serviceId].vnfs[vnfName]); if (!_.isNil(vnfModel)) { + const flags = this.store.getState().global.flags; result.push(this.getInstanceName(vnfInstance, serviceId, vnfName, vnfModel.isEcompGeneratedNaming)); result.push(this._basicControlGenerator.getProductFamilyControl(vnfInstance, result, false)); result.push(this.getLcpRegionControl(serviceId, vnfInstance, result)); result.push(this._basicControlGenerator.getLegacyRegion(vnfInstance)); result.push(this.getTenantControl(serviceId, vnfInstance, result)); - result.push(this.getPlatformControl(vnfInstance, result)); + result.push(this.getPlatformMultiselectControl(vnfInstance, result, flags['FLAG_2002_VNF_PLATFORM_MULTI_SELECT'])); result.push(this.getLineOfBusinessControl(vnfInstance, result)); result.push(this.getRollbackOnFailureControl(vnfInstance, result)); } @@ -139,20 +142,34 @@ export class VnfControlGenerator { }) }; - getPlatformControl = (instance: any, controls: FormControlModel[]): DropdownFormControl => { - return new DropdownFormControl({ - type: FormControlType.DROPDOWN, + + + getPlatformMultiselectControl = (instance: any, controls: FormControlModel[], isMultiSelected: boolean) : MultiselectFormControl => { + return new MultiselectFormControl({ + type: FormControlType.MULTI_SELECT , controlName: 'platformName', displayName: 'Platform', - dataTestId: 'platform', + dataTestId: 'multi-selectPlatform', + selectedFieldName : 'name' , + ngValue : 'name', placeHolder: 'Select Platform', isDisabled: false, name: "platform", - value: instance ? instance.platformName : null, + value: instance ? instance.platformName : '', + limitSelection : isMultiSelected ? 1000 : 1, validations: [new ValidatorModel(ValidatorOptions.required, 'is required')], onInitSelectedField: ['platformList'], - onInit: this._basicControlGenerator.getSubscribeInitResult.bind(null, this._aaiService.getCategoryParameters) - }) + onInit: this._basicControlGenerator.getSubscribeInitResult.bind(null, this._aaiService.getCategoryParameters), + onChange : (param: MultiSelectItem[], form: FormGroup) => { + form.controls['platformName'].setValue(param.map((multiSelectItem: MultiSelectItem)=>{ + return multiSelectItem.itemName + }).join(',')); + }, + convertOriginalDataToArray : (value?: string) => { + if(_.isNil(value)) return []; + return value.split(','); + } + }); }; getTenantControl = (serviceId: string, instance: any, controls: FormControlModel[]): DropdownFormControl => { diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGroupGenerator/vnfGroup.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGroupGenerator/vnfGroup.control.generator.spec.ts index 71d661191..81cfd9614 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGroupGenerator/vnfGroup.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGroupGenerator/vnfGroup.control.generator.spec.ts @@ -6,11 +6,7 @@ import {BasicControlGenerator} from "../basic.control.generator"; import {AaiService} from "../../../../services/aaiService/aai.service"; import {GenericFormService} from "../../generic-form.service"; import {FormBuilder} from "@angular/forms"; -import { - FormControlModel, - ValidatorModel, - ValidatorOptions -} from "../../../../models/formControlModels/formControl.model"; +import {FormControlModel, ValidatorModel, ValidatorOptions} from "../../../../models/formControlModels/formControl.model"; import {LogService} from "../../../../utils/log/log.service"; import {VnfGroupControlGenerator} from "./vnfGroup.control.generator"; import {Observable} from "rxjs"; @@ -25,19 +21,14 @@ class MockAppStore<T> { "type": "UPDATE_DRAWING_BOARD_STATUS", "drawingBoardStatus": "CREATE", "flags": { - "CREATE_INSTANCE_TEST": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_NETWORK_TO_ASYNC_INSTANTIATION": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true, "FLAG_SERVICE_MODEL_CACHE": false, "FLAG_SHOW_ASSIGNMENTS": true, "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, - "FLAG_DEFAULT_VNF": true, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": true, "FLAG_A_LA_CARTE_AUDIT_INFO": true, "FLAG_1810_CR_ADD_CLOUD_OWNER_TO_MSO_REQUEST": true, "FLAG_PRESENT_PROVIDER_NETWORKS_ASSOCIATIONS": true, - "FLAG_1810_CR_SOFT_DELETE_ALACARTE_VF_MODULE": true, "FLAG_1902_NEW_VIEW_EDIT": true } }, diff --git a/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html b/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html index d4c5118b3..edf86823c 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html +++ b/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html @@ -6,6 +6,11 @@ <checkbox-form-control *ngSwitchCase="'CHECKBOX'" [data]="formControl" [form]="dynamicFormGroup" ></checkbox-form-control> <dropdown-form-control *ngSwitchCase="'DROPDOWN'" [data]="formControl" [form]="dynamicFormGroup" ></dropdown-form-control> <file-form-control *ngSwitchCase="'FILE'" [data]="formControl" [form]="dynamicFormGroup"></file-form-control> + <multiselect-form-control *ngSwitchCase="'MULTI_SELECT'" + [data]="formControl" + [form]="dynamicFormGroup" + [multiselectOptions]="formControl?.options$" + [selectedItems]="formControl.value"></multiselect-form-control> </div> <div *ngIf="dynamicFormGroup != null && formControl != null && dynamicFormGroup.controls[formControl.controlName]?.errors"> <div *ngFor="let validatorModel of formControl?.validations"> diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html index 57064f658..f9a11eab1 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html @@ -3,14 +3,13 @@ <div class="modal-header"> <button type="button" class="close" - (click)="formPopupDetails?.onCancel(formPopupDetails.that,dynamicForm)" >× + (click)="formPopupDetails?.onCancel(formPopupDetails.that,dynamicForm)">× </button> <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">{{formPopupDetails?.title}} </span> </div> <div class="modal-body popup-content"> - <div class="header-left"> <div>MODEL: <span>"{{formPopupDetails?.leftSubTitle}}"</span></div> </div> @@ -36,12 +35,14 @@ <model-information [modelInformationItems]="formPopupDetails?.modelInformationItems"></model-information> </div> - <div class="instance-form"> + <div class="instance-form"> <div style="position: relative;height: 100%;overflow: auto;"> - <label id="notification-area" *ngIf="shouldShowNotification() == true" style="color: #959595;font-size: 12px;left: 30px;margin-left: 30px;">Data entered will apply to all service instances</label> - <generic-form [formControls]="formPopupDetails?.formControlList" - [dynamicInputs]="formPopupDetails?.dynamicInputsControlList" - (onFormChanged)="dynamicForm = $event" ></generic-form> + <label id="notification-area" *ngIf="shouldShowNotification() == true" + style="color: #959595;font-size: 12px;left: 30px;margin-left: 30px;">Data entered will apply to all + service instances</label> + <generic-form [formControls]="formPopupDetails?.formControlList" + [dynamicInputs]="formPopupDetails?.dynamicInputsControlList" + (onFormChanged)="dynamicForm = $event"></generic-form> </div> </div> @@ -54,6 +55,19 @@ </div> <div class="col-md-6" style="padding: 15px;padding-right: 35px;"> <button + *ngIf="showTemplateBtn" + [attr.data-tests-id]="'templateButton'" + type="button" class="btn btn-success submit" + (click)="openTemplateModal()" + ><span>Template</span></button> + <button + *ngIf="isShowPreviousInstantiationBtn" + [attr.data-tests-id]="'ShowPreviousInstancesButton'" + type="button" class="btn btn-success submit" + (click)="formPopupDetails.onOtherAction(formPopupDetails.that, dynamicForm)"> + <span>Previous Instantiation</span> + </button> + <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="formPopupDetails.onCancel(formPopupDetails.that, dynamicForm)"><span>Cancel</span></button> diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.scss b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.scss index 5057b44a5..18416dae6 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.scss +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.scss @@ -134,7 +134,7 @@ $grid-border: 1px #d2d2d2 solid; } .submit { - width: 120px; + min-width: 120px; height: 36px; background: #009fdb; border-radius: 2px; diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts index 8a95d108f..3939e44ff 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts @@ -13,55 +13,62 @@ import {AaiService} from "../../services/aaiService/aai.service"; import {GenericFormPopupService} from "./generic-form-popup.service"; import {FormControlModel} from "../../models/formControlModels/formControl.model"; import {FormGeneralErrorsService} from "../formGeneralErrors/formGeneralErrors.service"; +import {FeatureFlagsService, Features} from "../../services/featureFlag/feature-flags.service"; +import {InstantiationTemplatesModalComponent} from "./instantiationTemplatesModal/instantiation.templates.modal.component"; export interface PopupModel { - type : PopupType; - uuidData : UUIDData; - node : ITreeNode; - isUpdateMode : boolean; + type: PopupType; + uuidData: UUIDData; + node: ITreeNode; + isUpdateMode: boolean; } -export enum PopupType{ +export enum PopupType { SERVICE = 'service', VNF = 'vnf', NETWORK = 'network', VF_MODULE = 'vf_module', + VF_MODULE_UPGRADE = 'vf_module_upgrade', VNF_GROUP = 'vnf_group' } @Component({ - selector : 'generic-form-popup', - templateUrl : 'generic-form-popup.component.html', - styleUrls : ['generic-form-popup.component.scss'] + selector: 'generic-form-popup', + templateUrl: 'generic-form-popup.component.html', + styleUrls: ['generic-form-popup.component.scss'] }) -export class GenericFormPopupComponent extends DialogComponent<PopupModel, boolean> implements OnInit, OnDestroy{ - formPopupDetails : FormPopupDetails = null; - dynamicForm : FormGroup; - type : PopupType; - uuidData : UUIDData; - isUpdateMode : boolean; - node : ITreeNode = null; - hasGeneralApiError : boolean = false; +export class GenericFormPopupComponent extends DialogComponent<PopupModel, boolean> implements OnInit, OnDestroy { + formPopupDetails: FormPopupDetails = null; + dynamicForm: FormGroup; + type: PopupType; + uuidData: UUIDData; + showTemplateBtn: boolean = false; + isShowPreviousInstantiationBtn: boolean = false; + isUpdateMode: boolean; + node: ITreeNode = null; + hasGeneralApiError: boolean = false; parentElementClassName = 'content'; errorMsg = 'Page contains errors. Please see details next to the relevant fields.'; servicesQty = 1; quantityOptions = _.range(1, 51) - constructor(dialogService: DialogService , - private _iframeService : IframeService, + + constructor(dialogService: DialogService, + private _iframeService: IframeService, private _store: NgRedux<AppState>, - private _servicePopupService : ServicePopupService, - private _activatedRoute : ActivatedRoute, - private _aaiService : AaiService, + private _servicePopupService: ServicePopupService, + private _activatedRoute: ActivatedRoute, + private _aaiService: AaiService, + private _dialogService: DialogService, private _route: ActivatedRoute, - private _genericFormPopupService : GenericFormPopupService){ + private _genericFormPopupService: GenericFormPopupService) { super(dialogService); } - closeDialog(that) : void{ + closeDialog(that): void { this._iframeService.removeClassCloseModal(that.parentElementClassName); this.dialogService.removeDialog(this); setTimeout(() => { @@ -69,7 +76,7 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole }, 15); } - shouldShowNotification() : boolean { + shouldShowNotification(): boolean { return this.formPopupDetails && this.formPopupDetails.UUIDData['bulkSize'] > 1 } @@ -78,38 +85,17 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole .queryParams .subscribe(params => { console.log('changed'); - if(params['serviceModelId'] && params['isCreate']=="true"){ - this._genericFormPopupService.initReduxOnCreateNewService().then((serviceModelId : string)=>{ - this.uuidData = <any>{ - bulkSize : 1, - isMacro : this._store.getState().service.serviceHierarchy[serviceModelId].service.vidNotions.instantiationType === 'Macro', - type : PopupType.SERVICE, - serviceId: serviceModelId, - popupService: this._servicePopupService, - }; - - this.uuidData.popupService.closeDialogEvent.subscribe((that)=>{ - this.closeDialog(that); - }); - - this.formPopupDetails = this.uuidData.popupService.getGenericFormPopupDetails( - this.uuidData['serviceId'], - null, - null, - this.node, - this.uuidData, - false - ); - }); + if (params['serviceModelId'] && params['isCreate'] == "true") { + this.onInitForCreateNewServicePopup(); } }); - FormGeneralErrorsService.checkForErrorTrigger.subscribe(()=>{ + FormGeneralErrorsService.checkForErrorTrigger.subscribe(() => { this.hasSomeError(this.formPopupDetails, this.dynamicForm); }); - - if(!_.isNil(this.uuidData)){ - this.uuidData.popupService.closeDialogEvent.subscribe((that)=>{ + + if (!_.isNil(this.uuidData)) { + this.uuidData.popupService.closeDialogEvent.subscribe((that) => { this.closeDialog(that); }); @@ -118,28 +104,62 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole } } - hasSomeError(formPopupDetails : FormPopupDetails, form : FormGroup) : boolean{ - if(_.isNil(formPopupDetails)) return false; + private onInitForCreateNewServicePopup() { + this._genericFormPopupService.initReduxOnCreateNewService().then((serviceModelId: string) => { + this.uuidData = <any>{ + bulkSize: 1, + isMacro: this._store.getState().service.serviceHierarchy[serviceModelId].service.vidNotions.instantiationType === 'Macro', + type: PopupType.SERVICE, + serviceId: serviceModelId, + popupService: this._servicePopupService, + }; + this.showTemplateBtn = !!this._store.getState().global.flags["FLAG_2004_INSTANTIATION_TEMPLATES_POPUP"]; + + this.isShowPreviousInstantiationBtn = !!this._store.getState().global.flags["FLAG_2004_TEMP_BUTTON_TO_INSTANTIATION_STATUS_FILTER"]; + + this.uuidData.popupService.closeDialogEvent.subscribe((that) => { + this.closeDialog(that); + }); + + this.formPopupDetails = this.uuidData.popupService.getGenericFormPopupDetails( + this.uuidData['serviceId'], + null, + null, + this.node, + this.uuidData, + false + ); + }); + } + + hasSomeError(formPopupDetails: FormPopupDetails, form: FormGroup): boolean { + if (_.isNil(formPopupDetails)) return false; else { - for(let controlName in form.controls){ - if(form.controls[controlName].errors){ + for (let controlName in form.controls) { + if (form.controls[controlName].errors) { let error: string[] = Object.keys(form.controls[controlName].errors); - if(error.length === 1 && error[0] === 'required'){ + if (error.length === 1 && error[0] === 'required') { continue; - }else if(Object.keys(form.controls[controlName].errors).length > 0 ){ + } else if (Object.keys(form.controls[controlName].errors).length > 0) { return true; } } } } - return formPopupDetails.formControlList.filter((item : FormControlModel) => item.type === 'DROPDOWN' && item['hasEmptyOptions'] && item.isRequired()).length > 0 + return formPopupDetails.formControlList.filter((item: FormControlModel) => item.type === 'DROPDOWN' && item['hasEmptyOptions'] && item.isRequired()).length > 0 } + + + openTemplateModal = (): void => { + this._dialogService.addDialog(InstantiationTemplatesModalComponent, {}); + } + } -export class UUIDData extends Object{ - type : string; - popupService : any; +export class UUIDData extends Object { + type: string; + popupService: any; } diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.service.spec.ts index fa77bed5f..63c980cd5 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.service.spec.ts @@ -20,6 +20,7 @@ import {NetworkControlGenerator} from "../genericForm/formControlsServices/netwo import {VfModulePopuopService} from "./genericFormServices/vfModule/vfModule.popuop.service"; import {VfModuleControlGenerator} from "../genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator"; import {FeatureFlagsService} from "../../services/featureFlag/feature-flags.service"; +import {VfModuleUpgradePopupService} from "./genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service"; class MockAppStore<T>{ getState() { @@ -32,9 +33,6 @@ class MockAppStore<T>{ "FLAG_FABRIC_CONFIGURATION_ASSIGNMENTS": true, "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -970,6 +968,7 @@ describe('Generic Form popup Service', () => { NetworkPopupService, NetworkControlGenerator, VfModulePopuopService, + VfModuleUpgradePopupService, VfModuleControlGenerator, {provide:FeatureFlagsService, useClass: MockFeatureFlagsService}, {provide: ActivatedRoute, useClass: ActivatedRouteMock}, diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.spec.ts index 54af063d8..a3c83263c 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/basic.popup.service.spec.ts @@ -33,10 +33,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" 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..1d44a9e5e 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); + return new VfModule(rawModel, flags); } 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/components/genericFormPopup/genericFormServices/network/network.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/network/network.popup.service.spec.ts index eb094abfb..67c371212 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/network/network.popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/network/network.popup.service.spec.ts @@ -30,10 +30,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.spec.ts index 5b5acd33b..ebea695f7 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.spec.ts @@ -31,10 +31,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -2143,6 +2140,33 @@ describe('Service popup service', () => { expect(service.closeDialogEvent.next).toHaveBeenCalledWith(that); }); + test('showPreviousInstantiations should trigger postMessage', () => { + let that = <any>{ + parentElementClassName: 'content', + _iframeService: iframeService, + resetPopupData : () =>{ }, + serviceModel:{ + uuid:'1111' + } + + }; + + let expectedMessage= { + eventId: 'showPreviousInstantiations', + data: { + serviceModelId: that.serviceModel.uuid + } + }; + + jest.spyOn(window.parent, 'postMessage'); + + service.showPreviousInstantiations(that, fb.group({})); + + expect( window.parent.postMessage).toHaveBeenCalledWith(expectedMessage,"*") + + }); + + test('getDynamicInputs should return list of controls' ,() => { const result: FormControlModel[] = service.getDynamicInputs('6b528779-44a3-4472-bdff-9cd15ec93450'); diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.ts index 7694e6314..3e7e8c1e5 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/service/service.popup.service.ts @@ -20,6 +20,7 @@ import {ModelInfo} from "../../../../models/modelInfo"; import {FormControlModel} from "../../../../models/formControlModels/formControl.model"; import {createServiceInstance, updateServiceInstance} from "../../../../storeUtil/utils/service/service.actions"; import * as _ from 'lodash'; +import {Utils} from "../../../../utils/utils"; @Injectable() export class ServicePopupService implements GenericPopupInterface { @@ -58,7 +59,12 @@ export class ServicePopupService implements GenericPopupInterface { this.getDynamicInputs(serviceId), this.modelInformations, (that, form: FormGroup) => {that.onSubmit(that, form);}, - (that: any, form: FormGroup) => {that.onCancel(that, form); } + (that: any, form: FormGroup) => { + that.onCancel(that, form); + }, + (that: any, form: FormGroup) => { + that.showPreviousInstantiations(that, form); + } ); } @@ -122,13 +128,24 @@ export class ServicePopupService implements GenericPopupInterface { onSubmit(that, form: FormGroup, ...args): void { form = that.updateExtraValues(that, form); that.storeServiceInstance(form.value, args[0], [], new ModelInfo(that.serviceModel), that.serviceModel); - window.parent.postMessage( { - eventId: 'submitIframe', + const eventId = 'submitIframe'; + this.postMessageToWindowParent(eventId, that.serviceModel.uuid); + this.onCancel(that, form); + } + + showPreviousInstantiations(that, form: FormGroup,): void { + const eventId = 'showPreviousInstantiations'; + this.postMessageToWindowParent(eventId, that.serviceModel.uuid); + this.onCancel(that, form); + } + + private postMessageToWindowParent(eventId: string, serviceModelId:string) { + window.parent.postMessage({ + eventId: eventId, data: { - serviceModelId: that.serviceModel.uuid + serviceModelId } }, "*"); - this.onCancel(that, form); } updateExtraValues = (that, form) : any => { @@ -163,13 +180,13 @@ export class ServicePopupService implements GenericPopupInterface { this._store.dispatch(updateServiceInstance(formValues, serviceModel.modelVersionId)); } - if (this._store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD'] && isCreateMode) { + if (isCreateMode) { this._defaultDataGeneratorService.updateReduxOnFirstSet(serviceModel.modelVersionId, formValues); } }; setIsALaCarte = (formValues: any, instantiationType) => { - formValues.isALaCarte = instantiationType === 'ALaCarte'; + formValues.isALaCarte = Utils.isALaCarte(instantiationType); }; setTestApi = (formValues: any) =>{ diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.spec.ts index 5b27b6e29..6c487102f 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.spec.ts @@ -30,10 +30,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.ts index c7a71efc0..20336e5eb 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service.ts @@ -21,8 +21,7 @@ import {FormControlModel} from "../../../../models/formControlModels/formControl import * as _ from 'lodash'; import {createVFModuleInstance, updateVFModuleInstance} from "../../../../storeUtil/utils/vfModule/vfModule.actions"; -@Injectable() -export class VfModulePopuopService implements GenericPopupInterface { +export abstract class VfModulePopupServiceBase { dynamicInputs: any; instance: any; model: any; @@ -31,16 +30,27 @@ export class VfModulePopuopService implements GenericPopupInterface { uuidData: Object; closeDialogEvent: Subject<any> = new Subject<any>(); isUpdateMode: boolean; + storeVFModule = (that, formValues: any): void => { + formValues.modelInfo = new ModelInfo(that.model); + formValues.uuid = formValues.modelInfo.uuid; + formValues.isMissingData = false; + const vnf = that._store.getState().service.serviceInstance[that.uuidData.serviceId].vnfs[that.uuidData.vnfStoreKey]; + if (!that.uuidData.vFModuleStoreKey) { + this._store.dispatch(createVFModuleInstance(formValues, that.uuidData.modelName, that.uuidData.serviceId, 0, that.uuidData.vnfStoreKey)); + } else { + this._store.dispatch(updateVFModuleInstance(formValues, that.uuidData.modelName, that.uuidData.serviceId, that.uuidData.vFModuleStoreKey, that.uuidData.vnfStoreKey)); + } + }; - constructor(private _basicControlGenerator: BasicControlGenerator, - private _vfModuleControlGenerator: VfModuleControlGenerator, - private _iframeService: IframeService, - private _defaultDataGeneratorService: DefaultDataGeneratorService, - private _aaiService: AaiService, - private _basicPopupService : BasicPopupService, - private _store: NgRedux<AppState>) { - + protected constructor( + protected _basicControlGenerator: BasicControlGenerator, + protected _vfModuleControlGenerator: VfModuleControlGenerator, + protected _iframeService: IframeService, + protected _defaultDataGeneratorService: DefaultDataGeneratorService, + protected _aaiService: AaiService, + protected _basicPopupService: BasicPopupService, + protected _store: NgRedux<AppState>) { } getInstance(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string): any { @@ -51,45 +61,6 @@ export class VfModulePopuopService implements GenericPopupInterface { return vfModules[this.uuidData['modelName']][vfModuleStoreKey]; } - getDynamicInputs(UUIDData : Object) : FormControlModel[]{ - let dynamic = this._defaultDataGeneratorService.getArbitraryInputs(this._store.getState().service.serviceHierarchy[UUIDData['serviceId']].vfModules[UUIDData['modelName']].inputs); - return this.getVFModuleDynamicInputs(dynamic, UUIDData); - } - - getVFModuleDynamicInputs(dynamicInputs : any, UUIDData : Object) : FormControlModel[] { - let result : FormControlModel[] = []; - if(dynamicInputs) { - let vfModuleInstance = null; - if (_.has(this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs, UUIDData['vnfStoreKey']) && - _.has(this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs[UUIDData['vnfStoreKey']].vfModules, UUIDData['modelName'])) { - vfModuleInstance = Object.assign({},this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs[UUIDData['vnfStoreKey']].vfModules[UUIDData['modelName']][UUIDData['vfModuleStoreKey']]); - } - result = this._basicControlGenerator.getDynamicInputs(dynamicInputs, vfModuleInstance); - } - return result; - } - - - getGenericFormPopupDetails(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, node: ITreeNode, uuidData: Object, isUpdateMode: boolean): FormPopupDetails { - - this.uuidData = uuidData; - this.instance = this.getInstance(serviceId, vnfStoreKey, vfModuleStoreKey); - this.getModelInformation(serviceId, uuidData['modelName']); - - return new FormPopupDetails(this, - PopupType.VFMODULE, - uuidData, - this.getTitle(isUpdateMode), - this.getSubLeftTitle(), - this.getSubRightTitle(), - this.getControls(serviceId, vnfStoreKey, vfModuleStoreKey, isUpdateMode), - this.getDynamicInputs(uuidData), - this.modelInformations, - (that, form: FormGroup) => {that.onSubmit(that, form);}, - (that: any, form: FormGroup) => {that.onCancel(that, form); } - ); - } - getModelInformation(serviceId: string, modelName: string) { this._aaiService.getServiceModelById(serviceId).subscribe((result: any) => { this.serviceModel = new ServiceModel(result); @@ -116,69 +87,125 @@ export class VfModulePopuopService implements GenericPopupInterface { }); } - getControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, isUpdateMode: boolean) { - if (this._store.getState().service.serviceHierarchy[serviceId].service.vidNotions.instantiationType === 'Macro') { - return this._vfModuleControlGenerator.getMacroFormControls(serviceId, vnfStoreKey, vfModuleStoreKey, this.uuidData, isUpdateMode); - } else { - return this._vfModuleControlGenerator.getAlaCarteFormControls(serviceId, vnfStoreKey, vfModuleStoreKey, this.uuidData, isUpdateMode); - } + protected postSubmitIframeMessage(that) { + window.parent.postMessage({ + eventId: 'submitIframe', + data: { + serviceModelId: that.serviceModel.uuid + } + }, "*"); } + onCancel(that, form) { + form.reset(); + that._iframeService.removeClassCloseModal('content'); + this.closeDialogEvent.next(that); + } - onSubmit(that, form: FormGroup) { - form.value['instanceParams'] = form.value['instanceParams'] && [form.value['instanceParams']]; + getSubLeftTitle(): string { + return this.model.name; + } + + getSubRightTitle(): string { + return "Module (Heat stack) Instance Details"; + } + + abstract getTitle(isUpdateMode : boolean) : string; + abstract getControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, isUpdateMode: boolean); + abstract getDynamicInputs(UUIDData : Object) : FormControlModel[]; + + getGenericFormPopupDetails(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, node: ITreeNode, uuidData: Object, isUpdateMode: boolean): FormPopupDetails { + + this.uuidData = uuidData; + this.instance = this.getInstance(serviceId, vnfStoreKey, vfModuleStoreKey); + this.getModelInformation(serviceId, uuidData['modelName']); + + return new FormPopupDetails(this, + PopupType.VFMODULE, + uuidData, + this.getTitle(isUpdateMode), + this.getSubLeftTitle(), + this.getSubRightTitle(), + this.getControls(serviceId, vnfStoreKey, vfModuleStoreKey, isUpdateMode), + this.getDynamicInputs(uuidData), + this.modelInformations, + (that, form: FormGroup) => { + that.onSubmit(that, form); + }, + (that: any, form: FormGroup) => { + that.onCancel(that, form); + } + ); + } + + updateFormValueWithSupplementaryFile(form: FormGroup, that) { if (!_.isNil(form.controls['supplementaryFile_hidden_content']) && form.controls['supplementaryFile_hidden_content'].value) { form.value['supplementaryFileContent'] = JSON.parse(form.controls['supplementaryFile_hidden_content'].value); if (!_.isNil(form.controls['supplementaryFile_hidden'].value)) { form.value['supplementaryFileName'] = form.controls['supplementaryFile_hidden'].value.name; - } - else { + } else { form.value['supplementaryFileName'] = that.instance.supplementaryFileName; } - } - else { + } else { delete form.value['supplementaryFileContent']; delete form.value['supplementaryFileName']; } - that.storeVFModule(that, form.value); - window.parent.postMessage({ - eventId: 'submitIframe', - data: { - serviceModelId: that.serviceModel.uuid - } - }, "*"); - this.onCancel(that, form); } +} +@Injectable() +export class VfModulePopuopService extends VfModulePopupServiceBase implements GenericPopupInterface { + + + constructor(_basicControlGenerator: BasicControlGenerator, + _vfModuleControlGenerator: VfModuleControlGenerator, + _iframeService: IframeService, + _defaultDataGeneratorService: DefaultDataGeneratorService, + _aaiService: AaiService, + _basicPopupService : BasicPopupService, + _store: NgRedux<AppState>) { + super(_basicControlGenerator, _vfModuleControlGenerator, _iframeService, _defaultDataGeneratorService, _aaiService, _basicPopupService, _store); - onCancel(that, form) { - form.reset(); - that._iframeService.removeClassCloseModal('content'); - this.closeDialogEvent.next(that); } - storeVFModule = (that, formValues: any): void => { - formValues.modelInfo = new ModelInfo(that.model); - formValues.uuid = formValues.modelInfo.uuid; - formValues.isMissingData = false; - const vnf = that._store.getState().service.serviceInstance[that.uuidData.serviceId].vnfs[that.uuidData.vnfStoreKey]; + getDynamicInputs(UUIDData : Object) : FormControlModel[]{ + let dynamic = this._defaultDataGeneratorService.getArbitraryInputs(this._store.getState().service.serviceHierarchy[UUIDData['serviceId']].vfModules[UUIDData['modelName']].inputs); + return this.getVFModuleDynamicInputs(dynamic, UUIDData); + } - if (!that.uuidData.vFModuleStoreKey) { - this._store.dispatch(createVFModuleInstance(formValues, that.uuidData.modelName, that.uuidData.serviceId, 0, that.uuidData.vnfStoreKey)); - } else { - this._store.dispatch(updateVFModuleInstance(formValues, that.uuidData.modelName, that.uuidData.serviceId, that.uuidData.vFModuleStoreKey, that.uuidData.vnfStoreKey)); + getVFModuleDynamicInputs(dynamicInputs : any, UUIDData : Object) : FormControlModel[] { + let result : FormControlModel[] = []; + if(dynamicInputs) { + let vfModuleInstance = null; + if (_.has(this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs, UUIDData['vnfStoreKey']) && + _.has(this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs[UUIDData['vnfStoreKey']].vfModules, UUIDData['modelName'])) { + vfModuleInstance = Object.assign({},this._store.getState().service.serviceInstance[UUIDData['serviceId']].vnfs[UUIDData['vnfStoreKey']].vfModules[UUIDData['modelName']][UUIDData['vfModuleStoreKey']]); + } + result = this._basicControlGenerator.getDynamicInputs(dynamicInputs, vfModuleInstance); } - }; + return result; + } - getTitle(isUpdateMode : boolean) : string { - return isUpdateMode ? 'Edit Module (Heat stack)' : 'Set new Module (Heat stack)'; + + getControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, isUpdateMode: boolean) { + if (this._store.getState().service.serviceHierarchy[serviceId].service.vidNotions.instantiationType === 'Macro') { + return this._vfModuleControlGenerator.getMacroFormControls(serviceId, vnfStoreKey, vfModuleStoreKey, this.uuidData, isUpdateMode); + } else { + return this._vfModuleControlGenerator.getAlaCarteFormControls(serviceId, vnfStoreKey, vfModuleStoreKey, this.uuidData, isUpdateMode); + } } - getSubLeftTitle(): string { - return this.model.name; + + onSubmit(that, form: FormGroup) { + form.value['instanceParams'] = form.value['instanceParams'] && [form.value['instanceParams']]; + this.updateFormValueWithSupplementaryFile(form, that); + that.storeVFModule(that, form.value); + this.postSubmitIframeMessage(that); + this.onCancel(that, form); } - getSubRightTitle(): string { - return "Module (Heat stack) Instance Details"; + getTitle(isUpdateMode : boolean) : string { + return isUpdateMode ? 'Edit Module (Heat stack)' : 'Set new Module (Heat stack)'; } + } diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service.ts new file mode 100644 index 000000000..bbfe8705e --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service.ts @@ -0,0 +1,95 @@ +import {Injectable} from "@angular/core"; +import {ITreeNode} from "angular-tree-component/dist/defs/api"; +import {FormGroup} from "@angular/forms"; +import {VfModulePopupServiceBase} from "../vfModule/vfModule.popuop.service"; +import {upgradeVFModule} from "../../../../storeUtil/utils/vfModule/vfModule.actions"; +import {SharedTreeService} from "../../../../../drawingBoard/service-planning/objectsToTree/shared.tree.service"; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../../../store/reducers"; +import {BasicControlGenerator} from "../../../genericForm/formControlsServices/basic.control.generator"; +import {VfModuleControlGenerator} from "../../../genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator"; +import {IframeService} from "../../../../utils/iframe.service"; +import {DefaultDataGeneratorService} from "../../../../services/defaultDataServiceGenerator/default.data.generator.service"; +import {AaiService} from "../../../../services/aaiService/aai.service"; +import {BasicPopupService} from "../basic.popup.service"; +import {FormControlModel} from "../../../../models/formControlModels/formControl.model"; +import {CheckboxFormControl} from "../../../../models/formControlModels/checkboxFormControl.model"; +import {FormControlType} from "../../../../models/formControlModels/formControlTypes.enum"; +import {mergeObjectByPathAction} from "../../../../storeUtil/utils/general/general.actions"; + +export enum UpgradeFormControlNames { + RETAIN_VOLUME_GROUPS = 'retainVolumeGroups', + RETAIN_ASSIGNMENTS = 'retainAssignments', + SDN_C_PRE_LOAD = 'sdncPreLoad', +} + +@Injectable() +export class VfModuleUpgradePopupService extends VfModulePopupServiceBase { + constructor(protected _basicControlGenerator: BasicControlGenerator, + protected _vfModuleControlGenerator: VfModuleControlGenerator, + protected _iframeService: IframeService, + protected _defaultDataGeneratorService: DefaultDataGeneratorService, + protected _aaiService: AaiService, + protected _basicPopupService: BasicPopupService, + protected _store: NgRedux<AppState>, + private _sharedTreeService: SharedTreeService) { + super(_basicControlGenerator, _vfModuleControlGenerator, _iframeService, _defaultDataGeneratorService, _aaiService, _basicPopupService, _store); + } + + node: ITreeNode; + + getDynamicInputs = () => null; + + getControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, isUpdateMode: boolean): FormControlModel[] { + let result: FormControlModel[] =[ + this.getRetainAssignmentsControl(), + this.getRetainVolumeGroupsControl(), + this._basicControlGenerator.getSDNCControl(null) + ]; + + const vfModuleInstance = this._vfModuleControlGenerator.getVfModuleInstance(serviceId, vnfStoreKey, this.uuidData, isUpdateMode); + result = this._basicControlGenerator.concatSupplementaryFile(result, vfModuleInstance); + return result; + }; + + getTitle = (): string => 'Upgrade Module'; + + onSubmit(that, form: FormGroup) { + const node = that.uuidData.vfModule; + const serviceInstanceId: string = that.uuidData.serviceId; + const vnfStoreKey = node.parent.data.vnfStoreKey; + const modelName = node.data.modelName; + const dynamicModelName = node.data.dynamicModelName; + + this.updateFormValueWithSupplementaryFile(form, that); + + this._store.dispatch(upgradeVFModule(modelName, vnfStoreKey, serviceInstanceId, dynamicModelName)); + this._store.dispatch(mergeObjectByPathAction(['serviceInstance', serviceInstanceId, 'vnfs', vnfStoreKey, 'vfModules', modelName, dynamicModelName], form.value)); + this._sharedTreeService.upgradeBottomUp(node, serviceInstanceId); + + this.postSubmitIframeMessage(that); + this.onCancel(that, form); + } + + getRetainVolumeGroupsControl = (): CheckboxFormControl => { + return new CheckboxFormControl({ + type: FormControlType.CHECKBOX, + controlName: UpgradeFormControlNames.RETAIN_VOLUME_GROUPS, + displayName: 'Retain Volume Groups', + dataTestId: UpgradeFormControlNames.RETAIN_VOLUME_GROUPS, + value: true, + validations: [] + }) + }; + + getRetainAssignmentsControl = (): CheckboxFormControl => { + return new CheckboxFormControl({ + type: FormControlType.CHECKBOX, + controlName: UpgradeFormControlNames.RETAIN_ASSIGNMENTS, + displayName: 'Retain Assignments', + dataTestId: UpgradeFormControlNames.RETAIN_ASSIGNMENTS, + value: true, + validations: [] + }) + }; +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popup.service.spec.ts new file mode 100644 index 000000000..7c1cc084a --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popup.service.spec.ts @@ -0,0 +1,201 @@ +import {LogService} from "../../../../utils/log/log.service"; +import {NgRedux} from "@angular-redux/store"; +import {BasicControlGenerator, SDN_C_PRE_LOAD, SUPPLEMENTARY_FILE} from "../../../genericForm/formControlsServices/basic.control.generator"; +import {AaiService} from "../../../../services/aaiService/aai.service"; +import {HttpClient} from "@angular/common/http"; +import {GenericFormService} from "../../../genericForm/generic-form.service"; +import {FormBuilder, FormGroup} from "@angular/forms"; +import {IframeService} from "../../../../utils/iframe.service"; +import {DefaultDataGeneratorService} from "../../../../services/defaultDataServiceGenerator/default.data.generator.service"; +import {BasicPopupService} from "../basic.popup.service"; +import {VfModuleControlGenerator} from "../../../genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator"; +import {SdcUiServices} from "onap-ui-angular"; +import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; +import {getTestBed, TestBed} from "@angular/core/testing"; +import {UpgradeFormControlNames, VfModuleUpgradePopupService} from "./vfModule.upgrade.popuop.service"; +import {SharedTreeService} from "../../../../../drawingBoard/service-planning/objectsToTree/shared.tree.service"; +import {AppState} from "../../../../store/reducers"; +import {instance, mock} from "ts-mockito"; +import {GeneralActions} from "../../../../storeUtil/utils/general/general.actions"; +import {VfModuleActions} from "../../../../storeUtil/utils/vfModule/vfModule.actions"; +import {ServiceActions} from "../../../../storeUtil/utils/service/service.actions"; +import {FormControlModel} from "../../../../models/formControlModels/formControl.model"; + +class MockModalService<T> {} + +class MockAppStore<T> {} + +class MockReduxStore<T> { + getState() { + return { + service: { + serviceInstance : { + serviceId : { + vnfs : { + vnfStoreKey : { + vfModules: { + vfModuleName: { + vfModuleId : { + supplementaryFileName: "myFileName" + }}}}}}}} + }; + } + + dispatch() {} +} + +class MockFeatureFlagsService {} + +describe('VFModule popup service', () => { + let injector; + let service: VfModuleUpgradePopupService; + let genericFormService: GenericFormService; + let defaultDataGeneratorService: DefaultDataGeneratorService; + let fb: FormBuilder; + let iframeService: IframeService; + let store : NgRedux<AppState>; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + providers: [ + VfModuleUpgradePopupService, + BasicControlGenerator, + VfModuleControlGenerator, + DefaultDataGeneratorService, + GenericFormService, + FormBuilder, + IframeService, + AaiService, + LogService, + BasicPopupService, + SharedTreeService, + {provide: FeatureFlagsService, useClass: MockFeatureFlagsService}, + {provide: NgRedux, useClass: MockReduxStore}, + {provide: HttpClient, useClass: MockAppStore}, + {provide: SdcUiServices.ModalService, useClass: MockModalService} + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + service = injector.get(VfModuleUpgradePopupService); + genericFormService = injector.get(GenericFormService); + defaultDataGeneratorService = injector.get(DefaultDataGeneratorService); + fb = injector.get(FormBuilder); + iframeService = injector.get(IframeService); + store = injector.get(NgRedux); + service.uuidData = { + modelName: 'vfModuleName', + vFModuleStoreKey: 'vfModuleId' + }; + + })().then(done).catch(done.fail)); + + test('getTitle should return the correct title', () => { + expect(service.getTitle()).toBe("Upgrade Module") + }); + + function findControlByName(controls: FormControlModel[], controlName: string) : FormControlModel { + return controls.find((control) => { + return control.controlName === controlName; + }); + } + + function getControlByNameAndCheckValue(controlName: string, expectedValue: any) { + const controls = service.getControls('serviceId', 'vnfStoreKey', 'vfModuleId', true); + const control = findControlByName(controls, controlName); + expect(control).toBeDefined(); + expect(control.value).toEqual(expectedValue); + } + + test('get controls should return retainAssignments control with true value', ()=> { + getControlByNameAndCheckValue(UpgradeFormControlNames.RETAIN_ASSIGNMENTS, true); + }); + + test('get controls should return retainVolumeGroup control with true value', ()=> { + getControlByNameAndCheckValue(UpgradeFormControlNames.RETAIN_VOLUME_GROUPS, true); + }); + + test('get controls should contain SUPPLEMENTARY_FILE controller', ()=> { + + //when + const controls = service.getControls('serviceId', 'vnfStoreKey', 'vfModuleId', true); + + //then + const control = findControlByName(controls, SUPPLEMENTARY_FILE); + expect(control).toBeDefined(); + expect(control.selectedFile).toBe("myFileName"); + }); + + test('on submit should call merge action of form value to vfModule', () => { + + //given + + const serviceId = "serviceId5"; + const vnfStoreKey = 'vnfStoreKey3'; + const modelName = 'modelA'; + const dynamicModelName = 'dynamicModel'; + const that = { + uuidData : { + vfModule : { + data : { + modelName, + dynamicModelName + }, + parent : { + data: { + vnfStoreKey + }}}, + serviceId + }, + serviceModel: { + uuid : "someUuid" + }, + _iframeService: { + removeClassCloseModal : jest.fn() + } + }; + + let mockFrom: FormGroup = mock(FormGroup); + let form = instance(mockFrom); + form.value = { + a: "value", + b: "another" + }; + form.controls = { + supplementaryFile_hidden_content : { + value: '{"c": "c", "d": 1}' + }, + supplementaryFile_hidden : { + value: { + name: "name" + } + } + }; + + let expectedMergePayload = { + a: "value", + b: "another", + supplementaryFileContent: {c: "c", d: 1}, + supplementaryFileName: "name" + }; + + spyOn(store, 'dispatch'); + + //when + service.onSubmit(that, form); + + //then + expect(store.dispatch).toBeCalledWith( + {type: GeneralActions.MERGE_OBJECT_BY_PATH, path: ['serviceInstance', serviceId, 'vnfs', vnfStoreKey, 'vfModules',modelName, dynamicModelName], payload:expectedMergePayload}); + expect(store.dispatch).toBeCalledWith( + {type: VfModuleActions.UPGRADE_VFMODULE, dynamicModelName: "dynamicModel", modelName: "modelA", serviceId: "serviceId5", vnfStoreKey: "vnfStoreKey3"}); + expect(store.dispatch).toBeCalledWith({type: ServiceActions.UPGRADE_SERVICE_ACTION, serviceUuid: "serviceId5"}); + + }); + + + test( 'get controls should return usePreload with false value', () => { + getControlByNameAndCheckValue(SDN_C_PRE_LOAD, false); + }); +}); diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.spec.ts index 6458e4f97..c4317f241 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.spec.ts @@ -14,6 +14,7 @@ import {VnfControlGenerator} from "../../../genericForm/formControlsServices/vnf import {UUIDData} from "../../generic-form-popup.component"; import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flags.service"; import {getTestBed, TestBed} from "@angular/core/testing"; +import {VfModuleUpgradePopupService} from "../vfModuleUpgrade/vfModule.upgrade.popuop.service"; class MockAppStore<T> {} @@ -29,10 +30,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -2261,6 +2259,7 @@ describe('vnf new popup service', () => { LogService, BasicPopupService, VfModulePopuopService, + VfModuleUpgradePopupService, BasicControlGenerator, VnfControlGenerator, {provide: NgRedux, useClass: MockReduxStore}, @@ -2335,6 +2334,10 @@ describe('vnf new popup service', () => { expect(service.modelInformations[13].values).toEqual(['5']); }); + test('when there is no max instances in model , shell return maximum item with Unlimited text', () =>{ + expect(service.createMaximumToInstantiateModelInformationItem({}).values[0]).toEqual('Unlimited (default)'); + }); + test('getSubLeftTitle new vnf popup should return service model name', () => { service.uuidData = { serviceId: '6e59c5de-f052-46fa-aa7e-2fca9d674c44', diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.ts index b23f74530..283603275 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnf/vnf.popup.service.ts @@ -97,11 +97,21 @@ export class VnfPopupService implements GenericPopupInterface{ new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]), new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole]), new ModelInformationItem("Minimum to instantiate", "vnf-min", [!_.isNil(this.model.min) ? this.model.min.toString() : '0'], "", false), - new ModelInformationItem("Maximum to instantiate", "vnf-max", [!_.isNil(this.model.max) ? this.model.max.toString() : '1'], "", false) + (this.createMaximumToInstantiateModelInformationItem(this.model)) ]; }) } + createMaximumToInstantiateModelInformationItem(model) { + return new ModelInformationItem( + "Maximum to instantiate", + "vnf-max", + [!_.isNil(model.max) ? model.max.toString() : Constants.ModelInfo.UNLIMITED_DEFAULT], + "", + false + ); + } + getSubLeftTitle(): string { return "VNF MODEL: " + this._store.getState().service.serviceHierarchy[this.uuidData['serviceId']].vnfs[this.uuidData['modelName']].name; } diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnfGroup/vnfGroup.popup.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnfGroup/vnfGroup.popup.service.spec.ts index 5397a7233..3a81e5b2b 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnfGroup/vnfGroup.popup.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/genericFormServices/vnfGroup/vnfGroup.popup.service.spec.ts @@ -14,6 +14,7 @@ import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flag import {VnfGroupPopupService} from "./vnfGroup.popup.service"; import {VnfGroupControlGenerator} from "../../../genericForm/formControlsServices/vnfGroupGenerator/vnfGroup.control.generator"; import {getTestBed, TestBed} from "@angular/core/testing"; +import {VfModuleUpgradePopupService} from "../vfModuleUpgrade/vfModule.upgrade.popuop.service"; class MockAppStore<T> {} @@ -29,10 +30,7 @@ class MockReduxStore<T> { "FLAG_SHOW_VERIFY_SERVICE": false, "FLAG_SERVICE_MODEL_CACHE": true, "FLAG_ADVANCED_PORTS_FILTER": true, - "CREATE_INSTANCE_TEST": false, - "FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD": false, "FLAG_REGION_ID_FROM_REMOTE": true, - "EMPTY_DRAWING_BOARD_TEST": false, "FLAG_ADD_MSO_TESTAPI_FIELD": true }, "type": "[FLAGS] Update" @@ -2258,6 +2256,7 @@ describe('vnf group new popup service', () => { LogService, BasicPopupService, VfModulePopuopService, + VfModuleUpgradePopupService, BasicControlGenerator, VnfGroupControlGenerator, {provide: NgRedux, useClass: MockReduxStore}, diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html new file mode 100644 index 000000000..19f641a56 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html @@ -0,0 +1,164 @@ +<div id="template-popup" class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" + class="close" + (click)="closeModal()">× + </button> + <span [attr.data-tests-id]="'template-modal-title'" + class="modal-title">Templates + </span> + </div> + <div class="modal-body templateModalBody"> + <div class="row description-section"> + <div class="col-md-6"> + <div [attr.data-tests-id]="'description-part-1'">The following list presents previous instantiations done for + this model in this version. + </div> + <div [attr.data-tests-id]="'description-part-2'">You may use one of them as a baseline for your instantiation + or start from scratch. + </div> + <div [attr.data-tests-id]="'description-part-3'">Once you selecting one allows you to change the data before + start instantiating. + </div> + </div> + <div class="col-md-6"> + <div class="col-md-6"> + </div> + <div class="col-md-6"> + <input + class="filter-input form-control input-text" + placeholder="Filter..." + [(ngModel)]="filterText"> + </div> + </div> + </div> + <div class="row" style="margin-left: 0;margin-right: 0;padding: 20px;"> + <table id="member-table" class="table table-bordered" style="table-layout: fixed"> + <thead class="thead-dark"> + <tr> + <th class="header-title" id="header-userId">User ID</th> + <th class="header-title" id="header-createDate" style="width: 21ch;">Date</th> + <th class="header-title" id="header-instanceName" style="max-width: 50ch;">Instance Name</th> + <th class="header-title" id="header-instantiationStatus" style="width: 30ch;">Instantiation Status</th> + <th class="header-title" id="header-summary">Summary</th> + <th class="header-title" id="header-region">Region</th> + <th class="header-title" id="header-tenant">Tenant</th> + <th class="header-title" id="header-aicZone">AIC Zone</th> + </tr> + </thead> + <tbody> + <tr class="member-table-row" + *ngFor="let item of filterTableData | searchFilter: filterText ;" + (click)="selectedJobId = item.jobId" + [ngClass]="{'selected' : selectedJobId === item.jobId}" + [attr.data-tests-id]="'row-' + item.jobId"> + <td> + <div> + <custom-ellipsis + [dataTestId]="'userId-' + item.jobId" + [id]="item.userId" + [value]="item.userId" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td style="width: 21ch;"> + <div> + <custom-ellipsis + [dataTestId]="'createDate-' + item.jobId" + [id]="item.createDate" + [value]="item.createDate" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td style="max-width: 50ch;"> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'instanceName-' + item.jobId" + [id]="item.instanceName" + [value]="item.instanceName" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'instantiationStatus-' + item.jobId" + [id]="item.instantiationStatus" + [value]="item.instantiationStatus" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [dataTestId]="'summary-' + item.jobId" + [id]="item.summary" + [value]="item.summary" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'region-' + item.jobId" + [id]="item.region" + [value]="item.region" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'tenant-' + item.jobId" + [id]="item.tenant" + [value]="item.tenant" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [dataTestId]="'aicZone-' + item.jobId" + [id]="item.aicZone" + [value]="item.aicZone" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + <div class="modal-footer row" style="padding: 0"> + <div class="col-md-6"> + </div> + <div class="col-md-6" style="padding: 15px;padding-right: 35px;"> + <button + [disabled]="selectedJobId === null" + [attr.data-tests-id]="'LoadTemplateButton'" + type="button" class="btn btn-primary submit" + (click)="loadTemplate()"><span>Load Template</span> + </button> + <button + [attr.data-tests-id]="'startFromScratchButton'" + type="button" class="btn btn-success submit startFromScratchButton" + (click)="closeModal()"><span>Start from Scratch</span> + </button> + </div> + </div> + </div> +</div> diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss new file mode 100644 index 000000000..267d2cee0 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss @@ -0,0 +1,196 @@ +$grid-border: 1px #d2d2d2 solid; + +#template-popup { + color: #191919; + + thead { + background: #F8F8F8; + } + .left-panel { + background: #f2f2f2; + border-right: $grid-border; + } + + .header-common { + height: 100%; + align-items: center; + display: flex; + font-family: OpenSans-Semibold; + font-size: 12px; + } + + .header-text { + padding-left: 30px; + @extend .header-common; + } + + .header-left { + grid-area: header-left; + @extend .header-text; + @extend .left-panel; + border-bottom: $grid-border; + + span { + font-family: OpenSans-Regular; + font-size: 14px; + } + ; + } + + .header-right { + grid-area: header-right; + + @extend .header-text; + } + + .quantity-label { + grid-area: quantity-label; + @extend .header-common; + height: 100%; + font-family: OpenSans-Regular; + } + + input[type="number"]:hover::-webkit-inner-spin-button { + height: 20px; + } + + .popup-content { + display: grid; + grid-template-columns: 400px auto 30px 93px; + grid-template-rows: 50px calc(100vh - 180px); + grid-template-areas: "header-left header-right quantity-label quantity" "model-information instance-form instance-form instance-form"; + padding: 0; + } +} + +.modal { + background-color: #191919; + opacity: 0.8; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0; +} + +@media (min-width: 1150px) { + .popup-content { + grid-template-rows: 30px 680px; + } +} + +.modal-content { + border-radius: 0; + box-shadow: none; + border: none; + min-height: calc(100vh); + +} + +.modal-footer { + padding: 0; + position: absolute; + bottom: 0; + width: 100%; + + .cancel { + width: 120px; + height: 36px; + background: #ffffff; + border: 1px solid #009fdb; + border-radius: 2px; + + span { + font-family: OpenSans-Regular; + font-size: 14px; + color: #009fdb; + line-height: 16px; + } + } + + .startFromScratchButton { + width: 150px !important; + } + + .submit { + min-width: 120px; + height: 36px; + background: #009fdb; + border-radius: 2px; + border-color: #009fdb; + + + span { + font-family: OpenSans-Regular; + font-size: 14px; + color: #FFFFFF; + line-height: 16px; + } + } +} + +.modal-header { + background-color: #009fdb; + + padding-bottom: 13px; + padding-top: 13px; + padding-left: 29px; + padding-right: 21px; + + .close { + font-size: 32px; + font-weight: 200; + color: #d8d8d8; + text-shadow: none; + filter: none; + opacity: 1; + } + + .modal-title { + font-family: OpenSans-Regular; + font-size: 24px; + color: #fff; + line-height: 34px; + } +} + +.modal-body { + padding: 0; + height: calc(85vh); + + .description-section { + padding: 20px; + font-size: 20px; + } + + .filter-input { + float: right; + width: 50%; + } + + .details-item { + text-align: right; + } + + + td.loadTemplateButton { + text-align: center; + vertical-align: middle; + } + + td { + text-align: center; + vertical-align: middle; + padding-left: 5px; + padding-right: 5px; + } + + .member-table-row:hover { + background: #80808033 !important; + } + + .member-table-row.selected { + background: #8080808f !important; + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts new file mode 100644 index 000000000..4d89750f9 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts @@ -0,0 +1,57 @@ +import {Component, OnDestroy, OnInit} from "@angular/core"; +import {DialogComponent, DialogService} from "ng2-bootstrap-modal"; +import {IframeService} from "../../../utils/iframe.service"; +import {ActivatedRoute} from "@angular/router"; +import {ServiceInfoService} from "../../../server/serviceInfo/serviceInfo.service"; +import {InstantiationTemplatesModalService} from "./instantiation.templates.modal.service"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + +@Component({ + selector: 'template-modal', + templateUrl: 'instantiation.templates.modal.component.html', + styleUrls: ['instantiation.templates.modal.component.scss'] +}) + +export class InstantiationTemplatesModalComponent extends DialogComponent<string, boolean> implements OnInit, OnDestroy { + + selectedJobId : string = null; + templateModalComponentService: InstantiationTemplatesModalService; + originalTableData: InstantiationTemplatesRowModel[] = []; + filterTableData : InstantiationTemplatesRowModel[] = []; + filterText: string; + + constructor(dialogService: DialogService, + private _iframeService: IframeService, + private _serviceInfoService: ServiceInfoService, + private _templateModalComponentService: InstantiationTemplatesModalService, + private _route: ActivatedRoute) { + super(dialogService); + this.templateModalComponentService = _templateModalComponentService; + } + + ngOnInit(): void { + this.filterText = ''; + this._route + .queryParams + .subscribe(params => { + this._serviceInfoService.getServicesJobInfo(true, params['serviceModelId']).subscribe((jobs) => { + this.originalTableData = this._templateModalComponentService.convertResponseToUI(jobs); + this.filterTableData = this.originalTableData; + }); + }); + } + + loadTemplate = () => { + + }; + + + closeModal(): void { + this._iframeService.removeClassCloseModal('content'); + this.dialogService.removeDialog(this); + setTimeout(() => { + window.parent.postMessage("closeIframe", "*"); + }, 15); + + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts new file mode 100644 index 000000000..1ff0f61e2 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts @@ -0,0 +1,133 @@ +import {getTestBed, TestBed} from '@angular/core/testing'; +import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; +import {InstantiationTemplatesModalService} from "./instantiation.templates.modal.service"; +import {AaiService} from "../../../services/aaiService/aai.service"; +import {ActivatedRoute} from "@angular/router"; +import {IframeService} from "../../../utils/iframe.service"; +import {NgRedux} from "@angular-redux/store"; +import {FeatureFlagsService} from "../../../services/featureFlag/feature-flags.service"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + + +class ActivatedRouteMock<T> { + queryParams() { + return { + serviceModelId: '6e59c5de-f052-46fa-aa7e-2fca9d674c44' + } + } +} + +class MockAppStore { + +} + +describe('instantiation templates modal service', () => { + let injector; + let service: InstantiationTemplatesModalService; + let httpMock: HttpTestingController; + let _aaiService: AaiService; + let _activatedRoute: ActivatedRoute; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [InstantiationTemplatesModalService, + IframeService, + AaiService, + FeatureFlagsService, + {provide: ActivatedRoute, useClass: ActivatedRouteMock}, + {provide: NgRedux, useClass: MockAppStore} + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + service = injector.get(InstantiationTemplatesModalService); + httpMock = injector.get(HttpTestingController); + _aaiService = injector.get(AaiService); + _activatedRoute = injector.get(ActivatedRoute); + + })().then(done).catch(done.fail)); + + + test('service should be defined', () => { + expect(service).toBeDefined(); + }); + + + test('convertResponseToUI - should return table data', () => { + const jobs = [{ + "id": 5, + "created": 1524995555000, + "modified": 1524995556000, + "action": "INSTANTIATE", + "createdId": null, + "modifiedId": null, + "rowNum": null, + "auditUserId": null, + "auditTrail": null, + "jobId": "9f88fdb5-bb47-4bf3-8c5f-98f1ad0ec87c", + "templateId": "ce4ec177-cfc8-483e-8a2c-b7aea53fd740", + "userId": "16807000", + "msoRequestId": "c0011670-0e1a-4b74-945d-8bf5aede1d91", + "requestId": null, + "jobStatus": "FAILED", + "statusModifiedDate": 1524995555000, + "hidden": false, + "pause": false, + "owningEntityId": "aaa1", + "owningEntityName": "aaa1", + "project": "WATKINS", + "aicZoneId": "BAN1", + "aicZoneName": "VSDKYUTP-BAN1", + "tenantId": "1178612d2b394be4834ad77f567c0af2", + "tenantName": "AIN Web Tool-15-D-SSPtestcustome", + "regionId": "hvf6", + "regionName": null, + "serviceType": "TYLER SILVIA", + "subscriberName": "e433710f-9217-458d-a79d-1c7aff376d89", + "serviceInstanceId": null, + "serviceInstanceName": 'serviceInstanceName', + "serviceModelId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceModelName": "ComplexService", + "serviceModelVersion": "1.0", + "createdBulkDate": 1524995555000, + "isRetryEnabled": false + }]; + const tableRows: InstantiationTemplatesRowModel[] = service.convertResponseToUI(jobs); + expect(tableRows).toHaveLength(1); + expect(tableRows[0].userId).toEqual('16807000'); + expect((new Date(tableRows[0].createDate)).toISOString()).toEqual('2018-04-29T09:52:35.000Z'); + expect(tableRows[0].instanceName).toEqual('serviceInstanceName'); + expect(tableRows[0].instantiationStatus).toEqual('FAILED'); + expect(tableRows[0].region).toEqual('hvf6 (AAA1)'); + expect(tableRows[0].tenant).toEqual('AIN Web Tool-15-D-SSPtestcustome'); + expect(tableRows[0].aicZone).toEqual('VSDKYUTP-BAN1'); + expect(tableRows[0].jobId).toEqual('9f88fdb5-bb47-4bf3-8c5f-98f1ad0ec87c'); + }); + + + test('getCloudOwner should remove "-att" from owningEntityName : "att-owner', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({ + owningEntityName: 'att-owner', + regionId: 'regionId' + }); + expect(result.region).toEqual('regionId (OWNER)'); + }); + + test('getCloudOwner should not return owningEntityName if not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({owningEntityName: null, regionId: 'regionId'}); + expect(result.region).toEqual('regionId'); + }); + + test('getInstanceName should return instance name id exist if not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({serviceInstanceName: 'instanceName'}); + expect(result.instanceName).toEqual('instanceName'); + }); + + test('getInstanceName should return <Automatically generated> if instance name not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({}); + expect(result.instanceName).toEqual('<Automatically generated>'); + }); + +}); diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts new file mode 100644 index 000000000..7126da36a --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts @@ -0,0 +1,15 @@ +import {Injectable} from "@angular/core"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + +@Injectable() +export class InstantiationTemplatesModalService { + convertResponseToUI = (jobsResponse: any[]): InstantiationTemplatesRowModel[] => { + let tableRows: InstantiationTemplatesRowModel[] = []; + + jobsResponse.forEach((job) => { + tableRows.push(new InstantiationTemplatesRowModel(job)); + }); + + return tableRows; + }; +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts new file mode 100644 index 000000000..08982cc67 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts @@ -0,0 +1,51 @@ +import * as moment from 'moment'; +import * as _ from 'lodash'; + +export class InstantiationTemplatesRowModel { + readonly jobId: string; + readonly userId ?: string; + readonly createDate ?: string; + readonly instanceName ?: string; + readonly instantiationStatus?: string; + readonly summary?: string; + readonly region?: string; + readonly tenant?: string; + readonly aicZone?: string; + + constructor(data) { + this.jobId = data.jobId; + this.userId = !_.isNil(data.created) ? data.userId : null; + this.createDate = !_.isNil(data.created) ? moment(data.created).format("YYYY-MM-DD HH:mm:ss") : null; + this.instanceName = this.getInstanceName(data.serviceInstanceName); + this.instantiationStatus = !_.isNil(data.jobStatus) ? data.jobStatus : null; + this.summary = null; + this.region = this.getRegion(data.regionId, data.owningEntityName); + this.tenant = !_.isNil(data.tenantName) ? data.tenantName : null; + this.aicZone = !_.isNil(data.aicZoneName) ? data.aicZoneName : null; + + } + + + /************************************************************************************************** + return the LCP region and in brackets the cloud owner removing the “att-“ with capital letters. + **************************************************************************************************/ + getCloudOwner = (owningEntityName: string): string => { + const splitByAtt: string[] = owningEntityName.split('att-'); + let owning: string = splitByAtt[splitByAtt.length - 1]; + return owning.toUpperCase(); + }; + + getRegion = (regionId: string, owningEntityName: string): string => { + const convertOwning = !_.isNil(owningEntityName) ? `(${this.getCloudOwner(owningEntityName)})` : ''; + return `${regionId} ${convertOwning}`.trim(); + }; + + + getInstanceName = (instanceName?: string): string => { + if (_.isNil(instanceName)) { + return '<Automatically generated>'; + } + return instanceName; + } +} + diff --git a/vid-webpack-master/src/app/shared/models/formControlModels/formPopupDetails.model.ts b/vid-webpack-master/src/app/shared/models/formControlModels/formPopupDetails.model.ts index 8ea3d2d0b..40d74d63f 100644 --- a/vid-webpack-master/src/app/shared/models/formControlModels/formPopupDetails.model.ts +++ b/vid-webpack-master/src/app/shared/models/formControlModels/formPopupDetails.model.ts @@ -14,6 +14,8 @@ export class FormPopupDetails { modelInformationItems: ModelInformationItem[]; onSubmit : (that : any, form: FormGroup , ...args) => void; onCancel : (that : any, form: FormGroup) => void; + onOtherAction: (that: any, form: FormGroup) => void; + constructor(that : any, popupTypeName : PopupType , @@ -25,7 +27,8 @@ export class FormPopupDetails { dynamicInputsControlList : FormControlModel[], modelInformationItems : ModelInformationItem[], onSubmit : (that : any, form : FormGroup, ...args) => void, - onCancel : (that : any, form : FormGroup) => void){ + onCancel: (that: any, form: FormGroup) => void, + onOtherAction?: (that: any, form: FormGroup) => void) { this.title = title; this.leftSubTitle = leftSubTitle; this.rightSubTitle = rightSubTitle; @@ -34,6 +37,7 @@ export class FormPopupDetails { this.modelInformationItems = modelInformationItems; this.onSubmit = onSubmit; this.onCancel = onCancel; + this.onOtherAction = onOtherAction; this.popupTypeName = popupTypeName; this.UUIDData = UUIDData; this.that = that; @@ -49,6 +53,7 @@ export enum PopupType { VNF_MACRO ='vnf macro', VNF_A_LA_CARTE = 'vnf a-la-carte', VFMODULE = 'vfModule', + VFMODULE_UPGRADE = 'vfModule_upgrade', NETWORK_MACRO = 'network_macro', VNF_GROUP = 'vnfGroup' } diff --git a/vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts b/vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts index b13745104..f5db715ba 100644 --- a/vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts +++ b/vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts @@ -7,10 +7,14 @@ export class MultiselectFormControl extends FormControlModel{ options$ : Observable<any[]>; args : string[]; onInit: (data : MultiselectFormControl, form: FormGroup) => Observable<any>; - selectedItems : string; + selectedItems : any[]; onInitSelectedItems : string[]; + selectedFieldName : string; ngValue : string; settings: {}; + onInitSelectedField?: string[]; + convertOriginalDataToArray? : (values)=> void; + limitSelection?: number; constructor(data) { @@ -18,10 +22,14 @@ export class MultiselectFormControl extends FormControlModel{ this.type = FormControlType.MULTI_SELECT; this.options$ = data.options; this.onInit = data.onInit; - this.selectedItems = data.selectedItems; + this.selectedItems = data.selectedItems || []; this.onInitSelectedItems = data.onInitSelectedItems ? data.onInitSelectedItems : null; this.ngValue = data.selectedField ? data.selectedField : 'id'; + this.selectedFieldName = data.selectedFieldName; this.settings = data.settings || {}; + this.onInitSelectedField = data.onInitSelectedField ? data.onInitSelectedField : null; + this.convertOriginalDataToArray = data.convertOriginalDataToArray ? data.convertOriginalDataToArray : null + this.limitSelection = data.limitSelection ? data.limitSelection : 1000; } } 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/vfModule.ts b/vid-webpack-master/src/app/shared/models/vfModule.ts index c75202124..8f92ba428 100644 --- a/vid-webpack-master/src/app/shared/models/vfModule.ts +++ b/vid-webpack-master/src/app/shared/models/vfModule.ts @@ -1,4 +1,5 @@ import {NodeModel, NodeModelResponseInterface} from "./nodeModel"; +import {Utils} from "../utils/utils"; export interface Properties{ @@ -23,7 +24,7 @@ export class VfModule extends NodeModel { modelCustomizationName: string; volumeGroupAllowed : boolean; - constructor(vf?: VFModuleResponseInterface) { + constructor(vf?: VFModuleResponseInterface, flags?: { [key: string]: boolean }) { super(vf); if(vf){ this.customizationUuid = vf.customizationUuid; @@ -32,7 +33,7 @@ export class VfModule extends NodeModel { } if (vf && vf.properties) { this.min = vf.properties.minCountInstances; - this.max = vf.properties.maxCountInstances; + this.max = Utils.getMaxVfModule(vf.properties, flags); this.initial = vf.properties.initialCount; this.rollbackOnFailure = true } 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/pipes/searchFilter/search-filter.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts new file mode 100644 index 000000000..2567cbf27 --- /dev/null +++ b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts @@ -0,0 +1,17 @@ +import {SearchFilterPipe} from "./search-filter.pipe"; +import * as _ from 'lodash'; + +describe('Search filter pipe', () => { + + const items= [{'id':1, 'name': 'aaa'}, + {'id':12, 'name': 'bbb', 'children':{'first': 155, 'second': 2, 'third': 3}}, + {'id':3, 'name': 'ccc', 'children':{'first': 1, 'BbB': 'BbB', 'third': 3}}, + {'id':4, 'name': 'aad', 'children':{'first': 1, 'second': 2, 'third': 3}}]; + + test('should return items contains substring bb', () => { + let filter = new SearchFilterPipe(); + let res:any[] = filter.transform(items,'bb'); + expect(_.map(res, 'name' )).toEqual(['bbb','ccc']); + }); + +}); diff --git a/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts new file mode 100644 index 000000000..6e5cfc667 --- /dev/null +++ b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts @@ -0,0 +1,43 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import * as _ from 'lodash'; + +@Pipe({ + name: 'searchFilter' +}) +export class SearchFilterPipe implements PipeTransform { + transform(items: Object[], searchText: string): any[] { + if (!items) return []; + if (!searchText) return items; + return items.filter((item: object) => { + + const deepFlatObject = this.flatten(item); + + const values = _.values(deepFlatObject).map((item: string) => { + return item.toString().toLowerCase() + }); + + return _.some(values, _.method('includes', searchText.toLowerCase())); + }); + } + + flatten = object => { + return Object.assign( + {}, + ...(function _flatten(objectBit, path = '') { + //spread the result into our return object + if(objectBit === null) return []; + return [].concat( + //concat everything into one level + + ...Object.keys(objectBit).map( + //iterate over object + key => + typeof objectBit[key] === 'object' //check if there is a nested object + ? _flatten(objectBit[key], `${path}/${key}`) //call itself if there is + : { [`${path}/${key}`]: objectBit[key] } //append object with it’s path as key + ) + ); + })(object) + ); + }; +} diff --git a/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.spec.ts b/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.spec.ts new file mode 100644 index 000000000..1a3a1ab3f --- /dev/null +++ b/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.spec.ts @@ -0,0 +1,66 @@ +import {RecreateResolver} from "./recreate.resolver"; +import {getTestBed, TestBed} from '@angular/core/testing'; +import {NgRedux} from "@angular-redux/store"; +import {InstantiationTemplatesService} from "../../services/templateService/instantiationTemplates.service"; +import {AaiService} from "../../services/aaiService/aai.service"; +import {mock} from "ts-mockito"; +import {ServiceInstance} from "../../models/serviceInstance"; +import {HttpClientTestingModule} from "@angular/common/http/testing"; +import {FeatureFlagsService} from "../../services/featureFlag/feature-flags.service"; +import {convertToParamMap} from "@angular/router"; +import {of} from 'rxjs/observable/of' + +class MockAppStore<T> { + getState() {} +} + +describe('Recreate resolver', () => { + + let injector; + let recreateResolver: RecreateResolver; + let aaiService: AaiService; + let instantiationTemplatesService: InstantiationTemplatesService; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + FeatureFlagsService, + InstantiationTemplatesService, + RecreateResolver, + AaiService, + {provide: NgRedux, useClass: MockAppStore}, + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + recreateResolver = injector.get(RecreateResolver); + aaiService = injector.get(AaiService); + instantiationTemplatesService = injector.get(InstantiationTemplatesService); + })().then(done).catch(done.fail)); + + test("when resolve() invoked -> then getServiceModelById and retrieveAndStoreInstantiationTemplateTopology are called", done => { + jest.spyOn(aaiService, 'getServiceModelById') + .mockReturnValue(of({})); + jest.spyOn(instantiationTemplatesService, 'retrieveAndStoreInstantiationTemplateTopology') + .mockReturnValue(of(mock(ServiceInstance))); + + recreateResolver.resolve(<any>{ + queryParamMap: + convertToParamMap({ + serviceModelId: "someServiceModelId", + jobId: "someJobId", + }) + }) + + .subscribe(() => { + expect(aaiService.getServiceModelById) + .toHaveBeenCalledWith("someServiceModelId"); + expect(instantiationTemplatesService.retrieveAndStoreInstantiationTemplateTopology) + .toHaveBeenCalledWith("someJobId", "someServiceModelId"); + done(); + }); + }) + +}); diff --git a/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.ts b/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.ts new file mode 100644 index 000000000..b7e952a64 --- /dev/null +++ b/vid-webpack-master/src/app/shared/resolvers/recreate/recreate.resolver.ts @@ -0,0 +1,29 @@ +import {Injectable} from "@angular/core"; +import {NgRedux} from "@angular-redux/store"; + +import {ActivatedRouteSnapshot, Resolve} from "@angular/router"; +import {Observable} from "rxjs"; +import {AppState} from "../../store/reducers"; +import {InstantiationTemplatesService} from "../../services/templateService/instantiationTemplates.service"; +import {forkJoin} from "rxjs/observable/forkJoin"; +import {AaiService} from "../../services/aaiService/aai.service"; +import {ServiceInstance} from "../../models/serviceInstance"; + +@Injectable() +export class RecreateResolver implements Resolve<Observable<[any, ServiceInstance]>> { + constructor(private _templateService: InstantiationTemplatesService, + private _aaiService: AaiService, + private _store: NgRedux<AppState>) { + } + + resolve(route: ActivatedRouteSnapshot): Observable<[any, ServiceInstance]> { + const serviceModelId: string = route.queryParamMap.get("serviceModelId"); + const jobId: string = route.queryParamMap.get("jobId"); + + let serviceModelApi = this._aaiService.getServiceModelById(serviceModelId); + let instantiationTemplateApi = this._templateService.retrieveAndStoreInstantiationTemplateTopology(jobId, serviceModelId); + + return forkJoin([serviceModelApi, instantiationTemplateApi]) + } + +} diff --git a/vid-webpack-master/src/app/shared/resolvers/viewEdit/viewEdit.resolver.ts b/vid-webpack-master/src/app/shared/resolvers/viewEdit/viewEdit.resolver.ts index 540e02fe6..075e18f25 100644 --- a/vid-webpack-master/src/app/shared/resolvers/viewEdit/viewEdit.resolver.ts +++ b/vid-webpack-master/src/app/shared/resolvers/viewEdit/viewEdit.resolver.ts @@ -10,6 +10,7 @@ import {ServiceInstance} from "../../models/serviceInstance"; import * as _ from "lodash"; import {ModelInfo} from "../../models/modelInfo"; import {FeatureFlagsService, Features} from "../../services/featureFlag/feature-flags.service"; +import {Utils} from "../../utils/utils"; @Injectable() export class ViewEditResolver implements Resolve<Observable<boolean>> { @@ -69,7 +70,7 @@ export class ViewEditResolver implements Resolve<Observable<boolean>> { }; setIsALaCarte(service: any, instantiationType) :void{ - service.isALaCarte = instantiationType === 'ALaCarte'; + service.isALaCarte = Utils.isALaCarte(instantiationType); }; } diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts index 147434b1a..0234ea514 100644 --- a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts +++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts @@ -37,6 +37,25 @@ describe('Service Info Service', () => { }); }); + describe('#getServicesJobInfo', ()=> { + test('should call without serviceModelId', ()=>{ + let job: ServiceInfoModel = new ServiceInfoModel(); + + service.getServicesJobInfo().subscribe(); + const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH); + + expect(req.request.method).toBe('GET'); + }); + + test('should call with serviceModelId', ()=>{ + let job: ServiceInfoModel = new ServiceInfoModel(); + + service.getServicesJobInfo(true, "123").subscribe(); + const req = httpMock.expectOne(`${Constants.Path.SERVICES_JOB_INFO_PATH}?${Constants.Path.SERVICE_MODEL_ID}=123`); + expect(req.request.method).toBe('GET'); + }); + }); + describe('#getALaCarteJobAuditStatus Without params', ()=> { test('should return Observable<Object[]>', ()=>{ let job: ServiceInfoModel = new ServiceInfoModel(); diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts index fe6ebc7ee..388afdba0 100644 --- a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts +++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts @@ -2,8 +2,6 @@ import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import {ServiceInfoModel} from './serviceInfo.model'; import {HttpClient, HttpHeaders} from '@angular/common/http'; -import { of } from 'rxjs'; -import { map } from 'rxjs/operators'; import {Constants} from '../../utils/constants'; import {forkJoin} from "rxjs/observable/forkJoin"; import * as _ from 'lodash'; @@ -14,10 +12,11 @@ export class ServiceInfoService { constructor(private _http: HttpClient) { } - getServicesJobInfo(filterByUser : boolean, showSpinner: boolean = true): Observable<ServiceInfoModel[]> { + getServicesJobInfo(showSpinner: boolean = true, serviceModelId: string = null): Observable<ServiceInfoModel[]> { let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH; let headers = new HttpHeaders({'x-show-spinner': showSpinner.toString()}); - return this._http.get<ServiceInfoModel[]>(pathQuery, { headers: headers }).map(res => res ); + let params = serviceModelId ? {serviceModelId} : {}; + return this._http.get<ServiceInfoModel[]>(pathQuery, { headers: headers, params }); } deleteJob(jobId: string): Observable<any> { diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts index a34f2fe20..03461eaa1 100644 --- a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts +++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts @@ -32,6 +32,7 @@ describe('Default Data Generator Service', () => { let result = service.generateVFModule(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID], [], false, true); expect(result.isMissingData).toBeTruthy(); + expect(result.rollbackOnFailure).toBeTruthy(); }); test('generateVFModule should create vf module object', () => { @@ -51,6 +52,7 @@ describe('Default Data Generator Service', () => { expect(result.sdncPreReload).toBeNull(); expect(result.isMissingData).toBeTruthy(); expect(result.instanceParams).toEqual([{}]); + expect(result.rollbackOnFailure).toBeNull(); }); test('generateVNFData should create vnf object', () => { diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts index b0baa82ec..a3cb475a0 100644 --- a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts +++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts @@ -186,7 +186,7 @@ export class DefaultDataGeneratorService { for (let networkUUID in serviceHierarchy.networks) { const isEcompGeneratedNaming = this.getIsEcompGeneratedNaming(serviceHierarchy.networks[networkUUID]); let min_vnf_instances_greater_than_0 = serviceHierarchy.networks[networkUUID].properties['min_instances'] && serviceHierarchy.networks[networkUUID].properties['min_instances'] > 0; - if(this.store.getState().global.flags['FLAG_DEFAULT_VNF'] && min_vnf_instances_greater_than_0) + if(min_vnf_instances_greater_than_0) { this.createNetworkInstanceReduxIfNotExist( serviceId, @@ -203,7 +203,7 @@ export class DefaultDataGeneratorService { for (let vnfGroupUUID in serviceHierarchy.vnfGroups) { const isEcompGeneratedNaming = this.getIsEcompGeneratedNaming(serviceHierarchy.vnfGroups[vnfGroupUUID]); let min_vnf_group_instances_greater_than_0 = serviceHierarchy.vnfGroups[vnfGroupUUID].properties['min_instances'] && serviceHierarchy.vnfGroups[vnfGroupUUID].properties['min_instances'] > 0; - if(this.store.getState().global.flags['FLAG_DEFAULT_VNF'] && min_vnf_group_instances_greater_than_0) + if(min_vnf_group_instances_greater_than_0) { this.createVnfGroupInstanceReduxIfNotExist( serviceId, @@ -244,7 +244,7 @@ export class DefaultDataGeneratorService { } let min_vnf_instances_greater_than_0 = serviceHierarchy.vnfs[vnfUUID].properties['min_instances'] && serviceHierarchy.vnfs[vnfUUID].properties['min_instances'] > 0; - if(this.store.getState().global.flags['FLAG_DEFAULT_VNF'] && min_vnf_instances_greater_than_0) + if(min_vnf_instances_greater_than_0) { this.createVNFInstanceReduxIfNotExist( serviceId, @@ -328,6 +328,7 @@ export class DefaultDataGeneratorService { instanceParams ], 'trackById': DefaultDataGeneratorService.createRandomTrackById(), + 'rollbackOnFailure' : isALaCarte ? true : null, }; } 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 d6c37c936..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 @@ -8,11 +8,14 @@ export enum Features { FLAG_1902_VNF_GROUPING='FLAG_1902_VNF_GROUPING', FLAG_VF_MODULE_RESUME_STATUS_CREATE = 'FLAG_VF_MODULE_RESUME_STATUS_CREATE', FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE = 'FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE', - FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE = 'FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE', FLAG_1906_COMPONENT_INFO = 'FLAG_1906_COMPONENT_INFO', FLAG_1908_RESUME_MACRO_SERVICE = 'FLAG_1908_RESUME_MACRO_SERVICE', FLAG_FLASH_REPLACE_VF_MODULE ='FLAG_FLASH_REPLACE_VF_MODULE', - FLAG_FLASH_MORE_ACTIONS_BUTTON_IN_OLD_VIEW_EDIT ='FLAG_FLASH_MORE_ACTIONS_BUTTON_IN_OLD_VIEW_EDIT' + FLAG_FLASH_MORE_ACTIONS_BUTTON_IN_OLD_VIEW_EDIT ='FLAG_FLASH_MORE_ACTIONS_BUTTON_IN_OLD_VIEW_EDIT', + FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS ='FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS', + FLAG_2004_INSTANTIATION_STATUS_FILTER ='FLAG_2004_INSTANTIATION_STATUS_FILTER', + FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE = 'FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE', + FLAG_2004_TEMP_BUTTON_TO_INSTANTIATION_STATUS_FILTER ='FLAG_2004_TEMP_BUTTON_TO_INSTANTIATION_STATUS_FILTER', } @Injectable() @@ -24,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<AppState>): { [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<AppState>):boolean { let storeStateGlobalFields = store.getState().global; diff --git a/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.spec.ts b/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.spec.ts new file mode 100644 index 000000000..80b113bde --- /dev/null +++ b/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.spec.ts @@ -0,0 +1,51 @@ +import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing"; +import {InstantiationTemplatesService} from "./instantiationTemplates.service"; +import {mock} from "ts-mockito"; +import {NgRedux} from "@angular-redux/store"; +import {getTestBed, TestBed} from "@angular/core/testing"; +import {ServiceInstance} from "../../models/serviceInstance"; +import {Constants} from "../../utils/constants"; + +class MockAppStore<T> { + dispatch() {} + getState() {} +} + +describe("TemplateService", ()=>{ + let injector; + let httpMock: HttpTestingController; + let templateService: InstantiationTemplatesService; + + beforeAll( done => (async () => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + InstantiationTemplatesService, + {provide: NgRedux, useClass: MockAppStore}, + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + httpMock = injector.get(HttpTestingController); + templateService = injector.get(InstantiationTemplatesService); + })().then(done).catch(done.fail)); + + describe ('#retrieveInstantiationTemplateTopology tests', () => { + test('when called -> retrieve template from backend', done => { + const mockedTemplate = mock(ServiceInstance); + const jobId: string = "some-random-job-id"; + + templateService.retrieveInstantiationTemplateTopology(jobId) + .subscribe((result: ServiceInstance) => { + expect(Object.is(result, mockedTemplate)).toBe(true); + done(); + }); + + httpMock + .expectOne(`${Constants.Path.INSTANTIATION_TEMPLATE_TOPOLOGY}/${jobId}`) + .flush(mockedTemplate); + }) + }) +}); + diff --git a/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.ts b/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.ts new file mode 100644 index 000000000..018e0d367 --- /dev/null +++ b/vid-webpack-master/src/app/shared/services/templateService/instantiationTemplates.service.ts @@ -0,0 +1,27 @@ +import {Injectable} from "@angular/core"; +import {HttpClient} from "@angular/common/http"; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../store/reducers"; +import {Observable} from "rxjs"; +import {ServiceInstance} from "../../models/serviceInstance"; +import {Constants} from "../../utils/constants"; +import {createServiceInstance} from "../../storeUtil/utils/service/service.actions"; +import {createServiceInstanceFromTemplate} from "../../storeUtil/utils/useTemplate/useTemplate.action"; + +@Injectable() +export class InstantiationTemplatesService { + constructor(private http: HttpClient, private store: NgRedux<AppState>) { + } + + retrieveInstantiationTemplateTopology(jobId: string): Observable<ServiceInstance> { + let pathQuery: string = `${Constants.Path.INSTANTIATION_TEMPLATE_TOPOLOGY}/${jobId}`; + return this.http.get<ServiceInstance>(pathQuery) + } + + public retrieveAndStoreInstantiationTemplateTopology(jobId: string, serviceModelId: string): Observable<ServiceInstance> { + return this.retrieveInstantiationTemplateTopology(jobId).do((instantiationTemplate: ServiceInstance) => { + this.store.dispatch(createServiceInstanceFromTemplate(instantiationTemplate, serviceModelId)); + }); + }; + +} diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts index 93452256b..273dff472 100644 --- a/vid-webpack-master/src/app/shared/shared.module.ts +++ b/vid-webpack-master/src/app/shared/shared.module.ts @@ -42,6 +42,7 @@ import {NetworkPopupService} from "./components/genericFormPopup/genericFormServ import {NetworkControlGenerator} from "./components/genericForm/formControlsServices/networkGenerator/network.control.generator"; import {BasicPopupService} from "./components/genericFormPopup/genericFormServices/basic.popup.service"; import {VfModulePopuopService} from "./components/genericFormPopup/genericFormServices/vfModule/vfModule.popuop.service"; +import {VfModuleUpgradePopupService} from "./components/genericFormPopup/genericFormServices/vfModuleUpgrade/vfModule.upgrade.popuop.service"; import {VfModuleControlGenerator} from "./components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator"; import {OrderByPipe} from "./pipes/order/orderBy.pipe"; import {ServicePopupService} from "./components/genericFormPopup/genericFormServices/service/service.popup.service"; @@ -72,6 +73,12 @@ import {ClickOutsideDirective} from "./directives/clickOutside/clickOutside.dire import {DynamicInputsComponent} from "./components/dynamic-inputs/dynamic-inputs.component"; import {DynamicInputLabelPipe} from "./pipes/dynamicInputLabel/dynamic-input-label.pipe"; import {ModelInformationService} from "./components/model-information/model-information.service"; +import {MultiselectFormControlService} from "./components/formControls/component/multiselect/multiselect.formControl.service"; +import {InstantiationTemplatesModalComponent} from "./components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component"; +import {InstantiationTemplatesModalService} from "./components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service"; +import {SearchFilterPipe} from "./pipes/searchFilter/search-filter.pipe"; +import {RecreateResolver} from "./resolvers/recreate/recreate.resolver"; +import {InstantiationTemplatesService} from "./services/templateService/instantiationTemplates.service"; @NgModule({ @@ -112,6 +119,7 @@ import {ModelInformationService} from "./components/model-information/model-info SafePipe, ObjectToArrayPipe, DataFilterPipe, + SearchFilterPipe, InputFormControlComponent, FormControlMessageErrorComponent, GenericFormPopupComponent, @@ -123,7 +131,8 @@ import {ModelInformationService} from "./components/model-information/model-info SvgComponent, ErrorMsgComponent, DynamicInputsComponent, - DynamicInputLabelPipe + DynamicInputLabelPipe, + InstantiationTemplatesModalComponent ], exports: [ PopoverComponent, @@ -143,6 +152,7 @@ import {ModelInformationService} from "./components/model-information/model-info SafePipe, ObjectToArrayPipe, DataFilterPipe, + SearchFilterPipe, InputFormControlComponent, FormControlMessageErrorComponent, GenericFormPopupComponent, @@ -158,7 +168,8 @@ import {ModelInformationService} from "./components/model-information/model-info ], entryComponents : [ GenericFormPopupComponent, - SearchElementsModalComponent + SearchElementsModalComponent, + InstantiationTemplatesModalComponent ], providers: [ ServiceInfoService, @@ -173,6 +184,8 @@ import {ModelInformationService} from "./components/model-information/model-info FlagsResolve, ViewEditResolver, RetryResolver, + RecreateResolver, + InstantiationTemplatesService, ServiceControlGenerator, ServicePopupService, VnfControlGenerator, @@ -181,6 +194,7 @@ import {ModelInformationService} from "./components/model-information/model-info CustomValidators, NetworkPopupService, VfModulePopuopService, + VfModuleUpgradePopupService, NetworkControlGenerator, VnfGroupControlGenerator, VnfGroupPopupService, @@ -193,7 +207,10 @@ import {ModelInformationService} from "./components/model-information/model-info ElementsTableService, ErrorMsgService, DataFilterPipe, + SearchFilterPipe, ModelInformationService, + MultiselectFormControlService, + InstantiationTemplatesModalService ] }) export class SharedModule { diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.actions.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.actions.ts index 7a10eba0a..79dd3c717 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.actions.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.actions.ts @@ -5,6 +5,7 @@ import {ServiceType} from "../../../models/serviceType"; import {ITreeNode} from "angular-tree-component/dist/defs/api"; export enum GeneralActions { + MERGE_OBJECT_BY_PATH = "MERGE_OBJECT_BY_PATH", UPDATE_LCP_REGIONS_AND_TENANTS = "UPDATE_LCP_REGIONS_AND_TENANTS", UPDATE_SUBSCRIBERS = "UPDATE_SUBSCRIBERS", UPDATE_PRODUCT_FAMILIES = "UPDATE_PRODUCT_FAMILIES", @@ -78,6 +79,11 @@ export interface UpdateServiceTypesAction extends Action { subscriberId: string; } +export interface MergeObjectByPathAction extends Action{ + path: String[]; + payload: object; +} + export const updateLcpRegionsAndTenants: ActionCreator<UpdateLcpRegionsAndTenantsAction> = lcpRegionsAndTenants => ({ type: GeneralActions.UPDATE_LCP_REGIONS_AND_TENANTS, lcpRegionsAndTenants: lcpRegionsAndTenants @@ -147,4 +153,10 @@ export const updateServiceTypes: ActionCreator<UpdateServiceTypesAction> = (serv subscriberId: subscriberId }); +export const mergeObjectByPathAction : ActionCreator<MergeObjectByPathAction> = (path, payload) => ({ + type: GeneralActions.MERGE_OBJECT_BY_PATH, + path, + payload +}); + diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.spec.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.spec.ts index ed456314e..952a92842 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.spec.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.spec.ts @@ -1,22 +1,12 @@ import {LcpRegion} from "../../../models/lcpRegion"; import {Tenant} from "../../../models/tenant"; import {generalReducer} from "./general.reducers"; -import { - ChangeInstanceCounterAction, - RemoveInstanceAction, - DuplicateBulkInstancesAction, - GeneralActions, - UpdateAicZonesAction, - UpdateCategoryParametersAction, - UpdateProductFamiliesAction, - UpdateServiceTypesAction, - UpdateSubscribersAction, - UpdateUserIdAction, UpdateNetworkCollectionFunction, -} from "./general.actions"; +import {ChangeInstanceCounterAction, DuplicateBulkInstancesAction, GeneralActions, MergeObjectByPathAction, RemoveInstanceAction, UpdateAicZonesAction, UpdateCategoryParametersAction, UpdateNetworkCollectionFunction, UpdateProductFamiliesAction, UpdateServiceTypesAction, UpdateSubscribersAction, UpdateUserIdAction,} from "./general.actions"; import {SelectOption} from "../../../models/selectOption"; import {ServiceType} from "../../../models/serviceType"; import {ITreeNode} from "angular-tree-component/dist/defs/api"; import {VnfInstance} from "../../../models/vnfInstance"; +import each from "jest-each"; describe('generalReducer', () => { test('#UPDATE_LCP_REGIONS_AND_TENANTS : should update lcp region and tenants', () => { @@ -370,6 +360,45 @@ describe('generalReducer', () => { expect(state).toBeDefined(); expect(state['networkFunctions']).toBeDefined(); }); + + const originalMockObject = { + remain: 'forever', + obsolete: 'toBeChange' + }; + + each([ + [ + ['serviceInstance', 'serviceModelId', 'vnfs'], + { + remain: 'forever', + obsolete: 'newValue', + newField: 'newValue2' + } + ], + [ + ['serviceInstance', 'nowhere', 'somewhere'], + originalMockObject + ], + ]). + test('#MERGE_OBJECT_BY_PATH: should update some object by path %s', (path, expected) => { + let state = generalReducer(<any>{serviceInstance : { + 'serviceModelId' : { + vnfs : originalMockObject, + existingVNFCounterMap : {} + } + }}, + <MergeObjectByPathAction>{ + type: GeneralActions.MERGE_OBJECT_BY_PATH, + path, + payload: { + obsolete: 'newValue', + newField: 'newValue2' + } + }); + + expect(state).toBeDefined(); + expect(state.serviceInstance['serviceModelId'].vnfs).toEqual(expected); + }); }); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.ts index 5b265dbfd..f87a97397 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/general/general.reducers.ts @@ -1,12 +1,5 @@ import {Action} from "redux"; -import { - ChangeInstanceCounterAction, RemoveInstanceAction, DuplicateBulkInstancesAction, - GeneralActions, - UpdateAicZonesAction, UpdateCategoryParametersAction, - UpdateLcpRegionsAndTenantsAction, UpdateNetworkCollectionFunction, - UpdateProductFamiliesAction, UpdateServiceTypesAction, - UpdateSubscribersAction, UpdateUserIdAction -} from "./general.actions"; +import {ChangeInstanceCounterAction, DuplicateBulkInstancesAction, GeneralActions, MergeObjectByPathAction, RemoveInstanceAction, UpdateAicZonesAction, UpdateCategoryParametersAction, UpdateLcpRegionsAndTenantsAction, UpdateNetworkCollectionFunction, UpdateProductFamiliesAction, UpdateServiceTypesAction, UpdateSubscribersAction, UpdateUserIdAction} from "./general.actions"; import {TypeNodeInformation} from "../../../../drawingBoard/service-planning/typeNodeInformation.model"; import * as _ from "lodash"; import {ITreeNode} from "angular-tree-component/dist/defs/api"; @@ -92,6 +85,19 @@ export function generalReducer(state: ServiceState, action: Action) : ServiceSta return newState; } + case GeneralActions.MERGE_OBJECT_BY_PATH : { + const mergeObjectByPathAction = <MergeObjectByPathAction>action; + let newState = _.cloneDeep(state); + let targetObject = _.get(newState, <any>mergeObjectByPathAction.path); + if (targetObject) { + targetObject = _.merge(targetObject, mergeObjectByPathAction.payload); + } + else { + console.error(`Can't find object at ${mergeObjectByPathAction.path.join()}`) + } + return newState; + } + } } diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts index c02049eb9..a135563eb 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/main.reducer.ts @@ -9,9 +9,11 @@ import {VNFActions} from "./vnf/vnf.actions"; import {vnfReducer} from "./vnf/vnf.reducers"; import {generalReducer} from "./general/general.reducers"; import {serviceReducer} from "./service/service.reducers"; +import {useTemplateReducer} from "./useTemplate/useTemplate.reducer"; import {networkReducer} from "./network/network.reducers"; import {vfModuleReducer} from "./vfModule/vfModule.reducers"; import {ServiceInstance} from "../../models/serviceInstance"; +import {UseTemplateActions} from "./useTemplate/useTemplate.action"; import {SelectOptionInterface} from "../../models/selectOption"; import {ServiceType} from "../../models/serviceType"; import {VnfGroupActions} from "./vnfGroup/vnfGroup.actions"; @@ -72,6 +74,8 @@ export const MainReducer = function (state: ServiceState = initialState, action: return crReducer(state, action); }else if(Object.values(NcfActions).includes(action.type)){ return ncfReducer(state, action); + } else if(Object.values(UseTemplateActions).includes(action.type)) { + return useTemplateReducer(state, action); } else { return Object.assign({}, state); } diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.action.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.action.ts new file mode 100644 index 000000000..2cfd38482 --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.action.ts @@ -0,0 +1,17 @@ +import {Action, ActionCreator} from "redux"; +import {ServiceInstance} from "../../../models/serviceInstance"; + +export enum UseTemplateActions { + CREATE_SERVICE_INSTANCE_FROM_TEMPLATE = 'CREATE_SERVICE_INSTANCE_FROM_TEMPLATE', +} + +export interface CreateServiceInstanceFromTemplate extends Action { + serviceInstantiationTemplate?: ServiceInstance; + serviceModelId?: string; +} + +export const createServiceInstanceFromTemplate: ActionCreator<CreateServiceInstanceFromTemplate> = (serviceInstantiationTemplate, serviceModelId) => ({ + type: UseTemplateActions.CREATE_SERVICE_INSTANCE_FROM_TEMPLATE, + serviceInstantiationTemplate: serviceInstantiationTemplate, + serviceModelId: serviceModelId +}); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.spec.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.spec.ts new file mode 100644 index 000000000..e0f46e13a --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.spec.ts @@ -0,0 +1,18 @@ +import {ServiceInstance} from "../../../models/serviceInstance"; +import {useTemplateReducer} from "./useTemplate.reducer"; +import {CreateServiceInstanceFromTemplate, UseTemplateActions} from "./useTemplate.action"; + +test('#CREATE_SERVICE_INSTANCE_FROM_TEMPLATE should add new service instance from template to redux ', () => { + let serviceFromTemplateInstance: ServiceInstance = <any>{ + instanceName: 'templateInstanceName' + }; + let serviceState = useTemplateReducer(<any>{ + serviceInstance:{}}, + <CreateServiceInstanceFromTemplate> { + type: UseTemplateActions.CREATE_SERVICE_INSTANCE_FROM_TEMPLATE, + serviceModelId: 'serviceModelID', + serviceInstantiationTemplate: serviceFromTemplateInstance, + }) + expect (serviceState).toBeDefined(); + expect (serviceState.serviceInstance['serviceModelID'].instanceName).toEqual('templateInstanceName'); +}); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.ts new file mode 100644 index 000000000..5a06d6e0a --- /dev/null +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/useTemplate/useTemplate.reducer.ts @@ -0,0 +1,20 @@ +import {ServiceState} from "../main.reducer"; +import {Action} from "redux"; +import { + createServiceInstanceFromTemplate, + CreateServiceInstanceFromTemplate, + UseTemplateActions +} from "./useTemplate.action"; +import * as _ from "lodash"; + +export function useTemplateReducer(state: ServiceState, action: Action) : ServiceState { + switch (action.type) { + case UseTemplateActions.CREATE_SERVICE_INSTANCE_FROM_TEMPLATE : { + const updateServiceInstanceFromTemplateAction = <CreateServiceInstanceFromTemplate>action; + const uuid = updateServiceInstanceFromTemplateAction.serviceModelId; + let newState = _.cloneDeep(state); + newState.serviceInstance[uuid] = updateServiceInstanceFromTemplateAction.serviceInstantiationTemplate; + return newState; + } + } +} diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.actions.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.actions.ts index 59e5ee1fa..70c10c429 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.actions.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.actions.ts @@ -9,6 +9,8 @@ export enum VfModuleActions { UPDATE_VFMODULE_POSITION = "UPDATE_VFMODULE_POSITION", UPGRADE_VFMODULE = "UPGRADE_VFMODULE", UNDO_UPGRADE_VFMODULE_ACTION = "UNDO_UPGRADE_VFMODULE_ACTION", + UPDATE_VFMODULE_FEILD = "UPDATE_VFMODULE_FEILD", + DELETE_VFMODULE_FEILD = "DELETE_VFMODULE_FEILD", } @@ -62,6 +64,23 @@ export interface UndoUpgradeVfModuleInstanceAction extends Action { dynamicModelName: string; } +export interface UpdateVFModuleField extends Action { + modelName : string; + vnfStoreKey : string; + serviceId: string; + dynamicModelName: string; + fieldName: string; + fieldValue : any; +} + +export interface DeleteVFModuleField extends Action { + modelName : string; + vnfStoreKey : string; + serviceId: string; + dynamicModelName: string; + deleteFieldName: string; +} + export interface UndoDeleteActionVfModuleInstanceAction extends Action { dynamicModelName: string; vnfStoreKey : string; @@ -132,3 +151,22 @@ export const undoUgradeVFModule: ActionCreator<UndoUpgradeVfModuleInstanceAction vnfStoreKey, serviceId }); + +export const updateVFModuleField: ActionCreator<UpdateVFModuleField> = (modelName, vnfStoreKey, serviceId, dynamicModelName, fieldName, fieldValue) => ({ + type: VfModuleActions.UPDATE_VFMODULE_FEILD, + dynamicModelName, + modelName, + vnfStoreKey, + serviceId, + fieldName, + fieldValue +}); + +export const deleteVFModuleField: ActionCreator<DeleteVFModuleField> = (modelName, vnfStoreKey, serviceId, dynamicModelName, deleteFieldName) => ({ + type: VfModuleActions.DELETE_VFMODULE_FEILD, + dynamicModelName, + modelName, + vnfStoreKey, + serviceId, + deleteFieldName +}); diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.spec.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.spec.ts index ee0edb0a7..7b890b715 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.spec.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.spec.ts @@ -1,9 +1,9 @@ import { CreateVFModuleInstanceAction, - DeleteActionVfModuleInstanceAction, + DeleteActionVfModuleInstanceAction, DeleteVFModuleField, DeleteVfModuleInstanceAction, UndoDeleteActionVfModuleInstanceAction, - UpdateVFModluePosition, + UpdateVFModluePosition, UpdateVFModuleField, UpgradeVfModuleInstanceAction, VfModuleActions } from "./vfModule.actions"; @@ -14,12 +14,13 @@ import {ServiceInstanceActions} from "../../../models/serviceInstanceActions"; describe('vfModuleReducer', () => { test('#REMOVE_VNF_MODULE_INSTANCE : should delete existing vnf module by dynamicModelName', () => { - let state = vfModuleReducer(<any>{serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vfName' : { - vfModules : { - 'modelName' : { + let state = vfModuleReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vfName': { + vfModules: { + 'modelName': { 'dynamicModelName1': {}, 'dynamicModelName2': {}, } @@ -27,13 +28,14 @@ describe('vfModuleReducer', () => { } } } - }}, + } + }, <DeleteVfModuleInstanceAction>{ type: VfModuleActions.REMOVE_VNF_MODULE_INSTANCE, - modelName : 'modelName', - vfName : 'vfName', - vnfStoreKey : 'vfName', - serviceModelId : 'serviceModelId', + modelName: 'modelName', + vfName: 'vfName', + vnfStoreKey: 'vfName', + serviceModelId: 'serviceModelId', dynamicModelName: 'dynamicModelName1' }); @@ -43,26 +45,27 @@ describe('vfModuleReducer', () => { }); test('#DELETE_LAST_VNF_MODULE_INSTANCE : should delete existing vnf module', () => { - let state = vfModuleReducer(<any>{serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vfName' : { - vfModules : { - 'modelName' : { - 'dynamicModelName': { - } + let state = vfModuleReducer(<any>{ + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vfName': { + vfModules: { + 'modelName': { + 'dynamicModelName': {} } } } } } - }}, + } + }, <DeleteVfModuleInstanceAction>{ type: VfModuleActions.REMOVE_VNF_MODULE_INSTANCE, - modelName : 'modelName', - vfName : 'vfName', - vnfStoreKey : 'vfName', - serviceModelId : 'serviceModelId', + modelName: 'modelName', + vfName: 'vfName', + vnfStoreKey: 'vfName', + serviceModelId: 'serviceModelId', dynamicModelName: 'dynamicModelName' }); @@ -70,28 +73,29 @@ describe('vfModuleReducer', () => { expect(state.serviceInstance['serviceModelId'].vnfs['vfName'].vfModules['modelName']).not.toBeDefined(); }); - test('#CREATE_VF_MODULE: should create new vfModule to existing VNF', ()=>{ - let vfModuleInstance : VfModuleInstance = new VfModuleInstance(); + test('#CREATE_VF_MODULE: should create new vfModule to existing VNF', () => { + let vfModuleInstance: VfModuleInstance = new VfModuleInstance(); vfModuleInstance.instanceName = 'instanceName'; vfModuleInstance.isMissingData = false; vfModuleInstance.volumeGroupName = 'volumeGroupName'; - let vfModule = vfModuleReducer(<any>{serviceInstance : { - 'serviceUuid' : { - vnfs : { - 'vnfStoreKey' : { - 'vfModules' : { - } + let vfModule = vfModuleReducer(<any>{ + serviceInstance: { + 'serviceUuid': { + vnfs: { + 'vnfStoreKey': { + 'vfModules': {} } } } - }}, + } + }, <CreateVFModuleInstanceAction>{ type: VfModuleActions.CREATE_VF_MODULE, - vfId : 'vfId', - vfInstance : new VfModuleInstance(), - vnfStoreKey : 'vnfStoreKey', - serviceUuid : 'serviceUuid', - index : 1 + vfId: 'vfId', + vfInstance: new VfModuleInstance(), + vnfStoreKey: 'vnfStoreKey', + serviceUuid: 'serviceUuid', + index: 1 }).serviceInstance['serviceUuid'].vnfs['vnfStoreKey'].vfModules; let firstVfModuleName = Object.keys(vfModule)[0]; @@ -99,23 +103,64 @@ describe('vfModuleReducer', () => { expect(vfModule[firstVfModuleName].isMissingData).toBeFalsy(); }); - test('#UPDATE_VF_MODULE: should update existing VFModule', ()=>{ - let vfModuleInstance : VfModuleInstance = new VfModuleInstance(); - vfModuleInstance.instanceName = 'instanceName'; - vfModuleInstance.isMissingData = false; - vfModuleInstance.volumeGroupName = 'volumeGroupName'; - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} + test('#UPDATE_VFMODULE_FEILD: should update field with some value', () => { + const newFieldName = 'newFieldName'; + const newFieldValue = 'newFieldValue'; + let oldState = { + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { + 'dynamicModelName1': { + isMissingData: true, + action: 'None' + }, + 'dynamicModelName2': {}, + } + } + } + } + } + } + }; + + let newState = vfModuleReducer(<any>oldState, + <UpdateVFModuleField>{ + type: VfModuleActions.UPDATE_VFMODULE_FEILD, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId', + modelName: 'modelName', + fieldName: newFieldName, + fieldValue: newFieldValue + }); + + let vfModule = newState.serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + + expect(vfModule[newFieldName]).toEqual(newFieldValue); + }); + + test('#DELETE_VFMODULE_FEILD: should update field with some value', () => { + const deleteFieldName = 'deleteFieldName'; + let oldState = { + serviceHierarchy: { + 'serviceModelId': {} }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vfName' : { - vfModules : { - 'modelName' : { + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { 'dynamicModelName1': { - isMissingData : true + isMissingData: true, + [deleteFieldName]: true, + action: 'None' }, 'dynamicModelName2': {}, } @@ -123,192 +168,197 @@ describe('vfModuleReducer', () => { } } } - }}, - <CreateVFModuleInstanceAction>{ - type: VfModuleActions.UPDATE_VF_MODULE, - vfId : 'modelName', - vfInstance : new VfModuleInstance(), - vnfStoreKey : 'vfName', - dynamicModelName : 'dynamicModelName1', - serviceUuid : 'serviceModelId', - index : 1 - }).serviceInstance['serviceModelId'].vnfs['vfName'].vfModules; + } + }; + let newState = vfModuleReducer(<any>oldState, + <DeleteVFModuleField>{ + type: VfModuleActions.DELETE_VFMODULE_FEILD, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId', + modelName: 'modelName', + deleteFieldName: deleteFieldName, + }); - let firstVfModuleName = Object.keys(vfModule)[0]; - expect(vfModule[firstVfModuleName]).toBeDefined(); - expect(vfModule[firstVfModuleName].isMissingData).toBeFalsy(); - }); + let vfModule = newState.serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + expect(vfModule[deleteFieldName]).toBeUndefined(); +}); - test('#UPDATE_VFMODULE_POSITION: should update position', ()=>{ - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} - }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vfName' : { - vfModules : { - 'modelName' : { - 'dynamicModelName': { - isMissingData : true - } +test('#UPDATE_VFMODULE_POSITION: should update position', () => { + let vfModule = vfModuleReducer(<any>{ + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vfName': { + vfModules: { + 'modelName': { + 'dynamicModelName': { + isMissingData: true } } } } } - }}, - <UpdateVFModluePosition>{ - type: VfModuleActions.UPDATE_VFMODULE_POSITION, - node: { - position : 1, - dynamicModelName : "dynamicModelName", - modelName : "modelName" - }, - instanceId : "serviceModelId", - vnfStoreKey : "vfName" + } + } + }, + <UpdateVFModluePosition>{ + type: VfModuleActions.UPDATE_VFMODULE_POSITION, + node: { + position: 1, + dynamicModelName: "dynamicModelName", + modelName: "modelName" + }, + instanceId: "serviceModelId", + vnfStoreKey: "vfName" - }).serviceInstance['serviceModelId'].vnfs['vfName'].vfModules["modelName"]["dynamicModelName"]; - - expect(vfModule.position).toEqual(1); - }); + }).serviceInstance['serviceModelId'].vnfs['vfName'].vfModules["modelName"]["dynamicModelName"]; + expect(vfModule.position).toEqual(1); +}); - test('#DELETE_ACTION_VF_MODULE_INSTANCE', ()=>{ - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} - }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vnfStoreKey' : { - vfModules : { - 'modelName' : { - 'dynamicModelName1': { - isMissingData : true, - action : 'None' - }, - 'dynamicModelName2': {}, - } +test('#DELETE_ACTION_VF_MODULE_INSTANCE', () => { + let vfModule = vfModuleReducer(<any>{ + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { + 'dynamicModelName1': { + isMissingData: true, + action: 'None' + }, + 'dynamicModelName2': {}, } } } } - }}, - <DeleteActionVfModuleInstanceAction>{ - type: VfModuleActions.DELETE_ACTION_VF_MODULE_INSTANCE, - dynamicModelName: 'dynamicModelName1', - vnfStoreKey : 'vnfStoreKey', - serviceId: 'serviceModelId' - }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + } + } + }, + <DeleteActionVfModuleInstanceAction>{ + type: VfModuleActions.DELETE_ACTION_VF_MODULE_INSTANCE, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; - console.log(vfModule.action); - expect(vfModule).toBeDefined(); - expect(vfModule.isMissingData).toBeTruthy(); - expect(vfModule.action).toEqual(ServiceInstanceActions.None_Delete); - }); + console.log(vfModule.action); + expect(vfModule).toBeDefined(); + expect(vfModule.isMissingData).toBeTruthy(); + expect(vfModule.action).toEqual(ServiceInstanceActions.None_Delete); +}); - test('#UNDO_DELETE_ACTION_VF_MODULE_INSTANCE', ()=>{ - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} - }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vnfStoreKey' : { - vfModules : { - 'modelName' : { - 'dynamicModelName1': { - isMissingData : true, - action : 'None_Delete' - }, - 'dynamicModelName2': {}, - } +test('#UNDO_DELETE_ACTION_VF_MODULE_INSTANCE', () => { + let vfModule = vfModuleReducer(<any>{ + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { + 'dynamicModelName1': { + isMissingData: true, + action: 'None_Delete' + }, + 'dynamicModelName2': {}, } } } } - }}, - <UndoDeleteActionVfModuleInstanceAction>{ - type: VfModuleActions.UNDO_DELETE_ACTION_VF_MODULE_INSTANCE, - dynamicModelName: 'dynamicModelName1', - vnfStoreKey : 'vnfStoreKey', - serviceId: 'serviceModelId' - }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + } + } + }, + <UndoDeleteActionVfModuleInstanceAction>{ + type: VfModuleActions.UNDO_DELETE_ACTION_VF_MODULE_INSTANCE, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId' + }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; - console.log(vfModule.action); - expect(vfModule).toBeDefined(); - expect(vfModule.action).toEqual(ServiceInstanceActions.None); - }); + console.log(vfModule.action); + expect(vfModule).toBeDefined(); + expect(vfModule.action).toEqual(ServiceInstanceActions.None); +}); - test('#UPGRADE_VFMODULE', ()=>{ - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} - }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vnfStoreKey' : { - vfModules : { - 'modelName' : { - 'dynamicModelName1': { - isMissingData : true, - action : 'None' - }, - 'dynamicModelName2': {}, - } +test('#UPGRADE_VFMODULE', () => { + let vfModule = vfModuleReducer(<any>{ + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { + 'dynamicModelName1': { + isMissingData: true, + action: 'None' + }, + 'dynamicModelName2': {}, } } } } - }}, - <UpgradeVfModuleInstanceAction>{ - type: VfModuleActions.UPGRADE_VFMODULE, - dynamicModelName: 'dynamicModelName1', - vnfStoreKey : 'vnfStoreKey', - serviceId: 'serviceModelId', - modelName: 'modelName' - }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + } + } + }, + <UpgradeVfModuleInstanceAction>{ + type: VfModuleActions.UPGRADE_VFMODULE, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId', + modelName: 'modelName' + }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; - expect(vfModule.action).toEqual(ServiceInstanceActions.None_Upgrade); - }); + expect(vfModule.action).toEqual(ServiceInstanceActions.None_Upgrade); +}); - test('#UNDO_UPGRADE_VFMODULE', ()=>{ - let vfModule = vfModuleReducer(<any>{ - serviceHierarchy : { - 'serviceModelId' : {} - }, - serviceInstance : { - 'serviceModelId' : { - vnfs : { - 'vnfStoreKey' : { - vfModules : { - 'modelName' : { - 'dynamicModelName1': { - isMissingData : true, - action : 'None_Upgrade' - }, - 'dynamicModelName2': {}, - } +test('#UNDO_UPGRADE_VFMODULE', () => { + let vfModule = vfModuleReducer(<any>{ + serviceHierarchy: { + 'serviceModelId': {} + }, + serviceInstance: { + 'serviceModelId': { + vnfs: { + 'vnfStoreKey': { + vfModules: { + 'modelName': { + 'dynamicModelName1': { + isMissingData: true, + action: 'None_Upgrade' + }, + 'dynamicModelName2': {}, } } } } - }}, - <UpgradeVfModuleInstanceAction>{ - type: VfModuleActions.UNDO_UPGRADE_VFMODULE_ACTION, - dynamicModelName: 'dynamicModelName1', - vnfStoreKey : 'vnfStoreKey', - serviceId: 'serviceModelId', - modelName: 'modelName' - }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; - - expect(vfModule.action).toEqual(ServiceInstanceActions.None); - }); + } + } + }, + <UpgradeVfModuleInstanceAction>{ + type: VfModuleActions.UNDO_UPGRADE_VFMODULE_ACTION, + dynamicModelName: 'dynamicModelName1', + vnfStoreKey: 'vnfStoreKey', + serviceId: 'serviceModelId', + modelName: 'modelName' + }).serviceInstance['serviceModelId'].vnfs['vnfStoreKey'].vfModules['modelName']['dynamicModelName1']; + expect(vfModule.action).toEqual(ServiceInstanceActions.None); }); + +}) +; diff --git a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.ts b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.ts index a7aadba41..1bb2b15fd 100644 --- a/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.ts +++ b/vid-webpack-master/src/app/shared/storeUtil/utils/vfModule/vfModule.reducers.ts @@ -1,10 +1,10 @@ import {Action} from "redux"; import * as _ from "lodash"; import { - CreateVFModuleInstanceAction, DeleteActionVfModuleInstanceAction, - DeleteVfModuleInstanceAction, UndoDeleteActionVfModuleInstanceAction, UpdateVFModluePosition, + CreateVFModuleInstanceAction, DeleteActionVfModuleInstanceAction, DeleteVFModuleField, + DeleteVfModuleInstanceAction, UndoDeleteActionVfModuleInstanceAction, UpdateVFModluePosition, UpdateVFModuleField, UpdateVFModuleInstanceAction, UpgradeVfModuleInstanceAction, - VfModuleActions + VfModuleActions, } from "./vfModule.actions"; import {ServiceInstance} from "../../../models/serviceInstance"; import {VfModuleMap} from "../../../models/vfModulesMap"; @@ -145,6 +145,26 @@ export function vfModuleReducer(state: ServiceState , action: Action) : ServiceS } return clonedState; } + case VfModuleActions.UPDATE_VFMODULE_FEILD : { + let clonedState = _.cloneDeep(state); + let updateFieldAction = <UpdateVFModuleField> action; + + clonedState.serviceInstance[updateFieldAction.serviceId] + .vnfs[updateFieldAction.vnfStoreKey] + .vfModules[updateFieldAction.modelName][updateFieldAction.dynamicModelName][updateFieldAction.fieldName] = updateFieldAction.fieldValue; + + return clonedState; + } + case VfModuleActions.DELETE_VFMODULE_FEILD : { + let clonedState = _.cloneDeep(state); + let deleteAction = <DeleteVFModuleField> action; + + delete clonedState.serviceInstance[deleteAction.serviceId] + .vnfs[deleteAction.vnfStoreKey] + .vfModules[deleteAction.modelName][deleteAction.dynamicModelName][deleteAction.deleteFieldName]; + + return clonedState; + } } } diff --git a/vid-webpack-master/src/app/shared/utils/constants.ts b/vid-webpack-master/src/app/shared/utils/constants.ts index 400a4d8dc..f793e05db 100644 --- a/vid-webpack-master/src/app/shared/utils/constants.ts +++ b/vid-webpack-master/src/app/shared/utils/constants.ts @@ -92,7 +92,9 @@ export module Constants { public static WELCOME_PATH = 'welcome.htm'; public static IS_PERMITTED_SUB_PATH = '&isPermitted='; public static SERVICES_JOB_INFO_PATH = '../../asyncInstantiation'; + public static SERVICE_MODEL_ID = 'serviceModelId'; public static SERVICES_RETRY_TOPOLOGY = '../../asyncInstantiation/bulkForRetry'; + public static INSTANTIATION_TEMPLATE_TOPOLOGY = '../../asyncInstantiation/templateTopology'; public static CONFIGURATION_PATH = '../../get_property/{name}/defaultvalue'; public static SERVICES_JOB_AUDIT_PATH = '/auditStatus'; public static SERVICES_PROBE_PATH = "../../probe"; @@ -295,4 +297,8 @@ export module Constants { export class LegacyRegion { public static MEGA_REGION = ['AAIAIC25']; } + + export class ModelInfo { + public static UNLIMITED_DEFAULT = 'Unlimited (default)'; + } } diff --git a/vid-webpack-master/src/app/shared/utils/util.spec.ts b/vid-webpack-master/src/app/shared/utils/util.spec.ts index 2f9142f9c..ae39238c2 100644 --- a/vid-webpack-master/src/app/shared/utils/util.spec.ts +++ b/vid-webpack-master/src/app/shared/utils/util.spec.ts @@ -1,23 +1,8 @@ import {Utils} from "./utils"; -import {TestBed} from "@angular/core/testing"; +import each from "jest-each"; describe('Util', () => { - let util: Utils; - - beforeAll(done => (async () => { - TestBed.configureTestingModule({ - - }); - await TestBed.compileComponents(); - - util = new Utils(); - - })().then(done).catch(done.fail)); - - test('should be defined', () => { - expect(util).toBeDefined(); - }); test('hasContents should return false if object is undefined or null or empty', () => { expect(Utils.hasContents(undefined)).toBeFalsy(); @@ -28,4 +13,39 @@ describe('Util', () => { test('hasContents should return true if object is not undefined and not null and not empty', () => { expect(Utils.hasContents("someValue")).toBeTruthy(); }); + + const instantiationTypesDataProvider = [ + ['Macro', false ], + ['ALaCarte', true ], + ['ClientConfig', true], + ['dont know', true] + ]; + each(instantiationTypesDataProvider).test('instantiationType %s isALaCarte shall be %s', (instantiationType, expected ) => { + expect(Utils.isALaCarte(instantiationType)).toEqual(expected); + }); + + each([ + ["empty properties, empty flags",{}, {}, 1], + ["null properties, undefined flags",null, undefined, 1], + ["max_instances 3, flag is on", {max_instances:3}, {FLAG_2002_UNLIMITED_MAX: true}, 3], + ["max_instances 3, flag is off", {max_instances:3}, {FLAG_2002_UNLIMITED_MAX: false}, 3], + ["null properties, flag is on", null, {FLAG_2002_UNLIMITED_MAX: true}, null], + ["null properties, flag is off", null, {FLAG_2002_UNLIMITED_MAX: false}, 1], + ["undefined properties, flag is off", undefined, {FLAG_2002_UNLIMITED_MAX: false}, 1], + ]).test('getMaxFirstLevel %s', (desc, properties, flags, expected) => { + expect(Utils.getMaxFirstLevel(properties, flags)).toEqual(expected); + }); + + each([ + ["empty properties, empty flags",{}, {}, 1], + ["null properties, undefined flags",null, undefined, 1], + ["wrong field, flag is on", {max_instances:3}, {FLAG_2002_UNLIMITED_MAX: true}, null], + ["maxCountInstances 3, flag is on", {maxCountInstances:3}, {FLAG_2002_UNLIMITED_MAX: true}, 3], + ["maxCountInstances 3, flag is off", {maxCountInstances:3}, {FLAG_2002_UNLIMITED_MAX: true}, 3], + ]).test('getMaxFirstLevel %s', (desc, properties, flags, expected) => { + expect(Utils.getMaxVfModule(properties, flags)).toEqual(expected); + }); + + + }); diff --git a/vid-webpack-master/src/app/shared/utils/utils.ts b/vid-webpack-master/src/app/shared/utils/utils.ts index d63a3c997..3db770738 100644 --- a/vid-webpack-master/src/app/shared/utils/utils.ts +++ b/vid-webpack-master/src/app/shared/utils/utils.ts @@ -2,6 +2,21 @@ import * as _ from 'lodash' export class Utils { + static getMaxFirstLevel(properties, flags: { [key: string]: boolean }) : number | null{ + return this.getMaxInstancesAllowed(properties, 'max_instances', flags) + } + + static getMaxVfModule(properties, flags: { [key: string]: boolean }) : number | null{ + return this.getMaxInstancesAllowed(properties, 'maxCountInstances', flags) + } + + static getMaxInstancesAllowed(properties, filedName: string, flags: { [key: string]: boolean }) : number | null{ + if (!_.isNil(properties) && !_.isNil(properties[filedName])) { + return properties[filedName]; + } + return (flags && !!flags['FLAG_2002_UNLIMITED_MAX']) ? null : 1; + } + public static clampNumber = (number, min, max) => { return Math.max(min, Math.min(number, max)); }; @@ -179,6 +194,10 @@ export class Utils { return (convertedAsdcModel); }; + public static isALaCarte(instantiationType) { + return instantiationType !== 'Macro'; + } + private static convertOldModel(serviceModel ) { let resource = {}; let convertedAsdcModel = { |