mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
AAE-33909 Ensure onProcessFinish event triggers when invoked from onFormLoaded event (#10867)
* AAE-33909 Ensure onProcessFinish event triggers when invoked from onFormLoaded event * clean code * fix unit tests * update outcomes buttons * update
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
import { Directive, EventEmitter, Input, Output } from '@angular/core';
|
import { Directive, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { ThemePalette } from '@angular/material/core';
|
import { ThemePalette } from '@angular/material/core';
|
||||||
import { FormFieldModel, FormFieldValidator, FormModel, FormOutcomeEvent, FormOutcomeModel } from './widgets';
|
import { FormFieldModel, FormFieldValidator, FormModel, FormOutcomeEvent, FormOutcomeModel } from './widgets';
|
||||||
|
import { isOutcomeButtonVisible } from './helpers/buttons-visibility';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
standalone: true
|
standalone: true
|
||||||
@@ -103,10 +104,6 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -169,22 +166,7 @@ export abstract class FormBaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
||||||
if (outcome?.name) {
|
return isOutcomeButtonVisible(outcome, { isFormReadOnly, showCompleteButton: this.showCompleteButton, showSaveButton: this.showSaveButton });
|
||||||
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
|
||||||
return this.showCompleteButton;
|
|
||||||
}
|
|
||||||
if (isFormReadOnly) {
|
|
||||||
return outcome.isSelected;
|
|
||||||
}
|
|
||||||
if (outcome.name === FormOutcomeModel.SAVE_ACTION) {
|
|
||||||
return this.showSaveButton;
|
|
||||||
}
|
|
||||||
if (outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -73,6 +73,7 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
|||||||
if (w.adf === undefined) {
|
if (w.adf === undefined) {
|
||||||
w.adf = {};
|
w.adf = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalField = this.getField();
|
const originalField = this.getField();
|
||||||
if (originalField) {
|
if (originalField) {
|
||||||
const customTemplate = this.field.form.customFieldTemplates[originalField.type];
|
const customTemplate = this.field.form.customFieldTemplates[originalField.type];
|
||||||
|
@@ -40,7 +40,8 @@
|
|||||||
<section class="adf-grid-list-column-view" *ngIf="currentRootElement?.isExpanded">
|
<section class="adf-grid-list-column-view" *ngIf="currentRootElement?.isExpanded">
|
||||||
<div class="adf-grid-list-single-column"
|
<div class="adf-grid-list-single-column"
|
||||||
*ngFor="let column of currentRootElement?.columns"
|
*ngFor="let column of currentRootElement?.columns"
|
||||||
[style.width.%]="getColumnWidth(currentRootElement)">
|
[style.width.%]="getColumnWidth(currentRootElement)"
|
||||||
|
>
|
||||||
<ng-container *ngFor="let field of column?.fields">
|
<ng-container *ngFor="let field of column?.fields">
|
||||||
<ng-container *ngIf="field.type === 'section'; else formField">
|
<ng-container *ngIf="field.type === 'section'; else formField">
|
||||||
<adf-form-section [field]="field"/>
|
<adf-form-section [field]="field"/>
|
||||||
@@ -61,9 +62,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="currentRootElement.type === 'dynamic-table'" class="adf-container-widget">
|
<div *ngIf="currentRootElement.type === 'dynamic-table'" class="adf-container-widget">
|
||||||
<adf-form-field [field]="currentRootElement" />
|
<adf-form-field [field]="currentRootElement" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="adf-container-widget"
|
<div class="adf-container-widget"
|
||||||
*ngIf="currentRootElement.type === 'readonly' && currentRootElement.field.params.field.type === 'dynamic-table'">
|
*ngIf="currentRootElement.type === 'readonly' && currentRootElement.field.params.field.type === 'dynamic-table'">
|
||||||
<adf-form-field [field]="currentRootElement.field"/>
|
<adf-form-field [field]="currentRootElement.field"/>
|
||||||
|
@@ -0,0 +1,45 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { FormOutcomeModel } from '../widgets';
|
||||||
|
|
||||||
|
interface IsOutcomeButtonVisibleProps {
|
||||||
|
isFormReadOnly: boolean;
|
||||||
|
showCompleteButton: boolean;
|
||||||
|
showSaveButton: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isOutcomeButtonVisible = (outcome: FormOutcomeModel, props: IsOutcomeButtonVisibleProps): boolean => {
|
||||||
|
const { isFormReadOnly, showCompleteButton, showSaveButton } = props;
|
||||||
|
|
||||||
|
if (outcome?.name) {
|
||||||
|
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
||||||
|
return showCompleteButton;
|
||||||
|
}
|
||||||
|
if (isFormReadOnly) {
|
||||||
|
return outcome.isSelected;
|
||||||
|
}
|
||||||
|
if (outcome.name === FormOutcomeModel.SAVE_ACTION) {
|
||||||
|
return showSaveButton;
|
||||||
|
}
|
||||||
|
if (outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
@@ -23,6 +23,7 @@ export * from './components/form-renderer.component';
|
|||||||
export * from './components/widgets';
|
export * from './components/widgets';
|
||||||
export * from './components/middlewares/middleware';
|
export * from './components/middlewares/middleware';
|
||||||
export * from './components/middlewares/decimal-middleware.service';
|
export * from './components/middlewares/decimal-middleware.service';
|
||||||
|
export * from './components/helpers/buttons-visibility';
|
||||||
|
|
||||||
export * from './services/form-rendering.service';
|
export * from './services/form-rendering.service';
|
||||||
export * from './services/form.service';
|
export * from './services/form.service';
|
||||||
|
@@ -670,12 +670,36 @@ describe('FormCloudComponent', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
const formValues: any[] = [];
|
const formValues: TaskVariableCloud[] = [
|
||||||
|
{
|
||||||
|
name: 'var1',
|
||||||
|
value: 'value1',
|
||||||
|
id: 'var1',
|
||||||
|
type: 'string',
|
||||||
|
hasValue: () => true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const change = new SimpleChange(null, formValues, false);
|
const change = new SimpleChange(null, formValues, false);
|
||||||
formComponent.data = formValues;
|
formComponent.data = formValues;
|
||||||
formComponent.ngOnChanges({ data: change });
|
formComponent.ngOnChanges({ data: change });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not change form if custom form values is empty array', () => {
|
||||||
|
const formModel = new FormModel({
|
||||||
|
id: 'id',
|
||||||
|
taskId: 'task-id',
|
||||||
|
fields: [{ id: 'field1' }, { id: 'field2' }]
|
||||||
|
});
|
||||||
|
formComponent.form = formModel;
|
||||||
|
|
||||||
|
const formValues: TaskVariableCloud[] = [];
|
||||||
|
const change = new SimpleChange(null, formValues, false);
|
||||||
|
formComponent.ngOnChanges({ data: change });
|
||||||
|
|
||||||
|
expect(formComponent.form).toEqual(formModel);
|
||||||
|
});
|
||||||
|
|
||||||
it('should save task form and raise corresponding event', () => {
|
it('should save task form and raise corresponding event', () => {
|
||||||
spyOn(formCloudService, 'saveTaskForm').and.callFake(
|
spyOn(formCloudService, 'saveTaskForm').and.callFake(
|
||||||
() =>
|
() =>
|
||||||
|
@@ -242,13 +242,14 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = changes['data'];
|
const data = changes['data']?.currentValue;
|
||||||
if (data?.currentValue) {
|
if (data?.length > 0) {
|
||||||
this.refreshFormData();
|
this.refreshFormData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formRepresentation = changes['form'];
|
const formRepresentation = changes['form'];
|
||||||
|
|
||||||
if (formRepresentation?.currentValue) {
|
if (formRepresentation?.currentValue) {
|
||||||
this.form = formRepresentation.currentValue;
|
this.form = formRepresentation.currentValue;
|
||||||
this.onFormLoaded(this.form);
|
this.onFormLoaded(this.form);
|
||||||
|
@@ -17,13 +17,16 @@
|
|||||||
class="adf-process-input-container"
|
class="adf-process-input-container"
|
||||||
floatLabel="always"
|
floatLabel="always"
|
||||||
*ngIf="showSelectProcessDropdown"
|
*ngIf="showSelectProcessDropdown"
|
||||||
data-automation-id="adf-select-cloud-process-dropdown">
|
data-automation-id="adf-select-cloud-process-dropdown"
|
||||||
|
>
|
||||||
<mat-label class="adf-start-process-input-label">{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate }}</mat-label>
|
<mat-label class="adf-start-process-input-label">{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate }}</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
formControlName="processDefinition"
|
formControlName="processDefinition"
|
||||||
[matAutocomplete]="auto"
|
[matAutocomplete]="auto"
|
||||||
id="processDefinitionName">
|
id="processDefinitionName"
|
||||||
|
>
|
||||||
|
|
||||||
<div class="adf-process-input-autocomplete">
|
<div class="adf-process-input-autocomplete">
|
||||||
<mat-autocomplete
|
<mat-autocomplete
|
||||||
#auto="matAutocomplete"
|
#auto="matAutocomplete"
|
||||||
@@ -37,6 +40,7 @@
|
|||||||
{{ getProcessDefinitionValue(processDef) }}
|
{{ getProcessDefinitionValue(processDef) }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id="adf-select-process-dropdown"
|
id="adf-select-process-dropdown"
|
||||||
title="{{'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.SELECT_PROCESS_DROPDOWN' | translate}}"
|
title="{{'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.SELECT_PROCESS_DROPDOWN' | translate}}"
|
||||||
@@ -44,6 +48,7 @@
|
|||||||
(click)="displayDropdown($event)">
|
(click)="displayDropdown($event)">
|
||||||
<mat-icon>arrow_drop_down</mat-icon>
|
<mat-icon>arrow_drop_down</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<mat-error
|
<mat-error
|
||||||
*ngIf="processDefinition.hasError('required')"
|
*ngIf="processDefinition.hasError('required')"
|
||||||
@@ -79,8 +84,8 @@
|
|||||||
[data]="resolvedValues"
|
[data]="resolvedValues"
|
||||||
[formId]="processDefinitionCurrent.formKey"
|
[formId]="processDefinitionCurrent.formKey"
|
||||||
[displayModeConfigurations]="displayModeConfigurations"
|
[displayModeConfigurations]="displayModeConfigurations"
|
||||||
[showSaveButton]="false"
|
[showSaveButton]="showSaveButton"
|
||||||
[showCompleteButton]="false"
|
[showCompleteButton]="showCompleteButton"
|
||||||
[showRefreshButton]="false"
|
[showRefreshButton]="false"
|
||||||
[showValidationIcon]="false"
|
[showValidationIcon]="false"
|
||||||
[showTitle]="false"
|
[showTitle]="false"
|
||||||
|
@@ -35,7 +35,8 @@ import {
|
|||||||
FormModel,
|
FormModel,
|
||||||
InplaceFormInputComponent,
|
InplaceFormInputComponent,
|
||||||
LocalizedDatePipe,
|
LocalizedDatePipe,
|
||||||
TranslationService
|
TranslationService,
|
||||||
|
isOutcomeButtonVisible
|
||||||
} from '@alfresco/adf-core';
|
} 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';
|
||||||
@@ -95,8 +96,6 @@ 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 = '';
|
||||||
@@ -207,6 +206,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
private readonly hasVisibleOutcomesSubject = new BehaviorSubject<boolean>(false);
|
private readonly hasVisibleOutcomesSubject = new BehaviorSubject<boolean>(false);
|
||||||
private readonly dialog = inject(MatDialog);
|
private readonly dialog = inject(MatDialog);
|
||||||
|
|
||||||
|
showSaveButton = false;
|
||||||
|
showCompleteButton = false;
|
||||||
|
|
||||||
get isProcessFormValid(): boolean {
|
get isProcessFormValid(): boolean {
|
||||||
if (this.hasForm && this.isFormCloudLoaded) {
|
if (this.hasForm && this.isFormCloudLoaded) {
|
||||||
return (this.formCloud ? !Object.keys(this.formCloud.values).length : false) || this.formCloud?.isValid || this.isProcessStarting;
|
return (this.formCloud ? !Object.keys(this.formCloud.values).length : false) || this.formCloud?.isValid || this.isProcessStarting;
|
||||||
@@ -256,6 +258,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
.subscribe((processDefinitionName) => {
|
.subscribe((processDefinitionName) => {
|
||||||
this.selectProcessDefinitionByProcessDefinitionName(processDefinitionName);
|
this.selectProcessDefinitionByProcessDefinitionName(processDefinitionName);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.showStartProcessButton$ = combineLatest([this.displayStartSubject, this.hasVisibleOutcomesSubject]).pipe(
|
this.showStartProcessButton$ = combineLatest([this.displayStartSubject, this.hasVisibleOutcomesSubject]).pipe(
|
||||||
map(([displayStart, hasVisibleOutcomes]) => (displayStart !== null ? displayStart === 'true' : !hasVisibleOutcomes))
|
map(([displayStart, hasVisibleOutcomes]) => (displayStart !== null ? displayStart === 'true' : !hasVisibleOutcomes))
|
||||||
);
|
);
|
||||||
@@ -284,9 +287,14 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
this.isFormCloudLoaded = true;
|
this.isFormCloudLoaded = true;
|
||||||
this.formCloud = form;
|
this.formCloud = form;
|
||||||
|
|
||||||
if (this.startForm) {
|
const anyOutcomeVisible = form?.outcomes?.some((outcome) =>
|
||||||
this.hasVisibleOutcomesSubject.next(this.startForm.hasVisibleOutcomes);
|
isOutcomeButtonVisible(outcome, {
|
||||||
}
|
isFormReadOnly: form.readOnly,
|
||||||
|
showCompleteButton: this.showCompleteButton,
|
||||||
|
showSaveButton: this.showSaveButton
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.hasVisibleOutcomesSubject.next(anyOutcomeVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMaxNameLength(): number {
|
private getMaxNameLength(): number {
|
||||||
|
Reference in New Issue
Block a user