Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AAE-25190 Retrieve start process cloud customisation #10133

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,10 @@
(click)="cancelStartProcess()"
id="cancel_process"
>
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.CANCEL' | translate | uppercase}}
{{ cancelButtonLabel }}
</button>
<button
*ngIf="showStartProcessButton"
color="primary"
mat-raised-button
[disabled]="disableStartButton || !isProcessFormValid"
Expand All @@ -116,7 +117,7 @@
id="button-start"
class="adf-btn-start"
>
{{'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.START' | translate | uppercase}}
{{ startProcessButtonLabel }}
</button>
</div>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('StartProcessCloudComponent', () => {
let startProcessWithFormSpy: jasmine.Spy;
let formDefinitionSpy: jasmine.Spy;
let getStartEventFormStaticValuesMappingSpy: jasmine.Spy;
let getStartEventConstantSpy: jasmine.Spy;

const firstChange = new SimpleChange(undefined, 'myApp', true);

Expand Down Expand Up @@ -112,6 +113,7 @@ describe('StartProcessCloudComponent', () => {
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
startProcessWithFormSpy = spyOn(processService, 'startProcessWithForm').and.returnValue(of(fakeProcessWithFormInstance));
getStartEventFormStaticValuesMappingSpy = spyOn(processService, 'getStartEventFormStaticValuesMapping').and.returnValue(of([]));
getStartEventConstantSpy = spyOn(processService, 'getStartEventConstants').and.returnValue(of([]));
loader = TestbedHarnessEnvironment.loader(fixture);
});

Expand All @@ -120,6 +122,56 @@ describe('StartProcessCloudComponent', () => {
TestBed.resetTestingModule();
});

/**
* Setup the component with the given start event information.
* @param values the values for the form
* @param staticValues the static values retrieved from the API for the form
* @param constantValues the constant values retrieved from the API for customising the buttons
* @returns the start and cancel buttons HTML elements
*/
function loadWithStartEventInformation(
values?: TaskVariableCloud[],
staticValues?: TaskVariableCloud[] | Error,
constantValues?: TaskVariableCloud[] | Error
): {
startButton: any;
cancelButton: any;
} {
if (values) {
component.values = values;
}
if (staticValues) {
if (staticValues instanceof Error) {
getStartEventConstantSpy.and.returnValue(throwError(() => staticValues));
} else {
getStartEventFormStaticValuesMappingSpy.and.returnValue(of(staticValues));
}
}
if (constantValues) {
if (constantValues instanceof Error) {
getStartEventConstantSpy.and.returnValue(throwError(() => constantValues));
} else {
getStartEventConstantSpy.and.returnValue(of(constantValues));
}
}

component.name = 'My new process';
component.processDefinitionName = 'processwithoutform2';
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
fixture.detectChanges();

const change = new SimpleChange(null, 'MyApp', true);
component.ngOnChanges({ appName: change });
fixture.detectChanges();
tick(550);
fixture.detectChanges();

const startButton = fixture.nativeElement.querySelector('#button-start');
const cancelButton = fixture.nativeElement.querySelector('#cancel_process');

return { startButton, cancelButton };
}

describe('start a process without start form', () => {
beforeEach(() => {
component.name = 'My formless new process';
Expand Down Expand Up @@ -197,19 +249,47 @@ describe('StartProcessCloudComponent', () => {
new TaskVariableCloud({ name: 'static2', value: 0 }),
new TaskVariableCloud({ name: 'static3', value: true })
];
component.name = 'My new process';
component.processDefinitionName = 'processwithoutform2';
component.values = values;
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
getStartEventFormStaticValuesMappingSpy.and.returnValue(of(staticInputs));
fixture.detectChanges();

const change = new SimpleChange(null, 'MyApp', true);
component.ngOnChanges({ appName: change });
fixture.detectChanges();
tick(550);
loadWithStartEventInformation(values, staticInputs);

expect(component.resolvedValues).toEqual(staticInputs.concat(values));
}));

describe('start event constants', () => {
it('should not display the buttons when they are disabled by the constants', fakeAsync(() => {
const constants: TaskVariableCloud[] = [
new TaskVariableCloud({ name: 'startEnabled', value: 'false' }),
new TaskVariableCloud({ name: 'cancelEnabled', value: 'false' })
];

const { startButton, cancelButton } = loadWithStartEventInformation(null, null, constants);

expect(startButton).toBeNull();
expect(cancelButton).toBeNull();
}));

it('should display the customised button labels when they are set in the constants', fakeAsync(() => {
const constants: TaskVariableCloud[] = [
new TaskVariableCloud({ name: 'startEnabled', value: 'true' }),
new TaskVariableCloud({ name: 'startLabel', value: 'Start' }),
new TaskVariableCloud({ name: 'cancelEnabled', value: 'true' }),
new TaskVariableCloud({ name: 'cancelLabel', value: 'Cancel' })
];
const { startButton, cancelButton } = loadWithStartEventInformation(null, null, constants);

expect(startButton.textContent?.trim()).toEqual('Start');
expect(cancelButton.textContent?.trim()).toEqual('Cancel');
}));

it('should load with default values when retrieving the constants fails', fakeAsync(() => {
const { startButton, cancelButton } = loadWithStartEventInformation(null, null, new Error('test'));

expect(startButton).not.toBeNull();
expect(cancelButton).not.toBeNull();
expect(startButton.textContent?.trim()).toEqual(component.defaultStartProcessButtonLabel);
expect(cancelButton.textContent?.trim()).toEqual(component.defaultCancelProcessButtonLabel);
}));
});
});

describe('start a process with start form', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@ import {
ViewEncapsulation
} from '@angular/core';

import { ContentLinkModel, FORM_FIELD_VALIDATORS, FormFieldValidator, FormModel } from '@alfresco/adf-core';
import { ContentLinkModel, FORM_FIELD_VALIDATORS, FormFieldValidator, FormModel, TranslationService } from '@alfresco/adf-core';
import { AbstractControl, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { ProcessNameCloudPipe } from '../../../pipes/process-name-cloud.pipe';
import { catchError, debounceTime, takeUntil } from 'rxjs/operators';
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
import { ProcessWithFormPayloadCloud } from '../models/process-with-form-payload-cloud.model';
import { StartProcessCloudService } from '../services/start-process-cloud.service';
import { forkJoin, of, Subject } from 'rxjs';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
import { ProcessNameCloudPipe } from '../../../pipes/process-name-cloud.pipe';

const MAX_NAME_LENGTH: number = 255;
const PROCESS_DEFINITION_DEBOUNCE: number = 300;
Expand Down Expand Up @@ -131,6 +131,10 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
isFormCloudLoading = false;
processDefinitionLoaded = false;

showStartProcessButton = true;
startProcessButtonLabel: string;
cancelButtonLabel: string;

formCloud?: FormModel;
processForm = new FormGroup({
processInstanceName: new FormControl('', [
Expand Down Expand Up @@ -172,6 +176,19 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
return !!this.processDefinitionCurrent?.formKey;
}

get defaultStartProcessButtonLabel(): string {
return this.translateService.instant('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.START').toUpperCase();
}

get defaultCancelProcessButtonLabel(): string {
return this.translateService.instant('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.CANCEL').toUpperCase();
}

constructor(private translateService: TranslationService) {
this.startProcessButtonLabel = this.defaultStartProcessButtonLabel;
this.cancelButtonLabel = this.defaultCancelProcessButtonLabel;
}

ngOnInit() {
this.initFieldValidators();

Expand Down Expand Up @@ -230,19 +247,39 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
(process: ProcessDefinitionCloud) => process.name === selectedProcessDefinitionName || process.key === selectedProcessDefinitionName
);

this.startProcessCloudService.getStartEventFormStaticValuesMapping(this.appName, processDefinitionCurrent.id).subscribe(
(staticMappings) => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
this.processDefinitionCurrent = processDefinitionCurrent;
this.isFormCloudLoading = false;
},
() => {
this.resolvedValues = this.values;
this.processDefinitionCurrent = processDefinitionCurrent;
this.isFormCloudLoading = false;
forkJoin([
this.startProcessCloudService
.getStartEventFormStaticValuesMapping(this.appName, processDefinitionCurrent.id)
.pipe(catchError(() => of([] as TaskVariableCloud[]))),
this.startProcessCloudService
.getStartEventConstants(this.appName, processDefinitionCurrent.id)
.pipe(catchError(() => of([] as TaskVariableCloud[])))
]).subscribe(([staticMappings, constants]) => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
this.processDefinitionCurrent = processDefinitionCurrent;
this.isFormCloudLoading = false;

const displayStart = constants?.find((constant) => constant.name === 'startEnabled');
const startLabel = constants?.find((constant) => constant.name === 'startLabel');

const displayCancel = constants?.find((constant) => constant.name === 'cancelEnabled');
const cancelLabel = constants?.find((constant) => constant.name === 'cancelLabel');

if (displayStart) {
this.showStartProcessButton = displayStart?.value === 'true';
}
);
if (startLabel) {
this.startProcessButtonLabel = startLabel?.value?.trim()?.length > 0 ? startLabel.value.trim() : this.defaultStartProcessButtonLabel;
}

if (displayCancel) {
this.showCancelButton = displayCancel?.value === 'true' && this.showCancelButton;
}
if (cancelLabel) {
this.cancelButtonLabel = cancelLabel?.value?.trim()?.length > 0 ? cancelLabel.value.trim() : this.defaultCancelProcessButtonLabel;
}
});

this.isFormCloudLoaded = false;
this.processPayloadCloud.processDefinitionKey = processDefinitionCurrent.key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,29 @@ describe('StartProcessCloudService', () => {
expect(requestSpy.calls.mostRecent().args[0]).toContain(`${appName}/rb/v1/process-definitions/${processDefinitionId}/static-values`);
expect(requestSpy.calls.mostRecent().args[1].httpMethod).toBe('GET');
});

it('should transform the response into task variables when retrieving the constant values for the start event', async () => {
const appName = 'test-app';
const processDefinitionId = 'processDefinitionId';
const requestSpy = spyOn(adfHttpClient, 'request');
requestSpy.and.returnValue(Promise.resolve({ constant1: 'value', constant2: '0', constant3: 'true' }));

const result = await service.getStartEventConstants(appName, processDefinitionId).toPromise();

expect(result.length).toEqual(3);
expect(result[0].name).toEqual('constant1');
expect(result[0].id).toEqual('constant1');
expect(result[0].value).toEqual('value');
expect(result[0].type).toEqual('string');
expect(result[1].name).toEqual('constant2');
expect(result[1].id).toEqual('constant2');
expect(result[1].value).toEqual('0');
expect(result[1].type).toEqual('string');
expect(result[2].name).toEqual('constant3');
expect(result[2].id).toEqual('constant3');
expect(result[2].value).toEqual('true');
expect(result[2].type).toEqual('string');
expect(requestSpy.calls.mostRecent().args[0]).toContain(`${appName}/rb/v1/process-definitions/${processDefinitionId}/constant-values`);
expect(requestSpy.calls.mostRecent().args[1].httpMethod).toBe('GET');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,26 @@ export class StartProcessCloudService extends BaseCloudService {
})
);
}

/**
* Gets the constants mapped to the start form of a process definition.
*
* @param appName Name of the app
* @param processDefinitionId ID of the target process definition
* @returns Constants values for the start event
*/
getStartEventConstants(appName: string, processDefinitionId: string): Observable<TaskVariableCloud[]> {
const apiUrl = `${this.getBasePath(appName)}/rb/v1/process-definitions/${processDefinitionId}/constant-values`;
return this.get(apiUrl).pipe(
map((res: { [key: string]: any }) => {
const result = [];
if (res) {
Object.keys(res).forEach((constant) =>
result.push(new TaskVariableCloud({ name: constant, value: res[constant], type: 'string' }))
);
}
return result;
})
);
}
}
Loading