[ADF-3409] [ADF-3413] Standalone task - Attach/Remove forms bugs (#3670)

* Fix 3409 disable button logic
Fix 3413 change the formName based on selected form

* [ADF-3409] fixed missing import

* [ADF-3409] fixed Observable.of in of
This commit is contained in:
Maurizio Vitale
2018-08-10 10:17:19 +01:00
committed by Eugenio Romano
parent e1d5ef6ee9
commit 8330ed2879
8 changed files with 210 additions and 34 deletions

View File

@@ -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

View File

@@ -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',

View File

@@ -7,14 +7,14 @@
</mat-card-title>
<div class="adf-attach-form-row">
<mat-form-field class="adf-grid-full-width">
<mat-select placeholder="{{ 'ADF_TASK_LIST.ATTACH_FORM.SELECT_OPTION' | translate }}" id="form_id" [(ngModel)]="formId">
<mat-select [formControl]="attachFormControl" placeholder="{{ 'ADF_TASK_LIST.ATTACH_FORM.SELECT_OPTION' | translate }}" id="form_id" [(ngModel)]="selectedFormId">
<mat-option *ngFor="let form of forms" [value]="form.id">{{ form.name }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<adf-form
[formId]="formId"
<adf-form *ngIf="this.attachFormControl.valid"
[formId]="selectedFormId"
[readOnly]="true"
[showCompleteButton]="false"
[showRefreshButton]="false"
@@ -29,7 +29,7 @@
</div>
<div>
<button mat-button id="adf-no-form-cancel-button" (click)="onCancelButtonClick()">{{ 'ADF_TASK_LIST.START_TASK.FORM.ACTION.CANCEL' | translate }}</button>
<button mat-button id="adf-no-form-attach-form-button" color="primary" (click)="onAttachFormButtonClick()">{{ 'ADF_TASK_LIST.START_TASK.FORM.LABEL.ATTACHFORM' | translate }}</button>
<button mat-button id="adf-no-form-attach-form-button" [disabled]="disableSubmit" color="primary" (click)="onAttachFormButtonClick()">{{ 'ADF_TASK_LIST.START_TASK.FORM.LABEL.ATTACHFORM' | translate }}</button>
</div>
</mat-card-actions>
</mat-card>

View File

@@ -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();
fixture.whenStable().then(() => {
fixture.detectChanges();
const formContainer = fixture.debugElement.nativeElement.querySelector('adf-form');
fixture.whenStable().then(() => {
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(
{

View File

@@ -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();
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);

View File

@@ -31,7 +31,7 @@
<div class="adf-task-details-core-form">
<div *ngIf="isAssigned()">
<adf-form *ngIf="hasFormKey() && !showAttachForm" #activitiForm
<adf-form *ngIf="isFormComponentVisible()" #activitiForm
[showDebugButton]="debugMode"
[taskId]="taskDetails.id"
[showTitle]="showFormTitle"
@@ -48,7 +48,7 @@
(error)='onFormError($event)'
(executeOutcome)='onFormExecuteOutcome($event)'>
</adf-form>
<adf-task-standalone *ngIf="!hasFormKey() && !showAttachForm"
<adf-task-standalone *ngIf="isTaskStandaloneComponentVisible()"
[taskName]="taskDetails.name"
[taskId]="taskDetails.id"
[isCompleted]="isCompletedTask()"
@@ -57,7 +57,7 @@
(complete)="onComplete()"
(showAttachForm)="onShowAttachForm()">
</adf-task-standalone>
<adf-attach-form *ngIf="showAttachForm"
<adf-attach-form *ngIf="isShowAttachForm()"
[taskId]="taskDetails.id"
[formKey]="taskDetails.formKey"
(cancelAttachForm)="onCancelAttachForm()"

View File

@@ -25,7 +25,7 @@ import { CommentProcessService, LogService, AuthenticationService } from '@alfre
import { UserProcessModel } from '@alfresco/adf-core';
import { TaskDetailsModel } from '../models/task-details.model';
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock, taskDetailsWithOutAssigneeMock } from '../../mock';
import { noDataMock, taskDetailsMock, standaloneTaskWithForm, standaloneTaskWithoutForm, taskFormMock, tasksMock, taskDetailsWithOutAssigneeMock } from '../../mock';
import { TaskListService } from './../services/tasklist.service';
import { TaskDetailsComponent } from './task-details.component';
import { ProcessTestingModule } from '../../testing/process.testing.module';
@@ -151,25 +151,40 @@ describe('TaskDetailsComponent', () => {
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();

View File

@@ -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') {