diff options
author | Yoav Schneiderman <yoav.schneiderman@intl.att.com> | 2019-11-20 16:50:45 +0200 |
---|---|---|
committer | Einat Vinouze <einat.vinouze@intl.att.com> | 2019-11-26 12:41:29 +0200 |
commit | 091343aa4bbf1bd6b882e08113d90685c1c84ffe (patch) | |
tree | fbef4bda9987a59dff5109cf5cc401f95eb05068 | |
parent | ee6c513301200be38c3602a4c3084c2ff3bde10c (diff) |
Allow platform multi-selection for VNF in modern UI
Issue-ID: VID-722
Change-Id: Id87f59fff128e277d9158b83f3908754375c8b01
Signed-off-by: Yoav Schneiderman <yoav.schneiderman@intl.att.com>
Signed-off-by: Einat Vinouze <einat.vinouze@intl.att.com>
21 files changed, 308 insertions, 139 deletions
diff --git a/features.properties.md b/features.properties.md index 45d5922c7..20db29813 100644 --- a/features.properties.md +++ b/features.properties.md @@ -188,3 +188,6 @@ * FLAG_2002_IDENTIFY_INVARIANT_MACRO_UUID_BY_BACKEND, When flag is true, VID use macro_services_by_invariant_uuid.json file to identify if csar without instantiation type is macro service. Otherwise, MACRO_SERVICES list in vidConfiguration.js is used to identify if it's a macro service (in ng1 code) + +* FLAG_2002_VNF_PLATFORM_MULTI_SELECT + When flag is true the platform will appear as a multi select field, if false the platform will be dropdown list.
\ No newline at end of file diff --git a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java index d6d7a6aa2..6a6ac6898 100644 --- a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java +++ b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java @@ -79,6 +79,7 @@ public enum Features implements Feature { FLAG_FLASH_CLOUD_REGION_AND_NF_ROLE_OPTIONAL_SEARCH, FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE, FLAG_2002_ANY_ALACARTE_BESIDES_EXCLUDED_NEW_INSTANTIATION_UI, + FLAG_2002_VNF_PLATFORM_MULTI_SELECT, FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS, FLAG_2002_IDENTIFY_INVARIANT_MACRO_UUID_BY_BACKEND, ; diff --git a/vid-automation/src/main/java/org/onap/simulator/presetGenerator/presets/mso/PresetMSOCreateVnfALaCarteCypress2.java b/vid-automation/src/main/java/org/onap/simulator/presetGenerator/presets/mso/PresetMSOCreateVnfALaCarteCypress2.java index 96424e803..da1c3ffcf 100644 --- a/vid-automation/src/main/java/org/onap/simulator/presetGenerator/presets/mso/PresetMSOCreateVnfALaCarteCypress2.java +++ b/vid-automation/src/main/java/org/onap/simulator/presetGenerator/presets/mso/PresetMSOCreateVnfALaCarteCypress2.java @@ -24,7 +24,7 @@ public class PresetMSOCreateVnfALaCarteCypress2 extends PresetMSOCreateVnfBase { "{\"lcpCloudRegionId\":\"just another region\"," + addCloudOwnerIfNeeded() + "\"tenantId\":\"092eb9e8e4b7412e8787dd091bc58e86\"}," + - "\"platform\":{\"platformName\":\"xxx1\"}," + + "\"platform\":{\"platformName\":\"xxx1,platform\"}," + "\"modelInfo\":" + "{\"modelCustomizationId\":\"1da7b585-5e61-4993-b95e-8e6606c81e45\"," + "\"modelCustomizationName\":\"2017-488_PASQUALE-vPE 0\"," + diff --git a/vid-automation/src/main/java/vid/automation/test/infra/Features.java b/vid-automation/src/main/java/vid/automation/test/infra/Features.java index c1a505276..208f463d1 100644 --- a/vid-automation/src/main/java/vid/automation/test/infra/Features.java +++ b/vid-automation/src/main/java/vid/automation/test/infra/Features.java @@ -54,6 +54,7 @@ public enum Features implements Feature { FLAG_FLASH_CLOUD_REGION_AND_NF_ROLE_OPTIONAL_SEARCH, FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE, FLAG_2002_ANY_ALACARTE_BESIDES_EXCLUDED_NEW_INSTANTIATION_UI, + FLAG_2002_VNF_PLATFORM_MULTI_SELECT, FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS, FLAG_2002_IDENTIFY_INVARIANT_MACRO_UUID_BY_BACKEND, ; diff --git a/vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java b/vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java index 92d3f79c8..8fe0580aa 100644 --- a/vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java +++ b/vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java @@ -8,7 +8,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.onap.simulator.presetGenerator.presets.BasePresets.BaseMSOPreset.DEFAULT_INSTANCE_ID; @@ -20,14 +19,12 @@ import static vid.automation.test.services.SimulatorApi.retrieveRecordedRequests import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; - import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; - import org.onap.simulator.presetGenerator.presets.BasePresets.BaseMSOPreset; import org.onap.simulator.presetGenerator.presets.BasePresets.BasePreset; import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetCloudOwnersByCloudRegionId; diff --git a/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte-no-testapi.json b/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte-no-testapi.json index dfdab76f7..1c22fb894 100644 --- a/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte-no-testapi.json +++ b/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte-no-testapi.json @@ -101,7 +101,7 @@ "lcpCloudRegionId": "AAIAIC25", "legacyRegion": "just another region", "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", - "platformName": "xxx1", + "platformName": "xxx1,platform", "lineOfBusiness": "zzz1", "instanceParams": [ {} diff --git a/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json b/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json index cc1d5b566..7924340c0 100644 --- a/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json +++ b/vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json @@ -98,7 +98,7 @@ "lcpCloudRegionId": "AAIAIC25", "legacyRegion": "just another region", "tenantId": "092eb9e8e4b7412e8787dd091bc58e86", - "platformName": "xxx1", + "platformName": "xxx1,platform", "lineOfBusiness": "zzz1", "instanceParams": [ {} diff --git a/vid-automation/src/test/resources/features.properties b/vid-automation/src/test/resources/features.properties index 3b7fd310d..84522ae2b 100644 --- a/vid-automation/src/test/resources/features.properties +++ b/vid-automation/src/test/resources/features.properties @@ -35,3 +35,5 @@ FLAG_FLASH_REDUCED_RESPONSE_CHANGEMG = true FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE = false FLAG_SHOW_ORCHESTRATION_TYPE = false FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE = false +FLAG_A_LA_CARTE_PLATFORM_MULTI_SELECT = false + diff --git a/vid-webpack-master/cypress/integration/iFrames/ala-carte.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/ala-carte.e2e.ts index 57c673262..14b4bdc14 100644 --- a/vid-webpack-master/cypress/integration/iFrames/ala-carte.e2e.ts +++ b/vid-webpack-master/cypress/integration/iFrames/ala-carte.e2e.ts @@ -14,15 +14,15 @@ describe('A la carte', function () { const CONFIRM_BUTTON: string = 'confirmButton'; beforeEach(() => { - cy.clearSessionStorage(); - cy.setReduxState(); - cy.preventErrorsOnLoading(); - cy.initAAIMock(); - cy.initVidMock(); - cy.mockLatestVersionForService(SERVICE_ID, SERVICE_INVARIANT_ID); - cy.initAlaCarteService(); - cy.initZones(); - cy.login(); + cy.clearSessionStorage(); + cy.setReduxState(); + cy.preventErrorsOnLoading(); + cy.initAAIMock(); + cy.initVidMock(); + cy.mockLatestVersionForService(SERVICE_ID, SERVICE_INVARIANT_ID); + cy.initAlaCarteService(); + cy.initZones(); + cy.login(); }); afterEach(() => { @@ -30,8 +30,7 @@ describe('A la carte', function () { }); - - it(`service name should be mandatory : serviceEcompNaming = true`, ()=> { + it(`service name should be mandatory : serviceEcompNaming = true`, () => { cy.readFile('cypress/support/jsonBuilders/mocks/jsons/basicService.json').then((res) => { jsonBuilderAAIService.basicJson(res, Cypress.config('baseUrl') + '/rest/models/services/' + SERVICE_ID, @@ -43,13 +42,13 @@ describe('A la carte', function () { }); }); - it(`Service a-la-carte`, ()=> { + it(`Service a-la-carte`, () => { - const subscriptionServiceType : string = "TYLER SILVIA"; - const owningEntityName : string = "WayneHolland"; - const rollbackOnFailure : string = "true"; - const projectName : string = "WATKINS"; - const instanceName : string = "serviceInstanceName"; + const subscriptionServiceType: string = "TYLER SILVIA"; + const owningEntityName: string = "WayneHolland"; + const rollbackOnFailure: string = "true"; + const projectName: string = "WATKINS"; + const instanceName: string = "serviceInstanceName"; cy.readFile('cypress/support/jsonBuilders/mocks/jsons/emptyServiceRedux.json').then((res) => { cy.setTestApiParamToGR(); @@ -91,8 +90,20 @@ describe('A la carte', function () { }); }); + it(`VNF a-la-carte`, () => { + cy.readFile('cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json').then((res) => { + res['FLAG_2002_VNF_PLATFORM_MULTI_SELECT'] = true; + cy.server() + .route({ + method: 'GET', + delay: 0, + status: 200, + url: Cypress.config('baseUrl') + "/flags**", + response: res + }).as('initFlags with multi select'); + }); + - it(`VNF a-la-carte`, ()=> { cy.readFile('cypress/support/jsonBuilders/mocks/jsons/emptyServiceRedux.json').then((res) => { cy.setTestApiParamToGR(); res.service.serviceHierarchy['2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd'].service.vidNotions.instantiationType = 'ALaCarte'; @@ -119,31 +130,42 @@ describe('A la carte', function () { cy.get('#quantity-select').should('have.attr', 'disabled'); cy.getElementByDataTestsId('form-set').click({force: true}).then(() => { cy.getElementByDataTestsId('node-2017-488_PASQUALE-vPE 0-add-btn').click({force: true}).then(() => { + cy.selectDropdownOptionByText('productFamily', 'Emanuel'); cy.selectDropdownOptionByText('lcpRegion', 'AAIAIC25'); cy.typeToInput("lcpRegionText", "just another region"); cy.selectDropdownOptionByText('tenant', 'USP-SIP-IC-24335-T-01'); cy.selectDropdownOptionByText('lineOfBusiness', 'zzz1'); - cy.selectDropdownOptionByText('platform', 'xxx1'); + + cy.selelctPlatformValue(false, 'xxx1'); + cy.getElementByDataTestsId('form-set').click({force: true}).then(() => { - cy.getReduxState().then((state) => { - - const vnf = state.service.serviceInstance['2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd'].vnfs['2017-488_PASQUALE-vPE 0']; - cy.readFile('../vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json').then((file) => { - file.vnfs['2017-488_PASQUALE-vPE 0'].trackById = vnf.trackById; - file.vnfs['2017-488_PASQUALE-vPE 0'].vfModules = {}; - file.vnfs['2017-488_PASQUALE-vPE 0'].upgradedVFMSonsCounter = 0; - cy.deepCompare(vnf, file.vnfs['2017-488_PASQUALE-vPE 0']) + + const vnfMenuBtnDataTestId = 'node-69e09f68-8b63-4cc9-b9ff-860960b5db09-2017-488_PASQUALE-vPE 0-menu-btn'; + + cy.getElementByDataTestsId(vnfMenuBtnDataTestId).click({force: true}).then(() => { + cy.getElementByDataTestsId('context-menu-edit').click({force: true}); + cy.selelctPlatformValue(false, 'platform'); + cy.getElementByDataTestsId('form-set').click({force: true}).then(() => { + cy.getReduxState().then((state) => { + + const vnf = state.service.serviceInstance['2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd'].vnfs['2017-488_PASQUALE-vPE 0']; + cy.readFile('../vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json').then((file) => { + file.vnfs['2017-488_PASQUALE-vPE 0'].trackById = vnf.trackById; + file.vnfs['2017-488_PASQUALE-vPE 0'].vfModules = {}; + file.vnfs['2017-488_PASQUALE-vPE 0'].upgradedVFMSonsCounter = 0; + cy.deepCompare(vnf, file.vnfs['2017-488_PASQUALE-vPE 0']) + }); + }); }); }); }); - }); }); }); }); - it(`Network a-la-carte`, ()=> { + it(`Network a-la-carte`, () => { cy.readFile('cypress/support/jsonBuilders/mocks/jsons/emptyServiceRedux.json').then((res) => { cy.setTestApiParamToGR(); res.service.serviceHierarchy['2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd'].service.vidNotions.instantiationType = 'ALaCarte'; @@ -173,7 +195,8 @@ describe('A la carte', function () { cy.setReduxState(<any>res); cy.openIframe('app/ui/#/servicePlanning?serviceModelId=2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd'); cy.getElementByDataTestsId("node-ExtVL 0-add-btn").click({force: true}); - cy.selectDropdownOptionByText("platform", "xxx1"); + + cy.selelctPlatformValue(true, 'xxx1'); cy.selectDropdownOptionByText("lcpRegion", "AAIAIC25"); cy.selectDropdownOptionByText("tenant", "USP-SIP-IC-24335-T-01"); cy.selectDropdownOptionByText("productFamily", "ERICA"); @@ -193,7 +216,7 @@ describe('A la carte', function () { }); }); - it(`VFModule a-la-carte`, ()=> { + it(`VFModule a-la-carte`, () => { var timeBomb = new Date('12/09/2018'); if (new Date() < timeBomb) { return; @@ -210,7 +233,7 @@ describe('A la carte', function () { cy.selectDropdownOptionByText('lcpRegion', 'hvf6'); cy.selectDropdownOptionByText('tenant', 'AIN Web Tool-15-D-STTest2'); cy.selectDropdownOptionByText('lineOfBusiness', 'zzz1'); - cy.selectDropdownOptionByText('platform', 'xxx1'); + cy.selelctPlatformValue(true, 'xxx1'); cy.getElementByDataTestsId('form-set').click({force: true}).then(() => { const vnfName = '2017-488_PASQUALE-vPE 0'; let vfModulesNames: Array<string> = [ @@ -261,7 +284,7 @@ describe('A la carte', function () { .get('.error').contains(INSTANCE_NAME_NOT_MANDATORY_MESSAGE); } - function addVfModule (vnfName: string, vfModuleName: string, instanceName: string, lcpRegion: string, legacyRegion: string, tenant: string, rollback: boolean, sdncPreLoad: boolean, deleteVgName: boolean): Chainable<any> { + function addVfModule(vnfName: string, vfModuleName: string, instanceName: string, lcpRegion: string, legacyRegion: string, tenant: string, rollback: boolean, sdncPreLoad: boolean, deleteVgName: boolean): Chainable<any> { return cy.getElementByDataTestsId('node-' + vnfName).click({force: true}).then(() => { cy.getElementByDataTestsId('node-' + vfModuleName + '-add-btn').click({force: true}).then(() => { cy.getElementByDataTestsId('instanceName').clear().type(instanceName, {force: true}).then(() => { diff --git a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json index d9561f168..53038ed4e 100644 --- a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json +++ b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json @@ -19,5 +19,7 @@ "FLAG_FLASH_REPLACE_VF_MODULE": true, "FLAG_FLASH_MORE_ACTIONS_BUTTON_IN_OLD_VIEW_EDIT": true, "FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE": false, + "FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE": false, + "FLAG_2002_VNF_PLATFORM_MULTI_SELECT" : false, "FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS": true } diff --git a/vid-webpack-master/cypress/support/steps/genericForm/genericFormAction.steps.ts b/vid-webpack-master/cypress/support/steps/genericForm/genericFormAction.steps.ts index 9786369cf..41784daff 100644 --- a/vid-webpack-master/cypress/support/steps/genericForm/genericFormAction.steps.ts +++ b/vid-webpack-master/cypress/support/steps/genericForm/genericFormAction.steps.ts @@ -1,12 +1,29 @@ declare namespace Cypress { interface Chainable { genericFormSubmitForm: typeof genericFormSubmitForm + selelctPlatformValue: typeof selelctPlatformValue } } -function genericFormSubmitForm() : Chainable<any> { - return cy.getElementByDataTestsId('form-set').click({force: true}); + + + +function selelctPlatformValue(isDropdown: boolean, selectOption: string){ + if (isDropdown) { + cy.selectDropdownOptionByText('platform', selectOption); + } else { + cy.getElementByDataTestsId("multi-selectPlatform").get('.c-btn').click({force: true}) + .getElementByDataTestsId(`multi-selectPlatform-${selectOption}`).click() + .getElementByDataTestsId("multi-selectPlatform").get('.c-btn').click({force: true}); + + } +} + + +function genericFormSubmitForm(): Chainable<any> { + return cy.getElementByDataTestsId('form-set').click({force: true}); } Cypress.Commands.add('genericFormSubmitForm', genericFormSubmitForm); +Cypress.Commands.add('selelctPlatformValue', selelctPlatformValue); 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..9b900dedf 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,52 @@ 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 + }; + + 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.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.ts b/vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.ts new file mode 100644 index 000000000..4a9580563 --- /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 = (data : MultiselectFormControl) : Promise<MultiSelectItem[]> => { + return new Promise<MultiSelectItem[]>((resolve) =>{ + let result: MultiSelectItem[] = []; + if(data.options$) { + let index: number = 1; + data.options$.map((originalItems: any) => { + result.push(new MultiSelectItem(index, originalItems[data.ngValue], originalItems[data.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(data : MultiselectFormControl) : Promise<MultiSelectItem[]>{ + return new Promise<MultiSelectItem[]>((resolve) =>{ + let result: MultiSelectItem[] = []; + const hashMap = this.convertOptionsToHashMap(data); + + if(data.options$ && data.value) { + const convertArray = data.convertOriginalDataToArray ? data.convertOriginalDataToArray(data.value) : data.value; + convertArray.map((itemId) => { + const uniqueIdentifier = itemId.trim(); + result.push(new MultiSelectItem(hashMap[uniqueIdentifier].index, hashMap[uniqueIdentifier][data.ngValue], hashMap[uniqueIdentifier][data.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/vnfGenerator/vnf.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts index 5c6e25c6b..9230ccfa7 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 @@ -16,6 +16,7 @@ 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(){ @@ -939,6 +940,35 @@ describe('VNF Control Generator', () => { })().then(done).catch(done.fail)); + + test('should call platform dropdown control', ()=>{ + spyOn(service, 'getPlatformDropdownControl'); + + service.getPlatformControl(null, [], false); + + expect(service.getPlatformDropdownControl).toBeCalledWith(null, []); + }); + + test('should call platform multi select control', ()=>{ + spyOn(service, 'getPlatformMultiselectControl'); + + service.getPlatformControl(null, [], true); + + expect(service.getPlatformMultiselectControl).toBeCalledWith(null, []); + }); + + test('should generate platform multi select control', ()=>{ + const control = service.getPlatformMultiselectControl(null, []); + 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..55177aaac 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 @@ -20,6 +20,8 @@ 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', @@ -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.getPlatformControl(vnfInstance, result, flags['FLAG_2002_VNF_PLATFORM_MULTI_SELECT'])); result.push(this.getLineOfBusinessControl(vnfInstance, result)); result.push(this.getRollbackOnFailureControl(vnfInstance, result)); } @@ -139,20 +142,59 @@ export class VnfControlGenerator { }) }; - getPlatformControl = (instance: any, controls: FormControlModel[]): DropdownFormControl => { + + + getPlatformDropdownControl = (instance: any, controls: FormControlModel[]) : DropdownFormControl => { return new DropdownFormControl({ - type: FormControlType.DROPDOWN, + type: FormControlType.DROPDOWN , controlName: 'platformName', displayName: 'Platform', dataTestId: 'platform', + selectedFieldName : null , + ngValue : null, placeHolder: 'Select Platform', isDisabled: false, name: "platform", value: instance ? instance.platformName : null, 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), + }); + }; + + getPlatformMultiselectControl = (instance: any, controls: FormControlModel[]) : MultiselectFormControl => { + return new MultiselectFormControl({ + type: FormControlType.MULTI_SELECT , + controlName: 'platformName', + displayName: 'Platform', + dataTestId: 'multi-selectPlatform', + selectedFieldName : 'name' , + ngValue : 'name', + placeHolder: 'Select Platform', + isDisabled: false, + name: "platform", + value: instance ? instance.platformName : '', + validations: [new ValidatorModel(ValidatorOptions.required, 'is required')], + onInitSelectedField: ['platformList'], + 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(','); + } + }); + }; + + getPlatformControl = (instance: any, controls: FormControlModel[], isMultiSelect?: boolean): MultiselectFormControl | DropdownFormControl => { + const shouldGenerateDropdown = isMultiSelect === undefined || isMultiSelect === false; + if(shouldGenerateDropdown){ + return this.getPlatformDropdownControl(instance, controls); + } + return this.getPlatformMultiselectControl(instance, controls); }; getTenantControl = (serviceId: string, instance: any, controls: FormControlModel[]): DropdownFormControl => { 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/models/formControlModels/multiselectFormControl.model.ts b/vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts index b13745104..09fc1d250 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,13 @@ 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; constructor(data) { @@ -18,10 +21,13 @@ 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 } } diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts index d486f2975..d246771af 100644 --- a/vid-webpack-master/src/app/shared/shared.module.ts +++ b/vid-webpack-master/src/app/shared/shared.module.ts @@ -73,6 +73,7 @@ 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"; @NgModule({ @@ -196,6 +197,7 @@ import {ModelInformationService} from "./components/model-information/model-info ErrorMsgService, DataFilterPipe, ModelInformationService, + MultiselectFormControlService ] }) export class SharedModule { |