Allow platform multi-selection for VNF in modern UI 72/98672/10
authorYoav Schneiderman <yoav.schneiderman@intl.att.com>
Wed, 20 Nov 2019 14:50:45 +0000 (16:50 +0200)
committerEinat Vinouze <einat.vinouze@intl.att.com>
Tue, 26 Nov 2019 10:41:29 +0000 (12:41 +0200)
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:
features.properties.md
vid-app-common/src/main/java/org/onap/vid/properties/Features.java
vid-automation/src/main/java/org/onap/simulator/presetGenerator/presets/mso/PresetMSOCreateVnfALaCarteCypress2.java
vid-automation/src/main/java/vid/automation/test/infra/Features.java
vid-automation/src/test/java/org/onap/vid/api/AsyncInstantiationALaCarteApiTest.java
vid-automation/src/test/resources/a-la-carte/redux-a-la-carte-no-testapi.json
vid-automation/src/test/resources/a-la-carte/redux-a-la-carte.json
vid-automation/src/test/resources/features.properties
vid-webpack-master/cypress/integration/iFrames/ala-carte.e2e.ts
vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json
vid-webpack-master/cypress/support/steps/genericForm/genericFormAction.steps.ts
vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.html
vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.spec.ts [deleted file]
vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.component.ts
vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.formControl.service.ts [new file with mode: 0644]
vid-webpack-master/src/app/shared/components/formControls/component/multiselect/multiselect.model.ts [new file with mode: 0644]
vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.spec.ts
vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vnfGenerator/vnf.control.generator.ts
vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html
vid-webpack-master/src/app/shared/models/formControlModels/multiselectFormControl.model.ts
vid-webpack-master/src/app/shared/shared.module.ts

index 45d5922..20db298 100644 (file)
 * 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
index d6d7a6a..6a6ac68 100644 (file)
@@ -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,
     ;
index 96424e8..da1c3ff 100644 (file)
@@ -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\"," +
index c1a5052..208f463 100644 (file)
@@ -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,
     ;
index 92d3f79..8fe0580 100644 (file)
@@ -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;
index dfdab76..1c22fb8 100644 (file)
       "lcpCloudRegionId": "AAIAIC25",
       "legacyRegion": "just another region",
       "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
-      "platformName": "xxx1",
+      "platformName": "xxx1,platform",
       "lineOfBusiness": "zzz1",
       "instanceParams": [
         {}
index cc1d5b5..7924340 100644 (file)
@@ -98,7 +98,7 @@
       "lcpCloudRegionId": "AAIAIC25",
       "legacyRegion": "just another region",
       "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
-      "platformName": "xxx1",
+      "platformName": "xxx1,platform",
       "lineOfBusiness": "zzz1",
       "instanceParams": [
         {}
index 3b7fd31..84522ae 100644 (file)
@@ -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
+
index 57c6732..14b4bdc 100644 (file)
@@ -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(() => {
index d9561f1..53038ed 100644 (file)
@@ -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
 }
index 9786369..41784da 100644 (file)
@@ -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);
index f7c4894..f205259 100644 (file)
@@ -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 (file)
index 81c8d46..0000000
+++ /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();
-    }
-  )
-});
-
index 4b98c7e..9b900de 100644 (file)
@@ -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 (file)
index 0000000..4a95805
--- /dev/null
@@ -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 (file)
index 0000000..a495211
--- /dev/null
@@ -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;
+  }
+}
index 5c6e25c..9230ccf 100644 (file)
@@ -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";
index 7760ba8..55177aa 100644 (file)
@@ -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 => {
index d4c5118..edf8682 100644 (file)
@@ -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">
index b137451..09fc1d2 100644 (file)
@@ -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
   }
 
 }
index d486f29..d246771 100644 (file)
@@ -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 {