[ADF-3438] Task List Demo - created date filter and pagination (#3782)

* date filter and pagination

* remove wrong mat-form-field
This commit is contained in:
bbcodrin
2018-09-14 18:55:57 +03:00
committed by Eugenio Romano
parent c445066516
commit 73a5eddebd
8 changed files with 153 additions and 72 deletions

View File

@@ -1,40 +1,40 @@
<div class="task-list-demo-inputs"> <div class="task-list-demo-inputs">
<form [formGroup]="taskListForm"> <form [formGroup]="taskListForm">
<mat-form-field> <mat-form-field>
<mat-label>App Id</mat-label> <mat-label>App Id</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskAppId"> [formControl]="taskAppId">
<mat-error *ngIf="taskAppId.hasError('pattern')"> <mat-error *ngIf="taskAppId.hasError('pattern')">
{{ 'TASK_LIST_DEMO.ERROR_MESSAGE.APP_ID_TYPE_ERROR' | translate }} {{ 'TASK_LIST_DEMO.ERROR_MESSAGE.APP_ID_TYPE_ERROR' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Task Name</mat-label> <mat-label>Task Name</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskName"> [formControl]="taskName">
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Task Id</mat-label> <mat-label>Task Id</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskId"> [formControl]="taskId">
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Start</mat-label> <mat-label>Start</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
matTooltip="{{ 'TASK_LIST_DEMO.TOOLTIP_MESSAGE.START_INPUT' | translate }}" matTooltip="{{ 'TASK_LIST_DEMO.TOOLTIP_MESSAGE.START_INPUT' | translate }}"
[formControl]="taskStart"> [formControl]="taskStart">
<mat-error *ngIf="taskStart.hasError('pattern')"> <mat-error *ngIf="taskStart.hasError('pattern')">
{{ 'TASK_LIST_DEMO.ERROR_MESSAGE.NUMBER_TYPE_ERROR' | translate }} {{ 'TASK_LIST_DEMO.ERROR_MESSAGE.NUMBER_TYPE_ERROR' | translate }}
</mat-error> </mat-error>
@@ -42,72 +42,95 @@
<mat-form-field> <mat-form-field>
<mat-label>ProcessDefinitionId</mat-label> <mat-label>ProcessDefinitionId</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskProcessDefinitionId"> [formControl]="taskProcessDefinitionId">
<mat-hint>E.g. SimpleProcess:1:2</mat-hint> <mat-hint>E.g. SimpleProcess:1:2</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>ProcessInstanceId</mat-label> <mat-label>ProcessInstanceId</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskProcessInstanceId"> [formControl]="taskProcessInstanceId">
<mat-hint>E.g. 12345</mat-hint> <mat-hint>E.g. 12345</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Items per page</mat-label> <mat-label>Items per page</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskSize"> [formControl]="taskSize">
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Page</mat-label> <mat-label>Page</mat-label>
<input <input
matInput matInput
class="form-control" class="form-control"
[formControl]="taskPage"> [formControl]="taskPage">
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Process Instance</mat-label> <mat-label>Due After</mat-label>
<mat-select <input matInput class="form-control" [matDatepicker]="pickerAfter" placeholder="Choose a date"
[formControl]="taskDueAfter">
<mat-datepicker-toggle matSuffix [for]="pickerAfter"></mat-datepicker-toggle>
<mat-datepicker #pickerAfter></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Due Before</mat-label>
<input matInput class="form-control" [matDatepicker]="pickerBefore" placeholder="Choose a date"
[formControl]="taskDueBefore">
<mat-datepicker-toggle matSuffix [for]="pickerBefore"></mat-datepicker-toggle>
<mat-datepicker #pickerBefore></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Process Instance</mat-label>
<mat-select
class="form-control" class="form-control"
[formControl]="taskIncludeProcessInstance"> [formControl]="taskIncludeProcessInstance">
<mat-option *ngFor="let includeProcessInstanceOption of includeProcessInstanceOptions" [value]="includeProcessInstanceOption.value">{{ includeProcessInstanceOption.title }}</mat-option> <mat-option *ngFor="let includeProcessInstanceOption of includeProcessInstanceOptions"
</mat-select> [value]="includeProcessInstanceOption.value">{{ includeProcessInstanceOption.title }}
</mat-option>
</mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Assignment</mat-label> <mat-label>Assignment</mat-label>
<mat-select <mat-select
class="form-control" class="form-control"
[formControl]="taskAssignment"> [formControl]="taskAssignment">
<mat-option *ngFor="let assignmentOption of assignmentOptions" [value]="assignmentOption.value">{{ assignmentOption.title }}</mat-option> <mat-option *ngFor="let assignmentOption of assignmentOptions" [value]="assignmentOption.value">{{
</mat-select> assignmentOption.title }}
</mat-option>
</mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>State</mat-label> <mat-label>State</mat-label>
<mat-select <mat-select
class="form-control" class="form-control"
[formControl]="taskState"> [formControl]="taskState">
<mat-option *ngFor="let stateOption of stateOptions" [value]="stateOption.value">{{ stateOption.title }}</mat-option> <mat-option *ngFor="let stateOption of stateOptions" [value]="stateOption.value">{{
</mat-select> stateOption.title }}
</mat-option>
</mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Sort</mat-label> <mat-label>Sort</mat-label>
<mat-select <mat-select
class="form-control" class="form-control"
[formControl]="taskSort"> [formControl]="taskSort">
<mat-option *ngFor="let sortOption of sortOptions" [value]="sortOption.value">{{ sortOption.title }}</mat-option> <mat-option *ngFor="let sortOption of sortOptions" [value]="sortOption.value">{{ sortOption.title
</mat-select> }}
</mat-option>
</mat-select>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
@@ -128,19 +151,21 @@
[start]="start" [start]="start"
[page]="page" [page]="page"
[size]="size" [size]="size"
[dueAfter]="dueAfter"
[dueBefore]="dueBefore"
[includeProcessInstance]="includeProcessInstance" [includeProcessInstance]="includeProcessInstance"
#taskList> #taskList>
<data-columns> <data-columns>
<data-column key="id" title="Id"></data-column> <data-column key="id" title="Id"></data-column>
<data-column key="name" title="Name"></data-column> <data-column key="name" title="Name"></data-column>
<data-column key="description" title="Description"></data-column> <data-column key="description" title="Description"></data-column>
<data-column key="created" title="Created"></data-column> <data-column key="created" title="Created"></data-column>
<data-column key="dueDate" title="Due Date"></data-column> <data-column key="dueDate" title="Due Date"></data-column>
<data-column key="processInstanceId" title="Process Instance Id"></data-column> <data-column key="processInstanceId" title="Process Instance Id"></data-column>
<data-column key="processDefinitionId" title="Process Definition Id"></data-column> <data-column key="processDefinitionId" title="Process Definition Id"></data-column>
</data-columns> </data-columns>
</adf-tasklist> </adf-tasklist>
<adf-pagination <adf-pagination
[target]="taskList"> [target]="taskList">
</adf-pagination> </adf-pagination>

View File

@@ -1,12 +1,9 @@
.task-list-demo-inputs { .task-list-demo-inputs {
margin: 100px auto 0 auto; margin: 20px auto 0;
width: 80%; max-width: 1200px;
display: flex;
flex: wrap;
justify-content: space-evenly;
& mat-form-field { & mat-form-field {
margin: 20px 0; margin: 20px 5px;
width: calc(100% * (1/4) - 10px); width: calc(100% * (1/4) - 10px);
} }
} }
@@ -20,4 +17,4 @@
.task-list-demo-error-message { .task-list-demo-error-message {
color: red; color: red;
text-align: center; text-align: center;
} }

View File

@@ -55,6 +55,10 @@ export class TaskListDemoComponent implements OnInit {
page: number; page: number;
dueAfter: string;
dueBefore: string;
includeProcessInstance: boolean; includeProcessInstance: boolean;
assignmentOptions = [ assignmentOptions = [
@@ -111,6 +115,8 @@ export class TaskListDemoComponent implements OnInit {
taskSort: new FormControl(''), taskSort: new FormControl(''),
taskSize: new FormControl(''), taskSize: new FormControl(''),
taskPage: new FormControl(''), taskPage: new FormControl(''),
taskDueAfter: new FormControl(''),
taskDueBefore: new FormControl(''),
taskStart: new FormControl('', [Validators.pattern('^[0-9]*$')]), taskStart: new FormControl('', [Validators.pattern('^[0-9]*$')]),
taskIncludeProcessInstance: new FormControl('') taskIncludeProcessInstance: new FormControl('')
}); });
@@ -138,6 +144,8 @@ export class TaskListDemoComponent implements OnInit {
this.start = taskFilter.taskStart; this.start = taskFilter.taskStart;
this.size = taskFilter.taskSize; this.size = taskFilter.taskSize;
this.page = taskFilter.taskPage; this.page = taskFilter.taskPage;
this.dueAfter = taskFilter.taskDueAfter;
this.dueBefore = taskFilter.taskDueBefore;
this.includeProcessInstance = taskFilter.taskIncludeProcessInstance === 'include'; this.includeProcessInstance = taskFilter.taskIncludeProcessInstance === 'include';
} }
@@ -159,6 +167,8 @@ export class TaskListDemoComponent implements OnInit {
this.start = null; this.start = null;
this.size = null; this.size = null;
this.page = null; this.page = null;
this.dueAfter = null;
this.dueBefore = null;
} }
isFormValid() { isFormValid() {
@@ -212,4 +222,12 @@ export class TaskListDemoComponent implements OnInit {
get taskPage(): AbstractControl { get taskPage(): AbstractControl {
return this.taskListForm.get('taskPage'); return this.taskListForm.get('taskPage');
} }
get taskDueAfter(): AbstractControl {
return this.taskListForm.get('taskDueAfter');
}
get taskDueBefore(): AbstractControl {
return this.taskListForm.get('taskDueBefore');
}
} }

View File

@@ -55,6 +55,8 @@ when the task list is empty:
| appId | `number` | | The id of the app. | | appId | `number` | | The id of the app. |
| assignment | `string` | | The assignment of the process. Possible values are: "assignee" (the current user is the assignee), candidate (the current user is a task candidate", "group_x" (the task is assigned to a group where the current user is a member, no value(the current user is involved). | | assignment | `string` | | The assignment of the process. Possible values are: "assignee" (the current user is the assignee), candidate (the current user is a task candidate", "group_x" (the task is assigned to a group where the current user is a member, no value(the current user is involved). |
| data | `DataTableAdapter` | | (**Deprecated:** 2.4.0) Data source object that represents the number and the type of the columns that you want to show. | | data | `DataTableAdapter` | | (**Deprecated:** 2.4.0) Data source object that represents the number and the type of the columns that you want to show. |
| dueAfter | `string` | | Filter the tasks. Display only tasks with created_date before dueAfter.. |
| dueBefore | `string` | | Filter the tasks. Display only tasks with created_date before dueBefore. |
| includeProcessInstance | `boolean` | | Toggles inclusion of Process Instances | | includeProcessInstance | `boolean` | | Toggles inclusion of Process Instances |
| landingTaskId | `string` | | Define which task id should be selected after reloading. If the task id doesn't exist or nothing is passed then the first task will be selected. | | landingTaskId | `string` | | Define which task id should be selected after reloading. If the task id doesn't exist or nothing is passed then the first task will be selected. |
| multiselect | `boolean` | false | Toggles multiple row selection, renders checkboxes at the beginning of each row | | multiselect | `boolean` | false | Toggles multiple row selection, renders checkboxes at the beginning of each row |

View File

@@ -265,7 +265,7 @@ describe('PaginationComponent', () => {
component.ngOnInit(); component.ngOnInit();
customComponent.pagination.next(pagination); customComponent.pagination.next(pagination);
expect(component.pagination).toBe(pagination); expect(component.pagination).toEqual(pagination);
}); });
it('should update pagination by subscription', () => { it('should update pagination by subscription', () => {
@@ -280,17 +280,18 @@ describe('PaginationComponent', () => {
component.ngOnInit(); component.ngOnInit();
customComponent.pagination.next(pagination1); customComponent.pagination.next(pagination1);
expect(component.pagination).toBe(pagination1); expect(component.pagination).toEqual(pagination1);
customComponent.pagination.next(pagination2); customComponent.pagination.next(pagination2);
expect(component.pagination).toBe(pagination2); expect(component.pagination).toEqual(pagination2);
}); });
it('should send pagination event to paginated component', () => { it('should send pagination event to paginated component', () => {
const customComponent = <PaginatedComponent> { const customComponent = <PaginatedComponent> {
pagination: new BehaviorSubject<Pagination>({}), pagination: new BehaviorSubject<Pagination>({}),
updatePagination() {}, updatePagination() {},
supportedPageSizes: [] supportedPageSizes: [],
rows: []
}; };
spyOn(customComponent, 'updatePagination').and.stub(); spyOn(customComponent, 'updatePagination').and.stub();
@@ -308,7 +309,8 @@ describe('PaginationComponent', () => {
it('should go to previous page if current page has 0 items', () => { it('should go to previous page if current page has 0 items', () => {
const customComponent = <PaginatedComponent> { const customComponent = <PaginatedComponent> {
updatePagination() {}, updatePagination() {},
pagination: new BehaviorSubject<Pagination>({}) pagination: new BehaviorSubject<Pagination>({}),
rows: []
}; };
component.target = customComponent; component.target = customComponent;

View File

@@ -223,6 +223,28 @@ describe('TaskListComponent', () => {
}); });
}); });
it('should return the filtered task list by created date', (done) => {
let state = new SimpleChange(null, 'open', true);
let afterDate = new SimpleChange(null, '28-02-2017', true);
component.success.subscribe((res) => {
expect(res).toBeDefined();
expect(component.rows).toBeDefined();
expect(component.isListEmpty()).not.toBeTruthy();
expect(component.rows.length).toEqual(2);
expect(component.rows[0]['name']).toEqual('nameFake1');
expect(component.rows[0]['processDefinitionId']).toEqual('myprocess:1:4');
done();
});
component.ngAfterContentInit();
component.ngOnChanges({ 'state': state, 'afterDate': afterDate });
fixture.detectChanges();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
});
it('should return the filtered task list for all state', (done) => { it('should return the filtered task list for all state', (done) => {
let state = new SimpleChange(null, 'all', true); let state = new SimpleChange(null, 'all', true);
let processInstanceId = new SimpleChange(null, 'fakeprocessId', true); let processInstanceId = new SimpleChange(null, 'fakeprocessId', true);

View File

@@ -28,6 +28,7 @@ import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskListModel } from '../models/task-list.model'; import { TaskListModel } from '../models/task-list.model';
import { taskPresetsDefaultModel } from '../models/task-preset.model'; import { taskPresetsDefaultModel } from '../models/task-preset.model';
import { TaskListService } from './../services/tasklist.service'; import { TaskListService } from './../services/tasklist.service';
import moment from 'moment-es6';
@Component({ @Component({
selector: 'adf-tasklist', selector: 'adf-tasklist',
@@ -150,6 +151,14 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
@Input() @Input()
size: number = PaginationComponent.DEFAULT_PAGINATION.maxItems; size: number = PaginationComponent.DEFAULT_PAGINATION.maxItems;
/** Filter the tasks. Display only tasks with created_date after dueAfter. */
@Input()
dueAfter: string;
/** Filter the tasks. Display only tasks with created_date before dueBefore. */
@Input()
dueBefore: string;
rows: any[] = []; rows: any[] = [];
isLoading: boolean = true; isLoading: boolean = true;
sorting: any[] = ['created', 'desc']; sorting: any[] = ['created', 'desc'];
@@ -297,7 +306,7 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
* @param taskId * @param taskId
*/ */
isEqualToCurrentId(taskId: string): boolean { isEqualToCurrentId(taskId: string): boolean {
return this.currentInstanceId === taskId ? true : false; return this.currentInstanceId === taskId;
} }
/** /**
@@ -348,6 +357,8 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
let requestNode = { let requestNode = {
appDefinitionId: this.appId, appDefinitionId: this.appId,
dueAfter: this.dueAfter ? moment(this.dueAfter).toDate() : null,
dueBefore: this.dueBefore ? moment(this.dueBefore).toDate() : null,
processInstanceId: this.processInstanceId, processInstanceId: this.processInstanceId,
processDefinitionId: this.processDefinitionId, processDefinitionId: this.processDefinitionId,
processDefinitionKey: this.processDefinitionKey, processDefinitionKey: this.processDefinitionKey,

View File

@@ -109,6 +109,8 @@ export class FilterRepresentationModel implements UserTaskFilterRepresentation {
export class TaskQueryRequestRepresentationModel implements TaskQueryRequestRepresentation { export class TaskQueryRequestRepresentationModel implements TaskQueryRequestRepresentation {
appDefinitionId: string; appDefinitionId: string;
dueAfter: string;
dueBefore: string;
processInstanceId: string; processInstanceId: string;
processDefinitionId: string; processDefinitionId: string;
text: string; text: string;
@@ -124,6 +126,8 @@ export class TaskQueryRequestRepresentationModel implements TaskQueryRequestRepr
constructor(obj?: any) { constructor(obj?: any) {
if (obj) { if (obj) {
this.appDefinitionId = obj.appDefinitionId || null; this.appDefinitionId = obj.appDefinitionId || null;
this.dueAfter = obj.dueAfter || null;
this.dueBefore = obj.dueBefore || null;
this.processInstanceId = obj.processInstanceId || null; this.processInstanceId = obj.processInstanceId || null;
this.processDefinitionId = obj.processDefinitionId || null; this.processDefinitionId = obj.processDefinitionId || null;
this.text = obj.text || null; this.text = obj.text || null;