[ADF-4409] DemoShell - ADF compatibility with Activiti 7 (#4646)

* [ADF-4409] PorcessServicesCloud - add community page

* [ADF-4409] - add process and task details page

* [ADF-4409] fix lint and reset package-lock

* [ADF-4409] - PR changes

* [ADF-4409] -  PR changes

* [ADF-4409] - fix start task/process redirection

* [ADF-4409] - fix unit tests
This commit is contained in:
Silviu Popa
2019-04-30 12:13:10 +03:00
committed by Eugenio Romano
parent 5f3d665ab5
commit 860529058c
39 changed files with 1074 additions and 78 deletions

View File

@@ -23,6 +23,7 @@ import { ProcessCloudModule } from './process/process-cloud.module';
import { GroupCloudModule } from './group/group-cloud.module';
import { FormCloudModule } from './form/form-cloud.module';
import { TaskFormModule } from './task/task-form/task-form.module';
import { BaseCloudService } from './services/base-cloud.service';
@NgModule({
imports: [
@@ -42,7 +43,8 @@ import { TaskFormModule } from './task/task-form/task-form.module';
name: 'adf-process-services-cloud',
source: 'assets/adf-process-services-cloud'
}
}
},
BaseCloudService
],
exports: [
AppListCloudModule,

View File

@@ -219,7 +219,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges {
}
}
createSortProperties(): any {
get createSortProperties(): any {
this.checkMandatorySortProperties();
const sortProperties = this.sortProperties.map((property: string) => {
return <ProcessFilterOptions> { label: property.charAt(0).toUpperCase() + property.slice(1), value: property };
@@ -505,7 +505,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges {
type: 'select',
key: 'sort',
value: currentProcessFilter.sort || this.createSortProperties[0].value,
options: this.createSortProperties()
options: this.createSortProperties
}),
new ProcessFilterProperties({
label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DIRECTION',

View File

@@ -47,7 +47,7 @@ export class ProcessHeaderCloudComponent implements OnChanges {
}
ngOnChanges() {
if (this.appName && this.processInstanceId) {
if ((this.appName || this.appName === '') && this.processInstanceId) {
this.loadProcessInstanceDetails(this.appName, this.processInstanceId);
}
}

View File

@@ -20,11 +20,12 @@ import { Injectable } from '@angular/core';
import { Observable, from, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { ProcessInstanceCloud } from '../../start-process/models/process-instance-cloud.model';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable({
providedIn: 'root'
})
export class ProcessHeaderCloudService {
export class ProcessHeaderCloudService extends BaseCloudService {
contextRoot: string;
contentTypes = ['application/json'];
accepts = ['application/json'];
@@ -33,6 +34,7 @@ export class ProcessHeaderCloudService {
constructor(private alfrescoApiService: AlfrescoApiService,
private appConfigService: AppConfigService,
private logService: LogService) {
super();
this.contextRoot = this.appConfigService.get('bpmHost', '');
}
@@ -43,9 +45,8 @@ export class ProcessHeaderCloudService {
* @returns Process instance details
*/
getProcessInstanceById(appName: string, processInstanceId: string): Observable<ProcessInstanceCloud> {
if (appName && processInstanceId) {
const queryUrl = `${this.contextRoot}/${appName}/query/v1/process-instances/${processInstanceId}`;
if ((appName || appName === '') && processInstanceId) {
const queryUrl = `${this.getBasePath(appName)}/query/v1/process-instances/${processInstanceId}`;
return from(this.alfrescoApiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'GET',
null, null, null,

View File

@@ -43,7 +43,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
/** The name of the application. */
@Input()
appName: string = '';
appName: string;
/** Name of the initiator of the process. */
@Input()
@@ -156,7 +156,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
reload() {
this.requestNode = this.createRequestNode();
if (this.requestNode.appName) {
if (this.requestNode.appName || this.requestNode.appName === '') {
this.load(this.requestNode);
} else {
this.rows = [];

View File

@@ -19,8 +19,10 @@ import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-
import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
import { Observable, from, throwError } from 'rxjs';
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable()
export class ProcessListCloudService {
export class ProcessListCloudService extends BaseCloudService {
contentTypes = ['application/json'];
accepts = ['application/json'];
@@ -28,6 +30,7 @@ export class ProcessListCloudService {
constructor(private apiService: AlfrescoApiService,
private appConfigService: AppConfigService,
private logService: LogService) {
super();
}
/**
@@ -36,7 +39,7 @@ export class ProcessListCloudService {
* @returns Process information
*/
getProcessByRequest(requestNode: ProcessQueryCloudRequestModel): Observable<any> {
if (requestNode.appName) {
if (requestNode.appName || requestNode.appName === '') {
const queryUrl = this.buildQueryUrl(requestNode);
const queryParams = this.buildQueryParams(requestNode);
const sortingParams = this.buildSortingParam(requestNode.sorting);
@@ -55,7 +58,8 @@ export class ProcessListCloudService {
}
}
private buildQueryUrl(requestNode: ProcessQueryCloudRequestModel) {
return `${this.appConfigService.get('bpmHost', '')}/${requestNode.appName}/query/v1/process-instances`;
this.contextRoot = this.appConfigService.get('bpmHost', '');
return `${this.getBasePath(requestNode.appName)}/query/v1/process-instances`;
}
private isPropertyValueValid(requestNode, property) {

View File

@@ -122,7 +122,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
}
private getProcessDefinitionList(processDefinitionName: string): ProcessDefinitionCloud[] {
return this.processDefinitionList.filter((option) => option.name.toLowerCase().includes(processDefinitionName.toLowerCase()));
return this.processDefinitionList.filter((option) => option.name && option.name.toLowerCase().includes(processDefinitionName.toLowerCase()));
}
private getProcessIfExists(processDefinitionName: string): ProcessDefinitionCloud {

View File

@@ -22,11 +22,12 @@ import { map, catchError } from 'rxjs/operators';
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable({
providedIn: 'root'
})
export class StartProcessCloudService {
export class StartProcessCloudService extends BaseCloudService {
contextRoot: string;
contentTypes = ['application/json'];
@@ -34,8 +35,9 @@ export class StartProcessCloudService {
returnType = Object;
constructor(private alfrescoApiService: AlfrescoApiService,
private appConfigService: AppConfigService,
private logService: LogService) {
private logService: LogService,
private appConfigService: AppConfigService) {
super();
this.contextRoot = this.appConfigService.get('bpmHost', '');
}
@@ -46,8 +48,8 @@ export class StartProcessCloudService {
*/
getProcessDefinitions(appName: string): Observable<ProcessDefinitionCloud[]> {
if (appName) {
const queryUrl = `${this.contextRoot}/${appName}/rb/v1/process-definitions`;
if (appName || appName === '') {
const queryUrl = `${this.getBasePath(appName)}/rb/v1/process-definitions`;
return from(this.alfrescoApiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'GET',
@@ -75,7 +77,7 @@ export class StartProcessCloudService {
*/
startProcess(appName: string, requestPayload: ProcessPayloadCloud): Observable<ProcessInstanceCloud> {
const queryUrl = `${this.contextRoot}/${appName}/rb/v1/process-instances`;
const queryUrl = `${this.getBasePath(appName)}/rb/v1/process-instances`;
return from(this.alfrescoApiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',

View File

@@ -0,0 +1,35 @@
/*!
* @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';
@Injectable()
export class BaseCloudService {
public contextRoot: string;
getBasePath(appName: string) {
if (this.isValidAppName(appName)) {
return `${this.contextRoot}/${appName}`;
}
return this.contextRoot;
}
private isValidAppName(appName: string) {
return appName && appName !== '';
}
}

View File

@@ -20,13 +20,13 @@ import { AlfrescoApiService, LogService, AppConfigService, IdentityUserService }
import { from, throwError, Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { TaskDetailsCloudModel } from '../start-task/models/task-details-cloud.model';
import { BaseCloudService } from '../../services/base-cloud.service';
@Injectable({
providedIn: 'root'
})
export class TaskCloudService {
export class TaskCloudService extends BaseCloudService {
contextRoot: string;
contentTypes = ['application/json'];
accepts = ['application/json'];
returnType = Object;
@@ -37,6 +37,7 @@ export class TaskCloudService {
private logService: LogService,
private identityUserService: IdentityUserService
) {
super();
this.contextRoot = this.appConfigService.get('bpmHost', '');
}
@@ -102,8 +103,7 @@ export class TaskCloudService {
*/
claimTask(appName: string, taskId: string, assignee: string): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
const queryUrl = `${this.contextRoot}/${appName}/rb/v1/tasks/${taskId}/claim?assignee=${assignee}`;
const queryUrl = `${this.getBasePath(appName)}/rb/v1/tasks/${taskId}/claim?assignee=${assignee}`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
@@ -130,8 +130,7 @@ export class TaskCloudService {
*/
unclaimTask(appName: string, taskId: string): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
const queryUrl = `${this.contextRoot}/${appName}/rb/v1/tasks/${taskId}/release`;
const queryUrl = `${this.getBasePath(appName)}/rb/v1/tasks/${taskId}/release`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
@@ -157,9 +156,8 @@ export class TaskCloudService {
* @returns Task details
*/
getTaskById(appName: string, taskId: string): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
const queryUrl = `${this.contextRoot}/${appName}/query/v1/tasks/${taskId}`;
if ((appName || appName === '') && taskId) {
const queryUrl = `${this.getBasePath(appName)}/query/v1/tasks/${taskId}`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'GET',
null, null, null,
@@ -189,8 +187,7 @@ export class TaskCloudService {
if (appName && taskId) {
updatePayload.payloadType = 'UpdateTaskPayload';
const queryUrl = `${this.contextRoot}/${appName}/rb/v1/tasks/${taskId}`;
const queryUrl = `${this.getBasePath(appName)}/rb/v1/tasks/${taskId}`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'PUT',
null, null, null,
@@ -210,7 +207,7 @@ export class TaskCloudService {
}
private buildCompleteTaskUrl(appName: string, taskId: string): string {
return `${this.appConfigService.get('bpmHost')}/${appName}/rb/v1/tasks/${taskId}/complete`;
return `${this.getBasePath(appName)}/rb/v1/tasks/${taskId}/complete`;
}
private handleError(error: any) {

View File

@@ -17,7 +17,7 @@
import { PeopleCloudComponent } from './people-cloud.component';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { IdentityUserService, AlfrescoApiService, AlfrescoApiServiceMock, CoreModule, IdentityUserModel } from '@alfresco/adf-core';
import { IdentityUserService, AlfrescoApiService, CoreModule, IdentityUserModel, setupTestBed } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { of } from 'rxjs';
import { mockUsers } from '../../mock/user-cloud.mock';
@@ -43,31 +43,23 @@ describe('PeopleCloudComponent', () => {
{ id: mockUsers[2].id, username: mockUsers[2].username }
];
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
ProcessServiceCloudTestingModule,
StartTaskCloudModule
],
providers: [
IdentityUserService
]
})
.overrideComponent(PeopleCloudComponent, {
set: {
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
]
}
}).compileComponents();
}));
setupTestBed({
imports: [
CoreModule.forRoot(),
ProcessServiceCloudTestingModule,
StartTaskCloudModule
],
providers: [
IdentityUserService
]
});
beforeEach(() => {
fixture = TestBed.createComponent(PeopleCloudComponent);
component = fixture.componentInstance;
identityService = TestBed.get(IdentityUserService);
alfrescoApiService = TestBed.get(AlfrescoApiService);
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
});
it('should create PeopleCloudComponent', () => {
@@ -79,7 +71,6 @@ describe('PeopleCloudComponent', () => {
let findUsersByNameSpy: jasmine.Spy;
beforeEach(async(() => {
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers));
fixture.detectChanges();
element = fixture.nativeElement;
@@ -173,7 +164,6 @@ describe('PeopleCloudComponent', () => {
let findUsersByNameSpy: jasmine.Spy;
beforeEach(async(() => {
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
findUsersByNameSpy = spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers));
checkUserHasAccessSpy = spyOn(identityService, 'checkUserHasClientApp').and.returnValue(of(true));
checkUserHasAnyClientAppRoleSpy = spyOn(identityService, 'checkUserHasAnyClientAppRole').and.returnValue(of(true));
@@ -318,7 +308,6 @@ describe('PeopleCloudComponent', () => {
beforeEach(async(() => {
component.roles = ['mock-role-1', 'mock-role-2'];
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
spyOn(identityService, 'findUsersByName').and.returnValue(of(mockUsers));
checkUserHasRoleSpy = spyOn(identityService, 'checkUserHasRole').and.returnValue(of(true));
fixture.detectChanges();
@@ -458,6 +447,7 @@ describe('PeopleCloudComponent', () => {
component.preSelectUsers = <any> mockPreselectedUsers;
fixture.detectChanges();
element = fixture.nativeElement;
alfrescoApiService = TestBed.get(AlfrescoApiService);
}));
afterEach(() => {
@@ -473,8 +463,9 @@ describe('PeopleCloudComponent', () => {
});
}));
it('should pre-select all preSelectUsers when mode=multiple', async(() => {
it('should pre-select all preSelectUsers when mode=multiple validation disabled', async(() => {
component.mode = 'multiple';
fixture.detectChanges();
component.ngOnChanges({ 'preSelectUsers': change });
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -496,15 +487,11 @@ describe('PeopleCloudComponent', () => {
component.mode = 'multiple';
component.validate = true;
component.preSelectUsers = <any> mockPreselectedUsers;
fixture.detectChanges();
element = fixture.nativeElement;
alfrescoApiService = TestBed.get(AlfrescoApiService);
fixture.detectChanges();
}));
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should show chip list when mode=multiple', async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -514,9 +501,9 @@ describe('PeopleCloudComponent', () => {
}));
it('should pre-select all preSelectUsers when mode=multiple', async(() => {
fixture.detectChanges();
spyOn(component, 'searchUser').and.returnValue(Promise.resolve(mockPreselectedUsers));
component.mode = 'multiple';
fixture.detectChanges();
component.ngOnChanges({ 'preSelectUsers': change });
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -527,7 +514,6 @@ describe('PeopleCloudComponent', () => {
}));
it('should emit removeUser when a selected user is removed if mode=multiple', async(() => {
fixture.detectChanges();
const removeUserSpy = spyOn(component.removeUser, 'emit');
component.mode = 'multiple';
fixture.detectChanges();
@@ -559,6 +545,7 @@ describe('PeopleCloudComponent', () => {
const findByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(of(mockUsers[0]));
component.mode = 'multiple';
component.validate = true;
fixture.detectChanges();
component.preSelectUsers = <any> [{ id: mockUsers[0].id }, { id: mockUsers[1].id }];
component.ngOnChanges({ 'preSelectUsers': change });
fixture.detectChanges();
@@ -587,6 +574,7 @@ describe('PeopleCloudComponent', () => {
it('should filter user by email if validate true', async(() => {
const findUserByEmailSpy = spyOn(identityService, 'findUserByEmail').and.returnValue(of(mockUsers));
fixture.detectChanges();
component.mode = 'multiple';
component.validate = true;
component.preSelectUsers = <any> [{ email: mockUsers[1].email }, { email: mockUsers[2].email }];
@@ -604,6 +592,7 @@ describe('PeopleCloudComponent', () => {
const findUserByIdSpy = spyOn(identityService, 'findUserById').and.returnValue(of(mockUsers[0]));
component.mode = 'single';
component.validate = true;
fixture.detectChanges();
component.preSelectUsers = <any> [{ id: mockUsers[0].id }];
fixture.detectChanges();
fixture.whenStable().then(() => {

View File

@@ -25,15 +25,16 @@ import { from, Observable, throwError } from 'rxjs';
import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
import { TaskDetailsCloudModel, StartTaskCloudResponseModel } from '../models/task-details-cloud.model';
import { map, catchError } from 'rxjs/operators';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable()
export class StartTaskCloudService {
export class StartTaskCloudService extends BaseCloudService {
constructor(
private apiService: AlfrescoApiService,
private appConfigService: AppConfigService,
private logService: LogService
) {}
) { super(); }
/**
* Creates a new standalone task.
@@ -62,7 +63,8 @@ export class StartTaskCloudService {
}
private buildCreateTaskUrl(appName: string): any {
return `${this.appConfigService.get('bpmHost')}/${appName}/rb/v1/tasks`;
this.contextRoot = this.appConfigService.get('bpmHost');
return `${this.getBasePath(appName)}/rb/v1/tasks`;
}
private buildRequestBody(taskDetails: any) {

View File

@@ -231,7 +231,7 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
return this.filterProperties.indexOf(EditTaskFilterCloudComponent.LAST_MODIFIED) >= 0;
}
createSortProperties(): any {
get createSortProperties(): any {
this.checkMandatorySortProperties();
const sortProperties = this.sortProperties.map((property: string) => {
return <FilterOptions> { label: property.charAt(0).toUpperCase() + property.slice(1), value: property };
@@ -523,7 +523,7 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges {
type: 'select',
key: 'sort',
value: currentTaskFilter.sort || this.createSortProperties[0].value,
options: this.createSortProperties()
options: this.createSortProperties
}),
new TaskFilterProperties({
label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.DIRECTION',

View File

@@ -52,7 +52,6 @@ export class TaskFilterCloudService {
const username = this.getUsername();
const key = `task-filters-${appName}-${username}`;
const filters = JSON.parse(this.storage.getItem(key) || '[]');
if (filters.length === 0) {
this.createDefaultFilters(appName);
} else {

View File

@@ -67,7 +67,7 @@ export class TaskHeaderCloudComponent implements OnInit {
) { }
ngOnInit() {
if (this.appName && this.taskId) {
if ((this.appName || this.appName === '') && this.taskId) {
this.loadTaskDetailsById(this.appName, this.taskId);
}
@@ -226,7 +226,7 @@ export class TaskHeaderCloudComponent implements OnInit {
}
isTaskValid() {
return this.appName && this.taskId;
return (this.appName || this.appName === '') && this.taskId;
}
isTaskAssigned() {

View File

@@ -193,7 +193,7 @@ export class TaskListCloudComponent extends DataTableSchema implements OnChanges
reload() {
this.requestNode = this.createRequestNode();
if (this.requestNode.appName) {
if (this.requestNode.appName || this.requestNode.appName === '') {
this.load(this.requestNode);
} else {
this.rows = [];

View File

@@ -20,13 +20,15 @@ import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-
import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model';
import { Observable, from, throwError } from 'rxjs';
import { TaskListCloudSortingModel } from '../models/task-list-sorting.model';
import { BaseCloudService } from '../../../services/base-cloud.service';
@Injectable()
export class TaskListCloudService {
export class TaskListCloudService extends BaseCloudService {
constructor(private apiService: AlfrescoApiService,
private appConfigService: AppConfigService,
private logService: LogService) {
super();
}
contentTypes = ['application/json'];
@@ -38,7 +40,8 @@ export class TaskListCloudService {
* @returns Task information
*/
getTaskByRequest(requestNode: TaskQueryCloudRequestModel): Observable<any> {
if (requestNode.appName) {
if (requestNode.appName || requestNode.appName === '') {
const queryUrl = this.buildQueryUrl(requestNode);
const queryParams = this.buildQueryParams(requestNode);
const sortingParams = this.buildSortingParam(requestNode.sorting);
@@ -58,7 +61,8 @@ export class TaskListCloudService {
}
private buildQueryUrl(requestNode: TaskQueryCloudRequestModel) {
return `${this.appConfigService.get('bpmHost', '')}/${requestNode.appName}/query/v1/tasks`;
this.contextRoot = this.appConfigService.get('bpmHost', '');
return `${this.getBasePath(requestNode.appName)}/query/v1/tasks`;
}
private buildQueryParams(requestNode: TaskQueryCloudRequestModel) {