[ADF-1309] Task List Pagination (#2255)

* Basic version

* Fix pagination errors

* Fix error on complete task

* Add error

* Fix unit test

* Remove the external paginator component

* Rollback unit test about error event
This commit is contained in:
Maurizio Vitale 2017-08-29 14:28:27 +01:00 committed by Mario Romano
parent 8e3d84504a
commit 5d22e78bb7
28 changed files with 646 additions and 367 deletions

View File

@ -27,6 +27,8 @@
*ngIf="taskFilter && !isStartTaskMode()"> *ngIf="taskFilter && !isStartTaskMode()">
<activiti-tasklist <activiti-tasklist
[appId]="taskFilter?.appId" [appId]="taskFilter?.appId"
[page]="taskPage"
[size]="taskPagination.maxItems"
[processDefinitionKey]="taskFilter?.filter?.processDefinitionKey" [processDefinitionKey]="taskFilter?.filter?.processDefinitionKey"
[name]="taskFilter?.filter?.name" [name]="taskFilter?.filter?.name"
[assignment]="taskFilter?.filter?.assignment" [assignment]="taskFilter?.filter?.assignment"
@ -47,6 +49,15 @@
</data-columns> </data-columns>
--> -->
</activiti-tasklist> </activiti-tasklist>
<adf-pagination
(changePageNumber)="onChangePageNumber($event)"
(changePageSize)="onChangePageSize($event)"
(nextPage)="onNextPage($event)"
(prevPage)="onPrevPage($event)"
[pagination]="taskPagination"
[supportedPageSizes]="[2, 4, 6, 8, 10, 12]">
</adf-pagination>
</div> </div>
<div class="activiti-demo-grid-item activiti-demo-tasks-details" *ngIf="!isStartTaskMode()" <div class="activiti-demo-grid-item activiti-demo-tasks-details" *ngIf="!isStartTaskMode()"
[class.mdl-cell--7-col]="taskFilter && !isStartTaskMode()" [class.mdl-cell--7-col]="taskFilter && !isStartTaskMode()"

View File

@ -18,6 +18,7 @@
// tslint:disable-next-line:adf-file-name // tslint:disable-next-line:adf-file-name
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Pagination } from 'alfresco-js-api';
import { AnalyticsReportListComponent } from 'ng2-activiti-analytics'; import { AnalyticsReportListComponent } from 'ng2-activiti-analytics';
import { FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService } from 'ng2-activiti-form'; import { FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService } from 'ng2-activiti-form';
import { import {
@ -34,7 +35,8 @@ import {
TaskDetailsComponent, TaskDetailsComponent,
TaskDetailsEvent, TaskDetailsEvent,
TaskFiltersComponent, TaskFiltersComponent,
TaskListComponent TaskListComponent,
TaskListService
} from 'ng2-activiti-tasklist'; } from 'ng2-activiti-tasklist';
import { AlfrescoApiService } from 'ng2-alfresco-core'; import { AlfrescoApiService } from 'ng2-alfresco-core';
import { import {
@ -96,6 +98,12 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
currentProcessInstanceId: string; currentProcessInstanceId: string;
taskSchemaColumns: any [] = []; taskSchemaColumns: any [] = [];
taskPagination: Pagination = {
skipCount: 0,
maxItems: 2,
totalItems: 0
};
taskPage: number = 0;
processSchemaColumns: any [] = []; processSchemaColumns: any [] = [];
activeTab: string = 'tasks'; // tasks|processes|reports activeTab: string = 'tasks'; // tasks|processes|reports
@ -119,6 +127,7 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
constructor(private elementRef: ElementRef, constructor(private elementRef: ElementRef,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private taskListService: TaskListService,
private apiService: AlfrescoApiService, private apiService: AlfrescoApiService,
formRenderingService: FormRenderingService, formRenderingService: FormRenderingService,
formService: FormService) { formService: FormService) {
@ -157,7 +166,43 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
*/ */
} }
onPrevPage(pagination: Pagination): void {
this.taskPagination.skipCount = pagination.skipCount;
this.taskPage--;
}
onNextPage(pagination: Pagination): void {
this.taskPagination.skipCount = pagination.skipCount;
this.taskPage++;
}
onChangePageSize(pagination: Pagination): void {
const { skipCount, maxItems } = pagination;
this.taskPage = this.currentPage(skipCount, maxItems);
this.taskPagination.maxItems = maxItems;
this.taskPagination.skipCount = skipCount;
}
onChangePageNumber(pagination: Pagination): void {
const { maxItems, skipCount } = pagination;
this.taskPage = this.currentPage(skipCount, maxItems);
this.taskPagination.maxItems = maxItems;
this.taskPagination.skipCount = skipCount;
}
currentPage(skipCount: number, maxItems: number): number {
return (skipCount && maxItems) ? Math.floor(skipCount / maxItems) : 0;
}
ngOnInit() { ngOnInit() {
this.taskListService.tasksList$.subscribe(
(tasks) => {
this.taskPagination = {count: tasks.data.length, maxItems: this.taskPagination.maxItems, skipCount: this.taskPagination.skipCount, totalItems: tasks.total};
console.log({count: tasks.data.length, maxItems: this.taskPagination.maxItems, skipCount: this.taskPagination.skipCount, totalItems: tasks.total});
}, (err) => {
console.log('err');
});
if (this.router.url.includes('processes') ) { if (this.router.url.includes('processes') ) {
this.activeTab = 'processes'; this.activeTab = 'processes';
} }
@ -288,8 +333,14 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
} }
onFormCompleted(form): void { onFormCompleted(form): void {
this.taskList.reload();
this.currentTaskId = null; this.currentTaskId = null;
this.taskPagination.totalItems--;
const { skipCount, maxItems, totalItems } = this.taskPagination;
if (totalItems > 0 && (skipCount >= totalItems)) {
this.taskPagination.skipCount -= maxItems;
}
this.taskPage = this.currentPage(this.taskPagination.skipCount, maxItems);
this.taskList.reload();
} }
onFormContentClick(content: any): void { onFormContentClick(content: any): void {

View File

@ -10,14 +10,9 @@ module.exports = function (config) {
'./node_modules/hammerjs/hammer.js', './node_modules/hammerjs/hammer.js',
{pattern: './node_modules/@angular/material/prebuilt-themes/indigo-pink.css', included: true, watched: false}, {pattern: './node_modules/@angular/material/prebuilt-themes/indigo-pink.css', included: true, watched: false},
//diagrams
'./node_modules/chart.js/dist/Chart.js',
'./node_modules/alfresco-js-api/dist/alfresco-js-api.js', './node_modules/alfresco-js-api/dist/alfresco-js-api.js',
'./node_modules/raphael/raphael.js',
'./node_modules/moment/min/moment.min.js', './node_modules/moment/min/moment.min.js',
{pattern: './node_modules/ng2-translate/**/*.js', included: false, watched: false},
{pattern: './node_modules/ng2-charts/**/*.js', included: false, served: true, watched: false},
{pattern: './node_modules/moment/**/*.js', included: false, served: true, watched: false}, {pattern: './node_modules/moment/**/*.js', included: false, served: true, watched: false},
{pattern: 'karma-test-shim.js', watched: false}, {pattern: 'karma-test-shim.js', watched: false},

View File

@ -0,0 +1,30 @@
/*!
* @license
* Copyright 2016 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 { Injectable } from '@angular/core';
@Injectable()
export class AppConfigServiceMock {
constructor() { }
/** @override */
get(key: string) { }
load(resource: string, values?: {}) { }
}

View File

@ -84,7 +84,7 @@ export let fakeTaskList = {
}; };
export let fakeTaskListDifferentProcessDefinitionKey = { export let fakeTaskListDifferentProcessDefinitionKey = {
size: 1, total: 1, start: 0, size: 2, total: 1, start: 0,
data: [ data: [
{ {
id: '1', name: 'FakeNameTask', description: null, category: null, id: '1', name: 'FakeNameTask', description: null, category: null,

View File

@ -0,0 +1,28 @@
/*!
* @license
* Copyright 2016 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 { Observable } from 'rxjs/Rx';
export class TranslationMock {
public get(key: string|Array<string>, interpolateParams?: Object): Observable<string|any> {
return Observable.of(key);
}
addTranslationFolder() {
}
}

View File

@ -18,9 +18,10 @@
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { TranslationMock } from '../assets/translation.service.mock';
import { defaultApp, deployedApps, nonDeployedApps } from './../assets/apps-list.mock'; import { defaultApp, deployedApps, nonDeployedApps } from './../assets/apps-list.mock';
import { TaskListService } from './../services/tasklist.service'; import { TaskListService } from './../services/tasklist.service';
import { AppsListComponent } from './apps-list.component'; import { AppsListComponent } from './apps-list.component';
@ -43,13 +44,11 @@ describe('AppsListComponent', () => {
AppsListComponent AppsListComponent
], ],
providers: [ providers: [
TaskListService TaskListService,
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents(); }).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -17,8 +17,9 @@
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from '../services/tasklist.service'; import { TaskListService } from '../services/tasklist.service';
import { ChecklistComponent } from './checklist.component'; import { ChecklistComponent } from './checklist.component';
@ -46,15 +47,11 @@ describe('ChecklistComponent', () => {
ChecklistComponent ChecklistComponent
], ],
providers: [ providers: [
TaskListService TaskListService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => {
return Observable.of(key);
});
fixture = TestBed.createComponent(ChecklistComponent); fixture = TestBed.createComponent(ChecklistComponent);
checklistComponent = fixture.componentInstance; checklistComponent = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;

View File

@ -17,10 +17,12 @@
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { DataRowEvent, DataTableModule, ObjectDataRow } from 'ng2-alfresco-datatable'; import { DataRowEvent, DataTableModule, ObjectDataRow } from 'ng2-alfresco-datatable';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { Comment } from '../models/comment.model'; import { Comment } from '../models/comment.model';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { CommentListComponent } from './comment-list.component'; import { CommentListComponent } from './comment-list.component';
declare let jasmine: any; declare let jasmine: any;
@ -51,7 +53,9 @@ describe('CommentListComponent', () => {
CommentListComponent CommentListComponent
], ],
providers: [ providers: [
DatePipe DatePipe,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents().then(() => { }).compileComponents().then(() => {

View File

@ -20,7 +20,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { ActivitiFormModule } from 'ng2-activiti-form'; import { ActivitiFormModule } from 'ng2-activiti-form';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { MdInputModule } from '@angular/material'; import { MdInputModule } from '@angular/material';
@ -54,13 +56,12 @@ describe('CommentsComponent', () => {
providers: [ providers: [
TaskListService, TaskListService,
DatePipe, DatePipe,
PeopleService PeopleService,
{ provide: TranslationService, useClass: TranslationMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock }
] ]
}).compileComponents(); }).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -20,8 +20,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { ActivitiContentService } from 'ng2-activiti-form'; import { ActivitiContentService } from 'ng2-activiti-form';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { AttachmentComponent } from './create-task-attachment.component'; import { AttachmentComponent } from './create-task-attachment.component';
describe('Activiti Task Create Attachment', () => { describe('Activiti Task Create Attachment', () => {
@ -41,7 +42,8 @@ describe('Activiti Task Create Attachment', () => {
AttachmentComponent AttachmentComponent
], ],
providers: [ providers: [
{provide: AlfrescoTranslationService}, { provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock },
ActivitiContentService ActivitiContentService
] ]
}).compileComponents(); }).compileComponents();

View File

@ -16,9 +16,10 @@
*/ */
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { DataRowActionEvent, DataRowEvent, DataTableModule, ObjectDataRow } from 'ng2-alfresco-datatable'; import { DataRowActionEvent, DataRowEvent, DataTableModule, ObjectDataRow } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Observable'; import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { UserEventModel } from '../models/user-event.model'; import { UserEventModel } from '../models/user-event.model';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { PeopleListComponent } from './people-list.component'; import { PeopleListComponent } from './people-list.component';
@ -47,15 +48,13 @@ describe('PeopleListComponent', () => {
], ],
declarations: [ declarations: [
PeopleListComponent PeopleListComponent
],
providers: [
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => {
return Observable.of(key);
});
fixture = TestBed.createComponent(PeopleListComponent); fixture = TestBed.createComponent(PeopleListComponent);
peopleListComponent = fixture.componentInstance; peopleListComponent = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;

View File

@ -17,9 +17,11 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MdButtonModule, MdInputModule } from '@angular/material'; import { MdButtonModule, MdInputModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable'; import { DataTableModule } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { PeopleListComponent } from './people-list.component'; import { PeopleListComponent } from './people-list.component';
import { PeopleSearchComponent } from './people-search.component'; import { PeopleSearchComponent } from './people-search.component';
@ -60,13 +62,13 @@ describe('PeopleSearchComponent', () => {
declarations: [ declarations: [
PeopleSearchComponent, PeopleSearchComponent,
PeopleListComponent PeopleListComponent
],
providers: [
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
fixture = TestBed.createComponent(PeopleSearchComponent); fixture = TestBed.createComponent(PeopleSearchComponent);
peopleSearchComponent = fixture.componentInstance; peopleSearchComponent = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;

View File

@ -18,9 +18,10 @@
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MdButtonModule, MdInputModule } from '@angular/material'; import { MdButtonModule, MdInputModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, LogService, TranslationService } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable'; import { DataTableModule } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Observable'; import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { PeopleService } from '../services/people.service'; import { PeopleService } from '../services/people.service';
import { PeopleListComponent } from './people-list.component'; import { PeopleListComponent } from './people-list.component';
@ -66,17 +67,14 @@ describe('PeopleComponent', () => {
PeopleComponent PeopleComponent
], ],
providers: [ providers: [
PeopleService PeopleService,
{ provide: TranslationService, useClass: TranslationMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock }
], ],
schemas: [ NO_ERRORS_SCHEMA ] schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
logService = TestBed.get(LogService); logService = TestBed.get(LogService);
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
fixture = TestBed.createComponent(PeopleComponent); fixture = TestBed.createComponent(PeopleComponent);
activitiPeopleComponent = fixture.componentInstance; activitiPeopleComponent = fixture.componentInstance;
element = fixture.nativeElement; element = fixture.nativeElement;

View File

@ -17,8 +17,10 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MdButtonModule, MdDatepickerModule, MdGridListModule, MdIconModule, MdInputModule, MdNativeDateModule, MdSelectModule } from '@angular/material'; import { MdButtonModule, MdDatepickerModule, MdGridListModule, MdIconModule, MdInputModule, MdNativeDateModule, MdSelectModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { StartTaskModel } from '../models/start-task.model'; import { StartTaskModel } from '../models/start-task.model';
import { PeopleService } from '../services/people.service'; import { PeopleService } from '../services/people.service';
import { TaskListService } from '../services/tasklist.service'; import { TaskListService } from '../services/tasklist.service';
@ -65,12 +67,11 @@ describe('StartTaskComponent', () => {
], ],
providers: [ providers: [
TaskListService, TaskListService,
PeopleService PeopleService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
fixture = TestBed.createComponent(StartTaskComponent); fixture = TestBed.createComponent(StartTaskComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@ -19,11 +19,12 @@ import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MdProgressSpinnerModule } from '@angular/material'; import { MdProgressSpinnerModule } from '@angular/material';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { ActivitiContentService } from 'ng2-activiti-form'; import { ActivitiContentService } from 'ng2-activiti-form';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable'; import { DataTableModule } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { TaskAttachmentListComponent } from './task-attachment-list.component'; import { TaskAttachmentListComponent } from './task-attachment-list.component';
declare let jasmine: any; declare let jasmine: any;
@ -50,21 +51,13 @@ describe('TaskAttachmentList', () => {
TaskAttachmentListComponent TaskAttachmentListComponent
], ],
providers: [ providers: [
ActivitiContentService ActivitiContentService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents(); }).compileComponents();
let translateService: AlfrescoTranslationService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => {
return Observable.of(key);
});
let nativeTranslateService: TranslateService = TestBed.get(TranslateService);
spyOn(nativeTranslateService, 'get').and.callFake((key) => {
return Observable.of(key);
});
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -22,8 +22,10 @@ import { By } from '@angular/platform-browser';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { ActivitiFormModule, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form'; import { ActivitiFormModule, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form';
import { AlfrescoTranslationService, CoreModule, LogService } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, LogService, TranslationService } from 'ng2-alfresco-core';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { noDataMock, taskDetailsMock, taskFormMock, tasksMock } from './../assets/task-details.mock'; import { noDataMock, taskDetailsMock, taskFormMock, tasksMock } from './../assets/task-details.mock';
@ -70,15 +72,15 @@ describe('TaskDetailsComponent', () => {
], ],
providers: [ providers: [
TaskListService, TaskListService,
PeopleService PeopleService,
{ provide: TranslationService, useClass: TranslationMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock }
], ],
schemas: [ NO_ERRORS_SCHEMA ] schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents(); }).compileComponents();
logService = TestBed.get(LogService); logService = TestBed.get(LogService);
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -288,7 +288,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
onFormCompleted(form: FormModel): void { onFormCompleted(form: FormModel): void {
this.formCompleted.emit(form); this.formCompleted.emit(form);
if (this.showNextTask) { if (this.showNextTask && (this.taskDetails.processInstanceId || this.taskDetails.processDefinitionId)) {
this.loadNextTask(this.taskDetails.processInstanceId, this.taskDetails.processDefinitionId); this.loadNextTask(this.taskDetails.processInstanceId, this.taskDetails.processDefinitionId);
} }
} }

View File

@ -16,18 +16,19 @@
*/ */
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { async } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LogServiceMock } from 'ng2-alfresco-core'; import { AppConfigModule, AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { FilterParamsModel, FilterRepresentationModel } from '../models/filter.model'; import { FilterParamsModel, FilterRepresentationModel } from '../models/filter.model';
import { TaskListService } from '../services/tasklist.service'; import { TaskListService } from '../services/tasklist.service';
import { TaskFiltersComponent } from './task-filters.component'; import { TaskFiltersComponent } from './task-filters.component';
describe('TaskFiltersComponent', () => { describe('TaskFiltersComponent', () => {
let filterList: TaskFiltersComponent;
let activitiService: TaskListService; let activitiService: TaskListService;
let logService: LogServiceMock;
let fakeGlobalFilter = []; let fakeGlobalFilter = [];
fakeGlobalFilter.push(new FilterRepresentationModel({ fakeGlobalFilter.push(new FilterRepresentationModel({
@ -63,29 +64,81 @@ describe('TaskFiltersComponent', () => {
reject(fakeErrorFilterList); reject(fakeErrorFilterList);
}); });
let component: TaskFiltersComponent;
let fixture: ComponentFixture<TaskFiltersComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
AppConfigModule.forRoot('app.config.json', {
bpmHost: 'http://localhost:9876/bpm'
})
],
declarations: [
TaskFiltersComponent
],
providers: [
TaskListService,
{ provide: TranslationService, useClass: TranslationMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock }
]
}).compileComponents();
}));
beforeEach(() => { beforeEach(() => {
logService = new LogServiceMock(); fixture = TestBed.createComponent(TaskFiltersComponent);
activitiService = new TaskListService(null, logService); component = fixture.componentInstance;
filterList = new TaskFiltersComponent(activitiService);
activitiService = TestBed.get(TaskListService);
});
it('should emit an error with a bad response', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
const appId = '1';
let change = new SimpleChange(null, appId, true);
component.ngOnChanges({ 'appId': change });
component.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
});
it('should emit an error with a bad response', (done) => {
spyOn(activitiService, 'getDeployedApplications').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
const appId = 'fake-app';
let change = new SimpleChange(null, appId, true);
component.ngOnChanges({ 'appName': change });
component.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
}); });
it('should return the filter task list', (done) => { it('should return the filter task list', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change }); component.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.filters).toBeDefined(); expect(component.filters).toBeDefined();
expect(filterList.filters.length).toEqual(3); expect(component.filters.length).toEqual(3);
expect(filterList.filters[0].name).toEqual('FakeInvolvedTasks'); expect(component.filters[0].name).toEqual('FakeInvolvedTasks');
expect(filterList.filters[1].name).toEqual('FakeMyTasks1'); expect(component.filters[1].name).toEqual('FakeMyTasks1');
expect(filterList.filters[2].name).toEqual('FakeMyTasks2'); expect(component.filters[2].name).toEqual('FakeMyTasks2');
done(); done();
}); });
filterList.ngOnInit(); component.ngOnInit();
}); });
it('should return the filter task list, filtered By Name', (done) => { it('should return the filter task list, filtered By Name', (done) => {
@ -98,46 +151,16 @@ describe('TaskFiltersComponent', () => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
let change = new SimpleChange(null, 'test', true); let change = new SimpleChange(null, 'test', true);
filterList.ngOnChanges({ 'appName': change }); component.ngOnChanges({ 'appName': change });
filterList.onSuccess.subscribe((res) => { component.onSuccess.subscribe((res) => {
let deployApp: any = activitiService.getDeployedApplications; let deployApp: any = activitiService.getDeployedApplications;
expect(deployApp.calls.count()).toEqual(1); expect(deployApp.calls.count()).toEqual(1);
expect(res).toBeDefined(); expect(res).toBeDefined();
done(); done();
}); });
filterList.ngOnInit(); component.ngOnInit();
});
it('should emit an error with a bad response', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
const appId = '1';
let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
filterList.ngOnInit();
});
it('should emit an error with a bad response', (done) => {
spyOn(activitiService, 'getDeployedApplications').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
const appId = 'fake-app';
let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appName': change });
filterList.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
filterList.ngOnInit();
}); });
it('should select the first filter as default', (done) => { it('should select the first filter as default', (done) => {
@ -145,135 +168,139 @@ describe('TaskFiltersComponent', () => {
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { fixture.detectChanges();
component.ngOnChanges({ 'appId': change });
component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); expect(component.currentFilter.name).toEqual('FakeInvolvedTasks');
done(); done();
}); });
filterList.ngOnInit();
}); });
it('should select the task filter based on the input by name param', (done) => { it('should select the task filter based on the input by name param', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
filterList.filterParam = new FilterParamsModel({name: 'FakeMyTasks1'}); component.filterParam = new FilterParamsModel({name: 'FakeMyTasks1'});
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { fixture.detectChanges();
component.ngOnChanges({ 'appId': change });
component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(filterList.currentFilter.name).toEqual('FakeMyTasks1'); expect(component.currentFilter.name).toEqual('FakeMyTasks1');
done(); done();
}); });
filterList.ngOnInit();
}); });
it('should select the default task filter if filter input does not exist', (done) => { it('should select the default task filter if filter input does not exist', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
filterList.filterParam = new FilterParamsModel({name: 'UnexistableFilter'}); component.filterParam = new FilterParamsModel({name: 'UnexistableFilter'});
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { fixture.detectChanges();
component.ngOnChanges({ 'appId': change });
component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); expect(component.currentFilter.name).toEqual('FakeInvolvedTasks');
done(); done();
}); });
filterList.ngOnInit();
}); });
it('should select the task filter based on the input by index param', (done) => { it('should select the task filter based on the input by index param', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
filterList.filterParam = new FilterParamsModel({index: 2}); component.filterParam = new FilterParamsModel({index: 2});
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { fixture.detectChanges();
component.ngOnChanges({ 'appId': change });
component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(filterList.currentFilter.name).toEqual('FakeMyTasks2'); expect(component.currentFilter.name).toEqual('FakeMyTasks2');
done(); done();
}); });
filterList.ngOnInit();
}); });
it('should select the task filter based on the input by id param', (done) => { it('should select the task filter based on the input by id param', (done) => {
spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise)); spyOn(activitiService, 'getTaskListFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
filterList.filterParam = new FilterParamsModel({id: 10}); component.filterParam = new FilterParamsModel({id: 10});
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change });
filterList.onSuccess.subscribe((res) => { fixture.detectChanges();
component.ngOnChanges({ 'appId': change });
component.onSuccess.subscribe((res) => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(filterList.currentFilter).toBeDefined(); expect(component.currentFilter).toBeDefined();
expect(filterList.currentFilter.name).toEqual('FakeInvolvedTasks'); expect(component.currentFilter.name).toEqual('FakeInvolvedTasks');
done(); done();
}); });
filterList.ngOnInit();
}); });
it('should emit an event when a filter is selected', (done) => { it('should emit an event when a filter is selected', (done) => {
let currentFilter = new FilterRepresentationModel({ filter: { state: 'open', assignment: 'fake-involved' } }); let currentFilter = new FilterRepresentationModel({ filter: { state: 'open', assignment: 'fake-involved' } });
filterList.filterClick.subscribe((filter: FilterRepresentationModel) => { component.filterClick.subscribe((filter: FilterRepresentationModel) => {
expect(filter).toBeDefined(); expect(filter).toBeDefined();
expect(filter).toEqual(currentFilter); expect(filter).toEqual(currentFilter);
expect(filterList.currentFilter).toEqual(currentFilter); expect(component.currentFilter).toEqual(currentFilter);
done(); done();
}); });
filterList.selectFilter(currentFilter); component.selectFilter(currentFilter);
}); });
it('should reload filters by appId on binding changes', () => { it('should reload filters by appId on binding changes', () => {
spyOn(filterList, 'getFiltersByAppId').and.stub(); spyOn(component, 'getFiltersByAppId').and.stub();
const appId = '1'; const appId = '1';
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change }); component.ngOnChanges({ 'appId': change });
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId); expect(component.getFiltersByAppId).toHaveBeenCalledWith(appId);
}); });
it('should reload filters by appId null on binding changes', () => { it('should reload filters by appId null on binding changes', () => {
spyOn(filterList, 'getFiltersByAppId').and.stub(); spyOn(component, 'getFiltersByAppId').and.stub();
const appId = null; const appId = null;
let change = new SimpleChange(null, appId, true); let change = new SimpleChange(null, appId, true);
filterList.ngOnChanges({ 'appId': change }); component.ngOnChanges({ 'appId': change });
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId); expect(component.getFiltersByAppId).toHaveBeenCalledWith(appId);
}); });
it('should reload filters by app name on binding changes', () => { it('should reload filters by app name on binding changes', () => {
spyOn(filterList, 'getFiltersByAppName').and.stub(); spyOn(component, 'getFiltersByAppName').and.stub();
const appName = 'fake-app-name'; const appName = 'fake-app-name';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
filterList.ngOnChanges({ 'appName': change }); component.ngOnChanges({ 'appName': change });
expect(filterList.getFiltersByAppName).toHaveBeenCalledWith(appName); expect(component.getFiltersByAppName).toHaveBeenCalledWith(appName);
}); });
it('should return the current filter after one is selected', () => { it('should return the current filter after one is selected', () => {
@ -281,27 +308,32 @@ describe('TaskFiltersComponent', () => {
name: 'FakeMyTasks', name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' } filter: { state: 'open', assignment: 'fake-assignee' }
}); });
expect(filterList.currentFilter).toBeUndefined(); expect(component.currentFilter).toBeUndefined();
filterList.selectFilter(filter); component.selectFilter(filter);
expect(filterList.getCurrentFilter()).toBe(filter); expect(component.getCurrentFilter()).toBe(filter);
}); });
it('should load Default list when no appid or taskid are provided', () => { it('should load Default list when no appid or taskid are provided', () => {
spyOn(filterList, 'getFiltersByAppId').and.stub(); spyOn(component, 'getFiltersByAppId').and.stub();
let change = new SimpleChange(null, null, true); let change = new SimpleChange(null, null, true);
filterList.ngOnChanges({ 'appName': change }); component.ngOnChanges({ 'appName': change });
expect(filterList.getFiltersByAppId).toHaveBeenCalled(); expect(component.getFiltersByAppId).toHaveBeenCalled();
}); });
it('should change the current filter if a filter with taskid is found', async(() => { it('should change the current filter if a filter with taskid is found', async(() => {
spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(fakeFilter)); spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(fakeFilter));
filterList.filters = fakeGlobalFilter; component.filters = fakeGlobalFilter;
filterList.selectFilterWithTask('111'); component.selectFilterWithTask('111');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(component.currentFilter.landingTaskId).toBeDefined();
expect(component.currentFilter.landingTaskId).toBe('111');
});
expect(filterList.currentFilter.landingTaskId).toBeDefined();
expect(filterList.currentFilter.landingTaskId).toBe('111');
})); }));
it('should not change the current filter if no filter with taskid is found', async(() => { it('should not change the current filter if no filter with taskid is found', async(() => {
@ -309,11 +341,11 @@ describe('TaskFiltersComponent', () => {
name: 'FakeMyTasks', name: 'FakeMyTasks',
filter: { state: 'open', assignment: 'fake-assignee' } filter: { state: 'open', assignment: 'fake-assignee' }
}); });
filterList.filters = fakeGlobalFilter; component.filters = fakeGlobalFilter;
filterList.currentFilter = filter; component.currentFilter = filter;
spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(null)); spyOn(activitiService, 'isTaskRelatedToFilter').and.returnValue(Observable.of(null));
filterList.selectFilterWithTask('111'); component.selectFilterWithTask('111');
expect(filterList.currentFilter).toBe(filter); expect(component.currentFilter).toBe(filter);
})); }));
}); });

View File

@ -23,8 +23,7 @@ import { TaskListService } from './../services/tasklist.service';
@Component({ @Component({
selector: 'adf-filters, activiti-filters', selector: 'adf-filters, activiti-filters',
templateUrl: './task-filters.component.html', templateUrl: './task-filters.component.html',
styleUrls: ['task-filters.component.scss'], styleUrls: ['task-filters.component.scss']
providers: [TaskListService]
}) })
export class TaskFiltersComponent implements OnInit, OnChanges { export class TaskFiltersComponent implements OnInit, OnChanges {

View File

@ -18,8 +18,9 @@
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { AlfrescoTranslationService, CardViewUpdateService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CardViewUpdateService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { taskDetailsMock } from './../assets/task-details.mock'; import { taskDetailsMock } from './../assets/task-details.mock';
@ -44,13 +45,12 @@ describe('TaskHeaderComponent', () => {
], ],
providers: [ providers: [
TaskListService, TaskListService,
CardViewUpdateService CardViewUpdateService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents(); }).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService.translate, 'get').and.callFake((key) => { return Observable.of(key); });
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -18,64 +18,67 @@
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MdProgressSpinnerModule } from '@angular/material'; import { MdProgressSpinnerModule } from '@angular/material';
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; import { AppConfigModule, AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable'; import { DataTableModule } from 'ng2-alfresco-datatable';
import { DataRowEvent, ObjectDataRow, ObjectDataTableAdapter } from 'ng2-alfresco-datatable'; import { DataRowEvent, ObjectDataRow, ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Rx'; import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { TaskListService } from '../services/tasklist.service'; import { TaskListService } from '../services/tasklist.service';
import { TaskListComponent } from './tasklist.component'; import { TaskListComponent } from './tasklist.component';
declare let jasmine: any;
describe('TaskListComponent', () => { describe('TaskListComponent', () => {
let fakeGlobalTask = [ let fakeGlobalTask = {
{ size: 2,
id: 14, name: 'nameFake1', start: 0,
description: 'descriptionFake1', total: 2,
category: 'categoryFake1', data: [
assignee: { {
id: 2, firstName: 'firstNameFake1', lastName: 'lastNameFake1', email: 'emailFake1' id: 14, name: 'nameFake1',
description: 'descriptionFake1',
category: 'categoryFake1',
assignee: {
id: 2, firstName: 'firstNameFake1', lastName: 'lastNameFake1', email: 'emailFake1'
},
created: '2017-03-01T12:25:17.189+0000',
dueDate: '2017-04-02T12:25:17.189+0000',
endDate: '2017-05-03T12:25:31.129+0000',
duration: 13940,
priority: 50,
parentTaskId: 1,
parentTaskName: 'parentTaskNameFake',
processInstanceId: 2511,
processInstanceName: 'processInstanceNameFake',
processDefinitionId: 'myprocess:1:4',
processDefinitionName: 'processDefinitionNameFake',
processDefinitionDescription: 'processDefinitionDescriptionFake',
processDefinitionKey: 'myprocess',
processDefinitionCategory: 'http://www.activiti.org/processdef',
processDefinitionVersion: 1,
processDefinitionDeploymentId: '1',
formKey: 1,
processInstanceStartUserId: null,
initiatorCanCompleteTask: false,
adhocTaskCanBeReassigned: false,
taskDefinitionKey: 'sid-B6813AF5-8ACD-4481-A4D5-8BAAD1CB1416',
executionId: 2511,
memberOfCandidateGroup: false,
memberOfCandidateUsers: false,
managerOfCandidateGroup: false
}, },
created: '2017-03-01T12:25:17.189+0000',
dueDate: '2017-04-02T12:25:17.189+0000',
endDate: '2017-05-03T12:25:31.129+0000',
duration: 13940,
priority: 50,
parentTaskId: 1,
parentTaskName: 'parentTaskNameFake',
processInstanceId: 2511,
processInstanceName: 'processInstanceNameFake',
processDefinitionId: 'myprocess:1:4',
processDefinitionName: 'processDefinitionNameFake',
processDefinitionDescription: 'processDefinitionDescriptionFake',
processDefinitionKey: 'myprocess',
processDefinitionCategory: 'http://www.activiti.org/processdef',
processDefinitionVersion: 1,
processDefinitionDeploymentId: '1',
formKey: 1,
processInstanceStartUserId: null,
initiatorCanCompleteTask: false,
adhocTaskCanBeReassigned: false,
taskDefinitionKey: 'sid-B6813AF5-8ACD-4481-A4D5-8BAAD1CB1416',
executionId: 2511,
memberOfCandidateGroup: false,
memberOfCandidateUsers: false,
managerOfCandidateGroup: false
},
{ {
id: 2, name: '', description: 'descriptionFake2', category: null, id: 2, name: '', description: 'descriptionFake2', category: null,
assignee: { assignee: {
id: 1, firstName: 'fistNameFake2', lastName: 'Administrator2', email: 'admin' id: 1, firstName: 'fistNameFake2', lastName: 'Administrator2', email: 'admin'
}, },
created: '2017-03-01T12:25:17.189+0000', created: '2017-03-01T12:25:17.189+0000',
dueDate: '2017-04-02T12:25:17.189+0000', dueDate: '2017-04-02T12:25:17.189+0000',
endDate: null endDate: null
} }
]; ]
let fakeGlobalTotalTasks = {
size: 2, total: 2, start: 0,
data: []
}; };
let fakeErrorTaskList = { let fakeErrorTaskList = {
@ -91,6 +94,9 @@ describe('TaskListComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
CoreModule.forRoot(), CoreModule.forRoot(),
AppConfigModule.forRoot('app.config.json', {
bpmHost: 'http://localhost:9876/bpm'
}),
DataTableModule, DataTableModule,
MdProgressSpinnerModule MdProgressSpinnerModule
], ],
@ -98,13 +104,12 @@ describe('TaskListComponent', () => {
TaskListComponent TaskListComponent
], ],
providers: [ providers: [
TaskListService TaskListService,
{provide: TranslationService, useClass: TranslationMock},
{provide: AppConfigService, useClass: AppConfigServiceMock}
] ]
}).compileComponents(); }).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
})); }));
beforeEach(() => { beforeEach(() => {
@ -121,6 +126,14 @@ describe('TaskListComponent', () => {
window['componentHandler'] = componentHandler; window['componentHandler'] = componentHandler;
}); });
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should use the default schemaColumn as default', () => { it('should use the default schemaColumn as default', () => {
component.ngAfterContentInit(); component.ngAfterContentInit();
expect(component.data.getColumns()).toBeDefined(); expect(component.data.getColumns()).toBeDefined();
@ -147,9 +160,6 @@ describe('TaskListComponent', () => {
}); });
it('should return the filtered task list when the input parameters are passed', (done) => { it('should return the filtered task list when the input parameters are passed', (done) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
let state = new SimpleChange(null, 'open', true); let state = new SimpleChange(null, 'open', true);
let processDefinitionKey = new SimpleChange(null, null, true); let processDefinitionKey = new SimpleChange(null, null, true);
let assignment = new SimpleChange(null, 'fake-assignee', true); let assignment = new SimpleChange(null, 'fake-assignee', true);
@ -185,12 +195,15 @@ describe('TaskListComponent', () => {
component.ngAfterContentInit(); component.ngAfterContentInit();
component.ngOnChanges({'state': state, 'processDefinitionKey': processDefinitionKey, 'assignment': assignment}); component.ngOnChanges({'state': state, 'processDefinitionKey': processDefinitionKey, 'assignment': assignment});
fixture.detectChanges(); fixture.detectChanges();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should return the filtered task list by processDefinitionKey', (done) => { it('should return the filtered task list by processDefinitionKey', (done) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
let state = new SimpleChange(null, 'open', true); let state = new SimpleChange(null, 'open', true);
let processDefinitionKey = new SimpleChange(null, 'fakeprocess', true); let processDefinitionKey = new SimpleChange(null, 'fakeprocess', true);
let assignment = new SimpleChange(null, 'fake-assignee', true); let assignment = new SimpleChange(null, 'fake-assignee', true);
@ -207,12 +220,15 @@ describe('TaskListComponent', () => {
component.ngAfterContentInit(); component.ngAfterContentInit();
component.ngOnChanges({'state': state, 'processDefinitionKey': processDefinitionKey, 'assignment': assignment}); component.ngOnChanges({'state': state, 'processDefinitionKey': processDefinitionKey, 'assignment': assignment});
fixture.detectChanges(); fixture.detectChanges();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should return the filtered task list by processInstanceId', (done) => { it('should return the filtered task list by processInstanceId', (done) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
let state = new SimpleChange(null, 'open', true); let state = new SimpleChange(null, 'open', true);
let processInstanceId = new SimpleChange(null, 'fakeprocessId', true); let processInstanceId = new SimpleChange(null, 'fakeprocessId', true);
let assignment = new SimpleChange(null, 'fake-assignee', true); let assignment = new SimpleChange(null, 'fake-assignee', true);
@ -230,12 +246,15 @@ describe('TaskListComponent', () => {
component.ngAfterContentInit(); component.ngAfterContentInit();
component.ngOnChanges({'state': state, 'processInstanceId': processInstanceId, 'assignment': assignment}); component.ngOnChanges({'state': state, 'processInstanceId': processInstanceId, 'assignment': assignment});
fixture.detectChanges(); 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) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
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);
@ -255,6 +274,12 @@ describe('TaskListComponent', () => {
component.ngAfterContentInit(); component.ngAfterContentInit();
component.ngOnChanges({'state': state, 'processInstanceId': processInstanceId}); component.ngOnChanges({'state': state, 'processInstanceId': processInstanceId});
fixture.detectChanges(); fixture.detectChanges();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should return a currentId null when the taskList is empty', () => { it('should return a currentId null when the taskList is empty', () => {
@ -263,8 +288,6 @@ describe('TaskListComponent', () => {
}); });
it('should throw an exception when the response is wrong', (done) => { it('should throw an exception when the response is wrong', (done) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.throw(fakeErrorTaskList));
let state = new SimpleChange(null, 'open', true); let state = new SimpleChange(null, 'open', true);
let assignment = new SimpleChange(null, 'fake-assignee', true); let assignment = new SimpleChange(null, 'fake-assignee', true);
@ -275,13 +298,17 @@ describe('TaskListComponent', () => {
}); });
component.ngAfterContentInit(); component.ngAfterContentInit();
component.ngOnChanges({'state': state, 'assignment': assignment});
fixture.detectChanges(); fixture.detectChanges();
component.ngOnChanges({'state': state, 'assignment': assignment});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 404,
contentType: 'application/json',
responseText: JSON.stringify(fakeErrorTaskList)
});
}); });
it('should reload tasks when reload() is called', (done) => { it('should reload tasks when reload() is called', (done) => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
component.state = 'open'; component.state = 'open';
component.assignment = 'fake-assignee'; component.assignment = 'fake-assignee';
component.ngAfterContentInit(); component.ngAfterContentInit();
@ -293,7 +320,14 @@ describe('TaskListComponent', () => {
expect(component.data.getRows()[0].getValue('name')).toEqual('nameFake1'); expect(component.data.getRows()[0].getValue('name')).toEqual('nameFake1');
done(); done();
}); });
fixture.detectChanges();
component.reload(); component.reload();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should emit row click event', (done) => { it('should emit row click event', (done) => {
@ -314,15 +348,14 @@ describe('TaskListComponent', () => {
describe('component changes', () => { describe('component changes', () => {
beforeEach(() => { beforeEach(() => {
spyOn(taskListService, 'getTotalTasks').and.returnValue(Observable.of(fakeGlobalTotalTasks));
spyOn(taskListService, 'getTasks').and.returnValue(Observable.of(fakeGlobalTask));
component.data = new ObjectDataTableAdapter( component.data = new ObjectDataTableAdapter(
[], [],
[ [
{type: 'text', key: 'fake-id', title: 'Name'} {type: 'text', key: 'fake-id', title: 'Name'}
] ]
); );
fixture.detectChanges();
}); });
it('should NOT reload the tasks if the loadingTaskId is the same of the current task', () => { it('should NOT reload the tasks if the loadingTaskId is the same of the current task', () => {
@ -341,7 +374,6 @@ describe('TaskListComponent', () => {
const landingTaskId = '999'; const landingTaskId = '999';
let change = new SimpleChange(null, landingTaskId, true); let change = new SimpleChange(null, landingTaskId, true);
component.ngOnChanges({'landingTaskId': change}); component.ngOnChanges({'landingTaskId': change});
expect(component.reload).not.toHaveBeenCalled(); expect(component.reload).not.toHaveBeenCalled();
expect(component.data.getRows().length).toEqual(1); expect(component.data.getRows().length).toEqual(1);
@ -371,6 +403,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'landingTaskId': change}); component.ngOnChanges({'landingTaskId': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should NOT reload the process list when no parameters changed', () => { it('should NOT reload the process list when no parameters changed', () => {
@ -391,8 +429,13 @@ describe('TaskListComponent', () => {
expect(component.data.getRows()[1].getValue('name')).toEqual('No name'); expect(component.data.getRows()[1].getValue('name')).toEqual('No name');
done(); done();
}); });
component.ngOnChanges({'appId': change}); component.ngOnChanges({'appId': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should reload the list when the processDefinitionKey parameter changes', (done) => { it('should reload the list when the processDefinitionKey parameter changes', (done) => {
@ -409,6 +452,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'processDefinitionKey': change}); component.ngOnChanges({'processDefinitionKey': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should reload the list when the state parameter changes', (done) => { it('should reload the list when the state parameter changes', (done) => {
@ -425,6 +474,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'state': change}); component.ngOnChanges({'state': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should reload the list when the sort parameter changes', (done) => { it('should reload the list when the sort parameter changes', (done) => {
@ -441,6 +496,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'sort': change}); component.ngOnChanges({'sort': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should reload the process list when the name parameter changes', (done) => { it('should reload the process list when the name parameter changes', (done) => {
@ -457,6 +518,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'name': change}); component.ngOnChanges({'name': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
it('should reload the list when the assignment parameter changes', (done) => { it('should reload the list when the assignment parameter changes', (done) => {
@ -473,6 +540,12 @@ describe('TaskListComponent', () => {
}); });
component.ngOnChanges({'assignment': change}); component.ngOnChanges({'assignment': change});
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeGlobalTask)
});
}); });
}); });
}); });

View File

@ -15,20 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
import { AfterContentInit, Component, ContentChild, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { AfterContentInit, Component, ContentChild, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { DataColumnListComponent } from 'ng2-alfresco-core'; import { DataColumnListComponent } from 'ng2-alfresco-core';
import { DataColumn, DataRowEvent, DataTableAdapter, ObjectDataRow, ObjectDataTableAdapter } from 'ng2-alfresco-datatable'; import { DataColumn, DataRowEvent, DataTableAdapter, ObjectDataRow, ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { TaskQueryRequestRepresentationModel } from '../models/filter.model'; import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskListModel } from '../models/task-list.model';
import { TaskListService } from './../services/tasklist.service'; import { TaskListService } from './../services/tasklist.service';
const DEFAULT_SIZE = 5;
@Component({ @Component({
selector: 'adf-tasklist, activiti-tasklist', selector: 'adf-tasklist, activiti-tasklist',
templateUrl: './tasklist.component.html', templateUrl: './tasklist.component.html',
styleUrls: ['./tasklist.component.css'] styleUrls: ['./tasklist.component.css']
}) })
export class TaskListComponent implements OnChanges, AfterContentInit { export class TaskListComponent implements OnChanges, OnInit, AfterContentInit {
requestNode: TaskQueryRequestRepresentationModel; requestNode: TaskQueryRequestRepresentationModel;
@ -72,6 +73,12 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
currentInstanceId: string; currentInstanceId: string;
@Input()
page: number = 0;
@Input()
size: number = DEFAULT_SIZE;
isLoading: boolean = true; isLoading: boolean = true;
/** /**
@ -92,6 +99,23 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
constructor(private taskListService: TaskListService) { constructor(private taskListService: TaskListService) {
} }
ngOnInit() {
if (this.data === undefined) {
this.data = new ObjectDataTableAdapter();
}
this.taskListService.tasksList$.subscribe(
(tasks) => {
let instancesRow = this.createDataRow(tasks.data);
this.renderInstances(instancesRow);
this.selectTask(this.landingTaskId);
this.onSuccess.emit(tasks);
this.isLoading = false;
}, (error) => {
this.onError.emit(error);
this.isLoading = false;
});
}
ngAfterContentInit() { ngAfterContentInit() {
this.setupSchema(); this.setupSchema();
} }
@ -132,32 +156,11 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
} }
private isPropertyChanged(changes: SimpleChanges): boolean { private isPropertyChanged(changes: SimpleChanges): boolean {
let changed: boolean = false; let changed: boolean = true;
let appId = changes['appId'];
let processInstanceId = changes['processInstanceId'];
let processDefinitionKey = changes['processDefinitionKey'];
let state = changes['state'];
let sort = changes['sort'];
let name = changes['name'];
let assignment = changes['assignment'];
let landingTaskId = changes['landingTaskId']; let landingTaskId = changes['landingTaskId'];
if (appId && appId.currentValue) { if (landingTaskId && landingTaskId.currentValue && this.isEqualToCurrentId(landingTaskId.currentValue)) {
changed = true; changed = false;
} else if (processInstanceId && processInstanceId.currentValue) {
changed = true;
} else if (processDefinitionKey && processDefinitionKey.currentValue) {
changed = true;
} else if (state && state.currentValue) {
changed = true;
} else if (sort && sort.currentValue) {
changed = true;
} else if (name && name.currentValue) {
changed = true;
} else if (assignment && assignment.currentValue) {
changed = true;
} else if (landingTaskId && landingTaskId.currentValue && !this.isEqualToCurrentId(landingTaskId.currentValue)) {
changed = true;
} }
return changed; return changed;
} }
@ -171,24 +174,15 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
private load(requestNode: TaskQueryRequestRepresentationModel) { private load(requestNode: TaskQueryRequestRepresentationModel) {
this.isLoading = true; this.isLoading = true;
this.loadTasksByState().subscribe( this.loadTasksByState().subscribe();
(response) => {
let instancesRow = this.createDataRow(response);
this.renderInstances(instancesRow);
this.selectTask(requestNode.landingTaskId);
this.onSuccess.emit(response);
this.isLoading = false;
}, (error) => {
this.onError.emit(error);
this.isLoading = false;
});
} }
private loadTasksByState(): Observable<TaskDetailsModel[]> { private loadTasksByState(): Observable<TaskListModel> {
return this.requestNode.state === 'all' return this.requestNode.state === 'all'
? this.taskListService.findAllTasksWhitoutState(this.requestNode) ? this.taskListService.findAllTasksWhitoutState(this.requestNode)
: this.taskListService.findAllTaskByState(this.requestNode); : this.taskListService.findTasksByState(this.requestNode);
} }
/** /**
* Create an array of ObjectDataRow * Create an array of ObjectDataRow
* @param instances * @param instances
@ -281,6 +275,7 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
} }
private createRequestNode() { private createRequestNode() {
let requestNode = { let requestNode = {
appDefinitionId: this.appId, appDefinitionId: this.appId,
processInstanceId: this.processInstanceId, processInstanceId: this.processInstanceId,
@ -289,7 +284,10 @@ export class TaskListComponent implements OnChanges, AfterContentInit {
assignment: this.assignment, assignment: this.assignment,
state: this.state, state: this.state,
sort: this.sort, sort: this.sort,
landingTaskId: this.landingTaskId landingTaskId: this.landingTaskId,
page: this.page,
size: this.size,
start: 0
}; };
return new TaskQueryRequestRepresentationModel(requestNode); return new TaskQueryRequestRepresentationModel(requestNode);
} }

View File

@ -143,6 +143,7 @@ export class TaskQueryRequestRepresentationModel {
text: string; text: string;
assignment: string; assignment: string;
state: string; state: string;
start: string;
sort: string; sort: string;
page: number; page: number;
size: number; size: number;
@ -157,6 +158,7 @@ export class TaskQueryRequestRepresentationModel {
this.text = obj.text || null; this.text = obj.text || null;
this.assignment = obj.assignment || null; this.assignment = obj.assignment || null;
this.state = obj.state || null; this.state = obj.state || null;
this.start = obj.start || null;
this.sort = obj.sort || null; this.sort = obj.sort || null;
this.page = obj.page || 0; this.page = obj.page || 0;
this.size = obj.size || 25; this.size = obj.size || 25;

View File

@ -0,0 +1,27 @@
/*!
* @license
* Copyright 2016 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 { TaskDetailsModel } from './task-details.model';
export interface TaskListModel {
size: number;
total: number;
start: number;
length: number;
data: TaskDetailsModel [];
}

View File

@ -16,7 +16,8 @@
*/ */
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule } from 'ng2-alfresco-core';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
import { PeopleService } from './people.service'; import { PeopleService } from './people.service';
@ -48,7 +49,8 @@ describe('PeopleService', () => {
CoreModule.forRoot() CoreModule.forRoot()
], ],
providers: [ providers: [
PeopleService PeopleService,
{ provide: AppConfigService, useClass: AppConfigServiceMock }
] ]
}); });
service = TestBed.get(PeopleService); service = TestBed.get(PeopleService);

View File

@ -16,8 +16,9 @@
*/ */
import { async, TestBed } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core'; import { AppConfigService, CoreModule, TranslationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { AppConfigServiceMock } from '../assets/app-config.service.mock';
import { import {
fakeAppFilter, fakeAppFilter,
fakeAppPromise, fakeAppPromise,
@ -38,6 +39,7 @@ import {
fakeUser2, fakeUser2,
secondFakeTaskList secondFakeTaskList
} from '../assets/tasklist-service.mock'; } from '../assets/tasklist-service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { Comment } from '../models/comment.model'; import { Comment } from '../models/comment.model';
import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model'; import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
@ -56,7 +58,9 @@ describe('Activiti TaskList Service', () => {
CoreModule.forRoot() CoreModule.forRoot()
], ],
providers: [ providers: [
TaskListService TaskListService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: TranslationService, useClass: TranslationMock }
] ]
}).compileComponents(); }).compileComponents();
})); }));
@ -167,11 +171,14 @@ describe('Activiti TaskList Service', () => {
service.getTasks(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe( service.getTasks(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.size).toEqual(1);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.start).toEqual(0);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data).toBeDefined();
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data.length).toEqual(1);
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );
@ -187,12 +194,15 @@ describe('Activiti TaskList Service', () => {
service.getTasks(<TaskQueryRequestRepresentationModel> fakeFilterWithProcessDefinitionKey).subscribe( service.getTasks(<TaskQueryRequestRepresentationModel> fakeFilterWithProcessDefinitionKey).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.size).toEqual(2);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.start).toEqual(0);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data).toBeDefined();
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data.length).toEqual(2);
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res[0].processDefinitionKey).toEqual('1'); expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
expect(res.data[0].processDefinitionKey).toEqual('1');
done(); done();
} }
); );
@ -221,34 +231,41 @@ describe('Activiti TaskList Service', () => {
}); });
it('should return the task list with all tasks filtered by state', (done) => { it('should return the task list with all tasks filtered by state', (done) => {
spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList.data)); spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList));
spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList)); spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList));
service.findAllTaskByState(<TaskQueryRequestRepresentationModel> fakeFilter, 'open').subscribe( service.findAllTaskByState(<TaskQueryRequestRepresentationModel> fakeFilter, 'open').subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.size).toEqual(1);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.start).toEqual(0);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data).toBeDefined();
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data.length).toEqual(1);
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );
}); });
it('should return the task list with all tasks filtered', (done) => { it('should return the task list with all tasks filtered', (done) => {
spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList.data)); spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList));
spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList)); spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList));
service.findAllTaskByState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe( service.findAllTaskByState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.size).toEqual(1);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.start).toEqual(0);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data).toBeDefined();
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data.length).toEqual(1);
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );
@ -258,11 +275,14 @@ describe('Activiti TaskList Service', () => {
service.findTasksByState(<TaskQueryRequestRepresentationModel> fakeFilter, 'open').subscribe( service.findTasksByState(<TaskQueryRequestRepresentationModel> fakeFilter, 'open').subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(1); expect(res.size).toEqual(1);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.start).toEqual(0);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data).toBeDefined();
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data.length).toEqual(1);
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );
@ -277,12 +297,14 @@ describe('Activiti TaskList Service', () => {
it('should return the task list filtered', (done) => { it('should return the task list filtered', (done) => {
service.findTasksByState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe( service.findTasksByState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res.size).toEqual(1);
expect(res.length).toEqual(1); expect(res.start).toEqual(0);
expect(res[0].name).toEqual('FakeNameTask'); expect(res.data).toBeDefined();
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data.length).toEqual(1);
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );
@ -295,22 +317,23 @@ describe('Activiti TaskList Service', () => {
}); });
it('should return the task list with all tasks filtered without state', (done) => { it('should return the task list with all tasks filtered without state', (done) => {
spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList.data)); spyOn(service, 'getTasks').and.returnValue(Observable.of(fakeTaskList));
spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList)); spyOn(service, 'getTotalTasks').and.returnValue(Observable.of(fakeTaskList));
service.findAllTasksWhitoutState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe( service.findAllTasksWhitoutState(<TaskQueryRequestRepresentationModel> fakeFilter).subscribe(
res => { res => {
expect(res).toBeDefined(); expect(res).toBeDefined();
expect(res.length).toEqual(2); expect(res.data).toBeDefined();
expect(res[0].name).toEqual('FakeNameTask'); expect(res.data.length).toEqual(2);
expect(res[0].assignee.email).toEqual('fake-email@dom.com'); expect(res.data[0].name).toEqual('FakeNameTask');
expect(res[0].assignee.firstName).toEqual('firstName'); expect(res.data[0].assignee.email).toEqual('fake-email@dom.com');
expect(res[0].assignee.lastName).toEqual('lastName'); expect(res.data[0].assignee.firstName).toEqual('firstName');
expect(res.data[0].assignee.lastName).toEqual('lastName');
expect(res[1].name).toEqual('FakeNameTask'); expect(res.data[1].name).toEqual('FakeNameTask');
expect(res[1].assignee.email).toEqual('fake-email@dom.com'); expect(res.data[1].assignee.email).toEqual('fake-email@dom.com');
expect(res[1].assignee.firstName).toEqual('firstName'); expect(res.data[1].assignee.firstName).toEqual('firstName');
expect(res[1].assignee.lastName).toEqual('lastName'); expect(res.data[1].assignee.lastName).toEqual('lastName');
done(); done();
} }
); );

View File

@ -17,7 +17,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core'; import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable, Subject } from 'rxjs/Rx';
import { Comment } from '../models/comment.model'; import { Comment } from '../models/comment.model';
import { import {
FilterRepresentationModel, FilterRepresentationModel,
@ -25,10 +25,14 @@ import {
} from '../models/filter.model'; } from '../models/filter.model';
import { Form } from '../models/form.model'; import { Form } from '../models/form.model';
import { TaskDetailsModel } from '../models/task-details.model'; import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListModel } from '../models/task-list.model';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
@Injectable() @Injectable()
export class TaskListService { export class TaskListService {
private tasksListSubject = new Subject<TaskListModel>();
public tasksList$: Observable<TaskListModel> = this.tasksListSubject.asObservable();
constructor(private apiService: AlfrescoApiService, constructor(private apiService: AlfrescoApiService,
private logService: LogService) { private logService: LogService) {
@ -149,15 +153,12 @@ export class TaskListService {
* @param filter - TaskFilterRepresentationModel * @param filter - TaskFilterRepresentationModel
* @returns {any} * @returns {any}
*/ */
getTasks(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskDetailsModel[]> { getTasks(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskListModel> {
return Observable.fromPromise(this.callApiTasksFiltered(requestNode)) return Observable.fromPromise(this.callApiTasksFiltered(requestNode))
.map((res: any) => { .map((res: any) => {
if (requestNode.processDefinitionKey) { this.tasksListSubject.next(res);
return res.data.filter(p => p.processDefinitionKey === requestNode.processDefinitionKey); return res;
} else { }).catch(err => this.handleTasksError(err));
return res.data;
}
}).catch(err => this.handleError(err));
} }
/** /**
@ -165,7 +166,7 @@ export class TaskListService {
* @param filter - TaskFilterRepresentationModel * @param filter - TaskFilterRepresentationModel
* @returns {any} * @returns {any}
*/ */
findTasksByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskDetailsModel[]> { findTasksByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskListModel> {
if (state) { if (state) {
requestNode.state = state; requestNode.state = state;
} }
@ -177,7 +178,7 @@ export class TaskListService {
* @param filter - TaskFilterRepresentationModel * @param filter - TaskFilterRepresentationModel
* @returns {any} * @returns {any}
*/ */
findAllTaskByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskDetailsModel[]> { findAllTaskByState(requestNode: TaskQueryRequestRepresentationModel, state?: string): Observable<TaskListModel> {
if (state) { if (state) {
requestNode.state = state; requestNode.state = state;
} }
@ -193,12 +194,15 @@ export class TaskListService {
* @param filter - TaskFilterRepresentationModel * @param filter - TaskFilterRepresentationModel
* @returns {any} * @returns {any}
*/ */
findAllTasksWhitoutState(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskDetailsModel[]> { findAllTasksWhitoutState(requestNode: TaskQueryRequestRepresentationModel): Observable<TaskListModel> {
return Observable.forkJoin( return Observable.forkJoin(
this.findTasksByState(requestNode, 'open'), this.findTasksByState(requestNode, 'open'),
this.findAllTaskByState(requestNode, 'completed'), this.findAllTaskByState(requestNode, 'completed'),
(activeTasks: any, completedTasks: any) => { (activeTasks: TaskListModel, completedTasks: TaskListModel) => {
return activeTasks.concat(completedTasks); const tasks = Object.assign({}, activeTasks);
tasks.total += completedTasks.total;
tasks.data = tasks.data.concat(completedTasks.data);
return tasks;
} }
); );
} }
@ -519,9 +523,15 @@ export class TaskListService {
private handleError(error: any) { private handleError(error: any) {
this.logService.error(error); this.logService.error(error);
this.tasksListSubject.error(error);
return Observable.throw(error || 'Server error'); return Observable.throw(error || 'Server error');
} }
private handleTasksError(error: any) {
this.tasksListSubject.error(error.response.body);
return this.handleError(error);
}
/** /**
* Return a static Involved filter instance * Return a static Involved filter instance
* @param appId * @param appId