diff options
author | Ittay Stern <ittay.stern@att.com> | 2019-07-07 19:23:03 +0300 |
---|---|---|
committer | Ittay Stern <ittay.stern@att.com> | 2019-07-08 16:13:43 +0300 |
commit | f792671ae247a931f34d902e9276202b5016ef9a (patch) | |
tree | 6104971e8074c9a3d720836276ff18619719ec02 /vid-webpack-master/src/app/shared/components/searchMembersModal | |
parent | fc62274e8d15964d63c62bf0e2f4abc040252ee9 (diff) |
Merge from ecomp 718fd196 - Modern UI
Issue-ID: VID-378
Change-Id: I2736b98426e324ec3aa233b034229ba84d99839f
Signed-off-by: Ittay Stern <ittay.stern@att.com>
Diffstat (limited to 'vid-webpack-master/src/app/shared/components/searchMembersModal')
15 files changed, 813 insertions, 501 deletions
diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/element-table-row.model.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/element-table-row.model.ts new file mode 100644 index 000000000..250e2c1fa --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/element-table-row.model.ts @@ -0,0 +1,88 @@ +import {VnfMember} from "../../../models/VnfMember"; +import {Observable} from "rxjs"; +import {CustomTableColumnDefinition} from "./elements-table.component"; + +export class ElementTableRowModel extends VnfMember { + isSelected: boolean = false; +} + + +/******************************************************************************************************************************* + ModalInformation + * @type: popup type (VPN, NETWORK, VNFGROUP) + * @title: popup title + * @description: popup upper message + * @topButtonText: (optional) + * @text: button text + * @action: button action + * @backAction : arrow back button action (can close the modal/move to next step) + * @uniqObjectField: uniq object field that we can find in O(1) + * @maxSelectRow: max number of row that user can select (default = no limit)(optional) + * @getElements: function that should return Observable<any[]> of collection of elements to show in the table + * @noElementsMsg : when there are no element some message should shown + * @searchFields : extra information in the left section + * @criteria: extra criteria on table content (optional) + * @tableHeaders : table headers + * @tableContent: table td's information. + + ******************************************************************************************************************************/ + +export class ModalInformation { + type : string; + currentCriteriaInfo? : Object; + title ?: string; + description ?: string; + topButton?: { + text ?: string, + action ?: (...args) => any + }; + searchButton?: { + text ?: string, + action ?: (...args)=> any + }; + backAction? : (...args) => any; + uniqObjectField : string; + maxSelectRow ?: number; + getElements : (...args) => Observable<any[]>; + noElementsMsg : string; + searchFields: ISearchField[]; + criteria ?: ICriteria[]; + tableHeaders : CustomTableColumnDefinition[]; + tableContent : ITableContent[]; + serviceModelId: string; +} + + +export interface ISearchField { + title: string; + value: any; + dataTestId: string; + type : string; +} + + +export interface ICriteria { + label: string; + defaultValue: any; + onInit?: (...args) => Observable<string>; + onChange? : (...arg) => void; + type : string; + dataTestId : string; + isRequired ?: boolean; + currentValue ?: any; +} + + +export interface ITableContent { + id : string; + contents : {id : string[], value : string[], prefix ?: string, type? : string}[]; +} + +export enum SearchFieldItemType { + LABEL = 'LABEL', + DROPDOWN = 'DROPDOWN' +} + + + + diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.html b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.html new file mode 100644 index 000000000..036a1240f --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.html @@ -0,0 +1,71 @@ +<div class="table-header"> + <div class="left-header"> + <span class="title-header">{{modalInformation.description}}</span> + <div class="sub-title-header"> + <span class="vnf-match-your-criteria" class="total" [attr.data-tests-id]="'total-amount'" style="margin-right: 5px;"><span + [attr.data-tests-id]="'numberOfNotHideRows'">{{membersTableService.numberOfNotHideRows}}</span> {{modalInformation.type}}s match your criteria |</span> + <span class="vnf-selected" class="total" [attr.data-tests-id]="'total-selected'"><span + [attr.data-tests-id]="'numberOfSelectedRows'">{{membersTableService.numberOfSelectedRows}}</span> {{modalInformation.type}}{{membersTableService.numberOfSelectedRows>1?'s':'' }} selected</span> + </div> + </div> + + <div class="search-container"> + <sdc-filter-bar + [placeHolder]="'Filter'" + [debounceTime]="250" + [testId]="'vnf-members-search'" + (valueChange)="search($event)"> + </sdc-filter-bar> + </div> +</div> +<table id="member-table" class="table table-bordered" style="table-layout: fixed" *ngIf="data?.length > 0"> + <thead class="thead-dark"> + <tr> + <th class="allCheckboxAreSelected" style="position: relative;"> + <sdc-checkbox + [disabled]="membersTableService.isCheckAllDisabled(modalInformation.maxSelectRow)" + [(checked)]="membersTableService.allCheckboxAreSelected" + [testId]="'all-checkbox-selected'" + (checkedChange)="changeAllCheckboxStatus($event)" + ></sdc-checkbox> + </th> + <th class="header-title" *ngFor="let header of headers">{{header.displayName}}</th> + </tr> + </thead> + <tbody> + <tr class="member-table-row" *ngFor="let item of membersTableService.filteredMembers"> + <td class="sdcCheckboxMember" style="position: relative;" [attr.data-tests-id]="item[membersTableService.staticUniqObjectField]"> + <sdc-checkbox + [disabled]="membersTableService.isRowDisabled( membersTableService.allElementsStatusMap[item[membersTableService.staticUniqObjectField]]?.isSelected, modalInformation.maxSelectRow)" + [checked]="membersTableService.allElementsStatusMap[item[membersTableService.staticUniqObjectField]]?.isSelected" + [testId]="item[membersTableService.staticUniqObjectField]" + (checkedChange)="changeCheckboxStatus(item[membersTableService.staticUniqObjectField])" + ></sdc-checkbox></td> + + <td *ngFor="let tdInformation of modalInformation.tableContent" [id]="tdInformation.id"> + <div *ngIf="tdInformation.contents[0].type === 'LIST'; else noList"> + <custom-ellipsis + *ngFor="let tdInformationItem of getTdListInformationItemValue(tdInformation.contents[0], item) " + [id]="tdInformationItem" + [value]="tdInformationItem" + [breakWord]="true" + [hightlight]="filterValue"></custom-ellipsis> + </div> + <ng-template #noList> + <custom-ellipsis + *ngFor="let tdInformationItem of tdInformation.contents; index as i" + [id]="getTdInformationItemId(tdInformationItem, item)" + [value]="getTdInformationItemValue(tdInformationItem, item)" + [ngClass]="{'second-line' : i%2 === 1}" + [breakWord]="true" + [hightlight]="filterValue"></custom-ellipsis> + </ng-template> + + </td> + </tr> + + </tbody> +</table> +<div class="no-result" *ngIf="data?.length == 0">{{modalInformation?.noElementsMsg}}</div> + + diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.ts new file mode 100644 index 000000000..485a63c43 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.component.ts @@ -0,0 +1,144 @@ +import {Component, Input, OnChanges, Output, SimpleChanges, EventEmitter} from '@angular/core'; +import {ElementsTableService} from "./elements-table.service"; +import {ModalInformation} from "./element-table-row.model"; +import * as _ from 'lodash'; +import {Level1Instance} from "../../../models/level1Instance"; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../../store/reducers"; +import { + deleteGenericModalhelper, + deleteGenericModalTableDataHelper +} from "../../../storeUtil/utils/global/global.actions"; + +export class CustomTableColumnDefinition { + public displayName = ''; + public key : any = ''; + public type? = 'text'; + public filter? = ''; +} + +@Component({ + selector: 'app-members-table', + templateUrl: './elements-table.component.html', + styleUrls: ['./members-table.component.scss'] +}) + +export class ElementsTableComponent implements OnChanges{ + filterValue: string = null; + allMemberStatusMap = null; + membersTableService : ElementsTableService; + headers: CustomTableColumnDefinition[] = []; + searchQuery = null; + + @Input() modalInformation : ModalInformation; + @Input() data: Level1Instance[]; + @Output() selectedMembersAmountChange : EventEmitter<number> = new EventEmitter(); + constructor(private _membersTableService : ElementsTableService, private _store : NgRedux<AppState>){ + this.membersTableService = this._membersTableService; + } + + ngOnChanges(changes: SimpleChanges): void { + if(_.isNil(this.data)){ + this._membersTableService.resetAll(this.modalInformation.uniqObjectField, this.modalInformation.maxSelectRow); + }else { + ElementsTableService.uniqObjectField = this.modalInformation.uniqObjectField; + this.headers = this.modalInformation.tableHeaders; + const genericModalHelper = this._store.getState().global.genericModalHelper; + if(!_.isNil(genericModalHelper) && !_.isNil(genericModalHelper[`${this.modalInformation.type}_TABLE_DATA`]) && !_.isNil(genericModalHelper[`selected${this.modalInformation.type}`])){ + this.updateTablWithDefaultData(this._store.getState().global.genericModalHelper[`${this.modalInformation.type}_TABLE_DATA`]); + }else { + this.modalInformation.getElements().subscribe((res)=>{ + this.updateTablWithDefaultData(res); + }); + } + } + } + + updateTablWithDefaultData(tableData) : void{ + this._membersTableService.allElementsStatusMap = this._membersTableService.generateAllMembersStatus(tableData); + this._membersTableService.filteredMembers = this._membersTableService.sortElementsByName(tableData, "instanceName"); + this._membersTableService.updateAmountsAndCheckAll(this.modalInformation.uniqObjectField, this.modalInformation, this.modalInformation.maxSelectRow); + this.updateDefaultSelectedRows(); + } + + search(searchStr: string): void { + this.filterValue = searchStr; + this._membersTableService.filterMembers(this.filterValue, this.modalInformation.type); + } + + selectItem(item , maxNumberOfRows : number) : void { + if (maxNumberOfRows === 1) { + for (let currentItem in this.membersTableService.allElementsStatusMap) { + if (this.membersTableService.allElementsStatusMap[currentItem].isSelected) { + this.membersTableService.allElementsStatusMap[currentItem].isSelected = false; + this.membersTableService.allElementsStatusMap[item[this.membersTableService.staticUniqObjectField]].isSelected = !this.membersTableService.allElementsStatusMap[item[this.membersTableService.staticUniqObjectField]].isSelected; + return; + } + } + this.membersTableService.allElementsStatusMap[item[this.membersTableService.staticUniqObjectField]].isSelected = !this.membersTableService.allElementsStatusMap[item[this.membersTableService.staticUniqObjectField]].isSelected; + } + } + + updateDefaultSelectedRows(): void { + if(this._store.getState().global.genericModalHelper && this._store.getState().global.genericModalHelper[`selected${this.modalInformation.type}`]){ + const selectedIds = this._store.getState().global.genericModalHelper[`selected${this.modalInformation.type}`]; + for(const id in selectedIds){ + if(!_.isNil(this._membersTableService.allElementsStatusMap[id])){ + this._membersTableService.allElementsStatusMap[id].isSelected = true; + } + } + this._membersTableService.updateAmountsAndCheckAll(this.modalInformation.uniqObjectField, this.modalInformation, this.modalInformation.maxSelectRow); + this.selectedMembersAmountChange.emit(this._membersTableService.numberOfSelectedRows); + } + } + + changeAllCheckboxStatus(status: boolean) : void { + this._membersTableService.changeAllCheckboxStatus(status); + this.selectedMembersAmountChange.emit(this._membersTableService.numberOfSelectedRows); + } + + + changeCheckboxStatus(vnfInstanceId: string) : void { + if (this.modalInformation.maxSelectRow === 1) { + for (let currentItem in this.membersTableService.allElementsStatusMap) { + if (this.membersTableService.allElementsStatusMap[currentItem].isSelected) { + this.membersTableService.allElementsStatusMap[currentItem].isSelected = false; + this._store.dispatch(deleteGenericModalhelper(`selected${this.modalInformation.type}`, this.membersTableService.allElementsStatusMap[currentItem][this.modalInformation.uniqObjectField])); + this._store.dispatch(deleteGenericModalTableDataHelper(`${this.modalInformation.type}_TABLE_DATA`)); + } + } + } + this._membersTableService.changeCheckboxStatus(vnfInstanceId, this.data); + this.selectedMembersAmountChange.emit(this._membersTableService.numberOfSelectedRows); + } + + + getTdInformationItemId(data : {id : string[], value : string[], prefix ?: string}, item) : string { + let result = item; + for(const idVal of data.id){ + if(_.isNil(result)) return null; + result = result[idVal]; + } + return result; + } + + getTdInformationItemValue(data : {id : string[], value : string[], prefix ?: string}, item) : string { + let result = item; + for(const idVal of data.value){ + if(_.isNil(result)) return null; + result = result[idVal]; + } + return !_.isNil(data.prefix) ? data.prefix + result : result; + } + + + getTdListInformationItemValue(data : {id : string[], value : string[], prefix ?: string}, item) : string[] { + let result = item; + + for(let i = 0 ; i < data.value.length -1 ; i++){ + if(_.isNil(result)) return null; + result = result[data.value[i]]; + } + return _.map(result, _.last(data.value)); + } +} diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.service.spec.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.service.spec.ts index e53c63be1..db56836bd 100644 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.service.spec.ts +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.service.spec.ts @@ -1,11 +1,9 @@ -import {MembersTableService} from "./members-table.service"; +import {ElementsTableService} from "./elements-table.service"; import {TestBed, getTestBed} from "@angular/core/testing"; import {NgRedux} from "@angular-redux/store"; -import {CustomTableColumnDefinition} from "./members-table.component"; +import {CustomTableColumnDefinition} from "./elements-table.component"; import {AppState} from "../../../store/reducers"; -import {createRelatedVnfMemberInstance} from "../../../storeUtil/utils/relatedVnfMember/relatedVnfMember.actions"; import {DataFilterPipe} from "../../../pipes/dataFilter/data-filter.pipe"; -import {VnfMember} from "../../../models/VnfMember"; @@ -27,7 +25,7 @@ class MockAppStore<T> { "instanceName": "VNF1_INSTANCE_NAME", "instanceId": "VNF1_INSTANCE_ID", "orchStatus": null, - "lcpCloudRegionId": "mtn23b", + "lcpCloudRegionId": "hvf23b", "tenantId": "3e9a20a3e89e45f884e09df0cc2d2d2a", "tenantName": "APPC-24595-T-IST-02C", "modelInfo": { @@ -62,9 +60,9 @@ class MockAppStore<T> { } } -describe('MembersTableService view member count', () => { +describe('ElementsTableService view member count', () => { let injector; - let service: MembersTableService; + let service: ElementsTableService; let store: NgRedux<AppState>; let data = loadMockMembers(); @@ -73,7 +71,7 @@ describe('MembersTableService view member count', () => { TestBed.configureTestingModule( { providers: [ - MembersTableService, + ElementsTableService, {provide: NgRedux, useClass: MockAppStore}, DataFilterPipe @@ -83,94 +81,80 @@ describe('MembersTableService view member count', () => { await TestBed.compileComponents(); injector = getTestBed(); - service = injector.get(MembersTableService); + service = injector.get(ElementsTableService); store = injector.get(NgRedux) })().then(done).catch(done.fail)); test('should return number of displayed members', () => { - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); + service.modalInformation = <any>{ + uniqObjectField : "instanceId" + }; + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); service.filteredMembers = <any>data; - expect(service.calculateNotHideVnfMembers()).toEqual(2); + expect(service.calculateNotHideRows()).toEqual(2); }); test('should return number of selected members', () => { - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); - service.allMemberStatusMap['VNF1_INSTANCE_ID'].isSelected = true; - service.allMemberStatusMap['VNF2_INSTANCE_ID'].isSelected = true; - expect(service.calculateSelectedVnfMembers()).toEqual(2); + ElementsTableService.uniqObjectField = "instanceId"; + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); + service.allElementsStatusMap['VNF1_INSTANCE_ID'].isSelected = true; + service.allElementsStatusMap['VNF2_INSTANCE_ID'].isSelected = true; + expect(service.calculateSelectedRows()).toEqual(2); }); test('should return number of selected members', () => { - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); service.filteredMembers = <any>data; - service.allMemberStatusMap['VNF1_INSTANCE_ID'].isSelected = true; - service.filterMembers('VNF2'); - service.allMemberStatusMap['VNF2_INSTANCE_ID'].isSelected = true; - expect(service.calculateNotHideVnfMembers()).toEqual(1); - }); - - test('getHeader should return labels with array of keys', () => { - const headers: CustomTableColumnDefinition[] = MembersTableService.getHeaders(); - expect(headers).toEqual([ - {displayName: 'VNF instance name', key: ['instanceName']}, - {displayName: 'VNF version', key: ['modelInfo', 'modelVersion']}, - {displayName: 'VNF model name', key: ['modelInfo', 'modelName']}, - {displayName: 'Prov Status', key: ['provStatus']}, - {displayName: 'Service instance name', key: ['serviceInstanceName']}, - {displayName: 'Cloud Region', key: ['lcpCloudRegionId']}, - {displayName: 'Tenant Name', key: ['tenantName']} - ]); - }); - - - test('setMembers should dispatch action only on selected members', () => { - const vnfGroupStoreKey: string = 'vnfGroupStoreKey'; - const serviceId: string = 'serviceId'; - - jest.spyOn(store, 'dispatch'); - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); - service.allMemberStatusMap['VNF1_INSTANCE_ID'].isSelected = true; - service.setMembers({serviceId: serviceId, vnfGroupStoreKey: vnfGroupStoreKey}); - expect(store.dispatch).toHaveBeenCalledTimes(1); - expect(store.dispatch).toHaveBeenCalledWith(createRelatedVnfMemberInstance(vnfGroupStoreKey, serviceId, service.allMemberStatusMap['VNF1_INSTANCE_ID'])); + service.allElementsStatusMap['VNF1_INSTANCE_ID'].isSelected = true; + service.filterMembers('VNF2', "VNF"); + service.allElementsStatusMap['VNF2_INSTANCE_ID'].isSelected = true; + expect(service.calculateNotHideRows()).toEqual(1); }); test('generateAllMembersStatus should add to each instance isHide and isSelected and convert to map', () => { - let allMemberStatusMapMock = MembersTableService.generateAllMembersStatus(<any>data); + let allMemberStatusMapMock = service.generateAllMembersStatus(<any>data); for (const key in allMemberStatusMapMock) { expect(allMemberStatusMapMock[key].isSelected).toBeFalsy(); } }); test('changeAllCheckboxStatus', () => { + service.modalInformation = <any>{ + type : 'SomeType', + uniqObjectField : 'instanceId' + }; let data = loadMockMembers(); - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); service.filteredMembers = <any>data; service.changeAllCheckboxStatus(true); - for (let key in service.allMemberStatusMap) { - expect(service.allMemberStatusMap[key].isSelected).toEqual(true); + for (let key in service.allElementsStatusMap) { + expect(service.allElementsStatusMap[key].isSelected).toEqual(true); } }); test('should reset all numbers and lists', () => { + service.modalInformation = <any>{ + type : 'SomeType', + uniqObjectField : 'instanceId' + }; let data = loadMockMembers(); - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>data); + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); service.filteredMembers = <any>data; service.changeAllCheckboxStatus(true); - service.resetAll(); - expect(service.numberOfNotHideVnfMembers).toEqual(0); - expect(service.numberOfSelectedAndNotHideVnfMembers).toEqual(0); - expect(service.numberOfSelectedVnfMembers).toEqual(0); - expect(service.allMemberStatusMap).toEqual({}); + service.resetAll("instanceId"); + expect(service.numberOfNotHideRows).toEqual(0); + expect(service.numberOfSelectedAndNotHideRows).toEqual(0); + expect(service.numberOfSelectedRows).toEqual(0); + expect(service.allElementsStatusMap).toEqual({}); expect(service.filteredMembers.length).toEqual(0); }); test('checkAllCheckboxStatus should be false if not all are selected', () => { - service.allMemberStatusMap = MembersTableService.generateAllMembersStatus(<any>loadMockMembers()); - service.updateAmountsAndCheckAll(); + service.allElementsStatusMap = service.generateAllMembersStatus(<any>loadMockMembers()); + service.updateAmountsAndCheckAll("instanceId", <any>{}); expect(service.allCheckboxAreSelected).toEqual(false); }); @@ -178,7 +162,7 @@ describe('MembersTableService view member count', () => { test('sortVnfMembersByName should sort list by vnf name', () => { let data = <any>loadMockMembers(); - let sortedList = MembersTableService.sortVnfMembersByName(data, "instanceName"); + let sortedList = service.sortElementsByName(data, "instanceName"); expect(sortedList[0].instanceName).toEqual("VNF1_INSTANCE_NAME"); expect(sortedList[1].instanceName).toEqual("VNF2_INSTANCE_NAME"); @@ -187,22 +171,63 @@ describe('MembersTableService view member count', () => { data[0] = data[1]; data[1] = tmp; - sortedList = MembersTableService.sortVnfMembersByName(data, "instanceName"); + sortedList = service.sortElementsByName(data, "instanceName"); expect(sortedList[1].instanceName).toEqual("VNF1_INSTANCE_NAME"); expect(sortedList[0].instanceName).toEqual("VNF2_INSTANCE_NAME"); - sortedList = MembersTableService.sortVnfMembersByName(null, "instanceName"); + sortedList = service.sortElementsByName(null, "instanceName"); expect(sortedList).toEqual([]); - sortedList = MembersTableService.sortVnfMembersByName(data, undefined); + sortedList = service.sortElementsByName(data, undefined); expect(sortedList).toEqual([]); }); - test('should return only vnf members not associated to any vnf group', ()=>{ - const result: VnfMember[] = service.filterUsedVnfMembers("serviceModelId",loadMockMembers()); - expect(result.length).toEqual(1); - expect(result[0].instanceId).toEqual("VNF2_INSTANCE_ID"); + test('isRowDisabled should return false current row is selected', ()=> { + let isDisabled = service.isRowDisabled(true, null); + expect(isDisabled).toBeFalsy(); + }); + + + test('isRowDisabled should return false if there is no limit', ()=> { + let isDisabled = service.isRowDisabled(false, null); + expect(isDisabled).toBeFalsy(); + }); + + test('isRowDisabled should return false if number of rows are less then limit ', ()=> { + service.modalInformation = <any>{ + uniqObjectField : "instanceId" + }; + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); + service.allElementsStatusMap['VNF1_INSTANCE_ID'].isSelected = true; + service.allElementsStatusMap['VNF2_INSTANCE_ID'].isSelected = true; + + let isDisabled = service.isRowDisabled(false, 3); + expect(isDisabled).toBeFalsy(); + }); + + test('isRowDisabled should return true if number of rows are equal or more then limit ', ()=> { + ElementsTableService.uniqObjectField = "instanceId"; + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); + service.allElementsStatusMap['VNF1_INSTANCE_ID'].isSelected = true; + service.allElementsStatusMap['VNF2_INSTANCE_ID'].isSelected = true; + + let isDisabled = service.isRowDisabled(false, 2); + expect(isDisabled).toBeTruthy(); + }); + + + test('isCheckAllDisabled should false true if number of rows are equal or more then limit ', ()=> { + service.modalInformation = <any>{ + uniqObjectField : "instanceId" + }; + service.allElementsStatusMap = service.generateAllMembersStatus(<any>data); + service.allElementsStatusMap['VNF1_INSTANCE_ID'].isSelected = true; + service.allElementsStatusMap['VNF2_INSTANCE_ID'].isSelected = true; + + let isDisabled = service.isCheckAllDisabled( 2); + expect(isDisabled).toBeFalsy(); }); + }); @@ -214,7 +239,7 @@ function loadMockMembers(): any[] { "instanceId": "VNF1_INSTANCE_ID", "orchStatus": null, "productFamilyId": null, - "lcpCloudRegionId": "mtn23b", + "lcpCloudRegionId": "hvf23b", "tenantId": "3e9a20a3e89e45f884e09df0cc2d2d2a", "tenantName": "APPC-24595-T-IST-02C", "modelInfo": { @@ -242,7 +267,7 @@ function loadMockMembers(): any[] { "instanceId": "VNF2_INSTANCE_ID", "orchStatus": null, "productFamilyId": null, - "lcpCloudRegionId": "mtn23b", + "lcpCloudRegionId": "hvf23b", "tenantId": "3e9a20a3e89e45f884e09df0cc2d2d2a", "tenantName": "APPC-24595-T-IST-02C", "modelInfo": { diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.service.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.service.ts new file mode 100644 index 000000000..bd7f3979d --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/elements-table.service.ts @@ -0,0 +1,187 @@ +import {Injectable} from "@angular/core";; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../../store/reducers"; +import {DataFilterPipe} from "../../../pipes/dataFilter/data-filter.pipe"; +import {ElementTableRowModel, ModalInformation} from "./element-table-row.model"; +import {Level1Instance} from "../../../models/level1Instance"; +import * as _ from 'lodash'; +import {Subject} from "rxjs"; +import {CustomTableColumnDefinition} from "./elements-table.component"; +import { + deleteGenericModalhelper, + deleteGenericModalTableDataHelper, + updateGenericModalhelper, updateGenericModalTableDataHelper +} from "../../../storeUtil/utils/global/global.actions"; + +@Injectable() +export class ElementsTableService { + allElementsStatusMap : { [key:string]: ElementTableRowModel; }; + filteredMembers : any[]; + allCheckboxAreSelected : boolean; + numberOfNotHideRows : number; + numberOfSelectedRows : number; + numberOfSelectedAndNotHideRows : number; + numberOfNotSelectedAndNotHideRows : number; + maxSelectedRow : number; + modalInformation : ModalInformation; + + static uniqObjectField : string; + static changeFnTableDataTrigger : Subject<any> = new Subject(); + static changeModalInformationDataTrigger : Subject<{modalInformation, selectedRowsIds}> = new Subject(); + static selectRowsTrigger : Subject<string[]> = new Subject(); + + get staticUniqObjectField() { return ElementsTableService.uniqObjectField; } + + constructor(private _store: NgRedux<AppState>, private dataFilter: DataFilterPipe){ + this.resetAll(ElementsTableService.uniqObjectField, this.maxSelectedRow); + } + + updateAmountsAndCheckAll = (uniqObjectField: string, modalInformation : ModalInformation, maxSelectedRow? : number) : void => { + this.maxSelectedRow = maxSelectedRow; + this.modalInformation = modalInformation; + ElementsTableService.uniqObjectField = uniqObjectField; + this.numberOfSelectedRows = this.calculateSelectedRows(); + this.numberOfNotHideRows = this.calculateNotHideRows(); + this.numberOfSelectedAndNotHideRows = this.calculateSelectedAndNotHide(); + this.numberOfNotSelectedAndNotHideRows = this.calculateNotSelectedAndNotHide(); + this.allCheckboxAreSelected = this.numberOfNotHideRows > 0 && ((this.numberOfNotHideRows === this.numberOfSelectedAndNotHideRows) || (this.numberOfSelectedAndNotHideRows === this.maxSelectedRow)); + }; + + resetAll = (uniqObjectField: string, maxSelectedRow? : number) : void => { + this.allElementsStatusMap = {}; + this.filteredMembers = []; + this.numberOfSelectedRows = 0; + this.numberOfNotHideRows = 0; + this.numberOfSelectedAndNotHideRows = 0; + this.numberOfNotSelectedAndNotHideRows = 0; + this.allCheckboxAreSelected = false; + this.maxSelectedRow = maxSelectedRow; + ElementsTableService.uniqObjectField = uniqObjectField; + }; + + changeAllCheckboxStatus = (status : boolean) : void =>{ + for(const member of this.filteredMembers){ + this.allElementsStatusMap[member[this.modalInformation.uniqObjectField]].isSelected = status; + if(status){ + this._store.dispatch(updateGenericModalhelper(`selected${this.modalInformation.type}`, this.allElementsStatusMap[member[this.modalInformation.uniqObjectField]], this.modalInformation.uniqObjectField)); + }else { + this._store.dispatch(deleteGenericModalhelper(`selected${this.modalInformation.type}`,this.allElementsStatusMap[member[this.modalInformation.uniqObjectField]][this.modalInformation.uniqObjectField])); + } + } + this.updateAmountsAndCheckAll(ElementsTableService.uniqObjectField, this.modalInformation, this.maxSelectedRow); + }; + + changeCheckboxStatus = (vnfInstanceId : string, tableData) : void => { + if(_.isNil(this.allElementsStatusMap[vnfInstanceId].isSelected)){ + this.allElementsStatusMap[vnfInstanceId].isSelected = true; + this._store.dispatch(updateGenericModalhelper(`selected${this.modalInformation.type}`, this.allElementsStatusMap[vnfInstanceId], this.modalInformation.uniqObjectField)); + this._store.dispatch(updateGenericModalTableDataHelper(`${this.modalInformation.type}_TABLE_DATA`, tableData)); + }else { + this.allElementsStatusMap[vnfInstanceId].isSelected = !this.allElementsStatusMap[vnfInstanceId].isSelected; + if(this.allElementsStatusMap[vnfInstanceId].isSelected){ + this._store.dispatch(updateGenericModalhelper(`selected${this.modalInformation.type}`, this.allElementsStatusMap[vnfInstanceId], this.modalInformation.uniqObjectField)); + this._store.dispatch(updateGenericModalTableDataHelper(`${this.modalInformation.type}_TABLE_DATA`, tableData)); + }else { + this._store.dispatch(deleteGenericModalhelper(`selected${this.modalInformation.type}`, this.modalInformation.uniqObjectField)); + this._store.dispatch(deleteGenericModalhelper(`selected${this.modalInformation.type}`, vnfInstanceId)); + + this._store.dispatch(deleteGenericModalTableDataHelper(`${this.modalInformation.type}_TABLE_DATA`)); + } + } + + this.updateAmountsAndCheckAll(ElementsTableService.uniqObjectField, this.modalInformation, this.maxSelectedRow); + }; + + filterMembers(searchStr: string, type :string): void { + const keys: string[][] = this.getDataKeys(type); + const types :string[] = this.getDataType(type); + this.filteredMembers = this.dataFilter.transform(_.values(this.allElementsStatusMap), searchStr || '', keys, types); + this.updateAmountsAndCheckAll(ElementsTableService.uniqObjectField, this.modalInformation, this.maxSelectedRow); + } + + /************************************************** + generate elements data for select/ unselect rows + **************************************************/ + generateAllMembersStatus(tableData : Level1Instance[]) : { [key:string]: ElementTableRowModel; }{ + tableData.map((item) => { + item['isSelected'] = false + }); + return _.keyBy(tableData as ElementTableRowModel[],this.staticUniqObjectField); + } + + sortElementsByName(list : Level1Instance[], keyName : string) :Level1Instance[]{ + if(!_.isNil(list) && !_.isNil(keyName)) { + return list.sort(function(itemA, itemB) { return itemA[keyName]- itemB[keyName];}) + } + return []; + } + + /******************************** + table columns headers and key's + ********************************/ + static getHeaders(type: string) : CustomTableColumnDefinition[] { + return [ + {displayName: `${type} instance name`, key: ['instanceName']}, + {displayName: `${type} version`, key: ['modelInfo', 'modelVersion']}, + {displayName: `${type} model name`, key: ['modelInfo', 'modelName']}, + {displayName: 'Prov Status', key: ['provStatus']}, + {displayName: 'Service instance name', key: ['serviceInstanceName']}, + {displayName: 'Cloud Region', key: ['lcpCloudRegionId']}, + {displayName: 'Tenant Name', key: ['tenantName']} + ]; + } + + getDataKeys(type: string): string[][]{ + const headers = (!_.isNil(this.modalInformation) && !_.isNil(this.modalInformation.tableHeaders)) ? this.modalInformation.tableHeaders : ElementsTableService.getHeaders(type); + return headers.map((header)=> header.key).concat([[ElementsTableService.uniqObjectField]],[['serviceInstanceId']]); + } + + getDataType(type: string): string[]{ + const headers = (!_.isNil(this.modalInformation) && !_.isNil(this.modalInformation.tableHeaders)) ? this.modalInformation.tableHeaders : ElementsTableService.getHeaders(type); + return headers.map((header)=> header.type); + + } + + /************************************************************************************* + calculate the number of selected vnf members - include not visible and visible rows + @allElementsStatusMap: current vnf member status + *************************************************************************************/ + calculateSelectedRows() : number { + const flatObject = _.values(this.allElementsStatusMap); + return _.filter(flatObject, (item) => { if (item.isSelected) return item }).length; + } + + /************************************************ + calculate the number of display vnf members + @allElementsStatusMap: current vnf member status + ************************************************/ + calculateNotHideRows() : number { + return this.filteredMembers ? this.filteredMembers.length : 0; + } + + /************************************************ + calculate the number of display vnf members + @allElementsStatusMap: current vnf member status + ************************************************/ + calculateSelectedAndNotHide() : number { + return _.filter(this.filteredMembers, (item) => { if ( this.allElementsStatusMap[item[ElementsTableService.uniqObjectField]].isSelected) return item }).length; + } + + calculateNotSelectedAndNotHide() : number { + return _.filter(this.filteredMembers, (item) => { if ( !this.allElementsStatusMap[item[ElementsTableService.uniqObjectField]].isSelected) return item }).length; + } + + + isRowDisabled(currentRowIsSelected : boolean, maxSelectRow?: number) : boolean { + return _.isNil(maxSelectRow) || currentRowIsSelected || maxSelectRow === 1 ? false : maxSelectRow <= this.calculateSelectedRows(); + } + + isCheckAllDisabled(maxSelectRow?: number) : boolean{ + if(_.isNil(maxSelectRow)) return false; + else { + return this.numberOfNotSelectedAndNotHideRows > maxSelectRow; + } + } + + +} diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/member-table-row.model.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/member-table-row.model.ts deleted file mode 100644 index c5f1a7a07..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/member-table-row.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {VnfMember} from "../../../models/VnfMember"; - -export class MemberTableRowModel extends VnfMember{ - isSelected : boolean = false; -} - diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.html b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.html deleted file mode 100644 index 3a29ed824..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.html +++ /dev/null @@ -1,75 +0,0 @@ -<div class="table-header"> - <div class="left-header"> - <span class="title-header">{{description}}</span> - <div class="sub-title-header"> - <span class="vnf-match-your-criteria" class="total" [attr.data-tests-id]="'total-amount'" style="margin-right: 5px;"><span - [attr.data-tests-id]="'numberOfNotHideVnfMembers'">{{membersTableService.numberOfNotHideVnfMembers}}</span> VNFs match your criteria</span> - <span class="vnf-selected" class="total" [attr.data-tests-id]="'total-selected'"><span - [attr.data-tests-id]="'numberOfSelectedVnfMembers'">{{membersTableService.numberOfSelectedVnfMembers}}</span> VNF{{membersTableService.numberOfSelectedVnfMembers>1?'s':'' }} selected</span> - </div> - </div> - - <div class="search-container"> - <sdc-filter-bar - [placeHolder]="'Search...'" - [debounceTime]="250" - [testId]="'vnf-members-search'" - (valueChange)="search($event)"> - </sdc-filter-bar> - </div> -</div> -<table id="member-table" class="table table-bordered" *ngIf="data?.length > 0"> - <thead class="thead-dark"> - <tr> - <th class="allCheckboxAreSelected" style="position: relative;"> - <sdc-checkbox - [(checked)]="membersTableService.allCheckboxAreSelected" - [testId]="'all-checkbox-selected'" - (checkedChange)="changeAllCheckboxStatus($event)" - ></sdc-checkbox> - </th> - <th class="header-title" *ngFor="let header of headers">{{header.displayName}}</th> - </tr> - </thead> - <tbody> - <tr class="member-table-row" *ngFor="let vnf of membersTableService.filteredMembers"> - <td class="sdcCheckboxMember" style="position: relative;" [attr.data-tests-id]="vnf?.instanceId"> - <sdc-checkbox - [checked]="membersTableService.allMemberStatusMap[vnf.instanceId]?.isSelected" - [testId]="vnf?.instanceId" - (checkedChange)="changeCheckboxStatus(vnf.instanceId)" - ></sdc-checkbox></td> - <td id="vnfName"> - <custom-ellipsis [id]="vnf?.instanceName" [value]="vnf?.instanceName" - [hightlight]="filterValue"></custom-ellipsis> - <custom-ellipsis class="second-line" [id]="vnf?.instanceId" [value]="'UUID: '+ vnf?.instanceId" - [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="version"> - <custom-ellipsis [id]="vnf?.modelInfo?.modelVersion" [value]="vnf?.modelInfo?.modelVersion" [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="modelName"> - <custom-ellipsis [id]="vnf?.modelInfo?.modelName" [value]="vnf?.modelInfo?.modelName" [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="provStatus"> - <custom-ellipsis [id]="vnf?.provStatus" [value]="vnf?.provStatus" [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="serviceInstance"> - <custom-ellipsis [id]="vnf?.serviceInstanceName" [value]="vnf?.serviceInstanceName" - [hightlight]="filterValue"></custom-ellipsis> - <custom-ellipsis class="second-line" [id]="vnf?.serviceInstanceId" [value]="'UUID: '+ vnf?.serviceInstanceId" - [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="cloudRegion"> - <custom-ellipsis [id]="vnf?.lcpCloudRegionId" [value]="vnf?.lcpCloudRegionId" [hightlight]="filterValue"></custom-ellipsis> - </td> - <td id="tenantName"> - <custom-ellipsis [id]="vnf?.tenantName" [value]="vnf?.tenantName" [hightlight]="filterValue"></custom-ellipsis> - </td> - </tr> - - </tbody> -</table> -<div class="no-result" *ngIf="data?.length == 0">No VNFs were found that can belong to this group.</div> - - diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.scss b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.scss index 3be975222..2fa90b859 100644 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.scss +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.scss @@ -42,32 +42,46 @@ #member-table { border: 1px solid #D2D2D2; + display: flex; + flex-flow: column; + max-height: calc(100vh - 135px); + overflow-y: auto; thead { background: #F8F8F8; - th.allCheckboxAreSelected { - vertical-align: middle !important; - width: 48px; - max-width: 48px; - min-width: 48px; - height: 48px; - } - th.header-title { - font-family: OpenSans-SemiBold; - vertical-align: middle !important; - height: 48px; - font-size: 12px; + tr { + table-layout: fixed; + display: table; + width: 100%; + th.allCheckboxAreSelected { + vertical-align: middle !important; + width: 48px; + max-width: 48px; + min-width: 48px; + height: 48px; + } + th.header-title { + font-family: OpenSans-SemiBold; + vertical-align: middle !important; + height: 48px; + font-size: 12px; + } } } tbody { - td{ - text-align: center; - height: 60px; - padding-top: 0; - padding-bottom: 0; - max-height: 60px; - vertical-align: middle; - .second-line { - font-size: 12px; + tr { + table-layout: fixed; + display: table; + width: 100%; + td{ + text-align: center; + height: 60px; + padding-top: 0; + padding-bottom: 0; + max-height: 60px; + vertical-align: middle; + .second-line { + font-size: 12px; + } } } } @@ -89,3 +103,13 @@ align-items: center; justify-content: center; } + +td.sdcCheckboxMember { + vertical-align: middle !important; + width: 48px !important; + max-width: 48px !important; + min-width: 48px !important; + height: 48px !important; +} + + diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.ts deleted file mode 100644 index 9736563af..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import {Component, Input, OnChanges, Output, SimpleChanges, EventEmitter} from '@angular/core'; -import {VnfMember} from "../../../models/VnfMember"; -import {MembersTableService} from "./members-table.service"; -import * as _ from 'lodash'; - -export class CustomTableColumnDefinition { - public displayName = ''; - public key : any = ''; - public type? = 'text'; - public filter? = ''; -} - -@Component({ - selector: 'app-members-table', - templateUrl: './members-table.component.html', - styleUrls: ['./members-table.component.scss'] -}) - -export class MembersTableComponent implements OnChanges{ - filterValue: string = null; - allMemberStatusMap = null; - membersTableService : MembersTableService; - headers: CustomTableColumnDefinition[] = MembersTableService.getHeaders(); - @Input() data: VnfMember[]; - @Input() description: string; - @Output() selectedMembersAmountChange : EventEmitter<number> = new EventEmitter(); - constructor(private _membersTableService : MembersTableService){ - this.membersTableService = this._membersTableService; - } - - ngOnChanges(changes: SimpleChanges): void { - if(_.isNil(this.data)){ - this._membersTableService.resetAll(); - }else { - this._membersTableService.allMemberStatusMap = MembersTableService.generateAllMembersStatus(this.data); - this._membersTableService.filteredMembers = MembersTableService.sortVnfMembersByName(this.data, "instanceName"); - this._membersTableService.updateAmountsAndCheckAll(); - } - } - - search(searchStr: string): void { - this.filterValue = searchStr; - this._membersTableService.filterMembers(this.filterValue); - } - - changeAllCheckboxStatus(status: boolean) : void { - this._membersTableService.changeAllCheckboxStatus(status); - this.selectedMembersAmountChange.emit(this._membersTableService.numberOfSelectedVnfMembers); - } - - - changeCheckboxStatus(vnfInstanceId: string) : void { - this._membersTableService.changeCheckboxStatus(vnfInstanceId); - this.selectedMembersAmountChange.emit(this._membersTableService.numberOfSelectedVnfMembers); - } - -} diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.service.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.service.ts deleted file mode 100644 index 5b9cd39a2..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/members-table/members-table.service.ts +++ /dev/null @@ -1,153 +0,0 @@ -import {Injectable} from "@angular/core"; -import {VnfMember} from "../../../models/VnfMember"; -import {CustomTableColumnDefinition} from "./members-table.component"; -import {NgRedux} from "@angular-redux/store"; -import {AppState} from "../../../store/reducers"; -import {createRelatedVnfMemberInstance} from "../../../storeUtil/utils/relatedVnfMember/relatedVnfMember.actions"; -import * as _ from 'lodash'; -import {DataFilterPipe} from "../../../pipes/dataFilter/data-filter.pipe"; -import {MemberTableRowModel} from "./member-table-row.model"; - -@Injectable() -export class MembersTableService { - allMemberStatusMap : { [key:string]: MemberTableRowModel; }; - filteredMembers : VnfMember[]; - allCheckboxAreSelected : boolean; - numberOfNotHideVnfMembers : number; - numberOfSelectedVnfMembers : number; - numberOfSelectedAndNotHideVnfMembers : number; - - constructor(private _store: NgRedux<AppState>, private dataFilter: DataFilterPipe){ - this.resetAll(); - } - - filterUsedVnfMembers = (serviceModelId: string, result: VnfMember[]): VnfMember[] => { - const allMembersMap = _.keyBy(result as VnfMember[], 'instanceId'); - const vnfGroupsData = this._store.getState().service.serviceInstance[serviceModelId].vnfGroups; - const vnfMembersArr = _.flatMap(vnfGroupsData).map((vnfGroup) =>vnfGroup.vnfs ); - for( let vnf of vnfMembersArr ){ - for(let member in vnf){ - delete allMembersMap[member]; - } - } - return _.flatMap(allMembersMap); - }; - - updateAmountsAndCheckAll = () : void => { - this.numberOfSelectedVnfMembers = this.calculateSelectedVnfMembers(); - this.numberOfNotHideVnfMembers = this.calculateNotHideVnfMembers(); - this.numberOfSelectedAndNotHideVnfMembers = this.calculateSelectedAndNotHide(); - this.allCheckboxAreSelected = this.numberOfNotHideVnfMembers > 0 && this.numberOfNotHideVnfMembers === this.numberOfSelectedAndNotHideVnfMembers; - }; - - resetAll = () : void => { - this.allMemberStatusMap = {}; - this.filteredMembers = []; - this.numberOfSelectedVnfMembers = 0; - this.numberOfNotHideVnfMembers = 0; - this.numberOfSelectedAndNotHideVnfMembers = 0; - this.allCheckboxAreSelected = false; - }; - - changeAllCheckboxStatus = (status : boolean) : void =>{ - for(const member of this.filteredMembers){ - this.allMemberStatusMap[member.instanceId].isSelected = status; - } - this.updateAmountsAndCheckAll(); - }; - - changeCheckboxStatus = (vnfInstanceId : string ) : void =>{ - this.allMemberStatusMap[vnfInstanceId].isSelected = !this.allMemberStatusMap[vnfInstanceId].isSelected; - this.updateAmountsAndCheckAll(); - }; - - /************************************************ - iterate over all current vnf members: - 1) if vnf member is selected then update REDUX store - 2) if vnf member is not selected then delete member - @allMemberStatusMap: current vnf member status - @vnfGroupStoreKey: vnf group store key - @serviceId: service model id - ************************************************/ - setMembers = (data : {serviceId : string, vnfGroupStoreKey : string}) : void =>{ - let tmpMembers = this.allMemberStatusMap; - for(let key in tmpMembers){ - if(tmpMembers[key].isSelected){ - this._store.dispatch(createRelatedVnfMemberInstance( data.vnfGroupStoreKey, data.serviceId, tmpMembers[key])); - } - } - }; - - filterMembers(searchStr: string): void { - const keys: string[][] = MembersTableService.getDataKeys(); - this.filteredMembers = this.dataFilter.transform(_.values(this.allMemberStatusMap), searchStr || '', keys); - this.updateAmountsAndCheckAll(); - } - - /************************************ - generate vnf member data for select/ unselect rows - ************************************/ - static generateAllMembersStatus(tableData : VnfMember[]) : { [key:string]: MemberTableRowModel; }{ - - tableData.map((vnf) => { - vnf['isSelected'] = false - }); - return _.keyBy(tableData as MemberTableRowModel[], 'instanceId'); - } - - - static sortVnfMembersByName(list : VnfMember[], keyName : string) :VnfMember[]{ - if(!_.isNil(list) && !_.isNil(keyName)) { - return list.sort(function(itemA, itemB) { return itemA[keyName]- itemB[keyName];}) - } - return []; - - } - - /******************************** - table columns headers and key's - ********************************/ - static getHeaders() : CustomTableColumnDefinition[] { - return [ - {displayName: 'VNF instance name', key: ['instanceName']}, - {displayName: 'VNF version', key: ['modelInfo', 'modelVersion']}, - {displayName: 'VNF model name', key: ['modelInfo', 'modelName']}, - {displayName: 'Prov Status', key: ['provStatus']}, - {displayName: 'Service instance name', key: ['serviceInstanceName']}, - {displayName: 'Cloud Region', key: ['lcpCloudRegionId']}, - {displayName: 'Tenant Name', key: ['tenantName']} - ]; - } - - static getDataKeys(): string[][]{ - const headers = MembersTableService.getHeaders(); - return headers.map((header)=> header.key).concat([['instanceId']],[['serviceInstanceId']]); - } - - /************************************************************************************* - calculate the number of selected vnf members - include not visible and visible rows - @allMemberStatusMap: current vnf member status - *************************************************************************************/ - calculateSelectedVnfMembers() : number { - const flatObject = _.values(this.allMemberStatusMap); - return _.filter(flatObject, (item) => { if (item.isSelected) return item }).length; - } - - /************************************************ - calculate the number of display vnf members - @allMemberStatusMap: current vnf member status - ************************************************/ - calculateNotHideVnfMembers() : number { - return this.filteredMembers.length; - } - - /************************************************ - calculate the number of display vnf members - @allMemberStatusMap: current vnf member status - ************************************************/ - calculateSelectedAndNotHide() : number { - return _.filter(this.filteredMembers, (item) => { if ( this.allMemberStatusMap[item.instanceId].isSelected) return item }).length; - } - - -} diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.html b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.html new file mode 100644 index 000000000..7e79ca6f1 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.html @@ -0,0 +1,64 @@ +<div class="modal-search-member-content"> + <div class="header"> + <vid-svg-icon + [attr.data-tests-id]="'cancelBtn'" + (click)="backAction()" + class="navigation-arrow-back" + [mode]="'primary'" + [size]="'large'" + [name]="'navigation-arrow-back'" + [clickable]="true" + [fill]="'#FFFFFF'" + [widthViewBox]="'24'" + [heightViewBox]="'24'"> + </vid-svg-icon> + + <span class="title"> + {{modalInformation.title}} + </span> + <button type="submit" data-tests-id="setMembersBtn" [disabled]="disableSetElements" (click)="doneAction()" class="sdc-button sdc-button__primary">{{modalInformation?.topButton?.text}}</button> + </div> + <div class="content-wrapper"> + <div class="sidebar-left"> + <div class="search-criteria-wrapper"> + <div class="search-criteria-title">SEARCH CRITERIA</div> + <div class="search-item" *ngFor="let searchFieldItem of modalInformation?.searchFields"> + <div> + <div><span class="label-item" >{{searchFieldItem.title}}</span></div> + <div><span attr.data-tests-id="{{searchFieldItem.dataTestId}}" class="text-item">{{searchFieldItem.value}}</span></div> + </div> + </div> + <div class="search-item" *ngFor="let criteria of modalInformation?.criteria"> + <div *ngIf="criteria.type === 'DROPDOWN'"> + <div><span class="label-item" [ngClass]="{'required': criteria.isRequired}">{{criteria.label}}</span></div> + <div> + <select class="form-control input-text select-criteria" + id="{{criteria?.dataTestId}}-select" + [attr.data-tests-id]="criteria?.dataTestId" + (change)="criteria.onChange(criteria, $event.target.value)"> + + <option *ngFor="let option of criteria.onInit() | async" + class="{{option}} {{option}}-Option" + [value]="option">{{option}} + </option> + </select> + </div> + </div> + </div> + <div class="search-button" *ngIf="modalInformation.criteria && modalInformation.criteria.length > 0"> + <button type="submit" + data-tests-id="searchByNetworkRole" + [disabled]="disableSearchByNetworkRole" + (click)="searchByCriteriaAction()" + class="sdc-button sdc-button__primary">Search...</button> + </div> + </div> + </div> + <div class="sidebar-right"> + <app-members-table + [data]="elementsData" + [modalInformation]="modalInformation" + (selectedMembersAmountChange)="selectedMembersAmountChange($event)"></app-members-table> + </div> + </div> +</div> diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.scss b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.scss index d49653934..7d9d139d1 100644 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.scss +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.scss @@ -44,12 +44,12 @@ } .content-wrapper { - display: flex; .sidebar-left { - flex-basis: 285px; + width: 20%; border-right: 1px solid #D2D2D2; height: calc(100vh - 60px); + float: left; .search-criteria-wrapper{ @@ -82,8 +82,34 @@ } .sidebar-right { - flex: 1; - margin: 80px 50px; + padding: 15px 30px 0px 30px; + width: 80%; + float: right; } } } + +select.select-criteria { + webkit-appearance: none; + background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat; + background-size: 24px; + background-position-x: right; + background-position-y: center; + font-family: OpenSans-Italic; + font-size: 14px; + height: 38px; + -webkit-appearance: none; + -moz-appearance: none; +} + +.required:after { + content: " * "; + color: #cf2a2a; + margin-left: 3px; +} + +.search-button { + display: flex; + justify-content: space-around; +} + diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.ts new file mode 100644 index 000000000..211f59337 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-elements-modal.component.ts @@ -0,0 +1,91 @@ +import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {DialogComponent, DialogService} from "ng2-bootstrap-modal"; +import {IframeService} from "../../utils/iframe.service"; +import {AaiService} from "../../services/aaiService/aai.service"; +import {VnfGroupModel} from "../../models/vnfGroupModel"; +import {ElementsTableService} from "./members-table/elements-table.service"; +import {Level1Instance} from "../../models/level1Instance"; +import {ModalInformation} from "./members-table/element-table-row.model"; +import {NgRedux} from "@angular-redux/store"; +import {AppState} from "../../store/reducers"; +import {FormGroup} from "@angular/forms"; +import * as _ from "lodash"; +import {clearAllGenericModalhelper} from "../../storeUtil/utils/global/global.actions"; +@Component({ + selector: 'search-members-modal', + templateUrl: 'search-elements-modal.component.html', + styleUrls: ['search-elements-modal.component.scss'] +}) + +export class SearchElementsModalComponent extends DialogComponent<{ modalInformation: ModalInformation }, boolean> implements OnInit, OnDestroy { + modalInformation: ModalInformation; + parentElementClassName = 'content'; + elementsData: Level1Instance[]; + vnfGroupModel: VnfGroupModel; + disableSetElements: boolean = true; + disableSearchByNetworkRole: boolean = false; + dynamicFormGroup: FormGroup = null; + + constructor(dialogService: DialogService, + private _iframeService: IframeService, + private _aaiService: AaiService, + private _membersTableService: ElementsTableService, + private _store: NgRedux<AppState>) { + super(dialogService); + ElementsTableService.changeFnTableDataTrigger.subscribe((triggerRes) => { + this._membersTableService.resetAll(this.modalInformation.uniqObjectField, this.modalInformation.maxSelectRow); + this.elementsData = triggerRes; + }); + + ElementsTableService.changeModalInformationDataTrigger.subscribe(({modalInformation, selectedRowsIds}) => { + this.disableSetElements = true; + this.modalInformation = modalInformation; + this.ngOnInit(selectedRowsIds); + }) + } + + @ViewChild('ElementsTableComponent') membersTable; + + ngOnInit(selectedRowsIds?: string[]): void { + const genericModalHelper = this._store.getState().global.genericModalHelper; + if(!_.isNil(genericModalHelper) && !_.isNil(genericModalHelper[`${this.modalInformation.type}_TABLE_DATA`]) && !_.isNil(genericModalHelper[`selected${this.modalInformation.type}`])){ + this.elementsData = this._store.getState().global.genericModalHelper[`${this.modalInformation.type}_TABLE_DATA`]; + } else { + this.modalInformation.getElements() + .subscribe((result) => { + this.elementsData = result; + }); + } + }; + + closeDialog(): void { + this._iframeService.removeFullScreen(); + this._iframeService.removeClassCloseModal(this.parentElementClassName); + this.dialogService.removeDialog(this); + setTimeout(() => { + window.parent.postMessage("closeIframe", "*"); + }, 15); + } + + selectedMembersAmountChange(selectedMembersAmount: number): void { + this.disableSetElements = selectedMembersAmount == 0; + } + + doneAction(): void { + this.modalInformation.topButton.action.call(this, this); + } + + searchByCriteriaAction(): void { + this.modalInformation.searchButton.action.call(this, this); + } + + backAction(): void { + if (this.modalInformation.backAction) { + this.modalInformation.backAction.call(this, this); + } else { + this.closeDialog(); + } + } +} + + diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.html b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.html deleted file mode 100644 index 899bc9889..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.html +++ /dev/null @@ -1,35 +0,0 @@ -<div class="modal-search-member-content"> - <div class="header"> - <vid-svg-icon - [attr.data-tests-id]="'cancelBtn'" - (click)="closeDialog()" - class="navigation-arrow-back" - [mode]="'primary'" - [size]="'large'" - [name]="'navigation-arrow-back'" - [clickable]="true" - [fill]="'#FFFFFF'" - [widthViewBox]="'24'" - [heightViewBox]="'24'"> - </vid-svg-icon> - - <span class="title"> - {{title}} - </span> - <button type="submit" data-tests-id="setMembersBtn" [disabled]="disableSetMembers" (click)="setMembers()" class="sdc-button sdc-button__primary">SET MEMBERS</button> - </div> - <div class="content-wrapper"> - <div class="sidebar-left"> - <div class="search-criteria-wrapper"> - <div class="search-criteria-title">SEARCH CRITERIA</div> - <div class="search-item" *ngFor="let searchFieldItem of searchFields"> - <span class="label-item">{{searchFieldItem.title}}</span> - <span attr.data-tests-id="{{searchFieldItem.dataTestId}}" class="text-item">{{searchFieldItem.value}}</span> - </div> - </div> - </div> - <div class="sidebar-right"> - <app-members-table [data]="membersData" [description]="description" (selectedMembersAmountChange)="selectedMembersAmountChange($event)"></app-members-table> - </div> - </div> -</div> diff --git a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.ts b/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.ts deleted file mode 100644 index 9c65d222d..000000000 --- a/vid-webpack-master/src/app/shared/components/searchMembersModal/search-members-modal.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; -import {DialogComponent, DialogService} from "ng2-bootstrap-modal"; -import {IframeService} from "../../utils/iframe.service"; -import {AaiService} from "../../services/aaiService/aai.service"; -import {VnfMember} from "../../models/VnfMember"; -import {VnfGroupModel} from "../../models/vnfGroupModel"; -import {MembersTableService} from "./members-table/members-table.service"; -import {VnfGroupInstance} from "../../models/vnfGroupInstance"; - - -export interface PopupModel { - title: string; - serviceModelId : string; - searchFields: ISearchField[]; - description : string; - subscriberId: string, - serviceType: string, - node: VnfGroupInstance, - vnfGroupModel: VnfGroupModel; - -} - -export interface ISearchField { - title: string; - value: any; - dataTestId: string; -} - -@Component({ - selector : 'search-members-modal', - templateUrl : 'search-members-modal.component.html', - styleUrls : ['search-members-modal.component.scss'] -}) - -export class SearchMembersModalComponent extends DialogComponent<PopupModel, boolean> implements OnInit, OnDestroy { - title: string; - serviceModelId : string; - parentElementClassName = 'content'; - membersData: VnfMember[]; - description : string; - searchFields: ISearchField[]; - vnfGroupModel: VnfGroupModel; - subscriberId: string; - serviceType: string; - node: VnfGroupInstance; - disableSetMembers: boolean = true; - constructor(dialogService: DialogService , - private _iframeService : IframeService, - private _aaiService : AaiService, - private _membersTableService: MembersTableService){ - super(dialogService); - - } - @ViewChild('MembersTableComponent') membersTable; - - ngOnInit() : void{ - this._aaiService.getOptionalGroupMembers(this.serviceModelId, this.subscriberId, this.serviceType, (Object.values(this.vnfGroupModel.members))[0].sourceModelInvariant, this.vnfGroupModel.properties.type, this.vnfGroupModel.properties.role) - .subscribe((result: VnfMember[])=>{ - this.membersData = this._membersTableService.filterUsedVnfMembers(this.serviceModelId, result); - }); - }; - - - closeDialog() : void{ - this._iframeService.removeClassCloseModal(this.parentElementClassName); - this.dialogService.removeDialog(this); - setTimeout(() => { - window.parent.postMessage("closeIframe", "*"); - }, 15); - } - selectedMembersAmountChange(selectedMembersAmount: number) : void { - this.disableSetMembers = selectedMembersAmount==0; - } - - - setMembers() : void { - this._membersTableService.setMembers({serviceId : this.serviceModelId, vnfGroupStoreKey : this.node.vnfGroupStoreKey}); - this.closeDialog(); - } -} - - |