This is an automated email from the ASF dual-hosted git repository.

hshpak pushed a commit to branch 
feat/DATALAB-2881/filter-function-to-Images-page
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git

commit d01c5f95744b8bd375d3a54eb465746512af08f1
Author: Hennadii_Shpak <[email protected]>
AuthorDate: Thu Aug 4 00:10:36 2022 +0300

    DATALAB-2881 is finished, implemented reset filter by column name
---
 .../src/app/resources/images/images.component.html | 72 ++++++++++++++++++----
 .../src/app/resources/images/images.component.scss |  9 +++
 .../src/app/resources/images/images.component.ts   | 25 ++++++--
 .../src/app/resources/images/images.config.ts      |  5 +-
 .../src/app/resources/images/images.model.ts       |  4 ++
 .../src/app/resources/images/images.service.ts     | 67 ++++++++++++++++----
 6 files changed, 153 insertions(+), 29 deletions(-)

diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
index 15f1c2533..b782f49a3 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
@@ -94,10 +94,10 @@
         </div>
       </span>
 
-      <button mat-raised-button [disabled]="!(dataSource | async)?.length && 
!isFiltered" class="butt filter__btn" (click)="onFilterClick()">
-        <i class="material-icons" [ngClass]="{'filtered-icon': 
isFiltered}">filter_list</i>
+      <button mat-raised-button [disabled]="!(dataSource | async)?.length && 
!($isFiltered | async)" class="butt filter__btn" (click)="onFilterClick()">
+        <i class="material-icons" [ngClass]="{'filtered-icon': $isFiltered | 
async}">filter_list</i>
         <span class="filter__btn--name">Filter</span>
-        <button *ngIf="isFiltered" type="button" 
(click)="onResetFilterClick($event)" class="close__btn">&times;</button>
+        <button *ngIf="$isFiltered | async" type="button" 
(click)="onResetFilterClick($event)" class="close__btn">&times;</button>
       </button>
       <div *ngIf="isFilterOpened | async" class="filer__wrapper">
         <datalab-page-filter
@@ -166,43 +166,93 @@
 
       <ng-container matColumnDef="imageName">
         <th mat-header-cell *matHeaderCellDef class="name-col header-cell">
-          <span class="label image-label">Image name</span>
+          <span class="label image-label">
+            {{tableHeaderCellTitles.imageName}}
+            <button
+              *ngIf="($filteredColumnState | async)?.imageName"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(dropdownFieldNames.imageName)"
+            >
+              &times;
+            </button>
+          </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="imageStatus">
         <th mat-header-cell *matHeaderCellDef class="status-col header-cell">
-          <span class="label image-label"> Status </span>
+          <span class="label image-label">
+            {{tableHeaderCellTitles.imageStatus}}
+            <button
+              *ngIf="($filteredColumnState | async)?.statuses"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(dropdownFieldNames.statuses)"
+            >
+              &times;
+            </button>
+          </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="creationDate">
         <th mat-header-cell *matHeaderCellDef class="shape-col header-cell">
-          <span class="label image-label"> Creation date </span>
+          <span class="label image-label"> 
{{tableHeaderCellTitles.creationDate}} </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="endpoint">
         <th mat-header-cell *matHeaderCellDef class="tag-col header-cell">
-          <span class="label image-label"> Endpoint </span>
+          <span class="label image-label">
+            {{tableHeaderCellTitles.endpoint}}
+            <button
+              *ngIf="($filteredColumnState | async)?.endpoints"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(dropdownFieldNames.endpoints)"
+            >
+              &times;
+            </button>
+          </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="templateName">
         <th mat-header-cell *matHeaderCellDef class="resources-col 
label-header">
-          <span class="label image-label"> Template name </span>
+          <span class="label image-label">
+            {{tableHeaderCellTitles.templateName}}
+            <button
+              *ngIf="($filteredColumnState | async)?.templateNames"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(dropdownFieldNames.templateNames)"
+            >
+              &times;
+            </button>
+          </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="sharedStatus">
         <th mat-header-cell *matHeaderCellDef class="cost-col label-header">
-          <span class="label image-label"> Sharing </span>
+          <span class="label image-label">
+            {{tableHeaderCellTitles.sharedStatus}}
+            <button
+              *ngIf="($filteredColumnState | async)?.sharingStatuses"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(dropdownFieldNames.sharingStatuses)"
+            >
+              &times;
+            </button>
+          </span>
         </th>
       </ng-container>
 
       <ng-container matColumnDef="actions">
         <th mat-header-cell *matHeaderCellDef class="settings label-header">
-          <span class="label image-label"> Actions </span>
+          <span class="label image-label"> {{tableHeaderCellTitles.actions}} 
</span>
         </th>
       </ng-container>
 
@@ -285,7 +335,7 @@
 
       <ng-container matColumnDef="placeholder">
         <td mat-footer-cell *matFooterCellDef class="info" 
[colSpan]="displayedColumns.length - 1">
-          <span>{{ isFiltered ? 'No matches found' : 'There are no images yet' 
}}</span>
+          <span>{{ ($isFiltered | async) ? 'No matches found' : 'There are no 
images yet' }}</span>
         </td>
       </ng-container>
 
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
index 92be0c3a1..e317f2cde 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
@@ -252,3 +252,12 @@ td.mat-cell.image-page__project {
 .filtered-icon {
   color: #35afd5;
 }
+
+.label {
+  position: relative;
+}
+
+.header__close--btn.close__btn {
+  top: -15px;
+  right: -15px;
+}
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
index f1066cd31..7d9a7ee12 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
@@ -26,7 +26,7 @@ import { ToastrService } from 'ngx-toastr';
 
 import { GeneralEnvironmentStatus } from 
'../../administration/management/management.model';
 import { HealthStatusService } from '../../core/services';
-import { ImageFilterFormDropdownData, ImageFilterFormValue, ImageModel, 
ProjectModel } from './images.model';
+import { FilteredColumnList, ImageFilterFormDropdownData, 
ImageFilterFormValue, ImageModel, ProjectModel } from './images.model';
 import {
   TooltipStatuses,
   Image_Table_Column_Headers,
@@ -78,8 +78,9 @@ export class ImagesComponent implements OnInit, OnDestroy {
   $filterDropdownData: Observable<ImageFilterFormDropdownData>;
   $filterFormValue: Observable<ImageFilterFormValue>;
   $isProjectListEmpty: Observable<boolean>;
+  $filteredColumnState: Observable<FilteredColumnList>;
+  $isFiltered: Observable<boolean>;
   isShowActive: boolean = true;
-  isFiltered: boolean = false;
 
   constructor(
     private healthStatusService: HealthStatusService,
@@ -99,6 +100,8 @@ export class ImagesComponent implements OnInit, OnDestroy {
     this.getDropdownList();
     this.getFilterFormValue();
     this.getIsProjectListEmpty();
+    this.initFilteredColumnState();
+    this.initIsImageListFiltered();
   }
 
   ngOnDestroy(): void {
@@ -158,9 +161,10 @@ export class ImagesComponent implements OnInit, OnDestroy {
 
   onFilterApplyClick(filterFormValue: ImageFilterFormValue): void {
     const normalizeFilterFormValue = 
this.imagesService.normalizeFilterFormValue(filterFormValue, 
DropdownSelectAllValue);
+    this.imagesService.updateFilterColumnState(normalizeFilterFormValue);
     
this.imagesService.filterImagePageInfo(normalizeFilterFormValue).subscribe();
     this.imagesService.setFilterFormValue(filterFormValue);
-    this.isFiltered = true;
+    this.imagesService.checkIsPageFiltered();
     this.imagesService.closeFilter();
   }
 
@@ -182,7 +186,12 @@ export class ImagesComponent implements OnInit, OnDestroy {
     event.stopPropagation();
     this.imagesService.filterImagePageInfo(FilterFormInitialValue).subscribe();
     this.imagesService.setFilterFormValue(FilterFormInitialValue);
-    this.isFiltered = false;
+    this.imagesService.updateFilterColumnState(FilterFormInitialValue);
+    this.imagesService.checkIsPageFiltered();
+  }
+
+  onResetColumn(dropdownFieldNames: DropdownFieldNames): void {
+    this.imagesService.resetFilterField(dropdownFieldNames, 
DropdownSelectAllValue);
   }
 
   private getEnvironmentHealthStatus(): void {
@@ -194,6 +203,10 @@ export class ImagesComponent implements OnInit, OnDestroy {
     );
   }
 
+  private initFilteredColumnState(): void {
+    this.$filteredColumnState = this.imagesService.$filteredColumnState;
+  }
+
   private getUserImagePageInfo(): void {
     this.route.data.pipe(
       map(data => data['projectList']),
@@ -239,6 +252,10 @@ export class ImagesComponent implements OnInit, OnDestroy {
     this.$isProjectListEmpty = this.imagesService.$isProjectListEmpty;
   }
 
+  private initIsImageListFiltered(): void {
+    this.$isFiltered = this.imagesService.$isImageListFiltered;
+  }
+
   get isImageSelected(): boolean {
     return this.imagesService.isImageSelected();
   }
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
index 0fa0c8232..06867d403 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
@@ -21,7 +21,7 @@ export enum Image_Table_Column_Headers {
   imageName = 'Image name',
   creationDate = 'Creation date',
   provider = 'Provider',
-  imageStatus = 'Image status',
+  imageStatus = 'Status',
   sharedStatus = 'Shared status',
   templateName = 'Template name',
   actions = 'Actions',
@@ -90,6 +90,7 @@ export const FilterFormInitialValue = {
     imageName: '',
     statuses: [],
     templateNames: [],
+    sharingStatuses: [],
 };
 
 export const ChangedColumnStartValue = {
@@ -97,6 +98,7 @@ export const ChangedColumnStartValue = {
     imageName: false,
     statuses: false,
     templateNames: false,
+    sharingStatuses: false,
 };
 
 export enum ImageModelKeysForFilter {
@@ -108,3 +110,4 @@ export enum ImageModelKeysForFilter {
 }
 
 export const DropdownSelectAllValue = 'selectAllFound';
+
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
index b3a66902f..e66b8db1a 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
@@ -62,6 +62,7 @@ export interface ImageFilterFormValue {
   imageName: string;
   statuses: string[];
   templateNames: string[];
+  sharingStatuses: string[];
 }
 
 
@@ -75,4 +76,7 @@ export interface FilteredColumnList {
   statuses: boolean;
   endpoints: boolean;
   templateNames: boolean;
+  sharingStatuses: boolean;
 }
+
+export type FilterFormItemType = [string, string[] | string];
diff --git 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
index e8715ff8b..05dce5415 100644
--- 
a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
+++ 
b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
@@ -4,6 +4,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
 
 import {
   FilteredColumnList,
+  FilterFormItemType,
   ImageFilterFormDropdownData,
   ImageFilterFormValue,
   ImageModel,
@@ -26,7 +27,8 @@ export class ImagesService {
   // tslint:disable-next-line:max-line-length
   private $$filterDropdownData: BehaviorSubject<ImageFilterFormDropdownData> = 
new BehaviorSubject<ImageFilterFormDropdownData>({} as 
ImageFilterFormDropdownData);
   private $$filterFormValue: BehaviorSubject<ImageFilterFormValue> = new 
BehaviorSubject<ImageFilterFormValue>(FilterFormInitialValue);
-  private $$changedColumn: BehaviorSubject<FilteredColumnList> = new 
BehaviorSubject<FilteredColumnList>(ChangedColumnStartValue);
+  private $$filteredColumnState: BehaviorSubject<FilteredColumnList> = new 
BehaviorSubject<FilteredColumnList>(ChangedColumnStartValue);
+  private $$isImageListFiltered: BehaviorSubject<boolean> = new 
BehaviorSubject<boolean>(false);
   private dropdownStartValue: ImageFilterFormDropdownData;
 
   $projectList = this.$$projectList.asObservable();
@@ -35,6 +37,8 @@ export class ImagesService {
   $isFilterOpened = this.$$isFilterOpened.asObservable();
   $filterDropdownData = this.$$filterDropdownData.asObservable();
   $filterFormValue = this.$$filterFormValue.asObservable();
+  $filteredColumnState = this.$$filteredColumnState.asObservable();
+  $isImageListFiltered = this.$$isImageListFiltered.asObservable();
 
   constructor(
     private applicationServiceFacade: ApplicationServiceFacade,
@@ -114,11 +118,21 @@ export class ImagesService {
     this.$$isFilterOpened.next(false);
   }
 
-  filterDropdownField(field: keyof ImageFilterFormDropdownData, value: string, 
) {
+  filterDropdownField(field: keyof ImageFilterFormDropdownData, value: string, 
): void {
     const filteredDropdownList = this.dropdownStartValue[field].filter(item => 
item.toLowerCase().includes(value));
     this.addFilterDropdownData({...this.$$filterDropdownData.value, imageName: 
filteredDropdownList});
   }
 
+  resetFilterField(field: keyof ImageFilterFormDropdownData, exceptionValue: 
string = ''): void {
+    const droppedFieldValue = this.getDroppedFieldValue(field);
+    const updatedFilterFormValue = {...this.$$filterFormValue.value, [field]: 
droppedFieldValue};
+    const normalizeFormValue = 
this.normalizeFilterFormValue(updatedFilterFormValue, exceptionValue);
+    this.setFilterFormValue(updatedFilterFormValue);
+    this.updateFilterColumnState(normalizeFormValue);
+    this.filterImagePageInfo(normalizeFormValue).subscribe();
+    this.checkIsPageFiltered();
+  }
+
   setFilterFormValue(value: ImageFilterFormValue): void {
     this.$$filterFormValue.next(value);
   }
@@ -138,17 +152,44 @@ export class ImagesService {
       return filterFormValue;
     }
     return (<any>Object).entries(filterFormValue)
-      .reduce((acc, fieldItem) => {
-        const [ fieldName, fieldValue ] = fieldItem;
-        let value;
-
-        if (typeof fieldValue === 'string') {
-          value = fieldValue;
-        } else {
-          value = fieldValue.filter(item => item !== exceptionValue);
-        }
-        return {...acc, [fieldName]: value};
-      }, <ImageFilterFormValue>{});
+      .reduce((acc, fieldItem) => this.filterFormValue(acc, fieldItem, 
exceptionValue), <ImageFilterFormValue>{});
+  }
+
+  updateFilterColumnState(filterFormValue: ImageFilterFormValue): void {
+    const columnStateList = (<any>Object).entries(filterFormValue)
+      .reduce((acc, fieldItem) => this.checkColumnState(acc, fieldItem), 
<FilteredColumnList>{});
+
+    this.$$filteredColumnState.next(columnStateList);
+  }
+
+  getDroppedFieldValue(field: keyof ImageFilterFormDropdownData): string | [] {
+    return typeof this.$$filterFormValue.value[field] === 'string'
+      ? ''
+      : [];
+  }
+
+  checkIsPageFiltered() {
+    const isImageListFiltered = 
(<any>Object).values(this.$$filteredColumnState.value).some(item => 
Boolean(item));
+    this.$$isImageListFiltered.next(isImageListFiltered);
+  }
+
+  private checkColumnState(acc: FilteredColumnList, fieldItem: 
FilterFormItemType): FilteredColumnList {
+    const [ fieldName, fieldValue ] = fieldItem;
+    let isColumnFiltered: boolean;
+    isColumnFiltered = typeof fieldValue === 'string' ? Boolean(fieldValue) : 
Boolean(fieldValue.length);
+    return  {...acc, [fieldName]: isColumnFiltered};
+  }
+
+  private filterFormValue(acc: ImageFilterFormValue, fieldItem: 
FilterFormItemType, exceptionValue: string = ''): ImageFilterFormValue {
+    const [ fieldName, fieldValue ] = fieldItem;
+    let value;
+
+    if (typeof fieldValue === 'string') {
+      value = fieldValue;
+    } else {
+      value = fieldValue.filter(item => item !== exceptionValue);
+    }
+    return {...acc, [fieldName]: value};
   }
 
   private filterByCondition(arr: ProjectModel[], field: keyof ImageModel, 
comparedValue: string) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to