[ADF-4127] ProcessServicesCloud - add claim/unclaim directive (#4464)

* [ADF-4127] ProessServicesCloud - claim task directive

* [ADF-4127] - fix doc

* [ADF-4127] - revert docs changes

* [ADF-4127] - revert doc changes

* [ADF-4127] - fix doc and reset sourceLinker.js

* [ADF-4127] - refractor task-cloud.service. add validation for claim/unclaim and fix unit tests

* [ADF-4127] - fix docs files

* [ADF-4127[ - add aditional complete task validation

* [ADF-4127] - PR changes

* [ADF-4127] - complete docs file

* [ADF-4127] - more PR changes

* [ADF-4127] - change Unclaim task name and wait for task to be claimed and unclaimed before emit the success event

* [ADF-4127] - fix unit tests
This commit is contained in:
Silviu Popa
2019-03-25 14:24:26 +02:00
committed by Maurizio Vitale
parent 0b1e5d31d8
commit 31658c0974
26 changed files with 949 additions and 280 deletions

View File

@@ -4,7 +4,13 @@
<div class="adf-task-control">
<button mat-button (click)="goBack()">Cancel</button>
<button mat-button color="primary" *ngIf="canCompleteTask()" adf-cloud-complete-task [appName]="appName" [taskId]="taskId"
(success)="onCompletedTask($event)">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE' | translate }}</button>
(success)="onCompletedTask()">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE' | translate }}</button>
<button mat-button color="primary" *ngIf="canClaimTask()" adf-cloud-claim-task [appName]="appName" [taskId]="taskId"
(success)="onClaimTask()">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.CLAIM' | translate }}</button>
<button mat-button color="primary" *ngIf="canUnClaimTask()" adf-cloud-unclaim-task [appName]="appName" [taskId]="taskId"
(success)="onUnclaimTask()">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.UNCLAIM' | translate }}</button>
</div>
<adf-cloud-task-header class="adf-demop-card-container" [appName]="appName" [taskId]="taskId" [readOnly]="readOnly">

View File

@@ -17,7 +17,7 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { TaskCloudService, TaskDetailsCloudModel } from '@alfresco/adf-process-services-cloud';
import { TaskDetailsCloudModel, TaskCloudService } from '@alfresco/adf-process-services-cloud';
@Component({
templateUrl: './task-details-cloud-demo.component.html',
@@ -47,26 +47,42 @@ export class TaskDetailsCloudDemoComponent implements OnInit {
this.loadTaskDetailsById(this.appName, this.taskId);
}
loadTaskDetailsById(appName: string, taskId: string): any {
loadTaskDetailsById(appName: string, taskId: string) {
this.taskCloudService.getTaskById(appName, taskId).subscribe(
(taskDetails) => {
(taskDetails: TaskDetailsCloudModel ) => {
this.taskDetails = taskDetails;
});
}
isTaskValid() {
return this.appName && this.taskId;
isTaskValid(): boolean {
return this.appName !== undefined && this.taskId !== undefined;
}
canCompleteTask() {
canCompleteTask(): boolean {
return this.taskDetails && this.taskCloudService.canCompleteTask(this.taskDetails);
}
canClaimTask(): boolean {
return this.taskDetails && this.taskCloudService.canClaimTask(this.taskDetails);
}
canUnClaimTask(): boolean {
return this.taskDetails && this.taskCloudService.canUnclaimTask(this.taskDetails);
}
goBack() {
this.router.navigate([`/cloud/${this.appName}/`]);
}
onCompletedTask(evt: any) {
onCompletedTask() {
this.goBack();
}
onUnclaimTask() {
this.goBack();
}
onClaimTask() {
this.goBack();
}
}

View File

@@ -0,0 +1,26 @@
---
Title: Claim Task Directive
Added: v3.1.0
Status: Experimental
Last reviewed: 2019-03-05
---
# [Claim task directive](../../lib/process-services-cloud/src/lib/task/directives/claim-task.directive.ts "Defined in claim-task.directive.ts")
Claim a task
## Basic Usage
```html
<button adf-claim-task [appName]="appName" [taskId]="taskId" (success)="onTaskClaimed()">Complete</button>
```
## Class members
### Properties
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| taskId | `string` | empty |(Required) The id of the task. |
| appName | `string` | empty | (Required) The name of the application. |
| success | `EventEmitter<any>` | empty | Emitted when the task is completed. |
| error | `EventEmitter<any>` | empty | Emitted when the task cannot be completed. |

View File

@@ -17,33 +17,41 @@ Manages task cloud.
Validate if a task can be completed.
- _taskDetails:_ [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts) - task details object
- **Returns** `boolean` - Boolean value if the task can be completed
- **completeTask**(appName: `string`, taskId: `string`)<br/>
Complete a task
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task to complete
- **Returns** [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts) - Details of the task that was completed
- **canClaimTask**(taskDetails: [`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-filters/models/task-details-cloud.model.ts))<br/>
Validate if a task can be claimed.
- _taskDetails:_ [`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-filters/models/task-details-cloud.model.ts) - Task details object
- **Returns** `boolean` - Boolean value if the task can be claimed
- **canUnclaimTask**(taskDetails: [`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-filters/models/task-details-cloud.model.ts))<br/>
Validate if a task can be unclaimed.
- _taskDetails:_ [`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-filters/models/task-details-cloud.model.ts) - Task details object
- **Returns** `boolean` - Boolean value if the task can be unclaimed
- **claimTask**(appName: `string`, taskId: `string`, assignee: `string`): `any`<br/>
Claims a task for an assignee.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task to claim
- _assignee:_ `string` - User to assign the task to
- **Returns** `any` - Details of the claimed task
- **completeTask**(appName: `string`, taskId: `string`): `any`<br/>
Complete a task.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task to complete
- **Returns** `any` - Details of the task that was completed
- **getTaskById**(appName: `string`, taskId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>`<br/>
Gets details of a task.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task whose details you want
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>` - Task details
- **Returns** [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts) - Details of the claimed task
- **unclaimTask**(appName: `string`, taskId: `string`): `any`<br/>
Un-claims a task.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task to unclaim
- **Returns** `any` - Details of the task that was unclaimed
- **Returns** [`TaskDetailsCloudModel`](../../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts) - Details of the task that was unclaimed
- **getTaskById**(appName: `string`, taskId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>`<br/>
Gets details of a task.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task whose details you want
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>` - Task details
- **updateTask**(appName: `string`, taskId: `string`, updatePayload: `any`): `any`<br/>
Updates the details (name, description, due date) for a task.
- _appName:_ `string` - Name of the app
- _taskId:_ `string` - ID of the task to update
- _updatePayload:_ `any` - Data to update the task
- **Returns** `any` - Updated task details
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TaskDetailsCloudModel`](../../lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts)`>` - Updated task details
## Details

View File

@@ -0,0 +1,26 @@
---
Title: Unclaim Task Directive
Added: v3.1.0
Status: Experimental
Last reviewed: 2019-03-05
---
# [Unclaim task directive](../../lib/process-services-cloud/src/lib/task/directives/unclaim-task.directive.ts "Defined in unclaim-task.directive.ts")
Unclaim a task
## Basic Usage
```html
<button adf-unclaim-task [appName]="appName" [taskId]="taskId" (success)="onTaskUnclaimed()">Complete</button>
```
## Class members
### Properties
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| taskId | `string` | empty |(Required) The id of the task. |
| appName | `string` | empty | (Required) The name of the application. |
| success | `EventEmitter<any>` | empty | Emitted when the task is completed. |
| error | `EventEmitter<any>` | empty | Emitted when the task cannot be completed. |

View File

@@ -174,7 +174,7 @@
"ADF_CLOUD_TASK_HEADER": {
"BUTTON": {
"CLAIM": "Claim",
"UNCLAIM": "Requeue"
"UNCLAIM": "Release"
},
"PROPERTIES": {
"TASK_NAME": "Task",

View File

@@ -0,0 +1,167 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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, ContentChildren, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { setupTestBed, CoreModule } from '@alfresco/adf-core';
import { TaskCloudService } from '../services/task-cloud.service';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { ClaimTaskDirective } from './claim-task.directive';
import { taskClaimCloudMock } from '../task-header/mocks/fake-claim-task.mock';
describe('ClaimTaskDirective', () => {
@Component({
selector: 'adf-claim-test-component',
template: '<button adf-cloud-claim-task [taskId]="taskMock" [appName]="appNameMock" (success)="onClaimTask($event)"></button>'
})
class TestComponent {
taskMock = 'test1234';
appNameMock = 'simple-app';
@ViewChild(ClaimTaskDirective)
claimTaskDirective: ClaimTaskDirective;
onCompleteTask(event: any) {
return event;
}
}
let fixture: ComponentFixture<TestComponent>;
let taskCloudService: TaskCloudService;
setupTestBed({
imports: [
CoreModule.forRoot(),
RouterTestingModule
],
declarations: [
TestComponent,
ClaimTaskDirective
]
});
beforeEach(() => {
taskCloudService = TestBed.get(TaskCloudService);
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
it('should directive claim task', () => {
spyOn(taskCloudService, 'claimTask').and.returnValue(of(taskClaimCloudMock));
const button = fixture.nativeElement.querySelector('button');
button.click();
expect(taskCloudService.claimTask).toHaveBeenCalled();
});
});
describe('Claim Task Directive validation errors', () => {
@Component({
selector: 'adf-claim-no-fields-validation-component',
template: '<button adf-cloud-claim-task></button>'
})
class ClaimTestMissingInputDirectiveComponent {
appName = 'simple-app';
appNameUndefined = undefined;
appNameNull = null;
@ContentChildren(ClaimTaskDirective)
claimTaskValidationDirective: ClaimTaskDirective;
}
@Component({
selector: 'adf-claim-no-taskid-validation-component',
template: '<button adf-cloud-claim-task [appName]="appName"></button>'
})
class ClaimTestMissingTaskIdDirectiveComponent {
appName = 'simple-app';
@ContentChildren(ClaimTaskDirective)
claimTaskValidationDirective: ClaimTaskDirective;
}
@Component({
selector: 'adf-claim-undefined-appname-component',
template: '<button adf-cloud-claim-task [taskId]="taskMock" [appName]="appNameUndefined"></button>'
})
class ClaimTestInvalidAppNameUndefineddDirectiveComponent {
appNameUndefined = undefined;
taskMock = 'test1234';
@ContentChildren(ClaimTaskDirective)
claimTaskValidationDirective: ClaimTaskDirective;
}
@Component({
selector: 'adf-claim-null-appname-component',
template: '<button adf-cloud-claim-task [taskId]="taskMock" [appName]="appNameNull"></button>'
})
class ClaimTestInvalidAppNameNulldDirectiveComponent {
appNameNull = null;
taskMock = 'test1234';
@ViewChild(ClaimTaskDirective)
claimTaskValidationDirective: ClaimTaskDirective;
}
let fixture: ComponentFixture<any>;
setupTestBed({
imports: [
CoreModule.forRoot(),
RouterTestingModule
],
declarations: [
ClaimTestMissingTaskIdDirectiveComponent,
ClaimTestInvalidAppNameUndefineddDirectiveComponent,
ClaimTestInvalidAppNameNulldDirectiveComponent,
ClaimTestMissingInputDirectiveComponent,
ClaimTaskDirective
]
});
beforeEach(() => {
fixture = TestBed.createComponent(ClaimTestMissingInputDirectiveComponent);
});
it('should throw error when missing input', () => {
fixture = TestBed.createComponent(ClaimTestMissingInputDirectiveComponent);
expect(() => fixture.detectChanges()).toThrowError();
});
it('should throw error when taskId is not set', () => {
fixture = TestBed.createComponent(ClaimTestMissingTaskIdDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute taskId is required');
});
it('should throw error when appName is undefined', () => {
fixture = TestBed.createComponent(ClaimTestInvalidAppNameUndefineddDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute appName is required');
});
it('should throw error when appName is null', () => {
fixture = TestBed.createComponent(ClaimTestInvalidAppNameUndefineddDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute appName is required');
});
});

View File

@@ -0,0 +1,94 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Directive, Input, HostListener, Output, EventEmitter, OnInit } from '@angular/core';
import { IdentityUserService } from '@alfresco/adf-core';
import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
selector: '[adf-cloud-claim-task]'
})
export class ClaimTaskDirective implements OnInit {
/** (Required) The id of the task. */
@Input()
taskId: string;
/** (Required) The name of the application. */
@Input()
appName: string;
/** Emitted when the task is completed. */
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
/** Emitted when the task cannot be completed. */
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
invalidParams: string[] = [];
constructor(
private taskListService: TaskCloudService,
private identityUserService: IdentityUserService) { }
ngOnInit() {
this.validateInputs();
}
validateInputs() {
if (!this.isTaskValid()) {
this.invalidParams.push('taskId');
}
if (!this.isAppValid()) {
this.invalidParams.push('appName');
}
if (this.invalidParams.length) {
throw new Error(`Attribute ${this.invalidParams.join(', ')} is required`);
}
}
isTaskValid(): boolean {
return this.taskId && this.taskId.length > 0;
}
isAppValid(): boolean {
return this.appName && this.appName.length > 0;
}
@HostListener('click')
async onClick() {
try {
this.claimTask();
} catch (error) {
this.error.emit(error);
}
}
private async claimTask() {
const currentUser: string = this.identityUserService.getCurrentUserInfo().username;
try {
const result = await this.taskListService.claimTask(this.appName, this.taskId, currentUser).toPromise();
if (result) {
this.success.emit(result);
}
} catch (error) {
this.error.emit(error);
}
}
}

View File

@@ -20,8 +20,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule, setupTestBed } from '@alfresco/adf-core';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { TaskCloudService } from '../task-header/services/task-cloud.service';
import { taskCompleteCloudMock } from '../task-header/mocks/fake-complete-task.mock';
import { TaskCloudService } from '../services/task-cloud.service';
describe('CompleteTaskDirective', () => {

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Directive, Input, HostListener, Output, EventEmitter, OnInit } from '@angular/core';
import { TaskCloudService } from '../task-header/services/task-cloud.service';
import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
selector: '[adf-cloud-complete-task]'
@@ -59,11 +59,11 @@ export class CompleteTaskDirective implements OnInit {
}
}
isTaskValid() {
isTaskValid(): boolean {
return this.taskId && this.taskId.length > 0;
}
isAppValid() {
isAppValid(): boolean {
return this.appName && this.appName.length > 0;
}

View File

@@ -17,13 +17,19 @@
import { NgModule } from '@angular/core';
import { CompleteTaskDirective } from './complete-task.directive';
import { ClaimTaskDirective } from './claim-task.directive';
import { UnClaimTaskDirective } from './unclaim-task.directive';
@NgModule({
declarations: [
CompleteTaskDirective
CompleteTaskDirective,
ClaimTaskDirective,
UnClaimTaskDirective
],
exports: [
CompleteTaskDirective
CompleteTaskDirective,
ClaimTaskDirective,
UnClaimTaskDirective
]
})
export class TaskDirectiveModule { }

View File

@@ -0,0 +1,86 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Directive, Input, HostListener, Output, EventEmitter, OnInit } from '@angular/core';
import { TaskCloudService } from '../services/task-cloud.service';
@Directive({
selector: '[adf-cloud-unclaim-task]'
})
export class UnClaimTaskDirective implements OnInit {
/** (Required) The id of the task. */
@Input()
taskId: string;
/** (Required) The name of the application. */
@Input()
appName: string;
/** Emitted when the task is completed. */
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
/** Emitted when the task cannot be completed. */
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
invalidParams: string[] = [];
constructor(
private taskListService: TaskCloudService) { }
ngOnInit() {
this.validateInputs();
}
validateInputs() {
if (!this.isTaskValid()) {
this.invalidParams.push('taskId');
}
if (!this.isAppValid()) {
this.invalidParams.push('appName');
}
if (this.invalidParams.length) {
throw new Error(`Attribute ${this.invalidParams.join(', ')} is required`);
}
}
isTaskValid(): boolean {
return this.taskId && this.taskId.length > 0;
}
isAppValid(): boolean {
return this.appName && this.appName.length > 0;
}
@HostListener('click')
async onClick() {
try {
this.unclaimTask();
} catch (error) {
this.error.emit(error);
}
}
private async unclaimTask() {
await this.taskListService.unclaimTask(this.appName, this.taskId).subscribe(
() => {
this.success.emit(this.taskId);
});
}
}

View File

@@ -0,0 +1,164 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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, ContentChildren, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { setupTestBed, CoreModule } from '@alfresco/adf-core';
import { TaskCloudService } from '../services/task-cloud.service';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { UnClaimTaskDirective } from './unclaim-task.directive';
import { taskClaimCloudMock } from '../task-header/mocks/fake-claim-task.mock';
describe('UnClaimTaskDirective', () => {
@Component({
selector: 'adf-test-component',
template: '<button adf-cloud-unclaim-task [taskId]="taskIdMock" [appName]="appName"></button>'
})
class TestComponent {
appName = 'simple-app';
taskIdMock = '1234';
@ContentChildren(UnClaimTaskDirective)
unclaimTaskDirective: UnClaimTaskDirective;
}
let fixture: ComponentFixture<TestComponent>;
let taskCloudService: TaskCloudService;
setupTestBed({
imports: [
CoreModule.forRoot(),
RouterTestingModule
],
declarations: [
TestComponent,
UnClaimTaskDirective
],
providers: [ TaskCloudService ]
});
beforeEach(() => {
taskCloudService = TestBed.get(TaskCloudService);
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
it('should directive unclaim task', () => {
spyOn(taskCloudService, 'unclaimTask').and.returnValue(of(taskClaimCloudMock));
const button = fixture.nativeElement.querySelector('button');
button.click();
expect(taskCloudService.unclaimTask).toHaveBeenCalled();
});
});
describe('UnClaim Task Directive validation errors', () => {
@Component({
selector: 'adf-claim-no-fields-validation-component',
template: '<button adf-cloud-unclaim-task></button>'
})
class ClaimTestMissingInputDirectiveComponent {
appName = 'simple-app';
appNameUndefined = undefined;
appNameNull = null;
@ContentChildren(UnClaimTaskDirective)
claimTaskValidationDirective: UnClaimTaskDirective;
}
@Component({
selector: 'adf-claim-no-taskid-validation-component',
template: '<button adf-cloud-unclaim-task [appName]="appName"></button>'
})
class ClaimTestMissingTaskIdDirectiveComponent {
appName = 'simple-app';
@ContentChildren(UnClaimTaskDirective)
claimTaskValidationDirective: UnClaimTaskDirective;
}
@Component({
selector: 'adf-claim-undefined-appname-component',
template: '<button adf-cloud-unclaim-task [taskId]="taskMock" [appName]="appNameUndefined"></button>'
})
class ClaimTestInvalidAppNameUndefineddDirectiveComponent {
appNameUndefined = undefined;
taskMock = 'test1234';
@ContentChildren(UnClaimTaskDirective)
claimTaskValidationDirective: UnClaimTaskDirective;
}
@Component({
selector: 'adf-claim-null-appname-component',
template: '<button adf-cloud-unclaim-task [taskId]="taskMock" [appName]="appNameNull"></button>'
})
class ClaimTestInvalidAppNameNulldDirectiveComponent {
appNameNull = null;
taskMock = 'test1234';
@ViewChild(UnClaimTaskDirective)
claimTaskValidationDirective: UnClaimTaskDirective;
}
let fixture: ComponentFixture<any>;
setupTestBed({
imports: [
CoreModule.forRoot(),
RouterTestingModule
],
declarations: [
ClaimTestMissingTaskIdDirectiveComponent,
ClaimTestInvalidAppNameUndefineddDirectiveComponent,
ClaimTestInvalidAppNameNulldDirectiveComponent,
ClaimTestMissingInputDirectiveComponent,
UnClaimTaskDirective
]
});
beforeEach(() => {
fixture = TestBed.createComponent(ClaimTestMissingInputDirectiveComponent);
});
it('should throw error when missing input', () => {
fixture = TestBed.createComponent(ClaimTestMissingInputDirectiveComponent);
expect(() => fixture.detectChanges()).toThrowError();
});
it('should throw error when taskId is not set', () => {
fixture = TestBed.createComponent(ClaimTestMissingTaskIdDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute taskId is required');
});
it('should throw error when appName is undefined', () => {
fixture = TestBed.createComponent(ClaimTestInvalidAppNameUndefineddDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute appName is required');
});
it('should throw error when appName is null', () => {
fixture = TestBed.createComponent(ClaimTestInvalidAppNameUndefineddDirectiveComponent);
expect( () => fixture.detectChanges()).toThrowError('Attribute appName is required');
});
});

View File

@@ -0,0 +1,21 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 enum ClaimTaskEnum {
claim = 'claim',
unclaim = 'unclaim'
}

View File

@@ -22,3 +22,4 @@ export * from './task-header/public-api';
export * from './task-cloud.module';
export * from './directives/task-directive.module';
export * from './services/task-cloud.service';

View File

@@ -16,21 +16,19 @@
*/
import { async, TestBed } from '@angular/core/testing';
import { setupTestBed, IdentityUserService, IdentityUserModel, AlfrescoApiServiceMock } from '@alfresco/adf-core';
import { LogService, AppConfigService, StorageService, CoreModule } from '@alfresco/adf-core';
import { setupTestBed, IdentityUserService } from '@alfresco/adf-core';
import { AlfrescoApiServiceMock, LogService, AppConfigService, StorageService, CoreModule } from '@alfresco/adf-core';
import { TaskCloudService } from './task-cloud.service';
import { taskDetailsCloudMock } from '../mocks/task-details-cloud.mock';
import { taskCompleteCloudMock } from '../mocks/fake-complete-task.mock';
import { fakeTaskDetailsCloud } from '../mocks/fake-task-details-response.mock';
import { taskCompleteCloudMock } from '../task-header/mocks/fake-complete-task.mock';
import { taskDetailsCloudMock } 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';
describe('Task Cloud Service', () => {
let service: TaskCloudService;
let alfrescoApiMock: AlfrescoApiServiceMock;
let identityService: IdentityUserService;
let identityUserWithOutFirstNameMock = { firstName: null, lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com', username: 'superadminuser' };
let getCurrentUserInfoStub;
let fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutFirstNameMock);
let identityUserService: IdentityUserService;
function returnFakeTaskCompleteResults() {
return {
@@ -66,19 +64,17 @@ describe('Task Cloud Service', () => {
imports: [
CoreModule.forRoot()
],
providers: [IdentityUserService, LogService]
providers: [ IdentityUserService ]
});
beforeEach(async(() => {
identityService = TestBed.get(IdentityUserService);
getCurrentUserInfoStub = spyOn(identityService, 'getCurrentUserInfo');
getCurrentUserInfoStub.and.returnValue(fakeIdentityUser);
alfrescoApiMock = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService() );
identityUserService = TestBed.get(IdentityUserService);
spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(cloudMockUser);
service = new TaskCloudService(alfrescoApiMock,
new AppConfigService(null),
new LogService(new AppConfigService(null)),
identityService);
identityUserService);
}));
@@ -109,124 +105,7 @@ describe('Task Cloud Service', () => {
it('should canCompleteTask', () => {
const canCompleteTaskResult = service.canCompleteTask(taskDetailsCloudMock);
expect(canCompleteTaskResult).toBe(true);
});
it('should return the task details when querying by id', (done) => {
const appName = 'taskp-app';
const taskId = '68d54a8f';
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('task-app');
expect(res.id).toBe('68d54a8f');
done();
});
});
it('should throw error if appName is not defined when querying by id', (done) => {
const appName = null;
const taskId = '68d54a8f';
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined when querying by id', (done) => {
const appName = 'task-app';
const taskId = null;
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should return the task details when updating a task', (done) => {
const appName = 'taskp-app';
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('task-app');
expect(res.id).toBe('68d54a8f');
done();
});
});
it('should throw error if appName is not defined when updating a task', (done) => {
const appName = null;
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined when updating a task', (done) => {
const appName = 'task-app';
const taskId = null;
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should return the task details when updating a task', (done) => {
const appName = 'taskp-app';
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('task-app');
expect(res.id).toBe('68d54a8f');
done();
});
});
it('should throw error if appName is not defined when querying by id', (done) => {
const appName = null;
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined updating a task', (done) => {
const appName = 'task-app';
const taskId = null;
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
expect(canCompleteTaskResult).toBeTruthy();
});
it('should return the task details when claiming a task', (done) => {
@@ -305,4 +184,107 @@ describe('Task Cloud Service', () => {
done();
});
});
it('should return the task details when querying by id', (done) => {
const appName = 'taskp-app';
const taskId = '68d54a8f';
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('task-app');
expect(res.id).toBe('68d54a8f');
done();
});
});
it('should throw error if appName is not defined when querying by id', (done) => {
const appName = null;
const taskId = '68d54a8f';
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined when querying by id', (done) => {
const appName = 'task-app';
const taskId = null;
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.getTaskById(appName, taskId).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if appName is not defined when updating a task', (done) => {
const appName = null;
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined when updating a task', (done) => {
const appName = 'task-app';
const taskId = null;
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should return the task details when updating a task', (done) => {
const appName = 'taskp-app';
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe((res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.appName).toBe('task-app');
expect(res.id).toBe('68d54a8f');
done();
});
});
it('should throw error if appName is not defined when querying by id', (done) => {
const appName = null;
const taskId = '68d54a8f';
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
it('should throw error if taskId is not defined updating a task', (done) => {
const appName = 'task-app';
const taskId = null;
const updatePayload = { description: 'New description' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeTaskDetailsResults);
service.updateTask(appName, taskId, updatePayload).subscribe(
() => { },
(error) => {
expect(error).toBe('AppName/TaskId not configured');
done();
});
});
});

View File

@@ -19,7 +19,7 @@ import { Injectable } from '@angular/core';
import { AlfrescoApiService, LogService, AppConfigService, IdentityUserService } from '@alfresco/adf-core';
import { from, throwError, Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
import { TaskDetailsCloudModel } from '../start-task/models/task-details-cloud.model';
@Injectable({
providedIn: 'root'
@@ -46,7 +46,7 @@ export class TaskCloudService {
* @param taskId ID of the task to complete
* @returns Details of the task that was completed
*/
completeTask(appName: string, taskId: string) {
completeTask(appName: string, taskId: string): Observable<TaskDetailsCloudModel> {
const queryUrl = this.buildCompleteTaskUrl(appName, taskId);
const bodyParam = { 'payloadType': 'CompleteTaskPayload' };
const pathParams = {}, queryParams = {}, headerParams = {},
@@ -71,11 +71,83 @@ export class TaskCloudService {
*/
canCompleteTask(taskDetails: TaskDetailsCloudModel): boolean {
const currentUser = this.identityUserService.getCurrentUserInfo().username;
return taskDetails.owner === currentUser && !taskDetails.isCompleted();
return taskDetails.assignee && taskDetails.owner === currentUser && !taskDetails.isCompleted();
}
private buildCompleteTaskUrl(appName: string, taskId: string): any {
return `${this.appConfigService.get('bpmHost')}/${appName}-rb/v1/tasks/${taskId}/complete`;
/**
* Validate if a task can be claimed.
* @param taskDetails task details object
* @returns Boolean value if the task can be completed
*/
canClaimTask(taskDetails: TaskDetailsCloudModel): boolean {
return taskDetails && taskDetails.canClaimTask();
}
/**
* Validate if a task can be unclaimed.
* @param taskDetails task details object
* @returns Boolean value if the task can be completed
*/
canUnclaimTask(taskDetails: TaskDetailsCloudModel): boolean {
const currentUser = this.identityUserService.getCurrentUserInfo().username;
return taskDetails.canUnclaimTask(currentUser);
}
/**
* Claims a task for an assignee.
* @param appName Name of the app
* @param taskId ID of the task to claim
* @param assignee User to assign the task to
* @returns Details of the claimed task
*/
claimTask(appName: string, taskId: string, assignee: string): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/tasks/${taskId}/claim?assignee=${assignee}`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
null, null,
this.contentTypes, this.accepts,
this.returnType, null, null)
).pipe(
map((res: any) => {
return new TaskDetailsCloudModel(res.entry);
}),
catchError((err) => this.handleError(err))
);
} else {
this.logService.error('AppName and TaskId are mandatory for querying a task');
return throwError('AppName/TaskId not configured');
}
}
/**
* Un-claims a task.
* @param appName Name of the app
* @param taskId ID of the task to unclaim
* @returns Details of the task that was unclaimed
*/
unclaimTask(appName: string, taskId: string): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/tasks/${taskId}/release`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
null, null,
this.contentTypes, this.accepts,
this.returnType, null, null)
).pipe(
map((res: any) => {
return new TaskDetailsCloudModel(res.entry);
}),
catchError((err) => this.handleError(err))
);
} else {
this.logService.error('AppName and TaskId are mandatory for querying a task');
return throwError('AppName/TaskId not configured');
}
}
/**
@@ -113,7 +185,7 @@ export class TaskCloudService {
* @param updatePayload Data to update the task
* @returns Updated task details
*/
updateTask(appName: string, taskId: string, updatePayload: any): any {
updateTask(appName: string, taskId: string, updatePayload: any): Observable<TaskDetailsCloudModel> {
if (appName && taskId) {
updatePayload.payloadType = 'UpdateTaskPayload';
@@ -137,61 +209,8 @@ export class TaskCloudService {
}
}
/**
* Claims a task for an assignee.
* @param appName Name of the app
* @param taskId ID of the task to claim
* @param assignee User to assign the task to
* @returns Details of the claimed task
*/
claimTask(appName: string, taskId: string, assignee: string): any {
if (appName && taskId) {
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/tasks/${taskId}/claim?assignee=${assignee}`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
null, null,
this.contentTypes, this.accepts,
this.returnType, null, null)
).pipe(
map((res: any) => {
return new TaskDetailsCloudModel(res.entry);
}),
catchError((err) => this.handleError(err))
);
} else {
this.logService.error('AppName and TaskId are mandatory for querying a task');
return throwError('AppName/TaskId not configured');
}
}
/**
* Un-claims a task.
* @param appName Name of the app
* @param taskId ID of the task to unclaim
* @returns Details of the task that was unclaimed
*/
unclaimTask(appName: string, taskId: string): any {
if (appName && taskId) {
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/tasks/${taskId}/release`;
return from(this.apiService.getInstance()
.oauth2Auth.callCustomApi(queryUrl, 'POST',
null, null, null,
null, null,
this.contentTypes, this.accepts,
this.returnType, null, null)
).pipe(
map((res: any) => {
return new TaskDetailsCloudModel(res.entry);
}),
catchError((err) => this.handleError(err))
);
} else {
this.logService.error('AppName and TaskId are mandatory for querying a task');
return throwError('AppName/TaskId not configured');
}
private buildCompleteTaskUrl(appName: string, taskId: string): string {
return `${this.appConfigService.get('bpmHost')}/${appName}-rb/v1/tasks/${taskId}/complete`;
}
private handleError(error: any) {

View File

@@ -21,6 +21,10 @@ export const mockUsers = [
{ id: 'fake-id-3', username: 'first-name-3 last-name-3', firstName: 'first-name-3', lastName: 'last-name-3', email: 'abcde@xyz.com' }
];
export const cloudMockUser = {
id: 'fake-id-1', username: 'superadminuser', firstName: 'first-name-1', lastName: 'last-name-1', email: 'abc@xyz.com'
};
export const mockRoles = [
{ id: 'id-1', name: 'MOCK-ADMIN-ROLE'},
{ id: 'id-2', name: 'MOCK-USER-ROLE'},

View File

@@ -74,9 +74,17 @@ export class TaskDetailsCloudModel {
}
}
isCompleted() {
isCompleted(): boolean {
return this.status && this.status === TaskStatusEnum.COMPLETED;
}
canClaimTask(): boolean {
return this.status === TaskStatusEnum.CREATED;
}
canUnclaimTask(user: string): boolean {
return this.status !== TaskStatusEnum.COMPLETED && this.assignee === user;
}
}
export interface StartTaskCloudResponseModel {

View File

@@ -8,13 +8,6 @@
[editable]="!taskDetails.isCompleted()">
</adf-card-view>
</mat-card-content>
<mat-card-actions class="adf-controls">
<button *ngIf="isTaskClaimedByCandidateMember()" mat-button data-automation-id="header-unclaim-button" id="unclaim-task" (click)="unclaimTask()" class="adf-claim-controls">{{ 'ADF_CLOUD_TASK_HEADER.BUTTON.UNCLAIM' | translate }}
</button>
<button *ngIf="isTaskClaimable()" mat-button data-automation-id="header-claim-button" id="claim-task" (click)="claimTask()" class="adf-claim-controls">{{ 'ADF_CLOUD_TASK_HEADER.BUTTON.CLAIM' | translate }}
</button>
</mat-card-actions>
</mat-card>
</div>

View File

@@ -24,7 +24,7 @@ import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { RouterTestingModule } from '@angular/router/testing';
import { TaskCloudService } from '../services/task-cloud.service';
import { TaskCloudService } from '../../services/task-cloud.service';
describe('TaskHeaderCloudComponent', () => {
let component: TaskHeaderCloudComponent;

View File

@@ -24,11 +24,11 @@ import {
TranslationService,
AppConfigService,
UpdateNotification,
CardViewUpdateService,
IdentityUserService
CardViewUpdateService
} from '@alfresco/adf-core';
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
import { TaskCloudService } from '../services/task-cloud.service';
import { TaskDetailsCloudModel, TaskStatusEnum } from '../../start-task/models/task-details-cloud.model';
import { Router } from '@angular/router';
import { TaskCloudService } from '../../services/task-cloud.service';
@Component({
selector: 'adf-cloud-task-header',
@@ -61,18 +61,16 @@ export class TaskHeaderCloudComponent implements OnInit {
properties: CardViewItem[];
inEdit: boolean = false;
parentTaskName: string;
private currentUser: string;
constructor(
private taskCloudService: TaskCloudService,
private translationService: TranslationService,
private appConfig: AppConfigService,
private cardViewUpdateService: CardViewUpdateService,
private identityUserService: IdentityUserService
private router: Router,
private cardViewUpdateService: CardViewUpdateService
) { }
ngOnInit() {
this.loadCurrentBpmUserId();
if (this.appName && this.taskId) {
this.loadTaskDetailsById(this.appName, this.taskId);
}
@@ -80,10 +78,6 @@ export class TaskHeaderCloudComponent implements OnInit {
this.cardViewUpdateService.itemUpdated$.subscribe(this.updateTaskDetails.bind(this));
}
loadCurrentBpmUserId(): any {
this.currentUser = this.identityUserService.getCurrentUserInfo().username;
}
loadTaskDetailsById(appName: string, taskId: string): any {
this.taskCloudService.getTaskById(appName, taskId).subscribe(
(taskDetails) => {
@@ -224,55 +218,35 @@ export class TaskHeaderCloudComponent implements OnInit {
);
}
isTaskClaimable(): boolean {
return !this.hasAssignee() && this.isCandidateMember();
isCompleted() {
return this.taskDetails && this.taskDetails.status && this.taskDetails.status.toUpperCase() === TaskStatusEnum.COMPLETED;
}
hasAssignee(): boolean {
return !!this.taskDetails.assignee ? true : false;
}
isCandidateMember() {
return this.taskDetails.managerOfCandidateGroup || this.taskDetails.memberOfCandidateGroup || this.taskDetails.memberOfCandidateUsers;
}
isTaskClaimedByCandidateMember(): boolean {
return this.isCandidateMember() && this.isAssignedToCurrentUser() && !this.taskDetails.isCompleted();
}
isAssignedToCurrentUser(): boolean {
return this.hasAssignee() && this.isAssignedTo(this.currentUser);
}
isAssignedTo(userName): boolean {
return this.hasAssignee() ? this.taskDetails.assignee === userName : false;
}
isTaskValid() {
return this.appName && this.taskId;
}
isTaskAssigned() {
return this.taskDetails.assignee !== undefined;
}
isReadOnlyMode() {
return !this.readOnly;
}
claimTask() {
this.taskCloudService.claimTask(this.appName, this.taskId, this.currentUser).subscribe(
(res: any) => {
this.loadTaskDetailsById(this.appName, this.taskId);
this.claim.emit(this.taskId);
});
}
unclaimTask() {
this.taskCloudService.unclaimTask(this.appName, this.taskId).subscribe(
() => {
this.loadTaskDetailsById(this.appName, this.taskId);
this.unclaim.emit(this.taskId);
});
}
private isValidSelection(filteredProperties: string[], cardItem: CardViewBaseItemModel): boolean {
return filteredProperties ? filteredProperties.indexOf(cardItem.key) >= 0 : true;
}
goBack() {
this.router.navigate([`/cloud/${this.appName}/`]);
}
onCompletedTask(event: any) {
this.goBack();
}
}

View File

@@ -0,0 +1,31 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 taskClaimCloudMock = {
'entry': {
'appName': 'simple-app',
'appVersion': '',
'serviceName': 'simple-app-rb',
'serviceFullName': 'simple-app-rb',
'serviceType': 'runtime-bundle',
'serviceVersion': '',
'id': '68d54a8f',
'name': 'NXltAGmT',
'priority': 0,
'status': 'COMPLETED'
}
};

View File

@@ -17,6 +17,4 @@
export * from './components/task-header-cloud.component';
export * from './services/task-cloud.service';
export * from './task-header-cloud.module';

View File

@@ -0,0 +1,39 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CompleteTaskDirective } from './directives/complete-task.directive';
import { TaskCloudService } from './services/task-cloud.service';
import { ClaimTaskDirective } from './directives/claim-task.directive';
import { UnClaimTaskDirective } from './directives/unclaim-task.directive';
@NgModule({
declarations: [
CompleteTaskDirective,
ClaimTaskDirective,
UnClaimTaskDirective
],
exports: [
CompleteTaskDirective,
ClaimTaskDirective,
UnClaimTaskDirective
],
providers: [
TaskCloudService
]
})
export class TaskModule { }

View File

@@ -73,7 +73,7 @@
"BUTTON": {
"COMPLETE": "Complete",
"CLAIM": "Claim",
"UNCLAIM": "Requeue",
"UNCLAIM": "Release",
"DRAG-ATTACHMENT": "Drop files to upload",
"UPLOAD-ATTACHMENT": "Upload Attachment"
},