[ACS-5308] Highlight the selected filter in ADW (#8649)

* changes for highlight the selected filter

* implemented the changes as per review comments

* added test cases and implemented review comments

* fix code and linting errors

* e2e fixes

* linting fix

* lint fix

* minor fixes

* fix for unit test case

* e2e fix for process

---------

Co-authored-by: Denys Vuika <denys.vuika@gmail.com>
This commit is contained in:
Yasa-Nataliya
2023-06-16 15:20:08 +05:30
committed by GitHub
parent ac694cd7a2
commit 13f4f62608
6 changed files with 125 additions and 29 deletions

View File

@@ -1,4 +1,4 @@
<div *ngFor="let filter of filters" class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
<div *ngFor="let filter of filters" class="adf-filters__entry" [class.adf-active]="isActiveRoute(filter)">
<button
(click)="selectFilter(filter)"
[attr.aria-label]="filter.name | translate"

View File

@@ -27,6 +27,8 @@ import { By } from '@angular/platform-browser';
import { fakeProcessFilters } from '../../mock/process/process-filters.mock';
import { ProcessTestingModule } from '../../testing/process.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { NavigationStart, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
describe('ProcessFiltersComponent', () => {
@@ -34,11 +36,13 @@ describe('ProcessFiltersComponent', () => {
let fixture: ComponentFixture<ProcessFiltersComponent>;
let processFilterService: ProcessFilterService;
let appsProcessService: AppsProcessService;
let router: Router;
setupTestBed({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
ProcessTestingModule,
RouterTestingModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
@@ -48,6 +52,7 @@ describe('ProcessFiltersComponent', () => {
filterList = fixture.componentInstance;
processFilterService = TestBed.inject(ProcessFilterService);
appsProcessService = TestBed.inject(AppsProcessService);
router = TestBed.inject(Router);
});
afterEach(() => {
@@ -305,4 +310,18 @@ describe('ProcessFiltersComponent', () => {
const filters: any = fixture.debugElement.queryAll(By.css('.adf-icon'));
expect(filters.length).toBe(0);
});
it('should set isProcessActive to true when activeRoute includes "processes"', () => {
const navigationStartEvent = new NavigationStart(1, 'processes/123');
spyOn(router.events, 'pipe').and.returnValue(of(navigationStartEvent));
fixture.detectChanges();
expect(filterList.isProcessActive).toBe(true);
});
it('should set isProcessActive to false when activeRoute does not include "processes"', () => {
const navigationStartEvent = new NavigationStart(1, 'other-route');
spyOn(router.events, 'pipe').and.returnValue(of(navigationStartEvent));
fixture.detectChanges();
expect(filterList.isProcessActive).toBe(false);
});
});

View File

@@ -15,13 +15,16 @@
* limitations under the License.
*/
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { ProcessInstanceFilterRepresentation, UserProcessInstanceFilterRepresentation } from '@alfresco/js-api';
import { Observable } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { FilterProcessRepresentationModel } from '../models/filter-process.model';
import { ProcessFilterService } from './../services/process-filter.service';
import { AppsProcessService } from '../../app-list/services/apps-process.service';
import { IconModel } from '../../app-list/icon.model';
import { NavigationStart, Router } from '@angular/router';
import { filter, takeUntil } from 'rxjs/operators';
import { Location } from '@angular/common';
@Component({
selector: 'adf-process-instance-filters',
@@ -29,7 +32,7 @@ import { IconModel } from '../../app-list/icon.model';
styleUrls: ['./process-filters.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ProcessFiltersComponent implements OnInit, OnChanges {
export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
/** The parameters to filter the task filter. If there is no match then the default one
* (ie, the first filter in the list) is selected.
@@ -71,31 +74,51 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
filters: UserProcessInstanceFilterRepresentation [] = [];
active = false;
isProcessRoute: boolean;
isProcessActive: boolean;
private onDestroy$ = new Subject<boolean>();
private iconsMDL: IconModel;
constructor(private processFilterService: ProcessFilterService,
private appsProcessService: AppsProcessService) {
private appsProcessService: AppsProcessService,
private router: Router,
private location: Location) {
}
ngOnInit() {
this.iconsMDL = new IconModel();
this.router.events
.pipe(
filter((event) => event instanceof NavigationStart),
takeUntil(this.onDestroy$)
)
.subscribe((navigationStart: NavigationStart) => {
const activeRoute = navigationStart.url;
this.isProcessActive = activeRoute.includes('processes');
});
const currentRoute = this.location.path();
this.isProcessRoute = currentRoute.includes('processes');
}
ngOnChanges(changes: SimpleChanges) {
const appId = changes['appId'];
const appName = changes['appName'];
const filter = changes['filterParam'];
const filterParam = changes['filterParam'];
if (appId && (appId.currentValue || appId.currentValue === null)) {
this.getFiltersByAppId(appId.currentValue);
} else if (appName && appName.currentValue) {
this.getFiltersByAppName(appName.currentValue);
} else if (filter && filter.currentValue !== filter.previousValue) {
this.selectProcessFilter(filter.currentValue);
} else if (filterParam && filterParam.currentValue !== filterParam.previousValue) {
this.selectProcessFilter(filterParam.currentValue);
}
}
isActiveRoute(filterActive: ProcessInstanceFilterRepresentation): boolean {
return (this.isProcessActive || this.isProcessRoute) && this.currentFilter === filterActive;
}
/**
* Return the filter list filtered by appId
*
@@ -148,12 +171,12 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
/**
* Pass the selected filter as next
*
* @param filter
* @param filterModel
*/
selectFilter(filter: ProcessInstanceFilterRepresentation) {
this.currentFilter = filter;
selectFilter(filterModel: ProcessInstanceFilterRepresentation) {
this.currentFilter = filterModel;
this.active = true;
this.filterClicked.emit(filter);
this.filterClicked.emit(filterModel);
}
/**
@@ -222,4 +245,9 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
this.filters = [];
this.currentFilter = undefined;
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
}

View File

@@ -1,4 +1,4 @@
<div *ngFor="let filter of filters" class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
<div *ngFor="let filter of filters" class="adf-filters__entry" [class.adf-active]="isActiveRoute(filter)">
<button
(click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"

View File

@@ -28,6 +28,8 @@ import { ProcessTestingModule } from '../../testing/process.testing.module';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { fakeTaskFilters } from '../../mock/task/task-filters.mock';
import { NavigationStart, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
describe('TaskFiltersComponent', () => {
@@ -36,11 +38,13 @@ describe('TaskFiltersComponent', () => {
let appsProcessService: AppsProcessService;
let component: TaskFiltersComponent;
let fixture: ComponentFixture<TaskFiltersComponent>;
let router: Router;
setupTestBed({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
ProcessTestingModule,
RouterTestingModule
]
});
@@ -54,6 +58,7 @@ describe('TaskFiltersComponent', () => {
taskListService = TestBed.inject(TaskListService);
taskFilterService = TestBed.inject(TaskFilterService);
appsProcessService = TestBed.inject(AppsProcessService);
router = TestBed.inject(Router);
});
it('should emit an error with a bad response', async () => {
@@ -338,5 +343,19 @@ describe('TaskFiltersComponent', () => {
expect(taskFilterTwo.innerText).toBe('default-involved-filter');
expect(taskFilterThree.innerText).toBe('default-completed-filter');
});
it('should set isTaskActive to true when activeRoute includes "tasks"', () => {
const navigationStartEvent = new NavigationStart(1, 'tasks/123');
spyOn(router.events, 'pipe').and.returnValue(of(navigationStartEvent));
fixture.detectChanges();
expect(component.isTaskActive).toBe(true);
});
it('should set isTaskActive to false when activeRoute does not include "tasks"', () => {
const navigationStartEvent = new NavigationStart(1, 'other-route');
spyOn(router.events, 'pipe').and.returnValue(of(navigationStartEvent));
fixture.detectChanges();
expect(component.isTaskActive).toBe(false);
});
});
});

View File

@@ -16,12 +16,14 @@
*/
import { AppsProcessService } from '../../app-list/services/apps-process.service';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Observable } from 'rxjs';
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { FilterParamsModel, FilterRepresentationModel } from '../models/filter.model';
import { TaskFilterService } from './../services/task-filter.service';
import { TaskListService } from './../services/tasklist.service';
import { IconModel } from '../../app-list/icon.model';
import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
import { filter, takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-task-filters',
@@ -29,7 +31,7 @@ import { IconModel } from '../../app-list/icon.model';
styleUrls: ['./task-filters.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TaskFiltersComponent implements OnInit, OnChanges {
export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
/** Parameters to use for the task filter. If there is no match then
* the default filter (the first one the list) is selected.
@@ -71,30 +73,53 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
filters: FilterRepresentationModel [] = [];
private onDestroy$ = new Subject<boolean>();
isTaskRoute: boolean;
isTaskActive: boolean;
private iconsMDL: IconModel;
constructor(private taskFilterService: TaskFilterService,
private taskListService: TaskListService,
private appsProcessService: AppsProcessService) {
private appsProcessService: AppsProcessService,
private router: Router,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.iconsMDL = new IconModel();
this.router.events
.pipe(
filter((event) => event instanceof NavigationStart),
takeUntil(this.onDestroy$)
)
.subscribe((navigationStart: NavigationStart) => {
const activeRoute = navigationStart.url;
this.isTaskActive = activeRoute.includes('tasks');
});
this.activatedRoute.url.subscribe((segments) => {
const currentRoute = segments.join('/');
this.isTaskRoute = currentRoute.includes('tasks');
});
}
ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName'];
const appId = changes['appId'];
const filter = changes['filterParam'];
const filterParam = changes['filterParam'];
if (appName && appName.currentValue) {
this.getFiltersByAppName(appName.currentValue);
} else if (appId && appId.currentValue !== appId.previousValue) {
this.getFiltersByAppId(appId.currentValue);
} else if (filter && filter.currentValue !== filter.previousValue) {
this.selectFilterAndEmit(filter.currentValue);
} else if (filterParam && filterParam.currentValue !== filterParam.previousValue) {
this.selectFilterAndEmit(filterParam.currentValue);
}
}
isActiveRoute(filterActive: FilterRepresentationModel): boolean {
return (this.isTaskActive || this.isTaskRoute) && this.currentFilter === filterActive;
}
/**
* Return the task list filtered by appId or by appName
*
@@ -173,11 +198,11 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
*/
public selectFilter(newFilter: FilterParamsModel) {
if (newFilter) {
this.currentFilter = this.filters.find( (filter, index) =>
this.currentFilter = this.filters.find( (entry, index) =>
newFilter.index === index ||
newFilter.id === filter.id ||
newFilter.id === entry.id ||
(newFilter.name &&
(newFilter.name.toLocaleLowerCase() === filter.name.toLocaleLowerCase())
(newFilter.name.toLocaleLowerCase() === entry.name.toLocaleLowerCase())
));
}
}
@@ -190,8 +215,8 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
/**
* Selects and emits the clicked filter.
*/
onFilterClick(filter: FilterParamsModel) {
this.selectFilter(filter);
onFilterClick(filterParams: FilterParamsModel) {
this.selectFilter(filterParams);
this.filterClicked.emit(this.currentFilter);
}
@@ -203,8 +228,8 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
public selectFilterWithTask(taskId: string) {
const filteredFilterList: FilterRepresentationModel[] = [];
this.taskListService.getFilterForTaskById(taskId, this.filters).subscribe(
(filter: FilterRepresentationModel) => {
filteredFilterList.push(filter);
(filterModel: FilterRepresentationModel) => {
filteredFilterList.push(filterModel);
},
(err) => {
this.error.emit(err);
@@ -254,4 +279,9 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
this.filters = [];
this.currentFilter = undefined;
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
}