From 8e3bd154ed5ca3576c41d808f6c3882c8daa41a5 Mon Sep 17 00:00:00 2001 From: tomasz hanaj <12088991+tomaszhanaj@users.noreply.github.com> Date: Wed, 5 Feb 2025 15:18:11 +0100 Subject: [PATCH] AAE-30336 Screens updates (#10619) * [AAE-30336] updated interface and removed buttons * [AAE-30336] added fullscreen support for dynamic component * [AAE-30336] fullscreen feature and css fix * [AAE-30336] fixed wrong subscription, removed obsolete code * [AAE-30336] removed obsolete variable * [AAE-30336] updated unit test and model * [AAE-30336] updated documentation and comments --- .../components/screen-cloud.component.md | 108 ++++++++++++++++++ .../user-task-cloud-buttons.component.md | 51 +++++++++ .../components/user-task-cloud.component.md | 103 +++++++++++++++++ .../screen-cloud/screen-cloud.component.html | 7 +- .../screen-cloud.component.spec.ts | 38 +++--- .../screen-cloud/screen-cloud.component.ts | 65 ++++++++++- .../screen-cloud.model.ts} | 11 +- .../src/lib/screen/public-api.ts | 18 +++ .../user-task-cloud-buttons.component.ts | 2 + .../user-task-cloud.component.html | 19 +-- .../user-task-cloud.component.ts | 6 + lib/process-services-cloud/src/public-api.ts | 1 + 12 files changed, 397 insertions(+), 32 deletions(-) create mode 100644 docs/process-services-cloud/components/screen-cloud.component.md create mode 100644 docs/process-services-cloud/components/user-task-cloud-buttons.component.md create mode 100644 docs/process-services-cloud/components/user-task-cloud.component.md rename lib/process-services-cloud/src/lib/screen/{components/screen-cloud/screen-cloud.interface.ts => models/screen-cloud.model.ts} (79%) create mode 100644 lib/process-services-cloud/src/lib/screen/public-api.ts diff --git a/docs/process-services-cloud/components/screen-cloud.component.md b/docs/process-services-cloud/components/screen-cloud.component.md new file mode 100644 index 0000000000..845cf71a47 --- /dev/null +++ b/docs/process-services-cloud/components/screen-cloud.component.md @@ -0,0 +1,108 @@ +--- +Title: Screen Cloud Component +Added: 2025-02-05 +Status: Active +Last reviewed: 2025-02-05 +--- + +# Screen Cloud Component + +Provides space for a dynamic component. Dynamic component should implement interface UserTaskCustomUi. +Dynamic component must be registered with service that extends ScreenRenderingService. Key for component +is a string taken from property formKey stored in xml. In component this value is stored in property screenId. +To register component use method register, example: + +```typescript +import { ScreenRenderingService } from '@alfresco/adf-process-services-cloud'; + +export class YourService extends ScreenRenderingService { + + constructor() { + super(); + this.register( + { + [formKeyThatIdentifiesDynamicComponent]: () => DynamicComponent + }, + true + ); + } +} +``` + +## Basic Usage + +```html + +``` + +## Class members + +### Properties + +| Name | Type | Default value | Description | +|---------------------------|---------------------------------------|---------------|---------------------------------------------------| +| appName | `string` | "" | App id to fetch corresponding form and values. | +| canClaimTask | `boolean` | | Boolean informing if a task can be claimed. | +| canUnclaimTask | `boolean` | | Boolean informing if a task can be unclaimed. | +| processInstanceId | `string` | | Process Instance Id to fetch corresponding data. | +| readOnly | `boolean` | false | Toggle readonly state of the task. | +| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | +| screenId | `string` | | Screen id to create dynamic component | +| taskId | `string` | | Task id to fetch corresponding form and values. | +| taskName | `string` | | Name of the task. | + + +### Events + +| Name | Type | Description | +|--------------------|------------------------|--------------------------------------------| +| cancelTask | `EventEmitter` | Emitted when the task is cancelled. | +| error | `EventEmitter` | Emitted when any error occurs. | +| taskSaved | `EventEmitter` | Emitted when the task is saved. | +| claimTask | `EventEmitter` | Emitted when the task is claimed. | +| taskCompleted | `EventEmitter` | Emitted when the task is completed. | +| unclaimTask | `EventEmitter` | Emitted when the task is unclaimed. | + + +#### Enabling fullscreen display for the dynamic component + +Dynamic component must implement logic for method switchToDisplayMode. + +**MyView.component.html** + +```html + + + +``` diff --git a/docs/process-services-cloud/components/user-task-cloud-buttons.component.md b/docs/process-services-cloud/components/user-task-cloud-buttons.component.md new file mode 100644 index 0000000000..18940ff085 --- /dev/null +++ b/docs/process-services-cloud/components/user-task-cloud-buttons.component.md @@ -0,0 +1,51 @@ +--- +Title: User Task Cloud Buttons Component +Added: 2025-02-05 +Status: Active +Last reviewed: 2025-02-05 +--- + +# User Task Cloud Buttons Component + +Provides reusable component with buttons related to tasks. It contains three buttons: cancel, claim, unclaim. +Visibility of each button is controlled by input property. + +## Basic Usage + +```html + +``` + +## Class members + +### Properties + +| Name | Type | Default value | Description | +|---------------------------|---------------------------------------|---------------|---------------------------------------------------| +| appName | `string` | "" | App id to fetch corresponding form and values. | +| canClaimTask | `boolean` | | Boolean informing if a task can be claimed. | +| canUnclaimTask | `boolean` | | Boolean informing if a task can be unclaimed. | +| taskId | `string` | | Task id to fetch corresponding form and values. | +| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. | + + +### Events + +| Name | Type | Description | +|--------------------|------------------------|--------------------------------------------| +| cancelClick | `EventEmitter` | Emitted when the task is cancelled. | +| error | `EventEmitter` | Emitted when any error occurs. | +| claimTask | `EventEmitter` | Emitted when the task is claimed. | +| unclaimTask | `EventEmitter` | Emitted when the task is unclaimed. | + + diff --git a/docs/process-services-cloud/components/user-task-cloud.component.md b/docs/process-services-cloud/components/user-task-cloud.component.md new file mode 100644 index 0000000000..a3d5e89f5a --- /dev/null +++ b/docs/process-services-cloud/components/user-task-cloud.component.md @@ -0,0 +1,103 @@ +--- +Title: User Task Cloud Component +Added: 2025-02-05 +Status: Active +Last reviewed: 2025-02-05 +--- + +# User Task Cloud Component + +Based on property taskDetails: TaskDetailsCloudModel shows a form or a screen. + +## Basic Usage + +```html + +``` + +## Class members + +### 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. | +| fieldValidators | `FormFieldValidator[]` | | Allows to provide additional validators to the form field. | +| 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 | + +### Events + +| Name | Type | Description | +|--------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| cancelClick | `EventEmitter` | Emitted when the cancel button is clicked. | +| error | `EventEmitter` | Emitted when any error occurs. | +| executeOutcome | `EventEmitter` | Emitted when any outcome is executed. Default behaviour can be prevented via `event.preventDefault()`. | +| formContentClicked | `EventEmitter` | Emitted when form content is clicked. | +| formSaved | `EventEmitter` | Emitted when the form is saved. | +| onTaskLoaded | `EventEmitter` | Emitted when a task is loaded. | +| taskClaimed | `EventEmitter` | Emitted when the task is claimed. | +| taskCompleted | `EventEmitter` | Emitted when the task is completed. | +| taskUnclaimed | `EventEmitter` | Emitted when the task is unclaimed. | + | + +#### Enabling fullscreen display for the form of the task + +Provide a `displayModeConfiguration` array object containing the fullscreen configuration. You can use the configuration provided in the [`DisplayModeService`](../../../lib/process-services-cloud/src/lib/form/services/display-mode.service.ts) as a static member `DisplayModeService.IMPLEMENTED_DISPLAY_MODE_CONFIGURATIONS`, or configure your own if you want to customise the options for the fullscreen display mode. + +**MyView.component.html** + +```html + + + + +``` + +**MyView.component.ts** + +```ts +import { DisplayModeService } from '@alfresco/adf-process-services-cloud'; + +export class MyView { + + get displayConfigurations() { + return DisplayModeService.IMPLEMENTED_DISPLAY_MODE_CONFIGURATIONS; + } + +} +``` + +When the `displayModeConfigurations` contains the configuration for the fullscreen display, in the header of the form, a button to switch to fullscreen is displayed. Keep in mind that the header of the form is visible only if any of the parameters `showTitle`, `showRefreshButton`or `showValidationIcon` is `true`, but it is also possible to switch to the fullscreen display using a button that you can place wherever you want as shown in the previous example. + +## See also + +- [Form component](./form-cloud.component.md) +- [Form field model](../../core/models/form-field.model.md) +- [Form cloud service](../services/form-cloud.service.md) diff --git a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.html b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.html index 9da96ce9ae..fc5e43296f 100644 --- a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.html +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.html @@ -1,8 +1,5 @@ - -
+ + - - -
diff --git a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.spec.ts index f8693b68e7..e0ec11d45a 100644 --- a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.spec.ts @@ -17,7 +17,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CommonModule } from '@angular/common'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { By } from '@angular/platform-browser'; import { ScreenRenderingService } from '../../../services/public-api'; import { TaskScreenCloudComponent } from './screen-cloud.component'; @@ -36,37 +36,45 @@ import { TaskScreenCloudComponent } from './screen-cloud.component'; }) class TestComponent { @Input() taskId = ''; + @Input() screenId = ''; @Output() taskCompleted = new EventEmitter(); + displayMode: string; onComplete() { this.taskCompleted.emit(); } + switchToDisplayMode(newDisplayMode?: string) { + this.displayMode = newDisplayMode; + } } @Component({ selector: 'adf-cloud-test-actions-component', - template: ` - -
- -
-
- `, + template: ` `, imports: [CommonModule, TaskScreenCloudComponent], standalone: true }) class TestWrapperComponent { + @Input() screenId = ''; + @ViewChild('adfCloudTaskScreen') adfCloudTaskScreen: TaskScreenCloudComponent; onTaskCompleted() {} + switchToDisplayMode(newDisplayMode?: string): void { + if (this.adfCloudTaskScreen) { + this.adfCloudTaskScreen.switchToDisplayMode(newDisplayMode); + } + } } describe('TaskScreenCloudComponent', () => { let fixture: ComponentFixture; let screenRenderingService: ScreenRenderingService; + let component: TestWrapperComponent; beforeEach(() => { TestBed.configureTestingModule({ imports: [TaskScreenCloudComponent, TestComponent, TestWrapperComponent] }); fixture = TestBed.createComponent(TestWrapperComponent); + component = fixture.componentInstance; screenRenderingService = TestBed.inject(ScreenRenderingService); screenRenderingService.register({ ['test']: () => TestComponent }); fixture.componentRef.setInput('screenId', 'test'); @@ -78,11 +86,6 @@ describe('TaskScreenCloudComponent', () => { expect(dynamicComponent).toBeTruthy(); }); - it('should project content into component', async () => { - const projectedContent = fixture.debugElement.query(By.css('.adf-cloud-test-buttons')); - expect(projectedContent).toBeTruthy(); - }); - it('should set input property for dynamic component', () => { const inputValueFromDynamicComponent = fixture.debugElement.query(By.css('.adf-cloud-test-container-taskId')); expect((inputValueFromDynamicComponent.nativeElement as HTMLElement).textContent).toBe('1'); @@ -97,4 +100,13 @@ describe('TaskScreenCloudComponent', () => { (btnComplete.nativeElement as HTMLButtonElement).click(); expect(onTaskCompletedSpy).toHaveBeenCalled(); }); + + it('should call switchToDisplayMode on dynamic component', () => { + const taskScreenCloudComponentSpy = jasmine.createSpyObj('TaskScreenCloudComponent', ['switchToDisplayMode']); + component.adfCloudTaskScreen = taskScreenCloudComponentSpy; + component.switchToDisplayMode(); + fixture.detectChanges(); + + expect(component.adfCloudTaskScreen.switchToDisplayMode).toHaveBeenCalled(); + }); }); diff --git a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.ts b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.ts index dbe540a9a4..31a5758045 100644 --- a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.ts @@ -19,7 +19,7 @@ import { CommonModule } from '@angular/common'; import { Component, ComponentRef, DestroyRef, EventEmitter, inject, Input, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core'; import { ScreenRenderingService } from '../../../services/public-api'; import { MatCardModule } from '@angular/material/card'; -import { UserTaskCustomUi } from './screen-cloud.interface'; +import { UserTaskCustomUi } from '../../models/screen-cloud.model'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ @@ -30,17 +30,36 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; }) export class TaskScreenCloudComponent implements OnInit { /** Task id to fetch corresponding form and values. */ - @Input() taskId: string; - /** App id to fetch corresponding form and values. */ + @Input() + taskId: string; + + /** App name to fetch data for dynamic component. */ @Input() appName: string = ''; - /** Screen id to fetch corresponding screen widget. */ + + /** Boolean informing if a task can be claimed. */ + @Input() + canClaimTask: boolean; + + /** Boolean informing if a task can be unclaimed. */ + @Input() + canUnclaimTask: boolean; + + @Input() + showCancelButton: boolean; + + /** Screen id to create dynamic component. */ @Input() screenId: string = ''; + + /** Process Instance Id to fetch corresponding data. */ @Input() processInstanceId: string = ''; + + /** Name of the task. */ @Input() taskName: string = ''; + /** Toggle readonly state of the task. */ @Input() readOnly = false; @@ -57,12 +76,23 @@ export class TaskScreenCloudComponent implements OnInit { @Output() error = new EventEmitter(); + /** Emitted when the task is cancelled. */ + @Output() + cancelTask = new EventEmitter(); + + /** Emitted when the task is claimed. */ + @Output() + claimTask = new EventEmitter(); + + /** Emitted when the task is unclaimed. */ + @Output() + unclaimTask = new EventEmitter(); + @ViewChild('container', { read: ViewContainerRef, static: true }) container: ViewContainerRef; private destroyRef = inject(DestroyRef); componentRef: ComponentRef; - private readonly screenRenderingService = inject(ScreenRenderingService); ngOnInit() { @@ -94,6 +124,15 @@ export class TaskScreenCloudComponent implements OnInit { if (this.taskName && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'taskName')) { this.componentRef.setInput('taskName', this.taskName); } + if (this.canClaimTask && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'canClaimTask')) { + this.componentRef.setInput('canClaimTask', this.canClaimTask); + } + if (this.canUnclaimTask && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'canUnclaimTask')) { + this.componentRef.setInput('canUnclaimTask', this.canUnclaimTask); + } + if (this.showCancelButton && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'showCancelButton')) { + this.componentRef.setInput('showCancelButton', this.showCancelButton); + } } subscribeToOutputs() { @@ -106,5 +145,21 @@ export class TaskScreenCloudComponent implements OnInit { if (this.componentRef.instance?.error) { this.componentRef.instance.error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.error.emit(data)); } + + if (this.componentRef.instance?.claimTask) { + this.componentRef.instance.claimTask.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.claimTask.emit(data)); + } + if (this.componentRef.instance?.unclaimTask) { + this.componentRef.instance.unclaimTask.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.unclaimTask.emit(data)); + } + if (this.componentRef.instance?.cancelTask) { + this.componentRef.instance.cancelTask.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.cancelTask.emit(data)); + } + } + + switchToDisplayMode(newDisplayMode?: string) { + if (this.componentRef?.instance?.switchToDisplayMode) { + this.componentRef.instance.switchToDisplayMode(newDisplayMode); + } } } diff --git a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.interface.ts b/lib/process-services-cloud/src/lib/screen/models/screen-cloud.model.ts similarity index 79% rename from lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.interface.ts rename to lib/process-services-cloud/src/lib/screen/models/screen-cloud.model.ts index ab095f013d..3191303287 100644 --- a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.interface.ts +++ b/lib/process-services-cloud/src/lib/screen/models/screen-cloud.model.ts @@ -18,12 +18,19 @@ import { EventEmitter } from '@angular/core'; export interface UserTaskCustomUi { + appName: string; + canClaimTask: boolean; + canUnclaimTask: boolean; processInstanceId: string; taskName: string; - appName: string; taskId: string; screenId: string; + showCancelButton: boolean; + cancelTask: EventEmitter; + claimTask: EventEmitter; + error: EventEmitter; + switchToDisplayMode?: (newDisplayMode?: string) => void; taskCompleted: EventEmitter; taskSaved: EventEmitter; - error: EventEmitter; + unclaimTask: EventEmitter; } diff --git a/lib/process-services-cloud/src/lib/screen/public-api.ts b/lib/process-services-cloud/src/lib/screen/public-api.ts new file mode 100644 index 0000000000..4606418f3b --- /dev/null +++ b/lib/process-services-cloud/src/lib/screen/public-api.ts @@ -0,0 +1,18 @@ +/*! + * @license + * Copyright © 2005-2024 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. + */ + +export * from './models/screen-cloud.model'; diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.ts index 799ae4d189..f0eb53a636 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.ts @@ -34,9 +34,11 @@ export class UserTaskCloudButtonsComponent { @Input() appName: string = ''; + /** Boolean informing if a task can be claimed. */ @Input() canClaimTask: boolean; + /** Boolean informing if a task can be unclaimed. */ @Input() canUnclaimTask: boolean; 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 8d2cc4717e..5b8d0da533 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 @@ -26,18 +26,23 @@ - - - + (unclaimTask)="onUnclaimTask()" + /> 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 b4a175d817..daa8f15762 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 @@ -61,6 +61,9 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { @ViewChild('adfCloudTaskForm') adfCloudTaskForm: TaskFormCloudComponent; + @ViewChild('adfCloudTaskScreen') + adfCloudTaskScreen: TaskScreenCloudComponent; + /** App id to fetch corresponding form and values. */ @Input() appName: string = ''; @@ -270,5 +273,8 @@ export class UserTaskCloudComponent implements OnInit, OnChanges { if (this.adfCloudTaskForm) { this.adfCloudTaskForm.switchToDisplayMode(newDisplayMode); } + if (this.adfCloudTaskScreen) { + this.adfCloudTaskScreen.switchToDisplayMode(newDisplayMode); + } } } diff --git a/lib/process-services-cloud/src/public-api.ts b/lib/process-services-cloud/src/public-api.ts index c6f74cffcb..6beb04029e 100644 --- a/lib/process-services-cloud/src/public-api.ts +++ b/lib/process-services-cloud/src/public-api.ts @@ -24,6 +24,7 @@ export * from './lib/people/public-api'; export * from './lib/form/public-api'; export * from './lib/services/public-api'; export * from './lib/rich-text-editor/public-api'; +export * from './lib/screen/public-api'; export * from './lib/types'; export * from './lib/common/index';