[ADF-3282] Refactor Start Task Component (#4012)

* [ADF-3282] Refactor Start Task Component

* [ADF-3282] Fix e2e test

* [ADF-3282] Remove maxTaskNameLength from start task doc
This commit is contained in:
davidcanonieto
2018-11-29 14:57:36 +00:00
committed by Eugenio Romano
parent ca5543c48d
commit 49738ad555
10 changed files with 318 additions and 244 deletions

View File

@@ -497,6 +497,9 @@
]
}
},
"adf-start-task": {
"name": "My Task Name"
},
"adf-task-list": {
"presets": {
"default": [

View File

@@ -104,6 +104,7 @@
<div class="adf-grid-item adf-tasks-start" *ngIf="isStartTaskMode()" fxFlex.gt-md="1 1 auto">
<adf-start-task
[appId]="appId"
[name]="defaultTaskName"
(success)="onStartTaskSuccess($event)"
(cancel)="onCancelStartTask()">
</adf-start-task>

View File

@@ -137,6 +137,7 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
defaultProcessDefinitionName: string;
defaultProcessName: string;
defaultTaskName: string;
activeTab: number = this.tabs.tasks; // tasks|processes|reports
@@ -175,6 +176,7 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
this.defaultProcessName = this.appConfig.get<string>('adf-start-process.name');
this.defaultProcessDefinitionName = this.appConfig.get<string>('adf-start-process.processDefinitionName');
this.defaultTaskName = this.appConfig.get<string>('adf-start-task.name');
// Uncomment this line to replace all 'text' field editors with custom component
// formRenderingService.setComponentTypeResolver('text', () => CustomEditorComponent, true);

View File

@@ -15,7 +15,8 @@ Creates/Starts a new task for the specified app
```html
<adf-start-task
[appId]="YOUR_APP_ID">
[appId]="YOUR_APP_ID"
[name]="My Task Name">
</adf-start-task>
```
@@ -26,6 +27,7 @@ Creates/Starts a new task for the specified app
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| appId | `number` | | (required) The id of the app. |
| name | `string` | | Default Task Name |
### Events

View File

@@ -31,6 +31,7 @@ var StartTaskDialog = function () {
this.addName = function (userName) {
Util.waitUntilElementIsVisible(name);
name.clear();
name.sendKeys(userName);
return this;
};

View File

@@ -114,6 +114,7 @@
}
},
"START_TASK": {
"DEFAULT_NAME": "My Default Task",
"BUTTON": "CREATE TASK",
"FORM": {
"TITLE": "Start Task",
@@ -130,8 +131,10 @@
"START": "Start",
"CANCEL": "Cancel"
},
"DATE": {
"ERROR": "Date format DD/MM/YYYY"
"ERROR": {
"REQUIRED": "Field required",
"DATE": "Date format DD/MM/YYYY",
"MAXIMUM_LENGTH": "Length exceeded, {{characters}} characters max."
}
}
},

View File

@@ -1,93 +1,95 @@
<mat-card class="adf-new-task-layout-card">
<mat-grid-list cols="1" rowHeight="60px">
<mat-grid-tile>
<div class="adf-new-task-heading">{{'ADF_TASK_LIST.START_TASK.FORM.TITLE'|translate}}</div>
</mat-grid-tile>
</mat-grid-list>
<mat-card fxFlex="70%" class="adf-new-task-layout-card">
<mat-card-header fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="10px" class="adf-new-task-heading">
<mat-card-title>{{'ADF_TASK_LIST.START_TASK.FORM.TITLE' | translate}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="adf-new-task-layout-card-content">
<div class="adf-grid-full-width adf-grid-row">
<mat-form-field class="adf-grid-full-width adf-grid-column">
<input matInput
class="adf-grid-full-width"
placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.NAME'|translate}}"
[(ngModel)]="startTaskModel.name"
required
id="name_id">
<form [formGroup]="taskForm" fxLayout="column" fxLayoutGap="10px">
<div class="adf-task-name">
<mat-form-field fxFlex>
<mat-label>{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.NAME' | translate}}</mat-label>
<input
matInput
id="name_id"
formControlName="name">
<mat-error *ngIf="nameController.hasError('required')">
{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="nameController.hasError('maxlength')">
{{ 'ADF_TASK_LIST.START_TASK.FORM.ERROR.MAXIMUM_LENGTH' | translate : { characters : maxTaskNameLength } }}
</mat-error>
</mat-form-field>
</div>
<div class="adf-grid-full-width adf-grid-row">
<mat-form-field class="adf-grid-full-width adf-grid-column">
<div class="adf-task-description">
<mat-form-field fxFlex>
<mat-label>{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.DESCRIPTION' | translate}}</mat-label>
<textarea
matInput
class="adf-grid-full-width"
placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.DESCRIPTION'|translate}}"
[(ngModel)]="startTaskModel.description"
rows="1"
id="description_id">
id="description_id"
formControlName="description">
</textarea>
</mat-form-field>
</div>
<div class="adf-grid-full-width adf-grid-row">
<div class="adf-grid-column adf-grid-half-width">
<div class="adf-grid-full-width adf-grid-row">
<mat-form-field class="adf-grid-full-width">
<input matInput
[matDatepicker]="taskDatePicker"
(keydown)="true"
(keyup)="onDateChanged($event.srcElement.value)"
(dateInput)="onDateChanged($event.value)"
placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.DATE'|translate}}"
[(ngModel)]="startTaskModel.dueDate"
id="date_id">
<mat-datepicker-toggle matSuffix [for]="taskDatePicker"></mat-datepicker-toggle>
<mat-datepicker #taskDatePicker
[touchUi]="true"
(dateChanged)="onDateChanged($event)"
(opened)="clearDateInput()">
</mat-datepicker>
<div class="adf-error-text-container">
<div *ngIf="dateError">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.DATE.ERROR'|translate}}</div>
<mat-icon class="adf-error-icon">warning</mat-icon>
</div>
</div>
</mat-form-field>
<div class="input-row" fxLayout="row" fxLayout.lt-md="column" fxLayoutGap="20px" fxLayoutGap.lt-md="0px">
<mat-form-field fxFlex>
<input
matInput
(keyup)="onDateChanged($event.srcElement.value)"
(dateInput)="onDateChanged($event.value)"
[matDatepicker]="taskDatePicker"
placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.DATE'|translate}}"
id="date_id">
<mat-datepicker-toggle
matSuffix
[for]="taskDatePicker"></mat-datepicker-toggle>
<mat-datepicker
#taskDatePicker
[touchUi]="true">
</mat-datepicker>
<div class="adf-error-text-container">
<div *ngIf="dateError">
<div class="adf-error-text">{{'ADF_TASK_LIST.START_TASK.FORM.ERROR.DATE'|translate}}</div>
<mat-icon class="adf-error-icon">warning</mat-icon>
</div>
</div>
<div class="adf-grid-full-width adf-grid-row">
<mat-form-field class="adf-grid-full-width">
<mat-select placeholder="{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.FORM'|translate}}" id="form_id" [(ngModel)]="formKey">
<mat-option>{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.NONE'|translate}}</mat-option>
<mat-option *ngFor="let form of forms" [value]="form.id">{{ form.name }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="adf-grid-column adf-grid-half-width">
</mat-form-field>
<div fxFlex>
<people-widget
(peopleSelected)="getAssigneeId($event)"
[field]="field"
class="adf-people-widget-content"></people-widget>
</div>
</div>
</div>
<div class="adf-task-form">
<mat-form-field fxFlex="48%" fxFlex.xs="100%">
<mat-label id="form_label">{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.FORM'|translate}}</mat-label>
<mat-select
id="form_id"
class="form-control"
formControlName="formKey">
<mat-option>{{'ADF_TASK_LIST.START_TASK.FORM.LABEL.NONE'|translate}}</mat-option>
<mat-option *ngFor="let form of forms$ | async" [value]="form.id">{{ form.name }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</form>
</mat-card-content>
<mat-card-actions>
<mat-grid-list cols="1" rowHeight="60px">
<mat-grid-tile>
<div class="adf-new-task-footer">
<button mat-button (click)="onCancel()" id="button-cancel">
{{'ADF_TASK_LIST.START_TASK.FORM.ACTION.CANCEL'|translate}}
</button>
<button color="primary" mat-button [disabled]="!startTaskModel.name || dateError" (click)="start()" id="button-start">
{{'ADF_TASK_LIST.START_TASK.FORM.ACTION.START'|translate}}
</button>
</div>
</mat-grid-tile>
</mat-grid-list>
<div class="adf-new-task-footer" fxLayout="row" fxLayoutAlign="end end">
<button
mat-button
(click)="onCancel()"
id="button-cancel">
{{'ADF_TASK_LIST.START_TASK.FORM.ACTION.CANCEL'|translate}}
</button>
<button
color="primary"
mat-button
[disabled]="!isFormValid()"
(click)="saveTask()"
id="button-start">
{{'ADF_TASK_LIST.START_TASK.FORM.ACTION.START'|translate}}
</button>
</div>
</mat-card-actions>
</mat-card>

View File

@@ -6,56 +6,26 @@
$header-border: 1px solid mat-color($foreground, divider);
.adf-new-task-heading {
padding: 12px 20px;
font-weight: bold;
padding-top: 12px;
border-bottom: $header-border;
font-size: 18px;
float: left;
text-align: left;
width: calc(100% - 40px);
.mat-card-title {
font-weight: bold;
font-size: 18px;
}
}
.adf-new-task-form {
width: 100%;
}
.adf-new-task-layout-card {
width: 66%;
margin: 10px auto;
&-content {
display: flex;
flex-flow: row;
flex-wrap: wrap;
justify-content: space-between;
.adf-grid-row {
display: flex;
flex-flow: row;
flex-wrap: wrap;
justify-content: space-between;
margin-bottom: 8px;
}
.adf-grid-column {
display: flex;
flex-flow: column;
}
.adf-grid-full-width {
width: 100%;
}
.adf-grid-half-width {
width: 49%;
}
}
}
.adf-new-task-footer {
padding: 4px;
font-size: 18px;
border-top: 1px solid #eee;
float: left;
width: calc(100% - 40px);
text-align: right;
}
.adf-mat-select {
@@ -154,11 +124,3 @@
}
}
}
@media (max-width: 600px) {
.adf-new-task-layout-card {
width: 90%;
margin-left: auto;
margin-right: auto;
}
}

View File

@@ -16,33 +16,36 @@
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core';
import { Observable, of, throwError } from 'rxjs';
import { startTaskMock } from '../../mock';
import { StartTaskModel } from '../models/start-task.model';
import { setupTestBed, LogService } from '@alfresco/adf-core';
import { of, throwError, Observable } from 'rxjs';
import { TaskListService } from '../services/tasklist.service';
import { StartTaskComponent } from './start-task.component';
import { ProcessTestingModule } from '../../testing/process.testing.module';
import { taskDetailsMock } from '../../mock/task/task-details.mock';
import { TaskDetailsModel } from '../models/task-details.model';
describe('StartTaskComponent', () => {
let component: StartTaskComponent;
let fixture: ComponentFixture<StartTaskComponent>;
let service: TaskListService;
let logService: LogService;
let element: HTMLElement;
let getFormListSpy: jasmine.Spy;
let createNewTaskSpy: jasmine.Spy;
let fakeForms = [
let logSpy: jasmine.Spy;
let fakeForms$ = [
{
id: 123,
name: 'Display Data'
name: 'Display Data'
},
{
{
id: 1111,
name: 'Employee Info'
name: 'Employee Info'
}
];
let testUser = {id: 1001, firstName: 'fakeName', email: 'fake@app.activiti.com'};
let testUser = { id: 1001, firstName: 'fakeName', email: 'fake@app.activiti.com' };
setupTestBed({
imports: [ProcessTestingModule]
@@ -54,21 +57,28 @@ describe('StartTaskComponent', () => {
element = fixture.nativeElement;
service = TestBed.get(TaskListService);
getFormListSpy = spyOn(service, 'getFormList').and.returnValue(of(fakeForms));
logService = TestBed.get(LogService);
getFormListSpy = spyOn(service, 'getFormList').and.returnValue(new Observable((observer) => {
observer.next(fakeForms$);
observer.complete();
}));
fixture.detectChanges();
}));
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should create instance of StartTaskComponent', () => {
expect(fixture.componentInstance instanceof StartTaskComponent).toBe(true, 'should create StartTaskComponent');
expect(component instanceof StartTaskComponent).toBe(true, 'should create StartTaskComponent');
});
it('should fetch fake form on init', () => {
component.ngOnInit();
expect(component.forms).toEqual(fakeForms);
expect(component.forms[0].name).toEqual('Display Data');
expect(component.forms[1].name).toEqual('Employee Info');
expect(component.forms[1].id).toEqual(1111);
fixture.detectChanges();
expect(component.forms$).toBeDefined();
expect(getFormListSpy).toHaveBeenCalled();
});
@@ -87,8 +97,7 @@ describe('StartTaskComponent', () => {
it('should create new task when start is clicked', () => {
let successSpy = spyOn(component.success, 'emit');
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.taskForm.controls['name'].setValue('task');
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -97,8 +106,8 @@ describe('StartTaskComponent', () => {
it('should send on success event when the task is started', () => {
let successSpy = spyOn(component.success, 'emit');
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.taskDetailsModel = new TaskDetailsModel(taskDetailsMock);
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -113,7 +122,7 @@ describe('StartTaskComponent', () => {
it('should send on success event when only name is given', () => {
let successSpy = spyOn(component.success, 'emit');
component.appId = 42;
component.startTaskModel.name = 'fakeName';
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -122,7 +131,7 @@ describe('StartTaskComponent', () => {
it('should not emit success event when data not present', () => {
let successSpy = spyOn(component.success, 'emit');
component.startTaskModel = new StartTaskModel(null);
component.taskDetailsModel = new TaskDetailsModel(null);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -141,6 +150,9 @@ describe('StartTaskComponent', () => {
assignee: null
}
));
});
it('should attach form to the task when a form is selected', () => {
spyOn(service, 'attachFormToATask').and.returnValue(of(
{
id: 91,
@@ -149,13 +161,11 @@ describe('StartTaskComponent', () => {
assignee: null
}
));
});
it('should attach form to the task when a form is selected', () => {
let successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
component.taskForm.controls['formKey'].setValue(1204);
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.formKey = '1204';
component.taskDetailsModel = new TaskDetailsModel(taskDetailsMock);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -168,10 +178,19 @@ describe('StartTaskComponent', () => {
});
it('should not attach form to the task when a no form is selected', () => {
spyOn(service, 'attachFormToATask').and.returnValue(of(
{
id: 91,
name: 'fakeName',
formKey: null,
assignee: null
}
));
let successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
component.taskForm.controls['formKey'].setValue(null);
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.formKey = null;
component.taskDetailsModel = new TaskDetailsModel(taskDetailsMock);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -214,9 +233,9 @@ describe('StartTaskComponent', () => {
it('should assign task when an assignee is selected', () => {
let successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
component.taskForm.controls['formKey'].setValue(1204);
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.formKey = '1204';
component.assigneeId = testUser.id;
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
@@ -229,12 +248,31 @@ describe('StartTaskComponent', () => {
});
});
it('should assign task with id of selected user assigned', () => {
let successSpy = spyOn(component.success, 'emit');
component.taskDetailsModel = new TaskDetailsModel(taskDetailsMock);
component.taskForm.controls['name'].setValue('fakeName');
component.taskForm.controls['formKey'].setValue(1204);
component.appId = 42;
component.getAssigneeId(testUser.id);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
expect(successSpy).toHaveBeenCalledWith({
id: 91,
name: 'fakeName',
formKey: 1204,
assignee: testUser
});
});
it('should not assign task when no assignee is selected', () => {
let successSpy = spyOn(component.success, 'emit');
component.taskForm.controls['name'].setValue('fakeName');
component.taskForm.controls['formKey'].setValue(1204);
component.appId = 42;
component.formKey = '1204';
component.assigneeId = null;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.taskDetailsModel = new TaskDetailsModel(taskDetailsMock);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
@@ -245,27 +283,10 @@ describe('StartTaskComponent', () => {
assignee: null
});
});
it('should assign task with id of selected user assigned', () => {
let successSpy = spyOn(component.success, 'emit');
component.appId = 42;
component.startTaskModel = new StartTaskModel(startTaskMock);
component.formKey = '1204';
component.getAssigneeId(testUser.id);
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
createTaskButton.click();
expect(successSpy).toHaveBeenCalledWith({
id: 91,
name: 'fakeName',
formKey: 1204,
assignee: testUser
});
});
});
it('should not attach a form when a form id is not selected', () => {
let attachFormToATask = spyOn(service, 'attachFormToATask').and.returnValue(of());
let attachFormToATask = spyOn(service, 'attachFormToATask').and.returnValue([]);
spyOn(service, 'createNewTask').and.callFake(
function() {
return new Observable((observer) => {
@@ -273,14 +294,16 @@ describe('StartTaskComponent', () => {
observer.complete();
});
});
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
component.startTaskModel.name = 'fake-name';
fixture.detectChanges();
createTaskButton.click();
expect(attachFormToATask).not.toHaveBeenCalled();
});
it('should show start task button', () => {
fixture.detectChanges();
expect(element.querySelector('#button-start')).toBeDefined();
expect(element.querySelector('#button-start')).not.toBeNull();
expect(element.querySelector('#button-start').textContent).toContain('ADF_TASK_LIST.START_TASK.FORM.ACTION.START');
@@ -294,16 +317,15 @@ describe('StartTaskComponent', () => {
});
it('should disable start button if name is empty', () => {
component.startTaskModel.name = '';
component.taskForm.controls['name'].setValue('');
fixture.detectChanges();
let createTaskButton = fixture.nativeElement.querySelector('#button-start');
let createTaskButton = fixture.nativeElement.querySelector('#button-start');
expect(createTaskButton.disabled).toBeTruthy();
});
it('should cancel start task on cancel button click', () => {
let emitSpy = spyOn(component.cancel, 'emit');
let cancelTaskButton = fixture.nativeElement.querySelector('#button-cancel');
component.startTaskModel.name = '';
let cancelTaskButton = <HTMLElement> element.querySelector('#button-cancel');
fixture.detectChanges();
cancelTaskButton.click();
expect(emitSpy).not.toBeNull();
@@ -311,24 +333,24 @@ describe('StartTaskComponent', () => {
});
it('should enable start button if name is filled out', () => {
component.startTaskModel.name = 'fakeName';
component.taskForm.controls['name'].setValue('fakeName');
fixture.detectChanges();
let createTaskButton = fixture.nativeElement.querySelector('#button-start');
expect(createTaskButton.disabled).toBeFalsy();
});
it('should define the select option for Forms', () => {
component.forms = fakeForms;
it('should define the select options for Forms', () => {
component.forms$ = service.getFormList();
fixture.detectChanges();
let selectElement = fixture.nativeElement.querySelector('#form_id');
expect(selectElement.attributes['aria-label'].value).toContain('ADF_TASK_LIST.START_TASK.FORM.LABEL.FORM');
let selectElement = fixture.nativeElement.querySelector('#form_label');
expect(selectElement.innerHTML).toContain('ADF_TASK_LIST.START_TASK.FORM.LABEL.FORM');
});
it('should get formatted full name', () => {
let testUser1 = {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'};
let testUser2 = {'id': 1002, 'firstName': '', 'lastName': 'Adams', 'email': 'adams@app.activiti.com'};
let testUser3 = {'id': 1003, 'firstName': 'Wilbur', 'lastName': '', 'email': 'wilbur@app.activiti.com'};
let testUser4 = {'id': 1004, 'firstName': '', 'lastName': '', 'email': 'test@app.activiti.com'};
it('should get formatted fullname', () => {
let testUser1 = { 'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com' };
let testUser2 = { 'id': 1002, 'firstName': '', 'lastName': 'Adams', 'email': 'adams@app.activiti.com' };
let testUser3 = { 'id': 1003, 'firstName': 'Wilbur', 'lastName': '', 'email': 'wilbur@app.activiti.com' };
let testUser4 = { 'id': 1004, 'firstName': '', 'lastName': '', 'email': 'test@app.activiti.com' };
let testFullName1 = component.getDisplayUser(testUser1.firstName, testUser1.lastName, ' ');
let testFullName2 = component.getDisplayUser(testUser2.firstName, testUser2.lastName, ' ');
@@ -342,12 +364,44 @@ describe('StartTaskComponent', () => {
});
it('should emit error when there is an error while creating task', () => {
component.taskForm.controls['name'].setValue('fakeName');
let errorSpy = spyOn(component.error, 'emit');
spyOn(service, 'createNewTask').and.returnValue(throwError({}));
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
component.startTaskModel.name = 'fake-name';
fixture.detectChanges();
createTaskButton.click();
expect(errorSpy).toHaveBeenCalled();
});
it('should emit error when task name exceeds maximum length', () => {
component.maxTaskNameLength = 2;
component.ngOnInit();
fixture.detectChanges();
let name = component.taskForm.controls['name'];
name.setValue('task');
fixture.detectChanges();
expect(name.valid).toBeFalsy();
name.setValue('ta');
fixture.detectChanges();
expect(name.valid).toBeTruthy();
});
it('should emit error when task name field is empty', () => {
fixture.detectChanges();
let name = component.taskForm.controls['name'];
name.setValue('');
fixture.detectChanges();
expect(name.valid).toBeFalsy();
name.setValue('task');
fixture.detectChanges();
expect(name.valid).toBeTruthy();
});
it('should call logService when task name exceeds maximum length', () => {
logSpy = spyOn(logService, 'log').and.callThrough();
component.maxTaskNameLength = 300;
component.ngOnInit();
fixture.detectChanges();
expect(logSpy).toHaveBeenCalled();
});
});

View File

@@ -23,10 +23,10 @@ import moment from 'moment-es6';
import { Moment } from 'moment';
import { Observable, of } from 'rxjs';
import { Form } from '../models/form.model';
import { StartTaskModel } from '../models/start-task.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from './../services/tasklist.service';
import { switchMap, defaultIfEmpty } from 'rxjs/operators';
import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from '@angular/forms';
@Component({
selector: 'adf-start-task',
@@ -40,36 +40,31 @@ import { switchMap, defaultIfEmpty } from 'rxjs/operators';
export class StartTaskComponent implements OnInit {
public FORMAT_DATE: string = 'DD/MM/YYYY';
MAX_LENGTH: number = 255;
/** (required) The id of the app. */
@Input()
appId: number;
/** Emitted when the task is successfully created. */
@Input()
name: string = '';
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
/** Emitted when the cancel button is clicked by the user. */
@Output()
cancel: EventEmitter<void> = new EventEmitter<void>();
/** Emitted when an error occurs. */
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
startTaskModel: StartTaskModel = new StartTaskModel();
forms: Form[];
taskDetailsModel: TaskDetailsModel = new TaskDetailsModel();
forms$: Observable<Form[]>;
assigneeId: number;
formKey: string;
taskId: string;
dateError: boolean;
field: FormFieldModel;
taskForm: FormGroup;
dateError: boolean = false;
maxTaskNameLength: number = this.MAX_LENGTH;
loading = false;
/**
* Constructor
@@ -80,44 +75,74 @@ export class StartTaskComponent implements OnInit {
constructor(private taskService: TaskListService,
private dateAdapter: DateAdapter<Moment>,
private preferences: UserPreferencesService,
private formBuilder: FormBuilder,
private logService: LogService) {
}
ngOnInit() {
this.field = new FormFieldModel(new FormModel(), {id: this.assigneeId, value: this.assigneeId, placeholder: 'Assignee'});
if (this.name) {
this.taskDetailsModel.name = this.name;
}
this.validateMaxTaskNameLength();
this.field = new FormFieldModel(new FormModel(), { id: this.assigneeId, value: this.assigneeId, placeholder: 'Assignee' });
this.preferences.locale$.subscribe((locale) => {
this.dateAdapter.setLocale(locale);
});
this.loadFormsTask();
this.buildForm();
}
public start(): void {
if (this.startTaskModel.name) {
if (this.appId) {
this.startTaskModel.category = this.appId.toString();
}
this.taskService.createNewTask(new TaskDetailsModel(this.startTaskModel))
.pipe(
switchMap((createRes: any) =>
this.attachForm(createRes.id, this.formKey).pipe(
defaultIfEmpty(createRes),
switchMap((attachRes: any) =>
this.assignTaskByUserId(createRes.id, this.assigneeId).pipe(
defaultIfEmpty(attachRes ? attachRes : createRes)
)
buildForm() {
this.taskForm = this.formBuilder.group({
name: new FormControl(this.taskDetailsModel.name, [Validators.required, Validators.maxLength(this.maxTaskNameLength)]),
description: new FormControl(''),
formKey: new FormControl('')
});
this.taskForm.valueChanges.subscribe((taskFormValues) => this.setTaskDetails(taskFormValues));
}
setTaskDetails(form) {
this.taskDetailsModel.name = form.name;
this.taskDetailsModel.description = form.description;
this.taskDetailsModel.formKey = form.formKey ? form.formKey.toString() : null;
}
isFormValid() {
return this.taskForm.valid && !this.dateError && !this.loading;
}
public saveTask(): void {
this.loading = true;
if (this.appId) {
this.taskDetailsModel.category = this.appId.toString();
}
this.taskService.createNewTask(this.taskDetailsModel)
.pipe(
switchMap((createRes: any) =>
this.attachForm(createRes.id, this.taskDetailsModel.formKey).pipe(
defaultIfEmpty(createRes),
switchMap((attachRes: any) =>
this.assignTaskByUserId(createRes.id, this.assigneeId).pipe(
defaultIfEmpty(attachRes ? attachRes : createRes)
)
)
)
)
.subscribe(
(res: any) => {
this.success.emit(res);
},
(err) => {
this.error.emit(err);
this.logService.error('An error occurred while creating new task');
});
}
)
.subscribe(
(res: any) => {
this.loading = false;
this.success.emit(res);
},
(err) => {
this.loading = false;
this.error.emit(err);
this.logService.error('An error occurred while creating new task');
});
}
getAssigneeId(userId) {
@@ -145,13 +170,7 @@ export class StartTaskComponent implements OnInit {
}
private loadFormsTask(): void {
this.taskService.getFormList().subscribe((res: Form[]) => {
this.forms = res;
},
(err) => {
this.error.emit(err);
this.logService.error('An error occurred while trying to get the forms');
});
this.forms$ = this.taskService.getFormList();
}
public isUserNameEmpty(user: UserProcessModel): boolean {
@@ -168,20 +187,45 @@ export class StartTaskComponent implements OnInit {
return firstName + delimiter + lastName;
}
onDateChanged(newDateValue): void {
onDateChanged(newDateValue: any) {
this.dateError = false;
if (newDateValue) {
let momentDate = moment(newDateValue, this.FORMAT_DATE, true);
if (!momentDate.isValid()) {
this.dateError = true;
let momentDate;
if (typeof newDateValue === 'string') {
momentDate = moment(newDateValue, this.FORMAT_DATE, true);
} else {
momentDate = newDateValue;
}
if (momentDate.isValid()) {
this.taskDetailsModel.dueDate = momentDate.toDate();
} else {
this.dateError = true;
this.taskDetailsModel.dueDate = null;
}
} else {
this.taskDetailsModel.dueDate = null;
}
}
clearDateInput() {
const emptyValue = '';
this.startTaskModel.dueDate = emptyValue;
this.onDateChanged(emptyValue);
private validateMaxTaskNameLength() {
if (this.maxTaskNameLength > this.MAX_LENGTH) {
this.maxTaskNameLength = this.MAX_LENGTH;
this.logService.log(`the task name length cannot be greater than ${this.MAX_LENGTH}`);
}
}
get nameController(): AbstractControl {
return this.taskForm.get('name');
}
get descriptionController(): AbstractControl {
return this.taskForm.get('description');
}
get formKeyController(): AbstractControl {
return this.taskForm.get('formKey');
}
}