AAE-33090 Open Next Task Checkbox (#10757)

* [AAE-33090] Add optional checkbox for 'open next task' feature

* [AAE-33090] move translation to LABEL property

* [33090] add unit tests

* add tests for checkbox value

* [AAE-33090] remove some comments

* [AAE-33090] update documentation

* AAE-33090 kind of a typo

* AAE-33090 remove all comments
This commit is contained in:
Jonas Wollweber 2025-04-09 10:14:06 +02:00 committed by GitHub
parent f6c446498a
commit 659805ab20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 286 additions and 62 deletions

View File

@ -85,11 +85,13 @@ The template defined inside `empty-form` will be shown when no form definition i
| fieldValidators | [`FormFieldValidator`](../../../lib/core/src/lib/form/components/widgets/core/form-field-validator.ts)`[]` | | [FormFieldValidator](../../../lib/core/src/lib/form/components/widgets/core/form-field-validator.ts) allow to override the form field validators provided. | | fieldValidators | [`FormFieldValidator`](../../../lib/core/src/lib/form/components/widgets/core/form-field-validator.ts)`[]` | | [FormFieldValidator](../../../lib/core/src/lib/form/components/widgets/core/form-field-validator.ts) allow to override the form field validators provided. |
| form | [`FormModel`](../../../lib/core/src/lib/form/components/widgets/core/form.model.ts) | | Underlying form model instance. | | form | [`FormModel`](../../../lib/core/src/lib/form/components/widgets/core/form.model.ts) | | Underlying form model instance. |
| formId | `string` | | Task id to fetch corresponding form and values. | | formId | `string` | | Task id to fetch corresponding form and values. |
| isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. |
| nameNode | `string` | | Name to assign to the new node where the metadata are stored. | | nameNode | `string` | | Name to assign to the new node where the metadata are stored. |
| path | `string` | | Path of the folder where the metadata will be stored. | | path | `string` | | Path of the folder where the metadata will be stored. |
| processInstanceId | `string` | | ProcessInstanceId id to fetch corresponding form and values. | | processInstanceId | `string` | | ProcessInstanceId id to fetch corresponding form and values. |
| readOnly | `boolean` | false | Toggle readonly state of the form. Forces all form widgets to render as readonly if enabled. | | readOnly | `boolean` | false | Toggle readonly state of the form. Forces all form widgets to render as readonly if enabled. |
| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` outcome button. | | showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` outcome button. |
| showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. |
| showRefreshButton | `boolean` | true | Toggle rendering of the `Refresh` button. | | showRefreshButton | `boolean` | true | Toggle rendering of the `Refresh` button. |
| showSaveButton | `boolean` | true | Toggle rendering of the `Save` outcome button. | | showSaveButton | `boolean` | true | Toggle rendering of the `Save` outcome button. |
| showTitle | `boolean` | true | Toggle rendering of the form title. | | showTitle | `boolean` | true | Toggle rendering of the form title. |
@ -111,6 +113,7 @@ The template defined inside `empty-form` will be shown when no form definition i
| formSaved | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../../lib/core/src/lib/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Save` or custom outcomes. | | formSaved | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../../lib/core/src/lib/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Save` or custom outcomes. |
| displayModeOn | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormCloudDisplayModeConfiguration`](../../../lib/process-services-cloud/src/lib/services/form-fields.interfaces.ts)`>` | Emitted when a display mode configuration is turned on. | | displayModeOn | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormCloudDisplayModeConfiguration`](../../../lib/process-services-cloud/src/lib/services/form-fields.interfaces.ts)`>` | Emitted when a display mode configuration is turned on. |
| displayModeOff | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormCloudDisplayModeConfiguration`](../../../lib/process-services-cloud/src/lib/services/form-fields.interfaces.ts)`>` | Emitted when a display mode configuration is turned off. | | displayModeOff | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormCloudDisplayModeConfiguration`](../../../lib/process-services-cloud/src/lib/services/form-fields.interfaces.ts)`>` | Emitted when a display mode configuration is turned off. |
| nextTaskCheckboxCheckedChanged | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`MatCheckboxChange`](https://material.angular.io/components/checkbox/api#MatCheckboxChange)`>` | Emitted when the `Open next task` checkbox was toggled. |
## Details ## Details

View File

@ -37,9 +37,11 @@ Starts a process.
| Name | Type | Default value | Description | | Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- | | ---- | ---- | ------------- | ----------- |
| appName | `string` | "" | (required) Name of the app. | | appName | `string` | "" | (required) Name of the app. |
| isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. |
| maxNameLength | `number` | MAX_NAME_LENGTH | Maximum length of the process name. | | maxNameLength | `number` | MAX_NAME_LENGTH | Maximum length of the process name. |
| name | `string` | "" | Name of the process. | | name | `string` | "" | Name of the process. |
| processDefinitionName | `string` | | Name of the process definition. | | processDefinitionName | `string` | | Name of the process definition. |
| showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. |
| showSelectProcessDropdown | `boolean` | true | Show/hide the process dropdown list. | | showSelectProcessDropdown | `boolean` | true | Show/hide the process dropdown list. |
| showTitle | `boolean` | true | Show/hide title. | | showTitle | `boolean` | true | Show/hide title. |
| values | [`TaskVariableCloud`](../../../lib/process-services-cloud/src/lib/form/models/task-variable-cloud.model.ts)`[]` | | Parameter to pass form field values in the start form if one is associated. | | values | [`TaskVariableCloud`](../../../lib/process-services-cloud/src/lib/form/models/task-variable-cloud.model.ts)`[]` | | Parameter to pass form field values in the start form if one is associated. |
@ -52,6 +54,7 @@ Starts a process.
| cancel | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when the starting process is cancelled | | cancel | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when the starting process is cancelled |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when an error occurs. | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when an error occurs. |
| formContentClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ContentLinkModel`](../../../lib/core/src/lib/form/components/widgets/core/content-link.model.ts)`>` | Emitted when form content is clicked. | | formContentClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ContentLinkModel`](../../../lib/core/src/lib/form/components/widgets/core/content-link.model.ts)`>` | Emitted when form content is clicked. |
| nextTaskCheckboxCheckedChanged | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`MatCheckboxChange`](https://material.angular.io/components/checkbox/api#MatCheckboxChange)`>` | Emitted when the `Open next task` checkbox was toggled. |
| processDefinitionSelection | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessDefinitionCloud`](../../../lib/process-services-cloud/src/lib/models/process-definition-cloud.model.ts)`>` | Emitted when process definition selection changes. | | processDefinitionSelection | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessDefinitionCloud`](../../../lib/process-services-cloud/src/lib/models/process-definition-cloud.model.ts)`>` | Emitted when process definition selection changes. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when the process is successfully started. | | success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../../lib/process-services-cloud/src/lib/process/start-process/models/process-instance-cloud.model.ts)`>` | Emitted when the process is successfully started. |

View File

@ -33,34 +33,37 @@ Save and Complete buttons get disabled when at least one of the form's inputs ar
### Properties ### Properties
| Name | Type | Default value | Description | | Name | Type | Default value | Description |
|---------------------------|---------------------------------------|---------------|---------------------------------------------------| | ------------------------- | ------------------------------------- | ------------- | ------------------------------------------------------------------- |
| appName | `string` | "" | App id to fetch corresponding form and values. | | appName | `string` | "" | App id to fetch corresponding form and values. |
| readOnly | `boolean` | false | Toggle readonly state of the task. | | isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. |
| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | | readOnly | `boolean` | false | Toggle readonly state of the task. |
| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | | showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. |
| showRefreshButton | `boolean` | false | Toggle rendering of the `Refresh` button. | | showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. |
| showTitle | `boolean` | true | Toggle rendering of the form title. | | showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. |
| showValidationIcon | `boolean` | true | Toggle rendering of the `Validation` icon. | | showRefreshButton | `boolean` | false | Toggle rendering of the `Refresh` button. |
| taskId | `string` | | Task id to fetch corresponding form and values. | | showTitle | `boolean` | true | Toggle rendering of the form title. |
| displayModeConfigurations | `FormCloudDisplayModeConfiguration[]` | | The available display configurations for the form | | showValidationIcon | `boolean` | true | Toggle rendering of the `Validation` icon. |
| taskId | `string` | | Task id to fetch corresponding form and values. |
| displayModeConfigurations | `FormCloudDisplayModeConfiguration[]` | | The available display configurations for the form |
### Events ### Events
| Name | Type | Description | | Name | Type | Description |
|--------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------| | ------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | | cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. |
| error | `EventEmitter<any>` | Emitted when any error occurs. | | error | `EventEmitter<any>` | Emitted when any error occurs. |
| executeOutcome | `EventEmitter<FormOutcomeEvent>` | Emitted when any outcome is executed. Default behaviour can be prevented via `event.preventDefault()`. | | executeOutcome | `EventEmitter<FormOutcomeEvent>` | Emitted when any outcome is executed. Default behaviour can be prevented via `event.preventDefault()`. |
| formCompleted | `EventEmitter<FormModel>` | Emitted when the form is submitted with the `Complete` outcome. | | formCompleted | `EventEmitter<FormModel>` | Emitted when the form is submitted with the `Complete` outcome. |
| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | | formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. |
| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | | formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. |
| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | | nextTaskCheckboxCheckedChanged | `EventEmitter<MatCheckboxChange>` | Emitted when the `Open next task` checkbox was toggled. |
| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | | onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. |
| taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. | | taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. |
| taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. | | taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. |
| displayModeOn | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned on. | | taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. |
| displayModeOff | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned off. | | displayModeOn | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned on. |
| displayModeOff | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned off. |
#### Enabling fullscreen display for the form of the task #### Enabling fullscreen display for the form of the task

View File

@ -33,31 +33,33 @@ Based on property taskDetails: TaskDetailsCloudModel shows a form or a screen.
### Properties ### Properties
| Name | Type | Default value | Description | | Name | Type | Default value | Description |
|---------------------------|---------------------------------------|---------------|---------------------------------------------------| | ------------------------- | ------------------------------------- | ------------- | ------------------------------------------------------------------- |
| appName | `string` | "" | App id to fetch corresponding form and values. | | appName | `string` | "" | App id to fetch corresponding form and values. |
| readOnly | `boolean` | false | Toggle readonly state of the task. | | isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. |
| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | | readOnly | `boolean` | false | Toggle readonly state of the task. |
| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | | showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. |
| showTitle | `boolean` | true | Toggle rendering of the form title. | | showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. |
| showValidationIcon | `boolean` | true | Toggle rendering of the `Validation` icon. | | showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. |
| taskId | `string` | | Task id to fetch corresponding form and values. | | showTitle | `boolean` | true | Toggle rendering of the form title. |
| displayModeConfigurations | `FormCloudDisplayModeConfiguration[]` | | The available display configurations for the form | | showValidationIcon | `boolean` | true | Toggle rendering of the `Validation` icon. |
| taskId | `string` | | Task id to fetch corresponding form and values. |
| displayModeConfigurations | `FormCloudDisplayModeConfiguration[]` | | The available display configurations for the form |
### Events ### Events
| Name | Type | Description | | Name | Type | Description |
|--------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------| | ------------------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | | cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. |
| error | `EventEmitter<any>` | Emitted when any error occurs. | | error | `EventEmitter<any>` | Emitted when any error occurs. |
| executeOutcome | `EventEmitter<FormOutcomeEvent>` | Emitted when any outcome is executed. Default behaviour can be prevented via `event.preventDefault()`. | | executeOutcome | `EventEmitter<FormOutcomeEvent>` | Emitted when any outcome is executed. Default behaviour can be prevented via `event.preventDefault()`. |
| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | | formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. |
| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | | formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. |
| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | | nextTaskCheckboxCheckedChanged | `EventEmitter<MatCheckboxChange>` | Emitted when the `Open next task` checkbox was toggled. |
| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | | onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. |
| taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. | | taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. |
| taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. | | taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. |
| | taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. |
#### Enabling fullscreen display for the form of the task #### Enabling fullscreen display for the form of the task

View File

@ -74,6 +74,8 @@
<adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" /> <adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" />
</mat-card-content> </mat-card-content>
<mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end"> <mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end">
<mat-checkbox id="adf-form-open-next-task" *ngIf="showNextTaskCheckbox" [checked]="isNextTaskCheckboxChecked" (change)="onNextTaskCheckboxCheckedChanged($event)">{{'ADF_CLOUD_TASK_FORM.OPEN_NEXT_TASK.LABEL' | translate}}</mat-checkbox>
<span class="adf-card-actions-spacer"></span>
<ng-content select="adf-cloud-form-custom-outcomes" /> <ng-content select="adf-cloud-form-custom-outcomes" />
<ng-container *ngFor="let outcome of form.outcomes"> <ng-container *ngFor="let outcome of form.outcomes">
<button <button

View File

@ -18,6 +18,10 @@
flex-direction: column; flex-direction: column;
display: flex; display: flex;
} }
.adf-card-actions-spacer {
flex: 1 1 auto;
}
} }
&-fullscreen-container { &-fullscreen-container {

View File

@ -67,6 +67,7 @@ import { ProcessServiceCloudTestingModule } from '../../testing/process-service-
import { TaskVariableCloud } from '../models/task-variable-cloud.model'; import { TaskVariableCloud } from '../models/task-variable-cloud.model';
import { ProcessServicesCloudModule } from '../../process-services-cloud.module'; import { ProcessServicesCloudModule } from '../../process-services-cloud.module';
import { FormFieldValidator } from '../../../../../core/src/public-api'; import { FormFieldValidator } from '../../../../../core/src/public-api';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
const mockOauth2Auth: any = { const mockOauth2Auth: any = {
oauth2Auth: { oauth2Auth: {
@ -1191,6 +1192,64 @@ describe('FormCloudComponent', () => {
expect(form.fieldValidators.length).toBe(10); expect(form.fieldValidators.length).toBe(10);
}); });
it('should allow controlling [open next task] checkbox visibility', () => {
const formModel = new FormModel({ fields: [{ id: 'field2' }] });
formComponent.form = formModel;
const isCheckboxShown = () => {
const checkbox = fixture.debugElement.query(By.css('#adf-form-open-next-task'));
return !!checkbox;
};
fixture.detectChanges();
expect(isCheckboxShown()).toBeFalse();
formComponent.showNextTaskCheckbox = true;
fixture.detectChanges();
expect(isCheckboxShown()).toBeTrue();
formComponent.showNextTaskCheckbox = false;
fixture.detectChanges();
expect(isCheckboxShown()).toBeFalse();
});
it('should allow controlling [open next task] checkbox value', async () => {
const formModel = new FormModel({ fields: [{ id: 'field2' }] });
formComponent.form = formModel;
formComponent.showNextTaskCheckbox = true;
fixture.detectChanges();
const isCheckboxChecked = async () => {
const checkbox = await documentRootLoader.getHarness(MatCheckboxHarness.with({ selector: '#adf-form-open-next-task' }));
return checkbox.isChecked();
};
expect(await isCheckboxChecked()).toBeFalse();
formComponent.isNextTaskCheckboxChecked = true;
fixture.detectChanges();
expect(await isCheckboxChecked()).toBeTrue();
formComponent.isNextTaskCheckboxChecked = false;
fixture.detectChanges();
expect(await isCheckboxChecked()).toBeFalse();
});
it('should call onNextTaskCheckboxCheckedChanged when the checkbox is checked', async () => {
// Add fields to make sure the components are shown which contain the the checkbox
const formModel = new FormModel({ fields: [{ id: 'field2' }] });
formComponent.form = formModel;
formComponent.showNextTaskCheckbox = true;
fixture.detectChanges();
const checkbox = await documentRootLoader.getHarnessOrNull(MatCheckboxHarness);
spyOn(formComponent.nextTaskCheckboxCheckedChanged, 'emit');
await checkbox.check();
expect(formComponent.nextTaskCheckboxCheckedChanged.emit).toHaveBeenCalled();
});
describe('form validations', () => { describe('form validations', () => {
it('should be able to set visibility conditions for Attach File widget', async () => { it('should be able to set visibility conditions for Attach File widget', async () => {
spyOn(formCloudService, 'getForm').and.returnValue(of(conditionalUploadWidgetsMock)); spyOn(formCloudService, 'getForm').and.returnValue(of(conditionalUploadWidgetsMock));

View File

@ -67,6 +67,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { A11yModule } from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y';
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
export const FORM_CLOUD_FIELD_VALIDATORS_TOKEN = new InjectionToken<FormFieldValidator[]>('FORM_CLOUD_FIELD_VALIDATORS_TOKEN'); export const FORM_CLOUD_FIELD_VALIDATORS_TOKEN = new InjectionToken<FormFieldValidator[]>('FORM_CLOUD_FIELD_VALIDATORS_TOKEN');
@ -83,7 +84,8 @@ export const FORM_CLOUD_FIELD_VALIDATORS_TOKEN = new InjectionToken<FormFieldVal
MatIconModule, MatIconModule,
ToolbarDividerComponent, ToolbarDividerComponent,
ToolbarComponent, ToolbarComponent,
A11yModule A11yModule,
MatCheckboxModule
], ],
providers: [FormCloudSpinnerService], providers: [FormCloudSpinnerService],
templateUrl: './form-cloud.component.html', templateUrl: './form-cloud.component.html',
@ -114,12 +116,18 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
@Input() @Input()
data: TaskVariableCloud[]; data: TaskVariableCloud[];
/** /** The available display configurations for the form */
* The available display configurations for the form
*/
@Input() @Input()
displayModeConfigurations: FormCloudDisplayModeConfiguration[]; displayModeConfigurations: FormCloudDisplayModeConfiguration[];
/** Toggle rendering of the `Open next task` checkbox. */
@Input()
showNextTaskCheckbox = false;
/** Whether the `Open next task` checkbox is checked by default or not. */
@Input()
isNextTaskCheckboxChecked = false;
/** Emitted when the form is submitted with the `Save` or custom outcomes. */ /** Emitted when the form is submitted with the `Save` or custom outcomes. */
@Output() @Output()
formSaved = new EventEmitter<FormModel>(); formSaved = new EventEmitter<FormModel>();
@ -148,6 +156,10 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
@Output() @Output()
displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>(); displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>();
/** Emitted when the `Open next task` checkbox was toggled. */
@Output()
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
protected subscriptions: Subscription[] = []; protected subscriptions: Subscription[] = [];
nodeId: string; nodeId: string;
formCloudRepresentationJSON: any; formCloudRepresentationJSON: any;
@ -510,4 +522,8 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.fieldValidators = [...this.fieldValidators, ...injectedFieldValidators]; this.fieldValidators = [...this.fieldValidators, ...injectedFieldValidators];
} }
} }
onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) {
this.nextTaskCheckboxCheckedChanged.emit(event);
}
} }

View File

@ -379,7 +379,8 @@
"ERROR": { "ERROR": {
"INVALID_DESTINATION_FOLDER_PATH": "Invalid destination folder path", "INVALID_DESTINATION_FOLDER_PATH": "Invalid destination folder path",
"DESTINATION_FOLDER_PATH_ERROR": "The destination path is incorrect or does not exist, rollback to -my- location" "DESTINATION_FOLDER_PATH_ERROR": "The destination path is incorrect or does not exist, rollback to -my- location"
} },
"OPEN_NEXT_TASK": {"LABEL": "Open next task"}
}, },
"ADF_CLOUD_FORM_COMPONENT": { "ADF_CLOUD_FORM_COMPONENT": {
"RETRIEVE_METADATA": "Autofill Form" "RETRIEVE_METADATA": "Autofill Form"

View File

@ -84,9 +84,13 @@
[showRefreshButton]="false" [showRefreshButton]="false"
[showValidationIcon]="false" [showValidationIcon]="false"
[showTitle]="false" [showTitle]="false"
[showNextTaskCheckbox]="showNextTaskCheckbox"
[isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked"
(formContentClicked)="onFormContentClicked($event)" (formContentClicked)="onFormContentClicked($event)"
(formLoaded)="onFormLoaded($event)" (formLoaded)="onFormLoaded($event)"
(executeOutcome)="onCustomOutcomeClicked($event.outcome.name)"> (executeOutcome)="onCustomOutcomeClicked($event.outcome.name)"
(nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)"
>
<adf-cloud-form-custom-outcomes> <adf-cloud-form-custom-outcomes>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" /> <ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
</adf-cloud-form-custom-outcomes> </adf-cloud-form-custom-outcomes>

View File

@ -53,6 +53,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatOptionModule } from '@angular/material/core'; import { MatOptionModule } from '@angular/material/core';
import { FormCloudComponent } from '../../../form/components/form-cloud.component'; import { FormCloudComponent } from '../../../form/components/form-cloud.component';
import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component'; import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component';
import { MatCheckboxChange } from '@angular/material/checkbox';
const MAX_NAME_LENGTH: number = 255; const MAX_NAME_LENGTH: number = 255;
const PROCESS_DEFINITION_DEBOUNCE: number = 300; const PROCESS_DEFINITION_DEBOUNCE: number = 300;
@ -131,6 +132,14 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
@Input() @Input()
displayModeConfigurations: FormCloudDisplayModeConfiguration[]; displayModeConfigurations: FormCloudDisplayModeConfiguration[];
/** Toggle rendering of the `Open next task` checkbox. */
@Input()
showNextTaskCheckbox = false;
/** Whether the `Open next task` checkbox is checked by default or not. */
@Input()
isNextTaskCheckboxChecked = false;
/** Emitted when the process is successfully started. */ /** Emitted when the process is successfully started. */
@Output() @Output()
success = new EventEmitter<ProcessInstanceCloud>(); success = new EventEmitter<ProcessInstanceCloud>();
@ -151,6 +160,10 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
@Output() @Output()
processDefinitionSelection: EventEmitter<ProcessDefinitionCloud> = new EventEmitter<ProcessDefinitionCloud>(); processDefinitionSelection: EventEmitter<ProcessDefinitionCloud> = new EventEmitter<ProcessDefinitionCloud>();
/** Emitted when the `Open next task` checkbox was toggled. */
@Output()
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
processDefinitionList: ProcessDefinitionCloud[] = []; processDefinitionList: ProcessDefinitionCloud[] = [];
processDefinitionCurrent?: ProcessDefinitionCloud; processDefinitionCurrent?: ProcessDefinitionCloud;
errorMessageId: string = ''; errorMessageId: string = '';
@ -541,4 +554,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
} }
return processName; return processName;
} }
onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) {
this.nextTaskCheckboxCheckedChanged.emit(event);
}
} }

View File

@ -12,6 +12,8 @@
[showCompleteButton]="canCompleteTask()" [showCompleteButton]="canCompleteTask()"
[showSaveButton]="canCompleteTask()" [showSaveButton]="canCompleteTask()"
[displayModeConfigurations]="displayModeConfigurations" [displayModeConfigurations]="displayModeConfigurations"
[showNextTaskCheckbox]="showNextTaskCheckbox"
[isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked"
(formSaved)="onFormSaved($event)" (formSaved)="onFormSaved($event)"
(formCompleted)="onFormCompleted($event)" (formCompleted)="onFormCompleted($event)"
(formError)="onError($event)" (formError)="onError($event)"
@ -20,6 +22,7 @@
(executeOutcome)="onFormExecuteOutcome($event)" (executeOutcome)="onFormExecuteOutcome($event)"
(displayModeOn)="onDisplayModeOn($event)" (displayModeOn)="onDisplayModeOn($event)"
(displayModeOff)="onDisplayModeOff($event)" (displayModeOff)="onDisplayModeOff($event)"
(nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)"
> >
<adf-cloud-form-custom-outcomes> <adf-cloud-form-custom-outcomes>
<adf-cloud-user-task-cloud-buttons <adf-cloud-user-task-cloud-buttons

View File

@ -27,6 +27,7 @@ import { TaskDetailsCloudModel } from '../../../models/task-details-cloud.model'
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component'; import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
import { FormCustomOutcomesComponent } from '../../../../form/components/form-cloud-custom-outcomes.component'; import { FormCustomOutcomesComponent } from '../../../../form/components/form-cloud-custom-outcomes.component';
import { MatCheckboxChange } from '@angular/material/checkbox';
@Component({ @Component({
selector: 'adf-cloud-task-form', selector: 'adf-cloud-task-form',
@ -87,6 +88,14 @@ export class TaskFormCloudComponent {
@Input() @Input()
taskDetails: TaskDetailsCloudModel; taskDetails: TaskDetailsCloudModel;
/** Toggle rendering of the `Open next task` checkbox. */
@Input()
showNextTaskCheckbox = false;
/** Whether the `Open next task` checkbox is checked by default or not. */
@Input()
isNextTaskCheckboxChecked = false;
/** Emitted when the form is saved. */ /** Emitted when the form is saved. */
@Output() @Output()
formSaved = new EventEmitter<FormModel>(); formSaved = new EventEmitter<FormModel>();
@ -134,6 +143,10 @@ export class TaskFormCloudComponent {
@Output() @Output()
displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>(); displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>();
/** Emitted when the `Open next task` checkbox was toggled. */
@Output()
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
@ViewChild('adfCloudForm', { static: false }) @ViewChild('adfCloudForm', { static: false })
adfCloudForm: FormCloudComponent; adfCloudForm: FormCloudComponent;
@ -225,4 +238,8 @@ export class TaskFormCloudComponent {
onDisplayModeOff(displayModeConfiguration: FormCloudDisplayModeConfiguration) { onDisplayModeOff(displayModeConfiguration: FormCloudDisplayModeConfiguration) {
this.displayModeOff.emit(displayModeConfiguration); this.displayModeOff.emit(displayModeConfiguration);
} }
onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) {
this.nextTaskCheckboxCheckedChanged.emit(event);
}
} }

View File

@ -12,6 +12,8 @@
[showTitle]="showTitle" [showTitle]="showTitle"
[taskId]="taskId" [taskId]="taskId"
[taskDetails]="taskDetails" [taskDetails]="taskDetails"
[showNextTaskCheckbox]="showNextTaskCheckbox"
[isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked"
(cancelClick)="onCancelForm()" (cancelClick)="onCancelForm()"
(executeOutcome)="onExecuteOutcome($event)" (executeOutcome)="onExecuteOutcome($event)"
(error)="onError($event)" (error)="onError($event)"
@ -20,6 +22,7 @@
(taskCompleted)="onCompleteTaskForm()" (taskCompleted)="onCompleteTaskForm()"
(taskClaimed)="onClaimTask()" (taskClaimed)="onClaimTask()"
(taskUnclaimed)="onTaskUnclaimed()" (taskUnclaimed)="onTaskUnclaimed()"
(nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)"
/> />
</ng-container> </ng-container>
@ -63,6 +66,8 @@
[subtitle]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.SUBTITLE'" /> [subtitle]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.SUBTITLE'" />
</mat-card-content> </mat-card-content>
<mat-card-actions class="adf-task-form-actions" align="end"> <mat-card-actions class="adf-task-form-actions" align="end">
<mat-checkbox id="adf-form-open-next-task" *ngIf="showNextTaskCheckbox" [checked]="isNextTaskCheckboxChecked" (change)="onNextTaskCheckboxCheckedChanged($event)">{{'ADF_CLOUD_TASK_FORM.OPEN_NEXT_TASK.LABEL' | translate}}</mat-checkbox>
<span class="adf-card-actions-spacer"></span>
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" /> <ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
<button <button
*ngIf="canCompleteTask()" *ngIf="canCompleteTask()"

View File

@ -4,6 +4,10 @@
> div { > div {
height: 100%; height: 100%;
} }
.adf-card-actions-spacer {
flex: 1 1 auto;
}
} }
.adf-user-task-cloud-spinner { .adf-user-task-cloud-spinner {

View File

@ -36,6 +36,8 @@ import { ProcessServiceCloudTestingModule } from 'lib/process-services-cloud/src
import { of, throwError } from 'rxjs'; import { of, throwError } from 'rxjs';
import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { IdentityUserService } from '../../../../people/services/identity-user.service';
import { UserTaskCloudComponent } from './user-task-cloud.component'; import { UserTaskCloudComponent } from './user-task-cloud.component';
import { By } from '@angular/platform-browser';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
const taskDetails: TaskDetailsCloudModel = { const taskDetails: TaskDetailsCloudModel = {
appName: 'simple-app', appName: 'simple-app',
@ -476,4 +478,61 @@ describe('UserTaskCloudComponent', () => {
const noFormTemplateTitleText = await matCard.getTitleText(); const noFormTemplateTitleText = await matCard.getTitleText();
expect(noFormTemplateTitleText).toBe(''); expect(noFormTemplateTitleText).toBe('');
}); });
it('should allow controlling [open next task] checkbox visibility', () => {
taskDetails.formKey = 'form';
component.getTaskType();
const isCheckboxShown = () => {
const checkbox = fixture.debugElement.query(By.css('#adf-form-open-next-task'));
return !!checkbox;
};
fixture.detectChanges();
expect(isCheckboxShown()).toBeFalse();
component.showNextTaskCheckbox = true;
fixture.detectChanges();
expect(isCheckboxShown()).toBeTrue();
component.showNextTaskCheckbox = false;
fixture.detectChanges();
expect(isCheckboxShown()).toBeFalse();
});
it('should allow controlling [open next task] checkbox value', async () => {
taskDetails.formKey = 'form';
component.getTaskType();
component.showNextTaskCheckbox = true;
const isCheckboxChecked = async () => {
const checkbox = await loader.getHarness(MatCheckboxHarness.with({ selector: '#adf-form-open-next-task' }));
return checkbox.isChecked();
};
fixture.detectChanges();
expect(await isCheckboxChecked()).toBeFalse();
component.isNextTaskCheckboxChecked = true;
fixture.detectChanges();
expect(await isCheckboxChecked()).toBeTrue();
component.isNextTaskCheckboxChecked = false;
fixture.detectChanges();
expect(await isCheckboxChecked()).toBeFalse();
});
it('should call onNextTaskCheckboxCheckedChanged when the checkbox is checked', async () => {
taskDetails.formKey = 'form';
component.getTaskType();
component.showNextTaskCheckbox = true;
fixture.detectChanges();
const checkbox = await loader.getHarnessOrNull(MatCheckboxHarness);
spyOn(component.nextTaskCheckboxCheckedChanged, 'emit');
await checkbox.check();
expect(component.nextTaskCheckboxCheckedChanged.emit).toHaveBeenCalled();
});
}); });

View File

@ -31,6 +31,7 @@ import { MatCardModule } from '@angular/material/card';
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component'; import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component';
import { CompleteTaskDirective } from './complete-task/complete-task.directive'; import { CompleteTaskDirective } from './complete-task/complete-task.directive';
import { catchError, EMPTY, forkJoin } from 'rxjs'; import { catchError, EMPTY, forkJoin } from 'rxjs';
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
const TaskTypes = { const TaskTypes = {
Form: 'form', Form: 'form',
@ -53,7 +54,8 @@ type TaskTypesType = (typeof TaskTypes)[keyof typeof TaskTypes];
EmptyContentComponent, EmptyContentComponent,
TaskScreenCloudComponent, TaskScreenCloudComponent,
TaskFormCloudComponent, TaskFormCloudComponent,
CompleteTaskDirective CompleteTaskDirective,
MatCheckboxModule
], ],
templateUrl: './user-task-cloud.component.html', templateUrl: './user-task-cloud.component.html',
styleUrls: ['./user-task-cloud.component.scss'] styleUrls: ['./user-task-cloud.component.scss']
@ -85,6 +87,14 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
@Input() @Input()
showCompleteButton = true; showCompleteButton = true;
/** Toggle rendering of the `Open next task` checkbox. */
@Input()
showNextTaskCheckbox = false;
/** Whether the `Open next task` checkbox is checked by default or not. */
@Input()
isNextTaskCheckboxChecked = false;
/** Toggle rendering of the form title. */ /** Toggle rendering of the form title. */
@Input() @Input()
showTitle: boolean = true; showTitle: boolean = true;
@ -105,6 +115,10 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
/** Emitted when the `Open next task` checkbox was toggled. */
@Output()
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
/** /**
* Emitted when any outcome is executed. Default behaviour can be prevented * Emitted when any outcome is executed. Default behaviour can be prevented
* via `event.preventDefault()`. * via `event.preventDefault()`.
@ -182,15 +196,19 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
} }
getTaskType(): void { getTaskType(): void {
if (this.taskDetails && !!this.taskDetails.formKey && this.taskDetails.formKey.includes(this.taskTypeEnum.Form)) { if (this.taskDetails && !!this.taskDetails.formKey) {
this.taskType = this.taskTypeEnum.Form; if (this.taskDetails.formKey.includes(this.taskTypeEnum.Form)) {
} else if (this.taskDetails && !!this.taskDetails.formKey && this.taskDetails.formKey.includes(this.taskTypeEnum.Screen)) { this.taskType = this.taskTypeEnum.Form;
this.taskType = this.taskTypeEnum.Screen; return;
const screenId = this.taskDetails.formKey.replace(this.taskTypeEnum.Screen + '-', ''); } else if (this.taskDetails.formKey.includes(this.taskTypeEnum.Screen)) {
this.screenId = screenId; this.taskType = this.taskTypeEnum.Screen;
} else { const screenId = this.taskDetails.formKey.replace(this.taskTypeEnum.Screen + '-', '');
this.taskType = this.taskTypeEnum.None; this.screenId = screenId;
return;
}
} }
this.taskType = this.taskTypeEnum.None;
} }
hasCandidateUsers(): boolean { hasCandidateUsers(): boolean {
@ -250,6 +268,10 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
this.taskUnclaimed.emit(this.taskId); this.taskUnclaimed.emit(this.taskId);
} }
onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) {
this.nextTaskCheckboxCheckedChanged.emit(event);
}
private loadTask(): void { private loadTask(): void {
this.loading = true; this.loading = true;
const tasks$ = this.taskCloudService.getTaskById(this.appName, this.taskId); const tasks$ = this.taskCloudService.getTaskById(this.appName, this.taskId);