[ACA-4123] Unify APS and Cloud event emitters for filters (#6331)

* Experimental solution

* Unify event emitters for aps and cloud filters

* Update emitter descriptions

* Fix/Add unit tests

* Unit tests part 2

* Update documentation, put mock objects into separate mock files and remove them from test files

* rename tests

* align demo-shell with the new changes

* fix aps demo shell
This commit is contained in:
arditdomi
2020-11-16 14:37:17 +00:00
committed by GitHub
parent db1fb81c4d
commit 4dfa9b6d53
30 changed files with 561 additions and 445 deletions

View File

@@ -10,7 +10,8 @@
[appName]="appName" [appName]="appName"
[showIcons]="true" [showIcons]="true"
[filterParam]="currentTaskFilter$ | async" [filterParam]="currentTaskFilter$ | async"
(filterClick)="onTaskFilterSelected($event)"> (filterClicked)="onTaskFilterSelected($event)"
(filterSelected)="onTaskFilterSelected($event)">
</adf-cloud-task-filters> </adf-cloud-task-filters>
</mat-expansion-panel> </mat-expansion-panel>
@@ -25,7 +26,8 @@
[appName]="appName" [appName]="appName"
[showIcons]="true" [showIcons]="true"
[filterParam]="currentProcessFilter$ | async" [filterParam]="currentProcessFilter$ | async"
(filterClick)="onProcessFilterSelected($event)"> (filterClicked)="onProcessFilterSelected($event)"
(filterSelected)="onProcessFilterSelected($event)">
</adf-cloud-process-filters> </adf-cloud-process-filters>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>

View File

@@ -27,7 +27,8 @@
<adf-task-filters [filterParam]="filterSelected" <adf-task-filters [filterParam]="filterSelected"
[appId]="appId" [appId]="appId"
[showIcon]="showTaskFilterIcon" [showIcon]="showTaskFilterIcon"
(filterClick)="onTaskFilterClick($event)" (filterClicked)="onTaskFilterClick($event)"
(filterSelected)="onTaskFilterClick($event)"
(success)="onSuccessTaskFilterList()" #activitiFilter> (success)="onSuccessTaskFilterList()" #activitiFilter>
</adf-task-filters> </adf-task-filters>
</mat-expansion-panel> </mat-expansion-panel>
@@ -145,7 +146,7 @@
[appId]="appId" [appId]="appId"
[filterParam]="filterSelected" [filterParam]="filterSelected"
[showIcon]="showProcessFilterIcon" [showIcon]="showProcessFilterIcon"
(filterClick)="onProcessFilterChange($event)" (filterClicked)="onProcessFilterChange($event)"
(filterSelected)="onProcessFilterChange($event)" (filterSelected)="onProcessFilterChange($event)"
(success)="onSuccessProcessFilterList()"> (success)="onSuccessProcessFilterList()">
</adf-process-instance-filters> </adf-process-instance-filters>

View File

@@ -33,7 +33,8 @@ Lists all available process filters and allows to select a filter.
| Name | Type | Description | | Name | Type | Description |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs while loading the filters | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs while loading the filters |
| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterCloudModel`](../../../lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is selected/clicked | | filterSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterCloudModel`](../../../lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is being selected based on the filterParam input. |
| filterClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterCloudModel`](../../../lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is being clicked from the UI. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when filters are loaded successfully | | success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when filters are loaded successfully |
## See also ## See also

View File

@@ -30,7 +30,8 @@ Shows all available filters.
| Name | Type | Description | | Name | Type | Description |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs during loading. | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs during loading. |
| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`TaskFilterCloudModel`](../../../lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts)`>` | Emitted when a filter in the list is clicked. | | filterSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`TaskFilterCloudModel`](../../../lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts)`>` | Emitted when a filter is being selected based on the filterParam input. |
| filterClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`TaskFilterCloudModel`](../../../lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts)`>` | Emitted when a filter is being clicked from the UI. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the list is loaded. | | success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the list is loaded. |
## Details ## Details

View File

@@ -44,8 +44,8 @@ Collection of criteria used to filter process instances, which may be customized
| Name | Type | Description | | Name | Type | Description |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs. | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs. |
| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`UserProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/UserProcessInstanceFilterRepresentation.md)`>` | Emitted when the user selects a filter from the list. | | filterSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`UserProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/UserProcessInstanceFilterRepresentation.md)`>` | Emitted when a filter is being selected based on the filterParam input. |
| filterSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ProcessInstanceFilterRepresentation.md)`>` | Emitted when a process filter is selected. | | filterClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`UserProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/UserProcessInstanceFilterRepresentation.md)`>` | Emitted when a filter is being clicked from the UI. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ProcessInstanceFilterRepresentation.md)`[]>` | Emitted when the list of filters has been successfully loaded from the server. | | success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceFilterRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ProcessInstanceFilterRepresentation.md)`[]>` | Emitted when the list of filters has been successfully loaded from the server. |
## Details ## Details

View File

@@ -31,7 +31,8 @@ Shows all available filters.
| Name | Type | Description | | Name | Type | Description |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs during loading. | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs during loading. |
| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FilterRepresentationModel`](../../../lib/process-services/src/lib/task-list/models/filter.model.ts)`>` | Emitted when a filter in the list is clicked. | | filterSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FilterRepresentationModel`](../../../lib/process-services/src/lib/task-list/models/filter.model.ts)`>` | Emitted when a filter is being selected based on the filterParam input. |
| filterClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FilterRepresentationModel`](../../../lib/process-services/src/lib/task-list/models/filter.model.ts)`>` | Emitted when a filter is being clicked from the UI. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the list is loaded. | | success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the list is loaded. |
## Details ## Details

View File

@@ -1,7 +1,7 @@
<ng-container *ngIf="filters$ | async as filterList; else loading"> <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-filters__entry" [class.adf-active]="currentFilter === filter">
<button (click)="selectFilterById(filter.id)" <button (click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate" [attr.aria-label]="filter.name | translate"
[id]="filter.id" [id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'" [attr.data-automation-id]="filter.key + '_filter'"
@@ -18,4 +18,4 @@
<mat-spinner></mat-spinner> <mat-spinner></mat-spinner>
</div> </div>
</ng-container> </ng-container>
</ng-template> </ng-template>

View File

@@ -19,7 +19,6 @@ import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed } from '@alfresco/adf-core';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
import { ProcessFiltersCloudComponent } from './process-filters-cloud.component'; import { ProcessFiltersCloudComponent } from './process-filters-cloud.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
@@ -28,43 +27,20 @@ import { ProcessFiltersCloudModule } from '../process-filters-cloud.module';
import { PROCESS_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.service'; import { PROCESS_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.service';
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service'; import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { mockProcessFilters } from '../mock/process-filters-cloud.mock';
describe('ProcessFiltersCloudComponent', () => { describe('ProcessFiltersCloudComponent', () => {
let processFilterService: ProcessFilterCloudService; let processFilterService: ProcessFilterCloudService;
const fakeGlobalFilter = [
new ProcessFilterCloudModel({
name: 'FakeAllProcesses',
key: 'FakeAllProcesses',
icon: 'adjust',
id: '10',
status: ''
}),
new ProcessFilterCloudModel({
name: 'FakeRunningProcesses',
key: 'FakeRunningProcesses',
icon: 'inbox',
id: '11',
status: 'RUNNING'
}),
new ProcessFilterCloudModel({
name: 'FakeCompletedProcesses',
key: 'completed-processes',
icon: 'done',
id: '12',
status: 'COMPLETED'
})
];
const fakeGlobalFilterObservable = const fakeGlobalFilterObservable =
new Observable(function(observer) { new Observable(function(observer) {
observer.next(fakeGlobalFilter); observer.next(mockProcessFilters);
observer.complete(); observer.complete();
}); });
const fakeGlobalFilterPromise = new Promise(function (resolve) { const fakeGlobalFilterPromise = new Promise(function (resolve) {
resolve(fakeGlobalFilter); resolve(mockProcessFilters);
}); });
const mockErrorFilterList = { const mockErrorFilterList = {
@@ -197,7 +173,7 @@ describe('ProcessFiltersCloudComponent', () => {
const appName = 'my-app-1'; const appName = 'my-app-1';
const change = new SimpleChange(null, appName, true); const change = new SimpleChange(null, appName, true);
component.filterClick.subscribe((res) => { component.filterSelected.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(component.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(component.currentFilter.name).toEqual('FakeRunningProcesses'); expect(component.currentFilter.name).toEqual('FakeRunningProcesses');
@@ -217,7 +193,7 @@ describe('ProcessFiltersCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
component.filterClick.subscribe((res) => { component.filterSelected.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(component.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(component.currentFilter.name).toEqual('FakeCompletedProcesses'); expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
@@ -236,7 +212,7 @@ describe('ProcessFiltersCloudComponent', () => {
const change = new SimpleChange(null, appName, true); const change = new SimpleChange(null, appName, true);
fixture.detectChanges(); fixture.detectChanges();
component.filterClick.subscribe((res) => { component.filterSelected.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(component.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(component.currentFilter.name).toEqual('FakeCompletedProcesses'); expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
@@ -255,7 +231,7 @@ describe('ProcessFiltersCloudComponent', () => {
const change = new SimpleChange(null, appName, true); const change = new SimpleChange(null, appName, true);
fixture.detectChanges(); fixture.detectChanges();
component.filterClick.subscribe((res) => { component.filterSelected.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(component.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(component.currentFilter.name).toEqual('FakeCompletedProcesses'); expect(component.currentFilter.name).toEqual('FakeCompletedProcesses');
@@ -265,7 +241,7 @@ describe('ProcessFiltersCloudComponent', () => {
component.ngOnChanges({ 'appName': change }); component.ngOnChanges({ 'appName': change });
}); });
it('should emit an event when a filter is selected', (done) => { it('should filterClicked emit when a filter is clicked from the UI', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = { id: '10' }; component.filterParam = { id: '10' };
@@ -275,14 +251,14 @@ describe('ProcessFiltersCloudComponent', () => {
component.ngOnChanges({ 'appName': change }); component.ngOnChanges({ 'appName': change });
fixture.detectChanges(); fixture.detectChanges();
component.filterClick.subscribe((res) => { component.filterClicked.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(component.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(component.currentFilter.name).toEqual('FakeAllProcesses'); expect(component.currentFilter.name).toEqual('FakeAllProcesses');
done(); done();
}); });
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeGlobalFilter[0].key}_filter"]`); const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${mockProcessFilters[0].key}_filter"]`);
filterButton.click(); filterButton.click();
}); });
@@ -318,14 +294,14 @@ describe('ProcessFiltersCloudComponent', () => {
}); });
it('should change current filter when filterParam (name) changes', () => { it('should change current filter when filterParam (name) changes', () => {
component.filters = fakeGlobalFilter; component.filters = mockProcessFilters;
component.currentFilter = null; component.currentFilter = null;
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(component.currentFilter.name).toEqual(fakeGlobalFilter[2].name); expect(component.currentFilter.name).toEqual(mockProcessFilters[2].name);
}); });
const change = new SimpleChange(null, { name: fakeGlobalFilter[2].name }, true); const change = new SimpleChange(null, { name: mockProcessFilters[2].name }, true);
component.ngOnChanges({ 'filterParam': change }); component.ngOnChanges({ 'filterParam': change });
}); });
@@ -340,11 +316,11 @@ describe('ProcessFiltersCloudComponent', () => {
}); });
it('should return the current filter after one is selected', () => { it('should return the current filter after one is selected', () => {
const filter = fakeGlobalFilter[1]; const filter = mockProcessFilters[1];
component.filters = fakeGlobalFilter; component.filters = mockProcessFilters;
expect(component.currentFilter).toBeUndefined(); expect(component.currentFilter).toBeUndefined();
component.selectFilter(<ProcessFilterCloudModel> {id: filter.id}); component.selectFilter({ id: filter.id });
expect(component.getCurrentFilter()).toBe(filter); expect(component.getCurrentFilter()).toBe(filter);
}); });
}); });

View File

@@ -42,9 +42,13 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
@Input() @Input()
showIcons: boolean = false; showIcons: boolean = false;
/** Emitted when a filter is selected/clicked */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterClick = new EventEmitter<ProcessFilterCloudModel>(); filterSelected = new EventEmitter<ProcessFilterCloudModel>();
/** Emitted when a filter is being clicked from the UI. */
@Output()
filterClicked = new EventEmitter<ProcessFilterCloudModel>();
/** Emitted when filters are loaded successfully */ /** Emitted when filters are loaded successfully */
@Output() @Output()
@@ -126,12 +130,12 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
} }
/** /**
* Select and emit the given filter * Selects and emits the given filter
*/ */
public selectFilterAndEmit(newParamFilter: FilterParamsModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
if (newParamFilter) { if (newParamFilter) {
this.selectFilter(newParamFilter); this.selectFilter(newParamFilter);
this.filterClick.emit(this.currentFilter); this.filterSelected.emit(this.currentFilter);
} else { } else {
this.currentFilter = undefined; this.currentFilter = undefined;
} }
@@ -144,6 +148,18 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
this.selectFilterAndEmit(<ProcessFilterCloudModel> {id: id}); this.selectFilterAndEmit(<ProcessFilterCloudModel> {id: id});
} }
/**
* Selects and emits the clicked filter
*/
public onFilterClick(filter: ProcessFilterCloudModel) {
if (filter) {
this.selectFilter(filter);
this.filterClicked.emit(this.currentFilter);
} else {
this.currentFilter = undefined;
}
}
/** /**
* Select as default process filter the first in the list * Select as default process filter the first in the list
*/ */

View File

@@ -0,0 +1,169 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
import { DateCloudFilterType } from '../../../../..';
export const fakeProcessCloudFilters = [
{
name: 'MOCK_PROCESS_NAME_1',
id: '1',
key: 'all-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK_ALL',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_2',
id: '2',
key: 'run-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-RUNNING',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_3',
id: '3',
key: 'complete-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-COMPLETED',
order: 'DESC'
}
];
export const mockProcessFilters = [
new ProcessFilterCloudModel({
name: 'FakeAllProcesses',
key: 'FakeAllProcesses',
icon: 'adjust',
id: '10',
status: ''
}),
new ProcessFilterCloudModel({
name: 'FakeRunningProcesses',
key: 'FakeRunningProcesses',
icon: 'inbox',
id: '11',
status: 'RUNNING'
}),
new ProcessFilterCloudModel({
name: 'FakeCompletedProcesses',
key: 'completed-processes',
icon: 'done',
id: '12',
status: 'COMPLETED'
})
];
export const fakeProcessFilter: ProcessFilterCloudModel = new ProcessFilterCloudModel({
name: 'MOCK_PROCESS_NAME_1',
id: '1',
key: 'all-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK_ALL',
order: 'DESC',
index: 2,
processName: 'process-name',
processDefinitionName: 'process-def-name',
processInstanceId: 'processinstanceid',
initiator: 'mockuser',
processDefinitionId: 'processDefid',
processDefinitionKey: 'processDefKey',
lastModified: null,
lastModifiedTo: null,
lastModifiedFrom: null,
completedDateType: DateCloudFilterType.NO_DATE,
startedDateType: DateCloudFilterType.NO_DATE,
_completedFrom: null,
_completedTo: null,
startedDate: null,
_startFrom: null,
_startTo: null
});
export const fakeProcessCloudFilterEntries = {
list: {
entries: [
{
entry: {
key: 'process-filters-mock-appName-mock-username',
value: JSON.stringify(fakeProcessCloudFilters)
}
},
{
entry: fakeProcessCloudFilters[1]
},
{
entry: fakeProcessCloudFilters[2]
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 3,
hasMoreItems: false,
totalItems: 3
}
}
};
export const fakeEmptyProcessCloudFilterEntries = {
list: {
entries: [],
pagination: {
skipCount: 0,
maxItems: 100,
count: 0,
hasMoreItems: false,
totalItems: 0
}
}
};
export const fakeProcessCloudFilterWithDifferentEntries = {
list: {
entries: [
{
entry: {
key: 'my-mock-key-1',
value: 'my-mock-value-2'
}
},
{
entry: {
key: 'my-mock-key-2',
value: 'my-mock-key-2'
}
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 4,
hasMoreItems: false,
totalItems: 2
}
}
};

View File

@@ -23,8 +23,7 @@ import { PROCESS_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.ser
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service'; import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { fakeEmptyProcessCloudFilterEntries, fakeProcessCloudFilterEntries, fakeProcessCloudFilters, fakeProcessCloudFilterWithDifferentEntries, fakeProcessFilter } from '../mock/process-filters-cloud.mock';
import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';
describe('ProcessFilterCloudService', () => { describe('ProcessFilterCloudService', () => {
let service: ProcessFilterCloudService; let service: ProcessFilterCloudService;
@@ -41,187 +40,6 @@ describe('ProcessFilterCloudService', () => {
email: 'fakeIdentity@email.com' email: 'fakeIdentity@email.com'
}; };
const fakeProcessFilter: ProcessFilterCloudModel = new ProcessFilterCloudModel({
name: 'MOCK_PROCESS_NAME_1',
id: '1',
key: 'all-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK_ALL',
order: 'DESC',
index: 2,
processName: 'process-name',
processDefinitionName: 'process-def-name',
processInstanceId: 'processinstanceid',
initiator: 'mockuser',
processDefinitionId: 'processDefid',
processDefinitionKey: 'processDefKey',
lastModified: null,
lastModifiedTo: null,
lastModifiedFrom: null,
completedDateType: DateCloudFilterType.NO_DATE,
startedDateType: DateCloudFilterType.NO_DATE,
_completedFrom: null,
_completedTo: null,
startedDate: null,
_startFrom: null,
_startTo: null
});
const fakeProcessCloudFilterEntries = {
list: {
entries: [
{
entry: {
key: 'process-filters-mock-appName-mock-username',
value: JSON.stringify([
{
name: 'MOCK_PROCESS_NAME_1',
id: '1',
key: 'all-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK_ALL',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_2',
id: '2',
key: 'run-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-RUNNING',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_3',
id: '3',
key: 'complete-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-COMPLETED',
order: 'DESC'
}
])
}
},
{
entry: {
key: 'mock-key-2',
value: {
name: 'MOCK_PROCESS_NAME_2',
id: '2',
key: 'run-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-RUNNING',
order: 'DESC'
}
}
},
{
entry: {
key: 'mock-key-3',
value: {
name: 'MOCK_PROCESS_NAME_3',
id: '3',
key: 'complete-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-COMPLETED',
order: 'DESC'
}
}
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 3,
hasMoreItems: false,
totalItems: 3
}
}
};
const fakeEmptyProcessCloudFilterEntries = {
list: {
entries: [],
pagination: {
skipCount: 0,
maxItems: 100,
count: 0,
hasMoreItems: false,
totalItems: 0
}
}
};
const fakeProcessCloudFilterWithDifferentEntries = {
list: {
entries: [
{
entry: {
key: 'my-mock-key-1',
value: 'my-mock-value-2'
}
},
{
entry: {
key: 'my-mock-key-2',
value: 'my-mock-key-2'
}
}
],
pagination: {
skipCount: 0,
maxItems: 100,
count: 4,
hasMoreItems: false,
totalItems: 2
}
}
};
const fakeProcessCloudFilters = [
{
name: 'MOCK_PROCESS_NAME_1',
id: '1',
key: 'all-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK_ALL',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_2',
id: '2',
key: 'run-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-RUNNING',
order: 'DESC'
},
{
name: 'MOCK_PROCESS_NAME_3',
id: '3',
key: 'complete-mock-process',
icon: 'adjust',
appName: 'mock-appName',
sort: 'startDate',
status: 'MOCK-COMPLETED',
order: 'DESC'
}
];
setupTestBed({ setupTestBed({
imports: [ imports: [
TranslateModule.forRoot(), TranslateModule.forRoot(),

View File

@@ -1,6 +1,6 @@
<ng-container *ngIf="filters$ | async as filterList; else loading"> <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-filters__entry" [class.adf-active]="currentFilter === filter">
<button (click)="selectFilterAndEmit(filter)" <button (click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate" [attr.aria-label]="filter.name | translate"
[id]="filter.id" [id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'" [attr.data-automation-id]="filter.key + '_filter'"
@@ -17,4 +17,4 @@
<mat-spinner></mat-spinner> <mat-spinner></mat-spinner>
</div> </div>
</ng-container> </ng-container>
</ng-template> </ng-template>

View File

@@ -254,22 +254,35 @@ describe('ServiceTaskFiltersCloudComponent', () => {
})); }));
it('should emit an event when a filter is selected', async(() => { it('should emit the selected filter based on the filterParam input', async () => {
spyOn(serviceTaskFilterCloudService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(serviceTaskFilterCloudService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
spyOn(component.filterSelected, 'emit');
component.filterParam = { id: '12' }; const filterParam = { id: '10' };
const change = new SimpleChange(null, filterParam, true);
component.filterParam = filterParam;
const appName = 'my-app-1'; component.ngOnChanges({ 'filterParam': change });
const change = new SimpleChange(null, appName, true); fixture.detectChanges();
component.ngOnChanges({ 'appName': change });
expect(component.filterSelected.emit).toHaveBeenCalledWith(fakeGlobalServiceFilters[0]);
});
it('should filterClicked emit when a filter is clicked from the UI', async () => {
spyOn(serviceTaskFilterCloudService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
spyOn(component.filterClicked, 'emit');
fixture.detectChanges(); fixture.detectChanges();
spyOn(component, 'selectFilterAndEmit').and.stub(); await fixture.whenStable();
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeGlobalServiceFilters[1].key}_filter"]`);
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeGlobalServiceFilters[0].key}_filter"]`);
filterButton.click(); filterButton.click();
expect(component.selectFilterAndEmit).toHaveBeenCalledWith(fakeGlobalServiceFilters[1]);
})); fixture.detectChanges();
await fixture.whenStable();
expect(component.filterClicked.emit).toHaveBeenCalledWith(fakeGlobalServiceFilters[0]);
});
it('should reset the filter when the param is undefined', async(() => { it('should reset the filter when the param is undefined', async(() => {
spyOn(serviceTaskFilterCloudService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(serviceTaskFilterCloudService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);

View File

@@ -30,9 +30,13 @@ import { ServiceTaskFilterCloudService } from '../services/service-task-filter-c
}) })
export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges { export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges {
/** Emitted when a filter in the list is clicked. */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterClick = new EventEmitter<ServiceTaskFilterCloudModel>(); filterSelected = new EventEmitter<ServiceTaskFilterCloudModel>();
/** Emitted when a filter is being clicked from the UI. */
@Output()
filterClicked = new EventEmitter<ServiceTaskFilterCloudModel>();
filters$: Observable<ServiceTaskFilterCloudModel[]>; filters$: Observable<ServiceTaskFilterCloudModel[]>;
filters: ServiceTaskFilterCloudModel[] = []; filters: ServiceTaskFilterCloudModel[] = [];
@@ -91,7 +95,19 @@ export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudCompon
public selectFilterAndEmit(newParamFilter: FilterParamsModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
if (newParamFilter) { if (newParamFilter) {
this.selectFilter(newParamFilter); this.selectFilter(newParamFilter);
this.filterClick.emit(this.currentFilter); this.filterSelected.emit(this.currentFilter);
} else {
this.currentFilter = undefined;
}
}
/**
* Selects and emits the clicked filter.
*/
public onFilterClick(filter: FilterParamsModel) {
if (filter) {
this.selectFilter(filter);
this.filterClicked.emit(this.currentFilter);
} else { } else {
this.currentFilter = undefined; this.currentFilter = undefined;
} }

View File

@@ -254,22 +254,35 @@ describe('TaskFiltersCloudComponent', () => {
})); }));
it('should emit an event when a filter is selected', async(() => { it('should emit the selected filter based on the filterParam input', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
spyOn(component.filterSelected, 'emit');
component.filterParam = { id: '12' }; const filterParam = { id: '10' };
const change = new SimpleChange(null, filterParam, true);
component.filterParam = filterParam;
const appName = 'my-app-1'; component.ngOnChanges({ 'filterParam': change });
const change = new SimpleChange(null, appName, true); fixture.detectChanges();
component.ngOnChanges({ 'appName': change });
expect(component.filterSelected.emit).toHaveBeenCalledWith(fakeGlobalFilter[0]);
}));
it('should filterClicked emit when a filter is clicked from the UI', async () => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
spyOn(component.filterClicked, 'emit');
fixture.detectChanges(); fixture.detectChanges();
spyOn(component, 'selectFilterAndEmit').and.stub(); await fixture.whenStable();
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeGlobalFilter[1].key}_filter"]`);
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeGlobalFilter[0].key}_filter"]`);
filterButton.click(); filterButton.click();
expect(component.selectFilterAndEmit).toHaveBeenCalledWith(fakeGlobalFilter[1]);
})); fixture.detectChanges();
await fixture.whenStable();
expect(component.filterClicked.emit).toHaveBeenCalledWith(fakeGlobalFilter[0]);
});
it('should reset the filter when the param is undefined', async(() => { it('should reset the filter when the param is undefined', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);

View File

@@ -29,9 +29,13 @@ import { BaseTaskFiltersCloudComponent } from './base-task-filters-cloud.compone
styleUrls: ['base-task-filters-cloud.component.scss'] styleUrls: ['base-task-filters-cloud.component.scss']
}) })
export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges { export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent implements OnInit, OnChanges {
/** Emitted when a filter in the list is clicked. */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterClick = new EventEmitter<TaskFilterCloudModel>(); filterSelected = new EventEmitter<TaskFilterCloudModel>();
/** Emitted when a filter is being clicked from the UI. */
@Output()
filterClicked = new EventEmitter<TaskFilterCloudModel>();
filters$: Observable<TaskFilterCloudModel[]>; filters$: Observable<TaskFilterCloudModel[]>;
filters: TaskFilterCloudModel[] = []; filters: TaskFilterCloudModel[] = [];
@@ -90,7 +94,19 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
public selectFilterAndEmit(newParamFilter: FilterParamsModel) { public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
if (newParamFilter) { if (newParamFilter) {
this.selectFilter(newParamFilter); this.selectFilter(newParamFilter);
this.filterClick.emit(this.currentFilter); this.filterSelected.emit(this.currentFilter);
} else {
this.currentFilter = undefined;
}
}
/**
* Selects and emits the clicked filter.
*/
public onFilterClick(filter: FilterParamsModel) {
if (filter) {
this.selectFilter(filter);
this.filterClicked.emit(this.currentFilter);
} else { } else {
this.currentFilter = undefined; this.currentFilter = undefined;
} }

View File

@@ -22,7 +22,7 @@ export const fakeGlobalFilter = [
name: 'FakeInvolvedTasks', name: 'FakeInvolvedTasks',
key: 'fake-involved-tasks', key: 'fake-involved-tasks',
icon: 'adjust', icon: 'adjust',
id: 10, id: '10',
status: 'open', status: 'open',
assignee: 'fake-involved' assignee: 'fake-involved'
}), }),
@@ -30,7 +30,7 @@ export const fakeGlobalFilter = [
name: 'FakeMyTasks1', name: 'FakeMyTasks1',
key: 'fake-my-tast1', key: 'fake-my-tast1',
icon: 'done', icon: 'done',
id: 11, id: '11',
status: 'open', status: 'open',
assignee: 'fake-assignee' assignee: 'fake-assignee'
}), }),
@@ -38,7 +38,7 @@ export const fakeGlobalFilter = [
name: 'FakeMyTasks2', name: 'FakeMyTasks2',
key: 'fake-my-tast2', key: 'fake-my-tast2',
icon: 'inbox', icon: 'inbox',
id: 12, id: '12',
status: 'open', status: 'open',
assignee: 'fake-assignee' assignee: 'fake-assignee'
}) })

View File

@@ -0,0 +1,51 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FilterProcessRepresentationModel } from '../../process-list/models/filter-process.model';
export let fakeProcessFilters = [
new FilterProcessRepresentationModel({
id: 10,
name: 'FakeCompleted',
icon: 'glyphicon-th',
filter: { state: 'open', assignment: 'fake-involved' }
}),
new FilterProcessRepresentationModel({
id: 20,
name: 'FakeAll',
icon: 'glyphicon-random',
filter: { state: 'open', assignment: 'fake-assignee' }
}),
new FilterProcessRepresentationModel({
id: 30,
name: 'Running',
icon: 'glyphicon-ok-sign',
filter: { state: 'open', assignment: 'fake-running' }
})
];
export let fakeProcessFiltersResponse = {
size: 1, total: 1, start: 0,
data: [new FilterProcessRepresentationModel({
'name': 'Running',
'appId': '22',
'id': 333,
'recent': true,
'icon': 'glyphicon-random',
'filter': { 'sort': 'created-desc', 'name': '', 'state': 'running' }
})]
};

View File

@@ -16,26 +16,8 @@
*/ */
import { AppDefinitionRepresentationModel, TaskDetailsModel } from '../../task-list'; import { AppDefinitionRepresentationModel, TaskDetailsModel } from '../../task-list';
import { FilterProcessRepresentationModel } from '../../process-list/models/filter-process.model';
import { ProcessDefinitionRepresentation } from '../../process-list/models/process-definition.model'; import { ProcessDefinitionRepresentation } from '../../process-list/models/process-definition.model';
export let fakeProcessFilters = {
size: 1, total: 1, start: 0,
data: [new FilterProcessRepresentationModel({
'name': 'Running',
'appId': '22',
'id': 333,
'recent': true,
'icon': 'glyphicon-random',
'filter': { 'sort': 'created-desc', 'name': '', 'state': 'running' }
})]
};
export let fakeEmptyFilters = {
size: 0, total: 0, start: 0,
data: []
};
export let mockError = { export let mockError = {
message: null, message: null,
messageKey: 'GENERAL.ERROR.FORBIDDEN' messageKey: 'GENERAL.ERROR.FORBIDDEN'

View File

@@ -26,3 +26,5 @@ export * from './task/task-details.mock';
export * from './task/task-details.component.mock'; export * from './task/task-details.component.mock';
export * from './task/task-list.mock'; export * from './task/task-list.mock';
export * from './task/tasklist-service.mock'; export * from './task/tasklist-service.mock';
export * from './process/process-filters.mock';
export * from './task/task-filters.mock';

View File

@@ -0,0 +1,103 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AppDefinitionRepresentationModel, FilterRepresentationModel } from '../../task-list/models/filter.model';
export let fakeFiltersResponse = {
size: 2, total: 2, start: 0,
data: [
new AppDefinitionRepresentationModel(
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
}
),
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
}
]
};
export let fakeTaskFilters = [
new FilterRepresentationModel({
name: 'FakeInvolvedTasks',
icon: 'glyphicon-align-left',
id: 10,
filter: { state: 'open', assignment: 'fake-involved' }
}),
new FilterRepresentationModel({
name: 'FakeMyTasks1',
icon: 'glyphicon-ok-sign',
id: 11,
filter: { state: 'open', assignment: 'fake-assignee' }
}),
new FilterRepresentationModel({
name: 'FakeMyTasks2',
icon: 'glyphicon-inbox',
id: 12,
filter: { state: 'open', assignment: 'fake-assignee' }
})
];
export let fakeAppFilter = {
size: 1, total: 1, start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
}
]
};
export let fakeFilter = {
sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee'
};
export let fakeRepresentationFilter1: FilterRepresentationModel = new FilterRepresentationModel({
appId: 1,
name: 'CONTAIN FILTER',
recent: true,
icon: 'glyphicon-align-left',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'involved',
dueAfter: null,
dueBefore: null
}
});
export let fakeRepresentationFilter2: FilterRepresentationModel = new FilterRepresentationModel({
appId: 2,
name: 'NO TASK FILTER',
recent: false,
icon: 'glyphicon-inbox',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'assignee',
dueAfter: null,
dueBefore: null
}
});

View File

@@ -15,36 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { fakeAppFilter } from './task-filters.mock';
AppDefinitionRepresentationModel,
FilterRepresentationModel
} from '../../task-list/models/filter.model';
export let fakeFilters = {
size: 2, total: 2, start: 0,
data: [
new AppDefinitionRepresentationModel(
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
}
),
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
}
]
};
export let fakeAppFilter = {
size: 1, total: 1, start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
}
]
};
export let fakeApps = { export let fakeApps = {
size: 2, total: 2, start: 0, size: 2, total: 2, start: 0,
@@ -60,10 +31,6 @@ export let fakeApps = {
] ]
}; };
export let fakeFilter = {
sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee'
};
export let fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' }; export let fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
export let fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' }; export let fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' };
@@ -142,40 +109,6 @@ export let fakeTasksChecklist = {
] ]
}; };
export let fakeRepresentationFilter1: FilterRepresentationModel = new FilterRepresentationModel({
appId: 1,
name: 'CONTAIN FILTER',
recent: true,
icon: 'glyphicon-align-left',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'involved',
dueAfter: null,
dueBefore: null
}
});
export let fakeRepresentationFilter2: FilterRepresentationModel = new FilterRepresentationModel({
appId: 2,
name: 'NO TASK FILTER',
recent: false,
icon: 'glyphicon-inbox',
filter: {
processDefinitionId: null,
processDefinitionKey: null,
name: null,
state: 'open',
sort: 'created-desc',
assignment: 'assignee',
dueAfter: null,
dueBefore: null
}
});
export let fakeAppPromise = new Promise(function (resolve) { export let fakeAppPromise = new Promise(function (resolve) {
resolve(fakeAppFilter); resolve(fakeAppFilter);
}); });

View File

@@ -23,7 +23,7 @@ import { ProcessFilterService } from '../services/process-filter.service';
import { ProcessFiltersComponent } from './process-filters.component'; import { ProcessFiltersComponent } from './process-filters.component';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { fakeProcessFilters } from '../../mock'; import { fakeProcessFilters } from '../../mock/process/process-filters.mock';
import { ProcessTestingModule } from '../../testing/process.testing.module'; import { ProcessTestingModule } from '../../testing/process.testing.module';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -47,28 +47,7 @@ describe('ProcessFiltersComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ProcessFiltersComponent); fixture = TestBed.createComponent(ProcessFiltersComponent);
filterList = fixture.componentInstance; filterList = fixture.componentInstance;
fakeGlobalFilterPromise = Promise.resolve(fakeProcessFilters);
fakeGlobalFilterPromise = Promise.resolve([
new FilterProcessRepresentationModel({
id: 10,
name: 'FakeCompleted',
icon: 'glyphicon-th',
filter: { state: 'open', assignment: 'fake-involved' }
}),
new FilterProcessRepresentationModel({
id: 20,
name: 'FakeAll',
icon: 'glyphicon-random',
filter: { state: 'open', assignment: 'fake-assignee' }
}),
new FilterProcessRepresentationModel({
id: 30,
name: 'Running',
icon: 'glyphicon-ok-sign',
filter: { state: 'open', assignment: 'fake-running' }
})
]);
processFilterService = TestBed.inject(ProcessFilterService); processFilterService = TestBed.inject(ProcessFilterService);
appsProcessService = TestBed.inject(AppsProcessService); appsProcessService = TestBed.inject(AppsProcessService);
}); });
@@ -113,7 +92,7 @@ describe('ProcessFiltersComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should emit an event when a filter is selected', (done) => { it('should emit the selected filter based on the filterParam input', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(from(fakeGlobalFilterPromise)); spyOn(processFilterService, 'getProcessFilters').and.returnValue(from(fakeGlobalFilterPromise));
filterList.filterParam = new FilterProcessRepresentationModel({ id: 10 }); filterList.filterParam = new FilterProcessRepresentationModel({ id: 10 });
const appId = '1'; const appId = '1';
@@ -130,15 +109,33 @@ describe('ProcessFiltersComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should filterClicked emit when a filter is clicked from the UI', async () => {
filterList.filters = fakeProcessFilters;
spyOn(filterList.filterClicked, 'emit');
fixture.detectChanges();
await fixture.whenStable();
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeProcessFilters[0].name}_filter"]`);
filterButton.click();
expect(filterList.filterClicked.emit).toHaveBeenCalledWith(fakeProcessFilters[0]);
});
it('should reset selection when filterParam is a filter that does not exist', async () => { it('should reset selection when filterParam is a filter that does not exist', async () => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(from(fakeGlobalFilterPromise)); spyOn(processFilterService, 'getProcessFilters').and.returnValue(from(fakeGlobalFilterPromise));
filterList.currentFilter = fakeProcessFilters.data[0];
filterList.filterParam = new FilterProcessRepresentationModel({ name: 'non-existing-filter' }); const nonExistingFilterParam = { name: 'non-existing-filter' };
const appId = '1'; const appId = '1';
const change = new SimpleChange(null, appId, true); const change = new SimpleChange(null, appId, true);
filterList.currentFilter = nonExistingFilterParam;
filterList.filterParam = new FilterProcessRepresentationModel(nonExistingFilterParam);
filterList.ngOnChanges({ 'appId': change }); filterList.ngOnChanges({ 'appId': change });
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
expect(filterList.currentFilter).toBe(undefined); expect(filterList.currentFilter).toBe(undefined);
}); });
@@ -199,7 +196,7 @@ describe('ProcessFiltersComponent', () => {
filter: { state: 'open', assignment: 'fake-involved' } filter: { state: 'open', assignment: 'fake-involved' }
}); });
filterList.filterClick.subscribe((filter: FilterProcessRepresentationModel) => { filterList.filterClicked.subscribe((filter: FilterProcessRepresentationModel) => {
expect(filter).toBeDefined(); expect(filter).toBeDefined();
expect(filter).toEqual(currentFilter); expect(filter).toEqual(currentFilter);
expect(filterList.currentFilter).toEqual(currentFilter); expect(filterList.currentFilter).toEqual(currentFilter);

View File

@@ -36,9 +36,9 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
@Input() @Input()
filterParam: FilterProcessRepresentationModel; filterParam: FilterProcessRepresentationModel;
/** Emitted when the user selects a filter from the list. */ /** Emitted when a filter is being clicked from the UI. */
@Output() @Output()
filterClick: EventEmitter<UserProcessInstanceFilterRepresentation> = new EventEmitter<UserProcessInstanceFilterRepresentation>(); filterClicked: EventEmitter<UserProcessInstanceFilterRepresentation> = new EventEmitter<UserProcessInstanceFilterRepresentation>();
/** Emitted when the list of filters has been successfully loaded from the server. */ /** Emitted when the list of filters has been successfully loaded from the server. */
@Output() @Output()
@@ -60,9 +60,9 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
@Input() @Input()
showIcon: boolean = true; showIcon: boolean = true;
/** Emitted when a process filter is selected. */ /** Emitted when a filter is being selected based on the filterParam input. */
@Output() @Output()
filterSelected: EventEmitter<ProcessInstanceFilterRepresentation> = new EventEmitter<ProcessInstanceFilterRepresentation>(); filterSelected: EventEmitter<UserProcessInstanceFilterRepresentation> = new EventEmitter<UserProcessInstanceFilterRepresentation>();
filter$: Observable<ProcessInstanceFilterRepresentation>; filter$: Observable<ProcessInstanceFilterRepresentation>;
@@ -149,7 +149,7 @@ export class ProcessFiltersComponent implements OnInit, OnChanges {
selectFilter(filter: ProcessInstanceFilterRepresentation) { selectFilter(filter: ProcessInstanceFilterRepresentation) {
this.currentFilter = filter; this.currentFilter = filter;
this.active = true; this.active = true;
this.filterClick.emit(filter); this.filterClicked.emit(filter);
} }
/** /**

View File

@@ -16,7 +16,7 @@
*/ */
import { async } from '@angular/core/testing'; import { async } from '@angular/core/testing';
import { mockError, fakeProcessFilters } from '../../mock'; import { mockError, fakeProcessFiltersResponse } from '../../mock';
import { FilterProcessRepresentationModel } from '../models/filter-process.model'; import { FilterProcessRepresentationModel } from '../models/filter-process.model';
import { ProcessFilterService } from './process-filter.service'; import { ProcessFilterService } from './process-filter.service';
import { AlfrescoApiServiceMock, AlfrescoApiService, AppConfigService, import { AlfrescoApiServiceMock, AlfrescoApiService, AppConfigService,
@@ -50,7 +50,7 @@ describe('Process filter', () => {
beforeEach(() => { beforeEach(() => {
getFilters = spyOn(alfrescoApi.activiti.userFiltersApi, 'getUserProcessInstanceFilters') getFilters = spyOn(alfrescoApi.activiti.userFiltersApi, 'getUserProcessInstanceFilters')
.and .and
.returnValue(Promise.resolve(fakeProcessFilters)); .returnValue(Promise.resolve(fakeProcessFiltersResponse));
jasmine.Ajax.install(); jasmine.Ajax.install();
}); });
@@ -164,7 +164,7 @@ describe('Process filter', () => {
.callFake((processfilter: FilterProcessRepresentationModel) => Promise.resolve(processfilter)); .callFake((processfilter: FilterProcessRepresentationModel) => Promise.resolve(processfilter));
}); });
const filter = fakeProcessFilters.data[0]; const filter = fakeProcessFiltersResponse.data[0];
it('should call the API to create the filter', () => { it('should call the API to create the filter', () => {
service.addProcessFilter(filter); service.addProcessFilter(filter);

View File

@@ -1,5 +1,5 @@
<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]="currentFilter === filter">
<button (click)="selectFilterAndEmit(filter)" <button (click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate" [attr.aria-label]="filter.name | translate"
[id]="filter.id" [id]="filter.id"
[attr.data-automation-id]="filter.name + '_filter'" [attr.data-automation-id]="filter.name + '_filter'"
@@ -10,4 +10,4 @@
</ng-container> </ng-container>
<span data-automation-id="adf-filter-label" class="adf-filter-action-button__label">{{ filter.name | translate }}</span> <span data-automation-id="adf-filter-label" class="adf-filter-action-button__label">{{ filter.name | translate }}</span>
</button> </button>
</div> </div>

View File

@@ -26,6 +26,7 @@ import { TaskFiltersComponent } from './task-filters.component';
import { ProcessTestingModule } from '../../testing/process.testing.module'; import { ProcessTestingModule } from '../../testing/process.testing.module';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { fakeTaskFilters } from '../../mock/task/task-filters.mock';
describe('TaskFiltersComponent', () => { describe('TaskFiltersComponent', () => {
@@ -33,28 +34,8 @@ describe('TaskFiltersComponent', () => {
let taskFilterService: TaskFilterService; let taskFilterService: TaskFilterService;
let appsProcessService: AppsProcessService; let appsProcessService: AppsProcessService;
const fakeGlobalFilter = [];
fakeGlobalFilter.push(new FilterRepresentationModel({
name: 'FakeInvolvedTasks',
icon: 'glyphicon-align-left',
id: 10,
filter: { state: 'open', assignment: 'fake-involved' }
}));
fakeGlobalFilter.push(new FilterRepresentationModel({
name: 'FakeMyTasks1',
icon: 'glyphicon-ok-sign',
id: 11,
filter: { state: 'open', assignment: 'fake-assignee' }
}));
fakeGlobalFilter.push(new FilterRepresentationModel({
name: 'FakeMyTasks2',
icon: 'glyphicon-inbox',
id: 12,
filter: { state: 'open', assignment: 'fake-assignee' }
}));
const fakeGlobalFilterPromise = new Promise(function (resolve) { const fakeGlobalFilterPromise = new Promise(function (resolve) {
resolve(fakeGlobalFilter); resolve(fakeTaskFilters);
}); });
const fakeGlobalEmptyFilter = { const fakeGlobalEmptyFilter = {
@@ -217,17 +198,31 @@ describe('TaskFiltersComponent', () => {
}); });
}); });
it('should emit an event when a filter is selected', (done) => { it('should emit the selected filter based on the filterParam input', () => {
const currentFilter = fakeGlobalFilter[0]; spyOn(component.filterSelected, 'emit');
component.filters = fakeGlobalFilter; component.filters = fakeTaskFilters;
component.filterClick.subscribe((filter: FilterRepresentationModel) => {
expect(filter).toBeDefined();
expect(filter).toEqual(currentFilter);
expect(component.currentFilter).toEqual(currentFilter);
done();
});
component.selectFilterAndEmit(currentFilter); const filterParam = new FilterParamsModel({ id: 10 });
const change = new SimpleChange(null, filterParam, true);
component.filterParam = filterParam;
component.ngOnChanges({ 'filterParam': change });
fixture.detectChanges();
expect(component.filterSelected.emit).toHaveBeenCalledWith(fakeTaskFilters[0]);
});
it('should filterClicked emit when a filter is clicked from the UI', async () => {
component.filters = fakeTaskFilters;
spyOn(component.filterClicked, 'emit');
fixture.detectChanges();
await fixture.whenStable();
const filterButton = fixture.debugElement.nativeElement.querySelector(`[data-automation-id="${fakeTaskFilters[0].name}_filter"]`);
filterButton.click();
expect(component.filterClicked.emit).toHaveBeenCalledWith(fakeTaskFilters[0]);
}); });
it('should reload filters by appId on binding changes', () => { it('should reload filters by appId on binding changes', () => {
@@ -251,25 +246,25 @@ describe('TaskFiltersComponent', () => {
}); });
it('should change current filter when filterParam (id) changes', async () => { it('should change current filter when filterParam (id) changes', async () => {
component.filters = fakeGlobalFilter; component.filters = fakeTaskFilters;
component.currentFilter = null; component.currentFilter = null;
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(component.currentFilter.id).toEqual(fakeGlobalFilter[2].id); expect(component.currentFilter.id).toEqual(fakeTaskFilters[2].id);
}); });
const change = new SimpleChange(null, { id: fakeGlobalFilter[2].id }, true); const change = new SimpleChange(null, { id: fakeTaskFilters[2].id }, true);
component.ngOnChanges({ 'filterParam': change }); component.ngOnChanges({ 'filterParam': change });
}); });
it('should change current filter when filterParam (name) changes', async () => { it('should change current filter when filterParam (name) changes', async () => {
component.filters = fakeGlobalFilter; component.filters = fakeTaskFilters;
component.currentFilter = null; component.currentFilter = null;
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(component.currentFilter.name).toEqual(fakeGlobalFilter[2].name); expect(component.currentFilter.name).toEqual(fakeTaskFilters[2].name);
}); });
const change = new SimpleChange(null, { name: fakeGlobalFilter[2].name }, true); const change = new SimpleChange(null, { name: fakeTaskFilters[2].name }, true);
component.ngOnChanges({ 'filterParam': change }); component.ngOnChanges({ 'filterParam': change });
}); });
@@ -284,12 +279,11 @@ describe('TaskFiltersComponent', () => {
}); });
it('should return the current filter after one is selected', () => { it('should return the current filter after one is selected', () => {
const filter = fakeGlobalFilter[1]; component.filters = fakeTaskFilters;
component.filters = fakeGlobalFilter;
expect(component.currentFilter).toBeUndefined(); expect(component.currentFilter).toBeUndefined();
component.selectFilter(filter); component.selectFilter(fakeTaskFilters[1]);
expect(component.getCurrentFilter()).toBe(filter); expect(component.getCurrentFilter()).toBe(fakeTaskFilters[1]);
}); });
it('should load default list when app id is null', () => { it('should load default list when app id is null', () => {
@@ -306,7 +300,7 @@ describe('TaskFiltersComponent', () => {
name: 'FakeMyTasks', name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' } filter: { state: 'open', assignment: 'fake-assignee' }
}); });
component.filters = fakeGlobalFilter; component.filters = fakeTaskFilters;
component.currentFilter = filter; component.currentFilter = filter;
spyOn(taskListService, 'isTaskRelatedToFilter').and.returnValue(of(null)); spyOn(taskListService, 'isTaskRelatedToFilter').and.returnValue(of(null));
component.selectFilterWithTask('111'); component.selectFilterWithTask('111');
@@ -348,7 +342,7 @@ describe('TaskFiltersComponent', () => {
it('should reset selection when filterParam is a filter that does not exist', async () => { it('should reset selection when filterParam is a filter that does not exist', async () => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalFilterPromise)); spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(from(fakeGlobalFilterPromise));
component.currentFilter = fakeGlobalFilter[0]; component.currentFilter = fakeTaskFilters[0];
component.filterParam = new FilterRepresentationModel( {name: 'non-existing-filter'}); component.filterParam = new FilterRepresentationModel( {name: 'non-existing-filter'});
const appId = '1'; const appId = '1';
const change = new SimpleChange(null, appId, true); const change = new SimpleChange(null, appId, true);

View File

@@ -36,9 +36,13 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
@Input() @Input()
filterParam: FilterParamsModel; filterParam: FilterParamsModel;
/** Emitted when a filter in the list is clicked. */ /** Emitted when a filter is being clicked from the UI. */
@Output() @Output()
filterClick: EventEmitter<FilterRepresentationModel> = new EventEmitter<FilterRepresentationModel>(); filterClicked: EventEmitter<FilterRepresentationModel> = new EventEmitter<FilterRepresentationModel>();
/** Emitted when a filter is being selected based on the filterParam input. */
@Output()
filterSelected: EventEmitter<FilterRepresentationModel> = new EventEmitter<FilterRepresentationModel>();
/** Emitted when the list is loaded. */ /** Emitted when the list is loaded. */
@Output() @Output()
@@ -86,7 +90,7 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
} else if (appId && appId.currentValue !== appId.previousValue) { } else if (appId && appId.currentValue !== appId.previousValue) {
this.getFiltersByAppId(appId.currentValue); this.getFiltersByAppId(appId.currentValue);
} else if (filter && filter.currentValue !== filter.previousValue) { } else if (filter && filter.currentValue !== filter.previousValue) {
this.selectFilter(filter.currentValue); this.selectFilterAndEmit(filter.currentValue);
} }
} }
@@ -170,7 +174,15 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
public selectFilterAndEmit(newFilter: FilterParamsModel) { public selectFilterAndEmit(newFilter: FilterParamsModel) {
this.selectFilter(newFilter); this.selectFilter(newFilter);
this.filterClick.emit(this.currentFilter); this.filterSelected.emit(this.currentFilter);
}
/**
* Selects and emits the clicked filter.
*/
onFilterClick(filter: FilterParamsModel) {
this.selectFilter(filter);
this.filterClicked.emit(this.currentFilter);
} }
/** /**
@@ -189,7 +201,7 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
() => { () => {
if (filteredFilterList.length > 0) { if (filteredFilterList.length > 0) {
this.selectFilter(filteredFilterList[0]); this.selectFilter(filteredFilterList[0]);
this.filterClick.emit(this.currentFilter); this.filterSelected.emit(this.currentFilter);
} }
}); });
} }

View File

@@ -16,7 +16,8 @@
*/ */
import { async } from '@angular/core/testing'; import { async } from '@angular/core/testing';
import { fakeAppFilter, fakeAppPromise, fakeFilters } from '../../mock'; import { fakeAppPromise } from '../../mock';
import { fakeFiltersResponse, fakeAppFilter } from '../../mock/task/task-filters.mock';
import { FilterRepresentationModel } from '../models/filter.model'; import { FilterRepresentationModel } from '../models/filter.model';
import { TaskFilterService } from './task-filter.service'; import { TaskFilterService } from './task-filter.service';
import { AlfrescoApiServiceMock, LogService, AppConfigService, setupTestBed, CoreModule, StorageService } from '@alfresco/adf-core'; import { AlfrescoApiServiceMock, LogService, AppConfigService, setupTestBed, CoreModule, StorageService } from '@alfresco/adf-core';
@@ -58,7 +59,7 @@ describe('Activiti Task filter Service', () => {
jasmine.Ajax.requests.mostRecent().respondWith({ jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200, 'status': 200,
contentType: 'application/json', contentType: 'application/json',
responseText: JSON.stringify(fakeFilters) responseText: JSON.stringify(fakeFiltersResponse)
}); });
}); });
@@ -76,7 +77,7 @@ describe('Activiti Task filter Service', () => {
jasmine.Ajax.requests.mostRecent().respondWith({ jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200, 'status': 200,
contentType: 'application/json', contentType: 'application/json',
responseText: JSON.stringify(fakeFilters) responseText: JSON.stringify(fakeFiltersResponse)
}); });
}); });
@@ -95,7 +96,7 @@ describe('Activiti Task filter Service', () => {
jasmine.Ajax.requests.mostRecent().respondWith({ jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200, 'status': 200,
contentType: 'application/json', contentType: 'application/json',
responseText: JSON.stringify(fakeFilters) responseText: JSON.stringify(fakeFiltersResponse)
}); });
}); });

View File

@@ -20,11 +20,8 @@ import { UserProcessModel, setupTestBed, CoreModule, StorageService, AlfrescoApi
import { of } from 'rxjs'; import { of } from 'rxjs';
import { import {
fakeCompletedTaskList, fakeCompletedTaskList,
fakeFilter,
fakeFormList, fakeFormList,
fakeOpenTaskList, fakeOpenTaskList,
fakeRepresentationFilter1,
fakeRepresentationFilter2,
fakeTaskDetails, fakeTaskDetails,
fakeTaskList, fakeTaskList,
fakeTasksChecklist, fakeTasksChecklist,
@@ -32,6 +29,7 @@ import {
fakeUser2, fakeUser2,
secondFakeTaskList secondFakeTaskList
} from '../../mock'; } from '../../mock';
import { fakeRepresentationFilter1, fakeRepresentationFilter2, fakeFilter } from '../../mock/task/task-filters.mock';
import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model'; import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from './tasklist.service'; import { TaskListService } from './tasklist.service';