From 659805ab20de8554a8d1bd46152f00f1f4cc2b6a Mon Sep 17 00:00:00 2001 From: Jonas Wollweber <87132834+JWollweber@users.noreply.github.com> Date: Wed, 9 Apr 2025 10:14:06 +0200 Subject: [PATCH] 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 --- .../components/form-cloud.component.md | 3 + .../start-process-cloud.component.md | 3 + .../components/task-form-cloud.component.md | 53 +++++++++-------- .../components/user-task-cloud.component.md | 46 ++++++++------- .../form/components/form-cloud.component.html | 2 + .../form/components/form-cloud.component.scss | 4 ++ .../components/form-cloud.component.spec.ts | 59 +++++++++++++++++++ .../form/components/form-cloud.component.ts | 24 ++++++-- .../src/lib/i18n/en.json | 3 +- .../start-process-cloud.component.html | 6 +- .../start-process-cloud.component.ts | 17 ++++++ .../task-form-cloud.component.html | 3 + .../task-form-cloud.component.ts | 17 ++++++ .../user-task-cloud.component.html | 5 ++ .../user-task-cloud.component.scss | 4 ++ .../user-task-cloud.component.spec.ts | 59 +++++++++++++++++++ .../user-task-cloud.component.ts | 40 ++++++++++--- 17 files changed, 286 insertions(+), 62 deletions(-) diff --git a/docs/process-services-cloud/components/form-cloud.component.md b/docs/process-services-cloud/components/form-cloud.component.md index a1ed2c1c8c..53fe935c9e 100644 --- a/docs/process-services-cloud/components/form-cloud.component.md +++ b/docs/process-services-cloud/components/form-cloud.component.md @@ -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. | | 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. | +| 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. | | path | `string` | | Path of the folder where the metadata will be stored. | | 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. | | 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. | | showSaveButton | `boolean` | true | Toggle rendering of the `Save` outcome button. | | 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. | | 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. | +| 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 diff --git a/docs/process-services-cloud/components/start-process-cloud.component.md b/docs/process-services-cloud/components/start-process-cloud.component.md index cd2052622b..a263be81d0 100644 --- a/docs/process-services-cloud/components/start-process-cloud.component.md +++ b/docs/process-services-cloud/components/start-process-cloud.component.md @@ -37,9 +37,11 @@ Starts a process. | Name | Type | Default value | Description | | ---- | ---- | ------------- | ----------- | | 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. | | name | `string` | "" | Name of the process. | | 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. | | 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. | @@ -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 | | 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. | +| 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. | | 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. | diff --git a/docs/process-services-cloud/components/task-form-cloud.component.md b/docs/process-services-cloud/components/task-form-cloud.component.md index e8e4776256..765998fad0 100644 --- a/docs/process-services-cloud/components/task-form-cloud.component.md +++ b/docs/process-services-cloud/components/task-form-cloud.component.md @@ -33,34 +33,37 @@ Save and Complete buttons get disabled when at least one of the form's inputs ar ### Properties -| Name | Type | Default value | Description | -|---------------------------|---------------------------------------|---------------|---------------------------------------------------| -| appName | `string` | "" | App id to fetch corresponding form and values. | -| readOnly | `boolean` | false | Toggle readonly state of the task. | -| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | -| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | -| showRefreshButton | `boolean` | false | Toggle rendering of the `Refresh` button. | -| showTitle | `boolean` | true | Toggle rendering of the form title. | -| 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 | +| Name | Type | Default value | Description | +| ------------------------- | ------------------------------------- | ------------- | ------------------------------------------------------------------- | +| appName | `string` | "" | App id to fetch corresponding form and values. | +| isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. | +| readOnly | `boolean` | false | Toggle readonly state of the task. | +| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | +| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | +| showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. | +| showRefreshButton | `boolean` | false | Toggle rendering of the `Refresh` button. | +| showTitle | `boolean` | true | Toggle rendering of the form title. | +| 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 -| Name | Type | Description | -|--------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------| -| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | -| 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()`. | -| formCompleted | `EventEmitter<FormModel>` | Emitted when the form is submitted with the `Complete` outcome. | -| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | -| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | -| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | -| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | -| taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. | -| taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. | -| displayModeOn | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned on. | -| displayModeOff | `EventEmitter<FormCloudDisplayModeConfiguration>` | Emitted when a display mode configuration is turned off. | +| Name | Type | Description | +| ------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | +| 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()`. | +| formCompleted | `EventEmitter<FormModel>` | Emitted when the form is submitted with the `Complete` outcome. | +| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | +| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | +| nextTaskCheckboxCheckedChanged | `EventEmitter<MatCheckboxChange>` | Emitted when the `Open next task` checkbox was toggled. | +| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | +| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | +| taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. | +| taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. | +| 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 diff --git a/docs/process-services-cloud/components/user-task-cloud.component.md b/docs/process-services-cloud/components/user-task-cloud.component.md index 7c1c8c79da..2170128d4b 100644 --- a/docs/process-services-cloud/components/user-task-cloud.component.md +++ b/docs/process-services-cloud/components/user-task-cloud.component.md @@ -33,31 +33,33 @@ Based on property taskDetails: TaskDetailsCloudModel shows a form or a screen. ### Properties -| Name | Type | Default value | Description | -|---------------------------|---------------------------------------|---------------|---------------------------------------------------| -| appName | `string` | "" | App id to fetch corresponding form and values. | -| readOnly | `boolean` | false | Toggle readonly state of the task. | -| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | -| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | -| showTitle | `boolean` | true | Toggle rendering of the form title. | -| 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 | +| Name | Type | Default value | Description | +| ------------------------- | ------------------------------------- | ------------- | ------------------------------------------------------------------- | +| appName | `string` | "" | App id to fetch corresponding form and values. | +| isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. | +| readOnly | `boolean` | false | Toggle readonly state of the task. | +| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | +| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` button. | +| showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox. | +| showTitle | `boolean` | true | Toggle rendering of the form title. | +| 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 -| Name | Type | Description | -|--------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------| -| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | -| 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()`. | -| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | -| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | -| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | -| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | -| taskCompleted | `EventEmitter<string>` | Emitted when the task is completed. | -| taskUnclaimed | `EventEmitter<string>` | Emitted when the task is unclaimed. | - | +| Name | Type | Description | +| ------------------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| cancelClick | `EventEmitter<string>` | Emitted when the cancel button is clicked. | +| 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()`. | +| formContentClicked | `EventEmitter<ContentLinkModel>` | Emitted when form content is clicked. | +| formSaved | `EventEmitter<FormModel>` | Emitted when the form is saved. | +| nextTaskCheckboxCheckedChanged | `EventEmitter<MatCheckboxChange>` | Emitted when the `Open next task` checkbox was toggled. | +| onTaskLoaded | `EventEmitter<TaskDetailsCloudModel>` | Emitted when a task is loaded. | +| taskClaimed | `EventEmitter<string>` | Emitted when the task is claimed. | +| 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 diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.html b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.html index 9dc7ed70a1..c0e9959363 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.html +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.html @@ -74,6 +74,8 @@ <adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" /> </mat-card-content> <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-container *ngFor="let outcome of form.outcomes"> <button diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.scss b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.scss index cd24d4da22..46da9db344 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.scss @@ -18,6 +18,10 @@ flex-direction: column; display: flex; } + + .adf-card-actions-spacer { + flex: 1 1 auto; + } } &-fullscreen-container { diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts index 02e09d0b1d..47ae2e72b6 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts @@ -67,6 +67,7 @@ import { ProcessServiceCloudTestingModule } from '../../testing/process-service- import { TaskVariableCloud } from '../models/task-variable-cloud.model'; import { ProcessServicesCloudModule } from '../../process-services-cloud.module'; import { FormFieldValidator } from '../../../../../core/src/public-api'; +import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; const mockOauth2Auth: any = { oauth2Auth: { @@ -1191,6 +1192,64 @@ describe('FormCloudComponent', () => { 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', () => { it('should be able to set visibility conditions for Attach File widget', async () => { spyOn(formCloudService, 'getForm').and.returnValue(of(conditionalUploadWidgetsMock)); diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts index 6fca94124e..a916b888d2 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts @@ -67,6 +67,7 @@ import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; 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'); @@ -83,7 +84,8 @@ export const FORM_CLOUD_FIELD_VALIDATORS_TOKEN = new InjectionToken<FormFieldVal MatIconModule, ToolbarDividerComponent, ToolbarComponent, - A11yModule + A11yModule, + MatCheckboxModule ], providers: [FormCloudSpinnerService], templateUrl: './form-cloud.component.html', @@ -114,12 +116,18 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, @Input() data: TaskVariableCloud[]; - /** - * The available display configurations for the form - */ + /** The available display configurations for the form */ @Input() 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. */ @Output() formSaved = new EventEmitter<FormModel>(); @@ -148,6 +156,10 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, @Output() displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>(); + /** Emitted when the `Open next task` checkbox was toggled. */ + @Output() + nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>(); + protected subscriptions: Subscription[] = []; nodeId: string; formCloudRepresentationJSON: any; @@ -510,4 +522,8 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, this.fieldValidators = [...this.fieldValidators, ...injectedFieldValidators]; } } + + onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) { + this.nextTaskCheckboxCheckedChanged.emit(event); + } } diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json index 5bce112575..648aa975b1 100644 --- a/lib/process-services-cloud/src/lib/i18n/en.json +++ b/lib/process-services-cloud/src/lib/i18n/en.json @@ -379,7 +379,8 @@ "ERROR": { "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" - } + }, + "OPEN_NEXT_TASK": {"LABEL": "Open next task"} }, "ADF_CLOUD_FORM_COMPONENT": { "RETRIEVE_METADATA": "Autofill Form" diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.html b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.html index dda8f0df87..3224bfb896 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.html +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.html @@ -84,9 +84,13 @@ [showRefreshButton]="false" [showValidationIcon]="false" [showTitle]="false" + [showNextTaskCheckbox]="showNextTaskCheckbox" + [isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked" (formContentClicked)="onFormContentClicked($event)" (formLoaded)="onFormLoaded($event)" - (executeOutcome)="onCustomOutcomeClicked($event.outcome.name)"> + (executeOutcome)="onCustomOutcomeClicked($event.outcome.name)" + (nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)" + > <adf-cloud-form-custom-outcomes> <ng-template [ngTemplateOutlet]="taskFormCloudButtons" /> </adf-cloud-form-custom-outcomes> diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts index ec1b994b3e..8055d93d7e 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts @@ -53,6 +53,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatOptionModule } from '@angular/material/core'; import { FormCloudComponent } from '../../../form/components/form-cloud.component'; import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component'; +import { MatCheckboxChange } from '@angular/material/checkbox'; const MAX_NAME_LENGTH: number = 255; const PROCESS_DEFINITION_DEBOUNCE: number = 300; @@ -131,6 +132,14 @@ export class StartProcessCloudComponent implements OnChanges, OnInit { @Input() 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. */ @Output() success = new EventEmitter<ProcessInstanceCloud>(); @@ -151,6 +160,10 @@ export class StartProcessCloudComponent implements OnChanges, OnInit { @Output() processDefinitionSelection: EventEmitter<ProcessDefinitionCloud> = new EventEmitter<ProcessDefinitionCloud>(); + /** Emitted when the `Open next task` checkbox was toggled. */ + @Output() + nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>(); + processDefinitionList: ProcessDefinitionCloud[] = []; processDefinitionCurrent?: ProcessDefinitionCloud; errorMessageId: string = ''; @@ -541,4 +554,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit { } return processName; } + + onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) { + this.nextTaskCheckboxCheckedChanged.emit(event); + } } diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.html index 8aa9e99bf5..284027f8ec 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.html @@ -12,6 +12,8 @@ [showCompleteButton]="canCompleteTask()" [showSaveButton]="canCompleteTask()" [displayModeConfigurations]="displayModeConfigurations" + [showNextTaskCheckbox]="showNextTaskCheckbox" + [isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked" (formSaved)="onFormSaved($event)" (formCompleted)="onFormCompleted($event)" (formError)="onError($event)" @@ -20,6 +22,7 @@ (executeOutcome)="onFormExecuteOutcome($event)" (displayModeOn)="onDisplayModeOn($event)" (displayModeOff)="onDisplayModeOff($event)" + (nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)" > <adf-cloud-form-custom-outcomes> <adf-cloud-user-task-cloud-buttons diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts index 913286f21e..6de6015195 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts @@ -27,6 +27,7 @@ import { TaskDetailsCloudModel } from '../../../models/task-details-cloud.model' import { CommonModule } from '@angular/common'; import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component'; import { FormCustomOutcomesComponent } from '../../../../form/components/form-cloud-custom-outcomes.component'; +import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ selector: 'adf-cloud-task-form', @@ -87,6 +88,14 @@ export class TaskFormCloudComponent { @Input() 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. */ @Output() formSaved = new EventEmitter<FormModel>(); @@ -134,6 +143,10 @@ export class TaskFormCloudComponent { @Output() displayModeOff = new EventEmitter<FormCloudDisplayModeConfiguration>(); + /** Emitted when the `Open next task` checkbox was toggled. */ + @Output() + nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>(); + @ViewChild('adfCloudForm', { static: false }) adfCloudForm: FormCloudComponent; @@ -225,4 +238,8 @@ export class TaskFormCloudComponent { onDisplayModeOff(displayModeConfiguration: FormCloudDisplayModeConfiguration) { this.displayModeOff.emit(displayModeConfiguration); } + + onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) { + this.nextTaskCheckboxCheckedChanged.emit(event); + } } diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.html index 99a1049039..f910790485 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.html @@ -12,6 +12,8 @@ [showTitle]="showTitle" [taskId]="taskId" [taskDetails]="taskDetails" + [showNextTaskCheckbox]="showNextTaskCheckbox" + [isNextTaskCheckboxChecked]="isNextTaskCheckboxChecked" (cancelClick)="onCancelForm()" (executeOutcome)="onExecuteOutcome($event)" (error)="onError($event)" @@ -20,6 +22,7 @@ (taskCompleted)="onCompleteTaskForm()" (taskClaimed)="onClaimTask()" (taskUnclaimed)="onTaskUnclaimed()" + (nextTaskCheckboxCheckedChanged)="onNextTaskCheckboxCheckedChanged($event)" /> </ng-container> @@ -63,6 +66,8 @@ [subtitle]="'ADF_CLOUD_TASK_FORM.EMPTY_FORM.SUBTITLE'" /> </mat-card-content> <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" /> <button *ngIf="canCompleteTask()" diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.scss b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.scss index 0878f3b860..f1edffbbfb 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.scss @@ -4,6 +4,10 @@ > div { height: 100%; } + + .adf-card-actions-spacer { + flex: 1 1 auto; + } } .adf-user-task-cloud-spinner { diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.spec.ts index 8b1f86e88c..bcaba9c77c 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.spec.ts @@ -36,6 +36,8 @@ import { ProcessServiceCloudTestingModule } from 'lib/process-services-cloud/src import { of, throwError } from 'rxjs'; import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { UserTaskCloudComponent } from './user-task-cloud.component'; +import { By } from '@angular/platform-browser'; +import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; const taskDetails: TaskDetailsCloudModel = { appName: 'simple-app', @@ -476,4 +478,61 @@ describe('UserTaskCloudComponent', () => { const noFormTemplateTitleText = await matCard.getTitleText(); 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(); + }); }); diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.ts index 6528d59945..9008d26d8a 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.ts @@ -31,6 +31,7 @@ import { MatCardModule } from '@angular/material/card'; import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component'; import { CompleteTaskDirective } from './complete-task/complete-task.directive'; import { catchError, EMPTY, forkJoin } from 'rxjs'; +import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox'; const TaskTypes = { Form: 'form', @@ -53,7 +54,8 @@ type TaskTypesType = (typeof TaskTypes)[keyof typeof TaskTypes]; EmptyContentComponent, TaskScreenCloudComponent, TaskFormCloudComponent, - CompleteTaskDirective + CompleteTaskDirective, + MatCheckboxModule ], templateUrl: './user-task-cloud.component.html', styleUrls: ['./user-task-cloud.component.scss'] @@ -85,6 +87,14 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { @Input() 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. */ @Input() showTitle: boolean = true; @@ -105,6 +115,10 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { @Output() 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 * via `event.preventDefault()`. @@ -182,15 +196,19 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { } getTaskType(): void { - if (this.taskDetails && !!this.taskDetails.formKey && this.taskDetails.formKey.includes(this.taskTypeEnum.Form)) { - this.taskType = this.taskTypeEnum.Form; - } else if (this.taskDetails && !!this.taskDetails.formKey && this.taskDetails.formKey.includes(this.taskTypeEnum.Screen)) { - this.taskType = this.taskTypeEnum.Screen; - const screenId = this.taskDetails.formKey.replace(this.taskTypeEnum.Screen + '-', ''); - this.screenId = screenId; - } else { - this.taskType = this.taskTypeEnum.None; + if (this.taskDetails && !!this.taskDetails.formKey) { + if (this.taskDetails.formKey.includes(this.taskTypeEnum.Form)) { + this.taskType = this.taskTypeEnum.Form; + return; + } else if (this.taskDetails.formKey.includes(this.taskTypeEnum.Screen)) { + this.taskType = this.taskTypeEnum.Screen; + const screenId = this.taskDetails.formKey.replace(this.taskTypeEnum.Screen + '-', ''); + this.screenId = screenId; + return; + } } + + this.taskType = this.taskTypeEnum.None; } hasCandidateUsers(): boolean { @@ -250,6 +268,10 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { this.taskUnclaimed.emit(this.taskId); } + onNextTaskCheckboxCheckedChanged(event: MatCheckboxChange) { + this.nextTaskCheckboxCheckedChanged.emit(event); + } + private loadTask(): void { this.loading = true; const tasks$ = this.taskCloudService.getTaskById(this.appName, this.taskId);