diff --git a/docs/process-services/task-standalone.component.md b/docs/process-services/task-standalone.component.md index 4dded8fcc3..9713fef68f 100644 --- a/docs/process-services/task-standalone.component.md +++ b/docs/process-services/task-standalone.component.md @@ -5,7 +5,7 @@ Status: Active # Task Standalone component -This component can be used when there is no form attached to a task. +This component can be used when the task doesn't belong to any processes. ## Basic Usage diff --git a/lib/process-services/mock/task/task-details.mock.ts b/lib/process-services/mock/task/task-details.mock.ts index f93d082ccd..45362bcdc8 100644 --- a/lib/process-services/mock/task/task-details.mock.ts +++ b/lib/process-services/mock/task/task-details.mock.ts @@ -17,6 +17,76 @@ import { TaskDetailsModel } from '../../task-list/models/task-details.model'; +export let standaloneTaskWithForm = new TaskDetailsModel({ + 'id': '100', + 'name': 'Standalone Task With Form', + 'description': null, + 'category': null, + 'assignee': { 'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com' }, + 'created': '2016-11-03T15:25:42.749+0000', + 'dueDate': null, + 'endDate': null, + 'duration': null, + 'priority': 50, + 'parentTaskId': null, + 'parentTaskName': null, + 'processInstanceId': null, + 'processInstanceName': null, + 'processDefinitionId': null, + 'processDefinitionName': null, + 'processDefinitionDescription': null, + 'processDefinitionKey': null, + 'processDefinitionCategory': null, + 'processDefinitionVersion': null, + 'processDefinitionDeploymentId': null, + 'formKey': '222', + 'processInstanceStartUserId': null, + 'initiatorCanCompleteTask': false, + 'adhocTaskCanBeReassigned': false, + 'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE', + 'executionId': '86', + 'involvedGroups': [], + 'involvedPeople': [], + 'memberOfCandidateUsers': false, + 'managerOfCandidateGroup': false, + 'memberOfCandidateGroup': false +}); + +export let standaloneTaskWithoutForm = new TaskDetailsModel({ + 'id': '200', + 'name': 'Standalone Task Without Form', + 'description': null, + 'category': null, + 'assignee': { 'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com' }, + 'created': '2016-11-03T15:25:42.749+0000', + 'dueDate': null, + 'endDate': null, + 'duration': null, + 'priority': 50, + 'parentTaskId': null, + 'parentTaskName': null, + 'processInstanceId': null, + 'processInstanceName': null, + 'processDefinitionId': null, + 'processDefinitionName': null, + 'processDefinitionDescription': null, + 'processDefinitionKey': null, + 'processDefinitionCategory': null, + 'processDefinitionVersion': null, + 'processDefinitionDeploymentId': null, + 'formKey': null, + 'processInstanceStartUserId': null, + 'initiatorCanCompleteTask': false, + 'adhocTaskCanBeReassigned': false, + 'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE', + 'executionId': '86', + 'involvedGroups': [], + 'involvedPeople': [], + 'memberOfCandidateUsers': false, + 'managerOfCandidateGroup': false, + 'memberOfCandidateGroup': false +}); + export let taskDetailsMock = new TaskDetailsModel({ 'id': '91', 'name': 'Request translation', diff --git a/lib/process-services/task-list/components/attach-form.component.html b/lib/process-services/task-list/components/attach-form.component.html index 4c3dde0d17..f1864b2127 100644 --- a/lib/process-services/task-list/components/attach-form.component.html +++ b/lib/process-services/task-list/components/attach-form.component.html @@ -7,14 +7,14 @@
- + {{ form.name }}
-
- +
diff --git a/lib/process-services/task-list/components/attach-form.component.spec.ts b/lib/process-services/task-list/components/attach-form.component.spec.ts index ec159677f3..e3eb6b0254 100644 --- a/lib/process-services/task-list/components/attach-form.component.spec.ts +++ b/lib/process-services/task-list/components/attach-form.component.spec.ts @@ -21,6 +21,7 @@ import { setupTestBed } from '@alfresco/adf-core'; import { ProcessTestingModule } from '../../testing/process.testing.module'; import { TaskListService } from './../services/tasklist.service'; import { of } from 'rxjs'; +import { By } from '@angular/platform-browser'; describe('AttachFormComponent', () => { let component: AttachFormComponent; @@ -42,6 +43,19 @@ describe('AttachFormComponent', () => { fixture.detectChanges(); })); + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should show the attach button disabled', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + let attachButton = fixture.debugElement.query(By.css('#adf-no-form-attach-form-button')); + expect(attachButton.nativeElement.disabled).toBeTruthy(); + }); + })); + it('should emit cancel event if clicked on Cancel Button ', async(() => { fixture.detectChanges(); fixture.whenStable().then(() => { @@ -52,9 +66,9 @@ describe('AttachFormComponent', () => { }); })); - it('should call attachFormToATask if clicked on Complete Button', async(() => { + it('should call attachFormToATask if clicked on attach Button', async(() => { component.taskId = 1; - component.formId = 2; + component.attachFormControl.setValue(2); spyOn(taskService, 'attachFormToATask').and.returnValue(of(true)); fixture.detectChanges(); fixture.whenStable().then(() => { @@ -65,12 +79,42 @@ describe('AttachFormComponent', () => { }); })); + it('should render the attachForm enabled if the user select the different formId', async(() => { + component.taskId = 1; + component.formId = 2; + component.attachFormControl.setValue(3); + fixture.detectChanges(); + spyOn(taskService, 'attachFormToATask').and.returnValue(of(true)); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let attachButton = fixture.debugElement.query(By.css('#adf-no-form-attach-form-button')); + expect(attachButton.nativeElement.disabled).toBeFalsy(); + }); + })); + + it('should render a disabled attachForm button if the user select the original formId', async(() => { + component.taskId = 1; + component.formId = 2; + component.attachFormControl.setValue(3); + fixture.detectChanges(); + spyOn(taskService, 'attachFormToATask').and.returnValue(of(true)); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + component.attachFormControl.setValue(2); + fixture.detectChanges(); + let attachButton = fixture.debugElement.query(By.css('#adf-no-form-attach-form-button')); + expect(attachButton.nativeElement.disabled).toBeTruthy(); + }); + })); + it('should show the adf-form of the selected form', async(() => { component.taskId = 1; - component.formKey = 12; + component.selectedFormId = 12; fixture.detectChanges(); - const formContainer = fixture.debugElement.nativeElement.querySelector('adf-form'); fixture.whenStable().then(() => { + fixture.detectChanges(); + const formContainer = fixture.debugElement.nativeElement.querySelector('adf-form'); expect(formContainer).toBeDefined(); expect(formContainer).not.toBeNull(); }); @@ -79,32 +123,33 @@ describe('AttachFormComponent', () => { it('should show the formPreview of the selected form', async(() => { component.formKey = 12; fixture.detectChanges(); - const formContainer = fixture.debugElement.nativeElement.querySelector('.adf-form-container'); fixture.whenStable().then(() => { + fixture.detectChanges(); + const formContainer = fixture.debugElement.nativeElement.querySelector('.adf-form-container'); expect(formContainer).toBeDefined(); expect(formContainer).toBeNull(); }); })); - it('should remove form if it is present', (done) => { + it('should remove form if it is present', async(() => { component.taskId = 1; - component.formId = 10; + component.attachFormControl.setValue(10); component.formKey = 12; spyOn(taskService, 'deleteForm').and.returnValue(of({})); fixture.detectChanges(); fixture.whenStable().then(() => { + fixture.detectChanges(); expect(element.querySelector('#adf-no-form-remove-button')).toBeDefined(); const el = fixture.nativeElement.querySelector('#adf-no-form-remove-button'); el.click(); expect(component.formId).toBeNull(); - done(); }); - }); + })); - it('should emit success when form is changed', async(() => { + it('should emit success when a form is attached', async(() => { component.taskId = 1; - component.formId = 10; + component.attachFormControl.setValue(10); spyOn(taskService, 'attachFormToATask').and.returnValue(of( { diff --git a/lib/process-services/task-list/components/attach-form.component.ts b/lib/process-services/task-list/components/attach-form.component.ts index 3bee1e9165..bf2acc9062 100644 --- a/lib/process-services/task-list/components/attach-form.component.ts +++ b/lib/process-services/task-list/components/attach-form.component.ts @@ -16,9 +16,10 @@ */ import { FormService, LogService } from '@alfresco/adf-core'; -import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { Form } from '../models/form.model'; import { TaskListService } from './../services/tasklist.service'; +import { FormControl, Validators } from '@angular/forms'; @Component({ selector: 'adf-attach-form', @@ -26,7 +27,7 @@ import { TaskListService } from './../services/tasklist.service'; styleUrls: ['./attach-form.component.scss'] }) -export class AttachFormComponent implements OnChanges { +export class AttachFormComponent implements OnInit, OnChanges { constructor(private taskService: TaskListService, private logService: LogService, private formService: FormService) { } @@ -49,20 +50,42 @@ export class AttachFormComponent implements OnChanges { forms: Form[]; formId: number; + disableSubmit: boolean = true; + selectedFormId: number; + + attachFormControl: FormControl; + + ngOnInit() { + this.attachFormControl = new FormControl('', Validators.required); + this.attachFormControl.valueChanges.subscribe( (currentValue) => { + if (this.attachFormControl.valid) { + if ( this.formId !== currentValue) { + this.disableSubmit = false; + } else { + this.disableSubmit = true; + } + } + }); + } ngOnChanges() { + this.formId = undefined; + this.disableSubmit = true; this.loadFormsTask(); - this.onFormAttached(); + if (this.formKey) { + this.onFormAttached(); + } } onCancelButtonClick(): void { + this.selectedFormId = this.formId; this.cancelAttachForm.emit(); } onRemoveButtonClick(): void { this.taskService.deleteForm(this.taskId).subscribe( () => { - this.formId = null; + this.formId = this.selectedFormId = null; this.success.emit(); }, (err) => { @@ -72,7 +95,7 @@ export class AttachFormComponent implements OnChanges { } onAttachFormButtonClick(): void { - this.attachForm(this.taskId, this.formId); + this.attachForm(this.taskId, this.selectedFormId); } private loadFormsTask(): void { @@ -89,7 +112,7 @@ export class AttachFormComponent implements OnChanges { this.formService.getTaskForm(this.taskId) .subscribe((res) => { this.formService.getFormDefinitionByName(res.name).subscribe((formDef) => { - this.formId = formDef; + this.formId = this.selectedFormId = formDef; }); }, (err) => { this.error.emit(err); diff --git a/lib/process-services/task-list/components/task-details.component.html b/lib/process-services/task-list/components/task-details.component.html index 2a12bc0e0d..d2cc2877ff 100644 --- a/lib/process-services/task-list/components/task-details.component.html +++ b/lib/process-services/task-list/components/task-details.component.html @@ -31,7 +31,7 @@
- - - { it('should display task standalone component when the task does not have an associated form', async(() => { component.taskId = '123'; + getTaskDetailsSpy.and.returnValue(of(standaloneTaskWithoutForm)); + fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); + expect(component.isStandaloneTaskWithoutForm()).toBeTruthy(); expect(fixture.debugElement.query(By.css('adf-task-standalone'))).not.toBeNull(); }); })); - it('should not display task standalone component when the task have an associated form', async(() => { + it('should not display task standalone component when the task has a form', async(() => { component.taskId = '123'; - component.taskDetails = new TaskDetailsModel(taskDetailsMock); - component.taskDetails.formKey = '10'; + getTaskDetailsSpy.and.returnValue(of(standaloneTaskWithForm)); fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); + expect(component.isStandaloneTaskWithForm()).toBeTruthy(); expect(fixture.debugElement.query(By.css('adf-task-standalone'))).toBeDefined(); expect(fixture.debugElement.query(By.css('adf-task-standalone'))).not.toBeNull(); }); })); + it('should display the AttachFormComponent when standaloneTaskWithForm and click on attach button', async(() => { + component.taskId = '123'; + getTaskDetailsSpy.and.returnValue(of(standaloneTaskWithForm)); + fixture.detectChanges(); + component.onShowAttachForm(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(component.isStandaloneTaskWithForm()).toBeTruthy(); + expect(fixture.debugElement.query(By.css('adf-attach-form'))).toBeDefined(); + }); + })); + it('should display the claim message when the task is not assigned', async(() => { component.taskDetails = taskDetailsWithOutAssigneeMock; fixture.detectChanges(); diff --git a/lib/process-services/task-list/components/task-details.component.ts b/lib/process-services/task-list/components/task-details.component.ts index 1b3972dd61..2cba3c0e4f 100644 --- a/lib/process-services/task-list/components/task-details.component.ts +++ b/lib/process-services/task-list/components/task-details.component.ts @@ -217,11 +217,34 @@ export class TaskDetailsComponent implements OnInit, OnChanges { if (taskId && !taskId.currentValue) { this.reset(); } else if (taskId && taskId.currentValue) { - this.taskFormName = null; this.loadDetails(taskId.currentValue); } } + isStandaloneTask(): boolean { + return !(this.taskDetails && (!!this.taskDetails.processDefinitionId)); + } + + isStandaloneTaskWithForm(): boolean { + return this.isStandaloneTask() && this.hasFormKey(); + } + + isStandaloneTaskWithoutForm(): boolean { + return this.isStandaloneTask() && !this.hasFormKey(); + } + + isFormComponentVisible(): boolean { + return this.hasFormKey() && !this.isShowAttachForm(); + } + + isTaskStandaloneComponentVisible(): boolean { + return this.isStandaloneTaskWithoutForm() && !this.isShowAttachForm(); + } + + isShowAttachForm(): boolean { + return this.showAttachForm; + } + /** * Reset the task details */ @@ -232,10 +255,8 @@ export class TaskDetailsComponent implements OnInit, OnChanges { /** * Check if the task has a form */ - hasFormKey(): TaskDetailsModel | string | boolean { - return (this.taskDetails - && this.taskDetails.formKey - && this.taskDetails.formKey !== 'null'); + hasFormKey(): boolean { + return (this.taskDetails && (!!this.taskDetails.formKey)); } isTaskActive() { @@ -272,10 +293,12 @@ export class TaskDetailsComponent implements OnInit, OnChanges { private loadDetails(taskId: string) { this.taskPeople = []; this.readOnlyForm = false; + this.taskFormName = null; if (taskId) { this.taskListService.getTaskDetails(taskId).subscribe( (res: TaskDetailsModel) => { + this.showAttachForm = false; this.taskDetails = res; if (this.taskDetails.name === 'null') {