mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
AAE-32255 Start Process button in start event is showing and failing for form with custom outcomes (#10697)
* [AAE-32255] check if form has visible outcomes * [AAE-32255] readded ? * [AAE-32255] use pipe and observable * [AAE-32255] check if exists
This commit is contained in:
@@ -103,6 +103,10 @@ export abstract class FormBaseComponent {
|
|||||||
*/
|
*/
|
||||||
formStyle: string = '';
|
formStyle: string = '';
|
||||||
|
|
||||||
|
get hasVisibleOutcomes(): boolean {
|
||||||
|
return this.form?.outcomes?.some((outcome) => this.isOutcomeButtonVisible(outcome, this.form.readOnly));
|
||||||
|
}
|
||||||
|
|
||||||
get form(): FormModel {
|
get form(): FormModel {
|
||||||
return this._form;
|
return this._form;
|
||||||
}
|
}
|
||||||
|
@@ -73,6 +73,7 @@
|
|||||||
|
|
||||||
<ng-container *ngIf="hasForm else taskFormCloudButtons">
|
<ng-container *ngIf="hasForm else taskFormCloudButtons">
|
||||||
<adf-cloud-form
|
<adf-cloud-form
|
||||||
|
#startForm
|
||||||
[appName]="appName"
|
[appName]="appName"
|
||||||
[appVersion]="processDefinitionCurrent.appVersion"
|
[appVersion]="processDefinitionCurrent.appVersion"
|
||||||
[data]="resolvedValues"
|
[data]="resolvedValues"
|
||||||
@@ -108,7 +109,7 @@
|
|||||||
{{ cancelButtonLabel }}
|
{{ cancelButtonLabel }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
*ngIf="showStartProcessButton"
|
*ngIf="showStartProcessButton$ | async"
|
||||||
color="primary"
|
color="primary"
|
||||||
mat-raised-button
|
mat-raised-button
|
||||||
[disabled]="disableStartButton || !isProcessFormValid"
|
[disabled]="disableStartButton || !isProcessFormValid"
|
||||||
|
@@ -31,7 +31,8 @@ import {
|
|||||||
fakeNoNameProcessDefinitions,
|
fakeNoNameProcessDefinitions,
|
||||||
fakeSingleProcessDefinition,
|
fakeSingleProcessDefinition,
|
||||||
fakeSingleProcessDefinitionWithoutForm,
|
fakeSingleProcessDefinitionWithoutForm,
|
||||||
fakeFormModelJson
|
fakeFormModelJson,
|
||||||
|
fakeStartFormWithOutcomes
|
||||||
} from '../mock/start-process.component.mock';
|
} from '../mock/start-process.component.mock';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
||||||
@@ -69,6 +70,8 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
const panel = await loader.getHarness(MatAutocompleteHarness);
|
const panel = await loader.getHarness(MatAutocompleteHarness);
|
||||||
await panel.selectOption({ text: name });
|
await panel.selectOption({ text: name });
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
};
|
};
|
||||||
|
|
||||||
const typeValueInto = (selector: any, value: string) => {
|
const typeValueInto = (selector: any, value: string) => {
|
||||||
@@ -185,8 +188,6 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.processDefinitionName = 'process';
|
component.processDefinitionName = 'process';
|
||||||
await selectOptionByName('processwithoutform2');
|
await selectOptionByName('processwithoutform2');
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
expect(component.processDefinitionCurrent.name).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[1])).name);
|
expect(component.processDefinitionCurrent.name).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[1])).name);
|
||||||
const startBtn = fixture.nativeElement.querySelector('#button-start');
|
const startBtn = fixture.nativeElement.querySelector('#button-start');
|
||||||
@@ -537,8 +538,6 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
await selectOptionByName('processwithform');
|
await selectOptionByName('processwithform');
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
component.processDefinitionName = fakeProcessDefinitions[2].name;
|
component.processDefinitionName = fakeProcessDefinitions[2].name;
|
||||||
component.setProcessDefinitionOnForm(fakeProcessDefinitions[2].name);
|
component.setProcessDefinitionOnForm(fakeProcessDefinitions[2].name);
|
||||||
@@ -570,9 +569,6 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
component.ngOnChanges({});
|
component.ngOnChanges({});
|
||||||
await selectOptionByName('process');
|
await selectOptionByName('process');
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
expect(component.processDefinitionCurrent.name).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[3])).name);
|
expect(component.processDefinitionCurrent.name).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[3])).name);
|
||||||
expect(component.processDefinitionCurrent.key).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[3])).key);
|
expect(component.processDefinitionCurrent.key).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[3])).key);
|
||||||
});
|
});
|
||||||
@@ -701,16 +697,38 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should see start button', async () => {
|
it('should show start button', () => {
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
const startButton = fixture.debugElement.query(By.css('#button-start'));
|
const startButton = fixture.debugElement.query(By.css('#button-start'));
|
||||||
expect(startButton).toBeDefined();
|
expect(startButton).toBeDefined();
|
||||||
expect(startButton).not.toBeNull();
|
expect(startButton).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should show start button when start process has form without outcomes', async () => {
|
||||||
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
|
component.ngOnChanges({ appName: firstChange });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
await selectOptionByName('processwithform');
|
||||||
|
|
||||||
|
const startButton = fixture.debugElement.query(By.css('#button-start'));
|
||||||
|
expect(startButton).toBeDefined();
|
||||||
|
expect(startButton).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT see start button when start process has form with outcomes', async () => {
|
||||||
|
formDefinitionSpy.and.returnValue(of(fakeStartFormWithOutcomes));
|
||||||
|
component.ngOnChanges({ appName: firstChange });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
await selectOptionByName('processwithform');
|
||||||
|
|
||||||
|
const startButton = fixture.debugElement.query(By.css('#button-start'));
|
||||||
|
expect(startButton).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('should call service with the correct parameters when button is clicked and variables are defined and formCloud is undefined', async () => {
|
it('should call service with the correct parameters when button is clicked and variables are defined and formCloud is undefined', async () => {
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
component.processForm.controls['processInstanceName'].setValue('My Process 1');
|
component.processForm.controls['processInstanceName'].setValue('My Process 1');
|
||||||
@@ -820,8 +838,6 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
await selectOptionByName('processwithform');
|
await selectOptionByName('processwithform');
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
|
|
||||||
component.processDefinitionName = fakeProcessDefinitions[2].name;
|
component.processDefinitionName = fakeProcessDefinitions[2].name;
|
||||||
component.setProcessDefinitionOnForm(fakeProcessDefinitions[2].name);
|
component.setProcessDefinitionOnForm(fakeProcessDefinitions[2].name);
|
||||||
@@ -941,8 +957,6 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
component.processDefinitionName = 'processwithoutform1';
|
component.processDefinitionName = 'processwithoutform1';
|
||||||
await selectOptionByName(fakeProcessDefinitions[0].name);
|
await selectOptionByName(fakeProcessDefinitions[0].name);
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
expect(emitSpy).toHaveBeenCalledOnceWith(fakeProcessDefinitions[0]);
|
expect(emitSpy).toHaveBeenCalledOnceWith(fakeProcessDefinitions[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -32,12 +32,12 @@ import {
|
|||||||
import { ContentLinkModel, FormModel, InplaceFormInputComponent, LocalizedDatePipe, TranslationService } from '@alfresco/adf-core';
|
import { ContentLinkModel, FormModel, InplaceFormInputComponent, LocalizedDatePipe, TranslationService } from '@alfresco/adf-core';
|
||||||
import { AbstractControl, FormControl, FormGroup, ReactiveFormsModule, ValidatorFn, Validators } from '@angular/forms';
|
import { AbstractControl, FormControl, FormGroup, ReactiveFormsModule, ValidatorFn, Validators } from '@angular/forms';
|
||||||
import { MatAutocompleteModule, MatAutocompleteTrigger } from '@angular/material/autocomplete';
|
import { MatAutocompleteModule, MatAutocompleteTrigger } from '@angular/material/autocomplete';
|
||||||
import { catchError, debounceTime } from 'rxjs/operators';
|
import { catchError, debounceTime, map } from 'rxjs/operators';
|
||||||
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||||
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
||||||
import { ProcessWithFormPayloadCloud } from '../models/process-with-form-payload-cloud.model';
|
import { ProcessWithFormPayloadCloud } from '../models/process-with-form-payload-cloud.model';
|
||||||
import { StartProcessCloudService } from '../services/start-process-cloud.service';
|
import { StartProcessCloudService } from '../services/start-process-cloud.service';
|
||||||
import { forkJoin, of } from 'rxjs';
|
import { BehaviorSubject, forkJoin, Observable, of, combineLatest } from 'rxjs';
|
||||||
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
|
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
|
||||||
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
|
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
|
||||||
import { FormCloudDisplayModeConfiguration } from '../../../services/form-fields.interfaces';
|
import { FormCloudDisplayModeConfiguration } from '../../../services/form-fields.interfaces';
|
||||||
@@ -86,6 +86,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
@ViewChild(MatAutocompleteTrigger)
|
@ViewChild(MatAutocompleteTrigger)
|
||||||
inputAutocomplete: MatAutocompleteTrigger;
|
inputAutocomplete: MatAutocompleteTrigger;
|
||||||
|
|
||||||
|
@ViewChild('startForm') startForm: FormCloudComponent;
|
||||||
|
|
||||||
/** (required) Name of the app. */
|
/** (required) Name of the app. */
|
||||||
@Input()
|
@Input()
|
||||||
appName: string = '';
|
appName: string = '';
|
||||||
@@ -163,7 +165,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
isFormCloudLoading = false;
|
isFormCloudLoading = false;
|
||||||
processDefinitionLoaded = false;
|
processDefinitionLoaded = false;
|
||||||
|
|
||||||
showStartProcessButton = true;
|
showStartProcessButton$: Observable<boolean>;
|
||||||
startProcessButtonLabel: string;
|
startProcessButtonLabel: string;
|
||||||
cancelButtonLabel: string;
|
cancelButtonLabel: string;
|
||||||
|
|
||||||
@@ -180,6 +182,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
private readonly startProcessCloudService = inject(StartProcessCloudService);
|
private readonly startProcessCloudService = inject(StartProcessCloudService);
|
||||||
private readonly localizedDatePipe = inject(LocalizedDatePipe);
|
private readonly localizedDatePipe = inject(LocalizedDatePipe);
|
||||||
|
private readonly displayStartSubject = new BehaviorSubject<string>(null);
|
||||||
|
private readonly hasVisibleOutcomesSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
get isProcessFormValid(): boolean {
|
get isProcessFormValid(): boolean {
|
||||||
if (this.hasForm && this.isFormCloudLoaded) {
|
if (this.hasForm && this.isFormCloudLoaded) {
|
||||||
@@ -230,6 +234,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
.subscribe((processDefinitionName) => {
|
.subscribe((processDefinitionName) => {
|
||||||
this.selectProcessDefinitionByProcessDefinitionName(processDefinitionName);
|
this.selectProcessDefinitionByProcessDefinitionName(processDefinitionName);
|
||||||
});
|
});
|
||||||
|
this.showStartProcessButton$ = combineLatest([this.displayStartSubject, this.hasVisibleOutcomesSubject]).pipe(
|
||||||
|
map(([displayStart, hasVisibleOutcomes]) => (displayStart !== null ? displayStart === 'true' : !hasVisibleOutcomes))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
@@ -254,6 +261,10 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
onFormLoaded(form: FormModel) {
|
onFormLoaded(form: FormModel) {
|
||||||
this.isFormCloudLoaded = true;
|
this.isFormCloudLoaded = true;
|
||||||
this.formCloud = form;
|
this.formCloud = form;
|
||||||
|
|
||||||
|
if (this.startForm) {
|
||||||
|
this.hasVisibleOutcomesSubject.next(this.startForm.hasVisibleOutcomes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMaxNameLength(): number {
|
private getMaxNameLength(): number {
|
||||||
@@ -294,7 +305,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
const cancelLabel = constants?.find((constant) => constant.name === 'cancelLabel');
|
const cancelLabel = constants?.find((constant) => constant.name === 'cancelLabel');
|
||||||
|
|
||||||
if (displayStart) {
|
if (displayStart) {
|
||||||
this.showStartProcessButton = displayStart?.value === 'true';
|
this.displayStartSubject.next(displayStart?.value);
|
||||||
}
|
}
|
||||||
if (startLabel) {
|
if (startLabel) {
|
||||||
this.startProcessButtonLabel = startLabel?.value?.trim()?.length > 0 ? startLabel.value.trim() : this.defaultStartProcessButtonLabel;
|
this.startProcessButtonLabel = startLabel?.value?.trim()?.length > 0 ? startLabel.value.trim() : this.defaultStartProcessButtonLabel;
|
||||||
|
@@ -199,6 +199,26 @@ export const fakeStartForm = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fakeStartFormWithOutcomes = {
|
||||||
|
formRepresentation: {
|
||||||
|
...fakeStartForm.formRepresentation,
|
||||||
|
formDefinition: {
|
||||||
|
...fakeStartForm.formRepresentation.formDefinition,
|
||||||
|
outcomes: [
|
||||||
|
{
|
||||||
|
id: 'c5676ca7-8ad4-421c-9538-aaf8560bd5fc',
|
||||||
|
name: 'Option 1',
|
||||||
|
visibilityCondition: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '48e9c1f8-50b9-4d2f-998c-7836c132986f',
|
||||||
|
name: 'Option 2',
|
||||||
|
visibilityCondition: null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
export const fakeStartFormNotValid = {
|
export const fakeStartFormNotValid = {
|
||||||
formRepresentation: {
|
formRepresentation: {
|
||||||
id: 'form-a5d50817-5183-4850-802d-17af54b2632f',
|
id: 'form-a5d50817-5183-4850-802d-17af54b2632f',
|
||||||
|
Reference in New Issue
Block a user