diff --git a/lib/core/src/lib/form/public-api.ts b/lib/core/src/lib/form/public-api.ts index ba1d920878..e89e9fb064 100644 --- a/lib/core/src/lib/form/public-api.ts +++ b/lib/core/src/lib/form/public-api.ts @@ -28,6 +28,7 @@ export * from './services/form-rendering.service'; export * from './services/form.service'; export * from './services/form-validation-service.interface'; export * from './services/widget-visibility.service'; +export * from './services/screen-rendering.service'; export * from './pipes'; diff --git a/lib/core/src/lib/form/services/screen-rendering.service.spec.ts b/lib/core/src/lib/form/services/screen-rendering.service.spec.ts new file mode 100644 index 0000000000..d3a2e89cde --- /dev/null +++ b/lib/core/src/lib/form/services/screen-rendering.service.spec.ts @@ -0,0 +1,33 @@ +/*! + * @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. + */ + +import { TestBed } from '@angular/core/testing'; + +import { ScreenRenderingService } from './screen-rendering.service'; + +describe('ScreenRenderingService', () => { + let service: ScreenRenderingService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ScreenRenderingService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/lib/core/src/lib/form/services/screen-rendering.service.ts b/lib/core/src/lib/form/services/screen-rendering.service.ts new file mode 100644 index 0000000000..593ac83c80 --- /dev/null +++ b/lib/core/src/lib/form/services/screen-rendering.service.ts @@ -0,0 +1,24 @@ +/*! + * @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. + */ + +import { Injectable } from '@angular/core'; +import { DynamicComponentMapper } from '../../common/services/dynamic-component-mapper.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ScreenRenderingService extends DynamicComponentMapper {} 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 new file mode 100644 index 0000000000..3e609e3baa --- /dev/null +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.scss b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.scss new file mode 100644 index 0000000000..d16f66ad28 --- /dev/null +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.scss @@ -0,0 +1,3 @@ +div { + background-color: inherit; +} 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 new file mode 100644 index 0000000000..c9dc04ae55 --- /dev/null +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.spec.ts @@ -0,0 +1,38 @@ +/*! + * @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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ScreenCloudComponent } from './screen-cloud.component'; + +describe('ScreenCloudComponent', () => { + let component: ScreenCloudComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ScreenCloudComponent] + }); + fixture = TestBed.createComponent(ScreenCloudComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000..e50e0e8274 --- /dev/null +++ b/lib/process-services-cloud/src/lib/screen/components/screen-cloud/screen-cloud.component.ts @@ -0,0 +1,51 @@ +/*! + * @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. + */ + +// FormRenderingService, +import { DynamicComponentModel, ScreenRenderingService } from '@alfresco/adf-core'; +import { CommonModule } from '@angular/common'; +import { Component, ComponentRef, inject, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; + +@Component({ + selector: 'adf-cloud-screen-cloud', + standalone: true, + imports: [CommonModule], + templateUrl: './screen-cloud.component.html', + styleUrls: ['./screen-cloud.component.scss'] +}) +export class ScreenCloudComponent implements OnInit { + /** Task id to fetch corresponding form and values. */ + @Input() taskId: string; + /** App id to fetch corresponding form and values. */ + @Input() + appName: string = ''; + /** Toggle readonly state of the task. */ + @Input() + readOnly = false; + + @ViewChild('container', { read: ViewContainerRef, static: true }) + container: ViewContainerRef; + screenComponent: DynamicComponentModel = { type: 'screen-one' }; + componentRef: ComponentRef; + + private readonly screenRenderingService = inject(ScreenRenderingService); + + ngOnInit() { + const componentType = this.screenRenderingService.resolveComponentType(this.screenComponent); + this.componentRef = this.container.createComponent(componentType); + } +} diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html deleted file mode 100644 index 05a1d24464..0000000000 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html +++ /dev/null @@ -1,73 +0,0 @@ -
- - - - - - - - - - - -

- - {{ taskDetails?.name || 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }} - -

-
-
- - - - - - - - -
-
- - - - - -
- - - - 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 new file mode 100644 index 0000000000..3692ce7d20 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.html @@ -0,0 +1,42 @@ +
+ + + + + + + + + + + +
diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.scss b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.scss similarity index 67% rename from lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.scss rename to lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.scss index 80e7995fcc..3ed0885212 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.scss @@ -29,23 +29,4 @@ } } } - - &-cloud-spinner { - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } -} - -adf-cloud-task-form { - .adf-task-form-cloud-spinner { - display: flex; - justify-content: center; - align-items: center; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - overflow: hidden; - } } diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.spec.ts similarity index 97% rename from lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts rename to lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.spec.ts index cbba6d6888..d383a0f7b3 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.spec.ts @@ -20,7 +20,7 @@ import { By } from '@angular/platform-browser'; import { of } from 'rxjs'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FORM_FIELD_VALIDATORS, FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core'; -import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; +import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { TaskFormCloudComponent } from './task-form-cloud.component'; import { TaskDetailsCloudModel, @@ -29,15 +29,15 @@ import { TASK_CREATED_STATE, TASK_RELEASE_PERMISSION, TASK_VIEW_PERMISSION -} from '../../start-task/models/task-details-cloud.model'; -import { TaskCloudService } from '../../services/task-cloud.service'; -import { IdentityUserService } from '../../../people/services/identity-user.service'; +} from '../../../start-task/models/task-details-cloud.model'; +import { TaskCloudService } from '../../../services/task-cloud.service'; +import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; -import { DisplayModeService } from '../../../form/services/display-mode.service'; -import { FormCloudComponent } from '../../../form/components/form-cloud.component'; -import { MockFormFieldValidator } from '../mocks/task-form-cloud.mock'; +import { DisplayModeService } from '../../../../form/services/display-mode.service'; +import { FormCloudComponent } from '../../../../form/components/form-cloud.component'; +import { MockFormFieldValidator } from '../../mocks/task-form-cloud.mock'; const taskDetails: TaskDetailsCloudModel = { appName: 'simple-app', diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.stories.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.stories.ts similarity index 91% rename from lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.stories.ts rename to lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.stories.ts index e1d34d1ebc..91f657f5c4 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.stories.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.stories.ts @@ -16,13 +16,13 @@ */ import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; -import { FormCloudService } from '../../../form/public-api'; -import { TaskCloudService } from '../../services/task-cloud.service'; -import { TaskFormModule } from '../task-form.module'; +import { FormCloudService } from '../../../../form/public-api'; +import { TaskCloudService } from '../../../services/task-cloud.service'; +import { TaskFormModule } from '../../task-form.module'; import { TaskFormCloudComponent } from './task-form-cloud.component'; -import { TaskCloudServiceMock } from '../../mock/task-cloud.service.mock'; -import { FormCloudServiceMock } from '../../../form/mocks/form-cloud.service.mock'; -import { ProcessServicesCloudStoryModule } from '../../../testing/process-services-cloud-story.module'; +import { TaskCloudServiceMock } from '../../../mock/task-cloud.service.mock'; +import { FormCloudServiceMock } from '../../../../form/mocks/form-cloud.service.mock'; +import { ProcessServicesCloudStoryModule } from '../../../../testing/process-services-cloud-story.module'; import { importProvidersFrom } from '@angular/core'; export default { @@ -37,9 +37,7 @@ export default { ] }), applicationConfig({ - providers: [ - importProvidersFrom(ProcessServicesCloudStoryModule) - ] + providers: [importProvidersFrom(ProcessServicesCloudStoryModule)] }) ], argTypes: { diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts similarity index 73% rename from lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts rename to lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts index fbf86f0384..8c4c3bb700 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud/task-form-cloud.component.ts @@ -15,28 +15,15 @@ * limitations under the License. */ -import { - Component, - DestroyRef, - EventEmitter, - inject, - Input, - OnChanges, - OnInit, - Output, - SimpleChanges, - ViewChild, - ViewEncapsulation -} from '@angular/core'; -import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model'; -import { TaskCloudService } from '../../services/task-cloud.service'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; +import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model'; +import { TaskCloudService } from '../../../services/task-cloud.service'; import { ContentLinkModel, FORM_FIELD_VALIDATORS, FormFieldValidator, FormModel, FormOutcomeEvent, FormRenderingService } from '@alfresco/adf-core'; -import { AttachFileCloudWidgetComponent } from '../../../form/components/widgets/attach-file/attach-file-cloud-widget.component'; -import { DropdownCloudWidgetComponent } from '../../../form/components/widgets/dropdown/dropdown-cloud.widget'; -import { DateCloudWidgetComponent } from '../../../form/components/widgets/date/date-cloud.widget'; -import { FormCloudDisplayModeConfiguration } from '../../../services/form-fields.interfaces'; -import { FormCloudComponent } from '../../../form/components/form-cloud.component'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { AttachFileCloudWidgetComponent } from '../../../../form/components/widgets/attach-file/attach-file-cloud-widget.component'; +import { DropdownCloudWidgetComponent } from '../../../../form/components/widgets/dropdown/dropdown-cloud.widget'; +import { DateCloudWidgetComponent } from '../../../../form/components/widgets/date/date-cloud.widget'; +import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces'; +import { FormCloudComponent } from '../../../../form/components/form-cloud.component'; @Component({ selector: 'adf-cloud-task-form', @@ -44,11 +31,17 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; styleUrls: ['./task-form-cloud.component.scss'], encapsulation: ViewEncapsulation.None }) -export class TaskFormCloudComponent implements OnInit, OnChanges { +export class TaskFormCloudComponent implements OnInit { /** App id to fetch corresponding form and values. */ @Input() appName: string = ''; + /**Candidates user and groups */ + @Input() + candidateUsers: string[] = []; + @Input() + candidateGroups: string[] = []; + /** Task id to fetch corresponding form and values. */ @Input() taskId: string; @@ -87,6 +80,10 @@ export class TaskFormCloudComponent implements OnInit, OnChanges { @Input() fieldValidators: FormFieldValidator[]; + /** Task details. */ + @Input() + taskDetails: TaskDetailsCloudModel; + /** Emitted when the form is saved. */ @Output() formSaved = new EventEmitter(); @@ -126,12 +123,6 @@ export class TaskFormCloudComponent implements OnInit, OnChanges { @Output() executeOutcome = new EventEmitter(); - /** - * Emitted when a task is loaded`. - */ - @Output() - onTaskLoaded = new EventEmitter(); /* eslint-disable-line */ - /** Emitted when a display mode configuration is turned on. */ @Output() displayModeOn = new EventEmitter(); @@ -143,15 +134,8 @@ export class TaskFormCloudComponent implements OnInit, OnChanges { @ViewChild('adfCloudForm', { static: false }) adfCloudForm: FormCloudComponent; - taskDetails: TaskDetailsCloudModel; - - candidateUsers: string[] = []; - candidateGroups: string[] = []; - loading: boolean = false; - private readonly destroyRef = inject(DestroyRef); - constructor(private taskCloudService: TaskCloudService, private formRenderingService: FormRenderingService) { this.formRenderingService.setComponentTypeResolver('upload', () => AttachFileCloudWidgetComponent, true); this.formRenderingService.setComponentTypeResolver('dropdown', () => DropdownCloudWidgetComponent, true); @@ -160,46 +144,12 @@ export class TaskFormCloudComponent implements OnInit, OnChanges { ngOnInit() { this.initFieldValidators(); - - if (this.appName === '' && this.taskId) { - this.loadTask(); - } - } - - ngOnChanges(changes: SimpleChanges) { - const appName = changes['appName']; - if (appName && appName.currentValue !== appName.previousValue && this.taskId) { - this.loadTask(); - return; - } - - const taskId = changes['taskId']; - if (taskId?.currentValue && this.appName) { - this.loadTask(); - return; - } } private initFieldValidators() { this.fieldValidators = this.fieldValidators ? [...FORM_FIELD_VALIDATORS, ...this.fieldValidators] : [...FORM_FIELD_VALIDATORS]; } - private loadTask() { - this.loading = true; - this.taskCloudService - .getTaskById(this.appName, this.taskId) - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe((details) => { - this.taskDetails = details; - this.loading = false; - this.onTaskLoaded.emit(this.taskDetails); - }); - - this.taskCloudService.getCandidateUsers(this.appName, this.taskId).subscribe((users) => (this.candidateUsers = users || [])); - - this.taskCloudService.getCandidateGroups(this.appName, this.taskId).subscribe((groups) => (this.candidateGroups = groups || [])); - } - hasForm(): boolean { return this.taskDetails && !!this.taskDetails.formKey; } @@ -233,17 +183,14 @@ export class TaskFormCloudComponent implements OnInit, OnChanges { } onCompleteTask() { - this.loadTask(); this.taskCompleted.emit(this.taskId); } onClaimTask() { - this.loadTask(); this.taskClaimed.emit(this.taskId); } onUnclaimTask() { - this.loadTask(); this.taskUnclaimed.emit(this.taskId); } diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.html b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.html new file mode 100644 index 0000000000..f5821a8a76 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.html @@ -0,0 +1,27 @@ + + + diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.scss b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.scss new file mode 100644 index 0000000000..d16f66ad28 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.scss @@ -0,0 +1,3 @@ +div { + background-color: inherit; +} diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.spec.ts new file mode 100644 index 0000000000..306ca2ffc5 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.spec.ts @@ -0,0 +1,37 @@ +/*! + * @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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { UserTaskCloudButtonsComponent } from './user-task-cloud-buttons.component'; + +describe('UserTaskCloudButtonsComponent', () => { + let component: UserTaskCloudButtonsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [UserTaskCloudButtonsComponent] + }); + fixture = TestBed.createComponent(UserTaskCloudButtonsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000..c2b2850a73 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud-buttons/user-task-cloud-buttons.component.ts @@ -0,0 +1,71 @@ +/*! + * @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. + */ + +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'adf-cloud-user-task-cloud-buttons', + templateUrl: './user-task-cloud-buttons.component.html', + styleUrls: ['./user-task-cloud-buttons.component.scss'] +}) +export class UserTaskCloudButtonsComponent { + /** App id to fetch corresponding form and values. */ + @Input() + appName: string = ''; + + @Input() + canClaimTask: boolean; + + @Input() + canUnclaimTask: boolean; + + /** Task id to fetch corresponding form and values. */ + @Input() + taskId: string; + + /** Toggle rendering of the `Cancel` button. */ + @Input() + showCancelButton = true; + + /** Emitted when any error occurs. */ + @Output() error = new EventEmitter(); + + /** Emitted when the cancel button is clicked. */ + @Output() cancelClick = new EventEmitter(); + + /** Emitted when the task is claimed. */ + @Output() claimTask = new EventEmitter(); + + /** Emitted when the task is unclaimed. */ + @Output() unclaimTask = new EventEmitter(); + + onError(data: any): void { + this.error.emit(data); + } + + onUnclaimTask(): void { + this.unclaimTask.emit(); + } + + onClaimTask(): void { + this.claimTask.emit(); + } + + onCancelClick(): void { + this.cancelClick.emit(); + } +} 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 new file mode 100644 index 0000000000..384f0240d2 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.html @@ -0,0 +1,88 @@ +
+
+ + + + + + + + + + + + + + +

+ + {{ taskDetails?.name || 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }} + +

+
+
+ + + + + + + + +
+
+ +
+
+
+ + + + + + + + + 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 new file mode 100644 index 0000000000..a30d10d50e --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.scss @@ -0,0 +1,10 @@ +.adf-task-form-cloud-container { + width: 100%; + height: 100%; +} + +.adf-user-task-cloud-spinner { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} 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 new file mode 100644 index 0000000000..783ea62a73 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.spec.ts @@ -0,0 +1,37 @@ +/*! + * @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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { UserTaskCloudComponent } from './user-task-cloud.component'; + +describe('UserTaskCloudComponent', () => { + let component: UserTaskCloudComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [UserTaskCloudComponent] + }); + fixture = TestBed.createComponent(UserTaskCloudComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000..fdeb75e391 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.component.ts @@ -0,0 +1,250 @@ +/*! + * @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. + */ + +import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from '@alfresco/adf-core'; +import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces'; +import { TaskCloudService } from '../../../services/task-cloud.service'; +import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model'; +import { TaskFormCloudComponent } from '@alfresco/adf-process-services-cloud'; + +const TaskTypes = { + Form: 'form', + Screen: 'screen', + None: '' +} as const; + +type TaskTypesType = (typeof TaskTypes)[keyof typeof TaskTypes]; + +@Component({ + selector: 'adf-cloud-user-task', + templateUrl: './user-task-cloud.component.html', + styleUrls: ['./user-task-cloud.component.scss'] +}) +export class UserTaskCloudComponent implements OnInit, OnChanges { + @ViewChild('adfCloudTaskForm') + adfCloudTaskForm: TaskFormCloudComponent; + + /** App id to fetch corresponding form and values. */ + @Input() + appName: string = ''; + + /** The available display configurations for the form */ + @Input() + displayModeConfigurations: FormCloudDisplayModeConfiguration[]; + + /** FormFieldValidator allow to provide additional validators to the form field. */ + @Input() + fieldValidators: FormFieldValidator[]; + + /** Toggle readonly state of the task. */ + @Input() + readOnly = false; + + /** Toggle rendering of the `Cancel` button. */ + @Input() + showCancelButton = true; + + /** Toggle rendering of the `Complete` button. */ + @Input() + showCompleteButton = true; + + /** Toggle rendering of the form title. */ + @Input() + showTitle: boolean = true; + + /** Toggle rendering of the `Validation` icon. */ + @Input() + showValidationIcon = true; + + /** Task id to fetch corresponding form and values. */ + @Input() + taskId: string; + + /** Emitted when the cancel button is clicked. */ + @Output() + cancelClick = new EventEmitter(); + + /** Emitted when any error occurs. */ + @Output() + error = new EventEmitter(); + + /** + * Emitted when any outcome is executed. Default behaviour can be prevented + * via `event.preventDefault()`. + */ + @Output() + executeOutcome = new EventEmitter(); + + /** Emitted when form content is clicked. */ + @Output() + formContentClicked: EventEmitter = new EventEmitter(); + + /** Emitted when the form is saved. */ + @Output() + formSaved = new EventEmitter(); + + /** + * Emitted when a task is loaded`. + */ + @Output() + onTaskLoaded = new EventEmitter(); /* eslint-disable-line */ + + /** Emitted when the task is claimed. */ + @Output() + taskClaimed = new EventEmitter(); + + /** Emitted when the task is unclaimed. */ + @Output() + taskUnclaimed = new EventEmitter(); + + /** Emitted when the task is completed. */ + @Output() + taskCompleted = new EventEmitter(); + + candidateUsers: string[] = []; + candidateGroups: string[] = []; + loading: boolean = false; + taskDetails: TaskDetailsCloudModel; + taskType: TaskTypesType; + taskTypeEnum = TaskTypes; + + private taskCloudService: TaskCloudService = inject(TaskCloudService); + private readonly destroyRef = inject(DestroyRef); + + canClaimTask(): boolean { + return !this.readOnly && this.taskCloudService.canClaimTask(this.taskDetails) && this.hasCandidateUsersOrGroups(); + } + + canCompleteTask(): boolean { + return this.showCompleteButton && !this.readOnly && this.taskCloudService.canCompleteTask(this.taskDetails); + } + + canUnclaimTask(): boolean { + return !this.readOnly && this.taskCloudService.canUnclaimTask(this.taskDetails) && this.hasCandidateUsersOrGroups(); + } + + getTaskType() { + 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; + } else { + this.taskType = this.taskTypeEnum.None; + } + } + + hasCandidateUsers(): boolean { + return this.candidateUsers.length !== 0; + } + + hasCandidateGroups(): boolean { + return this.candidateGroups.length !== 0; + } + + hasCandidateUsersOrGroups(): boolean { + return this.hasCandidateUsers() || this.hasCandidateGroups(); + } + + onCancelForm() { + this.cancelClick.emit(); + } + + onCancelClick() { + this.cancelClick.emit(this.taskId); + } + + onClaimTask() { + this.loadTask(); + this.taskClaimed.emit(this.taskId); + } + + onCompleteTask() { + this.loadTask(); + this.taskCompleted.emit(this.taskId); + } + + onCompleteTaskForm() { + this.taskCompleted.emit(); + } + + onError(data: any) { + this.error.emit(data); + } + + onExecuteOutcome(outcome: FormOutcomeEvent) { + this.executeOutcome.emit(outcome); + } + onFormContentClicked(content: ContentLinkModel) { + this.formContentClicked.emit(content); + } + onFormSaved() { + this.formSaved.emit(); + } + + onTaskUnclaimed() { + this.taskUnclaimed.emit(); + } + + onUnclaimTask() { + this.loadTask(); + this.taskUnclaimed.emit(this.taskId); + } + + private loadTask() { + this.loading = true; + this.taskCloudService + .getTaskById(this.appName, this.taskId) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((details) => { + this.taskDetails = details; + this.getTaskType(); + this.loading = false; + this.onTaskLoaded.emit(this.taskDetails); + }); + + this.taskCloudService.getCandidateUsers(this.appName, this.taskId).subscribe((users) => (this.candidateUsers = users || [])); + this.taskCloudService.getCandidateGroups(this.appName, this.taskId).subscribe((groups) => (this.candidateGroups = groups || [])); + } + + public switchToDisplayMode(newDisplayMode?: string) { + if (this.adfCloudTaskForm) { + this.adfCloudTaskForm.switchToDisplayMode(newDisplayMode); + } + } + + ngOnChanges(changes: SimpleChanges) { + const appName = changes['appName']; + if (appName && appName.currentValue !== appName.previousValue && this.taskId) { + this.loadTask(); + return; + } + + const taskId = changes['taskId']; + if (taskId?.currentValue && this.appName) { + this.loadTask(); + return; + } + } + + ngOnInit() { + if (this.appName === '' && this.taskId) { + this.loadTask(); + } + } +} diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.interface.ts b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.interface.ts new file mode 100644 index 0000000000..773bffde36 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-form/components/user-task-cloud/user-task-cloud.interface.ts @@ -0,0 +1,26 @@ +/*! + * @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. + */ + +import { EventEmitter } from '@angular/core'; + +export interface UserTaskCustomUi { + error: EventEmitter; + cancelClick: EventEmitter; + taskClaimed: EventEmitter; + taskUnclaimed: EventEmitter; + taskCompleted: EventEmitter; +} diff --git a/lib/process-services-cloud/src/lib/task/task-form/public-api.ts b/lib/process-services-cloud/src/lib/task/task-form/public-api.ts index b75729a771..ed10ea7e25 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/public-api.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/public-api.ts @@ -15,6 +15,7 @@ * limitations under the License. */ -export * from './components/task-form-cloud.component'; +export * from './components/task-form-cloud/task-form-cloud.component'; +export * from './components/user-task-cloud/user-task-cloud.component'; export * from './task-form.module'; diff --git a/lib/process-services-cloud/src/lib/task/task-form/task-form.module.ts b/lib/process-services-cloud/src/lib/task/task-form/task-form.module.ts index 4a23edf819..bd3a42e459 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/task-form.module.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/task-form.module.ts @@ -21,22 +21,15 @@ import { MaterialModule } from '../../material.module'; import { FormCloudModule } from '../../form/form-cloud.module'; import { TaskDirectiveModule } from '../directives/task-directive.module'; -import { TaskFormCloudComponent } from './components/task-form-cloud.component'; +import { TaskFormCloudComponent } from './components/task-form-cloud/task-form-cloud.component'; import { CoreModule } from '@alfresco/adf-core'; +import { ScreenCloudComponent } from '../../screen/components/screen-cloud/screen-cloud.component'; +import { UserTaskCloudComponent } from './components/user-task-cloud/user-task-cloud.component'; +import { UserTaskCloudButtonsComponent } from './components/user-task-cloud-buttons/user-task-cloud-buttons.component'; @NgModule({ - imports: [ - CoreModule, - CommonModule, - MaterialModule, - FormCloudModule, - TaskDirectiveModule - ], - declarations: [ - TaskFormCloudComponent - ], - exports: [ - TaskFormCloudComponent - ] + imports: [CoreModule, CommonModule, MaterialModule, FormCloudModule, TaskDirectiveModule, ScreenCloudComponent], + declarations: [TaskFormCloudComponent, UserTaskCloudComponent, UserTaskCloudButtonsComponent], + exports: [TaskFormCloudComponent, UserTaskCloudComponent] }) -export class TaskFormModule { } +export class TaskFormModule {}