Merge pull request #993 from Alfresco/dev-valbano-893

Fix People add on Task details
This commit is contained in:
Denys Vuika
2016-11-03 19:54:12 +00:00
committed by GitHub
23 changed files with 1194 additions and 94 deletions

View File

@@ -19,6 +19,8 @@ import { NgModule, ModuleWithProviders } from '@angular/core';
import { CoreModule } from 'ng2-alfresco-core';
import { DataTableModule } from 'ng2-alfresco-datatable';
import { ActivitiFormModule } from 'ng2-activiti-form';
import { ActivitiPeopleService } from './src/services/activiti-people.service';
import { ActivitiTaskListService } from './src/services/activiti-tasklist.service';
import {
ActivitiApps,
@@ -30,11 +32,10 @@ import {
ActivitiComments,
ActivitiPeople,
ActivitiTaskHeader,
ActivitiStartProcessButton
ActivitiStartTaskButton,
ActivitiPeopleSearch
} from './src/components/index';
import { ActivitiTaskListService } from './src/services/activiti-tasklist.service';
export * from './src/components/index';
export * from './src/services/activiti-tasklist.service';
export * from './src/models/filter.model';
@@ -49,11 +50,13 @@ export const ACTIVITI_TASKLIST_DIRECTIVES: any[] = [
ActivitiComments,
ActivitiPeople,
ActivitiTaskHeader,
ActivitiStartProcessButton
ActivitiStartTaskButton,
ActivitiPeopleSearch
];
export const ACTIVITI_TASKLIST_PROVIDERS: any[] = [
ActivitiTaskListService
ActivitiTaskListService,
ActivitiPeopleService
];
@NgModule({

View File

@@ -1,33 +1,33 @@
<span class="activiti-label mdl-badge"
<span class="activiti-label mdl-badge" id="checklist-label"
[attr.data-badge]="checklist?.length">{{ 'TASK_DETAILS.LABELS.CHECKLIST' | translate }}</span>
<div id="addChecklist" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addChecklist">
<div *ngIf="!readOnly" id="addChecklist" (click)="showDialog()" id="add-checklist" class="icon material-icons">add</div>
<div *ngIf="!readOnly" class="mdl-tooltip" for="add-checklist">
Add a checklist
</div>
<div class="menu-container" *ngIf="checklist?.length > 0">
<ul class='mdl-list'>
<li class="mdl-list__item" *ngFor="let check of checklist">
<span class="mdl-list__item-primary-content">
<span class="mdl-list__item-primary-content" id="check-{{check.id}}">
<i class="material-icons mdl-list__item-icon">done</i>
{{check.name}}
</span>
</li>
</ul>
</div>
<div *ngIf="checklist?.length === 0">
<div *ngIf="checklist?.length === 0" id="checklist-none-message">
{{ 'TASK_DETAILS.CHECKLIST.NONE' | translate }}
</div>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">New Task</h4>
<dialog class="mdl-dialog" id="checklist-dialog" #dialog>
<h4 class="mdl-dialog__title" id="add-checklist-title">New Check</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" [(ngModel)]="taskName" id="task" />
<label class="mdl-textfield__label" for="task">Name</label>
<input class="mdl-textfield__input" type="text" [(ngModel)]="taskName" id="checklist-name"/>
<label class="mdl-textfield__label" for="checklist-name">Name</label>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="add()" class="mdl-button">Add Checklist</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
<button type="button" id="add-check" (click)="add()" class="mdl-button">Add Checklist</button>
<button type="button" id="close-check-dialog" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>
</dialog>

View File

@@ -0,0 +1,172 @@
/*!
* @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 {
CoreModule,
AlfrescoTranslationService
} from 'ng2-alfresco-core';
import { SimpleChange } from '@angular/core';
import { ActivitiTaskListService } from '../services/activiti-tasklist.service';
import { ActivitiChecklist } from './activiti-checklist.component';
import { TranslationMock } from '../assets/translation.service.mock';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { TaskDetailsModel } from '../models/task-details.model';
declare let jasmine: any;
const fakeTaskDetail = new TaskDetailsModel({
id: 'fake-check-id',
name: 'fake-check-name'
});
describe('Activiti Checklist Component', () => {
let checklistComponent: ActivitiChecklist;
let fixture: ComponentFixture<ActivitiChecklist>;
let element: HTMLElement;
let showChecklistDialog, closeCheckDialogButton;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CoreModule],
declarations: [ActivitiChecklist],
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock},
ActivitiTaskListService]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(ActivitiChecklist);
checklistComponent = fixture.componentInstance;
element = fixture.nativeElement;
fixture.detectChanges();
});
}));
it('should show people component title', () => {
expect(element.querySelector('#checklist-label')).toBeDefined();
expect(element.querySelector('#checklist-label')).not.toBeNull();
});
it('should show no checklist message', () => {
expect(element.querySelector('#checklist-none-message')).not.toBeNull();
expect(element.querySelector('#checklist-none-message').textContent).toContain('TASK_DETAILS.CHECKLIST.NONE');
});
describe('when interact with people dialog', () => {
beforeEach(() => {
checklistComponent.taskId = 'fake-task-id';
checklistComponent.checklist = [];
fixture.detectChanges();
showChecklistDialog = <HTMLElement> element.querySelector('#add-checklist');
closeCheckDialogButton = <HTMLElement> element.querySelector('#close-check-dialog');
});
it('should show dialog when clicked on add', () => {
expect(showChecklistDialog).not.toBeNull();
showChecklistDialog.click();
expect(element.querySelector('#checklist-dialog')).not.toBeNull();
expect(element.querySelector('#add-checklist-title')).not.toBeNull();
expect(element.querySelector('#add-checklist-title').textContent).toContain('New Check');
});
it('should close dialog when clicked on cancel', () => {
showChecklistDialog.click();
expect(element.querySelector('#checklist-dialog').getAttribute('open')).not.toBeNull();
closeCheckDialogButton.click();
expect(element.querySelector('#checklist-dialog').getAttribute('open')).toBeNull();
});
});
describe('when there are task checklist', () => {
beforeEach(() => {
checklistComponent.taskId = 'fake-task-id';
checklistComponent.checklist = [];
fixture.detectChanges();
showChecklistDialog = <HTMLElement> element.querySelector('#add-checklist');
});
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should show task checklist', () => {
checklistComponent.checklist.push(fakeTaskDetail);
fixture.detectChanges();
expect(element.querySelector('#check-fake-check-id')).not.toBeNull();
expect(element.querySelector('#check-fake-check-id').textContent).toContain('fake-check-name');
});
it('should add checklist', async(() => {
showChecklistDialog.click();
let addButtonDialog = <HTMLElement> element.querySelector('#add-check');
addButtonDialog.click();
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {id: 'fake-check-added-id', name: 'fake-check-added-name'}
});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#check-fake-check-added-id')).not.toBeNull();
expect(element.querySelector('#check-fake-check-added-id').textContent).toContain('fake-check-added-name');
});
}));
it('should show load task checklist on change', async(() => {
checklistComponent.taskId = 'new-fake-task-id';
checklistComponent.checklist.push(fakeTaskDetail);
fixture.detectChanges();
let change = new SimpleChange(null, 'new-fake-task-id');
checklistComponent.ngOnChanges({
taskId: change
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {data: [{id: 'fake-check-changed-id', name: 'fake-check-changed-name'}]}
});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#check-fake-check-changed-id')).not.toBeNull();
expect(element.querySelector('#check-fake-check-changed-id').textContent).toContain('fake-check-changed-name');
});
}));
it('should show empty checklist when task id is null', async(() => {
checklistComponent.taskId = 'new-fake-task-id';
checklistComponent.checklist.push(fakeTaskDetail);
fixture.detectChanges();
checklistComponent.taskId = null;
let change = new SimpleChange(null, 'new-fake-task-id');
checklistComponent.ngOnChanges({
taskId: change
});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#checklist-none-message')).not.toBeNull();
expect(element.querySelector('#checklist-none-message').textContent).toContain('TASK_DETAILS.CHECKLIST.NONE');
});
}));
});
});

View File

@@ -16,7 +16,7 @@
*/
import { Component, Input, OnInit, ViewChild, OnChanges, SimpleChanges } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
import { TaskDetailsModel } from '../models/task-details.model';
import { Observer, Observable } from 'rxjs/Rx';
@@ -33,6 +33,9 @@ export class ActivitiChecklist implements OnInit, OnChanges {
@Input()
taskId: string;
@Input()
readOnly: boolean = false;
@ViewChild('dialog')
dialog: any;
@@ -48,8 +51,7 @@ export class ActivitiChecklist implements OnInit, OnChanges {
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
constructor(private translate: AlfrescoTranslationService,
private activitiTaskList: ActivitiTaskListService) {
if (translate) {

View File

@@ -1,7 +1,7 @@
<span class="activiti-label mdl-badge"
[attr.data-badge]="comments?.length">{{ 'TASK_DETAILS.LABELS.COMMENTS' |translate }}</span>
<div id="addComment" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addComment">
<div *ngIf="!readOnly" id="addComment" (click)="showDialog()" class="icon material-icons">add</div>
<div *ngIf="!readOnly" class="mdl-tooltip" for="addComment">
Add a comment
</div>
@@ -32,4 +32,4 @@
<button type="button" (click)="add()" class="mdl-button">Add Comment</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>
</dialog>

View File

@@ -33,6 +33,9 @@ export class ActivitiComments implements OnInit, OnChanges {
@Input()
taskId: string;
@Input()
readOnly: boolean = false;
@ViewChild('dialog')
dialog: any;

View File

@@ -0,0 +1,18 @@
:host {
width: 100%;
}
.activiti-label {
font-weight: bolder;
}
.material-icons.people-search__icon:hover {
color: rgb(255, 152, 0);
}
.fix-element-user-list{
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px;
}

View File

@@ -0,0 +1,17 @@
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="userSearchText" [value]=""
[formControl]="searchUser"/>
<label class="mdl-textfield__label" for="userSearchText">Search user</label>
</div>
<ul class='mdl-list'>
<li class="mdl-list__item fix-element-user-list" *ngFor="let user of userList">
<span class="mdl-list__item-primary-content mdl-button mdl-js-button mdl-js-ripple-effect"
(click)="onRowClick(user)" id="user-{{user.id}}">
<i class="material-icons md-light people-search__icon">face</i>
{{getDisplayUser(user)}}
</span>
</li>
<div *ngIf="userList?.length === 0" id="no-user-found">
No user found to involve
</div>
</ul>

View File

@@ -0,0 +1,137 @@
/*!
* @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 {
CoreModule,
AlfrescoTranslationService
} from 'ng2-alfresco-core';
import { ActivitiPeopleSearch } from './activiti-people-search.component';
import { TranslationMock } from '../assets/translation.service.mock';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { User } from '../models/user.model';
import { Observable } from 'rxjs/Observable';
declare let jasmine: any;
const fakeUser: User = new User({
id: '1',
firstName: 'fake-name',
lastName: 'fake-last',
email: 'fake@mail.com'
});
const fakeSecondUser: User = new User({
id: '2',
firstName: 'fake-involve-name',
lastName: 'fake-involve-last',
email: 'fake-involve@mail.com'
});
describe('Activiti People Search', () => {
let activitiPeopleSearchComponent: ActivitiPeopleSearch;
let fixture: ComponentFixture<ActivitiPeopleSearch>;
let element: HTMLElement;
let componentHandler;
let userArray = [fakeUser, fakeSecondUser];
let searchInput;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CoreModule],
declarations: [ActivitiPeopleSearch],
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock}]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(ActivitiPeopleSearch);
activitiPeopleSearchComponent = fixture.componentInstance;
element = fixture.nativeElement;
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
activitiPeopleSearchComponent.results = Observable.of([]);
fixture.detectChanges();
});
}));
it('should show input search text', () => {
expect(element.querySelector('#userSearchText')).toBeDefined();
expect(element.querySelector('#userSearchText')).not.toBeNull();
});
it('should show no user found to involve message', () => {
fixture.detectChanges();
fixture.whenStable()
.then(() => {
expect(element.querySelector('#no-user-found')).not.toBeNull();
expect(element.querySelector('#no-user-found').textContent).toContain('No user found to involve');
});
});
it('should show user which can be involved ', (done) => {
activitiPeopleSearchComponent.onSearch.subscribe(() => {
activitiPeopleSearchComponent.results = Observable.of(userArray);
activitiPeopleSearchComponent.ngOnInit();
fixture.detectChanges();
fixture.whenStable()
.then(() => {
expect(element.querySelector('#user-1')).not.toBeNull();
expect(element.querySelector('#user-1').textContent)
.toContain('fake-name - fake-last');
expect(element.querySelector('#user-2')).not.toBeNull();
expect(element.querySelector('#user-2').textContent)
.toContain('fake-involve-name - fake-involve-last');
done();
});
});
searchInput = element.querySelector('#userSearchText');
searchInput.value = 'fake-search';
activitiPeopleSearchComponent.searchUser.markAsDirty();
searchInput.dispatchEvent(new Event('input'));
});
it('should send an event when an user is clicked', async(() => {
activitiPeopleSearchComponent.onRowClicked.subscribe((user) => {
expect(user).toBeDefined();
expect(user.firstName).toBe('fake-name');
});
activitiPeopleSearchComponent.results = Observable.of(userArray);
activitiPeopleSearchComponent.ngOnInit();
fixture.detectChanges();
fixture.whenStable()
.then(() => {
let userToSelect = <HTMLElement> element.querySelector('#user-1');
userToSelect.click();
});
}));
it('should remove clicked user', async(() => {
activitiPeopleSearchComponent.results = Observable.of(userArray);
activitiPeopleSearchComponent.ngOnInit();
fixture.detectChanges();
let userToSelect = <HTMLElement> element.querySelector('#user-1');
userToSelect.click();
fixture.detectChanges();
fixture.whenStable()
.then(() => {
expect(element.querySelector('#user-1')).toBeNull();
});
}));
});

View File

@@ -0,0 +1,93 @@
/*!
* @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 { Component, Input, Output, EventEmitter, OnInit, AfterViewInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { User } from '../models/user.model';
import { Observable } from 'rxjs/Observable';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
declare let componentHandler: any;
@Component({
selector: 'activiti-people-search',
moduleId: module.id,
templateUrl: './activiti-people-search.component.html',
styleUrls: ['./activiti-people-search.component.css']
})
export class ActivitiPeopleSearch implements OnInit, AfterViewInit {
@Input()
results: Observable<User[]>;
@Output()
onSearch: EventEmitter<any> = new EventEmitter();
@Output()
onRowClicked: EventEmitter<any> = new EventEmitter();
searchUser: FormControl = new FormControl();
userList: User[] = [];
constructor(private translate: AlfrescoTranslationService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
}
this.searchUser
.valueChanges
.debounceTime(200)
.subscribe((event) => {
this.onSearch.emit(event);
});
}
ngOnInit() {
this.results.subscribe((list) => {
this.userList = list;
});
}
ngAfterViewInit() {
this.setupMaterialComponents(componentHandler);
}
setupMaterialComponents(handler?: any): boolean {
// workaround for MDL issues with dynamic components
let isUpgraded: boolean = false;
if (handler) {
handler.upgradeAllRegistered();
isUpgraded = true;
}
return isUpgraded;
}
onRowClick(userClicked: User) {
this.onRowClicked.emit(userClicked);
this.userList = this.userList.filter((user) => {
return user.id !== userClicked.id;
});
}
getDisplayUser(user: User): string {
let firstName = user.firstName && user.firstName !== 'null' ? user.firstName : 'N/A';
let lastName = user.lastName && user.lastName !== 'null' ? user.lastName : 'N/A';
return firstName + ' - ' + lastName;
}
}

View File

@@ -6,6 +6,10 @@
font-weight: bolder;
}
.material-icons:hover {
.material-icons.people__icon:hover {
color: rgb(255, 152, 0);
}
.add-people-dialog__content {
padding: 20px 24px 2px;
}

View File

@@ -1,33 +1,36 @@
<span class="activiti-label mdl-badge"
<span class="activiti-label mdl-badge" id="people-title"
[attr.data-badge]="people?.length">{{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }}</span>
<div id="addPeople" (click)="showDialog()" class="icon material-icons">add</div>
<div class="mdl-tooltip" for="addPeople">
<div *ngIf="!readOnly" id="addPeople" (click)="showDialog()" class="icon material-icons people__icon">add</div>
<div *ngIf="!readOnly" class="mdl-tooltip" data-mdl-for="addPeople">
Add a person
</div>
<div class="menu-container" *ngIf="people?.length > 0">
<ul class='mdl-list'>
<li class="mdl-list__item" *ngFor="let user of people">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">face</i>
{{user.firstName}}
<i class="material-icons mdl-list__item-icon">face</i>
<span id="user-{{user.id}}">{{getDisplayUser(user)}}</span>
</span>
<a *ngIf="!readOnly" class="mdl-list__item-secondary-action">
<i id="remove" class="material-icons people__icon"
(click)="removeInvolvedUser(user)">delete</i>
</a>
</li>
</ul>
</div>
<div *ngIf="people?.length === 0">
<div *ngIf="people?.length === 0" id="no-people-label">
{{ 'TASK_DETAILS.PEOPLE.NONE' | translate }}
</div>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">New User</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="people" />
<label class="mdl-textfield__label" for="people">Name</label>
</div>
<dialog class="mdl-dialog" id="add-people-dialog" #dialog>
<h4 class="mdl-dialog__title" id="add-people-dialog-title">Involve User</h4>
<div class="mdl-dialog__content add-people-dialog__content">
<activiti-people-search (onSearch)="searchUser($event)"
(onRowClicked)="involveUser($event)"
[results]="peopleSearch$">
</activiti-people-search>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="add()" class="mdl-button">Add User</button>
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
<button type="button" id="close-people-dialog" (click)="cancel()" class="mdl-button close">Cancel</button>
</div>
</dialog>

View File

@@ -0,0 +1,252 @@
/*!
* @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 {
CoreModule,
AlfrescoTranslationService
} from 'ng2-alfresco-core';
import { ActivitiPeopleService } from '../services/activiti-people.service';
import { ActivitiPeople } from './activiti-people.component';
import { ActivitiPeopleSearch } from './activiti-people-search.component';
import { TranslationMock } from '../assets/translation.service.mock';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { User } from '../models/user.model';
declare let jasmine: any;
const fakeUser: User = new User({
id: 'fake-id',
firstName: 'fake-name',
lastName: 'fake-last',
email: 'fake@mail.com'
});
const fakeUserToInvolve: User = new User({
id: 'fake-involve-id',
firstName: 'fake-involve-name',
lastName: 'fake-involve-last',
email: 'fake-involve@mail.com'
});
describe('Activiti People Component', () => {
let activitiPeopleComponent: ActivitiPeople;
let fixture: ComponentFixture<ActivitiPeople>;
let element: HTMLElement;
let componentHandler;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CoreModule],
declarations: [ActivitiPeople, ActivitiPeopleSearch],
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock},
ActivitiPeopleService]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(ActivitiPeople);
activitiPeopleComponent = fixture.componentInstance;
element = fixture.nativeElement;
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
});
}));
it('should show people component title', () => {
expect(element.querySelector('#people-title')).toBeDefined();
expect(element.querySelector('#people-title')).not.toBeNull();
});
it('should show no people involved message', () => {
fixture.detectChanges();
fixture.whenStable()
.then(() => {
expect(element.querySelector('#no-people-label')).not.toBeNull();
expect(element.querySelector('#no-people-label').textContent).toContain('TASK_DETAILS.PEOPLE.NONE');
});
});
describe('when interact with people dialog', () => {
beforeEach(() => {
activitiPeopleComponent.taskId = 'fake-task-id';
activitiPeopleComponent.people = [];
fixture.detectChanges();
});
it('should show dialog when clicked on add', () => {
expect(element.querySelector('#addPeople')).not.toBeNull();
activitiPeopleComponent.showDialog();
expect(element.querySelector('#add-people-dialog')).not.toBeNull();
expect(element.querySelector('#add-people-dialog-title')).not.toBeNull();
expect(element.querySelector('#add-people-dialog-title').textContent).toContain('Involve User');
});
it('should close dialog when clicked on cancel', () => {
activitiPeopleComponent.showDialog();
expect(element.querySelector('#addPeople')).not.toBeNull();
activitiPeopleComponent.cancel();
let dialogWindow = <HTMLElement> element.querySelector('#add-people-dialog');
expect(dialogWindow.getAttribute('open')).toBeNull();
});
});
describe('when there are involved people', () => {
beforeEach(() => {
activitiPeopleComponent.taskId = 'fake-task-id';
activitiPeopleComponent.people.push(fakeUser);
fixture.detectChanges();
});
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should show people involved', () => {
expect(element.querySelector('#user-fake-id')).not.toBeNull();
expect(element.querySelector('#user-fake-id').textContent).toContain('fake-name');
expect(element.querySelector('#user-fake-id').textContent).toContain('fake-last');
});
it('should remove pepole involved', async(() => {
activitiPeopleComponent.removeInvolvedUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
fixture.whenStable()
.then(() => {
fixture.detectChanges();
expect(element.querySelector('#user-fake-id')).toBeNull();
});
}));
it('should involve pepole', async(() => {
activitiPeopleComponent.involveUser(fakeUserToInvolve);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
fixture.whenStable()
.then(() => {
fixture.detectChanges();
expect(element.querySelector('#user-fake-involve-id')).not.toBeNull();
expect(element.querySelector('#user-fake-involve-id').textContent)
.toBe('fake-involve-name fake-involve-last');
});
}));
it('should return an observable with user search results', (done) => {
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
expect(users.length).toBe(2);
expect(users[0].firstName).toBe('fake-test-1');
expect(users[0].lastName).toBe('fake-last-1');
expect(users[0].email).toBe('fake-test-1@test.com');
expect(users[0].id).toBe(1);
done();
});
activitiPeopleComponent.searchUser('fake-search-word');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {
data: [{
id: 1,
firstName: 'fake-test-1',
lastName: 'fake-last-1',
email: 'fake-test-1@test.com'
}, {
id: 2,
firstName: 'fake-test-2',
lastName: 'fake-last-2',
email: 'fake-test-2@test.com'
}]
}
});
});
it('should return an empty list for not valid search', (done) => {
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
expect(users.length).toBe(0);
done();
});
activitiPeopleComponent.searchUser('fake-search-word');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {}
});
});
});
describe('when there are errors on service call', () => {
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should log error message when search fails', async(() => {
console.log = jasmine.createSpy('log');
activitiPeopleComponent.peopleSearch$.subscribe(() => {
expect(console.log).toHaveBeenCalledWith('Could not load users');
});
activitiPeopleComponent.searchUser('fake-search');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
}));
it('should not remove user if remove involved user fail', async(() => {
activitiPeopleComponent.people.push(fakeUser);
fixture.detectChanges();
activitiPeopleComponent.removeInvolvedUser(fakeUser);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
fixture.whenStable()
.then(() => {
fixture.detectChanges();
expect(element.querySelector('#user-fake-id')).not.toBeNull();
expect(element.querySelector('#user-fake-id').textContent)
.toBe('fake-name fake-last');
});
}));
it('should not involve user if involve user fail', async(() => {
activitiPeopleComponent.involveUser(fakeUserToInvolve);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
fixture.whenStable()
.then(() => {
fixture.detectChanges();
expect(element.querySelector('#user-fake-id')).toBeNull();
expect(element.querySelector('#no-people-label').textContent).toContain('TASK_DETAILS.PEOPLE.NONE');
});
}));
});
});

View File

@@ -15,10 +15,11 @@
* limitations under the License.
*/
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Component, Input, ViewChild } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { User } from '../models/user.model';
import { Observer, Observable } from 'rxjs/Rx';
import { ActivitiPeopleService } from '../services/activiti-people.service';
@Component({
selector: 'activiti-people',
@@ -26,56 +27,79 @@ import { Observer, Observable } from 'rxjs/Rx';
templateUrl: './activiti-people.component.html',
styleUrls: ['./activiti-people.component.css']
})
export class ActivitiPeople implements OnInit {
export class ActivitiPeople {
@Input()
people: User [] = [];
@Input()
taskId: string = '';
@Input()
readOnly: boolean = false;
@ViewChild('dialog')
dialog: any;
private peopleObserver: Observer<User>;
people$: Observable<User>;
private peopleSearchObserver: Observer<User[]>;
peopleSearch$: Observable<User[]>;
/**
* Constructor
* @param auth
* @param translate
* @param people service
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService) {
constructor(private translate: AlfrescoTranslationService,
private peopleService: ActivitiPeopleService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
}
this.people$ = new Observable<User>(observer => this.peopleObserver = observer).share();
}
ngOnInit() {
this.people$.subscribe((user: User) => {
this.people.push(user);
});
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
}
public showDialog() {
if (!this.dialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.dialog.nativeElement);
}
if (this.dialog) {
if (!this.dialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.dialog.nativeElement);
}
this.dialog.nativeElement.showModal();
}
}
public add() {
alert('add people');
this.cancel();
}
public cancel() {
if (this.dialog) {
this.dialog.nativeElement.close();
this.peopleSearchObserver.next([]);
}
}
searchUser(searchedWord: string) {
this.peopleService.getWorkflowUsers(this.taskId, searchedWord)
.subscribe((users) => {
this.peopleSearchObserver.next(users);
}, error => console.log('Could not load users'));
}
involveUser(user: User) {
this.peopleService.involveUserWithTask(this.taskId, user.id.toString())
.subscribe(() => {
this.people.push(user);
}, error => console.error('Impossible to involve user with task'));
}
removeInvolvedUser(user: User) {
this.peopleService.removeInvolvedUser(this.taskId, user.id.toString())
.subscribe(() => {
this.people = this.people.filter((involvedUser) => {
return involvedUser.id !== user.id;
});
}, error => console.error('Impossible to remove involved user from task'));
}
getDisplayUser(user: User): string {
let firstName = user.firstName && user.firstName !== 'null' ? user.firstName : 'N/A';
let lastName = user.lastName && user.lastName !== 'null' ? user.lastName : 'N/A';
return firstName + ' ' + lastName;
}
}

View File

@@ -1,19 +1,27 @@
<button type="button" (click)="showDialog()" class="mdl-button">{{'START_TASK.BUTTON'|translate}}</button>
<button type="button" (click)="showDialog()" class="mdl-button" id="start-task-button">
{{'START_TASK.BUTTON'|translate}}
</button>
<dialog class="mdl-dialog" #dialog>
<h4 class="mdl-dialog__title">{{'START_TASK.DIALOG.TITLE'|translate}}</h4>
<dialog class="mdl-dialog" id="start-task-dialog" #dialog>
<h4 class="mdl-dialog__title" id="start-task-dialog-title">{{'START_TASK.DIALOG.TITLE'|translate}}</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" [(ngModel)]="name" id="taskName" />
<input class="mdl-textfield__input" type="text" [(ngModel)]="name" id="taskName"/>
<label class="mdl-textfield__label" for="taskName">{{'START_TASK.DIALOG.LABEL.NAME'|translate}}</label>
</div>
<div class="mdl-textfield mdl-js-textfield">
<textarea class="mdl-textfield__input" type="text" [(ngModel)]="description" rows="3" id="taskDescription"></textarea>
<label class="mdl-textfield__label" for="taskDescription">{{'START_TASK.DIALOG.LABEL.DESCRIPTION'|translate}}</label>
<textarea class="mdl-textfield__input" type="text" [(ngModel)]="description" rows="3"
id="taskDescription"></textarea>
<label class="mdl-textfield__label" id="task-description-label"
for="taskDescription">{{'START_TASK.DIALOG.LABEL.DESCRIPTION'|translate}}</label>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" (click)="start()" class="mdl-button">{{'START_TASK.DIALOG.ACTION.START'|translate}}</button>
<button type="button" (click)="cancel()" class="mdl-button close">{{'START_TASK.DIALOG.ACTION.CANCEL'|translate}}</button>
<button type="button" id="button-start" (click)="start()" class="mdl-button">
{{'START_TASK.DIALOG.ACTION.START'|translate}}
</button>
<button type="button" id="button-cancel" (click)="cancel()" class="mdl-button close">
{{'START_TASK.DIALOG.ACTION.CANCEL'|translate}}
</button>
</div>
</dialog>

View File

@@ -0,0 +1,124 @@
/*!
* @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 {
CoreModule,
AlfrescoTranslationService
} from 'ng2-alfresco-core';
import { ActivitiTaskListService } from '../services/activiti-tasklist.service';
import { ActivitiStartTaskButton } from './activiti-start-task.component';
import { TranslationMock } from '../assets/translation.service.mock';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
declare let jasmine: any;
describe('Activiti Start Task Component', () => {
let activitiStartTaskButton: ActivitiStartTaskButton;
let fixture: ComponentFixture<ActivitiStartTaskButton>;
let element: HTMLElement;
let startTaskButton: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CoreModule],
declarations: [ActivitiStartTaskButton],
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock},
ActivitiTaskListService]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(ActivitiStartTaskButton);
activitiStartTaskButton = fixture.componentInstance;
element = fixture.nativeElement;
fixture.detectChanges();
startTaskButton = <HTMLElement> element.querySelector('#start-task-button');
});
}));
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should show start task button', () => {
expect(element.querySelector('#start-task-button')).toBeDefined();
expect(element.querySelector('#start-task-button')).not.toBeNull();
expect(element.querySelector('#start-task-button').textContent).toContain('START_TASK.BUTTON');
});
it('should show start dialog on press button', () => {
startTaskButton.click();
expect(element.querySelector('#start-task-dialog')).not.toBeNull();
expect(element.querySelector('#start-task-dialog').getAttribute('open')).not.toBeNull();
expect(element.querySelector('#start-task-dialog-title')).not.toBeNull();
expect(element.querySelector('#start-task-dialog-title').textContent).toContain('START_TASK.DIALOG.TITLE');
});
it('should close start dialog on cancel button', () => {
startTaskButton.click();
expect(element.querySelector('#start-task-dialog')).not.toBeNull();
expect(element.querySelector('#start-task-dialog').getAttribute('open')).not.toBeNull();
let cancelButton = <HTMLElement> element.querySelector('#button-cancel');
cancelButton.click();
expect(element.querySelector('#start-task-dialog').getAttribute('open')).toBeNull();
});
it('should create new task when start is clicked', () => {
activitiStartTaskButton.onSuccess.subscribe(() => {
expect(element.querySelector('#start-task-dialog').getAttribute('open')).toBeNull();
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
startTaskButton.click();
activitiStartTaskButton.name = 'fake-name';
createTaskButton.click();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200
});
});
it('alert message is showed on start error', () => {
spyOn(window, 'alert');
activitiStartTaskButton.onSuccess.subscribe(() => {
expect(window.alert).toHaveBeenCalledWith('An error occurred while trying to add the task');
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
startTaskButton.click();
activitiStartTaskButton.name = 'fake-name';
createTaskButton.click();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 403
});
});
it('should send on success event when the task is started', () => {
activitiStartTaskButton.onSuccess.subscribe((res) => {
expect(res).toBeDefined();
});
let createTaskButton = <HTMLElement> element.querySelector('#button-start');
startTaskButton.click();
activitiStartTaskButton.name = 'fake-name';
createTaskButton.click();
jasmine.Ajax.requests.mostRecent().respondWith({
'status': 200,
contentType: 'json',
responseText: {}
});
});
});

View File

@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { TaskDetailsModel } from '../models/task-details.model';
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
@@ -29,7 +29,7 @@ declare let dialogPolyfill: any;
templateUrl: './activiti-start-task.component.html',
styleUrls: ['./activiti-start-task.component.css']
})
export class ActivitiStartProcessButton implements OnInit {
export class ActivitiStartTaskButton {
@Input()
appId: string;
@@ -49,8 +49,7 @@ export class ActivitiStartProcessButton implements OnInit {
* @param translate
* @param taskService
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService,
constructor(private translate: AlfrescoTranslationService,
private taskService: ActivitiTaskListService) {
if (translate) {
@@ -58,9 +57,6 @@ export class ActivitiStartProcessButton implements OnInit {
}
}
ngOnInit() {
}
public start() {
if (this.name) {
this.taskService.createNewTask(new TaskDetailsModel({

View File

@@ -12,13 +12,16 @@
<activiti-task-header [taskDetails]="taskDetails" #activitiheader></activiti-task-header>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<activiti-people [people]="taskPeople"></activiti-people>
<activiti-people [people]="taskPeople" [readOnly]="readOnlyForm"
[taskId]="taskDetails.id"></activiti-people>
</div>
<div class="mdl-cell mdl-cell--4-col">
<activiti-comments [taskId]="taskDetails.id" #activiticomments></activiti-comments>
<activiti-comments [readOnly]="readOnlyForm" [taskId]="taskDetails.id"
#activiticomments></activiti-comments>
</div>
<div class="mdl-cell mdl-cell--4-col">
<activiti-checklist [taskId]="taskDetails.id" #activitichecklist></activiti-checklist>
<activiti-checklist [readOnly]="readOnlyForm" [taskId]="taskDetails.id"
#activitichecklist></activiti-checklist>
</div>
</div>
<activiti-form *ngIf="hasFormKey()" [taskId]="taskDetails.id"

View File

@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { Component, Input, OnInit } from '@angular/core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Component, Input } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { TaskDetailsModel } from '../models/task-details.model';
declare let componentHandler: any;
@@ -27,7 +27,7 @@ declare let componentHandler: any;
templateUrl: './activiti-task-header.component.html',
styleUrls: ['./activiti-task-header.component.css']
})
export class ActivitiTaskHeader implements OnInit {
export class ActivitiTaskHeader {
@Input()
taskDetails: TaskDetailsModel;
@@ -37,16 +37,11 @@ export class ActivitiTaskHeader implements OnInit {
* @param auth
* @param translate
*/
constructor(private auth: AlfrescoAuthenticationService,
private translate: AlfrescoTranslationService) {
constructor(private translate: AlfrescoTranslationService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
}
}
ngOnInit() {
}
}

View File

@@ -25,3 +25,4 @@ export * from './no-task-detail-template.component';
export * from './activiti-filters.component';
export * from './activiti-task-details.component';
export * from './activiti-start-task.component';
export * from './activiti-people-search.component';

View File

@@ -8,7 +8,10 @@
"LABELS": {
"ASSIGNEE": "Assegnatario",
"DUE": "Scadenza",
"FORM": "Form"
"FORM": "Form",
"PEOPLE": "Persone",
"COMMENTS": "Commenti",
"CHECKLIST": "Checklist"
},
"MESSAGES": {
"NONE": "Nessun dettaglio task trovato."
@@ -25,4 +28,4 @@
"NONE": "Nessun filtro task selezionato."
}
}
}
}

View File

@@ -0,0 +1,169 @@
/*!
* @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 { ReflectiveInjector } from '@angular/core';
import {
AlfrescoAuthenticationService,
AlfrescoSettingsService,
AlfrescoApiService
} from 'ng2-alfresco-core';
import { User } from '../models/user.model';
import { ActivitiPeopleService } from './activiti-people.service';
declare let jasmine: any;
const firstInvolvedUser: User = new User({
id: '1',
email: 'fake-user1@fake.com',
firstName: 'fakeName1',
lastName: 'fakeLast1'
});
const secondInvolvedUser: User = new User({
id: '2',
email: 'fake-user2@fake.com',
firstName: 'fakeName2',
lastName: 'fakeLast2'
});
const fakeInvolveUserList: User[] = [firstInvolvedUser, secondInvolvedUser];
describe('Activiti People Search Service', () => {
let service, injector, apiService;
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate([
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
ActivitiPeopleService
]);
});
beforeEach(() => {
service = injector.get(ActivitiPeopleService);
apiService = injector.get(AlfrescoApiService);
});
it('can instantiate service with authorization', () => {
expect(apiService).not.toBeNull('authorization should be provided');
let serviceApi = new ActivitiPeopleService(null, apiService);
expect(serviceApi instanceof ActivitiPeopleService).toBe(true, 'new service should be ok');
});
describe('when user is logged in', () => {
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should be able to retrieve people to involve in the task', (done) => {
service.getWorkflowUsers('fake-task-id', 'fake-filter').subscribe(
(users: User[]) => {
expect(users).toBeDefined();
expect(users.length).toBe(2);
expect(users[0].id).toEqual('1');
expect(users[0].email).toEqual('fake-user1@fake.com');
expect(users[0].firstName).toEqual('fakeName1');
expect(users[0].lastName).toEqual('fakeLast1');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {data: fakeInvolveUserList}
});
});
it('should return empty list when there are no users to involve', (done) => {
service.getWorkflowUsers('fake-task-id', 'fake-filter').subscribe(
(users: User[]) => {
expect(users).toBeDefined();
expect(users.length).toBe(0);
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {}
});
});
it('getWorkflowUsers catch errors call', (done) => {
service.getWorkflowUsers('fake-task-id', 'fake-filter').subscribe(() => {
}, () => {
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
});
it('should be able to involve people in the task', (done) => {
service.involveUserWithTask('fake-task-id', 'fake-user-id').subscribe(
() => {
expect(jasmine.Ajax.requests.mostRecent().method).toBe('PUT');
expect(jasmine.Ajax.requests.mostRecent().url).toContain('tasks/fake-task-id/action/involve');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
});
it('involveUserWithTask catch errors call', (done) => {
service.involveUserWithTask('fake-task-id', 'fake-user-id').subscribe(() => {
}, () => {
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
});
it('should be able to remove involved people from task', (done) => {
service.removeInvolvedUser('fake-task-id', 'fake-user-id').subscribe(
() => {
expect(jasmine.Ajax.requests.mostRecent().method).toBe('PUT');
expect(jasmine.Ajax.requests.mostRecent().url).toContain('tasks/fake-task-id/action/remove-involved');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200
});
});
it('removeInvolvedUser catch errors call', (done) => {
service.removeInvolvedUser('fake-task-id', 'fake-user-id').subscribe(() => {
}, () => {
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 403
});
});
});
});

View File

@@ -0,0 +1,73 @@
/*!
* @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';
import { AlfrescoApiService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { Response } from '@angular/http';
import { User } from '../models/user.model';
@Injectable()
export class ActivitiPeopleService {
constructor(private authService: AlfrescoAuthenticationService,
private alfrescoJsApi: AlfrescoApiService) {
}
getWorkflowUsers(taskId: string, searchWord: string): Observable<User[]> {
let option = {excludeTaskId: taskId, filter: searchWord};
return Observable.fromPromise(this.getWorkflowUserApi(option))
.map((response: any) => <User[]> response.data || [])
.catch(this.handleError);
}
involveUserWithTask(taskId: string, idToInvolve: string): Observable<User[]> {
let node = {userId: idToInvolve};
return Observable.fromPromise(this.involveUserToTaskApi(taskId, node))
.catch(this.handleError);
}
removeInvolvedUser(taskId: string, idToRemove: string): Observable<User[]> {
let node = {userId: idToRemove};
return Observable.fromPromise(this.removeInvolvedUserFromTaskApi(taskId, node))
.catch(this.handleError);
}
private getWorkflowUserApi(options: any) {
return this.alfrescoJsApi.getInstance().activiti.usersWorkflowApi.getUsers(options);
}
private involveUserToTaskApi(taskId: string, node: any) {
return this.alfrescoJsApi.getInstance().activiti.taskActionsApi.involveUser(taskId, node);
}
private removeInvolvedUserFromTaskApi(taskId: string, node: any) {
return this.alfrescoJsApi.getInstance().activiti.taskActionsApi.removeInvolvedUser(taskId, node);
}
/**
* Throw the error
* @param error
* @returns {ErrorObservable}
*/
private handleError(error: Response) {
// in a real world app, we may send the error to some remote logging infrastructure
// instead of just logging it to the console
console.error(error);
return Observable.throw(error || 'Server error');
}
}