diff --git a/docs/docassets/images/task-filter-counter.png b/docs/docassets/images/task-filter-counter.png new file mode 100644 index 0000000000..80999e2e55 Binary files /dev/null and b/docs/docassets/images/task-filter-counter.png differ diff --git a/docs/process-services-cloud/components/task-filters-cloud.component.md b/docs/process-services-cloud/components/task-filters-cloud.component.md index 478a534611..eba4d0c67b 100644 --- a/docs/process-services-cloud/components/task-filters-cloud.component.md +++ b/docs/process-services-cloud/components/task-filters-cloud.component.md @@ -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. + +![](../../docassets/images/task-filter-counter.png) + ## See also * [Task filter Cloud Service](../services/task-filter-cloud.service.md) diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.html index 88e36c2e36..b0eae32717 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.html @@ -1,14 +1,18 @@ -
+
+ + {{ counters$[filter.key] | async }} +
diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.scss b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.scss index 7d7ddee13e..bf7d7fc6f1 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.scss @@ -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 { - padding-left: 20px; - margin: 0 8px !important; + .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; } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.ts index 7b4fd646a1..f0d7ecbe52 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/base-task-filters-cloud.component.ts @@ -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 = new EventEmitter(); + counters$: {[key: string]: Observable} = {}; + protected onDestroy$ = new Subject(); ngOnDestroy() { diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters-cloud.component.spec.ts index 4c20e80ed4..39152e72c0 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters-cloud.component.spec.ts @@ -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'); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts index 6900a14316..c1a406fa34 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts @@ -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'); + }); + })); }); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.ts index eec4fe45dd..b4845bed6a 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.ts @@ -40,10 +40,11 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp filters$: Observable; filters: TaskFilterCloudModel[] = []; currentFilter: TaskFilterCloudModel; + counters = {}; constructor(private taskFilterCloudService: TaskFilterCloudService, private translationService: TranslationService) { - super(); + super(); } ngOnInit() { @@ -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) => diff --git a/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts b/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts index eb073819d5..e97b6f760b 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts @@ -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', diff --git a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts index 128f8b6dad..932a5e1ec2 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts @@ -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; } } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.ts b/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.ts index da2ed40748..65e09222fa 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.ts @@ -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; filters$: Observable; 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 { + 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(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',