mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACA-4258] Add Task Filter Counters (#6556)
* [ACA-4258] Add Task Filter Counters * Fix unit test
This commit is contained in:
BIN
docs/docassets/images/task-filter-counter.png
Normal file
BIN
docs/docassets/images/task-filter-counter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@@ -56,6 +56,12 @@ as the value of `filterParam` as shown in the table below:
|
||||
| key | string | The key of the task filter |
|
||||
| index | string | The zero-based position of the filter in the array. |
|
||||
|
||||
### Showing Filter Counters
|
||||
|
||||
By default, filter counters are hidden. If you want to display filter counters you will need to add the `showCounter` property set to `true` in your TaskFilterCloudModel.
|
||||
|
||||

|
||||
|
||||
## See also
|
||||
|
||||
* [Task filter Cloud Service](../services/task-filter-cloud.service.md)
|
||||
|
@@ -1,14 +1,18 @@
|
||||
<ng-container *ngIf="filters$ | async as filterList; else loading">
|
||||
<div *ngFor="let filter of filterList" class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
|
||||
<div *ngFor="let filter of filterList" class="adf-task-filters__entry">
|
||||
<button (click)="onFilterClick(filter)"
|
||||
[attr.aria-label]="filter.name | translate"
|
||||
[id]="filter.id"
|
||||
[attr.data-automation-id]="filter.key + '_filter'"
|
||||
mat-button
|
||||
[class.adf-active]="currentFilter === filter"
|
||||
class="adf-filter-action-button adf-full-width" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<adf-icon data-automation-id="adf-filter-icon" *ngIf="showIcons" [value]="filter.icon"></adf-icon>
|
||||
<span data-automation-id="adf-filter-label" class="adf-filter-action-button__label">{{ filter.name | translate }}</span>
|
||||
</button>
|
||||
<span *ngIf="counters$[filter.key]" class="adf-filter-action-button__counter">
|
||||
{{ counters$[filter.key] | async }}
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #loading>
|
||||
|
@@ -2,28 +2,45 @@
|
||||
$primary: map-get($theme, primary);
|
||||
|
||||
.adf {
|
||||
&-filters__entry {
|
||||
&-task-filters__entry {
|
||||
display: flex;
|
||||
padding: 12px 0 !important;
|
||||
height: 24px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
font-size: 14px !important;
|
||||
font-weight: bold;
|
||||
opacity: 0.54;
|
||||
opacity: 1;
|
||||
|
||||
.adf-full-width {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-filter-action-button .adf-filter-action-button__label {
|
||||
.adf-filter-action-button {
|
||||
opacity: 0.54;
|
||||
padding: 16px;
|
||||
|
||||
.adf-filter-action-button__label {
|
||||
padding-left: 20px;
|
||||
margin: 0 8px !important;
|
||||
}
|
||||
}
|
||||
&-filters__entry {
|
||||
&.adf-active,
|
||||
|
||||
.adf-filter-action-button__counter {
|
||||
opacity: 0.54;
|
||||
padding-left: 10px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: mat-color($primary);
|
||||
.adf-filter-action-button__counter, .adf-filter-action-button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-active {
|
||||
color: mat-color($primary);
|
||||
opacity: 1;
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { EventEmitter, Input, Output, OnDestroy, Directive } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { FilterParamsModel } from '../models/filter-cloud.model';
|
||||
|
||||
@Directive()
|
||||
@@ -45,6 +45,8 @@ export abstract class BaseTaskFiltersCloudComponent implements OnDestroy {
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
counters$: {[key: string]: Observable<number>} = {};
|
||||
|
||||
protected onDestroy$ = new Subject<boolean>();
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@@ -111,7 +111,7 @@ describe('ServiceTaskFiltersCloudComponent', () => {
|
||||
component.showIcons = true;
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const filters = fixture.debugElement.queryAll(By.css('.adf-filters__entry'));
|
||||
const filters = fixture.debugElement.queryAll(By.css('.adf-task-filters__entry'));
|
||||
expect(component.filters.length).toBe(3);
|
||||
expect(filters.length).toBe(3);
|
||||
expect(filters[0].nativeElement.innerText).toContain('FakeServiceTasks');
|
||||
|
@@ -18,7 +18,7 @@
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { setupTestBed } from '@alfresco/adf-core';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { from, Observable, of } from 'rxjs';
|
||||
import { TASK_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
|
||||
import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
|
||||
@@ -68,6 +68,7 @@ describe('TaskFiltersCloudComponent', () => {
|
||||
component = fixture.componentInstance;
|
||||
|
||||
taskFilterService = TestBed.inject(TaskFilterCloudService);
|
||||
spyOn(taskFilterService, 'getTaskFilterCounter').and.returnValue(of(11));
|
||||
});
|
||||
|
||||
it('should attach specific icon for each filter if hasIcon is true', async(() => {
|
||||
@@ -111,7 +112,7 @@ describe('TaskFiltersCloudComponent', () => {
|
||||
component.showIcons = true;
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const filters = fixture.debugElement.queryAll(By.css('.adf-filters__entry'));
|
||||
const filters = fixture.debugElement.queryAll(By.css('.adf-task-filters__entry'));
|
||||
expect(component.filters.length).toBe(3);
|
||||
expect(filters.length).toBe(3);
|
||||
expect(filters[0].nativeElement.innerText).toContain('FakeInvolvedTasks');
|
||||
@@ -363,4 +364,19 @@ describe('TaskFiltersCloudComponent', () => {
|
||||
component.selectFilter(filter);
|
||||
expect(component.currentFilter).toBe(fakeGlobalFilter[0]);
|
||||
});
|
||||
|
||||
it('should display filter counter if property set to true', async(() => {
|
||||
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
|
||||
const change = new SimpleChange(undefined, 'my-app-1', true);
|
||||
component.ngOnChanges({'appName': change});
|
||||
fixture.detectChanges();
|
||||
component.showIcons = true;
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const filterCounters = fixture.debugElement.queryAll(By.css('.adf-filter-action-button__counter'));
|
||||
expect(component.filters.length).toBe(3);
|
||||
expect(filterCounters.length).toBe(1);
|
||||
expect(filterCounters[0].nativeElement.innerText).toContain('11');
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@@ -40,6 +40,7 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
|
||||
filters$: Observable<TaskFilterCloudModel[]>;
|
||||
filters: TaskFilterCloudModel[] = [];
|
||||
currentFilter: TaskFilterCloudModel;
|
||||
counters = {};
|
||||
|
||||
constructor(private taskFilterCloudService: TaskFilterCloudService,
|
||||
private translationService: TranslationService) {
|
||||
@@ -71,6 +72,7 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
|
||||
this.resetFilter();
|
||||
this.filters = Object.assign([], res);
|
||||
this.selectFilterAndEmit(this.filterParam);
|
||||
this.initFilterCounters();
|
||||
this.success.emit(res);
|
||||
},
|
||||
(err: any) => {
|
||||
@@ -79,6 +81,14 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
|
||||
);
|
||||
}
|
||||
|
||||
initFilterCounters() {
|
||||
this.filters.forEach((filter) => {
|
||||
if (filter.showCounter) {
|
||||
this.counters$[filter.key] = this.taskFilterCloudService.getTaskFilterCounter(filter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public selectFilter(paramFilter: FilterParamsModel) {
|
||||
if (paramFilter) {
|
||||
this.currentFilter = this.filters.find((filter, index) =>
|
||||
|
@@ -24,7 +24,8 @@ export const fakeGlobalFilter = [
|
||||
icon: 'adjust',
|
||||
id: '10',
|
||||
status: 'open',
|
||||
assignee: 'fake-involved'
|
||||
assignee: 'fake-involved',
|
||||
showCounter: true
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'FakeMyTasks1',
|
||||
@@ -32,7 +33,8 @@ export const fakeGlobalFilter = [
|
||||
icon: 'done',
|
||||
id: '11',
|
||||
status: 'open',
|
||||
assignee: 'fake-assignee'
|
||||
assignee: 'fake-assignee',
|
||||
showCounter: false
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'FakeMyTasks2',
|
||||
|
@@ -51,6 +51,7 @@ export class TaskFilterCloudModel {
|
||||
assignmentType: AssignmentType;
|
||||
completedDate: Date;
|
||||
completedBy: IdentityUserModel;
|
||||
showCounter: boolean;
|
||||
|
||||
private _completedFrom: string;
|
||||
private _completedTo: string;
|
||||
@@ -97,6 +98,7 @@ export class TaskFilterCloudModel {
|
||||
this.createdFrom = obj._createdFrom || null;
|
||||
this.createdTo = obj._createdTo || null;
|
||||
this.candidateGroups = obj.candidateGroups || null;
|
||||
this.showCounter = obj.showCounter || false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,26 +15,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { IdentityUserService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, AppConfigService, IdentityUserService } from '@alfresco/adf-core';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Observable, of, BehaviorSubject } from 'rxjs';
|
||||
import { Observable, of, BehaviorSubject, throwError } from 'rxjs';
|
||||
import { TaskFilterCloudModel } from '../models/filter-cloud.model';
|
||||
import { switchMap, map } from 'rxjs/operators';
|
||||
import { BaseCloudService } from '../../../services/base-cloud.service';
|
||||
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
|
||||
import { TASK_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { TaskCloudNodePaging } from '../../task-list/models/task-cloud.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TaskFilterCloudService {
|
||||
export class TaskFilterCloudService extends BaseCloudService {
|
||||
private filtersSubject: BehaviorSubject<TaskFilterCloudModel[]>;
|
||||
filters$: Observable<TaskFilterCloudModel[]>;
|
||||
|
||||
constructor(
|
||||
private identityUserService: IdentityUserService,
|
||||
@Inject(TASK_FILTERS_SERVICE_TOKEN)
|
||||
public preferenceService: PreferenceCloudServiceInterface
|
||||
) {
|
||||
public preferenceService: PreferenceCloudServiceInterface,
|
||||
apiService: AlfrescoApiService,
|
||||
appConfigService: AppConfigService) {
|
||||
super(apiService, appConfigService);
|
||||
this.filtersSubject = new BehaviorSubject([]);
|
||||
this.filters$ = this.filtersSubject.asObservable();
|
||||
}
|
||||
@@ -219,6 +223,27 @@ export class TaskFilterCloudService {
|
||||
return defaultFilters.findIndex((filter) => filterName === filter.name) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a task using an object with optional query properties.
|
||||
* @param requestNode Query object
|
||||
* @returns Task information
|
||||
*/
|
||||
getTaskFilterCounter(taskFilter: TaskFilterCloudModel): Observable<any> {
|
||||
if (taskFilter.appName || taskFilter.appName === '') {
|
||||
const queryUrl = `${this.getBasePath(taskFilter.appName)}/query/v1/tasks`;
|
||||
const queryParams = {
|
||||
assignee: taskFilter.assignee,
|
||||
status: taskFilter.status,
|
||||
appName: taskFilter.appName
|
||||
};
|
||||
return this.get<TaskCloudNodePaging>(queryUrl, queryParams).pipe(
|
||||
map((tasks) => tasks.list.pagination.totalItems)
|
||||
);
|
||||
} else {
|
||||
return throwError('Appname not configured');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls update preference api to update task filter
|
||||
* @param appName Name of the target app
|
||||
@@ -264,7 +289,8 @@ export class TaskFilterCloudService {
|
||||
status: 'ASSIGNED',
|
||||
assignee: this.identityUserService.getCurrentUserInfo().username,
|
||||
sort: 'createdDate',
|
||||
order: 'DESC'
|
||||
order: 'DESC',
|
||||
showCounter: true
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'ADF_CLOUD_TASK_FILTERS.QUEUED_TASKS',
|
||||
@@ -274,7 +300,8 @@ export class TaskFilterCloudService {
|
||||
status: 'CREATED',
|
||||
assignee: '',
|
||||
sort: 'createdDate',
|
||||
order: 'DESC'
|
||||
order: 'DESC',
|
||||
showCounter: true
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'ADF_CLOUD_TASK_FILTERS.COMPLETED_TASKS',
|
||||
|
Reference in New Issue
Block a user