diff --git a/docs/process-services/services/task-filter.service.md b/docs/process-services/services/task-filter.service.md
index 0d47dd8e06..f537b02df7 100644
--- a/docs/process-services/services/task-filter.service.md
+++ b/docs/process-services/services/task-filter.service.md
@@ -30,8 +30,8 @@ Manage Task Filters, which are pre-configured Task Instance queries.
- _appId:_ `number` - ID of the target app
- _index:_ `number` - (Optional) of the filter (optional)
- **Returns** `UserTaskFilterRepresentation` - The newly created filter
-- **getInvolvedTasksFilterInstance**(appId: `number`, index?: `number`): `UserTaskFilterRepresentation`
- Creates and returns a filter for "Involved" task instances.
+- **getOverdueTasksFilterInstance**(appId: `number`, index?: `number`): `UserTaskFilterRepresentation`
+ Creates and returns a filter for "Overdue" task instances.
- _appId:_ `number` - ID of the target app
- _index:_ `number` - (Optional) of the filter (optional)
- **Returns** `UserTaskFilterRepresentation` - The newly created filter
@@ -40,8 +40,8 @@ Manage Task Filters, which are pre-configured Task Instance queries.
- _appId:_ `number` - ID of the target app
- _index:_ `number` - (Optional) of the filter (optional)
- **Returns** `UserTaskFilterRepresentation` - The newly created filter
-- **getQueuedTasksFilterInstance**(appId: `number`, index?: `number`): `UserTaskFilterRepresentation`
- Creates and returns a filter for "Queued Tasks" task instances.
+- **getUnassignedTasksFilterInstance**(appId: `number`, index?: `number`): `UserTaskFilterRepresentation`
+ Creates and returns a filter for "Unassigned Tasks" task instances.
- _appId:_ `number` - ID of the target app
- _index:_ `number` - (Optional) of the filter (optional)
- **Returns** `UserTaskFilterRepresentation` - The newly created filter
@@ -55,6 +55,11 @@ Manage Task Filters, which are pre-configured Task Instance queries.
- _taskName:_ `string` - Name of the filter
- _appId:_ `number` - (Optional) ID of the app for the filter
- **Returns** `ObservableUserTaskFilterRepresentation>` - Details of task filter
+- **updateTaskFilter**(filterId: `number`, updatedFilter: `UserTaskFilterRepresentation`): `Observable`
+ Updates the instance of the filter.
+ - filterId:_ `number` - ID of a filter to update
+ - updatedFilter:_ `UserTaskFilterRepresentation` - new filter body
+ - **Returns** `Observable` - Updated filter instance.
- **getTaskListFilters**(appId?: `number`): `UserTaskFilterRepresentation[]>`
Gets all task filters for a process app.
- _appId:_ `number` - (Optional) Optional ID for a specific app
@@ -84,16 +89,16 @@ The response is an array of `UserTaskFilterRepresentation` objects:
filters:
0: {id: 10, appId: 2, name: "Involved Tasks", recent: true, icon: "glyphicon-align-left", …}
1: {id: 9, appId: 2, name: "My Tasks", recent: false, icon: "glyphicon-inbox", …}
- 2: {id: 11, appId: 2, name: "Queued Tasks", recent: false, icon: "glyphicon-record", …}
+ 2: {id: 11, appId: 2, name: "Unassigned Tasks", recent: false, icon: "glyphicon-record", …}
3: {id: 12, appId: 2, name: "Completed Tasks", recent: false, icon: "glyphicon-ok-sign", …}
4: {id: 4004, appId: 2, name: "Completed Tasks", recent: false, icon: "glyphicon-ok-sign", …}
5: {id: 4005, appId: 2, name: "My Tasks", recent: false, icon: "glyphicon-inbox", …}
- 6: {id: 4006, appId: 2, name: "Queued Tasks", recent: false, icon: "glyphicon-record", …}
+ 6: {id: 4006, appId: 2, name: "Unassigned Tasks", recent: false, icon: "glyphicon-record", …}
7: {id: 4007, appId: 2, name: "Involved Tasks", recent: false, icon: "glyphicon-align-left", …}
```
These filters can now be used to get matching task instances for the process app with ID 2,
-such as 'Involved Tasks', 'My Tasks', 'Queued Tasks', and 'Completed Tasks'.
+such as 'Involved Tasks', 'My Tasks', 'Unassigned Tasks', and 'Completed Tasks'.
### Importing
diff --git a/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.spec.ts b/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.spec.ts
index 86559c7cce..d98809e692 100644
--- a/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.spec.ts
+++ b/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.spec.ts
@@ -117,6 +117,50 @@ describe('TaskFiltersComponent', () => {
expect(createDefaultFiltersSpy).toHaveBeenCalledWith(appId);
});
+ it('should migrate obsolete filters to their new instances', () => {
+ const involvedFilter = new UserTaskFilterRepresentation({
+ name: 'Involved Tasks',
+ icon: 'glyphicon-align-left',
+ id: 10,
+ filter: { state: 'open', assignment: 'involved' }
+ });
+ const queuedFilter = new UserTaskFilterRepresentation({
+ name: 'Queued Tasks',
+ icon: 'glyphicon-ok-sign',
+ id: 11,
+ filter: { state: 'open', assignment: 'candidate' }
+ });
+ const taskFilters = [involvedFilter, queuedFilter];
+ spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(of(taskFilters));
+ spyOn(taskFilterService, 'updateTaskFilter').and.returnValue(of({}));
+ component.getFiltersByAppId(1);
+ fixture.detectChanges();
+ expect(taskFilterService.updateTaskFilter).toHaveBeenCalledTimes(2);
+ expect(taskFilterService.updateTaskFilter).toHaveBeenCalledWith(10, taskFilterService.getOverdueTasksFilterInstance(undefined));
+ expect(taskFilterService.updateTaskFilter).toHaveBeenCalledWith(11, taskFilterService.getUnassignedTasksFilterInstance(undefined));
+ });
+
+ it('should not migrate other filters', () => {
+ const myTasksFilter = new UserTaskFilterRepresentation({
+ name: 'My Tasks',
+ icon: 'glyphicon-align-left',
+ id: 10,
+ filter: { state: 'open', assignment: 'assignee' }
+ });
+ const completedFilter = new UserTaskFilterRepresentation({
+ name: 'Completed Tasks',
+ icon: 'glyphicon-ok-sign',
+ id: 11,
+ filter: { state: 'completed', assignment: 'involved' }
+ });
+ const taskFilters = [myTasksFilter, completedFilter];
+ spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(of(taskFilters));
+ spyOn(taskFilterService, 'updateTaskFilter').and.returnValue(of({}));
+ component.getFiltersByAppId(1);
+ fixture.detectChanges();
+ expect(taskFilterService.updateTaskFilter).not.toHaveBeenCalled();
+ });
+
it('should return the filter task list, filtered By Name', () => {
const deployApp = spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(of({} as any));
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(of(fakeTaskFilters));
diff --git a/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.ts b/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.ts
index 8d779a8ebe..fbedaecd11 100644
--- a/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.ts
+++ b/lib/process-services/src/lib/task-list/components/task-filters/task-filters.component.ts
@@ -28,6 +28,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { IconComponent } from '@alfresco/adf-core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { forkJoin, Observable } from 'rxjs';
@Component({
selector: 'adf-task-filters',
@@ -136,10 +137,14 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
if (res.length === 0 && this.isFilterListEmpty()) {
this.createFiltersByAppId(appId);
} else {
- this.resetFilter();
- this.filters = res;
- this.selectFilter(this.filterParam);
- this.success.emit(res);
+ const migratedFilters = this.migrateObsoleteFilters(res);
+ if (migratedFilters.length > 0) {
+ forkJoin(migratedFilters).subscribe(() => {
+ this.setTaskFilters(res);
+ });
+ } else {
+ this.setTaskFilters(res);
+ }
}
},
(err: any) => {
@@ -172,10 +177,7 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
private createFiltersByAppId(appId?: number): void {
this.taskFilterService.createDefaultFilters(appId).subscribe(
(resDefault) => {
- this.resetFilter();
- this.filters = resDefault;
- this.selectFilter(this.filterParam);
- this.success.emit(resDefault);
+ this.setTaskFilters(resDefault);
},
(errDefault: any) => {
this.error.emit(errDefault);
@@ -272,4 +274,41 @@ export class TaskFiltersComponent implements OnInit, OnChanges {
this.filters = [];
this.currentFilter = undefined;
}
+
+ /**
+ * Migrate "Involved" and "Queued" filters to "Overdue" and "Unassigned" filters
+ *
+ * @param filters - list of filters to migrate
+ * @returns list of observables for each migrated filter
+ */
+ private migrateObsoleteFilters(filters: UserTaskFilterRepresentation[]): Observable[] {
+ const migratedFilters: Observable[] = [];
+ filters.forEach((filterToMigrate) => {
+ switch (filterToMigrate.name) {
+ case 'Involved Tasks':
+ migratedFilters.push(
+ this.taskFilterService.updateTaskFilter(filterToMigrate.id, this.taskFilterService.getOverdueTasksFilterInstance(this.appId))
+ );
+ break;
+ case 'Queued Tasks':
+ migratedFilters.push(
+ this.taskFilterService.updateTaskFilter(
+ filterToMigrate.id,
+ this.taskFilterService.getUnassignedTasksFilterInstance(this.appId)
+ )
+ );
+ break;
+ default:
+ break;
+ }
+ });
+ return migratedFilters;
+ }
+
+ private setTaskFilters(taskFilters: UserTaskFilterRepresentation[]): void {
+ this.resetFilter();
+ this.filters = taskFilters;
+ this.selectFilter(this.filterParam);
+ this.success.emit(taskFilters);
+ }
}
diff --git a/lib/process-services/src/lib/task-list/services/task-filter.service.spec.ts b/lib/process-services/src/lib/task-list/services/task-filter.service.spec.ts
new file mode 100644
index 0000000000..6749ef1f65
--- /dev/null
+++ b/lib/process-services/src/lib/task-list/services/task-filter.service.spec.ts
@@ -0,0 +1,166 @@
+/*!
+ * @license
+ * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * 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 { TestBed } from '@angular/core/testing';
+import { TaskFilterService } from './task-filter.service';
+import { CoreTestingModule } from '@alfresco/adf-core';
+import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
+
+describe('TaskListService', () => {
+ let service: TaskFilterService;
+
+ const mockTaskFilters = [
+ { id: 1, name: 'first one' },
+ { id: 2, name: 'second one' },
+ { id: 3, name: 'third one' }
+ ];
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [CoreTestingModule],
+ providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }]
+ });
+ service = TestBed.inject(TaskFilterService);
+ });
+
+ it('should provide my tasks filter instance', () => {
+ const myTasksFilter = service.getMyTasksFilterInstance(1, 11);
+ expect(myTasksFilter.name).toBe('My Tasks');
+ expect(myTasksFilter.appId).toBe(1);
+ expect(myTasksFilter.recent).toBe(false);
+ expect(myTasksFilter.icon).toBe('glyphicon-inbox');
+ expect(myTasksFilter.index).toBe(11);
+ expect(myTasksFilter.filter.sort).toBe('created-desc');
+ expect(myTasksFilter.filter.name).toBe('');
+ expect(myTasksFilter.filter.state).toBe('open');
+ expect(myTasksFilter.filter.assignment).toBe('assignee');
+ });
+
+ it('should provide overdue tasks filter instance', () => {
+ const overdueTasksFilter = service.getOverdueTasksFilterInstance(1, 11);
+ expect(overdueTasksFilter.name).toBe('Overdue Tasks');
+ expect(overdueTasksFilter.appId).toBe(1);
+ expect(overdueTasksFilter.recent).toBe(false);
+ expect(overdueTasksFilter.icon).toBe('glyphicon-align-left');
+ expect(overdueTasksFilter.index).toBe(11);
+ expect(overdueTasksFilter.filter.sort).toBe('created-desc');
+ expect(overdueTasksFilter.filter.name).toBe('');
+ expect(overdueTasksFilter.filter.state).toBe('open');
+ expect(overdueTasksFilter.filter.assignment).toBe('assignee');
+ });
+
+ it('should provide unassigned tasks filter instance', () => {
+ const unassignedTasksFilter = service.getUnassignedTasksFilterInstance(1, 11);
+ expect(unassignedTasksFilter.name).toBe('Unassigned Tasks');
+ expect(unassignedTasksFilter.appId).toBe(1);
+ expect(unassignedTasksFilter.recent).toBe(false);
+ expect(unassignedTasksFilter.icon).toBe('glyphicon-record');
+ expect(unassignedTasksFilter.index).toBe(11);
+ expect(unassignedTasksFilter.filter.sort).toBe('created-desc');
+ expect(unassignedTasksFilter.filter.name).toBe('');
+ expect(unassignedTasksFilter.filter.state).toBe('open');
+ expect(unassignedTasksFilter.filter.assignment).toBe('candidate');
+ });
+
+ it('should provide completed tasks filter instance', () => {
+ const completedTasksFilter = service.getCompletedTasksFilterInstance(1, 11);
+ expect(completedTasksFilter.name).toBe('Completed Tasks');
+ expect(completedTasksFilter.appId).toBe(1);
+ expect(completedTasksFilter.recent).toBe(true);
+ expect(completedTasksFilter.icon).toBe('glyphicon-ok-sign');
+ expect(completedTasksFilter.index).toBe(11);
+ expect(completedTasksFilter.filter.sort).toBe('created-desc');
+ expect(completedTasksFilter.filter.name).toBe('');
+ expect(completedTasksFilter.filter.state).toBe('completed');
+ expect(completedTasksFilter.filter.assignment).toBe('involved');
+ });
+
+ it('should call right task filters api', () => {
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({}));
+ service.callApiTaskFilters(1);
+ service.callApiTaskFilters();
+ expect(service.userFiltersApi.getUserTaskFilters).toHaveBeenCalledTimes(2);
+ expect(service.userFiltersApi.getUserTaskFilters).toHaveBeenCalledWith({ appId: 1 });
+ });
+
+ it('should call right update task filter api', () => {
+ spyOn(service.userFiltersApi, 'updateUserTaskFilter').and.returnValue(Promise.resolve({}));
+ service.updateTaskFilter(1, { name: 'test' });
+ expect(service.userFiltersApi.updateUserTaskFilter).toHaveBeenCalledTimes(1);
+ expect(service.userFiltersApi.updateUserTaskFilter).toHaveBeenCalledWith(1, { name: 'test' });
+ });
+
+ it('should call right add task filter api', () => {
+ spyOn(service.userFiltersApi, 'createUserTaskFilter').and.returnValue(Promise.resolve({}));
+ service.addFilter({ name: 'test' });
+ expect(service.userFiltersApi.createUserTaskFilter).toHaveBeenCalledTimes(1);
+ expect(service.userFiltersApi.createUserTaskFilter).toHaveBeenCalledWith({ name: 'test' });
+ });
+
+ it('should get task filter by name if response contain matching one', (done) => {
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({ data: mockTaskFilters }));
+ service.getTaskFilterByName('first one').subscribe((filter) => {
+ expect(filter.name).toBe('first one');
+ done();
+ });
+ });
+
+ it('should return undefined if task with given name is not found in the response', (done) => {
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({ data: mockTaskFilters }));
+ service.getTaskFilterByName('other one').subscribe((filter) => {
+ expect(filter).toBeUndefined();
+ done();
+ });
+ });
+
+ it('should get task filter by id if response contain matching one', (done) => {
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({ data: mockTaskFilters }));
+ service.getTaskFilterById(2).subscribe((filter) => {
+ expect(filter.id).toBe(2);
+ expect(filter.name).toBe('second one');
+ done();
+ });
+ });
+
+ it('should return undefined if task with given id is not found in the response', (done) => {
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({ data: mockTaskFilters }));
+ service.getTaskFilterByName('other one').subscribe((filter) => {
+ expect(filter).toBeUndefined();
+ done();
+ });
+ });
+
+ it('should return true if filter with given name exists', () => {
+ expect(service.isFilterAlreadyExisting(mockTaskFilters, 'first one')).toBe(true);
+ });
+
+ it('should return false if filter with given name does not exist', () => {
+ expect(service.isFilterAlreadyExisting(mockTaskFilters, 'another one')).toBe(false);
+ });
+
+ it('should return list of task filters without duplications', (done) => {
+ mockTaskFilters.push({ id: 1, name: 'first one' });
+ spyOn(service.userFiltersApi, 'getUserTaskFilters').and.returnValue(Promise.resolve({ data: mockTaskFilters }));
+ service.getTaskListFilters().subscribe((filters) => {
+ expect(filters.length).toBe(3);
+ expect(filters[0].name).toBe('first one');
+ expect(filters[1].name).toBe('second one');
+ expect(filters[2].name).toBe('third one');
+ done();
+ });
+ });
+});
diff --git a/lib/process-services/src/lib/task-list/services/task-filter.service.ts b/lib/process-services/src/lib/task-list/services/task-filter.service.ts
index c6e40cffac..6ae14178b6 100644
--- a/lib/process-services/src/lib/task-list/services/task-filter.service.ts
+++ b/lib/process-services/src/lib/task-list/services/task-filter.service.ts
@@ -43,25 +43,25 @@ export class TaskFilterService {
const myTasksFilter = this.getMyTasksFilterInstance(appId, 0);
const myTaskObservable = this.addFilter(myTasksFilter);
- const involvedTasksFilter = this.getInvolvedTasksFilterInstance(appId, 1);
- const involvedObservable = this.addFilter(involvedTasksFilter);
+ const overdueTasksFilter = this.getOverdueTasksFilterInstance(appId, 1);
+ const overdueObservable = this.addFilter(overdueTasksFilter);
- const queuedTasksFilter = this.getQueuedTasksFilterInstance(appId, 2);
- const queuedObservable = this.addFilter(queuedTasksFilter);
+ const unassignedTasksFilter = this.getUnassignedTasksFilterInstance(appId, 2);
+ const unassignedObservable = this.addFilter(unassignedTasksFilter);
const completedTasksFilter = this.getCompletedTasksFilterInstance(appId, 3);
const completeObservable = this.addFilter(completedTasksFilter);
return new Observable((observer) => {
- forkJoin([myTaskObservable, involvedObservable, queuedObservable, completeObservable]).subscribe((res) => {
+ forkJoin([myTaskObservable, overdueObservable, unassignedObservable, completeObservable]).subscribe((res) => {
const filters: UserTaskFilterRepresentation[] = [];
res.forEach((filter) => {
if (!this.isFilterAlreadyExisting(filters, filter.name)) {
- if (filter.name === involvedTasksFilter.name) {
+ if (filter.name === overdueTasksFilter.name) {
filters.push(
new UserTaskFilterRepresentation({
...filter,
- filter: involvedTasksFilter.filter,
+ filter: overdueTasksFilter.filter,
appId
})
);
@@ -73,11 +73,11 @@ export class TaskFilterService {
appId
})
);
- } else if (filter.name === queuedTasksFilter.name) {
+ } else if (filter.name === unassignedTasksFilter.name) {
filters.push(
new UserTaskFilterRepresentation({
...filter,
- filter: queuedTasksFilter.filter,
+ filter: unassignedTasksFilter.filter,
appId
})
);
@@ -162,6 +162,17 @@ export class TaskFilterService {
return from(this.userFiltersApi.createUserTaskFilter(filter));
}
+ /**
+ * Update a task filter
+ *
+ * @param filterId existing filter id
+ * @param updatedFilter updated filter body
+ * @returns Observable
+ */
+ updateTaskFilter(filterId: number, updatedFilter: UserTaskFilterRepresentation): Observable {
+ return from(this.userFiltersApi.updateUserTaskFilter(filterId, updatedFilter));
+ }
+
/**
* Calls `getUserTaskFilters` from the Alfresco JS API.
*
@@ -200,33 +211,33 @@ export class TaskFilterService {
}
/**
- * Creates and returns a filter for "Involved" task instances.
+ * Creates and returns a filter for "Overdue" task instances.
*
* @param appId ID of the target app
* @param index of the filter (optional)
* @returns The newly created filter
*/
- getInvolvedTasksFilterInstance(appId: number, index?: number): UserTaskFilterRepresentation {
+ getOverdueTasksFilterInstance(appId: number, index?: number): UserTaskFilterRepresentation {
return new UserTaskFilterRepresentation({
- name: 'Involved Tasks',
+ name: 'Overdue Tasks',
appId,
recent: false,
icon: 'glyphicon-align-left',
- filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'involved' },
+ filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'assignee' },
index
});
}
/**
- * Creates and returns a filter for "Queued Tasks" task instances.
+ * Creates and returns a filter for "Unassigned Tasks" task instances.
*
* @param appId ID of the target app
* @param index of the filter (optional)
* @returns The newly created filter
*/
- getQueuedTasksFilterInstance(appId: number, index?: number): UserTaskFilterRepresentation {
+ getUnassignedTasksFilterInstance(appId: number, index?: number): UserTaskFilterRepresentation {
return new UserTaskFilterRepresentation({
- name: 'Queued Tasks',
+ name: 'Unassigned Tasks',
appId,
recent: false,
icon: 'glyphicon-record',