AAE-25145 Sort process and task lists by process variables (#10412)

This commit is contained in:
Robert Duda 2024-11-21 12:24:33 +01:00 committed by GitHub
parent 356260b5d1
commit fc9c82733c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 169 additions and 26 deletions

View File

@ -16,7 +16,7 @@
*/
import { Pagination } from '@alfresco/js-api';
import { TaskListCloudSortingModel } from './task-list-sorting.model';
import { TaskListCloudSortingModel, TaskListRequestSortingModel } from './task-list-sorting.model';
import { TaskFilterCloudModel } from '../task/task-filters/models/filter-cloud.model';
export class TaskQueryCloudRequestModel {
@ -103,7 +103,7 @@ export interface TaskListRequestTaskVariableFilter {
export class TaskListRequestModel {
appName: string;
pagination?: Pagination;
sorting?: TaskListCloudSortingModel[];
sorting?: TaskListRequestSortingModel;
onlyStandalone?: boolean;
onlyRoot?: boolean;
@ -172,7 +172,11 @@ export class TaskFilterCloudAdapter extends TaskListRequestModel {
super({
appName: filter.appName,
pagination: { maxItems: 25, skipCount: 0 },
sorting: [{ orderBy: filter.sort, direction: filter.order }],
sorting: new TaskListRequestSortingModel({
orderBy: filter.sort,
direction: filter.order,
isFieldProcessVariable: false
}),
onlyStandalone: filter.standalone,
name: filter.taskNames,

View File

@ -26,3 +26,29 @@ export class TaskListCloudSortingModel {
}
}
}
export class TaskListRequestSortingModel extends TaskListCloudSortingModel {
orderBy: string;
direction: string;
isFieldProcessVariable: boolean;
processVariableData?: {
processDefinitionKeys: string[];
type: string;
}
constructor(obj: TaskListRequestSortingModel) {
super(obj);
if (obj.isFieldProcessVariable) {
this.isFieldProcessVariable = true;
this.processVariableData = obj.processVariableData;
if (!this.processVariableData.processDefinitionKeys?.length ||
!this.processVariableData.type
) {
throw new Error('missing required property when sorting by process variable');
}
} else {
this.isFieldProcessVariable = false;
}
}
}

View File

@ -48,7 +48,7 @@ import { ProcessListCloudService } from '../services/process-list-cloud.service'
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { processCloudPresetsDefaultModel } from '../models/process-cloud-preset.model';
import { ProcessListRequestModel, ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
import { ProcessListCloudSortingModel, ProcessListRequestSortingModel } from '../models/process-list-sorting.model';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
import {
@ -328,6 +328,7 @@ export class ProcessListCloudComponent
this.pagination.next(processes.list.pagination);
},
error: (error) => {
console.error(error);
this.error.emit(error);
this.isLoading = false;
}
@ -526,7 +527,7 @@ export class ProcessListCloudComponent
maxItems: this.size,
skipCount: this.skipCount
},
sorting: this.sorting,
sorting: this.getProcessListRequestSorting(),
name: this.names,
initiator: this.initiators,
appVersion: this.appVersions,
@ -545,6 +546,39 @@ export class ProcessListCloudComponent
return new ProcessListRequestModel(requestNode);
}
private getProcessListRequestSorting(): ProcessListRequestSortingModel {
if (!this.sorting?.length) {
return new ProcessListRequestSortingModel({
orderBy: this.defaultSorting.key,
direction: this.defaultSorting.direction,
isFieldProcessVariable: false
});
}
const orderBy = this.sorting[0]?.orderBy;
const direction = this.sorting[0]?.direction;
const orderByColumn = this.columnList?.columns.find((column) => column.key === orderBy);
const isFieldProcessVariable = orderByColumn?.customData?.columnType === 'process-variable-column';
if (isFieldProcessVariable) {
const processDefinitionKeys = orderByColumn.customData.variableDefinitionsPayload.map(
(variableDefinition) => variableDefinition.split('/')[0]
);
const variableName = orderByColumn.customData.variableDefinitionsPayload[0].split('/')[1];
return new ProcessListRequestSortingModel({
orderBy: variableName,
direction,
isFieldProcessVariable: true,
processVariableData: {
processDefinitionKeys,
type: orderByColumn.customData.variableType
}
});
} else {
return new ProcessListRequestSortingModel({orderBy, direction, isFieldProcessVariable: false});
}
}
private createRequestNode(): ProcessQueryCloudRequestModel {
const requestNode = {
appName: this.appName,

View File

@ -16,7 +16,7 @@
*/
import { Pagination } from '@alfresco/js-api';
import { ProcessListCloudSortingModel } from './process-list-sorting.model';
import { ProcessListCloudSortingModel, ProcessListRequestSortingModel } from './process-list-sorting.model';
import { ProcessFilterCloudModel } from '../../process-filters/models/process-filter-cloud.model';
export class ProcessQueryCloudRequestModel {
@ -90,7 +90,7 @@ export interface ProcessListRequestProcessVariableFilter {
export class ProcessListRequestModel {
appName: string;
pagination?: Pagination;
sorting?: ProcessListCloudSortingModel[];
sorting?: ProcessListRequestSortingModel;
name?: string[];
initiator?: string[];
@ -138,7 +138,11 @@ export class ProcessFilterCloudAdapter extends ProcessListRequestModel {
super({
appName: filter.appName,
pagination: { maxItems: 25, skipCount: 0 },
sorting: [{ orderBy: filter.sort, direction: filter.order }],
sorting: new ProcessListRequestSortingModel({
orderBy: filter.sort,
direction: filter.order,
isFieldProcessVariable: false
}),
name: filter.processDefinitionNames,
initiator: filter.initiators,

View File

@ -25,3 +25,28 @@ export class ProcessListCloudSortingModel {
}
}
}
export class ProcessListRequestSortingModel extends ProcessListCloudSortingModel {
orderBy: string;
direction: string;
isFieldProcessVariable: boolean;
processVariableData?: {
processDefinitionKeys: string[];
type: string;
}
constructor(obj: ProcessListRequestSortingModel) {
super(obj);
if (obj.isFieldProcessVariable) {
this.isFieldProcessVariable = true;
this.processVariableData = obj.processVariableData;
if (!this.processVariableData.processDefinitionKeys?.length ||
!this.processVariableData.type
) {
throw new Error('missing required property when sorting by process variable');
}
} else {
this.isFieldProcessVariable = false;
}
}
}

View File

@ -148,10 +148,7 @@ describe('ProcessListCloudService', () => {
const processRequest = {
appName: 'fakeName',
pagination: { skipCount: 0, maxItems: 20 },
sorting: [
{ orderBy: 'NAME', direction: 'DESC' },
{ orderBy: 'TITLE', direction: 'ASC' }
]
sorting: { orderBy: 'NAME', direction: 'DESC', isFieldProcessVariable: false }
} as ProcessListRequestModel;
requestSpy.and.callFake(returnCallQueryParameters);
@ -159,7 +156,6 @@ describe('ProcessListCloudService', () => {
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 () => {

View File

@ -85,8 +85,7 @@ export class ProcessListCloudService extends BaseCloudService {
const queryParams = {
maxItems: requestNode.pagination?.maxItems || 25,
skipCount: requestNode.pagination?.skipCount || 0,
sort: this.buildSortingParam(requestNode.sorting || [])
skipCount: requestNode.pagination?.skipCount || 0
};
const queryData = this.buildQueryData(requestNode);
@ -118,6 +117,18 @@ export class ProcessListCloudService extends BaseCloudService {
processVariableKeys: requestNode.processVariableKeys
};
if (requestNode.sorting) {
queryData['sort'] = {
field: requestNode.sorting.orderBy,
direction: requestNode.sorting.direction.toLowerCase(),
isProcessVariable: requestNode.sorting.isFieldProcessVariable
};
if (queryData['sort'].isProcessVariable) {
queryData['sort'].processDefinitionKeys = requestNode.sorting.processVariableData?.processDefinitionKeys;
queryData['sort'].type = requestNode.sorting.processVariableData?.type;
}
}
Object.keys(queryData).forEach((key) => {
const value = queryData[key];
const isValueEmpty = !value;

View File

@ -148,7 +148,7 @@ export abstract class BaseTaskListCloudComponent<T = unknown>
formattedSorting: any[];
dataAdapter: ObjectDataTableAdapter | undefined;
private defaultSorting = { key: 'startDate', direction: 'desc' };
protected defaultSorting = { key: 'startDate', direction: 'desc' };
boundReplacePriorityValues: (row: DataRow, col: DataColumn) => any;
protected abstract isLoading$: Observable<boolean>;

View File

@ -24,7 +24,7 @@ import { TASK_LIST_CLOUD_TOKEN, TASK_LIST_PREFERENCES_SERVICE_TOKEN, TASK_SEARCH
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
import { TaskListCloudServiceInterface } from '../../../services/task-list-cloud.service.interface';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { filter, map, switchMap, take } from 'rxjs/operators';
import { filter, map, switchMap, take, tap } 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';
@ -32,6 +32,7 @@ import { PaginatedEntries } from '@alfresco/js-api';
import { TaskInstanceCloudListViewModel } from '../models/task-cloud-view.model';
import { TasksListDatatableAdapter } from '../datatable/task-list-datatable-adapter';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { TaskListRequestSortingModel } from '../../../models/task-list-sorting.model';
const PRESET_KEY = 'adf-cloud-task-list.presets';
@ -211,6 +212,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
combineLatest([this.isColumnSchemaCreated$, this.fetchProcessesTrigger$])
.pipe(
tap(() => this.isReloadingSubject$.next(true)),
filter((isColumnSchemaCreated) => !!isColumnSchemaCreated),
switchMap(() => {
if (this.searchMethod === 'POST') {
@ -240,6 +242,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
this.pagination.next(tasks.list.pagination);
},
error: (error) => {
console.error(error);
this.error.emit(error);
this.isReloadingSubject$.next(false);
}
@ -258,7 +261,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
maxItems: this.size,
skipCount: this.skipCount
},
sorting: this.sorting,
sorting: this.getTaskListRequestSorting(),
onlyStandalone: this.standalone,
name: this.names,
processDefinitionName: this.processDefinitionNames,
@ -329,4 +332,37 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
return displayedVariableColumns.length ? displayedVariableColumns : undefined;
}
private getTaskListRequestSorting(): TaskListRequestSortingModel {
if (!this.sorting?.length) {
return new TaskListRequestSortingModel({
orderBy: this.defaultSorting.key,
direction: this.defaultSorting.direction,
isFieldProcessVariable: false
});
}
const orderBy = this.sorting[0]?.orderBy;
const direction = this.sorting[0]?.direction;
const orderByColumn = this.columnList?.columns.find((column) => column.key === orderBy);
const isFieldProcessVariable = orderByColumn?.customData?.columnType === 'process-variable-column';
if (isFieldProcessVariable) {
const processDefinitionKeys = orderByColumn.customData.variableDefinitionsPayload.map(
(variableDefinition) => variableDefinition.split('/')[0]
);
const variableName = orderByColumn.customData.variableDefinitionsPayload[0].split('/')[1];
return new TaskListRequestSortingModel({
orderBy: variableName,
direction,
isFieldProcessVariable: true,
processVariableData: {
processDefinitionKeys,
type: orderByColumn.customData.variableType
}
});
} else {
return new TaskListRequestSortingModel({orderBy, direction, isFieldProcessVariable: false});
}
}
}

View File

@ -139,10 +139,7 @@ describe('TaskListCloudService', () => {
const taskRequest = {
appName: 'fakeName',
pagination: { skipCount: 0, maxItems: 20 },
sorting: [
{ orderBy: 'NAME', direction: 'DESC' },
{ orderBy: 'TITLE', direction: 'ASC' }
]
sorting: { orderBy: 'NAME', direction: 'DESC', isFieldProcessVariable: false }
} as TaskListRequestModel;
requestSpy.and.callFake(returnCallQueryParameters);
@ -150,7 +147,6 @@ describe('TaskListCloudService', () => {
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 () => {

View File

@ -74,8 +74,7 @@ export class TaskListCloudService extends BaseCloudService implements TaskListCl
const queryParams = {
maxItems: requestNode.pagination?.maxItems || 25,
skipCount: requestNode.pagination?.skipCount || 0,
sort: this.buildSortingParam(requestNode.sorting || [])
skipCount: requestNode.pagination?.skipCount || 0
};
const queryData = this.buildQueryData(requestNode);
@ -115,6 +114,18 @@ export class TaskListCloudService extends BaseCloudService implements TaskListCl
processVariableKeys: requestNode.processVariableKeys
};
if (requestNode.sorting) {
queryData['sort'] = {
field: requestNode.sorting.orderBy,
direction: requestNode.sorting.direction.toLowerCase(),
isProcessVariable: requestNode.sorting.isFieldProcessVariable
};
if (queryData['sort'].isProcessVariable) {
queryData['sort'].processDefinitionKeys = requestNode.sorting.processVariableData?.processDefinitionKeys;
queryData['sort'].type = requestNode.sorting.processVariableData?.type;
}
}
Object.keys(queryData).forEach((key) => {
const value = queryData[key];
const isValueEmpty = !value;