mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
AAE-26192 New task search API (#10319)
* AAE-26192 New task search API * small changes * use DI instead of inputs * cr * fix units
This commit is contained in:
parent
2303cb2d59
commit
0a89d9be97
@ -34,7 +34,8 @@ Allows one or more users to be selected (with auto-suggestion) based on the inpu
|
||||
| required | `boolean` | false | Mark this field as required |
|
||||
| roles | `string[]` | | Role names of the users to be listed. |
|
||||
| searchUserCtrl | `FormControl<any>` | | FormControl to search the user |
|
||||
| title | `string` | | Placeholder translation key |
|
||||
| title | `string` | | Label translation key |
|
||||
| placeholder | `string` | | Placeholder for the input field |
|
||||
| hideInputOnSingleSelection | `boolean` | false | Hide the input field when a user is selected in single selection mode. The input will be shown again when the user is removed using the icon on the chip. |
|
||||
| formFieldAppearance | [`MatFormFieldAppearance`](https://material.angular.io/components/form-field/api#MatFormFieldAppearance) | "fill" | Material form field appearance (fill / outline). |
|
||||
| formFieldSubscriptSizing | [`SubscriptSizing`](https://material.angular.io/components/form-field/api#SubscriptSizing) | "fixed" | Material form field subscript sizing (fixed / dynamic). |
|
||||
|
@ -87,6 +87,12 @@ when the task list is empty:
|
||||
| standalone | `boolean` | false | Filter the tasks. Display only the tasks that belong to a process in case is false or tasks that doesn't belong to a process in case of true. |
|
||||
| status | `string` | "" | Filter the tasks. Display only tasks with status equal to the supplied value. |
|
||||
| stickyHeader | `boolean` | false | Toggles the sticky header mode. |
|
||||
| names | `string[]` | [] | Filter the tasks. Display only tasks with names matching any of the supplied strings. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
| processDefinitionNames | `string[]` | [] | Filter the tasks. Display only tasks under provided processes. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
| statuses | `string[]` | [] | Filter the tasks. Display only tasks with provided statuses. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
| assignees | `string[]` | [] | Filter the tasks. Display only tasks with assignees whose usernames are present in the array. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
| priorities | `string[]` | [] | Filter the tasks. Display only tasks with provided priorities. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
| completedByUsers | `string[]` | [] | Filter the tasks. Display only tasks completed by users whose usernames are present in the array. This input will be used only if `TASK_SEARCH_API_METHOD_TOKEN` is provided with `POST` value. |
|
||||
|
||||
### Events
|
||||
|
||||
|
@ -15,7 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Pagination } from '@alfresco/js-api';
|
||||
import { TaskListCloudSortingModel } from './task-list-sorting.model';
|
||||
import { TaskFilterCloudModel } from '../task/task-filters/models/filter-cloud.model';
|
||||
|
||||
export class TaskQueryCloudRequestModel {
|
||||
appName: string;
|
||||
@ -90,3 +92,102 @@ export class TaskQueryCloudRequestModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TaskListRequestTaskVariableFilter {
|
||||
name?: string;
|
||||
type?: string;
|
||||
value?: string;
|
||||
operator?: string;
|
||||
}
|
||||
|
||||
export class TaskListRequestModel {
|
||||
appName: string;
|
||||
pagination?: Pagination;
|
||||
sorting?: TaskListCloudSortingModel[];
|
||||
|
||||
onlyStandalone?: boolean;
|
||||
onlyRoot?: boolean;
|
||||
name?: string[];
|
||||
description?: string[];
|
||||
processDefinitionName?: string[];
|
||||
priority?: string[];
|
||||
status?: string[];
|
||||
completedBy?: string[];
|
||||
assignee?: string[];
|
||||
createdFrom?: string;
|
||||
createdTo?: string;
|
||||
lastModifiedFrom?: string;
|
||||
lastModifiedTo?: string;
|
||||
lastClaimedFrom?: string;
|
||||
lastClaimedTo?: string;
|
||||
dueDateFrom?: string;
|
||||
dueDateTo?: string;
|
||||
completedFrom?: string;
|
||||
completedTo?: string;
|
||||
candidateUserId?: string[];
|
||||
candidateGroupId?: string[];
|
||||
|
||||
taskVariableFilters?: TaskListRequestTaskVariableFilter[];
|
||||
variableKeys?: string[];
|
||||
|
||||
constructor(obj: Partial<TaskListRequestModel>) {
|
||||
if (!obj.appName) {
|
||||
throw new Error('appName not configured');
|
||||
}
|
||||
|
||||
this.appName = obj.appName;
|
||||
this.pagination = obj.pagination;
|
||||
this.sorting = obj.sorting;
|
||||
|
||||
this.onlyStandalone = obj.onlyStandalone;
|
||||
this.onlyRoot = obj.onlyRoot;
|
||||
this.name = obj.name;
|
||||
this.description = obj.description;
|
||||
this.processDefinitionName = obj.processDefinitionName;
|
||||
this.priority = obj.priority;
|
||||
this.status = obj.status;
|
||||
this.completedBy = obj.completedBy;
|
||||
this.assignee = obj.assignee;
|
||||
this.createdFrom = obj.createdFrom;
|
||||
this.createdTo = obj.createdTo;
|
||||
this.lastModifiedFrom = obj.lastModifiedFrom;
|
||||
this.lastModifiedTo = obj.lastModifiedTo;
|
||||
this.lastClaimedFrom = obj.lastClaimedFrom;
|
||||
this.lastClaimedTo = obj.lastClaimedTo;
|
||||
this.dueDateFrom = obj.dueDateFrom;
|
||||
this.dueDateTo = obj.dueDateTo;
|
||||
this.completedFrom = obj.completedFrom;
|
||||
this.completedTo = obj.completedTo;
|
||||
this.candidateUserId = obj.candidateUserId;
|
||||
this.candidateGroupId = obj.candidateGroupId;
|
||||
this.taskVariableFilters = obj.taskVariableFilters;
|
||||
this.variableKeys = obj.variableKeys;
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskFilterCloudAdapter extends TaskListRequestModel {
|
||||
constructor(filter: TaskFilterCloudModel) {
|
||||
super({
|
||||
appName: filter.appName,
|
||||
pagination: { maxItems: 25, skipCount: 0 },
|
||||
sorting: [{ orderBy: filter.sort, direction: filter.order }],
|
||||
|
||||
onlyStandalone: filter.standalone,
|
||||
name: filter.taskNames,
|
||||
processDefinitionName: filter.processDefinitionNames,
|
||||
priority: filter.priorities?.map((priority) => priority.toString()),
|
||||
status: filter.statuses,
|
||||
completedBy: filter.completedByUsers,
|
||||
assignee: filter.assignees,
|
||||
createdFrom: filter.createdFrom,
|
||||
createdTo: filter.createdTo,
|
||||
lastModifiedFrom: filter.lastModifiedFrom,
|
||||
lastModifiedTo: filter.lastModifiedTo,
|
||||
dueDateFrom: filter.dueDateFrom,
|
||||
dueDateTo: filter.dueDateTo,
|
||||
completedFrom: filter.completedFrom,
|
||||
completedTo: filter.completedTo,
|
||||
candidateGroupId: filter.candidateGroups?.map((group) => group.id)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,13 @@
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputFor]="userMultipleChipList"
|
||||
[required]="required"
|
||||
[placeholder]="placeholder"
|
||||
(focus)="setFocus(true)"
|
||||
(blur)="setFocus(false); markAsTouched()"
|
||||
class="adf-cloud-input"
|
||||
data-automation-id="adf-people-cloud-search-input" #userInput>
|
||||
data-automation-id="adf-people-cloud-search-input"
|
||||
#userInput
|
||||
>
|
||||
</mat-chip-grid>
|
||||
|
||||
|
||||
|
@ -119,11 +119,17 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy, After
|
||||
searchUserCtrl = new UntypedFormControl({ value: '', disabled: false });
|
||||
|
||||
/**
|
||||
* Placeholder translation key
|
||||
* Label translation key
|
||||
*/
|
||||
@Input()
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* Placeholder for the input field
|
||||
*/
|
||||
@Input()
|
||||
placeholder: string;
|
||||
|
||||
/**
|
||||
* Hide the matInput associated with the chip grid when a single user is selected in single selection mode.
|
||||
* The input will be shown again when the user is removed using the icon on the chip.
|
||||
|
@ -19,13 +19,12 @@ import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { BaseCloudService } from '../../../services/base-cloud.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface';
|
||||
import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { TaskCloudNodePaging } from '../../../models/task-cloud.model';
|
||||
import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProcessTaskListCloudService extends BaseCloudService implements TaskListCloudServiceInterface {
|
||||
export class ProcessTaskListCloudService extends BaseCloudService {
|
||||
/**
|
||||
* Finds a task using an object with optional query properties.
|
||||
*
|
||||
|
@ -28,3 +28,9 @@ export const PROCESS_FILTERS_SERVICE_TOKEN = new InjectionToken<PreferenceCloudS
|
||||
export const TASK_FILTERS_SERVICE_TOKEN = new InjectionToken<PreferenceCloudServiceInterface>('task-filters-cloud');
|
||||
|
||||
export const TASK_LIST_CLOUD_TOKEN = new InjectionToken<TaskListCloudServiceInterface>('task-list-cloud');
|
||||
|
||||
/**
|
||||
* Token used to indicate the API used to search for tasks.
|
||||
* 'POST' value should be provided only if the used Activiti version is 8.7.0 or higher.
|
||||
*/
|
||||
export const TASK_SEARCH_API_METHOD_TOKEN = new InjectionToken<'GET' | 'POST'>('task-search-method');
|
||||
|
@ -16,8 +16,26 @@
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model';
|
||||
import { TaskListRequestModel, TaskQueryCloudRequestModel } from '../models/filter-cloud-model';
|
||||
|
||||
export interface TaskListCloudServiceInterface {
|
||||
/**
|
||||
* Finds a task using an object with optional query properties.
|
||||
*
|
||||
* @deprecated From Activiti 8.7.0 forward, use TaskListCloudService.fetchTaskList instead.
|
||||
* @param requestNode Query object
|
||||
* @param queryUrl Query url
|
||||
* @returns Task information
|
||||
*/
|
||||
getTaskByRequest(requestNode: TaskQueryCloudRequestModel, queryUrl?: string): Observable<any>;
|
||||
|
||||
/**
|
||||
* Available from Activiti version 8.7.0 onwards.
|
||||
* Retrieves a list of tasks using an object with optional query properties.
|
||||
*
|
||||
* @param requestNode Query object
|
||||
* @param queryUrl Query url
|
||||
* @returns List of tasks
|
||||
*/
|
||||
fetchTaskList(requestNode: TaskListRequestModel, queryUrl?: string): Observable<any>;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,9 @@ import { debounceTime, takeUntil, tap } from 'rxjs/operators';
|
||||
import { BaseTaskFiltersCloudComponent } from './base-task-filters-cloud.component';
|
||||
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
|
||||
import { TaskCloudEngineEvent } from '../../../models/engine-event-cloud.model';
|
||||
import { TaskListCloudService } from '../../task-list/services/task-list-cloud.service';
|
||||
import { TaskFilterCloudAdapter } from '../../../models/filter-cloud-model';
|
||||
import { TASK_SEARCH_API_METHOD_TOKEN } from '../../../services/cloud-token.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-cloud-task-filters',
|
||||
@ -55,8 +58,10 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
|
||||
currentFiltersValues: { [key: string]: number } = {};
|
||||
|
||||
private readonly taskFilterCloudService = inject(TaskFilterCloudService);
|
||||
private readonly taskListCloudService = inject(TaskListCloudService);
|
||||
private readonly translationService = inject(TranslationService);
|
||||
private readonly appConfigService = inject(AppConfigService);
|
||||
private readonly searchMethod = inject<'GET' | 'POST'>(TASK_SEARCH_API_METHOD_TOKEN, { optional: true });
|
||||
|
||||
ngOnInit() {
|
||||
this.enableNotifications = this.appConfigService.get('notifications', true);
|
||||
@ -114,24 +119,31 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
|
||||
|
||||
/**
|
||||
* Get current value for filter and check if value has changed
|
||||
*
|
||||
* @param filter filter
|
||||
*/
|
||||
updateFilterCounter(filter: TaskFilterCloudModel): void {
|
||||
if (filter?.showCounter) {
|
||||
this.taskFilterCloudService
|
||||
.getTaskFilterCounter(filter)
|
||||
.pipe(
|
||||
tap((filterCounter) => {
|
||||
this.checkIfFilterValuesHasBeenUpdated(filter.key, filterCounter);
|
||||
})
|
||||
)
|
||||
.subscribe((data) => {
|
||||
this.counters = {
|
||||
...this.counters,
|
||||
[filter.key]: data
|
||||
};
|
||||
});
|
||||
if (!filter?.showCounter) {
|
||||
return;
|
||||
}
|
||||
this.fetchTaskFilterCounter(filter)
|
||||
.pipe(
|
||||
tap((filterCounter) => {
|
||||
this.checkIfFilterValuesHasBeenUpdated(filter.key, filterCounter);
|
||||
})
|
||||
)
|
||||
.subscribe((data) => {
|
||||
this.counters = {
|
||||
...this.counters,
|
||||
[filter.key]: data
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private fetchTaskFilterCounter(filter: TaskFilterCloudModel): Observable<number> {
|
||||
return this.searchMethod === 'POST'
|
||||
? this.taskListCloudService.getTaskListCounter(new TaskFilterCloudAdapter(filter))
|
||||
: this.taskFilterCloudService.getTaskFilterCounter(filter);
|
||||
}
|
||||
|
||||
initFilterCounterNotifications() {
|
||||
|
@ -21,6 +21,7 @@ import { TaskFilterCloudModel, ServiceTaskFilterCloudModel, AssignmentType, Task
|
||||
|
||||
export const fakeGlobalFilter: any[] = [
|
||||
{
|
||||
appName: 'fake-app-name',
|
||||
name: 'FakeInvolvedTasks',
|
||||
key: 'fake-involved-tasks',
|
||||
icon: 'adjust',
|
||||
@ -244,37 +245,37 @@ export const fakeTaskFilter = new TaskFilterCloudModel({
|
||||
status: 'ALL'
|
||||
});
|
||||
|
||||
export const fakeTaskCloudFilters = [
|
||||
{
|
||||
export const fakeTaskCloudFilters: TaskFilterCloudModel[] = [
|
||||
new TaskFilterCloudModel({
|
||||
name: 'FAKE_TASK_1',
|
||||
id: '1',
|
||||
key: 'all-fake-task',
|
||||
key: 'completed-fake-task',
|
||||
icon: 'adjust',
|
||||
appName: 'fakeAppName',
|
||||
sort: 'startDate',
|
||||
status: 'ALL',
|
||||
status: TaskStatusFilter.COMPLETED,
|
||||
order: 'DESC'
|
||||
},
|
||||
{
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'FAKE_TASK_2',
|
||||
id: '2',
|
||||
key: 'run-fake-task',
|
||||
icon: 'adjust',
|
||||
appName: 'fakeAppName',
|
||||
sort: 'startDate',
|
||||
status: 'RUNNING',
|
||||
status: TaskStatusFilter.ASSIGNED,
|
||||
order: 'DESC'
|
||||
},
|
||||
{
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'FAKE_TASK_3',
|
||||
id: '3',
|
||||
key: 'complete-fake-task',
|
||||
icon: 'adjust',
|
||||
appName: 'fakeAppName',
|
||||
sort: 'startDate',
|
||||
status: 'COMPLETED',
|
||||
status: TaskStatusFilter.COMPLETED,
|
||||
order: 'DESC'
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
export const taskNotifications = [
|
||||
@ -290,8 +291,8 @@ export const taskCloudEngineEventsMock = {
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultTaskFiltersMock = [
|
||||
{
|
||||
export const defaultTaskFiltersMock: TaskFilterCloudModel[] = [
|
||||
new TaskFilterCloudModel({
|
||||
name: 'CREATED_TASK_FILTER',
|
||||
id: '1',
|
||||
key: 'created',
|
||||
@ -300,8 +301,8 @@ export const defaultTaskFiltersMock = [
|
||||
sort: 'startDate',
|
||||
status: TaskStatusFilter.CREATED,
|
||||
order: 'DESC'
|
||||
},
|
||||
{
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'ASSIGNED_TASK_FILTER',
|
||||
id: '2',
|
||||
key: 'assigned',
|
||||
@ -310,8 +311,8 @@ export const defaultTaskFiltersMock = [
|
||||
sort: 'startDate',
|
||||
status: TaskStatusFilter.ASSIGNED,
|
||||
order: 'DESC'
|
||||
},
|
||||
{
|
||||
}),
|
||||
new TaskFilterCloudModel({
|
||||
name: 'COMPLETED_TASK_FILTER',
|
||||
id: '3',
|
||||
key: 'complete-fake-task',
|
||||
@ -320,7 +321,7 @@ export const defaultTaskFiltersMock = [
|
||||
sort: 'startDate',
|
||||
status: TaskStatusFilter.COMPLETED,
|
||||
order: 'DESC'
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
export const fakeFilterNotification: TaskDetailsCloudModel = {
|
||||
|
@ -25,7 +25,7 @@ import { ComponentSelectionMode } from '../../../types';
|
||||
import { IdentityGroupModel } from '../../../group/models/identity-group.model';
|
||||
import { IdentityUserModel } from '../../../people/models/identity-user.model';
|
||||
|
||||
export class TaskFilterCloudModel {
|
||||
export class TaskFilterCloudModel {
|
||||
id: string;
|
||||
name: string;
|
||||
key: string;
|
||||
@ -60,6 +60,13 @@ export class TaskFilterCloudModel {
|
||||
completedBy: IdentityUserModel;
|
||||
showCounter: boolean;
|
||||
|
||||
taskNames: string[] | null;
|
||||
statuses: TaskStatusFilter[] | null;
|
||||
assignees: string[] | null;
|
||||
processDefinitionNames: string[] | null;
|
||||
priorities: string[] | null;
|
||||
completedByUsers: string[] | null;
|
||||
|
||||
private _completedFrom: string;
|
||||
private _completedTo: string;
|
||||
private _dueDateFrom: string;
|
||||
@ -108,6 +115,13 @@ export class TaskFilterCloudModel {
|
||||
this.createdTo = obj._createdTo || null;
|
||||
this.candidateGroups = obj.candidateGroups || null;
|
||||
this.showCounter = obj.showCounter || false;
|
||||
|
||||
this.taskNames = obj.taskNames || null;
|
||||
this.statuses = obj.statuses || null;
|
||||
this.assignees = obj.assignees || null;
|
||||
this.processDefinitionNames = obj.processDefinitionNames || null;
|
||||
this.priorities = obj.priorities || null;
|
||||
this.completedByUsers = obj.completedByUsers || null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import { ProcessServiceCloudTestingModule } from '../../../testing/process-servi
|
||||
import { IdentityUserService } from '../../../people/services/identity-user.service';
|
||||
import { ApolloModule } from 'apollo-angular';
|
||||
import { StorageService } from '@alfresco/adf-core';
|
||||
import { TaskStatusFilter } from '../public-api';
|
||||
|
||||
describe('TaskFilterCloudService', () => {
|
||||
let service: TaskFilterCloudService;
|
||||
@ -46,18 +47,17 @@ describe('TaskFilterCloudService', () => {
|
||||
let createPreferenceSpy: jasmine.Spy;
|
||||
let getCurrentUserInfoSpy: jasmine.Spy;
|
||||
|
||||
const identityUserMock = { username: 'fakeusername', firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
|
||||
const identityUserMock = {
|
||||
username: 'fakeusername',
|
||||
firstName: 'fake-identity-first-name',
|
||||
lastName: 'fake-identity-last-name',
|
||||
email: 'fakeIdentity@email.com'
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
ProcessServiceCloudTestingModule,
|
||||
ApolloModule
|
||||
],
|
||||
providers: [
|
||||
{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: UserPreferenceCloudService }
|
||||
]
|
||||
imports: [HttpClientTestingModule, ProcessServiceCloudTestingModule, ApolloModule],
|
||||
providers: [{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: UserPreferenceCloudService }]
|
||||
});
|
||||
service = TestBed.inject(TaskFilterCloudService);
|
||||
notificationCloudService = TestBed.inject(NotificationCloudService);
|
||||
@ -90,17 +90,20 @@ describe('TaskFilterCloudService', () => {
|
||||
expect(res[0].appName).toBe('fakeAppName');
|
||||
expect(res[0].id).toBe('1');
|
||||
expect(res[0].name).toBe('FAKE_TASK_1');
|
||||
expect(res[0].status).toBe('ALL');
|
||||
expect(res[0].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[0].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
expect(res[1].appName).toBe('fakeAppName');
|
||||
expect(res[1].id).toBe('2');
|
||||
expect(res[1].name).toBe('FAKE_TASK_2');
|
||||
expect(res[1].status).toBe('RUNNING');
|
||||
expect(res[1].status).toBe(TaskStatusFilter.ASSIGNED);
|
||||
expect(res[1].statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
|
||||
expect(res[2].appName).toBe('fakeAppName');
|
||||
expect(res[2].id).toBe('3');
|
||||
expect(res[2].name).toBe('FAKE_TASK_3');
|
||||
expect(res[2].status).toBe('COMPLETED');
|
||||
expect(res[2].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[2].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
expect(createPreferenceSpy).toHaveBeenCalled();
|
||||
done();
|
||||
@ -116,17 +119,20 @@ describe('TaskFilterCloudService', () => {
|
||||
expect(res[0].appName).toBe('fakeAppName');
|
||||
expect(res[0].id).toBe('1');
|
||||
expect(res[0].name).toBe('FAKE_TASK_1');
|
||||
expect(res[0].status).toBe('ALL');
|
||||
expect(res[0].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[0].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
expect(res[1].appName).toBe('fakeAppName');
|
||||
expect(res[1].id).toBe('2');
|
||||
expect(res[1].name).toBe('FAKE_TASK_2');
|
||||
expect(res[1].status).toBe('RUNNING');
|
||||
expect(res[1].status).toBe(TaskStatusFilter.ASSIGNED);
|
||||
expect(res[1].statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
|
||||
expect(res[2].appName).toBe('fakeAppName');
|
||||
expect(res[2].id).toBe('3');
|
||||
expect(res[2].name).toBe('FAKE_TASK_3');
|
||||
expect(res[2].status).toBe('COMPLETED');
|
||||
expect(res[2].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[2].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
expect(getPreferencesSpy).toHaveBeenCalled();
|
||||
done();
|
||||
@ -144,17 +150,20 @@ describe('TaskFilterCloudService', () => {
|
||||
expect(res[0].appName).toBe('fakeAppName');
|
||||
expect(res[0].id).toBe('1');
|
||||
expect(res[0].name).toBe('FAKE_TASK_1');
|
||||
expect(res[0].status).toBe('ALL');
|
||||
expect(res[0].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[0].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
expect(res[1].appName).toBe('fakeAppName');
|
||||
expect(res[1].id).toBe('2');
|
||||
expect(res[1].name).toBe('FAKE_TASK_2');
|
||||
expect(res[1].status).toBe('RUNNING');
|
||||
expect(res[1].status).toBe(TaskStatusFilter.ASSIGNED);
|
||||
expect(res[1].statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
|
||||
expect(res[2].appName).toBe('fakeAppName');
|
||||
expect(res[2].id).toBe('3');
|
||||
expect(res[2].name).toBe('FAKE_TASK_3');
|
||||
expect(res[2].status).toBe('COMPLETED');
|
||||
expect(res[2].status).toBe(TaskStatusFilter.COMPLETED);
|
||||
expect(res[2].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
done();
|
||||
});
|
||||
@ -167,7 +176,8 @@ describe('TaskFilterCloudService', () => {
|
||||
expect(res.appName).toBe('fakeAppName');
|
||||
expect(res.id).toBe('2');
|
||||
expect(res.name).toBe('FAKE_TASK_2');
|
||||
expect(res.status).toBe('RUNNING');
|
||||
expect(res.status).toBe(TaskStatusFilter.ASSIGNED);
|
||||
expect(res.statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
|
||||
expect(getPreferenceByKeySpy).toHaveBeenCalled();
|
||||
done();
|
||||
@ -183,7 +193,8 @@ describe('TaskFilterCloudService', () => {
|
||||
expect(res.appName).toBe('fakeAppName');
|
||||
expect(res.id).toBe('2');
|
||||
expect(res.name).toBe('FAKE_TASK_2');
|
||||
expect(res.status).toBe('RUNNING');
|
||||
expect(res.status).toBe(TaskStatusFilter.ASSIGNED);
|
||||
expect(res.statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -245,14 +256,17 @@ describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService',
|
||||
let getPreferencesSpy: jasmine.Spy;
|
||||
let storageService: StorageService;
|
||||
|
||||
const identityUserMock = { username: 'fakeusername', firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
|
||||
const identityUserMock = {
|
||||
username: 'fakeusername',
|
||||
firstName: 'fake-identity-first-name',
|
||||
lastName: 'fake-identity-last-name',
|
||||
email: 'fakeIdentity@email.com'
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule, ProcessServiceCloudTestingModule, ApolloModule],
|
||||
providers: [
|
||||
{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }
|
||||
]
|
||||
providers: [{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }]
|
||||
});
|
||||
service = TestBed.inject(TaskFilterCloudService);
|
||||
preferenceCloudService = service.preferenceService;
|
||||
@ -272,20 +286,24 @@ describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService',
|
||||
expect(res[0].key).toEqual('my-tasks');
|
||||
expect(res[0].appName).toEqual(appName);
|
||||
expect(res[0].icon).toEqual('inbox');
|
||||
expect(res[0].status).toEqual('ASSIGNED');
|
||||
expect(res[0].status).toEqual(TaskStatusFilter.ASSIGNED);
|
||||
expect(res[0].statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
expect(res[0].assignee).toEqual(identityUserMock.username);
|
||||
expect(res[0].assignees).toContain(identityUserMock.username);
|
||||
|
||||
expect(res[1].name).toEqual('ADF_CLOUD_TASK_FILTERS.QUEUED_TASKS');
|
||||
expect(res[1].key).toEqual('queued-tasks');
|
||||
expect(res[1].appName).toEqual(appName);
|
||||
expect(res[1].icon).toEqual('queue');
|
||||
expect(res[1].status).toEqual('CREATED');
|
||||
expect(res[1].status).toEqual(TaskStatusFilter.CREATED);
|
||||
expect(res[1].statuses).toContain(TaskStatusFilter.CREATED);
|
||||
|
||||
expect(res[2].name).toEqual('ADF_CLOUD_TASK_FILTERS.COMPLETED_TASKS');
|
||||
expect(res[2].key).toEqual('completed-tasks');
|
||||
expect(res[2].appName).toEqual(appName);
|
||||
expect(res[2].icon).toEqual('done');
|
||||
expect(res[2].status).toEqual('COMPLETED');
|
||||
expect(res[2].status).toEqual(TaskStatusFilter.COMPLETED);
|
||||
expect(res[2].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
expect(getPreferencesSpy).toHaveBeenCalled();
|
||||
|
||||
const localData = JSON.parse(storageService.getItem(`task-filters-${appName}-${identityUserMock.username}`));
|
||||
@ -295,20 +313,24 @@ describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService',
|
||||
expect(localData[0].key).toEqual('my-tasks');
|
||||
expect(localData[0].appName).toEqual(appName);
|
||||
expect(localData[0].icon).toEqual('inbox');
|
||||
expect(localData[0].status).toEqual('ASSIGNED');
|
||||
expect(localData[0].status).toEqual(TaskStatusFilter.ASSIGNED);
|
||||
expect(localData[0].statuses).toContain(TaskStatusFilter.ASSIGNED);
|
||||
expect(localData[0].assignee).toEqual(identityUserMock.username);
|
||||
expect(localData[0].assignees).toContain(identityUserMock.username);
|
||||
|
||||
expect(localData[1].name).toEqual('ADF_CLOUD_TASK_FILTERS.QUEUED_TASKS');
|
||||
expect(localData[1].key).toEqual('queued-tasks');
|
||||
expect(localData[1].appName).toEqual(appName);
|
||||
expect(localData[1].icon).toEqual('queue');
|
||||
expect(localData[1].status).toEqual('CREATED');
|
||||
expect(localData[1].status).toEqual(TaskStatusFilter.CREATED);
|
||||
expect(localData[1].statuses).toContain(TaskStatusFilter.CREATED);
|
||||
|
||||
expect(localData[2].name).toEqual('ADF_CLOUD_TASK_FILTERS.COMPLETED_TASKS');
|
||||
expect(localData[2].key).toEqual('completed-tasks');
|
||||
expect(localData[2].appName).toEqual(appName);
|
||||
expect(localData[2].icon).toEqual('done');
|
||||
expect(localData[2].status).toEqual('COMPLETED');
|
||||
expect(localData[2].status).toEqual(TaskStatusFilter.COMPLETED);
|
||||
expect(localData[2].statuses).toContain(TaskStatusFilter.COMPLETED);
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -80,7 +80,8 @@ export class TaskFilterCloudService extends BaseCloudService {
|
||||
} else {
|
||||
return of(this.findFiltersByKeyInPreferences(preferences, key));
|
||||
}
|
||||
})
|
||||
}),
|
||||
switchMap((filters) => this.handleCreateFilterBackwardsCompatibility(appName, key, filters))
|
||||
)
|
||||
.subscribe((filters) => {
|
||||
this.addFiltersToStream(filters);
|
||||
@ -379,4 +380,45 @@ export class TaskFilterCloudService extends BaseCloudService {
|
||||
refreshFilter(filterKey: string): void {
|
||||
this.filterKeyToBeRefreshedSource.next(filterKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is run after retrieving the filter array from preferences.
|
||||
* It handles the backwards compatibility with the new API by looking for the new properties and their counterparts in each passed filter.
|
||||
* If the new property is not found, it is created and assigned the value constructed from the old property.
|
||||
* The filters are then updated in the preferences and returned.
|
||||
* Old properties are left untouched for purposes like feature toggling.
|
||||
*
|
||||
* @param appName Name of the target app.
|
||||
* @param key Key of the task filters.
|
||||
* @param filters Array of task filters to be checked for backward compatibility.
|
||||
* @returns Observable of task filters with updated properties.
|
||||
*/
|
||||
private handleCreateFilterBackwardsCompatibility(
|
||||
appName: string,
|
||||
key: string,
|
||||
filters: TaskFilterCloudModel[]
|
||||
): Observable<TaskFilterCloudModel[]> {
|
||||
filters.forEach((filter) => {
|
||||
if (filter.taskName && !filter.taskNames) {
|
||||
filter.taskNames = [filter.taskName];
|
||||
}
|
||||
if (filter.status && !filter.statuses) {
|
||||
filter.statuses = [filter.status];
|
||||
}
|
||||
if (filter.assignee && !filter.assignees) {
|
||||
filter.assignees = [filter.assignee];
|
||||
}
|
||||
if (filter.processDefinitionName && !filter.processDefinitionNames) {
|
||||
filter.processDefinitionNames = [filter.processDefinitionName];
|
||||
}
|
||||
if (filter.completedBy?.username && !filter.completedByUsers) {
|
||||
filter.completedByUsers = [filter.completedBy.username];
|
||||
}
|
||||
if (filter.priority && !filter.priorities) {
|
||||
filter.priorities = [`${filter.priority}`];
|
||||
}
|
||||
});
|
||||
|
||||
return this.updateTaskFilters(appName, key, filters);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import { ProcessServiceCloudTestingModule } from '../../../testing/process-servi
|
||||
import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model';
|
||||
import { shareReplay, skip } from 'rxjs/operators';
|
||||
import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface';
|
||||
import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN, TASK_SEARCH_API_METHOD_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { TaskListCloudModule } from '../task-list-cloud.module';
|
||||
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
@ -100,7 +100,7 @@ describe('TaskListCloudComponent', () => {
|
||||
updatePreference: of({})
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const configureTestingModule = (providers: any[]) => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ProcessServiceCloudTestingModule],
|
||||
providers: [
|
||||
@ -111,7 +111,8 @@ describe('TaskListCloudComponent', () => {
|
||||
{
|
||||
provide: TASK_LIST_PREFERENCES_SERVICE_TOKEN,
|
||||
useValue: preferencesService
|
||||
}
|
||||
},
|
||||
...providers
|
||||
]
|
||||
});
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
@ -141,352 +142,512 @@ describe('TaskListCloudComponent', () => {
|
||||
|
||||
component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should be able to inject TaskListCloudService instance', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.taskListCloudService instanceof TaskListCloudService).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should use the default schemaColumn as default', () => {
|
||||
component.ngAfterContentInit();
|
||||
expect(component.columns).toBeDefined();
|
||||
expect(component.columns.length).toEqual(3);
|
||||
});
|
||||
|
||||
it('should display empty content when process list is empty', async () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(emptyList));
|
||||
fixture.detectChanges();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
|
||||
expect(component.rows.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should use the custom schemaColumn from app.config.json', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
component.ngAfterContentInit();
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toEqual(fakeCustomSchema);
|
||||
});
|
||||
|
||||
it('should hide columns on applying new columns visibility through columns selector', () => {
|
||||
component.showMainDatatableActions = true;
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.ngAfterContentInit();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const mainMenuButton = fixture.debugElement.query(By.css('[data-automation-id="adf-datatable-main-menu-button"]'));
|
||||
mainMenuButton.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnSelectorMenu = fixture.debugElement.query(By.css('adf-datatable-column-selector'));
|
||||
expect(columnSelectorMenu).toBeTruthy();
|
||||
|
||||
const columnsSelectorInstance = columnSelectorMenu.componentInstance as ColumnsSelectorComponent;
|
||||
expect(columnsSelectorInstance.columns).toBe(component.columns, 'should pass columns as input');
|
||||
|
||||
const newColumns = (component.columns as DataColumn[]).map((column, index) => ({
|
||||
...column,
|
||||
isHidden: index !== 0 // only first one is shown
|
||||
}));
|
||||
|
||||
columnSelectorMenu.triggerEventHandler('submitColumnsVisibility', newColumns);
|
||||
fixture.detectChanges();
|
||||
|
||||
const displayedColumns = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-header'));
|
||||
expect(displayedColumns.length).toBe(2, 'only column with isHidden set to false and action column should be shown');
|
||||
});
|
||||
|
||||
it('should fetch custom schemaColumn when the input presetColumn is defined', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toBeDefined();
|
||||
expect(component.columns.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return an empty task list when no input parameters are passed', () => {
|
||||
component.ngAfterContentInit();
|
||||
expect(component.rows).toBeDefined();
|
||||
expect(component.isListEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return the results if an application name is given', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
component.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(component.rows).toBeDefined();
|
||||
expect(component.isListEmpty()).not.toBeTruthy();
|
||||
expect(component.rows.length).toEqual(1);
|
||||
|
||||
const expectedTask = {
|
||||
...fakeGlobalTask,
|
||||
variables: fakeGlobalTask.processVariables
|
||||
};
|
||||
|
||||
expect(component.rows[0]).toEqual(expectedTask);
|
||||
done();
|
||||
});
|
||||
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should emit row click event', (done) => {
|
||||
const row = new ObjectDataRow({ id: '999' });
|
||||
const rowEvent = new DataRowEvent(row, null);
|
||||
component.rowClick.subscribe((taskId) => {
|
||||
expect(taskId).toEqual('999');
|
||||
expect(component.currentInstanceId).toEqual('999');
|
||||
done();
|
||||
});
|
||||
component.onRowClick(rowEvent);
|
||||
});
|
||||
|
||||
it('should re-create columns when a column width gets changed', () => {
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
});
|
||||
|
||||
it('should update columns widths when a column width gets changed', () => {
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120
|
||||
});
|
||||
});
|
||||
|
||||
it('should update columns widths while preserving previously saved widths when a column width gets changed', () => {
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120
|
||||
});
|
||||
|
||||
newColumns[1].width = 150;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(component.columns[1].width).toBe(150);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120,
|
||||
created: 150
|
||||
});
|
||||
});
|
||||
|
||||
it('should re-create columns when a column order gets changed', () => {
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.columns[0].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.NAME');
|
||||
expect(component.columns[1].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED');
|
||||
expect(component.columns[2].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.ASSIGNEE');
|
||||
|
||||
component.onColumnOrderChanged([component.columns[1], ...component.columns]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.columns[0].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED');
|
||||
expect(component.columns[1].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.NAME');
|
||||
expect(component.columns[2].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.ASSIGNEE');
|
||||
});
|
||||
|
||||
it('should create datatable schema when a column visibility gets changed', () => {
|
||||
component.ngAfterContentInit();
|
||||
spyOn(component, 'createDatatableSchema');
|
||||
|
||||
component.onColumnsVisibilityChange(component.columns);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.createDatatableSchema).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call endpoint when a column visibility gets changed', () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest');
|
||||
component.ngAfterContentInit();
|
||||
spyOn(component, 'createDatatableSchema');
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onColumnsVisibilityChange(component.columns);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(taskListCloudService.getTaskByRequest).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('component changes', () => {
|
||||
describe('TASK_SEARCH_API_METHOD_TOKEN injected with GET value', () => {
|
||||
beforeEach(() => {
|
||||
component.rows = fakeGlobalTasks.list.entries;
|
||||
configureTestingModule([{ provide: TASK_SEARCH_API_METHOD_TOKEN, useValue: 'GET' }]);
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
|
||||
expect(component.rows.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should hide columns on applying new columns visibility through columns selector', () => {
|
||||
component.showMainDatatableActions = true;
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.ngAfterContentInit();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const mainMenuButton = fixture.debugElement.query(By.css('[data-automation-id="adf-datatable-main-menu-button"]'));
|
||||
mainMenuButton.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnSelectorMenu = fixture.debugElement.query(By.css('adf-datatable-column-selector'));
|
||||
expect(columnSelectorMenu).toBeTruthy();
|
||||
|
||||
const columnsSelectorInstance = columnSelectorMenu.componentInstance as ColumnsSelectorComponent;
|
||||
expect(columnsSelectorInstance.columns).toBe(component.columns, 'should pass columns as input');
|
||||
|
||||
const newColumns = (component.columns as DataColumn[]).map((column, index) => ({
|
||||
...column,
|
||||
isHidden: index !== 0 // only first one is shown
|
||||
}));
|
||||
|
||||
columnSelectorMenu.triggerEventHandler('submitColumnsVisibility', newColumns);
|
||||
fixture.detectChanges();
|
||||
|
||||
const displayedColumns = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-header'));
|
||||
expect(displayedColumns.length).toBe(2, 'only column with isHidden set to false and action column should be shown');
|
||||
});
|
||||
|
||||
it('should return the results if an application name is given', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
component.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(component.rows).toBeDefined();
|
||||
expect(component.isListEmpty()).not.toBeTruthy();
|
||||
expect(component.rows.length).toEqual(1);
|
||||
|
||||
const expectedTask = {
|
||||
...fakeGlobalTask,
|
||||
variables: fakeGlobalTask.processVariables
|
||||
};
|
||||
|
||||
expect(component.rows[0]).toEqual(expectedTask);
|
||||
done();
|
||||
});
|
||||
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should NOT reload the task list when no parameters changed', () => {
|
||||
it('should call endpoint when a column visibility gets changed', () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest');
|
||||
component.rows = null;
|
||||
component.ngAfterContentInit();
|
||||
spyOn(component, 'createDatatableSchema');
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onColumnsVisibilityChange(component.columns);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(taskListCloudService.getTaskByRequest).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
describe('component changes', () => {
|
||||
beforeEach(() => {
|
||||
component.rows = fakeGlobalTasks.list.entries;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should reload the task list when input parameters changed', () => {
|
||||
const getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.appName = 'mock-app-name';
|
||||
component.priority = 1;
|
||||
component.status = 'mock-status';
|
||||
component.lastModifiedFrom = 'mock-lastmodified-date';
|
||||
component.owner = 'mock-owner-name';
|
||||
const priorityChange = new SimpleChange(undefined, 1, true);
|
||||
const statusChange = new SimpleChange(undefined, 'mock-status', true);
|
||||
const lastModifiedFromChange = new SimpleChange(undefined, 'mock-lastmodified-date', true);
|
||||
const ownerChange = new SimpleChange(undefined, 'mock-owner-name', true);
|
||||
component.ngOnChanges({
|
||||
priority: priorityChange,
|
||||
status: statusChange,
|
||||
lastModifiedFrom: lastModifiedFromChange,
|
||||
owner: ownerChange
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(getTaskByRequestSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload task list when sorting on a column changes', () => {
|
||||
const getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.onSortingChanged(
|
||||
new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
key: 'fakeName',
|
||||
direction: 'asc'
|
||||
},
|
||||
bubbles: true
|
||||
})
|
||||
);
|
||||
fixture.detectChanges();
|
||||
expect(component.sorting).toEqual([
|
||||
new TaskListCloudSortingModel({
|
||||
orderBy: 'fakeName',
|
||||
direction: 'ASC'
|
||||
})
|
||||
]);
|
||||
expect(component.formattedSorting).toEqual(['fakeName', 'asc']);
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(getTaskByRequestSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('TASK_SEARCH_API_METHOD_TOKEN injected with POST value', () => {
|
||||
beforeEach(() => {
|
||||
configureTestingModule([{ provide: TASK_SEARCH_API_METHOD_TOKEN, useValue: 'POST' }]);
|
||||
component.appName = 'mock-app-name';
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
|
||||
expect(component.rows.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should hide columns on applying new columns visibility through columns selector', () => {
|
||||
component.showMainDatatableActions = true;
|
||||
spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
component.ngAfterContentInit();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const mainMenuButton = fixture.debugElement.query(By.css('[data-automation-id="adf-datatable-main-menu-button"]'));
|
||||
mainMenuButton.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnSelectorMenu = fixture.debugElement.query(By.css('adf-datatable-column-selector'));
|
||||
expect(columnSelectorMenu).toBeTruthy();
|
||||
|
||||
const columnsSelectorInstance = columnSelectorMenu.componentInstance as ColumnsSelectorComponent;
|
||||
expect(columnsSelectorInstance.columns).toBe(component.columns, 'should pass columns as input');
|
||||
|
||||
const newColumns = (component.columns as DataColumn[]).map((column, index) => ({
|
||||
...column,
|
||||
isHidden: index !== 0 // only first one is shown
|
||||
}));
|
||||
|
||||
columnSelectorMenu.triggerEventHandler('submitColumnsVisibility', newColumns);
|
||||
fixture.detectChanges();
|
||||
|
||||
const displayedColumns = fixture.debugElement.queryAll(By.css('.adf-datatable-cell-header'));
|
||||
expect(displayedColumns.length).toBe(2, 'only column with isHidden set to false and action column should be shown');
|
||||
});
|
||||
|
||||
it('should return the results if an application name is given', (done) => {
|
||||
spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
component.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(component.rows).toBeDefined();
|
||||
expect(component.isListEmpty()).not.toBeTruthy();
|
||||
expect(component.rows.length).toEqual(1);
|
||||
|
||||
const expectedTask = {
|
||||
...fakeGlobalTask,
|
||||
variables: fakeGlobalTask.processVariables
|
||||
};
|
||||
|
||||
expect(component.rows[0]).toEqual(expectedTask);
|
||||
done();
|
||||
});
|
||||
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should call endpoint when a column visibility gets changed', () => {
|
||||
const fetchTaskListSpy = spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
component.ngAfterContentInit();
|
||||
spyOn(component, 'createDatatableSchema');
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onColumnsVisibilityChange(component.columns);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fetchTaskListSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
describe('component changes', () => {
|
||||
beforeEach(() => {
|
||||
component.rows = fakeGlobalTasks.list.entries;
|
||||
component.appName = 'mock-app-name';
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should reload the task list when input parameters changed', () => {
|
||||
const fetchTaskListSpy = spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
component.appName = 'mock-app-name';
|
||||
component.priorities = ['1', '2'];
|
||||
component.statuses = ['mock-status-1', 'mock-status-2'];
|
||||
component.lastModifiedFrom = 'mock-lastmodified-date';
|
||||
const prioritiesChange = new SimpleChange(undefined, ['1'], true);
|
||||
const statusesChange = new SimpleChange(undefined, ['mock-status'], true);
|
||||
const lastModifiedFromChange = new SimpleChange(undefined, 'mock-lastmodified-date', true);
|
||||
component.ngOnChanges({
|
||||
priorities: prioritiesChange,
|
||||
statuses: statusesChange,
|
||||
lastModifiedFrom: lastModifiedFromChange
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(fetchTaskListSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload task list when sorting on a column changes', () => {
|
||||
const fetchTaskListSpy = spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
fixture.detectChanges();
|
||||
component.onSortingChanged(
|
||||
new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
key: 'fakeName',
|
||||
direction: 'asc'
|
||||
},
|
||||
bubbles: true
|
||||
})
|
||||
);
|
||||
fixture.detectChanges();
|
||||
expect(component.sorting).toEqual([
|
||||
new TaskListCloudSortingModel({
|
||||
orderBy: 'fakeName',
|
||||
direction: 'ASC'
|
||||
})
|
||||
]);
|
||||
expect(component.formattedSorting).toEqual(['fakeName', 'asc']);
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(fetchTaskListSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('API agnostic', () => {
|
||||
beforeEach(() => {
|
||||
configureTestingModule([]);
|
||||
});
|
||||
|
||||
it('should be able to inject TaskListCloudService instance', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.taskListCloudService instanceof TaskListCloudService).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should use the default schemaColumn as default', () => {
|
||||
component.ngAfterContentInit();
|
||||
expect(component.columns).toBeDefined();
|
||||
expect(component.columns.length).toEqual(3);
|
||||
});
|
||||
|
||||
it('should display empty content when process list is empty', async () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(emptyList));
|
||||
fixture.detectChanges();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
});
|
||||
|
||||
it('should use the custom schemaColumn from app.config.json', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
component.ngAfterContentInit();
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toEqual(fakeCustomSchema);
|
||||
});
|
||||
|
||||
it('should fetch custom schemaColumn when the input presetColumn is defined', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toBeDefined();
|
||||
expect(component.columns.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return an empty task list when no input parameters are passed', () => {
|
||||
component.ngAfterContentInit();
|
||||
expect(component.rows).toBeDefined();
|
||||
expect(component.isListEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should reload the task list when input parameters changed', () => {
|
||||
const getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.appName = 'mock-app-name';
|
||||
component.priority = 1;
|
||||
component.status = 'mock-status';
|
||||
component.lastModifiedFrom = 'mock-lastmodified-date';
|
||||
component.owner = 'mock-owner-name';
|
||||
const priorityChange = new SimpleChange(undefined, 1, true);
|
||||
const statusChange = new SimpleChange(undefined, 'mock-status', true);
|
||||
const lastModifiedFromChange = new SimpleChange(undefined, 'mock-lastmodified-date', true);
|
||||
const ownerChange = new SimpleChange(undefined, 'mock-owner-name', true);
|
||||
component.ngOnChanges({
|
||||
priority: priorityChange,
|
||||
status: statusChange,
|
||||
lastModifiedFrom: lastModifiedFromChange,
|
||||
owner: ownerChange
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(getTaskByRequestSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set formattedSorting if sorting input changes', () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
spyOn(component, 'formatSorting').and.callThrough();
|
||||
|
||||
component.appName = 'mock-app-name';
|
||||
const mockSort = [
|
||||
new TaskListCloudSortingModel({
|
||||
orderBy: 'startDate',
|
||||
direction: 'DESC'
|
||||
})
|
||||
];
|
||||
const sortChange = new SimpleChange(undefined, mockSort, true);
|
||||
component.ngOnChanges({
|
||||
sorting: sortChange
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.formatSorting).toHaveBeenCalledWith(mockSort);
|
||||
expect(component.formattedSorting).toEqual(['startDate', 'desc']);
|
||||
});
|
||||
|
||||
it('should reload task list when sorting on a column changes', () => {
|
||||
const getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.onSortingChanged(
|
||||
new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
key: 'fakeName',
|
||||
direction: 'asc'
|
||||
},
|
||||
bubbles: true
|
||||
})
|
||||
);
|
||||
fixture.detectChanges();
|
||||
expect(component.sorting).toEqual([
|
||||
new TaskListCloudSortingModel({
|
||||
orderBy: 'fakeName',
|
||||
direction: 'ASC'
|
||||
})
|
||||
]);
|
||||
expect(component.formattedSorting).toEqual(['fakeName', 'asc']);
|
||||
expect(component.isListEmpty()).toBeFalsy();
|
||||
expect(getTaskByRequestSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset pagination when resetPaginationValues is called', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
const size = component.size;
|
||||
const skipCount = component.skipCount;
|
||||
component.pagination.pipe(skip(3)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(size);
|
||||
expect(component.skipCount).toBe(skipCount);
|
||||
expect(updatedPagination.maxItems).toEqual(size);
|
||||
expect(updatedPagination.skipCount).toEqual(skipCount);
|
||||
it('should emit row click event', (done) => {
|
||||
const row = new ObjectDataRow({ id: '999' });
|
||||
const rowEvent = new DataRowEvent(row, null);
|
||||
component.rowClick.subscribe((taskId) => {
|
||||
expect(taskId).toEqual('999');
|
||||
expect(component.currentInstanceId).toEqual('999');
|
||||
done();
|
||||
});
|
||||
|
||||
const pagination = {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.updatePagination(pagination);
|
||||
|
||||
component.resetPagination();
|
||||
component.onRowClick(rowEvent);
|
||||
});
|
||||
|
||||
it('should set pagination and reload when updatePagination is called', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
spyOn(component, 'reload').and.stub();
|
||||
it('should re-create columns when a column width gets changed', () => {
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const pagination = {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.pagination.pipe(skip(1)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(pagination.maxItems);
|
||||
expect(component.skipCount).toBe(pagination.skipCount);
|
||||
expect(updatedPagination.maxItems).toEqual(pagination.maxItems);
|
||||
expect(updatedPagination.skipCount).toEqual(pagination.skipCount);
|
||||
done();
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
});
|
||||
|
||||
it('should update columns widths when a column width gets changed', () => {
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120
|
||||
});
|
||||
});
|
||||
|
||||
it('should update columns widths while preserving previously saved widths when a column width gets changed', () => {
|
||||
component.appName = 'fake-app-name';
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const newColumns = [...component.columns];
|
||||
newColumns[0].width = 120;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120
|
||||
});
|
||||
|
||||
component.updatePagination(pagination);
|
||||
newColumns[1].width = 150;
|
||||
component.onColumnsWidthChanged(newColumns);
|
||||
|
||||
expect(component.columns[0].width).toBe(120);
|
||||
expect(component.columns[1].width).toBe(150);
|
||||
expect(preferencesService.updatePreference).toHaveBeenCalledWith('fake-app-name', 'tasks-list-cloud-columns-widths', {
|
||||
name: 120,
|
||||
created: 150
|
||||
});
|
||||
});
|
||||
|
||||
it('should re-create columns when a column order gets changed', () => {
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.columns[0].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.NAME');
|
||||
expect(component.columns[1].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED');
|
||||
expect(component.columns[2].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.ASSIGNEE');
|
||||
|
||||
component.onColumnOrderChanged([component.columns[1], ...component.columns]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.columns[0].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED');
|
||||
expect(component.columns[1].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.NAME');
|
||||
expect(component.columns[2].title).toBe('ADF_CLOUD_TASK_LIST.PROPERTIES.ASSIGNEE');
|
||||
});
|
||||
|
||||
it('should create datatable schema when a column visibility gets changed', () => {
|
||||
component.ngAfterContentInit();
|
||||
spyOn(component, 'createDatatableSchema');
|
||||
|
||||
component.onColumnsVisibilityChange(component.columns);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.createDatatableSchema).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('component changes', () => {
|
||||
beforeEach(() => {
|
||||
component.rows = fakeGlobalTasks.list.entries;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should NOT reload the task list when no parameters changed', () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest');
|
||||
component.rows = null;
|
||||
fixture.detectChanges();
|
||||
expect(component.isListEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set formattedSorting if sorting input changes', () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
spyOn(component, 'formatSorting').and.callThrough();
|
||||
|
||||
component.appName = 'mock-app-name';
|
||||
const mockSort = [
|
||||
new TaskListCloudSortingModel({
|
||||
orderBy: 'startDate',
|
||||
direction: 'DESC'
|
||||
})
|
||||
];
|
||||
const sortChange = new SimpleChange(undefined, mockSort, true);
|
||||
component.ngOnChanges({
|
||||
sorting: sortChange
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.formatSorting).toHaveBeenCalledWith(mockSort);
|
||||
expect(component.formattedSorting).toEqual(['startDate', 'desc']);
|
||||
});
|
||||
|
||||
it('should reset pagination when resetPaginationValues is called', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
const size = component.size;
|
||||
const skipCount = component.skipCount;
|
||||
component.pagination.pipe(skip(3)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(size);
|
||||
expect(component.skipCount).toBe(skipCount);
|
||||
expect(updatedPagination.maxItems).toEqual(size);
|
||||
expect(updatedPagination.skipCount).toEqual(skipCount);
|
||||
done();
|
||||
});
|
||||
|
||||
const pagination = {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.updatePagination(pagination);
|
||||
|
||||
component.resetPagination();
|
||||
});
|
||||
|
||||
it('should set pagination and reload when updatePagination is called', (done) => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
spyOn(component, 'reload').and.stub();
|
||||
|
||||
const pagination = {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.pagination.pipe(skip(1)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(pagination.maxItems);
|
||||
expect(component.skipCount).toBe(pagination.skipCount);
|
||||
expect(updatedPagination.maxItems).toEqual(pagination.maxItems);
|
||||
expect(updatedPagination.skipCount).toEqual(pagination.skipCount);
|
||||
done();
|
||||
});
|
||||
|
||||
component.updatePagination(pagination);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -505,6 +666,7 @@ describe('TaskListCloudComponent: Injecting custom colums for tasklist - CustomT
|
||||
});
|
||||
taskListCloudService = TestBed.inject(TASK_LIST_CLOUD_TOKEN);
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
fixtureCustom = TestBed.createComponent(CustomTaskListComponent);
|
||||
copyFixture = TestBed.createComponent(CustomCopyContentTaskListComponent);
|
||||
fixtureCustom.detectChanges();
|
||||
@ -559,6 +721,7 @@ describe('TaskListCloudComponent: Creating an empty custom template - EmptyTempl
|
||||
taskListCloudService = TestBed.inject(TASK_LIST_CLOUD_TOKEN);
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(emptyList));
|
||||
spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
|
||||
fixtureEmpty = TestBed.createComponent(EmptyTemplateComponent);
|
||||
fixtureEmpty.detectChanges();
|
||||
@ -578,7 +741,8 @@ describe('TaskListCloudComponent: Creating an empty custom template - EmptyTempl
|
||||
});
|
||||
|
||||
describe('TaskListCloudComponent: Copy cell content directive from app.config specifications', () => {
|
||||
let taskSpy: jasmine.Spy;
|
||||
let getTaskByRequestSpy: jasmine.Spy;
|
||||
let fetchTaskListSpy: jasmine.Spy;
|
||||
let appConfig: AppConfigService;
|
||||
let taskListCloudService: TaskListCloudServiceInterface;
|
||||
let component: TaskListCloudComponent;
|
||||
@ -619,7 +783,8 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
});
|
||||
fixture = TestBed.createComponent(TaskListCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
taskSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
fetchTaskListSpy = spyOn(taskListCloudService, 'fetchTaskList').and.returnValue(of(fakeGlobalTasks));
|
||||
component.isColumnSchemaCreated$ = of(true);
|
||||
});
|
||||
|
||||
@ -628,7 +793,6 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
});
|
||||
|
||||
it('should show tooltip if config copyContent flag is true', () => {
|
||||
taskSpy.and.returnValue(of(fakeGlobalTasks));
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
|
||||
component.reload();
|
||||
@ -643,19 +807,18 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
});
|
||||
|
||||
it('should replace priority values', () => {
|
||||
taskSpy.and.returnValue(of(fakeGlobalTasks));
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const cell = fixture.debugElement.query(By.css('[data-automation-id="text_ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE"]'));
|
||||
expect(cell.nativeElement.textContent).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE');
|
||||
});
|
||||
|
||||
it('replacePriorityValues should return undefined when no rows defined', () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
taskSpy.and.returnValue(of(emptyList));
|
||||
getTaskByRequestSpy.and.returnValue(of(emptyList));
|
||||
fetchTaskListSpy.and.returnValue(of(emptyList));
|
||||
fixture.detectChanges();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
@ -681,7 +844,6 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
});
|
||||
|
||||
it('replacePriorityValues should return replaced value when rows are defined', () => {
|
||||
taskSpy.and.returnValue(of(fakeGlobalTasks));
|
||||
fixture.detectChanges();
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
@ -15,16 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, Input, Inject, OnDestroy } from '@angular/core';
|
||||
import { Component, ViewEncapsulation, Input, Inject, OnDestroy, Optional } from '@angular/core';
|
||||
import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { TaskListRequestModel, TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { BaseTaskListCloudComponent } from './base-task-list-cloud.component';
|
||||
import { TaskCloudService } from '../../services/task-cloud.service';
|
||||
import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN, TASK_SEARCH_API_METHOD_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
|
||||
import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface';
|
||||
import { Subject, of, BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import { map, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Subject, BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import { filter, map, switchMap, take, takeUntil } from 'rxjs/operators';
|
||||
import { VariableMapperService } from '../../../services/variable-mapper.sevice';
|
||||
import { ProcessListDataColumnCustomData } from '../../../models/data-column-custom-data';
|
||||
import { TaskCloudModel } from '../../../models/task-cloud.model';
|
||||
@ -145,6 +145,48 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
||||
@Input()
|
||||
candidateGroupId: string = '';
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks with names matching any of the supplied strings.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
names: string[] = [];
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks with assignees whose usernames are present in the array.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
assignees: string[] = [];
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks with provided statuses.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
statuses: string[] = [];
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks under provided processes.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
processDefinitionNames: string[] = [];
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks with provided priorities.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
priorities: string[] = [];
|
||||
|
||||
/**
|
||||
* Filter the tasks. Display only tasks completed by users whose usernames are present in the array.
|
||||
* This input will be used only if TASK_SEARCH_API_METHOD_TOKEN is provided with 'POST' value.
|
||||
*/
|
||||
@Input()
|
||||
completedByUsers: string[] = [];
|
||||
|
||||
private onDestroyTaskList$ = new Subject<boolean>();
|
||||
|
||||
rows: TaskInstanceCloudListViewModel[] = [];
|
||||
@ -156,6 +198,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
||||
);
|
||||
|
||||
constructor(
|
||||
@Inject(TASK_SEARCH_API_METHOD_TOKEN) @Optional() private searchMethod: 'GET' | 'POST',
|
||||
@Inject(TASK_LIST_CLOUD_TOKEN) public taskListCloudService: TaskListCloudServiceInterface,
|
||||
appConfigService: AppConfigService,
|
||||
taskCloudService: TaskCloudService,
|
||||
@ -176,13 +219,22 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
||||
|
||||
this.isColumnSchemaCreated$
|
||||
.pipe(
|
||||
switchMap(() => of(this.createRequestNode())),
|
||||
tap((requestNode) => (this.requestNode = requestNode)),
|
||||
switchMap((requestNode) => this.taskListCloudService.getTaskByRequest(requestNode)),
|
||||
filter((isColumnSchemaCreated) => !!isColumnSchemaCreated),
|
||||
take(1),
|
||||
switchMap(() => {
|
||||
if (this.searchMethod === 'POST') {
|
||||
const requestNode = this.createTaskListRequestNode();
|
||||
return this.taskListCloudService.fetchTaskList(requestNode).pipe(take(1));
|
||||
} else {
|
||||
const requestNode = this.createRequestNode();
|
||||
this.requestNode = requestNode;
|
||||
return this.taskListCloudService.getTaskByRequest(requestNode);
|
||||
}
|
||||
}),
|
||||
takeUntil(this.onDestroyTaskList$)
|
||||
)
|
||||
.subscribe(
|
||||
(tasks: { list: PaginatedEntries<TaskCloudModel> }) => {
|
||||
.subscribe({
|
||||
next: (tasks: { list: PaginatedEntries<TaskCloudModel> }) => {
|
||||
const tasksWithVariables = tasks.list.entries.map((task) => ({
|
||||
...task,
|
||||
variables: task.processVariables
|
||||
@ -196,14 +248,43 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
||||
this.isReloadingSubject$.next(false);
|
||||
this.pagination.next(tasks.list.pagination);
|
||||
},
|
||||
(error) => {
|
||||
error: (error) => {
|
||||
this.error.emit(error);
|
||||
this.isReloadingSubject$.next(false);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
createRequestNode(): TaskQueryCloudRequestModel {
|
||||
private createTaskListRequestNode(): TaskListRequestModel {
|
||||
const requestNode: TaskListRequestModel = {
|
||||
appName: this.appName,
|
||||
pagination: {
|
||||
maxItems: this.size,
|
||||
skipCount: this.skipCount
|
||||
},
|
||||
sorting: this.sorting,
|
||||
onlyStandalone: this.standalone,
|
||||
name: this.names,
|
||||
processDefinitionName: this.processDefinitionNames,
|
||||
priority: this.priorities,
|
||||
status: this.statuses,
|
||||
completedBy: this.completedByUsers,
|
||||
assignee: this.assignees,
|
||||
createdFrom: this.createdFrom,
|
||||
createdTo: this.createdTo,
|
||||
lastModifiedFrom: this.lastModifiedFrom,
|
||||
lastModifiedTo: this.lastModifiedTo,
|
||||
dueDateFrom: this.dueDateFrom,
|
||||
dueDateTo: this.dueDateTo,
|
||||
completedFrom: this.completedFrom,
|
||||
completedTo: this.completedTo,
|
||||
variableKeys: this.getRequestNodeVariables()
|
||||
};
|
||||
|
||||
return new TaskListRequestModel(requestNode);
|
||||
}
|
||||
|
||||
private createRequestNode(): TaskQueryCloudRequestModel {
|
||||
const requestNode = {
|
||||
appName: this.appName,
|
||||
assignee: this.assignee,
|
||||
|
@ -17,9 +17,10 @@
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { TaskListCloudService } from './task-list-cloud.service';
|
||||
import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { TaskListRequestModel, TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
|
||||
import { AdfHttpClient } from '@alfresco/adf-core/api';
|
||||
import { catchError, firstValueFrom, of } from 'rxjs';
|
||||
|
||||
describe('TaskListCloudService', () => {
|
||||
let service: TaskListCloudService;
|
||||
@ -39,59 +40,126 @@ describe('TaskListCloudService', () => {
|
||||
requestSpy = spyOn(adfHttpClient, 'request');
|
||||
});
|
||||
|
||||
it('should append to the call all the parameters', (done) => {
|
||||
const taskRequest = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' } as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
service.getTaskByRequest(taskRequest).subscribe((res) => {
|
||||
describe('getTaskByRequest', () => {
|
||||
it('should append to the call all the parameters', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
skipCount: 0,
|
||||
maxItems: 20,
|
||||
service: 'fake-service'
|
||||
} as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
|
||||
const res = await firstValueFrom(service.getTaskByRequest(taskRequest));
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.skipCount).toBe(0);
|
||||
expect(res.maxItems).toBe(20);
|
||||
expect(res.service).toBe('fake-service');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should concat the app name to the request url', (done) => {
|
||||
const taskRequest = { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' } as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
service.getTaskByRequest(taskRequest).subscribe((requestUrl) => {
|
||||
it('should concat the app name to the request url', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
skipCount: 0,
|
||||
maxItems: 20,
|
||||
service: 'fake-service'
|
||||
} as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
|
||||
const requestUrl = await firstValueFrom(service.getTaskByRequest(taskRequest));
|
||||
|
||||
expect(requestUrl).toBeDefined();
|
||||
expect(requestUrl).not.toBeNull();
|
||||
expect(requestUrl).toContain('/fakeName/query/v1/tasks');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should concat the sorting to append as parameters', (done) => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
skipCount: 0,
|
||||
maxItems: 20,
|
||||
service: 'fake-service',
|
||||
sorting: [
|
||||
{ orderBy: 'NAME', direction: 'DESC' },
|
||||
{ orderBy: 'TITLE', direction: 'ASC' }
|
||||
]
|
||||
} as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
service.getTaskByRequest(taskRequest).subscribe((res) => {
|
||||
it('should concat the sorting to append as parameters', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
skipCount: 0,
|
||||
maxItems: 20,
|
||||
service: 'fake-service',
|
||||
sorting: [
|
||||
{ orderBy: 'NAME', direction: 'DESC' },
|
||||
{ orderBy: 'TITLE', direction: 'ASC' }
|
||||
]
|
||||
} as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
|
||||
const res = await firstValueFrom(service.getTaskByRequest(taskRequest));
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.sort).toBe('NAME,DESC&TITLE,ASC');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return an error when app name is not specified', async () => {
|
||||
const taskRequest = { appName: null } as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
|
||||
const res = await firstValueFrom(service.getTaskByRequest(taskRequest).pipe(catchError((error) => of(error))));
|
||||
|
||||
expect(res).toBe('Appname not configured');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error when app name is not specified', (done) => {
|
||||
const taskRequest = { appName: null } as TaskQueryCloudRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
service.getTaskByRequest(taskRequest).subscribe(
|
||||
() => {},
|
||||
(error) => {
|
||||
expect(error).toBe('Appname not configured');
|
||||
done();
|
||||
}
|
||||
);
|
||||
describe('fetchTaskList', () => {
|
||||
it('should append to the call all the parameters', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
pagination: { skipCount: 0, maxItems: 20 }
|
||||
} as TaskListRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
|
||||
const res = await firstValueFrom(service.fetchTaskList(taskRequest));
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.skipCount).toBe(0);
|
||||
expect(res.maxItems).toBe(20);
|
||||
});
|
||||
|
||||
it('should concat the app name to the request url', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
pagination: { skipCount: 0, maxItems: 20 }
|
||||
} as TaskListRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
|
||||
const res = await firstValueFrom(service.fetchTaskList(taskRequest));
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res).toContain('/fakeName/query/v1/tasks/search');
|
||||
});
|
||||
|
||||
it('should concat the sorting to append as parameters', async () => {
|
||||
const taskRequest = {
|
||||
appName: 'fakeName',
|
||||
pagination: { skipCount: 0, maxItems: 20 },
|
||||
sorting: [
|
||||
{ orderBy: 'NAME', direction: 'DESC' },
|
||||
{ orderBy: 'TITLE', direction: 'ASC' }
|
||||
]
|
||||
} as TaskListRequestModel;
|
||||
requestSpy.and.callFake(returnCallQueryParameters);
|
||||
|
||||
const res = await firstValueFrom(service.fetchTaskList(taskRequest));
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.sort).toBe('NAME,DESC&TITLE,ASC');
|
||||
});
|
||||
|
||||
it('should return an error when app name is not specified', async () => {
|
||||
const taskRequest = { appName: null } as TaskListRequestModel;
|
||||
requestSpy.and.callFake(returnCallUrl);
|
||||
|
||||
const res = await firstValueFrom(service.fetchTaskList(taskRequest).pipe(catchError((error) => of(error.message))));
|
||||
|
||||
expect(res).toBe('Appname not configured');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { TaskQueryCloudRequestModel, TaskListRequestModel } from '../../../models/filter-cloud-model';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model';
|
||||
import { BaseCloudService } from '../../../services/base-cloud.service';
|
||||
@ -29,6 +29,7 @@ export class TaskListCloudService extends BaseCloudService implements TaskListCl
|
||||
/**
|
||||
* Finds a task using an object with optional query properties.
|
||||
*
|
||||
* @deprecated From Activiti 8.7.0 forward, use TaskListCloudService.fetchTaskList instead.
|
||||
* @param requestNode Query object
|
||||
* @param queryUrl Query url
|
||||
* @returns Task information
|
||||
@ -56,6 +57,78 @@ export class TaskListCloudService extends BaseCloudService implements TaskListCl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Available from Activiti version 8.7.0 onwards.
|
||||
* Retrieves a list of tasks using an object with optional query properties.
|
||||
*
|
||||
* @param requestNode Query object
|
||||
* @param queryUrl Query url
|
||||
* @returns List of tasks
|
||||
*/
|
||||
fetchTaskList(requestNode: TaskListRequestModel, queryUrl?: string): Observable<any> {
|
||||
if (!requestNode?.appName) {
|
||||
return throwError(() => new Error('Appname not configured'));
|
||||
}
|
||||
|
||||
queryUrl = queryUrl || `${this.getBasePath(requestNode.appName)}/query/v1/tasks/search`;
|
||||
|
||||
const queryParams = {
|
||||
maxItems: requestNode.pagination?.maxItems || 25,
|
||||
skipCount: requestNode.pagination?.skipCount || 0,
|
||||
sort: this.buildSortingParam(requestNode.sorting || [])
|
||||
};
|
||||
|
||||
const queryData = this.buildQueryData(requestNode);
|
||||
|
||||
return this.post<any, TaskCloudNodePaging>(queryUrl, queryData, queryParams).pipe(
|
||||
map((response) => {
|
||||
const entries = response.list?.entries;
|
||||
if (entries) {
|
||||
response.list.entries = entries.map((entryData) => entryData.entry) as any;
|
||||
}
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getTaskListCounter(requestNode: TaskListRequestModel): Observable<number> {
|
||||
if (!requestNode.appName) {
|
||||
return throwError(() => new Error('Appname not configured'));
|
||||
}
|
||||
return this.fetchTaskList(requestNode).pipe(map((tasks) => tasks.list.pagination.totalItems));
|
||||
}
|
||||
|
||||
protected buildQueryData(requestNode: TaskListRequestModel) {
|
||||
const variableKeys = requestNode.variableKeys?.length > 0 ? requestNode.variableKeys.join(',') : undefined;
|
||||
|
||||
const queryData: any = {
|
||||
status: requestNode.status,
|
||||
processDefinitionName: requestNode.processDefinitionName,
|
||||
assignee: requestNode.assignee,
|
||||
priority: requestNode.priority,
|
||||
name: requestNode.name,
|
||||
completedBy: requestNode.completedBy,
|
||||
completedFrom: requestNode.completedFrom,
|
||||
completedTo: requestNode.completedTo,
|
||||
createdFrom: requestNode.createdFrom,
|
||||
createdTo: requestNode.createdTo,
|
||||
dueDateFrom: requestNode.dueDateFrom,
|
||||
dueDateTo: requestNode.dueDateTo,
|
||||
variableKeys
|
||||
};
|
||||
|
||||
Object.keys(queryData).forEach((key) => {
|
||||
const value = queryData[key];
|
||||
const isValueEmpty = !value;
|
||||
const isValueArrayWithEmptyValue = Array.isArray(value) && (value.length === 0 || value[0] === null);
|
||||
if (isValueEmpty || isValueArrayWithEmptyValue) {
|
||||
delete queryData[key];
|
||||
}
|
||||
});
|
||||
|
||||
return queryData;
|
||||
}
|
||||
|
||||
protected buildQueryParams(requestNode: TaskQueryCloudRequestModel): any {
|
||||
const queryParam: any = {};
|
||||
for (const propertyKey in requestNode) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user