diff --git a/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.html b/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.html
index 2a72d8d545..68056e9373 100644
--- a/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.html
+++ b/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.html
@@ -4,7 +4,13 @@
+ (success)="onCompletedTask()">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE' | translate }}
+
+
+
+
diff --git a/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.ts b/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.ts
index 6838200b2e..25f72933b2 100644
--- a/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.ts
+++ b/demo-shell/src/app/components/app-layout/cloud/task-details-cloud-demo.component.ts
@@ -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();
}
}
diff --git a/docs/process-services-cloud/claim-task.directive.md b/docs/process-services-cloud/claim-task.directive.md
new file mode 100644
index 0000000000..97ccdd8e80
--- /dev/null
+++ b/docs/process-services-cloud/claim-task.directive.md
@@ -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
+
+```
+## 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` | empty | Emitted when the task is completed. |
+| error | `EventEmitter` | empty | Emitted when the task cannot be completed. |
\ No newline at end of file
diff --git a/docs/process-services-cloud/services/task-cloud.service.md b/docs/process-services-cloud/services/task-cloud.service.md
index 4b1675e7e2..e27229d5c5 100644
--- a/docs/process-services-cloud/services/task-cloud.service.md
+++ b/docs/process-services-cloud/services/task-cloud.service.md
@@ -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`)
+ 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))
+ 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))
+ 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`
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`
- 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)`>`
- 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`
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)`>`
+ 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`
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
diff --git a/docs/process-services-cloud/unclaim-tas.directie.md b/docs/process-services-cloud/unclaim-tas.directie.md
new file mode 100644
index 0000000000..1bdebdf9b0
--- /dev/null
+++ b/docs/process-services-cloud/unclaim-tas.directie.md
@@ -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
+
+```
+## 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` | empty | Emitted when the task is completed. |
+| error | `EventEmitter` | empty | Emitted when the task cannot be completed. |
\ No newline at end of file
diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json
index 671168543d..8080e779ee 100644
--- a/lib/process-services-cloud/src/lib/i18n/en.json
+++ b/lib/process-services-cloud/src/lib/i18n/en.json
@@ -174,7 +174,7 @@
"ADF_CLOUD_TASK_HEADER": {
"BUTTON": {
"CLAIM": "Claim",
- "UNCLAIM": "Requeue"
+ "UNCLAIM": "Release"
},
"PROPERTIES": {
"TASK_NAME": "Task",
diff --git a/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.spec.ts b/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.spec.ts
new file mode 100644
index 0000000000..9a5c93dd95
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.spec.ts
@@ -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: ''
+ })
+ class TestComponent {
+
+ taskMock = 'test1234';
+ appNameMock = 'simple-app';
+
+ @ViewChild(ClaimTaskDirective)
+ claimTaskDirective: ClaimTaskDirective;
+
+ onCompleteTask(event: any) {
+ return event;
+ }
+ }
+
+ let fixture: ComponentFixture;
+ 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: ''
+ })
+ class ClaimTestMissingInputDirectiveComponent {
+
+ appName = 'simple-app';
+ appNameUndefined = undefined;
+ appNameNull = null;
+
+ @ContentChildren(ClaimTaskDirective)
+ claimTaskValidationDirective: ClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-no-taskid-validation-component',
+ template: ''
+ })
+ class ClaimTestMissingTaskIdDirectiveComponent {
+
+ appName = 'simple-app';
+
+ @ContentChildren(ClaimTaskDirective)
+ claimTaskValidationDirective: ClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-undefined-appname-component',
+ template: ''
+ })
+ class ClaimTestInvalidAppNameUndefineddDirectiveComponent {
+
+ appNameUndefined = undefined;
+ taskMock = 'test1234';
+
+ @ContentChildren(ClaimTaskDirective)
+ claimTaskValidationDirective: ClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-null-appname-component',
+ template: ''
+ })
+ class ClaimTestInvalidAppNameNulldDirectiveComponent {
+
+ appNameNull = null;
+ taskMock = 'test1234';
+
+ @ViewChild(ClaimTaskDirective)
+ claimTaskValidationDirective: ClaimTaskDirective;
+ }
+
+ let fixture: ComponentFixture;
+
+ 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');
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.ts b/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.ts
new file mode 100644
index 0000000000..54bbd8e46d
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/directives/claim-task.directive.ts
@@ -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 = new EventEmitter();
+
+ /** Emitted when the task cannot be completed. */
+ @Output()
+ error: EventEmitter = new EventEmitter();
+
+ 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);
+ }
+ }
+}
diff --git a/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.spec.ts b/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.spec.ts
index 0d1fdc413c..8d35553bd2 100644
--- a/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.spec.ts
+++ b/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.spec.ts
@@ -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', () => {
diff --git a/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.ts b/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.ts
index 7d604d5bc7..8652123ebf 100644
--- a/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.ts
+++ b/lib/process-services-cloud/src/lib/task/directives/complete-task.directive.ts
@@ -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;
}
diff --git a/lib/process-services-cloud/src/lib/task/directives/task-directive.module.ts b/lib/process-services-cloud/src/lib/task/directives/task-directive.module.ts
index 8280bb9385..50aad9c624 100644
--- a/lib/process-services-cloud/src/lib/task/directives/task-directive.module.ts
+++ b/lib/process-services-cloud/src/lib/task/directives/task-directive.module.ts
@@ -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 { }
diff --git a/lib/process-services-cloud/src/lib/task/directives/unclaim-task.directive.ts b/lib/process-services-cloud/src/lib/task/directives/unclaim-task.directive.ts
new file mode 100644
index 0000000000..492e372450
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/directives/unclaim-task.directive.ts
@@ -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 = new EventEmitter();
+
+ /** Emitted when the task cannot be completed. */
+ @Output()
+ error: EventEmitter = new EventEmitter();
+
+ 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);
+ });
+ }
+}
diff --git a/lib/process-services-cloud/src/lib/task/directives/unclaim-tast.directive.spec.ts b/lib/process-services-cloud/src/lib/task/directives/unclaim-tast.directive.spec.ts
new file mode 100644
index 0000000000..f8c15756ed
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/directives/unclaim-tast.directive.spec.ts
@@ -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: ''
+ })
+ class TestComponent {
+
+ appName = 'simple-app';
+ taskIdMock = '1234';
+
+ @ContentChildren(UnClaimTaskDirective)
+ unclaimTaskDirective: UnClaimTaskDirective;
+ }
+
+ let fixture: ComponentFixture;
+ 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: ''
+ })
+ class ClaimTestMissingInputDirectiveComponent {
+
+ appName = 'simple-app';
+ appNameUndefined = undefined;
+ appNameNull = null;
+
+ @ContentChildren(UnClaimTaskDirective)
+ claimTaskValidationDirective: UnClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-no-taskid-validation-component',
+ template: ''
+ })
+ class ClaimTestMissingTaskIdDirectiveComponent {
+
+ appName = 'simple-app';
+
+ @ContentChildren(UnClaimTaskDirective)
+ claimTaskValidationDirective: UnClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-undefined-appname-component',
+ template: ''
+ })
+ class ClaimTestInvalidAppNameUndefineddDirectiveComponent {
+
+ appNameUndefined = undefined;
+ taskMock = 'test1234';
+
+ @ContentChildren(UnClaimTaskDirective)
+ claimTaskValidationDirective: UnClaimTaskDirective;
+ }
+
+ @Component({
+ selector: 'adf-claim-null-appname-component',
+ template: ''
+ })
+ class ClaimTestInvalidAppNameNulldDirectiveComponent {
+
+ appNameNull = null;
+ taskMock = 'test1234';
+
+ @ViewChild(UnClaimTaskDirective)
+ claimTaskValidationDirective: UnClaimTaskDirective;
+ }
+
+ let fixture: ComponentFixture;
+
+ 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');
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/task/models/task.model.ts b/lib/process-services-cloud/src/lib/task/models/task.model.ts
new file mode 100644
index 0000000000..9a5b9b886a
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/models/task.model.ts
@@ -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'
+}
diff --git a/lib/process-services-cloud/src/lib/task/public-api.ts b/lib/process-services-cloud/src/lib/task/public-api.ts
index c2b1682a4e..1d0afddbc5 100644
--- a/lib/process-services-cloud/src/lib/task/public-api.ts
+++ b/lib/process-services-cloud/src/lib/task/public-api.ts
@@ -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';
diff --git a/lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts
similarity index 85%
rename from lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.spec.ts
rename to lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts
index 89b464d51d..30bf8eb1e0 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.spec.ts
+++ b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts
@@ -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();
+ });
+ });
});
diff --git a/lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.ts b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.ts
similarity index 86%
rename from lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.ts
rename to lib/process-services-cloud/src/lib/task/services/task-cloud.service.ts
index 1c8bb1c25b..c353cb0d3f 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/services/task-cloud.service.ts
+++ b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.ts
@@ -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 {
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 {
+ 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 {
+ 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 {
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) {
diff --git a/lib/process-services-cloud/src/lib/task/start-task/mock/user-cloud.mock.ts b/lib/process-services-cloud/src/lib/task/start-task/mock/user-cloud.mock.ts
index c5edc9f95f..1bf9362984 100644
--- a/lib/process-services-cloud/src/lib/task/start-task/mock/user-cloud.mock.ts
+++ b/lib/process-services-cloud/src/lib/task/start-task/mock/user-cloud.mock.ts
@@ -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'},
diff --git a/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts b/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts
index 2668626b93..091ed1ca92 100644
--- a/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts
+++ b/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts
@@ -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 {
diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html
index a16a0935e7..eb21f20d68 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html
+++ b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html
@@ -8,13 +8,6 @@
[editable]="!taskDetails.isCompleted()">
-
-
-
-
-
diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts
index acf648d631..108a178734 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts
+++ b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts
@@ -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;
diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.ts
index d53e3a8f00..3aa0fa3c1b 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.ts
+++ b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.ts
@@ -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();
+ }
}
diff --git a/lib/process-services-cloud/src/lib/task/task-header/mocks/fake-claim-task.mock.ts b/lib/process-services-cloud/src/lib/task/task-header/mocks/fake-claim-task.mock.ts
new file mode 100644
index 0000000000..f1dd26bb22
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/task-header/mocks/fake-claim-task.mock.ts
@@ -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'
+ }
+};
diff --git a/lib/process-services-cloud/src/lib/task/task-header/public-api.ts b/lib/process-services-cloud/src/lib/task/task-header/public-api.ts
index 596020d265..0be25b6c89 100644
--- a/lib/process-services-cloud/src/lib/task/task-header/public-api.ts
+++ b/lib/process-services-cloud/src/lib/task/task-header/public-api.ts
@@ -17,6 +17,4 @@
export * from './components/task-header-cloud.component';
-export * from './services/task-cloud.service';
-
export * from './task-header-cloud.module';
diff --git a/lib/process-services-cloud/src/lib/task/task.module.ts b/lib/process-services-cloud/src/lib/task/task.module.ts
new file mode 100644
index 0000000000..926e213c5f
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/task/task.module.ts
@@ -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 { }
diff --git a/lib/process-services/i18n/en.json b/lib/process-services/i18n/en.json
index 6d2c1283ac..199cd86c4d 100644
--- a/lib/process-services/i18n/en.json
+++ b/lib/process-services/i18n/en.json
@@ -73,7 +73,7 @@
"BUTTON": {
"COMPLETE": "Complete",
"CLAIM": "Claim",
- "UNCLAIM": "Requeue",
+ "UNCLAIM": "Release",
"DRAG-ATTACHMENT": "Drop files to upload",
"UPLOAD-ATTACHMENT": "Upload Attachment"
},