diff --git a/webapp/src/app/core/services/auth.service.ts b/webapp/src/app/core/services/auth.service.ts index 775f490f0f..358631b293 100644 --- a/webapp/src/app/core/services/auth.service.ts +++ b/webapp/src/app/core/services/auth.service.ts @@ -230,7 +230,7 @@ export class AuthService { get redirectUrl(): string { let redirectUrl = ''; - redirectUrl = this.dataStore.getRedirectUrl() || redirectUrl; + redirectUrl = localStorage.getItem("redirectUrl"); return redirectUrl; } @@ -328,13 +328,13 @@ export class AuthService { this.fetchRolePermissionMapping().subscribe(result => { this.logger.log('info', '**Successfully set user role capabilities mapping Fetched information**'); - + observer.next('success'); + observer.complete(); }, error => { this.logger.log('info', '**Error in setting user role capabilities information**'); + observer.error(error); }); - observer.next('success'); - observer.complete(); } else { const errorMessage = response.message || 'Error authenticating the id_token'; this.logger.log('error ', errorMessage); diff --git a/webapp/src/app/core/services/permission-guard.service.ts b/webapp/src/app/core/services/permission-guard.service.ts index 0471afb331..ad13217081 100644 --- a/webapp/src/app/core/services/permission-guard.service.ts +++ b/webapp/src/app/core/services/permission-guard.service.ts @@ -38,6 +38,9 @@ export class PermissionGuardService implements CanActivate { this.router.navigate(['/home']); return false; } + const redirectUrl = location.origin + state.url; + if(!redirectUrl.includes("home")) + localStorage.setItem("redirectUrl",redirectUrl); return true; } diff --git a/webapp/src/app/core/services/table-state.service.ts b/webapp/src/app/core/services/table-state.service.ts index 653d1e6c1d..01baeec64e 100644 --- a/webapp/src/app/core/services/table-state.service.ts +++ b/webapp/src/app/core/services/table-state.service.ts @@ -1,28 +1,76 @@ import { Injectable } from '@angular/core'; +import { LoggerService } from 'src/app/shared/services/logger.service'; @Injectable() export class TableStateService { - state: Object = {}; + stateLabel = "allTableStates"; + + constructor( + private logger: LoggerService + ){} setState(componentKey, obj){ - this.state[componentKey] = obj; + try{ + const state = this.getStateFromLocalStorage(); + state[componentKey] = obj; + localStorage.setItem(this.stateLabel, JSON.stringify(state)); + }catch(e){ + this.logger.log(componentKey, ": Error in saving state: "+e); + } } getState(componentKey){ - return this.state?this.state[componentKey]:this.state; + let componentState:any = {}; + try{ + const state = this.getStateFromLocalStorage(); + componentState = state[componentKey]; + }catch(e){ + this.logger.log(componentKey, ": Error in getting state: "+e); + } + return componentState; + } + + getStateFromLocalStorage(){ + const state = localStorage.getItem(this.stateLabel); + if(!(state && state!="undefined")){ + localStorage.setItem("allTableStates", JSON.stringify({})); + return {}; + } + return JSON.parse(state); } persistOnly(componentKey){ let componentState = this.getState(componentKey); this.clearAll(); - this.setState(componentState, componentKey); + this.setState(componentKey, componentState); } clearState(componentKey){ - this.setState(componentKey, {}); + try{ + const componentState = this.getState(componentKey); + const keys = Object.keys(componentState); + const columnsListKey = keys.find(key => key.includes("whiteList")); + const filterListKey = keys.find(key => key.includes("filter")); + componentState[filterListKey]?.forEach(filter => { + filter.value = undefined; + filter.filterValue = undefined; + }) + const newState = {}; + newState[columnsListKey] = componentState[columnsListKey]; + newState[filterListKey] = componentState[filterListKey]; + this.setState(componentKey, newState); + }catch(e){ + this.logger.log(componentKey, ": Error in clearing state: "+e); + } } clearAll(){ - this.state = {}; + const state = this.getStateFromLocalStorage(); + if(state){ + const storedStatesKeys = Object.keys(state); + storedStatesKeys.forEach(state => { + this.clearState(state); + }) + } } } \ No newline at end of file diff --git a/webapp/src/app/pacman-features/modules/admin/policies/policies.component.html b/webapp/src/app/pacman-features/modules/admin/policies/policies.component.html index 5b14066129..8ce1dbe67c 100644 --- a/webapp/src/app/pacman-features/modules/admin/policies/policies.component.html +++ b/webapp/src/app/pacman-features/modules/admin/policies/policies.component.html @@ -32,7 +32,12 @@
{{pageTitle}}
[showSearchBar]="true" [showAddRemoveCol]="true" [showFilterBtn]="true" [onScrollDataLoader]="onScrollDataLoader" [totalRows]="totalRows" [tableScrollTop]="tableScrollTop" [tableDataLoaded]="tableDataLoaded" [columnsSortFunctionMap]="columnsSortFunctionMap" [rowClickable]="true" [doLocalFilter]="true" [doLocalSearch]="true" - [filterTypeLabels]="filterTypeLabels" [filterTagLabels]="filterTagLabels" [filteredArray]="filters"> + [filterTypeLabels]="filterTypeLabels" [filterTagLabels]="filterTagLabels" [filteredArray]="filters" + (whitelistColumnsChanged)="handleWhitelistColumnsChange($event)" + (selectedFilter)="handleFilterSelection()" + (selectedFilterType)="handleFilterTypeSelection()" + (deleteFilters)="deleteFilters($event)" + [selectedRowIndex]="selectedRowIndex">
{{dataTableDesc}}
diff --git a/webapp/src/app/pacman-features/modules/admin/policies/policies.component.ts b/webapp/src/app/pacman-features/modules/admin/policies/policies.component.ts index 9bb20b371d..d7ab040289 100644 --- a/webapp/src/app/pacman-features/modules/admin/policies/policies.component.ts +++ b/webapp/src/app/pacman-features/modules/admin/policies/policies.component.ts @@ -125,6 +125,7 @@ export class PoliciesComponent implements OnInit, OnDestroy { pageNumber: number = 0; searchTxt: String = ""; + selectedRowIndex; tableData: any = []; tableDataLoaded: boolean = false; filters: any = []; @@ -172,8 +173,9 @@ export class PoliciesComponent implements OnInit, OnDestroy { ); let state = this.tableStateService.getState("adminPolicies") || {}; if(stateUpdated){ - this.clearState(); - state = {}; + // this.clearState(); + state.data = []; + // state = {}; } if(state){ this.headerColName = state.headerColName || 'Severity'; @@ -188,6 +190,7 @@ export class PoliciesComponent implements OnInit, OnDestroy { this.whiteListColumns = state?.whiteListColumns || Object.keys(this.columnWidths); this.tableScrollTop = state?.tableScrollTop; this.filters = state?.filters || []; + this.selectedRowIndex = state?.selectedRowIndex; if(this.filters){ this.getFiltersData(this.tableData); @@ -206,12 +209,38 @@ export class PoliciesComponent implements OnInit, OnDestroy { handleHeaderColNameSelection(event){ this.headerColName = event.headerColName; this.direction = event.direction; + this.storeState(); + } + + handleWhitelistColumnsChange(event){ + this.whiteListColumns = event; + this.storeState(); + } + + deleteFilters(event?) { + try { + if (!event) { + this.filters = []; + } else if (event.clearAll) { + this.filters = []; + } + this.storeState(); + } catch (error) { } + } + + handleFilterSelection(){ + this.storeState(); + } + + handleFilterTypeSelection(){ + this.storeState(); } nextPage(e) { try { this.pageNumber++; this.showLoader = true; + this.storeState(); this.getPolicyDetails(true); } catch (error) { this.errorMessage = this.errorHandling.handleJavascriptError(error); @@ -254,7 +283,7 @@ export class PoliciesComponent implements OnInit, OnDestroy { getFiltersData(data){ this.filterTypeLabels = []; this.filterTagLabels = {}; - const filtersList = [...this.whiteListColumns, "Autofix status"]; + const filtersList = [...Object.keys(this.columnWidths), "Autofix status"]; filtersList.forEach(column => { if(column.toLowerCase()=='actions'){ return; @@ -387,17 +416,29 @@ export class PoliciesComponent implements OnInit, OnDestroy { }else{ this.tableDataLoaded = false; this.bucketNumber = 0; - // this.tableData = []; + this.tableData = []; this.getPolicyDetails(); } } - storeState(state){ + storeState(data?){ + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + bucketNumber: this.bucketNumber, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + selectedRowIndex: this.selectedRowIndex + } this.tableStateService.setState("adminPolicies", state); } clearState(){ - this.tableStateService.clearState("adminPolicies"); + // this.tableStateService.clearState("adminPolicies"); this.isStatePreserved = false; } @@ -610,19 +651,9 @@ export class PoliciesComponent implements OnInit, OnDestroy { const row = event.rowSelected; const data = event.data; const policyId = event.rowSelected["Policy ID"].text; - const state = { - totalRows: this.totalRows, - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - bucketNumber: this.bucketNumber, - searchTxt: event.searchTxt, - tableScrollTop: event.tableScrollTop, - filters: event.filters - // filterText: this.filterText - } - this.storeState(state); + this.tableScrollTop = event.tableScrollTop; + this.selectedRowIndex = event.selectedRowIndex; + this.storeState(data); try { this.workflowService.addRouterSnapshotToLevel( this.router.routerState.snapshot.root, 0, this.pageTitle diff --git a/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.html b/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.html index e8f98a1b14..1715891f47 100644 --- a/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.html +++ b/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.html @@ -50,6 +50,8 @@
{{ pageTitle }}
(selectedFilter)="changeFilterTags($event)" (selectedFilterType)="changeFilterType($event)" (whitelistColumnsChanged)="handleWhitelistColumnsChange($event)" + [doLocalSort]="false" + [selectedRowIndex]="selectedRowIndex" >
{{ dataTableDesc }}
diff --git a/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.ts b/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.ts index 8d66b34c61..8f9cbe70ca 100644 --- a/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.ts +++ b/webapp/src/app/pacman-features/modules/assets/asset-list/asset-list.component.ts @@ -72,9 +72,10 @@ export class AssetListComponent implements OnInit, OnDestroy { headerColName; direction; tableScrollTop=0; + selectedRowIndex; onScrollDataLoader: Subject = new Subject(); columnWidths = {'Asset ID': 2, 'Asset Type': 1, 'Account ID':1, 'Account Name': 1, 'Region': 1, 'Cloud Type': 1}; - columnNamesMap = {"_resourceid": "Asset ID"}; + columnNamesMap = {}; columnsSortFunctionMap = { Severity: (a, b, isAsc) => { let severeness = {"low":1, "medium":2, "high":3, "critical":4, "default": 5 * (isAsc ? 1 : -1)} @@ -163,7 +164,18 @@ export class AssetListComponent implements OnInit, OnDestroy { this.workflowService.checkIfFlowExistsCurrently(this.pageLevel); this.selectedAssetGroup = assetGroupName; // this.updateComponent(); - this.getFilters(); + this.getFilters().then(() => { + this.filterTypeLabels.forEach(label => { + if(label=="Exempted" || label=="Tagged"){ + return; + } + if(!Object.keys(this.columnWidths).includes(label)){ + this.columnWidths[label] = 0.7; + } + }) + this.columnWidths = {...this.columnWidths} + + }); }); this.subscriptionDomain = this.domainObservableService @@ -176,24 +188,23 @@ export class AssetListComponent implements OnInit, OnDestroy { ngOnInit() { const state = this.tableStateService.getState(this.pageTitle) || {}; - if(state){ - this.headerColName = state.headerColName || 'Asset ID'; - this.direction = state.direction || 'asc'; - this.bucketNumber = state.bucketNumber || 0; - this.totalRows = state.totalRows || 0; - this.searchTxt = state?.searchTxt || ''; - - this.tableData = state?.data || []; - this.tableDataLoaded = true; - this.displayedColumns = Object.keys(this.columnWidths); - this.whiteListColumns = state?.whiteListColumns || this.displayedColumns; - this.tableScrollTop = state?.tableScrollTop; - - if(this.tableData && this.tableData.length>0){ - this.isStatePreserved = true; - }else{ - this.isStatePreserved = false; - } + this.headerColName = state.headerColName ?? 'Asset ID'; + this.direction = state.direction ?? 'asc'; + this.bucketNumber = state.bucketNumber ?? 0; + this.totalRows = state.totalRows ?? 0; + this.searchTxt = state?.searchTxt ?? ''; + this.selectedRowIndex = state?.selectedRowIndex; + + this.tableData = state?.data ?? []; + this.tableDataLoaded = true; + this.displayedColumns = ['Asset ID', 'Asset Type', 'Account ID', 'Account Name', 'Region', 'Cloud Type']; + this.whiteListColumns = state?.whiteListColumns ?? this.displayedColumns; + this.tableScrollTop = state?.tableScrollTop; + + if(this.tableData && this.tableData.length>0){ + this.isStatePreserved = true; + }else{ + this.isStatePreserved = false; } this.urlToRedirect = this.router.routerState.snapshot.url; @@ -210,8 +221,15 @@ export class AssetListComponent implements OnInit, OnDestroy { handleHeaderColNameSelection(event: any) { this.headerColName = event.headerColName; this.direction = event.direction; - this.selectedOrder = this.direction; + this.bucketNumber = 0; + + this.storeState(); + this.updateComponent(); + } + + updateSortFieldName() { + this.selectedOrder = this.direction; const sortColName = this.headerColName.toLowerCase(); this.sortOrder = null; if (sortColName === "asset id") { @@ -232,20 +250,42 @@ export class AssetListComponent implements OnInit, OnDestroy { }else if(sortColName === "cloud type"){ this.fieldType = "string"; this.fieldName = "_cloudType.keyword"; + }else{ + let apiColName:any = Object.keys(this.columnNamesMap).find(col => col==this.headerColName); + if(!apiColName){ + apiColName = _.find(this.filterTypeOptions, { + optionName: this.headerColName, + })["optionValue"]; + } + this.fieldType = "string"; + this.fieldName = apiColName; } - this.updateComponent(); } handleWhitelistColumnsChange(event){ this.whiteListColumns = event; + this.storeState(); } - storeState(state){ + storeState(data?){ + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + bucketNumber: this.bucketNumber, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + filterText: this.filterText, + selectedRowIndex: this.selectedRowIndex + } this.tableStateService.setState(this.pageTitle, state); } clearState(){ - this.tableStateService.clearState(this.pageTitle); + // this.tableStateService.clearState(this.pageTitle); this.isStatePreserved = false; } @@ -288,12 +328,17 @@ export class AssetListComponent implements OnInit, OnDestroy { try { if (!event) { this.filters = []; + this.storeState(); + } else if(event.index && !this.filters[event.index].filterValue){ + this.filters.splice(event.index, 1); + this.storeState(); } else { if (event.clearAll) { this.filters = []; } else { this.filters.splice(event.index, 1); } + this.storeState(); this.getUpdatedUrl(); this.updateComponent(); } @@ -306,36 +351,65 @@ export class AssetListComponent implements OnInit, OnDestroy { */ getFilterArray() { try { - // let labelsKey = Object.keys(this.labels); - const filterObjKeys = Object.keys(this.filterText); + const filterObjKeys = Object.keys(this.filterText); const dataArray = []; for (let i = 0; i < filterObjKeys.length; i++) { let obj = {}; + const keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: filterObjKeys[i], + })["optionName"]; obj = { - name: filterObjKeys[i], + keyDisplayValue, + filterkey: filterObjKeys[i], }; dataArray.push(obj); + } + + const state = this.tableStateService.getState(this.pageTitle) ?? {}; + const filters = state?.filters; + + if(filters){ + const dataArrayFilterKeys = dataArray.map(obj => obj.keyDisplayValue); + filters.forEach(filter => { + if(!dataArrayFilterKeys.includes(filter.keyDisplayValue)){ + dataArray.push({ + filterkey: filter.filterkey, + keyDisplayValue: filter.key + }); + } + }); } + const formattedFilters = dataArray; for (let i = 0; i < formattedFilters.length; i++) { - let keyValue = _.find(this.filterTypeOptions, { - optionValue: formattedFilters[i].name, - })["optionName"]; - this.changeFilterType(keyValue).then(() => { - let filterValue = _.find(this.filterTagOptions[keyValue], { - id: this.filterText[filterObjKeys[i]], - })["name"]; - const eachObj = { - keyDisplayValue: keyValue, - filterValue: filterValue, - key: keyValue, // <-- displayKey-- Resource Type - value: this.filterText[filterObjKeys[i]], // <<-- value to be shown in the filter UI-- S2 - filterkey: filterObjKeys[i].trim(), // <<-- filter key that to be passed -- "resourceType " - compareKey: filterObjKeys[i].toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" - }; - this.filters.push(eachObj); - this.filters = [...this.filters]; + let keyDisplayValue = formattedFilters[i].keyDisplayValue; + if(!keyDisplayValue){ + keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: formattedFilters[i].filterKey, + })["optionName"]; + } + + this.changeFilterType(keyDisplayValue).then(() => { + let filterValueObj = _.find(this.filterTagOptions[keyDisplayValue], { + id: this.filterText[formattedFilters[i].filterkey], + }); + + let filterKey = dataArray[i].filterkey; + + if(!this.filters.find(filter => filter.keyDisplayValue==keyDisplayValue)){ + const eachObj = { + keyDisplayValue: keyDisplayValue, + filterValue: filterValueObj?filterValueObj["name"]:undefined, + key: keyDisplayValue, // <-- displayKey-- Resource Type + value: this.filterText[filterKey], // <<-- value to be shown in the filter UI-- S2 + filterkey: filterKey?.trim(), // <<-- filter key that to be passed -- "resourceType " + compareKey: filterKey?.toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" + }; + this.filters.push(eachObj); + this.filters = [...this.filters]; + this.storeState(); + } }) } } catch (error) { @@ -350,13 +424,14 @@ export class AssetListComponent implements OnInit, OnDestroy { */ updateComponent() { + this.updateSortFieldName(); if(this.isStatePreserved){ this.tableDataLoaded = true; this.clearState(); }else{ this.tableDataLoaded = false; this.bucketNumber = 0; - // this.tableData = []; + this.tableData = []; this.getData(); } } @@ -639,6 +714,10 @@ export class AssetListComponent implements OnInit, OnDestroy { newObj = Object.assign(newObj, { [elementnew]: row[element] }); } // change data value + const isTag = element.split(".")[0]=="tags"; + if(isTag){ + columnNamesMap[element] = element.split(".")[1]; + } newObj[elementnew] = DATA_MAPPING[typeof newObj[elementnew]=="string"?newObj[elementnew].toLowerCase():newObj[elementnew]]?DATA_MAPPING[newObj[elementnew].toLowerCase()]: newObj[elementnew]; }); newData.push(newObj); @@ -649,19 +728,9 @@ export class AssetListComponent implements OnInit, OnDestroy { goToDetails(event) { const row = event.rowSelected; - const data = event.data; - const state = { - totalRows: this.totalRows, - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - bucketNumber: this.bucketNumber, - searchTxt: this.searchTxt, - tableScrollTop: event.tableScrollTop - // filterText: this.filterText - } - this.storeState(state); + this.tableScrollTop = event.tableScrollTop; + this.selectedRowIndex = event.selectedRowIndex; + this.storeState(event.data); try { this.workflowService.addRouterSnapshotToLevel( this.router.routerState.snapshot.root, 0, this.pageTitle @@ -711,6 +780,7 @@ export class AssetListComponent implements OnInit, OnDestroy { try { this.tableScrollTop = e; this.bucketNumber++; + this.storeState(); this.getData(true); } catch (error) { this.errorMessage = this.errorHandling.handleJavascriptError(error); @@ -771,7 +841,7 @@ export class AssetListComponent implements OnInit, OnDestroy { callNewSearch(searchVal){ this.searchTxt = searchVal; // this.state.searchValue = searchVal; - this.isStatePreserved = false; + this.storeState(); this.updateComponent(); // this.getUpdatedUrl(); } @@ -791,38 +861,42 @@ export class AssetListComponent implements OnInit, OnDestroy { */ getFilters() { - try { - let filterId = 8; - if ( - this.urlID && - (this.urlID.toLowerCase() === "pull-request-trend" || - this.urlID.toLowerCase() === "pull-request-age" || - this.urlID.toLowerCase() === "branching-strategy") - ) { - filterId = 9; + return new Promise((resolve) => { + try { + let filterId = 8; + if ( + this.urlID && + (this.urlID.toLowerCase() === "pull-request-trend" || + this.urlID.toLowerCase() === "pull-request-age" || + this.urlID.toLowerCase() === "branching-strategy") + ) { + filterId = 9; + } + this.issueFilterSubscription = this.issueFilterService + .getFilters( + { filterId: filterId, domain: this.selectedDomain }, + environment.issueFilter.url, + environment.issueFilter.method + ) + .subscribe((response) => { + this.filterTypeOptions = response[0].response; + resolve(true); + this.trimStringsInArrayOfObjs(this.filterTypeOptions); + this.filterTypeLabels = _.map(this.filterTypeOptions, "optionName"); + + this.filterTypeLabels.sort(); + + this.routerParam(); + // this.deleteFilters(); + this.getFilterArray(); + this.updateComponent(); + }); + } catch (error) { + this.errorMessage = this.errorHandling.handleJavascriptError(error); + this.logger.log("error", error); + resolve(false); } - this.issueFilterSubscription = this.issueFilterService - .getFilters( - { filterId: filterId, domain: this.selectedDomain }, - environment.issueFilter.url, - environment.issueFilter.method - ) - .subscribe((response) => { - this.filterTypeOptions = response[0].response; - this.trimStringsInArrayOfObjs(this.filterTypeOptions); - this.filterTypeLabels = _.map(this.filterTypeOptions, "optionName"); - - this.filterTypeLabels.sort(); - - this.routerParam(); - // this.deleteFilters(); - this.getFilterArray(); - this.updateComponent(); - }); - } catch (error) { - this.errorMessage = this.errorHandling.handleJavascriptError(error); - this.logger.log("error", error); - } + }) } changeFilterType(value) { @@ -850,6 +924,7 @@ export class AssetListComponent implements OnInit, OnDestroy { this.filterTagLabels[value] = _.map(response[0].response, "name"); this.filterTagLabels[value].sort((a,b)=>a.localeCompare(b)); resolve(this.filterTagOptions[value]); + this.storeState(); }); } @@ -862,6 +937,9 @@ export class AssetListComponent implements OnInit, OnDestroy { changeFilterTags(event) { let value = event.filterValue; + if(!value){ + return; + } this.currentFilterType = _.find(this.filterTypeOptions, { optionName: event.filterKeyDisplayValue, }); @@ -886,6 +964,7 @@ export class AssetListComponent implements OnInit, OnDestroy { } ); } + this.storeState(); this.getUpdatedUrl(); this.utils.clickClearDropdown(); this.updateComponent(); diff --git a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.html b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.html index 5775806c0e..4f8d4ff62d 100644 --- a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.html +++ b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.html @@ -111,6 +111,11 @@ [filterTagLabels]="filterTagLabels" [filteredArray]="filters" [rowSize]="'SM'" + (whitelistColumnsChanged)="handleWhitelistColumnsChange($event)" + (selectedFilter)="handleFilterSelection()" + (selectedFilterType)="handleFilterTypeSelection()" + (deleteFilters)="deleteFilters($event)" + [selectedRowIndex]="selectedRowIndex" > diff --git a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.spec.ts b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.spec.ts index c17242c941..57b2ac9185 100644 --- a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.spec.ts +++ b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.spec.ts @@ -348,20 +348,6 @@ describe('ComplianceDashboardComponent', () => { expect(component.breakpoint2).toBe(1); }) - - - it('should get date', () => { - const date = "2022-09-15T16:27:12.574Z"; - const expectedDate = "09-15-2022"; - const returnedDate = component.calculateDate(date); - expect(returnedDate).toBe(expectedDate); - const date2 = "2022-11-01T16:27:12.574Z"; - const expectedDate2 = "11-01-2022"; - const returnedDate2 = component.calculateDate(date2); - expect(returnedDate2).toBe(expectedDate2); - }) - - it('should get filtersType and filterLabels', () => { spyOn(fakeIssueFilterService, 'getFilters').and.returnValue(of(issueFilterResponse)); component.getFilters(); diff --git a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.ts b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.ts index e3818f234f..1c5460d208 100644 --- a/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.ts +++ b/webapp/src/app/pacman-features/modules/compliance/compliance-dashboard/compliance-dashboard.component.ts @@ -138,6 +138,7 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { policyCategory: 'Category', }; columnWidths = { Policy: 3, Violations: 1, Source: 1, Severity: 1, Category: 1, Compliance: 1 }; + selectedRowIndex : number; centeredColumns = { Policy: false, Violations: true, @@ -297,6 +298,7 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { this.tableScrollTop = state?.tableScrollTop; this.totalRows = state.totalRows || 0; this.filters = state?.filters || []; + this.selectedRowIndex = state?.selectedRowIndex; if (this.filters) { this.getFiltersData(this.complianceTableData); @@ -441,16 +443,42 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { handleHeaderColNameSelection(event) { this.headerColName = event.headerColName; this.direction = event.direction; + this.storeState(); + } + + handleWhitelistColumnsChange(event){ + this.whiteListColumns = event; + this.storeState(); + } + + handleFilterTypeSelection(){ + this.storeState(); + } + + handleFilterSelection(){ + this.storeState(); } clearState() { - this.tableStateService.clearState('dashboard'); + // this.tableStateService.clearState('dashboard'); this.isStatePreserved = false; } - storeState(state) { - this.tableStateService.setState('dashboard', state); - } + storeState(data?){ + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + bucketNumber: this.bucketNumber, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + selectedRowIndex: this.selectedRowIndex + } + this.tableStateService.setState("dashboard", state); + } getDistributionBySeverity() { const distributionBySeverityUrl = environment.distributionBySeverity.url; @@ -629,20 +657,14 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { } deleteFilters(event?) { try { - if (!event) { - this.filters = []; - } else { - if (event.clearAll) { - this.filters = []; - } else { - this.filters.splice(event.index, 1); - } - this.getUpdatedUrl(); - this.updateComponent(); - } - } catch (error) {} - /* TODO: Aditya: Why are we not calling any updateCompliance function in observable to update the filters */ - } + if (!event) { + this.filters = []; + } else if (event.clearAll) { + this.filters = []; + } + this.storeState(); + } catch (error) { } + } /* * this functin passes query params to filter component to show filter */ @@ -1020,29 +1042,29 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { getFiltersData(data) { this.filterTypeLabels = []; this.filterTagLabels = {}; - this.whiteListColumns.forEach((column) => { - if (column == 'Violations') { - return; - } + const filtersList = Object.keys(this.columnWidths); + filtersList.forEach(column => { let filterTags = []; this.filterTypeLabels.push(column); - if (column == 'Severity') { - filterTags = ['low', 'medium', 'high', 'critical']; - } else if (column == 'Category') { - filterTags = ['security', 'cost', 'operations', 'tagging']; - } else if (column == 'Compliance') { - filterTags = ['0%-25%', '26%-50%', '51%-75%', '76%-100%']; - } else { - const set = new Set(); - data.forEach((row) => { - set.add(row[column].valueText); - }); - filterTags = Array.from(set); - this.sortFilters(filterTags, column); + if(column=='Severity'){ + filterTags = ["low", "medium", "high", "critical"]; + }else if(column=='Category'){ + filterTags = ["security", "cost", "operations", "tagging"]; + } + else if(column=='Compliance'){ + filterTags = ["0%-25%","26%-50%","51%-75%","76%-100%"]; + } + else{ + const set = new Set(); + data.forEach(row => { + set.add(row[column].valueText); + }); + filterTags = Array.from(set); + this.sortFilters(filterTags, column); } this.filterTagLabels[column] = filterTags; - }); - this.filterTypeLabels.sort(); + }); + this.filterTypeLabels.sort(); } sortFilters(array, column) { @@ -1162,19 +1184,9 @@ export class ComplianceDashboardComponent implements OnInit, OnDestroy { goToDetails(event) { const selectedRow = event.rowSelected; const data = event.data; - const state = { - totalRows: this.totalRows, - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - bucketNumber: this.bucketNumber, - searchTxt: event.searchTxt, - tableScrollTop: event.tableScrollTop, - filters: event.filters, - // filterText: this.filterText - }; - this.storeState(state); + this.tableScrollTop = event.tableScrollTop; + this.selectedRowIndex = event.selectedRowIndex; + this.storeState(data); try { this.workflowService.addRouterSnapshotToLevel( this.router.routerState.snapshot.root, diff --git a/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.html b/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.html index 673ca9015a..29ae13ce09 100644 --- a/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.html +++ b/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.html @@ -51,6 +51,7 @@ [tableScrollTop]="tableScrollTop" [totalRows]="totalRows" [whiteListColumns]="whiteListColumns" + [selectedRowIndex]="selectedRowIndex" (deleteFilters)="deleteFilters($event)" (downloadClicked)="handlePopClick($event)" (headerColNameSelected)="handleHeaderColNameSelection($event)" diff --git a/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.ts b/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.ts index 8517f2717f..2dd99b34a7 100644 --- a/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.ts +++ b/webapp/src/app/pacman-features/modules/compliance/issue-listing/issue-listing.component.ts @@ -48,6 +48,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { adminAccess = false; // check for admin access showDownloadBtn = true; showFilterBtn = true; + selectedRowIndex; private assetGroupSubscription: Subscription; private domainSubscription: Subscription; private routeSubscription: Subscription; @@ -65,6 +66,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { direction; tableScrollTop=0; onScrollDataLoader: Subject = new Subject(); + columnWidths = {'Policy': 2, 'Violation ID': 1, 'Asset ID': 1, 'Asset Type': 0.5, 'Account Name': 0.7, 'Region': 0.7, 'Severity': 0.5, 'Category':0.5, 'Age': 0.5, 'Status': 0.5}; centeredColumns = { Policy: false, 'Violation ID': false, @@ -72,8 +74,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { Severity: true, Category: true, }; - columnWidths = {'Policy': 2, 'Violation ID': 1, 'Resource ID': 1, 'Severity': 0.5, 'Category':0.5}; - columnNamesMap = {"PolicyName": "Policy","IssueId":"Violation ID"}; + columnNamesMap = {"PolicyName": "Policy","IssueId":"Violation ID", "Asset Type":"resourcetype", "AccountName": "Account Name"}; fieldName: string = "severity.keyword"; fieldType: string = "number"; selectedOrder: string = "desc"; @@ -116,7 +117,6 @@ export class IssueListingComponent implements OnInit, OnDestroy { displayedColumns; tableData = []; isStatePreserved = false; - selectedRowIndex: number; constructor( private assetGroupObservableService: AssetGroupObservableService, @@ -141,11 +141,21 @@ export class IssueListingComponent implements OnInit, OnDestroy { .getAssetGroup() .subscribe((assetGroupName) => { this.tableScrollTop = 0; - this.searchTxt = ""; this.backButtonRequired = this.workflowService.checkIfFlowExistsCurrently(this.pageLevel); this.selectedAssetGroup = assetGroupName; - this.getFilters(); + this.getFilters().then(() => { + this.filterTypeLabels.forEach(label => { + if(label=="Exempted" || label=="Tagged"){ + return; + } + if(!Object.keys(this.columnWidths).includes(label)){ + this.columnWidths[label] = 0.7; + } + }) + this.columnWidths = {...this.columnWidths}; + + }); }); this.domainSubscription = this.domainObservableService @@ -155,30 +165,47 @@ export class IssueListingComponent implements OnInit, OnDestroy { }); } - ngOnInit() { - const state = this.tableStateService.getState("issueListing") || {}; + getDataFromPreservedState(){ + const state = this.tableStateService.getState(this.pageTitle) ?? {}; if(state){ - this.headerColName = state.headerColName || 'Severity'; - this.direction = state.direction || 'desc'; - this.bucketNumber = state.bucketNumber || 0; - this.totalRows = state.totalRows || 0; - this.searchTxt = state?.searchTxt || ''; - + this.headerColName = state.headerColName ?? 'Severity'; + this.direction = state.direction ?? 'desc'; + this.bucketNumber = state.bucketNumber ?? 0; + this.totalRows = state.totalRows ?? 0; + this.searchTxt = state?.searchTxt ?? ''; + this.tableDataLoaded = true; - this.tableData = state?.data || []; - this.displayedColumns = Object.keys(this.columnWidths); - this.whiteListColumns = state?.whiteListColumns || this.displayedColumns; + this.tableData = state?.data ?? []; + this.displayedColumns = ['Policy', 'Asset ID', 'Severity', 'Category', 'Age']; + this.whiteListColumns = state?.whiteListColumns ?? this.displayedColumns; this.tableScrollTop = state?.tableScrollTop; + this.selectedRowIndex = state?.selectedRowIndex; - if(this.tableData && this.tableData.length>0){ + if(this.tableData && this.tableData.length>0){ this.isStatePreserved = true; this.selectedRowIndex = state.selectedRowIndex; }else{ this.isStatePreserved = false; } + + // if(filter){ + // console.log("chose to navigate: ", filter); + + // this.router.navigate(["./"], { + // relativeTo: this.activatedRoute, + // queryParams: {filter: filter}, + // queryParamsHandling: "merge" + // }).catch(e => { + // console.log("error navigating: ", e); + // }) + // } } + } + ngOnInit() { + + this.getDataFromPreservedState(); const breadcrumbInfo = this.workflowService.getDetailsFromStorage()["level0"]; if(breadcrumbInfo){ @@ -196,14 +223,9 @@ export class IssueListingComponent implements OnInit, OnDestroy { this.getData(); } - handleAddFilterClick(e){} - - handleHeaderColNameSelection(event: any) { - this.headerColName = event.headerColName; - const sortColName = this.headerColName?.toLowerCase(); - this.direction = event.direction; + updateSortFieldName(){ + const sortColName = this.headerColName.toLowerCase(); this.selectedOrder = this.direction; - this.bucketNumber = 0; this.sortOrder = null; if (sortColName === "severity") { this.fieldName = "severity.keyword"; @@ -222,20 +244,58 @@ export class IssueListingComponent implements OnInit, OnDestroy { } else if (sortColName === "policy") { this.fieldType = "number"; this.fieldName = "policyId.keyword"; + }else if (sortColName === "asset type") { + this.fieldType = "string"; + this.fieldName = "resourcetType.keyword"; + }else if (sortColName === "age") { + this.fieldType = "number"; + this.fieldName = "createdDate"; + }else{ + let apiColName:any = Object.keys(this.columnNamesMap).find(col => col==this.headerColName); + if(!apiColName){ + apiColName = _.find(this.filterTypeOptions, { + optionName: this.headerColName, + })["optionValue"]; + } + this.fieldType = "string"; + this.fieldName = apiColName; } + } + + handleHeaderColNameSelection(event: any) { + this.headerColName = event.headerColName; + this.direction = event.direction; + + this.bucketNumber = 0; + + this.storeState(); this.updateComponent(); } handleWhitelistColumnsChange(event){ this.whiteListColumns = event; + this.storeState(); } - storeState(state){ - this.tableStateService.setState("issueListing", state); + storeState(data?){ + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + bucketNumber: this.bucketNumber, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + selectedRowIndex: this.selectedRowIndex + // filterText: this.filterText + } + this.tableStateService.setState(this.pageTitle, state); } clearState(){ - this.tableStateService.clearState("issueListing"); + // this.tableStateService.clearState(this.pageTitle); this.isStatePreserved = false; } @@ -303,12 +363,18 @@ export class IssueListingComponent implements OnInit, OnDestroy { try { if (!event) { this.filters = []; - } else { + this.storeState(); + }else if(event.index && !this.filters[event.index].filterValue){ + this.filters.splice(event.index, 1); + this.storeState(); + } + else { if (event.clearAll) { this.filters = []; } else { this.filters.splice(event.index, 1); } + this.storeState(); this.getUpdatedUrl(); this.updateComponent(); } @@ -320,36 +386,65 @@ export class IssueListingComponent implements OnInit, OnDestroy { */ getFilterArray() { try { - // let labelsKey = Object.keys(this.labels); - const filterObjKeys = Object.keys(this.filterText); + const filterObjKeys = Object.keys(this.filterText); const dataArray = []; for (let i = 0; i < filterObjKeys.length; i++) { let obj = {}; + const keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: filterObjKeys[i], + })["optionName"]; obj = { - name: filterObjKeys[i], + keyDisplayValue, + filterkey: filterObjKeys[i], }; dataArray.push(obj); + } + + const state = this.tableStateService.getState(this.pageTitle) ?? {}; + const filters = state?.filters; + + if(filters){ + const dataArrayFilterKeys = dataArray.map(obj => obj.keyDisplayValue); + filters.forEach(filter => { + if(!dataArrayFilterKeys.includes(filter.keyDisplayValue)){ + dataArray.push({ + filterkey: filter.filterkey, + keyDisplayValue: filter.key + }); + } + }); } + const formattedFilters = dataArray; for (let i = 0; i < formattedFilters.length; i++) { - let keyValue = _.find(this.filterTypeOptions, { - optionValue: formattedFilters[i].name, - })["optionName"]; - this.changeFilterType(keyValue).then(() => { - let filterValue = _.find(this.filterTagOptions[keyValue], { - id: this.filterText[filterObjKeys[i]], - })["name"]; - const eachObj = { - keyDisplayValue: keyValue, - filterValue: filterValue, - key: keyValue, // <-- displayKey-- Resource Type - value: this.filterText[filterObjKeys[i]], // <<-- value to be shown in the filter UI-- S2 - filterkey: filterObjKeys[i].trim(), // <<-- filter key that to be passed -- "resourceType " - compareKey: filterObjKeys[i].toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" - }; - this.filters.push(eachObj); - this.filters = [...this.filters]; + let keyDisplayValue = formattedFilters[i].keyDisplayValue; + if(!keyDisplayValue){ + keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: formattedFilters[i].filterKey, + })["optionName"]; + } + + this.changeFilterType(keyDisplayValue).then(() => { + let filterValueObj = _.find(this.filterTagOptions[keyDisplayValue], { + id: this.filterText[formattedFilters[i].filterkey], + }); + + let filterKey = dataArray[i].filterkey; + + if(!this.filters.find(filter => filter.keyDisplayValue==keyDisplayValue)){ + const eachObj = { + keyDisplayValue: keyDisplayValue, + filterValue: filterValueObj?filterValueObj["name"]:undefined, + key: keyDisplayValue, // <-- displayKey-- Resource Type + value: this.filterText[filterKey], // <<-- value to be shown in the filter UI-- S2 + filterkey: filterKey?.trim(), // <<-- filter key that to be passed -- "resourceType " + compareKey: filterKey?.toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" + }; + this.filters.push(eachObj); + this.filters = [...this.filters]; + this.storeState(); + } }) } } catch (error) { @@ -364,7 +459,8 @@ export class IssueListingComponent implements OnInit, OnDestroy { */ getFilters() { - this.filterErrorMessage = ''; + return new Promise((resolve) => { + this.filterErrorMessage = ''; let isApiError = true; try { this.issueFilterSubscription = this.issueFilterService @@ -375,6 +471,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { ) .subscribe((response) => { this.filterTypeLabels = _.map(response[0].response, "optionName"); + resolve(true); this.filterTypeOptions = response[0].response; if(this.filterTypeLabels.length==0){ @@ -390,8 +487,10 @@ export class IssueListingComponent implements OnInit, OnDestroy { this.filterErrorMessage = 'apiResponseError'; this.errorMessage = this.errorHandling.handleJavascriptError(error); this.logger.log("error", error); + resolve(false); } if(isApiError) this.filterErrorMessage = 'apiResponseError'; + }); } changeFilterType(value) { @@ -422,6 +521,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { this.filterTagLabels[value].sort((a,b)=>a.localeCompare(b)); if(this.filterTagLabels[value].length==0) this.filterErrorMessage = 'noDataAvailable'; resolve(this.filterTagOptions[value]); + this.storeState(); }); } } catch (error) { @@ -434,6 +534,9 @@ export class IssueListingComponent implements OnInit, OnDestroy { changeFilterTags(event) { let value = event.filterValue; + if(!value){ + return; + } this.currentFilterType = _.find(this.filterTypeOptions, { optionName: event.filterKeyDisplayValue, }); @@ -459,6 +562,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { } ); } + this.storeState(); this.getUpdatedUrl(); this.utils.clickClearDropdown(); this.updateComponent(); @@ -469,13 +573,14 @@ export class IssueListingComponent implements OnInit, OnDestroy { } updateComponent() { + this.updateSortFieldName(); if(this.isStatePreserved){ this.tableDataLoaded = true; this.clearState(); }else{ this.tableDataLoaded = false; this.bucketNumber = 0; - // this.tableData = []; + this.tableData = []; this.getData(); } } @@ -593,7 +698,6 @@ export class IssueListingComponent implements OnInit, OnDestroy { }else{ this.tableData = processData; } - } } catch (e) { this.tableErrorMessage = 'apiResponseError'; @@ -640,27 +744,18 @@ export class IssueListingComponent implements OnInit, OnDestroy { // change data value newObj[elementnew] = DATA_MAPPING[typeof newObj[elementnew]=="string"?newObj[elementnew].toLowerCase():newObj[elementnew]]?DATA_MAPPING[newObj[elementnew].toLowerCase()]: newObj[elementnew]; }); + newData.push(newObj); }); return newData; } goToDetails(event) { - // store in this function const row = event.rowSelected; - const data = event.data; - const state = { - totalRows: this.totalRows, - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - bucketNumber: this.bucketNumber, - searchTxt: this.searchTxt, - tableScrollTop: event.tableScrollTop, - selectedRowIndex: event.selectedRowIndex, - } - this.storeState(state); + this.tableScrollTop = event.tableScrollTop; + this.selectedRowIndex = event.selectedRowIndex; + this.storeState(event.data); + try { this.workflowService.addRouterSnapshotToLevel( this.router.routerState.snapshot.root, 0, this.breadcrumbPresent @@ -752,6 +847,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { try { this.tableScrollTop = e; this.bucketNumber++; + this.storeState(); this.getData(true); } catch (error) { this.errorMessage = this.errorHandling.handleJavascriptError(error); @@ -761,7 +857,8 @@ export class IssueListingComponent implements OnInit, OnDestroy { callNewSearch(searchVal){ this.searchTxt = searchVal; - // this.state.searchValue = searchVal; + // this.searchValue = searchVal; + this.storeState(); this.isStatePreserved = false; this.updateComponent(); // this.getUpdatedUrl(); @@ -769,6 +866,7 @@ export class IssueListingComponent implements OnInit, OnDestroy { ngOnDestroy() { + // this.storeState(); try { if (this.assetGroupSubscription) { this.assetGroupSubscription.unsubscribe(); diff --git a/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.html b/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.html index d180f3d0c8..fe019e9a3d 100644 --- a/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.html +++ b/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.html @@ -64,6 +64,12 @@ (searchCalledEventEmitter)="callNewSearch($event)" (searchInColumnsChanged)="handleSearchInColumnsChange($event)" (headerColNameSelected)="handleHeaderColNameSelection($event)" + gapBetweenFilterAndTable="0px" + (whitelistColumnsChanged)="handleWhitelistColumnsChange($event)" + (selectedFilter)="handleFilterSelection()" + (selectedFilterType)="handleFilterTypeSelection()" + (deleteFilters)="deleteFilters($event)" + [selectedRowIndex]="selectedRowIndex" > diff --git a/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.ts b/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.ts index a8607d1cd9..2a4eda5176 100644 --- a/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.ts +++ b/webapp/src/app/pacman-features/modules/compliance/policy-knowledgebase/policy-knowledgebase.component.ts @@ -127,6 +127,7 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe } state: any = {}; whiteListColumns; + selectedRowIndex; displayedColumns; tableScrollTop = 0; tableData = []; @@ -174,11 +175,10 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe this.tableScrollTop = state?.tableScrollTop; this.filters = state?.filters || []; this.totalRows = this.tableData.length; + this.selectedRowIndex = state?.selectedRowIndex; - if(this.filters){ - this.getFiltersData(this.tableData); - } if(this.tableData && this.tableData.length>0){ + this.getFiltersData(this.tableData); this.isStatePreserved = true; }else{ this.isStatePreserved = false; @@ -203,10 +203,12 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe handleHeaderColNameSelection(event){ this.headerColName = event.headerColName; this.direction = event.direction; + this.storeState(); } handleWhitelistColumnsChange(event){ this.whiteListColumns = event; + this.storeState(); } handleSearchInColumnsChange(event){ @@ -252,11 +254,22 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe } clearState(){ - this.tableStateService.clearState("policyKnowledgebase"); + // this.tableStateService.clearState("policyKnowledgebase"); this.isStatePreserved = false; } - storeState(state){ + storeState(data?){ + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + selectedRowIndex: this.selectedRowIndex + } this.tableStateService.setState("policyKnowledgebase", state); } @@ -281,6 +294,7 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe }else{ this.searchTxt = searchVal; } + this.storeState(); // this.getUpdatedUrl(); } @@ -425,7 +439,7 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe getFiltersData(data){ this.filterTypeLabels = []; this.filterTagLabels = {}; - const filtersList = [...this.whiteListColumns, "Autofix status"]; + const filtersList = [...Object.keys(this.columnWidths), "Autofix status"]; filtersList.forEach(column => { let filterTags = []; this.filterTypeLabels.push(column); @@ -500,17 +514,9 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe // store in this function const tileData = event.rowSelected; const data = event.data; - const state = { - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - searchTxt: event.searchTxt, - tableScrollTop: event.tableScrollTop, - filters: event.filters - // filterText: this.filterText - } - this.storeState(state); + this.selectedRowIndex = event.selectedRowIndex; + this.tableScrollTop = event.tableScrollTop; + this.storeState(data); let autofixEnabled = false; if ( tileData.autoFixEnabled) { autofixEnabled = true; @@ -530,19 +536,39 @@ export class PolicyKnowledgebaseComponent implements OnInit, AfterViewInit, OnDe } } - applyFilterByCategory(policyCategory: PolicyCategory) { - const key = 'Category'; - const newFilters = this.filters.filter((f) => f.key !== key); - if (policyCategory !== PolicyCategory.ALL_POLICIES) { - newFilters.push({ - key, - keyDisplayValue: key, - filterValue: policyCategory, - value: policyCategory, - }); - } - this.filters = newFilters; - } + deleteFilters(event?) { + try { + if (!event) { + this.filters = []; + } else if (event.clearAll) { + this.filters = []; + } + this.storeState(); + } catch (error) { } + } + + handleFilterSelection(){ + this.storeState(); + } + + handleFilterTypeSelection(){ + this.storeState(); + } + + applyFilterByCategory(policyCategory: PolicyCategory) { + const key = 'Category'; + const newFilters = this.filters.filter((f) => f.key !== key); + if (policyCategory !== PolicyCategory.ALL_POLICIES) { + newFilters.push({ + key, + keyDisplayValue: key, + filterValue: policyCategory, + value: policyCategory, + }); + } + this.filters = newFilters; + this.storeState(); + } ngOnDestroy() { try { diff --git a/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.html b/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.html index cf5e9de4c5..3ece89bbb7 100644 --- a/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.html +++ b/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.html @@ -41,7 +41,9 @@ [totalRows]="totalRows" [whiteListColumns]="whiteListColumns" (headerColNameSelected)="handleHeaderColNameSelection($event)" - style="height: 100%; width: 100%;"> + style="height: 100%; width: 100%;" + (whitelistColumnsChanged)="handleWhitelistColumnsChange($event)" + [selectedRowIndex]="selectedRowIndex"> diff --git a/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.ts b/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.ts index 7256e9396f..cf0e4209cc 100644 --- a/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.ts +++ b/webapp/src/app/pacman-features/modules/notifications/cloud-notifications/cloud-notifications.component.ts @@ -86,6 +86,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { tableData: any = []; displayedColumns: string[] = []; whiteListColumns: any = []; + selectedRowIndex; tableScrollTop: any; isTableStatePreserved = false; @@ -143,6 +144,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { this.bucketNumber = state.bucketNumber || 0; this.totalRows = state.totalRows || 0; this.searchTxt = state?.searchTxt || ''; + this.selectedRowIndex = state?.selectedRowIndex; this.tableDataLoaded = true; @@ -223,12 +225,17 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { try { if (!event) { this.filters = []; - } else { + this.storeState(); + } else if(event.index && !this.filters[event.index].filterValue){ + this.filters.splice(event.index, 1); + this.storeState(); + }else { if (event.clearAll) { this.filters = []; } else { this.filters.splice(event.index, 1); } + this.storeState(); this.getUpdatedUrl(); this.updateComponent(); } @@ -244,43 +251,71 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { */ getFilterArray() { try { - const filterObjKeys = Object.keys(this.filterText); - const dataArray = []; - for (let i = 0; i < filterObjKeys.length; i++) { - let obj = {}; - obj = { - name: filterObjKeys[i], - }; - dataArray.push(obj); - } - - const formattedFilters = dataArray; - for (let i = 0; i < formattedFilters.length; i++) { - const keyValue = _.find(this.filterTypeOptions, { - optionValue: formattedFilters[i].name, - })['optionName']; - - this.changeFilterType(keyValue).then(() => { - const filterValue = _.find(this.filterTagOptions[keyValue], { - id: this.filterText[filterObjKeys[i]], - })['name']; - const eachObj = { - keyDisplayValue: keyValue, - filterValue: filterValue, - key: keyValue, // <-- displayKey-- Resource Type - value: this.filterText[filterObjKeys[i]], // <<-- value to be shown in the filter UI-- S2 - filterkey: filterObjKeys[i].trim(), // <<-- filter key that to be passed -- "resourceType " - compareKey: filterObjKeys[i].toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" - }; - this.filters.push(eachObj); - this.filters = [...this.filters]; + const filterObjKeys = Object.keys(this.filterText); + const dataArray = []; + for (let i = 0; i < filterObjKeys.length; i++) { + let obj = {}; + const keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: filterObjKeys[i], + })["optionName"]; + obj = { + keyDisplayValue, + filterkey: filterObjKeys[i], + }; + dataArray.push(obj); + } + + const state = this.tableStateService.getState(this.pageTitle) ?? {}; + const filters = state?.filters; + + if(filters){ + const dataArrayFilterKeys = dataArray.map(obj => obj.keyDisplayValue); + filters.forEach(filter => { + if(!dataArrayFilterKeys.includes(filter.keyDisplayValue)){ + dataArray.push({ + filterkey: filter.filterkey, + keyDisplayValue: filter.key }); + } + }); + } + + const formattedFilters = dataArray; + for (let i = 0; i < formattedFilters.length; i++) { + + let keyDisplayValue = formattedFilters[i].keyDisplayValue; + if(!keyDisplayValue){ + keyDisplayValue = _.find(this.filterTypeOptions, { + optionValue: formattedFilters[i].filterKey, + })["optionName"]; } + + this.changeFilterType(keyDisplayValue).then(() => { + let filterValueObj = _.find(this.filterTagOptions[keyDisplayValue], { + id: this.filterText[formattedFilters[i].filterkey], + }); + + let filterKey = dataArray[i].filterkey; + + if(!this.filters.find(filter => filter.keyDisplayValue==keyDisplayValue)){ + const eachObj = { + keyDisplayValue: keyDisplayValue, + filterValue: filterValueObj?filterValueObj["name"]:undefined, + key: keyDisplayValue, // <-- displayKey-- Resource Type + value: this.filterText[filterKey], // <<-- value to be shown in the filter UI-- S2 + filterkey: filterKey?.trim(), // <<-- filter key that to be passed -- "resourceType " + compareKey: filterKey?.toLowerCase().trim(), // <<-- key to compare whether a key is already present -- "resourcetype" + }; + this.filters.push(eachObj); + this.filters = [...this.filters]; + this.storeState(); + } + }) + } } catch (error) { - this.errorMessage = this.errorHandler.handleJavascriptError(error); - this.logger.log('error', error); + this.logger.log("error", error); } - } + } /** * This function get calls the keyword service before initializing @@ -325,14 +360,20 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { if (!this.filterTagOptions[value] || !this.filterTagLabels[value]) { this.filterSubscription = this.filterService - .getFilters(queryParams, environment.base + urlObj.url, 'GET') - .subscribe((response) => { - this.filterTagOptions[value] = response[0].response; - this.filterTagLabels[value] = _.map(response[0].response, 'name'); - this.filterTagLabels[value].sort((a, b) => a.localeCompare(b)); - - resolve(this.filterTagOptions[value]); - }); + .getFilters( + queryParams, + environment.base + + urlObj.url, + "GET" + ) + .subscribe((response) => { + this.filterTagOptions[value] = response[0].response; + this.filterTagLabels[value] = _.map(response[0].response, "name"); + this.filterTagLabels[value].sort((a,b)=>a.localeCompare(b)); + + resolve(this.filterTagOptions[value]); + this.storeState(); + }); } } catch (error) { this.errorMessage = this.errorHandler.handleJavascriptError(error); @@ -369,6 +410,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { }, ); } + this.storeState(); this.getUpdatedUrl(); this.updateComponent(); } catch (error) { @@ -382,6 +424,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { this.tableDataLoaded = true; this.clearState(); } else { + this.tableData = []; this.tableDataLoaded = false; this.bucketNumber = 0; this.getData(); @@ -391,14 +434,33 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { handleHeaderColNameSelection(event){ this.headerColName = event.headerColName; this.direction = event.direction; + this.storeState(); + } + + handleWhitelistColumnsChange(event){ + this.whiteListColumns = event; + this.storeState(); } - storeState(state) { + storeState(data?) { + const state = { + totalRows: this.totalRows, + data: data, + headerColName: this.headerColName, + direction: this.direction, + whiteListColumns: this.whiteListColumns, + bucketNumber: this.bucketNumber, + searchTxt: this.searchTxt, + tableScrollTop: this.tableScrollTop, + filters: this.filters, + filterText: this.filterText, + selectedRowIndex: this.selectedRowIndex + } this.tableStateService.setState(this.pageTitle, state); } clearState() { - this.tableStateService.clearState(this.pageTitle); + // this.tableStateService.clearState(this.pageTitle); this.isTableStatePreserved = false; } @@ -537,18 +599,10 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { goToDetails(event) { const rowSelected = event.rowSelected; const data = event.data; - const state = { - totalRows: this.totalRows, - data: data, - headerColName: this.headerColName, - direction: this.direction, - whiteListColumns: this.whiteListColumns, - bucketNumber: this.bucketNumber, - searchTxt: this.searchTxt, - tableScrollTop: event.tableScrollTop, - }; + this.selectedRowIndex = event.selectedRowIndex; + this.tableScrollTop = event.tableScrollTop; - this.storeState(state); + this.storeState(data); try { const eventId = encodeURIComponent(rowSelected['eventId'].valueText); this.workflowService.addRouterSnapshotToLevel( @@ -576,6 +630,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { try { this.tableScrollTop = e; this.bucketNumber++; + this.storeState(); this.getData(true); } catch (error) { this.logger.log('error', error); @@ -619,6 +674,7 @@ export class CloudNotificationsComponent implements OnInit, OnDestroy { callNewSearch(searchVal) { this.searchTxt = searchVal; this.isTableStatePreserved = false; + this.storeState(); this.updateComponent(); } diff --git a/webapp/src/app/pacman-features/modules/omnisearch/omni-search-details/omni-search-details.component.ts b/webapp/src/app/pacman-features/modules/omnisearch/omni-search-details/omni-search-details.component.ts index de643a012c..509cf1b26f 100644 --- a/webapp/src/app/pacman-features/modules/omnisearch/omni-search-details/omni-search-details.component.ts +++ b/webapp/src/app/pacman-features/modules/omnisearch/omni-search-details/omni-search-details.component.ts @@ -576,6 +576,7 @@ export class OmniSearchDetailsComponent implements OnInit, OnDestroy { this.filterDataIsRequested = false; if (!this.utils.isObjectEmpty(data)) { this.filterPresent = true; + if(data?.groupBy?.values) data.groupBy.values.splice(2, 1); this.filterData = data; /** * save the Filter Obj to seesion storage to load first next time diff --git a/webapp/src/app/post-login-app/common/contextual-menu/contextual-menu.component.ts b/webapp/src/app/post-login-app/common/contextual-menu/contextual-menu.component.ts index 2f8d737be7..d105cc50c7 100644 --- a/webapp/src/app/post-login-app/common/contextual-menu/contextual-menu.component.ts +++ b/webapp/src/app/post-login-app/common/contextual-menu/contextual-menu.component.ts @@ -75,7 +75,7 @@ export class ContextualMenuComponent implements OnInit, AfterViewInit, OnChanges this.assetTypeMapService.fetchAssetTypes(); this.router.events.subscribe((val) => { if (val instanceof NavigationEnd) { - this.currentNode = this.getCurrentParentNodeFromRoute(); + // this.currentNode = this.getCurrentParentNodeFromRoute(); this.selectCurrentNode(); } }); @@ -111,7 +111,7 @@ export class ContextualMenuComponent implements OnInit, AfterViewInit, OnChanges this.showPacLoader.pop(); } }); - this.currentNode = this.getCurrentParentNodeFromRoute(); + // this.currentNode = this.getCurrentParentNodeFromRoute(); } ngAfterViewInit() { @@ -156,8 +156,22 @@ export class ContextualMenuComponent implements OnInit, AfterViewInit, OnChanges return parent; } } + return ['', '']; } + // selectNode(node: TreeNode, event: Event) { + // this.workflowService.clearAllLevels(); + // node.toggleExpanded(); + // this.currentNodeId = node.id; + // this.currentParentId = node.parent.id; + // if (node.hasChildren) { + // this.currentParentId = node.id; + // }else{ + // this.tableStateService.clearAll(); + // } + // node.mouseAction('click', event); + // } + getProvider() { /* Store the recently viewed asset list in stringify format */ try { diff --git a/webapp/src/app/shared/dropdown/dropdown.component.css b/webapp/src/app/shared/dropdown/dropdown.component.css index e4bbb35d28..ca7df937e4 100644 --- a/webapp/src/app/shared/dropdown/dropdown.component.css +++ b/webapp/src/app/shared/dropdown/dropdown.component.css @@ -13,9 +13,9 @@ align-items: center; } -::ng-deep .dropdown-wrapper .mat-form-field.mat-focused.mat-primary{ +/* ::ng-deep .dropdown-wrapper .mat-form-field.mat-focused.mat-primary{ border: 1px solid var(--primary-400); -} +} */ ::ng-deep .mat-option-text{ font: var(--text-body-2) !important; @@ -42,6 +42,10 @@ width: 14px !important; display: none !important; } +::ng-deep .mat-option.mat-option-disabled{ + opacity: 40%; +} + .dropdown-wrapper ::ng-deep .mat-select{ color: var(--text-high-emphasis); font: var(--text-body-2); @@ -67,3 +71,75 @@ img{ gap: 10px; } +::ng-deep .mat-checkbox-layout{ + padding: 8px 16px; + align-items: center !important; + width: 100%; +} + +::ng-deep .mat-checkbox-inner-container{ + margin: 0 !important; + margin-right: 8px !important; +} + +::ng-deep .mat-checkbox-label{ + color: var(--text-low-emphasis); + font: var(--text-body-2); +} + +::ng-deep .mat-checkbox{ + width: 100%; +} + +::ng-deep .mat-checkbox:hover{ + background-color: rgba(0,0,0,.04); +} + +::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background{ + background-color: var(--primary-400); +} + +.apply-btn{ + width: 100%; + padding: 4px 8px; + height: 44px; +} + +.button ::ng-deep .mat-select-value{ + display: none; +} + +.button ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-infix{ + width: 20px; +} + +.button{ + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border-200); + padding: 0 16px; + font: var(--text-caption); + color: var(--text-medium-emphasis); +} + +.button ::ng-deep .mat-select{ + padding: 0; +} + +.button mat-form-field{ + width: 100%; + border: none !important; +} + +.dropdown-title{ + color: #00000061; + opacity: 40%; + font: var(--text-body-2); + line-height: 3em; + height: 3em; + user-select: none; + overflow: hidden; + text-overflow: ellipsis; + padding: 0 16px; +} \ No newline at end of file diff --git a/webapp/src/app/shared/dropdown/dropdown.component.html b/webapp/src/app/shared/dropdown/dropdown.component.html index 5fe5891d9e..c7162bfc07 100644 --- a/webapp/src/app/shared/dropdown/dropdown.component.html +++ b/webapp/src/app/shared/dropdown/dropdown.component.html @@ -1,39 +1,52 @@ -