AAE-44435 Fix incorrect Start process button on user task forms (#11837)

This commit is contained in:
Alex Molodyh
2026-04-30 12:39:28 -07:00
committed by GitHub
parent b49513e9c2
commit d3ad66d25b
6 changed files with 145 additions and 20 deletions
@@ -121,20 +121,17 @@
}
<div class="adf-cloud-form-outcome-buttons">
<ng-content select="adf-cloud-form-custom-outcomes" />
@for (outcome of form.outcomes; track outcome.name) {
@if (outcome.isVisible) {
<button
[id]="'adf-form-' + outcome.name | formatSpace"
[color]="getColorForOutcome(outcome.name)"
mat-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
class="adf-cloud-form-custom-outcome-button"
(click)="onOutcomeClicked(outcome)"
>
{{ getCustomOutcomeButtonText(outcome) || (outcome.name | translate | uppercase) }}
</button>
}
@for (outcome of visibleOutcomes; track outcome.name) {
<button
[id]="'adf-form-' + outcome.name | formatSpace"
[color]="getColorForOutcome(outcome.name)"
mat-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
class="adf-cloud-form-custom-outcome-button"
(click)="onOutcomeClicked(outcome)"
>
{{ getCustomOutcomeButtonText(outcome) || (outcome.name | translate | uppercase) }}
</button>
}
</div>
</mat-card-actions>
@@ -1210,6 +1210,33 @@ describe('FormCloudComponent', () => {
expect(formComponent.isOutcomeButtonEnabled(startProcessOutcome)).toBeTruthy();
});
it('should not include START_PROCESS outcome when form is loaded for a task', () => {
formComponent.taskId = 'mock-task-id';
formComponent.appName = 'mock-app';
const form = formComponent.parseForm(cloudFormMock);
const startProcessOutcome = form.outcomes.find((outcome) => outcome.id === FormModel.START_PROCESS_OUTCOME);
expect(startProcessOutcome).toBeUndefined();
});
it('should populate visibleOutcomes when the form is set', () => {
formComponent.showCompleteButton = true;
formComponent.form = new FormModel(cloudFormMock);
expect(formComponent.visibleOutcomes.length).toBeGreaterThan(0);
expect(formComponent.visibleOutcomes.every((outcome) => outcome.name !== FormOutcomeModel.START_PROCESS_ACTION)).toBe(true);
});
it('should clear visibleOutcomes when the form is cleared', () => {
formComponent.showCompleteButton = true;
formComponent.form = new FormModel(cloudFormMock);
expect(formComponent.visibleOutcomes.length).toBeGreaterThan(0);
formComponent.form = null;
expect(formComponent.visibleOutcomes).toEqual([]);
});
it('should raise [executeOutcome] event for formService', async () => {
spyOn(formComponent.executeOutcome, 'emit');
@@ -1656,6 +1683,7 @@ describe('FormCloudComponent', () => {
describe('Custom outcome button text for default outcomes', () => {
beforeEach(() => {
formComponent.showCompleteButton = true;
formComponent.form = formComponent.parseForm(emptyFormRepresentationJSON);
});
@@ -175,6 +175,19 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
formCloudRepresentationJSON: any;
fieldValidators: FormFieldValidator[] = [];
/** Pre-computed list of outcome buttons to render, filtered by visibility rules. */
visibleOutcomes: FormOutcomeModel[] = [];
override get form(): FormModel {
return super.form;
}
@Input()
override set form(form: FormModel) {
super.form = form;
this.recomputeVisibleOutcomes();
}
readonly id: string;
displayMode: string;
displayConfiguration: FormCloudDisplayModeConfiguration = DisplayModeService.DEFAULT_DISPLAY_MODE_CONFIGURATIONS[0];
@@ -268,6 +281,13 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.disableSaveButton = false;
}
});
this.formService.formRulesEvent
.pipe(
filter((event) => event?.type === 'fieldValueChanged' && event.form?.id === this.form?.id),
takeUntilDestroyed()
)
.subscribe(() => this.recomputeVisibleOutcomes());
}
@HostListener('keydown', ['$event'])
@@ -318,6 +338,10 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.setCheckParentVisibilityForValidationOnFields();
this.form.validateForm();
}
if (changes['readOnly'] || changes['showCompleteButton'] || changes['showSaveButton']) {
this.recomputeVisibleOutcomes();
}
}
ngOnInit(): void {
@@ -511,9 +535,11 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
});
const form = new FormModel(formCloudRepresentationJSON, formValues, this.readOnly, this.formService, undefined, this.fieldValidators);
if (!form) {
form.outcomes = this.getFormDefinitionOutcomes(form);
if (this.taskId) {
form.outcomes = (form.outcomes ?? []).filter((outcome) => outcome.id !== FormModel.START_PROCESS_OUTCOME);
}
return form;
}
@@ -533,6 +559,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
checkVisibility(field: FormFieldModel) {
if (field?.form) {
this.visibilityService.refreshVisibility(field.form);
this.recomputeVisibleOutcomes();
}
}
@@ -545,6 +572,16 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}
}
private recomputeVisibleOutcomes(): void {
const outcomes = this.form?.outcomes;
if (!outcomes) {
this.visibleOutcomes = [];
return;
}
this.visibleOutcomes = outcomes.filter((outcome) => outcome.isVisible && this.isOutcomeButtonVisible(outcome, this.form.readOnly));
}
/**
* Sets the parent visibility check flag on all form fields.
* When enabled, fields inside hidden groups/sections will skip validation.