[AAE-3694] Add new Service Method for service task integration (#6199)

* [AAE-3694] Add new Service Method for service task integration

* Split task list services in two

* Move ServiceTaskQueryCloudRequestModel to a newe file
This commit is contained in:
davidcanonieto
2020-10-01 14:15:39 +02:00
committed by GitHub
parent f2f9049c2c
commit 877a9f00e9
10 changed files with 312 additions and 71 deletions

View File

@@ -1,15 +1,12 @@
<div fxLayout="row"
fxFill
fxLayoutGap="2px">
<div fxLayout
fxFill>
<adf-cloud-service-task-filters [appName]="appName"
[filterParam]="{index: 0}"
(filterClick)="onTaskFilterSelected($event)">
</adf-cloud-service-task-filters>
<div fxLayout="column"
fxFill
fxLayoutGap="2px">
fxFlex>
<adf-cloud-edit-service-task-filter [id]="filterId"
[appName]="appName"
[filterProperties]="taskFilterProperties.filterProperties"
@@ -19,6 +16,7 @@
</adf-cloud-edit-service-task-filter>
<div fxLayout="column"
fxFlex
fxFill
fxLayoutAlign="space-between"
*ngIf="editedFilter">
<adf-cloud-service-task-list #taskCloud

View File

@@ -39,7 +39,7 @@ import { BaseEditTaskFilterCloudComponent } from './base-edit-task-filter-cloud.
export class EditServiceTaskFilterCloudComponent extends BaseEditTaskFilterCloudComponent {
public static DEFAULT_TASK_FILTER_PROPERTIES = ['appName', 'activityName', 'status', 'sort', 'order'];
public static DEFAULT_TASK_SORT_PROPERTIES = ['id', 'name', 'startedDate', 'completedDate'];
public static DEFAULT_TASK_SORT_PROPERTIES = ['id', 'activityName', 'startedDate', 'completedDate'];
public static DEFAULT_TASK_STATUS_PROPERTIES = [
{ label: 'ALL', value: '' },
{ label: 'STARTED', value: 'STARTED' },

View File

@@ -19,7 +19,6 @@ import { Component, SimpleChange, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { AppConfigService, setupTestBed, DataRowEvent, ObjectDataRow } from '@alfresco/adf-core';
import { TaskListCloudService } from '../services/task-list-cloud.service';
import { ServiceTaskListCloudComponent } from './service-task-list-cloud.component';
import { fakeServiceTask, fakeCustomSchema } from '../mock/fake-task-response.mock';
import { of } from 'rxjs';
@@ -28,6 +27,7 @@ import { Person } from '@alfresco/js-api';
import { TranslateModule } from '@ngx-translate/core';
import { TaskListCloudSortingModel } from '../models/task-list-sorting.model';
import { skip } from 'rxjs/operators';
import { ServiceTaskListCloudService } from '../services/service-task-list-cloud.service';
@Component({
template: `
@@ -75,7 +75,7 @@ describe('ServiceTaskListCloudComponent', () => {
let component: ServiceTaskListCloudComponent;
let fixture: ComponentFixture<ServiceTaskListCloudComponent>;
let appConfig: AppConfigService;
let taskListCloudService: TaskListCloudService;
let serviceTaskListCloudService: ServiceTaskListCloudService;
setupTestBed({
imports: [
@@ -89,7 +89,7 @@ describe('ServiceTaskListCloudComponent', () => {
beforeEach(() => {
appConfig = TestBed.inject(AppConfigService);
taskListCloudService = TestBed.inject(TaskListCloudService);
serviceTaskListCloudService = TestBed.inject(ServiceTaskListCloudService);
fixture = TestBed.createComponent(ServiceTaskListCloudComponent);
component = fixture.componentInstance;
appConfig.config = Object.assign(appConfig.config, {
@@ -126,7 +126,7 @@ describe('ServiceTaskListCloudComponent', () => {
it('should display empty content when process list is empty', () => {
const emptyList = { list: { entries: [] } };
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(emptyList));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(emptyList));
fixture.detectChanges();
expect(component.isLoading).toBe(true);
@@ -145,7 +145,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should load spinner and show the content', () => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
fixture.detectChanges();
@@ -187,7 +187,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should return the results if an application name is given', (done) => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
component.success.subscribe((res) => {
expect(res).toBeDefined();
@@ -216,7 +216,7 @@ describe('ServiceTaskListCloudComponent', () => {
it('should reload tasks when reload() is called', (done) => {
component.appName = 'fake';
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
component.success.subscribe((res) => {
expect(res).toBeDefined();
expect(component.rows).toBeDefined();
@@ -250,14 +250,14 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should NOT reload the task list when no parameters changed', () => {
spyOn(taskListCloudService, 'getTaskByRequest');
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest');
component.rows = null;
fixture.detectChanges();
expect(component.isListEmpty()).toBeTruthy();
});
it('should reload the task list when input parameters changed', () => {
const getServiceTaskByRequestSpy = spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
const getServiceTaskByRequestSpy = spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
component.appName = 'mock-app-name';
component.queryParams.status = 'mock-status';
const queryParams = new SimpleChange(undefined, { status: 'mock-status' }, true);
@@ -270,7 +270,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should set formattedSorting if sorting input changes', () => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(component, 'formatSorting').and.callThrough();
component.appName = 'mock-app-name';
@@ -290,7 +290,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should reload task list when sorting on a column changes', () => {
const getServiceTaskByRequestSpy = spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
const getServiceTaskByRequestSpy = spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
component.onSortingChanged(new CustomEvent('sorting-changed', {
detail: {
key: 'fakeName',
@@ -311,7 +311,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should reset pagination when resetPaginationValues is called', async (done) => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
component.ngOnChanges({ appName });
@@ -339,7 +339,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
it('should set pagination and reload when updatePagination is called', (done) => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(component, 'reload').and.stub();
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
component.ngOnChanges({ appName });
@@ -382,7 +382,7 @@ describe('ServiceTaskListCloudComponent', () => {
});
beforeEach(() => {
spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
fixtureCustom = TestBed.createComponent(CustomTaskListComponent);
copyFixture = TestBed.createComponent(CustomCopyContentTaskListComponent);
fixtureCustom.detectChanges();
@@ -451,7 +451,7 @@ describe('ServiceTaskListCloudComponent', () => {
beforeEach(() => {
appConfig = TestBed.inject(AppConfigService);
taskListCloudService = TestBed.inject(TaskListCloudService);
serviceTaskListCloudService = TestBed.inject(ServiceTaskListCloudService);
appConfig.config = Object.assign(appConfig.config, {
'adf-cloud-service-task-list': {
'presets': {
@@ -476,7 +476,7 @@ describe('ServiceTaskListCloudComponent', () => {
fixture = TestBed.createComponent(ServiceTaskListCloudComponent);
component = fixture.componentInstance;
element = fixture.debugElement.nativeElement;
taskSpy = spyOn(taskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
taskSpy = spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
});
afterEach(() => {

View File

@@ -19,9 +19,9 @@ import { Component, ViewEncapsulation, Input } from '@angular/core';
import {
AppConfigService, UserPreferencesService
} from '@alfresco/adf-core';
import { ServiceTaskQueryCloudRequestModel } from '../models/filter-cloud-model';
import { TaskListCloudService } from '../services/task-list-cloud.service';
import { ServiceTaskQueryCloudRequestModel } from '../models/service-task-cloud.model';
import { BaseTaskListCloudComponent } from './base-task-list-cloud.component';
import { ServiceTaskListCloudService } from '../services/service-task-list-cloud.service';
@Component({
selector: 'adf-cloud-service-task-list',
@@ -36,7 +36,7 @@ export class ServiceTaskListCloudComponent extends BaseTaskListCloudComponent {
@Input()
queryParams: { [key: string]: any } = {};
constructor(private taskListCloudService: TaskListCloudService,
constructor(private serviceTaskListCloudService: ServiceTaskListCloudService,
appConfigService: AppConfigService,
userPreferences: UserPreferencesService) {
super(appConfigService, userPreferences, ServiceTaskListCloudComponent.PRESET_KEY);
@@ -44,7 +44,7 @@ export class ServiceTaskListCloudComponent extends BaseTaskListCloudComponent {
load(requestNode: ServiceTaskQueryCloudRequestModel) {
this.isLoading = true;
this.taskListCloudService.getServiceTaskByRequest(requestNode).subscribe(
this.serviceTaskListCloudService.getServiceTaskByRequest(requestNode).subscribe(
(tasks) => {
this.rows = tasks.list.entries;
this.success.emit(tasks);

View File

@@ -80,26 +80,3 @@ export class TaskQueryCloudRequestModel {
}
}
}
export interface ServiceTaskQueryCloudRequestModel {
appName: string;
appVersion?: string;
id?: string;
status?: string;
maxItems: number;
skipCount: number;
sorting?: TaskListCloudSortingModel[];
activityName?: string;
activityType?: string;
completedDate?: Date;
elementId?: string;
executionId?: string;
processDefinitionId?: string;
processDefinitionKey?: string;
processDefinitionVersion?: number;
processInstanceId?: string;
serviceFullName?: string;
serviceName?: string;
serviceVersion?: string;
startedDate?: Date;
}

View File

@@ -0,0 +1,48 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TaskListCloudSortingModel } from './task-list-sorting.model';
export interface ServiceTaskQueryCloudRequestModel {
appName: string;
appVersion?: string;
id?: string;
status?: string;
maxItems: number;
skipCount: number;
sorting?: TaskListCloudSortingModel[];
activityName?: string;
activityType?: string;
completedDate?: Date;
elementId?: string;
executionId?: string;
processDefinitionId?: string;
processDefinitionKey?: string;
processDefinitionVersion?: number;
processInstanceId?: string;
serviceFullName?: string;
serviceName?: string;
serviceVersion?: string;
startedDate?: Date;
}
export interface ServiceTaskIntegrationContextCloudModel extends ServiceTaskQueryCloudRequestModel {
errorDate?: Date;
errorClassName?: string;
errorCode?: string;
errorMessage?: string;
}

View File

@@ -19,6 +19,7 @@ export * from './components/task-list-cloud.component';
export * from './components/service-task-list-cloud.component';
export * from './models/filter-cloud-model';
export * from './models/service-task-cloud.model';
export * from './models/task-list-sorting.model';
export * from './models/task-preset-cloud.model';

View File

@@ -0,0 +1,134 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async } from '@angular/core/testing';
import { setupTestBed, StorageService, AlfrescoApiServiceMock, LogService, AppConfigService, CoreModule } from '@alfresco/adf-core';
import { fakeTaskCloudList } from '../mock/fake-task-response.mock';
import { ServiceTaskListCloudService } from './service-task-list-cloud.service';
import { ServiceTaskQueryCloudRequestModel } from '../models/service-task-cloud.model';
describe('Activiti ServiceTaskList Cloud Service', () => {
let service: ServiceTaskListCloudService;
let alfrescoApiMock: AlfrescoApiServiceMock;
function returnFakeTaskListResults() {
return {
oauth2Auth: {
callCustomApi: () => {
return Promise.resolve(fakeTaskCloudList);
}
}
};
}
function returnCallQueryParameters() {
return {
oauth2Auth: {
callCustomApi: (_queryUrl, _operation, _context, queryParams) => {
return Promise.resolve(queryParams);
}
}
};
}
function returnCallUrl() {
return {
oauth2Auth: {
callCustomApi: (queryUrl) => {
return Promise.resolve(queryUrl);
}
}
};
}
setupTestBed({
imports: [
CoreModule.forRoot()
]
});
beforeEach(async(() => {
alfrescoApiMock = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService());
service = new ServiceTaskListCloudService(alfrescoApiMock,
new AppConfigService(null),
new LogService(new AppConfigService(null)));
}));
it('should return the tasks', (done) => {
const taskRequest: ServiceTaskQueryCloudRequestModel = <ServiceTaskQueryCloudRequestModel> { appName: 'fakeName' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskListResults);
service.getServiceTaskByRequest(taskRequest).subscribe((res) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.list.entries.length).toBe(2);
expect(res.list.entries[0].entry.appName).toBe('save-the-cheerleader');
expect(res.list.entries[1].entry.appName).toBe('save-the-cheerleader');
done();
});
});
it('should append to the call all the parameters', (done) => {
const taskRequest: ServiceTaskQueryCloudRequestModel = <ServiceTaskQueryCloudRequestModel> { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallQueryParameters);
service.getServiceTaskByRequest(taskRequest).subscribe((res) => {
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: ServiceTaskQueryCloudRequestModel = <ServiceTaskQueryCloudRequestModel> { appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl);
service.getServiceTaskByRequest(taskRequest).subscribe((requestUrl) => {
expect(requestUrl).toBeDefined();
expect(requestUrl).not.toBeNull();
expect(requestUrl).toContain('/fakeName/query/admin/v1/service-tasks');
done();
});
});
it('should concat the sorting to append as parameters', (done) => {
const taskRequest: ServiceTaskQueryCloudRequestModel = <ServiceTaskQueryCloudRequestModel> {
appName: 'fakeName', skipCount: 0, maxItems: 20, service: 'fake-service',
sorting: [{ orderBy: 'NAME', direction: 'DESC' }, { orderBy: 'TITLE', direction: 'ASC' }]
};
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallQueryParameters);
service.getServiceTaskByRequest(taskRequest).subscribe((res) => {
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', (done) => {
const taskRequest: ServiceTaskQueryCloudRequestModel = <ServiceTaskQueryCloudRequestModel> { appName: null };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnCallUrl);
service.getServiceTaskByRequest(taskRequest).subscribe(
() => { },
(error) => {
expect(error).toBe('Appname not configured');
done();
}
);
});
});

View File

@@ -0,0 +1,103 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core';
import { ServiceTaskQueryCloudRequestModel, ServiceTaskIntegrationContextCloudModel } from '../models/service-task-cloud.model';
import { Observable, throwError } from 'rxjs';
import { TaskListCloudSortingModel } from '../models/task-list-sorting.model';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable({ providedIn: 'root' })
export class ServiceTaskListCloudService extends BaseCloudService {
constructor(apiService: AlfrescoApiService,
appConfigService: AppConfigService,
private logService: LogService) {
super(apiService, appConfigService);
}
/**
* Finds a task using an object with optional query properties.
* @param requestNode Query object
* @returns Task information
*/
getServiceTaskByRequest(requestNode: ServiceTaskQueryCloudRequestModel): Observable<any> {
if (requestNode.appName || requestNode.appName === '') {
const queryUrl = `${this.getBasePath(requestNode.appName)}/query/admin/v1/service-tasks`;
const queryParams = this.buildQueryParams(requestNode);
const sortingParams = this.buildSortingParam(requestNode.sorting);
if (sortingParams) {
queryParams['sort'] = sortingParams;
}
return this.get(queryUrl, queryParams);
} else {
this.logService.error('Appname is mandatory for querying task');
return throwError('Appname not configured');
}
}
/**
* Finds a service task integration context using an object with optional query properties.
* @param appName string
* @param serviceTaskId string
* @returns Service Task Integration Context information
*/
getServiceTaskStatus(appName: string, serviceTaskId: string): Observable<ServiceTaskIntegrationContextCloudModel> {
if (appName) {
const queryUrl = `${this.getBasePath(appName)}/query/admin/v1/service-tasks/${serviceTaskId}/integration-context`;
return this.get(queryUrl);
} else {
this.logService.error('Appname is mandatory for querying task');
return throwError('Appname not configured');
}
}
private buildQueryParams(requestNode: ServiceTaskQueryCloudRequestModel): Object {
const queryParam: Object = {};
for (const property in requestNode) {
if (requestNode.hasOwnProperty(property) &&
!this.isExcludedField(property) &&
this.isPropertyValueValid(requestNode, property)) {
queryParam[property] = requestNode[property];
}
}
return queryParam;
}
private isExcludedField(property: string): boolean {
return property === 'appName' || property === 'sorting';
}
private isPropertyValueValid(requestNode: any, property: string): boolean {
return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
}
private buildSortingParam(models: TaskListCloudSortingModel[]): string {
let finalSorting: string = '';
if (models) {
for (const sort of models) {
if (!finalSorting) {
finalSorting = `${sort.orderBy},${sort.direction}`;
} else {
finalSorting = `${finalSorting}&${sort.orderBy},${sort.direction}`;
}
}
}
return encodeURI(finalSorting);
}
}

View File

@@ -17,7 +17,7 @@
import { Injectable } from '@angular/core';
import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core';
import { TaskQueryCloudRequestModel, ServiceTaskQueryCloudRequestModel } from '../models/filter-cloud-model';
import { TaskQueryCloudRequestModel } 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';
@@ -51,26 +51,6 @@ export class TaskListCloudService extends BaseCloudService {
}
}
/**
* Finds a task using an object with optional query properties.
* @param requestNode Query object
* @returns Task information
*/
getServiceTaskByRequest(requestNode: ServiceTaskQueryCloudRequestModel): Observable<any> {
if (requestNode.appName || requestNode.appName === '') {
const queryUrl = `${this.getBasePath(requestNode.appName)}/query/admin/v1/service-tasks`;
const queryParams = this.buildQueryParams(requestNode);
const sortingParams = this.buildSortingParam(requestNode.sorting);
if (sortingParams) {
queryParams['sort'] = sortingParams;
}
return this.get(queryUrl, queryParams);
} else {
this.logService.error('Appname is mandatory for querying task');
return throwError('Appname not configured');
}
}
private buildQueryParams(requestNode: TaskQueryCloudRequestModel): Object {
const queryParam: Object = {};
for (const property in requestNode) {