Skip to content

Commit

Permalink
AAE-25190 Retrieve start process cloud customisation (#10133)
Browse files Browse the repository at this point in the history
* AAE-25190 Restrieve start process cloud customisation

* AAE-25190 Fix code duplucation

* AAE-25190 Address review comments

* AAE-25190 Address review comments
  • Loading branch information
pmartinezga committed Sep 6, 2024
1 parent 166325d commit b60797e
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 30 deletions.
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;
})
);
}
}

0 comments on commit b60797e

Please sign in to comment.