mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[ADF-794] Add people assignment component (#1977)
* Add people component * exported people service * added people-list component to show the involved user list * changed people-search component layout * changed people-list usage in people component * changed people-list data table from custom template to data adapter * changes people-search component related to people-list * changes in activiti-people related to people-list and people-search component * changed data adapter to direct data column setting to data-table * removed ngChanges and added User and UserEvent models * added User and UserEvent model in emitter and other emitter handler * added user event model * changed activiti-people component with latest UX changes * addedand changed translate keys to the components * added hasUser method to check the condition in html * fixed tslint issue and test case issue in activiti-people component * added test case for actviti-people-list component * test case added for activiti-people-search component * changed activiti-people test cases according to latest UX changes * added description for activiti-people component * changed test case to fix component.upgradeElement issue * changes requested by Vito Albano #1 * splitted getDisplayUser into getDisplayUser and getInitialUsername
This commit is contained in:
@@ -425,6 +425,31 @@ The purpose of the component is populate the local variable called `properties`
|
|||||||
"description": "string"
|
"description": "string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
## Task People Component
|
||||||
|
|
||||||
|
This component displays involved users to a specified task
|
||||||
|
|
||||||
|
```html
|
||||||
|
<activiti-people
|
||||||
|
[people]="YOUR_INVOLVED_PEOPLE_LIST"
|
||||||
|
[taskId]="YOUR_TASK_ID"
|
||||||
|
[readOnly]="YOUR_READ_ONLY_FLAG">
|
||||||
|
</activiti-people>
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| people | User[] | The array of User object to display |
|
||||||
|
| taskId | string | The numeric ID of the task |
|
||||||
|
| readOnly | boolean | The boolean flag |
|
||||||
|
|
||||||
|
#### Events
|
||||||
|
|
||||||
|
No Events
|
||||||
|
|
||||||
## Build from sources
|
## Build from sources
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -36,11 +36,13 @@ import {
|
|||||||
ActivitiStartTaskButton,
|
ActivitiStartTaskButton,
|
||||||
ActivitiPeopleSearch,
|
ActivitiPeopleSearch,
|
||||||
TaskAttachmentListComponent,
|
TaskAttachmentListComponent,
|
||||||
ActivitiCreateTaskAttachmentComponent
|
ActivitiCreateTaskAttachmentComponent,
|
||||||
|
ActivitiPeopleList
|
||||||
} from './src/components/index';
|
} from './src/components/index';
|
||||||
|
|
||||||
export * from './src/components/index';
|
export * from './src/components/index';
|
||||||
export * from './src/services/activiti-tasklist.service';
|
export * from './src/services/activiti-tasklist.service';
|
||||||
|
export * from './src/services/activiti-people.service';
|
||||||
export * from './src/models/index';
|
export * from './src/models/index';
|
||||||
|
|
||||||
export const ACTIVITI_TASKLIST_DIRECTIVES: any[] = [
|
export const ACTIVITI_TASKLIST_DIRECTIVES: any[] = [
|
||||||
@@ -56,7 +58,8 @@ export const ACTIVITI_TASKLIST_DIRECTIVES: any[] = [
|
|||||||
ActivitiStartTaskButton,
|
ActivitiStartTaskButton,
|
||||||
ActivitiPeopleSearch,
|
ActivitiPeopleSearch,
|
||||||
TaskAttachmentListComponent,
|
TaskAttachmentListComponent,
|
||||||
ActivitiCreateTaskAttachmentComponent
|
ActivitiCreateTaskAttachmentComponent,
|
||||||
|
ActivitiPeopleList
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ACTIVITI_TASKLIST_PROVIDERS: any[] = [
|
export const ACTIVITI_TASKLIST_PROVIDERS: any[] = [
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<alfresco-datatable
|
||||||
|
[rows]="users"
|
||||||
|
[actions]="hasActions()"
|
||||||
|
(rowClick)="selectUser($event)"
|
||||||
|
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||||
|
(executeRowAction)="onExecuteRowAction($event)">
|
||||||
|
</alfresco-datatable>
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||||
|
import { ActivitiPeopleList } from './activiti-people-list.component';
|
||||||
|
import { User, UserEventModel } from '../models/index';
|
||||||
|
import { DataTableModule, ObjectDataRow, DataRowEvent, DataRowActionEvent } from 'ng2-alfresco-datatable';
|
||||||
|
|
||||||
|
declare let jasmine: any;
|
||||||
|
|
||||||
|
const fakeUser: User = new User({
|
||||||
|
id: '1',
|
||||||
|
firstName: 'fake-name',
|
||||||
|
lastName: 'fake-last',
|
||||||
|
email: 'fake@mail.com'
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ActivitiPeopleList', () => {
|
||||||
|
|
||||||
|
let activitiPeopleListComponent: ActivitiPeopleList;
|
||||||
|
let fixture: ComponentFixture<ActivitiPeopleList>;
|
||||||
|
let element: HTMLElement;
|
||||||
|
let componentHandler;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
CoreModule.forRoot(),
|
||||||
|
DataTableModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
ActivitiPeopleList
|
||||||
|
]
|
||||||
|
}).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(ActivitiPeopleList);
|
||||||
|
activitiPeopleListComponent = fixture.componentInstance;
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||||
|
'upgradeAllRegistered'
|
||||||
|
]);
|
||||||
|
|
||||||
|
window['componentHandler'] = componentHandler;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should emit row click event', (done) => {
|
||||||
|
let row = new ObjectDataRow(fakeUser);
|
||||||
|
let rowEvent = new DataRowEvent(row, null);
|
||||||
|
|
||||||
|
activitiPeopleListComponent.clickRow.subscribe(selectedUser => {
|
||||||
|
expect(selectedUser.id).toEqual('1');
|
||||||
|
expect(selectedUser.email).toEqual('fake@mail.com');
|
||||||
|
expect(activitiPeopleListComponent.user.id).toEqual('1');
|
||||||
|
expect(activitiPeopleListComponent.user.email).toEqual('fake@mail.com');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
activitiPeopleListComponent.selectUser(rowEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit row action event', (done) => {
|
||||||
|
let row = new ObjectDataRow(fakeUser);
|
||||||
|
let removeObj = {
|
||||||
|
name: 'remove',
|
||||||
|
title: 'Remove'
|
||||||
|
};
|
||||||
|
let rowActionEvent = new DataRowActionEvent(row, removeObj);
|
||||||
|
|
||||||
|
activitiPeopleListComponent.clickAction.subscribe((selectedAction: UserEventModel) => {
|
||||||
|
expect(selectedAction.type).toEqual('remove');
|
||||||
|
expect(selectedAction.value.id).toEqual('1');
|
||||||
|
expect(selectedAction.value.email).toEqual('fake@mail.com');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
activitiPeopleListComponent.onExecuteRowAction(rowActionEvent);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*!
|
||||||
|
* @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, ViewChild, ContentChild } from '@angular/core';
|
||||||
|
import { User, UserEventModel } from '../models/index';
|
||||||
|
import { DataColumnListComponent } from 'ng2-alfresco-core';
|
||||||
|
import { DataTableComponent } from 'ng2-alfresco-datatable';
|
||||||
|
|
||||||
|
declare let componentHandler: any;
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'activiti-people-list',
|
||||||
|
templateUrl: './activiti-people-list.component.html',
|
||||||
|
styleUrls: ['./activiti-people-list.component.css']
|
||||||
|
})
|
||||||
|
|
||||||
|
export class ActivitiPeopleList {
|
||||||
|
|
||||||
|
@ContentChild(DataColumnListComponent) columnList: DataColumnListComponent;
|
||||||
|
|
||||||
|
@ViewChild(DataTableComponent)
|
||||||
|
peopleDataTable: DataTableComponent;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
users: User[];
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
actions: boolean = false;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
clickRow: EventEmitter<User> = new EventEmitter<User>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
clickAction: EventEmitter<UserEventModel> = new EventEmitter<UserEventModel>();
|
||||||
|
|
||||||
|
user: User;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit() {
|
||||||
|
this.peopleDataTable.columnList = this.columnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectUser(event: any) {
|
||||||
|
this.user = event.value.obj;
|
||||||
|
this.clickRow.emit(this.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasActions(): boolean {
|
||||||
|
return this.actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowRowActionsMenu(event: any) {
|
||||||
|
|
||||||
|
let removeAction = {
|
||||||
|
title: 'Remove',
|
||||||
|
name: 'remove'
|
||||||
|
};
|
||||||
|
|
||||||
|
event.value.actions = [
|
||||||
|
removeAction
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
onExecuteRowAction(event: any) {
|
||||||
|
let args = event.value;
|
||||||
|
let action = args.action;
|
||||||
|
this.clickAction.emit(new UserEventModel({type: action.name, value: args.row.obj}));
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
-1
@@ -33,4 +33,60 @@
|
|||||||
|
|
||||||
.mdl-chip-search-people__text{
|
.mdl-chip-search-people__text{
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-text-header{
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.54;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-container{
|
||||||
|
max-height: 152px;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-action-container {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
text-align: right;
|
||||||
|
padding: 5px 0px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-action-container>button{
|
||||||
|
opacity: 0.54;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-action-container>button:hover{
|
||||||
|
color: rgb(255, 152, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-full-name {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-pic {
|
||||||
|
background: #ffc800;
|
||||||
|
padding: 10px 6px;
|
||||||
|
border-radius: 100px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Muli;
|
||||||
|
text-transform: uppercase;
|
||||||
|
min-width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
||||||
|
padding: 4px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
+32
-14
@@ -1,15 +1,33 @@
|
|||||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
<div class="search-text-header">{{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}</div>
|
||||||
<input class="mdl-textfield__input" type="text" id="userSearchText" [value]="" [formControl]="searchUser"/>
|
<div class="search-text-container">
|
||||||
<label class="mdl-textfield__label" for="userSearchText">Search user</label>
|
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||||
</div>
|
<input class="mdl-textfield__input" type="text" id="userSearchText" [value]="" [formControl]="searchUser"/>
|
||||||
<ul class='mdl-list'>
|
<label class="mdl-textfield__label" for="userSearchText">Search user</label>
|
||||||
<li class="mdl-list__item fix-element-user-list" *ngFor="let user of userList">
|
|
||||||
<button (click)="onRowClick(user)" id="user-{{user.id}}" class="mdl-chip mdl-chip--contact mdl-chip-search-people">
|
|
||||||
<img class="mdl-chip__contact" [src]="iconImageUrl" />
|
|
||||||
<span class="mdl-chip__text mdl-chip-search-people__text">{{getDisplayUser(user)}}</span>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<div *ngIf="userList?.length === 0" id="no-user-found">
|
|
||||||
{{'PEOPLE.SEARCH.NO_USERS' | translate }}
|
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</div>
|
||||||
|
<div class="search-list-container" id="search-people-list" *ngIf="hasUsers()">
|
||||||
|
<activiti-people-list
|
||||||
|
[users]="users"
|
||||||
|
(clickRow)="onRowClick($event)">
|
||||||
|
<data-columns>
|
||||||
|
<data-column key="firstName">
|
||||||
|
<ng-template let-entry="$implicit">
|
||||||
|
<div class="people-pic">{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||||
|
</ng-template>
|
||||||
|
</data-column>
|
||||||
|
<data-column key="email" class="full-width">
|
||||||
|
<ng-template let-entry="$implicit">
|
||||||
|
<div class="people-full-name">{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}</div>
|
||||||
|
</ng-template>
|
||||||
|
</data-column>
|
||||||
|
</data-columns>
|
||||||
|
</activiti-people-list>
|
||||||
|
</div>
|
||||||
|
<div class="search-list-action-container">
|
||||||
|
<button type="button" id="close-people-search" (click)="closeSearchList()" class="mdl-button close">
|
||||||
|
{{'PEOPLE.DIALOG_CLOSE' | translate }}
|
||||||
|
</button>
|
||||||
|
<button type="button" id="add-people" (click)="addInvolvedUser()" class="mdl-button close">
|
||||||
|
{{'PEOPLE.ADD_USER' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
+23
-18
@@ -19,6 +19,8 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
|
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||||
import { ActivitiPeopleSearch } from './activiti-people-search.component';
|
import { ActivitiPeopleSearch } from './activiti-people-search.component';
|
||||||
|
import { ActivitiPeopleList } from './activiti-people-list.component';
|
||||||
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
import { User } from '../models/user.model';
|
import { User } from '../models/user.model';
|
||||||
|
|
||||||
declare let jasmine: any;
|
declare let jasmine: any;
|
||||||
@@ -49,10 +51,12 @@ describe('ActivitiPeopleSearch', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule.forRoot()
|
CoreModule.forRoot(),
|
||||||
|
DataTableModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ActivitiPeopleSearch
|
ActivitiPeopleSearch,
|
||||||
|
ActivitiPeopleList
|
||||||
]
|
]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
|
|
||||||
@@ -78,28 +82,25 @@ describe('ActivitiPeopleSearch', () => {
|
|||||||
expect(element.querySelector('#userSearchText')).not.toBeNull();
|
expect(element.querySelector('#userSearchText')).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show no user found to involve message', () => {
|
it('should hide people-list container', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(element.querySelector('#no-user-found')).not.toBeNull();
|
expect(element.querySelector('#search-people-list')).toBeNull();
|
||||||
expect(element.querySelector('#no-user-found').textContent).toContain('PEOPLE.SEARCH.NO_USERS');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show user which can be involved ', (done) => {
|
it('should show user which can be involved ', (done) => {
|
||||||
activitiPeopleSearchComponent.onSearch.subscribe(() => {
|
activitiPeopleSearchComponent.searchPeople.subscribe(() => {
|
||||||
activitiPeopleSearchComponent.results = Observable.of(userArray);
|
activitiPeopleSearchComponent.results = Observable.of(userArray);
|
||||||
activitiPeopleSearchComponent.ngOnInit();
|
activitiPeopleSearchComponent.ngOnInit();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(element.querySelector('#user-1')).not.toBeNull();
|
let gatewayElement: any = element.querySelector('#search-people-list tbody');
|
||||||
expect(element.querySelector('#user-1').textContent)
|
expect(gatewayElement).not.toBeNull();
|
||||||
.toContain('fake-name - fake-last');
|
expect(gatewayElement.children.length).toBe(2);
|
||||||
expect(element.querySelector('#user-2')).not.toBeNull();
|
|
||||||
expect(element.querySelector('#user-2').textContent)
|
|
||||||
.toContain('fake-involve-name - fake-involve-last');
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -110,7 +111,7 @@ describe('ActivitiPeopleSearch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should send an event when an user is clicked', (done) => {
|
it('should send an event when an user is clicked', (done) => {
|
||||||
activitiPeopleSearchComponent.onRowClicked.subscribe((user) => {
|
activitiPeopleSearchComponent.success.subscribe((user) => {
|
||||||
expect(user).toBeDefined();
|
expect(user).toBeDefined();
|
||||||
expect(user.firstName).toBe('fake-name');
|
expect(user.firstName).toBe('fake-name');
|
||||||
done();
|
done();
|
||||||
@@ -120,8 +121,9 @@ describe('ActivitiPeopleSearch', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let userToSelect = <HTMLElement> element.querySelector('#user-1');
|
activitiPeopleSearchComponent.onRowClick(fakeUser);
|
||||||
userToSelect.click();
|
let addUserButton = <HTMLElement> element.querySelector('#add-people');
|
||||||
|
addUserButton.click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,13 +131,16 @@ describe('ActivitiPeopleSearch', () => {
|
|||||||
activitiPeopleSearchComponent.results = Observable.of(userArray);
|
activitiPeopleSearchComponent.results = Observable.of(userArray);
|
||||||
activitiPeopleSearchComponent.ngOnInit();
|
activitiPeopleSearchComponent.ngOnInit();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let userToSelect = <HTMLElement> element.querySelector('#user-1');
|
activitiPeopleSearchComponent.onRowClick(fakeUser);
|
||||||
userToSelect.click();
|
let addUserButton = <HTMLElement> element.querySelector('#add-people');
|
||||||
|
addUserButton.click();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(element.querySelector('#user-1')).toBeNull();
|
let gatewayElement: any = element.querySelector('#search-people-list tbody');
|
||||||
|
expect(gatewayElement).not.toBeNull();
|
||||||
|
expect(gatewayElement.children.length).toBe(1);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+40
-17
@@ -32,21 +32,23 @@ declare var require: any;
|
|||||||
|
|
||||||
export class ActivitiPeopleSearch implements OnInit, AfterViewInit {
|
export class ActivitiPeopleSearch implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
@Input()
|
|
||||||
iconImageUrl: string = require('../assets/images/user.jpg');
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
results: Observable<User[]>;
|
results: Observable<User[]>;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
onSearch: EventEmitter<any> = new EventEmitter();
|
searchPeople: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
onRowClicked: EventEmitter<any> = new EventEmitter();
|
success: EventEmitter<User> = new EventEmitter<User>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
closeSearch = new EventEmitter();
|
||||||
|
|
||||||
searchUser: FormControl = new FormControl();
|
searchUser: FormControl = new FormControl();
|
||||||
|
|
||||||
userList: User[] = [];
|
users: User[] = [];
|
||||||
|
|
||||||
|
selectedUser: User;
|
||||||
|
|
||||||
constructor(private translateService: AlfrescoTranslationService) {
|
constructor(private translateService: AlfrescoTranslationService) {
|
||||||
if (translateService) {
|
if (translateService) {
|
||||||
@@ -58,16 +60,16 @@ export class ActivitiPeopleSearch implements OnInit, AfterViewInit {
|
|||||||
.debounceTime(200)
|
.debounceTime(200)
|
||||||
.subscribe((event: string) => {
|
.subscribe((event: string) => {
|
||||||
if (event && event.trim()) {
|
if (event && event.trim()) {
|
||||||
this.onSearch.emit(event);
|
this.searchPeople.emit(event);
|
||||||
} else {
|
} else {
|
||||||
this.userList = [];
|
this.users = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.results.subscribe((list) => {
|
this.results.subscribe((list) => {
|
||||||
this.userList = list;
|
this.users = list;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,17 +87,38 @@ export class ActivitiPeopleSearch implements OnInit, AfterViewInit {
|
|||||||
return isUpgraded;
|
return isUpgraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClick(userClicked: User) {
|
onRowClick(user: User) {
|
||||||
this.onRowClicked.emit(userClicked);
|
this.selectedUser = user;
|
||||||
this.userList = this.userList.filter((user) => {
|
}
|
||||||
|
|
||||||
|
closeSearchList() {
|
||||||
|
this.closeSearch.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
addInvolvedUser() {
|
||||||
|
if (this.selectedUser === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.success.emit(this.selectedUser);
|
||||||
|
this.users = this.users.filter((user) => {
|
||||||
this.searchUser.reset();
|
this.searchUser.reset();
|
||||||
return user.id !== userClicked.id;
|
return user.id !== this.selectedUser.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisplayUser(user: User): string {
|
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
||||||
let firstName = user.firstName && user.firstName !== 'null' ? user.firstName : 'N/A';
|
firstName = (firstName !== null ? firstName : '');
|
||||||
let lastName = user.lastName && user.lastName !== 'null' ? user.lastName : 'N/A';
|
lastName = (lastName !== null ? lastName : '');
|
||||||
return firstName + ' - ' + lastName;
|
return firstName + delimiter + lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitialUserName(firstName: string, lastName: string) {
|
||||||
|
firstName = (firstName !== null && firstName !== '' ? firstName[0] : '');
|
||||||
|
lastName = (lastName !== null && lastName !== '' ? lastName[0] : '');
|
||||||
|
return this.getDisplayUser(firstName, lastName, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
hasUsers() {
|
||||||
|
return (this.users && this.users.length > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,74 @@
|
|||||||
:host {
|
.assignment-header{
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding: 6px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assigment-count{
|
||||||
|
float: left;
|
||||||
|
padding: 10px 0px;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-family: Muli;
|
||||||
|
opacity: 0.54;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-people{
|
||||||
|
float: right;
|
||||||
|
padding: 8px;
|
||||||
|
height: 26px;
|
||||||
|
opacity: 0.54;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-people:hover{
|
||||||
|
color: #ff9100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assignment-top-container{
|
||||||
|
border-top: 2px solid #eee;
|
||||||
|
margin: 8px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assignment-container{
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activiti-label {
|
.assignment-list-container {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-full-name {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-email {
|
||||||
|
font-family: 'Muli';
|
||||||
|
opacity: 0.54;
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-edit-label {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
|
||||||
|
activiti-people-list >>> alfresco-datatable >>> .people-pic {
|
||||||
|
background: #ffc800;
|
||||||
|
padding: 12px 10px;
|
||||||
|
border-radius: 100px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: Muli;
|
||||||
|
text-transform: uppercase
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-icons.people__icon:hover {
|
activiti-people-list >>> alfresco-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
||||||
color: rgb(255, 152, 0);
|
padding: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
.add-people-dialog__content {
|
|
||||||
padding: 20px 24px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-tooltip {
|
|
||||||
will-change: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-icons {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-33
@@ -1,36 +1,42 @@
|
|||||||
<span class="activiti-label mdl-badge" id="people-title"
|
<div class="mdl-grid mdl-shadow--2dp assignment-top-container">
|
||||||
[attr.data-badge]="people?.length">{{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }}</span>
|
<div class="assignment-header">
|
||||||
<div *ngIf="!readOnly" id="addPeople" (click)="showDialog()" class="icon material-icons people__icon">add</div>
|
<div *ngIf="hasPeople()" class="assigment-count" id="people-title">
|
||||||
<div *ngIf="!readOnly" class="mdl-tooltip" data-mdl-for="addPeople">
|
{{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }} {{ ' (' + people.length + ')' }}
|
||||||
Add a person
|
</div>
|
||||||
</div>
|
<div *ngIf="!hasPeople()" class="assigment-count" id="no-people-label">
|
||||||
<div class="menu-container" *ngIf="people?.length > 0">
|
{{ 'TASK_DETAILS.PEOPLE.NONE' | translate }}
|
||||||
<ul class='mdl-list'>
|
</div>
|
||||||
<li class="mdl-list__item" *ngFor="let user of people">
|
<div *ngIf="isEditMode()" class="add-people" (click)="onAddAssignement()">
|
||||||
<span class="mdl-chip mdl-chip--contact mdl-chip--deletable">
|
<i class="material-icons">person_add</i>
|
||||||
<img class="mdl-chip__contact" [src]="iconImageUrl" />
|
</div>
|
||||||
<span id="user-{{user.id}}" class="mdl-chip__text">{{getDisplayUser(user)}}</span>
|
</div>
|
||||||
<a *ngIf="!readOnly" class="mdl-chip__action"><i id="remove-{{user.id}}" (click)="removeInvolvedUser(user)" class="material-icons people__icon">cancel</i></a>
|
<div class="assignment-container" *ngIf="showAssignment">
|
||||||
</span>
|
<activiti-people-search
|
||||||
</li>
|
(searchPeople)="searchUser($event)"
|
||||||
</ul>
|
(success)="involveUser($event)"
|
||||||
</div>
|
(closeSearch)="onCloseSearch()"
|
||||||
<div *ngIf="people?.length === 0" id="no-people-label">
|
[results]="peopleSearch$">
|
||||||
{{ 'TASK_DETAILS.PEOPLE.NONE' | translate }}
|
|
||||||
</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$"
|
|
||||||
[iconImageUrl]="iconImageUrl" #activitipeoplesearch>
|
|
||||||
</activiti-people-search>
|
</activiti-people-search>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="assignment-list-container" id="assignment-people-list" *ngIf="hasPeople()">
|
||||||
<button type="button" id="close-people-dialog" (click)="closeDialog()" class="mdl-button close">
|
<activiti-people-list
|
||||||
{{'PEOPLE.DIALOG_CLOSE' | translate }}
|
[users]="people"
|
||||||
</button>
|
[actions]="isEditMode()"
|
||||||
|
(clickAction)="onClickAction($event)">
|
||||||
|
<data-columns>
|
||||||
|
<data-column key="firstName">
|
||||||
|
<ng-template let-entry="$implicit">
|
||||||
|
<div class="people-pic">{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||||
|
</ng-template>
|
||||||
|
</data-column>
|
||||||
|
<data-column key="email" class="full-width">
|
||||||
|
<ng-template let-entry="$implicit">
|
||||||
|
<div class="people-full-name">{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}</div>
|
||||||
|
<div class="people-email">{{ entry.row.obj.email }}</div>
|
||||||
|
<div class="people-edit-label">can edit</div>
|
||||||
|
</ng-template>
|
||||||
|
</data-column>
|
||||||
|
</data-columns>
|
||||||
|
</activiti-people-list>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</div>
|
||||||
|
|||||||
+51
-71
@@ -16,12 +16,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { CoreModule, AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
|
import { CoreModule, AlfrescoTranslationService, LogService } 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 { ActivitiPeopleSearch } from './activiti-people-search.component';
|
||||||
|
import { ActivitiPeopleList } from './activiti-people-list.component';
|
||||||
|
import { ActivitiPeople } from './activiti-people.component';
|
||||||
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
import { User } from '../models/user.model';
|
import { User } from '../models/user.model';
|
||||||
|
import { ActivitiPeopleService } from '../services/activiti-people.service';
|
||||||
|
|
||||||
declare let jasmine: any;
|
declare let jasmine: any;
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ const fakeUser: User = new User({
|
|||||||
email: 'fake@mail.com'
|
email: 'fake@mail.com'
|
||||||
});
|
});
|
||||||
|
|
||||||
const fakeUserToInvolve: User = new User({
|
const fakeSecondUser: User = new User({
|
||||||
id: 'fake-involve-id',
|
id: 'fake-involve-id',
|
||||||
firstName: 'fake-involve-name',
|
firstName: 'fake-involve-name',
|
||||||
lastName: 'fake-involve-last',
|
lastName: 'fake-involve-last',
|
||||||
@@ -45,21 +47,25 @@ describe('ActivitiPeople', () => {
|
|||||||
let fixture: ComponentFixture<ActivitiPeople>;
|
let fixture: ComponentFixture<ActivitiPeople>;
|
||||||
let element: HTMLElement;
|
let element: HTMLElement;
|
||||||
let componentHandler;
|
let componentHandler;
|
||||||
|
let userArray = [fakeUser, fakeSecondUser];
|
||||||
let logService: LogService;
|
let logService: LogService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CoreModule.forRoot()
|
CoreModule.forRoot(),
|
||||||
|
DataTableModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ActivitiPeople,
|
ActivitiPeopleSearch,
|
||||||
ActivitiPeopleSearch
|
ActivitiPeopleList,
|
||||||
|
ActivitiPeople
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ActivitiPeopleService
|
ActivitiPeopleService
|
||||||
]
|
]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
|
|
||||||
logService = TestBed.get(LogService);
|
logService = TestBed.get(LogService);
|
||||||
|
|
||||||
let translateService = TestBed.get(AlfrescoTranslationService);
|
let translateService = TestBed.get(AlfrescoTranslationService);
|
||||||
@@ -74,16 +80,24 @@ describe('ActivitiPeople', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
window['componentHandler'] = componentHandler;
|
window['componentHandler'] = componentHandler;
|
||||||
|
|
||||||
|
activitiPeopleComponent.people = [];
|
||||||
|
activitiPeopleComponent.readOnly = true;
|
||||||
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should show people component title', () => {
|
it('should show people component title', async(() => {
|
||||||
expect(element.querySelector('#people-title')).toBeDefined();
|
activitiPeopleComponent.people = [...userArray];
|
||||||
expect(element.querySelector('#people-title')).not.toBeNull();
|
fixture.detectChanges();
|
||||||
});
|
fixture.whenStable()
|
||||||
|
.then(() => {
|
||||||
|
expect(element.querySelector('#people-title')).toBeDefined();
|
||||||
|
expect(element.querySelector('#people-title')).not.toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should show no people involved message', () => {
|
it('should show no people involved message', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
expect(element.querySelector('#no-people-label')).not.toBeNull();
|
expect(element.querySelector('#no-people-label')).not.toBeNull();
|
||||||
@@ -91,51 +105,11 @@ describe('ActivitiPeople', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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.closeDialog();
|
|
||||||
let dialogWindow = <HTMLElement> element.querySelector('#add-people-dialog');
|
|
||||||
expect(dialogWindow.getAttribute('open')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reset search input when the dialog is closed', () => {
|
|
||||||
let userInputSearch: HTMLInputElement;
|
|
||||||
activitiPeopleComponent.showDialog();
|
|
||||||
expect(element.querySelector('#addPeople')).not.toBeNull();
|
|
||||||
userInputSearch = <HTMLInputElement> element.querySelector('#userSearchText');
|
|
||||||
userInputSearch.value = 'fake-search-value';
|
|
||||||
activitiPeopleComponent.closeDialog();
|
|
||||||
activitiPeopleComponent.showDialog();
|
|
||||||
userInputSearch = <HTMLInputElement> element.querySelector('#userSearchText');
|
|
||||||
|
|
||||||
expect(userInputSearch).not.toBeNull();
|
|
||||||
expect(userInputSearch.value).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when there are involved people', () => {
|
describe('when there are involved people', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
activitiPeopleComponent.taskId = 'fake-task-id';
|
activitiPeopleComponent.taskId = 'fake-task-id';
|
||||||
activitiPeopleComponent.people.push(fakeUser);
|
activitiPeopleComponent.people.push(...userArray);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -147,11 +121,14 @@ describe('ActivitiPeople', () => {
|
|||||||
jasmine.Ajax.uninstall();
|
jasmine.Ajax.uninstall();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show people involved', () => {
|
it('should show people involved', async(() => {
|
||||||
expect(element.querySelector('#user-fake-id')).not.toBeNull();
|
fixture.whenStable()
|
||||||
expect(element.querySelector('#user-fake-id').textContent).toContain('fake-name');
|
.then(() => {
|
||||||
expect(element.querySelector('#user-fake-id').textContent).toContain('fake-last');
|
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||||
});
|
expect(gatewayElement).not.toBeNull();
|
||||||
|
expect(gatewayElement.children.length).toBe(2);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should remove pepole involved', async(() => {
|
it('should remove pepole involved', async(() => {
|
||||||
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
||||||
@@ -161,21 +138,23 @@ describe('ActivitiPeople', () => {
|
|||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(element.querySelector('#user-fake-id')).toBeNull();
|
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||||
|
expect(gatewayElement).not.toBeNull();
|
||||||
|
expect(gatewayElement.children.length).toBe(1);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should involve pepole', async(() => {
|
it('should involve pepole', async(() => {
|
||||||
activitiPeopleComponent.involveUser(fakeUserToInvolve);
|
activitiPeopleComponent.involveUser(fakeUser);
|
||||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
status: 200
|
status: 200
|
||||||
});
|
});
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(element.querySelector('#user-fake-involve-id')).not.toBeNull();
|
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||||
expect(element.querySelector('#user-fake-involve-id').textContent)
|
expect(gatewayElement).not.toBeNull();
|
||||||
.toBe('fake-involve-name fake-involve-last');
|
expect(gatewayElement.children.length).toBe(3);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -226,6 +205,8 @@ describe('ActivitiPeople', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jasmine.Ajax.install();
|
jasmine.Ajax.install();
|
||||||
|
activitiPeopleComponent.people.push(...userArray);
|
||||||
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -243,8 +224,6 @@ describe('ActivitiPeople', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not remove user if remove involved user fail', async(() => {
|
it('should not remove user if remove involved user fail', async(() => {
|
||||||
activitiPeopleComponent.people.push(fakeUser);
|
|
||||||
fixture.detectChanges();
|
|
||||||
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
||||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
status: 403
|
status: 403
|
||||||
@@ -252,22 +231,23 @@ describe('ActivitiPeople', () => {
|
|||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(element.querySelector('#user-fake-id')).not.toBeNull();
|
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||||
expect(element.querySelector('#user-fake-id').textContent)
|
expect(gatewayElement).not.toBeNull();
|
||||||
.toBe('fake-name fake-last');
|
expect(gatewayElement.children.length).toBe(2);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not involve user if involve user fail', async(() => {
|
it('should not involve user if involve user fail', async(() => {
|
||||||
activitiPeopleComponent.involveUser(fakeUserToInvolve);
|
activitiPeopleComponent.involveUser(fakeUser);
|
||||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
status: 403
|
status: 403
|
||||||
});
|
});
|
||||||
fixture.whenStable()
|
fixture.whenStable()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(element.querySelector('#user-fake-id')).toBeNull();
|
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||||
expect(element.querySelector('#no-people-label').textContent).toContain('TASK_DETAILS.PEOPLE.NONE');
|
expect(gatewayElement).not.toBeNull();
|
||||||
|
expect(gatewayElement.children.length).toBe(2);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, ViewChild } from '@angular/core';
|
import { Component, Input, AfterViewInit } from '@angular/core';
|
||||||
import { Observer, Observable } from 'rxjs/Rx';
|
import { Observer, Observable } from 'rxjs/Rx';
|
||||||
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
|
||||||
import { User } from '../models/user.model';
|
import { User, UserEventModel } from '../models/index';
|
||||||
import { ActivitiPeopleService } from '../services/activiti-people.service';
|
import { ActivitiPeopleService } from '../services/activiti-people.service';
|
||||||
|
|
||||||
declare let dialogPolyfill: any;
|
declare let componentHandler: any;
|
||||||
declare var require: any;
|
declare var require: any;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -29,7 +29,7 @@ declare var require: any;
|
|||||||
templateUrl: './activiti-people.component.html',
|
templateUrl: './activiti-people.component.html',
|
||||||
styleUrls: ['./activiti-people.component.css']
|
styleUrls: ['./activiti-people.component.css']
|
||||||
})
|
})
|
||||||
export class ActivitiPeople {
|
export class ActivitiPeople implements AfterViewInit {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
iconImageUrl: string = require('../assets/images/user.jpg');
|
iconImageUrl: string = require('../assets/images/user.jpg');
|
||||||
@@ -43,11 +43,7 @@ export class ActivitiPeople {
|
|||||||
@Input()
|
@Input()
|
||||||
readOnly: boolean = false;
|
readOnly: boolean = false;
|
||||||
|
|
||||||
@ViewChild('dialog')
|
showAssignment: boolean = false;
|
||||||
dialog: any;
|
|
||||||
|
|
||||||
@ViewChild('activitipeoplesearch')
|
|
||||||
activitipeoplesearch: any;
|
|
||||||
|
|
||||||
private peopleSearchObserver: Observer<User[]>;
|
private peopleSearchObserver: Observer<User[]>;
|
||||||
peopleSearch$: Observable<User[]>;
|
peopleSearch$: Observable<User[]>;
|
||||||
@@ -66,21 +62,18 @@ export class ActivitiPeople {
|
|||||||
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
|
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
|
||||||
}
|
}
|
||||||
|
|
||||||
public showDialog() {
|
ngAfterViewInit() {
|
||||||
if (!this.dialog.nativeElement.showModal) {
|
this.setupMaterialComponents(componentHandler);
|
||||||
dialogPolyfill.registerDialog(this.dialog.nativeElement);
|
|
||||||
}
|
|
||||||
if (this.dialog) {
|
|
||||||
this.dialog.nativeElement.showModal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog() {
|
setupMaterialComponents(handler?: any): boolean {
|
||||||
if (this.dialog) {
|
// workaround for MDL issues with dynamic components
|
||||||
this.dialog.nativeElement.close();
|
let isUpgraded: boolean = false;
|
||||||
this.peopleSearchObserver.next([]);
|
if (handler) {
|
||||||
this.activitipeoplesearch.searchUser.reset();
|
handler.upgradeAllRegistered();
|
||||||
|
isUpgraded = true;
|
||||||
}
|
}
|
||||||
|
return isUpgraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUser(searchedWord: string) {
|
searchUser(searchedWord: string) {
|
||||||
@@ -91,9 +84,10 @@ export class ActivitiPeople {
|
|||||||
}
|
}
|
||||||
|
|
||||||
involveUser(user: User) {
|
involveUser(user: User) {
|
||||||
|
this.showAssignment = false;
|
||||||
this.peopleService.involveUserWithTask(this.taskId, user.id.toString())
|
this.peopleService.involveUserWithTask(this.taskId, user.id.toString())
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.people.push(user);
|
this.people = [...this.people, user];
|
||||||
}, error => this.logService.error('Impossible to involve user with task'));
|
}, error => this.logService.error('Impossible to involve user with task'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +100,38 @@ export class ActivitiPeople {
|
|||||||
}, error => this.logService.error('Impossible to remove involved user from task'));
|
}, error => this.logService.error('Impossible to remove involved user from task'));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisplayUser(user: User): string {
|
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
||||||
let firstName = user.firstName && user.firstName !== 'null' ? user.firstName : 'N/A';
|
firstName = (firstName !== null ? firstName : '');
|
||||||
let lastName = user.lastName && user.lastName !== 'null' ? user.lastName : 'N/A';
|
lastName = (lastName !== null ? lastName : '');
|
||||||
return firstName + ' ' + lastName;
|
return firstName + delimiter + lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitialUserName(firstName: string, lastName: string) {
|
||||||
|
firstName = (firstName !== null && firstName !== '' ? firstName[0] : '');
|
||||||
|
lastName = (lastName !== null && lastName !== '' ? lastName[0] : '');
|
||||||
|
return this.getDisplayUser(firstName, lastName, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddAssignement() {
|
||||||
|
this.showAssignment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickAction(event: UserEventModel) {
|
||||||
|
if (event.type === 'remove') {
|
||||||
|
this.removeInvolvedUser(event.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPeople() {
|
||||||
|
return this.people && this.people.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEditMode() {
|
||||||
|
return !this.readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseSearch() {
|
||||||
|
this.showAssignment = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,3 +28,4 @@ export * from './activiti-task-details.component';
|
|||||||
export * from './activiti-start-task.component';
|
export * from './activiti-start-task.component';
|
||||||
export * from './activiti-people-search.component';
|
export * from './activiti-people-search.component';
|
||||||
export * from './adf-create-task-attachment.component';
|
export * from './adf-create-task-attachment.component';
|
||||||
|
export * from './activiti-people-list.component';
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
"ASSIGNEE": "Assignee",
|
"ASSIGNEE": "Assignee",
|
||||||
"DUE": "Due",
|
"DUE": "Due",
|
||||||
"FORM": "Form",
|
"FORM": "Form",
|
||||||
"PEOPLE": "People",
|
"PEOPLE": "People this task is shared with",
|
||||||
"COMMENTS": "Comments",
|
"COMMENTS": "Comments",
|
||||||
"CHECKLIST": "Checklist"
|
"CHECKLIST": "Checklist",
|
||||||
|
"ADD_PEOPLE": "Add people & groups"
|
||||||
},
|
},
|
||||||
"BUTTON": {
|
"BUTTON": {
|
||||||
"COMPLETE": "Complete",
|
"COMPLETE": "Complete",
|
||||||
@@ -84,6 +85,7 @@
|
|||||||
},
|
},
|
||||||
"PEOPLE": {
|
"PEOPLE": {
|
||||||
"DIALOG_CLOSE": "CLOSE",
|
"DIALOG_CLOSE": "CLOSE",
|
||||||
|
"ADD_USER": "ADD",
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"NO_USERS": "No user found to involve"
|
"NO_USERS": "No user found to involve"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ export * from './icon.model';
|
|||||||
export * from './user.model';
|
export * from './user.model';
|
||||||
export * from './task-details.model';
|
export * from './task-details.model';
|
||||||
export * from './task-details.event';
|
export * from './task-details.event';
|
||||||
|
export * from './user-event.model';
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This object represent the User Event.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns {UserEventModel} .
|
||||||
|
*/
|
||||||
|
export class UserEventModel {
|
||||||
|
type: string = '';
|
||||||
|
value: any = {};
|
||||||
|
|
||||||
|
constructor(obj?: any) {
|
||||||
|
this.type = obj && obj.type;
|
||||||
|
this.value = obj && obj.value || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user