AAE-26215 migrate to standalone directives (#10532)

* delete unused directive

* convert process header to standalone

* cleanup [ci:force]

* remove unused/deprecated components [ci:force]

* remove unused/deprecated components [ci:force]

* migrate task header [ci:force]

* migrate task directives [ci:force]

* migrate task directives [ci:force]
This commit is contained in:
Denys Vuika 2025-01-07 09:20:17 -05:00 committed by GitHub
parent 82e4196e26
commit 72cdf514e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 272 additions and 1643 deletions

View File

@ -489,7 +489,6 @@ Status: Experimental | [Source](<>) |
| [Process Header Cloud Component](process-services-cloud/components/process-header-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Shows all the information related to a process instance. | [Source](../lib/process-services-cloud/src/lib/process/process-header/components/process-header-cloud.component.ts) |
| [Process Instance List Cloud component](process-services-cloud/components/process-list-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Renders a list containing all the process instances matched by the parameters specified. | [Source](../lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts) |
| [Start Process Cloud Component](process-services-cloud/components/start-process-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Starts a process. | [Source](../lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts) |
| [Start Task Cloud Component](process-services-cloud/components/start-task-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Creates/starts a new task for the specified app. | [Source](../lib/process-services-cloud/src/lib/task/start-task/components/start-task-cloud.component.ts) |
| [Task Filters Cloud component](process-services-cloud/components/task-filters-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Shows all available filters. | [Source](../lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.ts) |
| [Form cloud component](process-services-cloud/components/task-form-cloud.component.md) | Shows a form for a task. | [Source](../lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts) |
| [Task Header Cloud Component](process-services-cloud/components/task-header-cloud.component.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Shows all the information related to a task. | [Source](../lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.ts) |
@ -499,7 +498,6 @@ Status: Experimental | [Source](<>) |
| Name | Description | Source link |
| ---- | ----------- | ----------- |
| [Cancel Process Directive](process-services-cloud/directives/cancel-process.directive.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Cancels a process | [Source](../lib/process-services-cloud/src/lib/process/directives/cancel-process.directive.ts) |
| [Claim Task Cloud Directive](process-services-cloud/directives/claim-task-cloud.directive.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Claims a task | [Source](../lib/process-services-cloud/src/lib/task/directives/claim-task-cloud.directive.ts) |
| [Complete Task Directive](process-services-cloud/directives/complete-task.directive.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Completes a task. | [Source](../lib/process-services-cloud/src/lib/task/directives/complete-task.directive.ts) |
| [Unclaim Task Cloud Directive](process-services-cloud/directives/unclaim-task-cloud.directive.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Unclaims a task | [Source](../lib/process-services-cloud/src/lib/task/directives/unclaim-task-cloud.directive.ts) |
@ -522,7 +520,6 @@ Status: Experimental | [Source](<>) |
| [Process Filter Cloud Service](process-services-cloud/services/process-filter-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Manage Process Filters, which are pre-configured Process Instance queries. | [Source](../lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.ts) |
| [Process List Cloud Service](process-services-cloud/services/process-list-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Searches processes. | [Source](../lib/process-services-cloud/src/lib/process/process-list/services/process-list-cloud.service.ts) |
| [Start Process Cloud Service](process-services-cloud/services/start-process-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Gets process definitions and starts processes. | [Source](../lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.ts) |
| [Start Task Cloud Service](process-services-cloud/services/start-task-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Starts standalone tasks. | [Source](../lib/process-services-cloud/src/lib/task/services/start-task-cloud.service.ts) |
| [Task Cloud Service](process-services-cloud/services/task-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Manages task cloud. | [Source](../lib/process-services-cloud/src/lib/task/services/task-cloud.service.ts) |
| [Task Filter Cloud Service](process-services-cloud/services/task-filter-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Manages task filters. | [Source](../lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.ts) |
| [Task List Cloud Service](process-services-cloud/services/task-list-cloud.service.md) ![Experimental](docassets/images/ExperimentalIcon.png) | Searches tasks. | [Source](../lib/process-services-cloud/src/lib/task/task-list/services/task-list-cloud.service.ts) |

View File

@ -1,38 +0,0 @@
---
Title: Start Task Cloud Component
Added: v3.0.0
Status: Experimental
Last reviewed: 2019-03-20
---
# [Start Task Cloud Component](../../../lib/process-services-cloud/src/lib/task/start-task/components/start-task-cloud.component.ts "Defined in start-task-cloud.component.ts")
Creates/starts a new task for the specified app.
![adf-cloud-start-task](../../docassets/images/adf-cloud-start-task.png)
## Basic Usage
```html
<adf-cloud-start-task
[appName]="YOUR_APP_NAME">
</adf-cloud-start-task>
```
## Class members
### Properties
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| appName | `string` | "" | (required) Name of the app. |
| maxNameLength | `number` | MAX_NAME_LENGTH | Maximum length of the task name. |
| name | `string` | "" | Name of the task. |
### Events
| Name | Type | Description |
| ---- | ---- | ----------- |
| cancel | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<void>` | Emitted when the cancel button is clicked by the user. |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an error occurs. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the task is successfully created. |

View File

@ -1,23 +0,0 @@
---
Title: Cancel Process Directive
Added: v3.7.0
Status: Experimental
Last reviewed: 2019-12-09
---
# [Cancel process directive](../../../lib/process-services-cloud/src/lib/process/directives/cancel-process.directive.ts "Defined in cancel-process.directive.ts")
Cancels a process
## Basic Usage
```html
<button adf-cloud-cancel-process (success)="onProcessCancelled()" (error)="onCancelProcessError()">Cancel</button>
```
### Events
| Name | Type | Description |
| ---- | ---- | ----------- |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the process can not be cancelled. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when the process is cancelled. |

View File

@ -1,34 +0,0 @@
---
Title: Start Task Cloud Service
Added: v3.0.0
Status: Experimental
Last reviewed: 2019-01-09
---
# [Start Task Cloud Service](../../../lib/process-services-cloud/src/lib/task/services/start-task-cloud.service.ts "Defined in start-task-cloud.service.ts")
Starts standalone tasks.
## Class members
### Methods
- **createNewTask**(taskDetails: [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>`<br/>
(**Deprecated:** in 3.5.0, use TaskCloudService instead. Creates a new standalone task.)
- _taskDetails:_ [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts) - Details of the task to create
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>` - Details of the newly created task
- **getBasePath**(appName: `string`): `string`<br/>
- _appName:_ `string` -
- **Returns** `string` -
## Details
The `createNewTask` method works the same way as the method with the same name in the
[Tasklist service](../../process-services/services/tasklist.service.md)
but uses the cloud variants of the classes for the parameter and return value. See the
[Tasklist service](../../process-services/services/tasklist.service.md) page for usage examples.
## See also
- [Tasklist service](../../process-services/services/tasklist.service.md)

View File

@ -1,79 +0,0 @@
/*!
* @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, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CancelProcessDirective } from './cancel-process.directive';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { ProcessInstanceCloud } from '../start-process/models/process-instance-cloud.model';
import { IdentityUserService } from '../../people/services/identity-user.service';
const processDetailsMockRunning: ProcessInstanceCloud = { initiator: 'usermock', status: 'RUNNING' };
const processDetailsMockCompleted: ProcessInstanceCloud = { initiator: 'usermock', status: 'COMPLETED' };
describe('CancelProcessDirective', () => {
@Component({
selector: 'adf-cloud-cancel-process-test-component',
template: '<button adf-cloud-cancel-process></button>'
})
class TestComponent {
@ViewChild(CancelProcessDirective)
cancelProcessDirective: CancelProcessDirective;
}
let fixture: ComponentFixture<TestComponent>;
let identityUserService: IdentityUserService;
let component: TestComponent;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
declarations: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
identityUserService = TestBed.inject(IdentityUserService);
spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue({ username: 'usermock' });
fixture.detectChanges();
});
it('should directive call cancelProcess when button is clicked', () => {
const cancelProcessSpy = spyOn(component.cancelProcessDirective, 'cancelProcess').and.callThrough();
const button = fixture.nativeElement.querySelector('button');
button.click();
expect(cancelProcessSpy).toHaveBeenCalled();
});
it('should checkCanCancelProcess return false when process status is COMPLETED', () => {
component.cancelProcessDirective.processInstanceDetails = processDetailsMockCompleted;
fixture.detectChanges();
expect(component.cancelProcessDirective.checkCanCancelProcess()).toBeFalsy();
});
it('should checkCanCancelProcess return true when process status is RUNNING and logged in user is the processInitiator', () => {
component.cancelProcessDirective.processInstanceDetails = processDetailsMockRunning;
fixture.detectChanges();
expect(component.cancelProcessDirective.checkCanCancelProcess()).toBeTruthy();
});
it('should checkCanCancelProcess return false when logged in user is not the processInitiator', () => {
component.cancelProcessDirective.processInstanceDetails = processDetailsMockRunning;
component.cancelProcessDirective.processInstanceDetails.initiator = 'mock-user';
fixture.detectChanges();
expect(component.cancelProcessDirective.checkCanCancelProcess()).toBeFalsy();
});
});

View File

@ -1,84 +0,0 @@
/*!
* @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 { DestroyRef, Directive, ElementRef, EventEmitter, HostListener, inject, OnInit, Output } from '@angular/core';
import { ProcessCloudService } from '../services/process-cloud.service';
import { ProcessInstanceCloud } from '../start-process/models/process-instance-cloud.model';
import { IdentityUserService } from '../../people/services/identity-user.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[adf-cloud-cancel-process]'
})
export class CancelProcessDirective implements OnInit {
/** Emitted when the process is cancelled. */
@Output()
success = new EventEmitter<any>();
/** Emitted when the process cannot be cancelled. */
@Output()
error = new EventEmitter<any>();
processInstanceDetails: ProcessInstanceCloud;
canCancelProcess = false;
private readonly destroyRef = inject(DestroyRef);
constructor(
private elementRef: ElementRef,
private processCloudService: ProcessCloudService,
private identityUserService: IdentityUserService) {}
ngOnInit() {
this.processCloudService.dataChangesDetected
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((processDetails) => {
this.processInstanceDetails = processDetails;
this.canCancelProcess = this.checkCanCancelProcess();
this.setElementVisibility();
});
}
@HostListener('click')
onClick() {
this.cancelProcess();
}
private setElementVisibility() {
this.elementRef.nativeElement.disabled = !this.canCancelProcess;
}
checkCanCancelProcess(): boolean {
const currentUser = this.identityUserService.getCurrentUserInfo().username;
return this.processInstanceDetails.initiator === currentUser && this.processInstanceDetails.status === 'RUNNING';
}
cancelProcess() {
if (this.canCancelProcess) {
this.processCloudService.cancelProcess(this.processInstanceDetails.appName, this.processInstanceDetails.id)
.subscribe(
(response) => this.success.emit(response),
(error) => this.error.emit(error)
);
} else {
this.error.emit('Permission denied, only process initiator can cancel the process');
}
}
}

View File

@ -1,29 +0,0 @@
/*!
* @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 { NgModule } from '@angular/core';
import { CancelProcessDirective } from './cancel-process.directive';
@NgModule({
declarations: [
CancelProcessDirective
],
exports: [
CancelProcessDirective
]
})
export class ProcessDirectiveModule { }

View File

@ -1,20 +0,0 @@
/*!
* @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 './cancel-process.directive';
export * from './process-directive.module';

View File

@ -19,20 +19,12 @@ import { NgModule } from '@angular/core';
import { ProcessFiltersCloudModule } from './process-filters/process-filters-cloud.module';
import { ProcessListCloudModule } from './process-list/process-list-cloud.module';
import { CoreModule, LocalizedDatePipe } from '@alfresco/adf-core';
import { ProcessHeaderCloudModule } from './process-header/process-header-cloud.module';
import { ProcessDirectiveModule } from './directives/process-directive.module';
import { StartProcessCloudComponent } from './start-process/components/start-process-cloud.component';
import { ProcessHeaderCloudComponent } from './process-header/components/process-header-cloud.component';
@NgModule({
imports: [
CoreModule,
ProcessFiltersCloudModule,
ProcessListCloudModule,
StartProcessCloudComponent,
ProcessHeaderCloudModule,
ProcessDirectiveModule
],
exports: [ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudModule, ProcessDirectiveModule],
imports: [CoreModule, ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent],
exports: [ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent],
providers: [LocalizedDatePipe]
})
export class ProcessCloudModule {}

View File

@ -21,7 +21,6 @@ import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { ProcessHeaderCloudComponent } from './process-header-cloud.component';
import { ProcessHeaderCloudModule } from '../process-header-cloud.module';
import { ProcessCloudService } from '../../services/process-cloud.service';
import { processInstanceDetailsCloudMock } from '../../mock/process-instance-details-cloud.mock';
@ -33,7 +32,7 @@ describe('ProcessHeaderCloudComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, ProcessHeaderCloudModule]
imports: [ProcessServiceCloudTestingModule, ProcessHeaderCloudComponent]
});
fixture = TestBed.createComponent(ProcessHeaderCloudComponent);
component = fixture.componentInstance;

View File

@ -16,7 +16,6 @@
*/
import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular';
import { ProcessHeaderCloudModule } from '../process-header-cloud.module';
import { ProcessServicesCloudStoryModule } from '../../../testing/process-services-cloud-story.module';
import { ProcessHeaderCloudComponent } from './process-header-cloud.component';
import { ProcessCloudServiceMock } from '../../mock/process-cloud.service.mock';
@ -28,7 +27,7 @@ export default {
title: 'Process Services Cloud/Process Cloud/Process Header Cloud/Process Header Cloud',
decorators: [
moduleMetadata({
imports: [ProcessHeaderCloudModule]
imports: [ProcessHeaderCloudComponent]
}),
applicationConfig({
providers: [{ provide: ProcessCloudService, useClass: ProcessCloudServiceMock }, importProvidersFrom(ProcessServicesCloudStoryModule)]

View File

@ -15,20 +15,11 @@
* limitations under the License.
*/
import {
Component,
DestroyRef,
EventEmitter,
inject,
Input,
OnChanges,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core';
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core';
import {
AppConfigService,
CardViewBaseItemModel,
CardViewComponent,
CardViewDateItemModel,
CardViewItem,
CardViewTextItemModel,
@ -37,9 +28,13 @@ import {
import { ProcessInstanceCloud } from '../../start-process/models/process-instance-cloud.model';
import { ProcessCloudService } from '../../services/process-cloud.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatCardModule } from '@angular/material/card';
import { NgIf } from '@angular/common';
@Component({
selector: 'adf-cloud-process-header',
standalone: true,
imports: [CardViewComponent, MatCardModule, NgIf],
templateUrl: './process-header-cloud.component.html',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./process-header-cloud.component.scss'],
@ -75,7 +70,9 @@ export class ProcessHeaderCloudComponent implements OnChanges, OnInit {
this.dateFormat = this.appConfig.get('adf-cloud-process-header.defaultDateFormat');
this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale');
this.processCloudService.dataChangesDetected.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((processDetails) => this.onLoaded(processDetails));
this.processCloudService.dataChangesDetected
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((processDetails) => this.onLoaded(processDetails));
}
ngOnChanges() {

View File

@ -16,19 +16,11 @@
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MaterialModule } from '../../material.module';
import { CoreModule } from '@alfresco/adf-core';
import { ProcessHeaderCloudComponent } from './components/process-header-cloud.component';
/** @deprecated use ProcessHeaderCloudComponent instead */
@NgModule({
imports: [
CommonModule,
MaterialModule,
CoreModule
],
declarations: [ProcessHeaderCloudComponent],
imports: [ProcessHeaderCloudComponent],
exports: [ProcessHeaderCloudComponent]
})
export class ProcessHeaderCloudModule {}

View File

@ -19,7 +19,6 @@ export * from './process-list/public-api';
export * from './process-filters/public-api';
export * from './start-process/public-api';
export * from './process-header/public-api';
export * from './directives/public-api';
export * from './services/process-cloud.service';
export * from './process-cloud.module';

View File

@ -21,10 +21,10 @@ import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[adf-cloud-claim-task]'
selector: '[adf-cloud-claim-task]',
standalone: true
})
export class ClaimTaskCloudDirective implements OnInit {
/** (Required) The id of the task. */
@Input()
taskId: string;
@ -47,14 +47,14 @@ export class ClaimTaskCloudDirective implements OnInit {
private readonly el: ElementRef,
private readonly renderer: Renderer2,
private taskListService: TaskCloudService,
private identityUserService: IdentityUserService) { }
private identityUserService: IdentityUserService
) {}
ngOnInit() {
this.validateInputs();
}
validateInputs() {
if (!this.isTaskValid()) {
this.invalidParams.push('taskId');
}
@ -81,7 +81,6 @@ export class ClaimTaskCloudDirective implements OnInit {
} catch (error) {
this.error.emit(error);
}
}
private async claimTask() {

View File

@ -27,6 +27,8 @@ import { By } from '@angular/platform-browser';
describe('CompleteTaskDirective', () => {
@Component({
selector: 'adf-cloud-test-component',
standalone: true,
imports: [CompleteTaskDirective],
template: `<button
adf-cloud-complete-task
[taskId]="taskMock"
@ -56,8 +58,7 @@ describe('CompleteTaskDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
declarations: [TestComponent]
imports: [ProcessServiceCloudTestingModule, TestComponent]
});
taskCloudService = TestBed.inject(TaskCloudService);
fixture = TestBed.createComponent(TestComponent);
@ -105,6 +106,8 @@ describe('CompleteTaskDirective', () => {
describe('Complete Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-no-fields-validation-component',
standalone: true,
imports: [CompleteTaskDirective],
template: '<button adf-cloud-complete-task (success)="onCompleteTask($event)"></button>'
})
class TestMissingInputDirectiveComponent {
@ -122,6 +125,8 @@ describe('Complete Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-no-taskid-validation-component',
standalone: true,
imports: [CompleteTaskDirective],
template: '<button adf-cloud-complete-task [appName]="appName" (success)="onCompleteTask($event)"></button>'
})
class TestMissingTaskIdDirectiveComponent {
@ -137,7 +142,9 @@ describe('Complete Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-undefined-appname-component',
template: '<button adf-cloud-complete-task [taskId]="taskMock" [appName]="appNameUndefined" (success)="onCompleteTask($event)"></button>'
standalone: true,
imports: [CompleteTaskDirective],
template: '<button adf-cloud-complete-task [taskId]="taskMock" [appName]="undefined" (success)="onCompleteTask($event)"></button>'
})
class TestInvalidAppNameUndefinedDirectiveComponent {
appName = 'simple-app';
@ -153,7 +160,9 @@ describe('Complete Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-null-appname-component',
template: '<button adf-cloud-complete-task [taskId]="taskMock" [appName]="appNameNull" (success)="onCompleteTask($event)"></button>'
standalone: true,
imports: [CompleteTaskDirective],
template: '<button adf-cloud-complete-task [taskId]="taskMock" [appName]="null" (success)="onCompleteTask($event)"></button>'
})
class TestInvalidAppNameNullDirectiveComponent {
appName = 'simple-app';
@ -171,8 +180,8 @@ describe('Complete Task Directive validation errors', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
declarations: [
imports: [
ProcessServiceCloudTestingModule,
TestMissingTaskIdDirectiveComponent,
TestInvalidAppNameUndefinedDirectiveComponent,
TestInvalidAppNameNullDirectiveComponent,

View File

@ -20,10 +20,10 @@ import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[adf-cloud-complete-task]'
selector: '[adf-cloud-complete-task]',
standalone: true
})
export class CompleteTaskDirective implements OnInit {
/** (Required) The id of the task. */
@Input()
taskId: string;
@ -42,18 +42,13 @@ export class CompleteTaskDirective implements OnInit {
invalidParams: string[] = [];
constructor(
private readonly el: ElementRef,
private readonly renderer: Renderer2,
private readonly taskListService: TaskCloudService
) { }
constructor(private readonly el: ElementRef, private readonly renderer: Renderer2, private readonly taskListService: TaskCloudService) {}
ngOnInit() {
this.validateInputs();
}
validateInputs() {
if (!this.isTaskValid()) {
this.invalidParams.push('taskId');
}
@ -85,6 +80,5 @@ export class CompleteTaskDirective implements OnInit {
this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
this.error.emit(error);
}
}
}

View File

@ -20,16 +20,11 @@ import { CompleteTaskDirective } from './complete-task.directive';
import { ClaimTaskCloudDirective } from './claim-task-cloud.directive';
import { UnClaimTaskCloudDirective } from './unclaim-task-cloud.directive';
export const TASK_DIRECTIVES = [CompleteTaskDirective, ClaimTaskCloudDirective, UnClaimTaskCloudDirective] as const;
/** @deprecated */
@NgModule({
declarations: [
CompleteTaskDirective,
ClaimTaskCloudDirective,
UnClaimTaskCloudDirective
],
exports: [
CompleteTaskDirective,
ClaimTaskCloudDirective,
UnClaimTaskCloudDirective
]
imports: [...TASK_DIRECTIVES],
exports: [...TASK_DIRECTIVES]
})
export class TaskDirectiveModule {}

View File

@ -27,6 +27,8 @@ import { By } from '@angular/platform-browser';
describe('UnClaimTaskCloudDirective', () => {
@Component({
selector: 'adf-cloud-test-component',
standalone: true,
imports: [UnClaimTaskCloudDirective],
template: '<button adf-cloud-unclaim-task [taskId]="taskIdMock" [appName]="appName" (error)="onError($event)"></button>'
})
class TestComponent {
@ -46,8 +48,7 @@ describe('UnClaimTaskCloudDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
declarations: [TestComponent]
imports: [ProcessServiceCloudTestingModule, TestComponent]
});
taskCloudService = TestBed.inject(TaskCloudService);
fixture = TestBed.createComponent(TestComponent);
@ -95,6 +96,8 @@ describe('UnClaimTaskCloudDirective', () => {
describe('UnClaim Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-claim-no-fields-validation-component',
standalone: true,
imports: [UnClaimTaskCloudDirective],
template: '<button adf-cloud-unclaim-task></button>'
})
class ClaimTestMissingInputDirectiveComponent {
@ -108,6 +111,8 @@ describe('UnClaim Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-claim-no-taskid-validation-component',
standalone: true,
imports: [UnClaimTaskCloudDirective],
template: '<button adf-cloud-unclaim-task [appName]="appName"></button>'
})
class ClaimTestMissingTaskIdDirectiveComponent {
@ -119,6 +124,8 @@ describe('UnClaim Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-claim-undefined-appname-component',
standalone: true,
imports: [UnClaimTaskCloudDirective],
template: '<button adf-cloud-unclaim-task [taskId]="taskMock" [appName]="appNameUndefined"></button>'
})
class ClaimTestInvalidAppNameUndefinedDirectiveComponent {
@ -131,6 +138,8 @@ describe('UnClaim Task Directive validation errors', () => {
@Component({
selector: 'adf-cloud-claim-null-appname-component',
standalone: true,
imports: [UnClaimTaskCloudDirective],
template: '<button adf-cloud-unclaim-task [taskId]="taskMock" [appName]="appNameNull"></button>'
})
class ClaimTestInvalidAppNameNullDirectiveComponent {
@ -145,8 +154,8 @@ describe('UnClaim Task Directive validation errors', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
declarations: [
imports: [
ProcessServiceCloudTestingModule,
ClaimTestMissingTaskIdDirectiveComponent,
ClaimTestInvalidAppNameUndefinedDirectiveComponent,
ClaimTestInvalidAppNameNullDirectiveComponent,

View File

@ -20,10 +20,10 @@ import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: '[adf-cloud-unclaim-task]'
selector: '[adf-cloud-unclaim-task]',
standalone: true
})
export class UnClaimTaskCloudDirective implements OnInit {
/** (Required) The id of the task. */
@Input()
taskId: string;
@ -42,17 +42,13 @@ export class UnClaimTaskCloudDirective implements OnInit {
invalidParams: string[] = [];
constructor(
private readonly el: ElementRef,
private readonly renderer: Renderer2,
private taskListService: TaskCloudService) { }
constructor(private readonly el: ElementRef, private readonly renderer: Renderer2, private taskListService: TaskCloudService) {}
ngOnInit() {
this.validateInputs();
}
validateInputs() {
if (!this.isTaskValid()) {
this.invalidParams.push('taskId');
}

View File

@ -15,11 +15,6 @@
* limitations under the License.
*/
// eslint-disable-next-line no-shadow
export enum ClaimTaskEnum {
claim = 'claim',
unclaim = 'unclaim'
}
export interface TaskPriorityOption {
label: string;
key: string;

View File

@ -24,6 +24,5 @@ export * from './directives/public-api';
export * from './models/public-api';
export * from './services/task-cloud.service';
export * from './services/start-task-cloud.service';
export * from './task-cloud.module';

View File

@ -1,42 +0,0 @@
/*!
* @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 { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { StartTaskCloudRequestModel } from '../start-task/models/start-task-cloud-request.model';
import { TaskDetailsCloudModel, StartTaskCloudResponseModel } from '../start-task/models/task-details-cloud.model';
import { BaseCloudService } from '../../services/base-cloud.service';
@Injectable({ providedIn: 'root' })
export class StartTaskCloudService extends BaseCloudService {
/**
* @deprecated in 3.5.0, use TaskCloudService instead.
* Creates a new standalone task.
* @param taskDetails Details of the task to create
* @returns Details of the newly created task
*/
createNewTask(taskDetails: TaskDetailsCloudModel): Observable<TaskDetailsCloudModel> {
const url = `${this.getBasePath(taskDetails.appName)}/rb/v1/tasks`;
const payload = JSON.stringify(new StartTaskCloudRequestModel(taskDetails));
return this.post<any, StartTaskCloudResponseModel>(url, payload)
.pipe(
map(response => response.entry)
);
}
}

View File

@ -24,12 +24,44 @@ import {
createdTaskDetailsCloudMock,
emptyOwnerTaskDetailsCloudMock
} from '../task-header/mocks/task-details-cloud.mock';
import { fakeTaskDetailsCloud } from '../task-header/mocks/fake-task-details-response.mock';
import { cloudMockUser } from '../start-task/mock/user-cloud.mock';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { IdentityUserService } from '../../people/services/identity-user.service';
import { AdfHttpClient } from '@alfresco/adf-core/api';
const fakeTaskDetailsCloud = {
entry: {
appName: 'task-app',
appVersion: '',
id: '68d54a8f',
assignee: 'Phil Woods',
name: 'This is a new task',
description: 'This is the description ',
createdDate: 1545048055900,
dueDate: 1545091200000,
claimedDate: 1545140162601,
priority: 0,
category: null,
processDefinitionId: null,
processInstanceId: null,
status: 'ASSIGNED',
owner: 'Phil Woods',
parentTaskId: null,
formKey: null,
lastModified: 1545140162601,
lastModifiedTo: null,
lastModifiedFrom: null,
standalone: true
}
};
const cloudMockUser = {
id: 'fake-id-1',
username: 'AssignedTaskUser',
firstName: 'first-name-1',
lastName: 'last-name-1',
email: 'abc@xyz.com'
};
describe('Task Cloud Service', () => {
let service: TaskCloudService;
let adfHttpClient: AdfHttpClient;

View File

@ -1,108 +0,0 @@
<mat-card appearance="outlined">
<mat-card-header class="adf-cloud-start-task-heading">
<mat-card-title class="adf-cloud-start-task-heading-title">{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.TITLE' | translate}}</mat-card-title>
</mat-card-header>
<form [formGroup]="taskForm" (ngSubmit)="saveTask()">
<mat-card-content>
<div class="adf-task-name">
<mat-form-field class="adf-task-name-form-field">
<mat-label>{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.NAME' | translate }}</mat-label>
<input
matInput
id="name_id"
class="form-control"
formControlName="name">
<mat-error *ngIf="nameController.hasError('required')">
{{ 'ADF_CLOUD_START_TASK.ERROR.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="nameController.hasError('maxlength')">
{{ 'ADF_CLOUD_START_TASK.ERROR.MAXIMUM_LENGTH' | translate : {characters: maxNameLength} }}
</mat-error>
</mat-form-field>
</div>
<div class="adf-cloud-start-task-form-row">
<mat-form-field class="adf-cloud-start-task-form-row-form-field">
<mat-label>{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.DESCRIPTION' | translate}}</mat-label>
<textarea
matInput
class="form-control"
id="description_id"
formControlName="description">
</textarea>
</mat-form-field>
<mat-form-field class="adf-cloud-priority-container">
<mat-label>{{ 'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.PRIORITY' | translate }}</mat-label>
<mat-select formControlName="priority">
<mat-option *ngFor="let priorityOption of priorities" [value]="priorityOption.value">{{ priorityOption.label | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="adf-cloud-start-task-form-row">
<mat-form-field>
<input matInput
[matDatepicker]="taskDatePicker"
(focusout)="onDateChanged($any($event).srcElement.value)"
placeholder="{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.DATE'|translate}}"
[(ngModel)]="dueDate"
[ngModelOptions]="{standalone: true}"
id="date_id">
<mat-datepicker-toggle matSuffix [for]="taskDatePicker" />
<mat-datepicker #taskDatePicker
[touchUi]="true"
(dateChanged)="onDateChanged($event)" />
<div class="adf-cloud-date-error-container">
<div *ngIf="dateError">
<div class="adf-error-text">{{'ADF_CLOUD_START_TASK.ERROR.DATE' | translate}}</div>
<mat-icon class="adf-error-icon">warning</mat-icon>
</div>
</div>
</mat-form-field>
<adf-cloud-people #peopleInput *ngIf="currentUser"
[appName]="appName"
[preSelectUsers]="[currentUser]"
[searchUserCtrl]="assigneeFormControl"
(selectUser)="onAssigneeSelect($event)"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.ASSIGNEE'"
(removeUser)="onAssigneeRemove()" />
</div>
<div class="adf-cloud-start-task-form-row">
<adf-cloud-group #groupInput
*ngIf="currentUser"
[mode]="'multiple'"
[title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'"
[appName]="appName"
[searchGroupsControl]="candidateUserFormControl"
(selectGroup)="onCandidateGroupSelect($event)"
(removeGroup)="onCandidateGroupRemove($event)" />
<adf-cloud-form-definition-selector *ngIf="appName"
[appName]="appName"
(selectForm)="onFormSelect($event)" />
</div>
</mat-card-content>
<mat-card-actions>
<div class="adf-cloud-start-task-footer">
<button
mat-button
class="adf-cloud-start-task-footer-button"
type="button"
(click)="onCancel()"
id="button-cancel">
{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.ACTION.CANCEL' | translate | uppercase}}
</button>
<button
color="primary"
type="submit"
[disabled]="!canStartTask()"
mat-button
class="adf-cloud-start-task-footer-button"
id="button-start">
{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.ACTION.START' | translate | uppercase}}
</button>
</div>
</mat-card-actions>
</form>
</mat-card>

View File

@ -1,92 +0,0 @@
@import 'styles/flex';
.adf-cloud-start-task-heading {
border-bottom: 1px solid var(--adf-theme-foreground-divider-color);
margin-bottom: 10px;
.adf-cloud-start-task-heading-title {
font-weight: bold;
font-size: var(--theme-adf-task-title-font-size);
}
}
.adf-cloud-priority-container {
padding-top: 1.1em;
}
.adf-cloud-date-error-container {
position: absolute;
height: 20px;
margin-top: 12px;
width: 100%;
& > div {
display: flex;
flex-flow: row;
justify-content: flex-start;
}
.adf-error-text {
padding-right: 8px;
height: 16px;
font-size: var(--theme-caption-font-size);
line-height: 1.33;
color: var(--theme-warn-color);
width: auto;
}
.adf-error-icon {
font-size: var(--theme-adf-icon-1-font-size);
color: var(--theme-warn-color);
}
}
.adf-cloud-start-task-footer {
padding: 4px;
font-size: var(--theme-adf-task-footer-font-size);
border-top: 1px solid #eee;
display: flex;
place-content: flex-end;
align-items: flex-end;
}
adf-cloud-start-task {
.adf {
&-task-name {
display: flex;
.adf-task-name-form-field {
flex: 1;
}
}
&-cloud-start-task-form-row {
display: flex;
.adf-cloud-start-task-form-row-form-field,
adf-cloud-people,
adf-cloud-group,
adf-cloud-form-definition-selector {
flex: 1;
}
.adf-cloud-start-task-form-row-form-field,
adf-cloud-group {
margin-right: 20px;
&:last-of-type:not(:first-of-type) {
margin-right: 0;
}
}
@include layout-bp(lt-md) {
flex-direction: column;
.adf-cloud-start-task-form-row-form-field,
adf-cloud-group {
margin-right: 0;
}
}
}
}
}

View File

@ -1,247 +0,0 @@
/*!
* @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 { AlfrescoApiService } from '@alfresco/adf-content-services';
import { StartTaskCloudComponent } from './start-task-cloud.component';
import { of, throwError } from 'rxjs';
import { taskDetailsMock } from '../mock/task-details.mock';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ProcessServiceCloudTestingModule } from './../../../testing/process-service-cloud.testing.module';
import { FormDefinitionSelectorCloudService } from '../../../form/services/form-definition-selector-cloud.service';
import { TaskCloudService } from '../../services/task-cloud.service';
import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
import { IdentityUserService } from '../../../people/services/identity-user.service';
import { IdentityUserModel } from '../../../people/models/identity-user.model';
describe('StartTaskCloudComponent', () => {
let component: StartTaskCloudComponent;
let fixture: ComponentFixture<StartTaskCloudComponent>;
let service: TaskCloudService;
let identityService: IdentityUserService;
let formDefinitionSelectorCloudService: FormDefinitionSelectorCloudService;
let element: HTMLElement;
let createNewTaskSpy: jasmine.Spy;
let alfrescoApiService: AlfrescoApiService;
const mock: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(taskDetailsMock)
},
isEcmLoggedIn: () => false,
reply: jasmine.createSpy('reply')
};
const mockUser: IdentityUserModel = { username: 'currentUser', firstName: 'Test', lastName: 'User', email: 'currentUser@test.com' };
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
fixture = TestBed.createComponent(StartTaskCloudComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
service = TestBed.inject(TaskCloudService);
identityService = TestBed.inject(IdentityUserService);
alfrescoApiService = TestBed.inject(AlfrescoApiService);
formDefinitionSelectorCloudService = TestBed.inject(FormDefinitionSelectorCloudService);
spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock);
createNewTaskSpy = spyOn(service, 'createNewTask').and.returnValue(of(taskDetailsMock as any));
spyOn(identityService, 'getCurrentUserInfo').and.returnValue(mockUser);
spyOn(formDefinitionSelectorCloudService, 'getForms').and.returnValue(of([]));
fixture.detectChanges();
});
describe('create task', () => {
it('should create new task when start button is clicked', async () => {
const successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
await fixture.whenStable();
expect(createNewTaskSpy).toHaveBeenCalled();
expect(successSpy).toHaveBeenCalled();
});
it('should send on success event when the task is started', async () => {
const successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
component.assigneeName = 'fake-assignee';
fixture.detectChanges();
await fixture.whenStable();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
await fixture.whenStable();
expect(successSpy).toHaveBeenCalledWith(taskDetailsMock);
});
it('should send on success event when only name is given', async () => {
const successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
await fixture.whenStable();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
await fixture.whenStable();
expect(successSpy).toHaveBeenCalled();
});
it('should not emit success event when data not present', () => {
const successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('');
fixture.detectChanges();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
expect(createNewTaskSpy).not.toHaveBeenCalled();
expect(successSpy).not.toHaveBeenCalled();
});
it('should not start task to the logged in user when invalid assignee is selected', (done) => {
component.taskForm.controls['name'].setValue('fakeName');
component.appName = 'fakeAppName';
fixture.detectChanges();
const assigneeInput = element.querySelector<HTMLElement>('input.adf-cloud-input');
assigneeInput.nodeValue = 'a';
fixture.detectChanges();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
const taskRequest = new StartTaskCloudRequestModel({ name: 'fakeName', assignee: 'currentUser', candidateGroups: [] });
expect(createNewTaskSpy).toHaveBeenCalledWith(taskRequest, 'fakeAppName');
done();
});
});
it('should not start task to the logged in user when assignee is not selected', (done) => {
component.taskForm.controls['name'].setValue('fakeName');
component.appName = 'fakeAppName';
fixture.detectChanges();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
const taskRequest = new StartTaskCloudRequestModel({ name: 'fakeName', assignee: 'currentUser', candidateGroups: [] });
expect(createNewTaskSpy).toHaveBeenCalledWith(taskRequest, 'fakeAppName');
done();
});
});
});
it('should show logged in user as assignee by default', () => {
fixture.detectChanges();
const assignee = fixture.nativeElement.querySelector('[data-automation-id="adf-people-cloud-chip-currentUser"]');
expect(assignee).toBeDefined();
expect(assignee.innerText).toContain('Test User');
});
it('should show start task button', () => {
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
const startButton = element.querySelector('#button-start');
expect(startButton).toBeDefined();
expect(startButton.textContent).toContain('ADF_CLOUD_TASK_LIST.START_TASK.FORM.ACTION.START');
});
it('should disable start button if name is empty', () => {
component.taskForm.controls['name'].setValue('');
fixture.detectChanges();
const createTaskButton = fixture.nativeElement.querySelector('#button-start');
expect(createTaskButton.disabled).toBeTruthy();
});
it('should cancel start task on cancel button click', () => {
fixture.detectChanges();
const emitSpy = spyOn(component.cancel, 'emit');
const cancelTaskButton = fixture.nativeElement.querySelector('#button-cancel');
cancelTaskButton.click();
expect(emitSpy).not.toBeNull();
expect(emitSpy).toHaveBeenCalled();
});
it('should enable start button if name is filled out', () => {
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
const createTaskButton = fixture.nativeElement.querySelector('#button-start');
expect(createTaskButton.disabled).toBeFalsy();
});
it('should emit error when there is an error while creating task', () => {
component.taskForm.controls['name'].setValue('fakeName');
const errorSpy = spyOn(component.error, 'emit');
createNewTaskSpy.and.returnValue(throwError({}));
component.appName = 'fakeAppName';
fixture.detectChanges();
const assigneeInput = element.querySelector<HTMLElement>('input.adf-cloud-input');
assigneeInput.nodeValue = 'a';
fixture.detectChanges();
const createTaskButton = element.querySelector<HTMLElement>('#button-start');
createTaskButton.click();
fixture.detectChanges();
expect(errorSpy).toHaveBeenCalled();
});
it('should emit error when task name exceeds maximum length', () => {
component.maxNameLength = 2;
component.ngOnInit();
fixture.detectChanges();
const name = component.taskForm.controls['name'];
name.setValue('task');
fixture.detectChanges();
expect(name.valid).toBeFalsy();
name.setValue('ta');
fixture.detectChanges();
expect(name.valid).toBeTruthy();
});
it('should emit error when task name field is empty', () => {
fixture.detectChanges();
const name = component.taskForm.controls['name'];
name.setValue('');
fixture.detectChanges();
expect(name.valid).toBeFalsy();
name.setValue('task');
fixture.detectChanges();
expect(name.valid).toBeTruthy();
});
it('should emit error when description have only white spaces', () => {
fixture.detectChanges();
const description = component.taskForm.controls['description'];
description.setValue(' ');
fixture.detectChanges();
expect(description.valid).toBeFalsy();
description.setValue('');
fixture.detectChanges();
expect(description.valid).toBeTruthy();
});
});

View File

@ -1,234 +0,0 @@
/*!
* @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, DestroyRef, EventEmitter, inject, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { Observable } from 'rxjs';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { DateFnsUtils, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
import { PeopleCloudComponent } from '../../../people/components/people-cloud.component';
import { GroupCloudComponent } from '../../../group/components/group-cloud.component';
import { TaskCloudService } from '../../services/task-cloud.service';
import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
import { TaskPriorityOption } from '../../models/task.model';
import { IdentityUserService } from '../../../people/services/identity-user.service';
import { IdentityUserModel } from '../../../people/models/identity-user.model';
import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter';
import { isValid, parse } from 'date-fns';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
const MAX_NAME_LENGTH = 255;
const DATE_FORMAT: string = 'dd/MM/yyyy';
@Component({
selector: 'adf-cloud-start-task',
templateUrl: './start-task-cloud.component.html',
styleUrls: ['./start-task-cloud.component.scss'],
providers: [
{ provide: DateAdapter, useClass: DateFnsAdapter },
{ provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS }
],
encapsulation: ViewEncapsulation.None
})
export class StartTaskCloudComponent implements OnInit {
/** (required) Name of the app. */
@Input()
appName: string = '';
/** Maximum length of the task name. */
@Input()
maxNameLength: number = MAX_NAME_LENGTH;
/** Name of the task. */
@Input()
name: string = '';
/** Emitted when the task is successfully created. */
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
/** Emitted when the cancel button is clicked by the user. */
@Output()
cancel: EventEmitter<void> = new EventEmitter<void>();
/** Emitted when an error occurs. */
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
@ViewChild('peopleInput')
assignee: PeopleCloudComponent;
@ViewChild('groupInput')
candidateGroups: GroupCloudComponent;
users$: Observable<any[]>;
taskId: string;
dueDate: Date;
submitted = false;
assigneeName: string;
candidateGroupNames: string[] = [];
dateError: boolean;
taskForm: UntypedFormGroup;
currentUser: IdentityUserModel;
formKey: string;
priorities: TaskPriorityOption[];
private assigneeForm = new UntypedFormControl('');
private groupForm = new UntypedFormControl('');
private readonly destroyRef = inject(DestroyRef);
constructor(
private taskService: TaskCloudService,
private dateAdapter: DateAdapter<DateFnsAdapter>,
private userPreferencesService: UserPreferencesService,
private formBuilder: UntypedFormBuilder,
private identityUserService: IdentityUserService
) {}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((locale) => this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale)));
this.loadCurrentUser();
this.buildForm();
this.loadDefaultPriorities();
}
buildForm() {
this.taskForm = this.formBuilder.group({
name: new UntypedFormControl(this.name, [Validators.required, Validators.maxLength(this.getMaxNameLength()), this.whitespaceValidator]),
priority: new UntypedFormControl(''),
description: new UntypedFormControl('', [this.whitespaceValidator]),
formKey: new UntypedFormControl()
});
}
private getMaxNameLength(): number {
return this.maxNameLength > MAX_NAME_LENGTH ? MAX_NAME_LENGTH : this.maxNameLength;
}
private loadCurrentUser() {
this.currentUser = this.identityUserService.getCurrentUserInfo();
this.assigneeName = this.currentUser.username;
}
private loadDefaultPriorities() {
this.priorities = this.taskService.priorities;
}
public saveTask() {
this.submitted = true;
const newTask = Object.assign(this.taskForm.value);
newTask.dueDate = this.dueDate;
newTask.assignee = this.assigneeName;
newTask.formKey = this.formKey;
newTask.candidateGroups = this.candidateGroupNames;
this.createNewTask(new StartTaskCloudRequestModel(newTask));
}
private createNewTask(newTask: StartTaskCloudRequestModel) {
this.taskService.createNewTask(newTask, this.appName).subscribe(
(res: any) => {
this.submitted = false;
this.success.emit(res);
},
(err) => {
this.submitted = false;
this.error.emit(err);
}
);
}
public onCancel() {
this.cancel.emit();
}
onDateChanged(newDateValue) {
this.dateError = false;
if (newDateValue) {
const date = parse(newDateValue, DATE_FORMAT, new Date());
if (!isValid(date)) {
this.dateError = true;
}
}
}
onAssigneeSelect(assignee: IdentityUserModel) {
this.assigneeName = assignee ? assignee.username : '';
}
onAssigneeRemove() {
this.assigneeName = '';
}
onCandidateGroupSelect(candidateGroup: any) {
if (candidateGroup.name) {
this.candidateGroupNames.push(candidateGroup.name);
}
}
onCandidateGroupRemove(candidateGroup: any) {
if (candidateGroup.name) {
this.candidateGroupNames = this.candidateGroupNames.filter((name: string) => name !== candidateGroup.name);
}
}
canStartTask(): boolean {
return !(this.dateError || !this.taskForm.valid || this.submitted || this.assignee.hasError() || this.candidateGroups.hasError());
}
public whitespaceValidator(control: UntypedFormControl) {
const isWhitespace = (control.value || '').trim().length === 0;
const isControlValid = control.value.length === 0 || !isWhitespace;
return isControlValid ? null : { whitespace: true };
}
get nameController(): UntypedFormControl {
return this.taskForm.get('name') as UntypedFormControl;
}
get priorityController(): UntypedFormControl {
return this.taskForm.get('priority') as UntypedFormControl;
}
get assigneeFormControl(): UntypedFormControl {
return this.assigneeForm;
}
get candidateUserFormControl(): UntypedFormControl {
return this.groupForm;
}
onFormSelect(formKey: string) {
this.formKey = formKey || '';
}
}

View File

@ -1,20 +0,0 @@
/*!
* @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 { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
export const taskDetailsMock = new StartTaskCloudRequestModel({ assignee: 'fake-assigne', name: 'fake-name' });

View File

@ -1,20 +0,0 @@
/*!
* @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 const cloudMockUser = {
id: 'fake-id-1', username: 'AssignedTaskUser', firstName: 'first-name-1', lastName: 'last-name-1', email: 'abc@xyz.com'
};

View File

@ -16,5 +16,3 @@
*/
export * from './models/task-details-cloud.model';
export * from './components/start-task-cloud.component';
export * from './start-task-cloud.module';

View File

@ -1,66 +0,0 @@
/*!
* @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 { of, throwError } from 'rxjs';
import { taskDetailsMock } from '../mock/task-details.mock';
import { TaskDetailsCloudModel } from '../models/task-details-cloud.model';
import { HttpErrorResponse } from '@angular/common/http';
import { TaskCloudService } from '../../services/task-cloud.service';
import { ProcessServiceCloudTestingModule } from './../../../testing/process-service-cloud.testing.module';
describe('StartTaskCloudService', () => {
let service: TaskCloudService;
const fakeAppName: string = 'fake-app';
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule]
});
service = TestBed.inject(TaskCloudService);
});
it('should able to create a new task ', (done) => {
spyOn(service, 'createNewTask').and.returnValue(of({ id: 'fake-id', name: 'fake-name' }));
service.createNewTask(taskDetailsMock, fakeAppName).subscribe((res: TaskDetailsCloudModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual('fake-id');
expect(res.name).toEqual('fake-name');
done();
});
});
it('Should not able to create a task if error occurred', () => {
const errorResponse = new HttpErrorResponse({
error: 'Mock Error',
status: 404,
statusText: 'Not Found'
});
spyOn(service, 'createNewTask').and.returnValue(throwError(errorResponse));
service.createNewTask(taskDetailsMock, fakeAppName).subscribe(
() => {
fail('expected an error, not applications');
},
(error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
}
);
});
});

View File

@ -1,45 +0,0 @@
/*!
* @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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MaterialModule } from '../../material.module';
import { CoreModule } from '@alfresco/adf-core';
import { StartTaskCloudComponent } from './components/start-task-cloud.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { GroupCloudModule } from '../../group/group-cloud.module';
import { FormCloudModule } from '../../form/form-cloud.module';
import { PeopleCloudModule } from '../../people/people-cloud.module';
@NgModule({
imports: [
CommonModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
GroupCloudModule,
CoreModule,
FormCloudModule,
PeopleCloudModule
],
declarations: [StartTaskCloudComponent],
exports: [
StartTaskCloudComponent
]
})
export class StartTaskCloudModule {
}

View File

@ -18,27 +18,12 @@
import { NgModule } from '@angular/core';
import { TaskListCloudModule } from './task-list/task-list-cloud.module';
import { TaskFiltersCloudModule } from './task-filters/task-filters-cloud.module';
import { StartTaskCloudModule } from './start-task/start-task-cloud.module';
import { TaskHeaderCloudModule } from './task-header/task-header-cloud.module';
import { TaskDirectiveModule } from './directives/task-directive.module';
import { TASK_DIRECTIVES } from './directives/task-directive.module';
import { TaskFormModule } from './task-form/task-form.module';
import { TaskHeaderCloudComponent } from './task-header/components/task-header-cloud.component';
@NgModule({
imports: [
TaskListCloudModule,
TaskFiltersCloudModule,
StartTaskCloudModule,
TaskHeaderCloudModule,
TaskDirectiveModule,
TaskFormModule
],
exports: [
TaskListCloudModule,
TaskFiltersCloudModule,
StartTaskCloudModule,
TaskHeaderCloudModule,
TaskDirectiveModule,
TaskFormModule
]
imports: [TaskListCloudModule, TaskFiltersCloudModule, TaskHeaderCloudComponent, ...TASK_DIRECTIVES, TaskFormModule],
exports: [TaskListCloudModule, TaskFiltersCloudModule, TaskHeaderCloudComponent, ...TASK_DIRECTIVES, TaskFormModule]
})
export class TaskCloudModule {}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { FORM_FIELD_VALIDATORS, FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core';
import { FORM_FIELD_VALIDATORS, FormFieldModel, FormFieldValidator, FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core';
import { FormCustomOutcomesComponent } from '@alfresco/adf-process-services-cloud';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
@ -32,7 +32,6 @@ import {
TASK_VIEW_PERMISSION,
TaskDetailsCloudModel
} from '../../../start-task/models/task-details-cloud.model';
import { MockFormFieldValidator } from '../../mocks/task-form-cloud.mock';
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
import { TaskFormCloudComponent } from './task-form-cloud.component';
@ -52,6 +51,16 @@ const taskDetails: TaskDetailsCloudModel = {
permissions: [TASK_VIEW_PERMISSION]
};
class MockFormFieldValidator implements FormFieldValidator {
isSupported(_field: FormFieldModel): boolean {
return true;
}
validate(_field: FormFieldModel): boolean {
return true;
}
}
describe('TaskFormCloudComponent', () => {
let taskCloudService: TaskCloudService;
let identityUserService: IdentityUserService;

View File

@ -1,29 +0,0 @@
/*!
* @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 {
appName: string;
taskId: string;
screenId: string;
error: EventEmitter<any>;
cancelClick: EventEmitter<string>;
taskClaimed: EventEmitter<string>;
taskUnclaimed: EventEmitter<string>;
taskCompleted: EventEmitter<string>;
}

View File

@ -1,28 +0,0 @@
/*!
* @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 { FormFieldModel, FormFieldValidator } from '@alfresco/adf-core';
export class MockFormFieldValidator implements FormFieldValidator {
isSupported(_field: FormFieldModel): boolean {
return true;
}
validate(_field: FormFieldModel): boolean {
return true;
}
}

View File

@ -19,7 +19,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MaterialModule } from '../../material.module';
import { FormCloudModule } from '../../form/form-cloud.module';
import { TaskDirectiveModule } from '../directives/task-directive.module';
import { TASK_DIRECTIVES } from '../directives/task-directive.module';
import { TaskFormCloudComponent } from './components/task-form-cloud/task-form-cloud.component';
import { CoreModule } from '@alfresco/adf-core';
import { TaskScreenCloudComponent } from '../../screen/components/screen-cloud/screen-cloud.component';
@ -27,7 +27,7 @@ import { UserTaskCloudComponent } from './components/user-task-cloud/user-task-c
import { UserTaskCloudButtonsComponent } from './components/user-task-cloud-buttons/user-task-cloud-buttons.component';
@NgModule({
imports: [CoreModule, CommonModule, MaterialModule, FormCloudModule, TaskDirectiveModule, TaskScreenCloudComponent],
imports: [CoreModule, CommonModule, MaterialModule, FormCloudModule, ...TASK_DIRECTIVES, TaskScreenCloudComponent],
declarations: [TaskFormCloudComponent, UserTaskCloudComponent, UserTaskCloudButtonsComponent],
exports: [TaskFormCloudComponent, UserTaskCloudComponent]
})

View File

@ -23,7 +23,6 @@ import { AlfrescoApiService } from '@alfresco/adf-content-services';
import { AppConfigService } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { TaskCloudService } from '../../services/task-cloud.service';
import { TaskHeaderCloudModule } from '../task-header-cloud.module';
import {
assignedTaskDetailsCloudMock,
completedTaskDetailsCloudMock,
@ -32,7 +31,6 @@ import {
taskDetailsWithParentTaskIdMock,
createdTaskDetailsCloudMock
} from '../mocks/task-details-cloud.mock';
import { MatSelectModule } from '@angular/material/select';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSelectHarness } from '@angular/material/select/testing';
@ -62,7 +60,7 @@ describe('TaskHeaderCloudComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, TaskHeaderCloudModule, MatSelectModule]
imports: [ProcessServiceCloudTestingModule, TaskHeaderCloudComponent]
});
appConfigService = TestBed.inject(AppConfigService);
appConfigService.config = {

View File

@ -16,7 +16,6 @@
*/
import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular';
import { TaskHeaderCloudModule } from '../task-header-cloud.module';
import { TaskHeaderCloudComponent } from './task-header-cloud.component';
import { TaskCloudService } from '../../services/task-cloud.service';
import { TaskCloudServiceMock } from '../../mock/task-cloud.service.mock';
@ -28,7 +27,7 @@ export default {
title: 'Process Services Cloud/Task Cloud/Task Header Cloud/Task Header Cloud',
decorators: [
moduleMetadata({
imports: [TaskHeaderCloudModule],
imports: [TaskHeaderCloudComponent],
providers: [{ provide: TaskCloudService, useClass: TaskCloudServiceMock }]
}),
applicationConfig({

View File

@ -15,17 +15,7 @@
* limitations under the License.
*/
import {
Component,
DestroyRef,
EventEmitter,
inject,
Input,
OnChanges,
OnInit,
Output,
ViewEncapsulation
} from '@angular/core';
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { catchError, concatMap, finalize } from 'rxjs/operators';
import { forkJoin, of } from 'rxjs';
import {
@ -33,6 +23,7 @@ import {
CardViewArrayItem,
CardViewArrayItemModel,
CardViewBaseItemModel,
CardViewComponent,
CardViewDateItemModel,
CardViewDatetimeItemModel,
CardViewItem,
@ -45,15 +36,19 @@ import {
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
import { TaskCloudService } from '../../services/task-cloud.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatCardModule } from '@angular/material/card';
@Component({
selector: 'adf-cloud-task-header',
standalone: true,
imports: [CommonModule, MatProgressSpinnerModule, CardViewComponent, MatCardModule],
templateUrl: './task-header-cloud.component.html',
styleUrls: ['./task-header-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TaskHeaderCloudComponent implements OnInit, OnChanges {
/** (Required) The name of the application. */
@Input()
appName: string = '';
@ -103,16 +98,11 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
}
ngOnInit() {
this.taskCloudService.dataChangesDetected$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.taskCloudService.dataChangesDetected$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
this.loadTaskDetailsById(this.appName, this.taskId);
});
this.cardViewUpdateService.itemUpdated$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(this.updateTaskDetails.bind(this)
);
this.cardViewUpdateService.itemUpdated$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.updateTaskDetails.bind(this));
}
ngOnChanges() {
@ -126,7 +116,9 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
loadTaskDetailsById(appName: string, taskId: string) {
this.isLoading = true;
this.taskCloudService.getTaskById(appName, taskId).pipe(
this.taskCloudService
.getTaskById(appName, taskId)
.pipe(
concatMap((task) =>
forkJoin(
of(task),
@ -135,7 +127,9 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
)
),
finalize(() => (this.isLoading = false))
).subscribe(([taskDetails, candidateUsers, candidateGroups]) => {
)
.subscribe(
([taskDetails, candidateUsers, candidateGroups]) => {
this.taskDetails = taskDetails;
this.candidateGroups = candidateGroups.map((user) => ({ icon: 'group', value: user } as CardViewArrayItem));
this.candidateUsers = candidateUsers.map((group) => ({ icon: 'person', value: group } as CardViewArrayItem));
@ -148,40 +142,34 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
},
(err) => {
this.error.emit(err);
});
}
);
}
private initDefaultProperties() {
return [
new CardViewTextItemModel(
{
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.ASSIGNEE',
value: this.taskDetails.assignee,
key: 'assignee',
clickable: this.isAssigneePropertyClickable(),
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.ASSIGNEE_DEFAULT'),
icon: 'create'
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.STATUS',
value: this.taskDetails.status,
key: 'status'
}
),
new CardViewSelectItemModel(
{
}),
new CardViewSelectItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.PRIORITY',
value: this.taskDetails.priority.toString(),
key: 'priority',
editable: true,
displayNoneOption: false,
options$: of(this.taskCloudService.priorities)
}
),
new CardViewDatetimeItemModel(
{
}),
new CardViewDatetimeItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.DUE_DATE',
value: this.taskDetails.dueDate,
key: 'dueDate',
@ -189,79 +177,61 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
editable: true,
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.CATEGORY',
value: this.taskDetails.category,
key: 'category',
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.CATEGORY_DEFAULT')
}
),
new CardViewDateItemModel(
{
}),
new CardViewDateItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.CREATED',
value: this.taskDetails.createdDate,
key: 'created',
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.PARENT_NAME',
value: this.parentTaskName,
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.PARENT_NAME_DEFAULT'),
key: 'parentName',
clickable: true
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.PARENT_TASK_ID',
value: this.taskDetails.parentTaskId,
key: 'parentTaskId',
clickable: true
}
),
new CardViewDateItemModel(
{
}),
new CardViewDateItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.END_DATE',
value: this.taskDetails.completedDate,
key: 'endDate',
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.ID',
value: this.taskDetails.id,
key: 'id'
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.PROCESS_INSTANCE_ID',
value: this.processInstanceId,
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.PROCESS_INSTANCE_ID_DEFAULT'),
key: 'processInstanceId',
clickable: true
}
),
new CardViewTextItemModel(
{
}),
new CardViewTextItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.DESCRIPTION',
value: this.taskDetails.description,
key: 'description',
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.DESCRIPTION_DEFAULT'),
multiline: true,
editable: true
}
),
new CardViewArrayItemModel(
{
}),
new CardViewArrayItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.CANDIDATE_USERS',
value: of(this.candidateUsers),
key: 'candidateUsers',
@ -269,10 +239,8 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
clickable: false,
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.CANDIDATE_USERS_DEFAULT'),
noOfItemsToDisplay: 2
}
),
new CardViewArrayItemModel(
{
}),
new CardViewArrayItemModel({
label: 'ADF_CLOUD_TASK_HEADER.PROPERTIES.CANDIDATE_GROUPS',
value: of(this.candidateGroups),
key: 'candidateGroups',
@ -280,8 +248,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
clickable: false,
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.CANDIDATE_GROUPS_DEFAULT'),
noOfItemsToDisplay: 2
}
)
})
];
}
@ -302,11 +269,14 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
* @param updateNotification notification model
*/
private updateTaskDetails(updateNotification: UpdateNotification) {
this.taskCloudService.updateTask(this.appName, this.taskId, updateNotification.changed)
.pipe(catchError(() => {
this.taskCloudService
.updateTask(this.appName, this.taskId, updateNotification.changed)
.pipe(
catchError(() => {
this.cardViewUpdateService.updateElement(updateNotification.target);
return of(null);
}))
})
)
.subscribe((taskDetails) => {
if (taskDetails) {
this.taskDetails = taskDetails;
@ -315,13 +285,10 @@ export class TaskHeaderCloudComponent implements OnInit, OnChanges {
}
private loadParentName(taskId: string) {
this.taskCloudService.getTaskById(this.appName, taskId)
.subscribe(
(taskDetails) => {
this.taskCloudService.getTaskById(this.appName, taskId).subscribe((taskDetails) => {
this.parentTaskName = taskDetails.name;
this.refreshData();
}
);
});
}
isCompleted(): boolean {

View File

@ -1,42 +0,0 @@
/*!
* @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 const fakeTaskDetailsCloud = {
entry: {
appName: 'task-app',
appVersion: '',
id: '68d54a8f',
assignee: 'Phil Woods',
name: 'This is a new task',
description: 'This is the description ',
createdDate: 1545048055900,
dueDate: 1545091200000,
claimedDate: 1545140162601,
priority: 0,
category: null,
processDefinitionId: null,
processInstanceId: null,
status: 'ASSIGNED',
owner: 'Phil Woods',
parentTaskId: null,
formKey: null,
lastModified: 1545140162601,
lastModifiedTo: null,
lastModifiedFrom: null,
standalone: true
}
};

View File

@ -16,22 +16,11 @@
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MaterialModule } from '../../material.module';
import { CoreModule } from '@alfresco/adf-core';
import { TaskHeaderCloudComponent } from './components/task-header-cloud.component';
/** @deprecated use TaskHeaderCloudComponent standalone component */
@NgModule({
imports: [
CommonModule,
MaterialModule,
CoreModule.forChild()
],
declarations: [
TaskHeaderCloudComponent
],
exports: [
TaskHeaderCloudComponent
]
imports: [TaskHeaderCloudComponent],
exports: [TaskHeaderCloudComponent]
})
export class TaskHeaderCloudModule {}

View File

@ -1,39 +0,0 @@
/*!
* @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 { NgModule } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { TaskListCloudModule } from '../task-list-cloud.module';
import {
AppConfigService,
AppConfigServiceMock,
TranslationService,
TranslationMock,
CONTEXT_MENU_DIRECTIVES
} from '@alfresco/adf-core';
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
@NgModule({
imports: [HttpClientModule, NoopAnimationsModule, TaskListCloudModule, ...CONTEXT_MENU_DIRECTIVES],
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
]
})
export class TaskListTestingModule {}