From 7f4614cebf441d02bc0028c5a6266d2f8bbcee92 Mon Sep 17 00:00:00 2001 From: Infad Kachancheri Date: Wed, 21 Jun 2017 14:02:48 +0530 Subject: [PATCH] [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 --- .../ng2-activiti-tasklist/README.md | 25 ++++ .../docs/assets/activiti_people.png | Bin 0 -> 14826 bytes ng2-components/ng2-activiti-tasklist/index.ts | 7 +- .../activiti-people-list.component.css | 0 .../activiti-people-list.component.html | 7 + .../activiti-people-list.component.spec.ts | 100 ++++++++++++++ .../activiti-people-list.component.ts | 99 ++++++++++++++ .../activiti-people-search.component.css | 58 ++++++++- .../activiti-people-search.component.html | 46 +++++-- .../activiti-people-search.component.spec.ts | 41 +++--- .../activiti-people-search.component.ts | 57 +++++--- .../components/activiti-people.component.css | 83 +++++++++--- .../components/activiti-people.component.html | 72 ++++++----- .../activiti-people.component.spec.ts | 122 ++++++++---------- .../components/activiti-people.component.ts | 74 +++++++---- .../src/components/index.ts | 1 + .../ng2-activiti-tasklist/src/i18n/en.json | 6 +- .../ng2-activiti-tasklist/src/models/index.ts | 1 + .../src/models/user-event.model.ts | 33 +++++ 19 files changed, 632 insertions(+), 200 deletions(-) create mode 100644 ng2-components/ng2-activiti-tasklist/docs/assets/activiti_people.png create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.css create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.html create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.spec.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/models/user-event.model.ts diff --git a/ng2-components/ng2-activiti-tasklist/README.md b/ng2-components/ng2-activiti-tasklist/README.md index e3b71364ba..dd176ad64a 100644 --- a/ng2-components/ng2-activiti-tasklist/README.md +++ b/ng2-components/ng2-activiti-tasklist/README.md @@ -425,6 +425,31 @@ The purpose of the component is populate the local variable called `properties` "description": "string" } ``` +## Task People Component + +This component displays involved users to a specified task + +```html + + +``` + +![activiti-people](docs/assets/activiti_people.png) + +### 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 diff --git a/ng2-components/ng2-activiti-tasklist/docs/assets/activiti_people.png b/ng2-components/ng2-activiti-tasklist/docs/assets/activiti_people.png new file mode 100644 index 0000000000000000000000000000000000000000..42c7c41728f2591e3c30d5a254a6b3fdedb560b3 GIT binary patch literal 14826 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 + \ No newline at end of file diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.spec.ts new file mode 100644 index 0000000000..3ec6e1a778 --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.spec.ts @@ -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; + 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); + }); +}); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.ts new file mode 100644 index 0000000000..eeb4645130 --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-list.component.ts @@ -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 = new EventEmitter(); + + @Output() + clickAction: EventEmitter = new EventEmitter(); + + 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})); + } +} diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.css b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.css index 2bbb854137..aeed7723a1 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.css +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.css @@ -33,4 +33,60 @@ .mdl-chip-search-people__text{ padding-left: 10px; -} \ No newline at end of file +} + +.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%; +} diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.html index 106ad72f01..c9d407a6a1 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.html @@ -1,15 +1,33 @@ -
- - -
-
    -
  • - -
  • -
    - {{'PEOPLE.SEARCH.NO_USERS' | translate }} +
    {{ 'TASK_DETAILS.LABELS.ADD_PEOPLE' | translate }}
    +
    +
    + +
    -
+ +
+ + + + +
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}
+
+
+ + +
{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}
+
+
+
+
+
+
+ + +
\ No newline at end of file diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.spec.ts index 3def161a37..04a7676d6e 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.spec.ts @@ -19,6 +19,8 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { Observable } from 'rxjs/Observable'; import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core'; 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'; declare let jasmine: any; @@ -49,10 +51,12 @@ describe('ActivitiPeopleSearch', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - CoreModule.forRoot() + CoreModule.forRoot(), + DataTableModule ], declarations: [ - ActivitiPeopleSearch + ActivitiPeopleSearch, + ActivitiPeopleList ] }).compileComponents().then(() => { @@ -78,28 +82,25 @@ describe('ActivitiPeopleSearch', () => { expect(element.querySelector('#userSearchText')).not.toBeNull(); }); - it('should show no user found to involve message', () => { + it('should hide people-list container', () => { fixture.detectChanges(); fixture.whenStable() .then(() => { - expect(element.querySelector('#no-user-found')).not.toBeNull(); - expect(element.querySelector('#no-user-found').textContent).toContain('PEOPLE.SEARCH.NO_USERS'); + expect(element.querySelector('#search-people-list')).toBeNull(); }); + }); it('should show user which can be involved ', (done) => { - activitiPeopleSearchComponent.onSearch.subscribe(() => { + activitiPeopleSearchComponent.searchPeople.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'); + let gatewayElement: any = element.querySelector('#search-people-list tbody'); + expect(gatewayElement).not.toBeNull(); + expect(gatewayElement.children.length).toBe(2); done(); }); }); @@ -110,7 +111,7 @@ describe('ActivitiPeopleSearch', () => { }); it('should send an event when an user is clicked', (done) => { - activitiPeopleSearchComponent.onRowClicked.subscribe((user) => { + activitiPeopleSearchComponent.success.subscribe((user) => { expect(user).toBeDefined(); expect(user.firstName).toBe('fake-name'); done(); @@ -120,8 +121,9 @@ describe('ActivitiPeopleSearch', () => { fixture.detectChanges(); fixture.whenStable() .then(() => { - let userToSelect = element.querySelector('#user-1'); - userToSelect.click(); + activitiPeopleSearchComponent.onRowClick(fakeUser); + let addUserButton = element.querySelector('#add-people'); + addUserButton.click(); }); }); @@ -129,13 +131,16 @@ describe('ActivitiPeopleSearch', () => { activitiPeopleSearchComponent.results = Observable.of(userArray); activitiPeopleSearchComponent.ngOnInit(); fixture.detectChanges(); - let userToSelect = element.querySelector('#user-1'); - userToSelect.click(); + activitiPeopleSearchComponent.onRowClick(fakeUser); + let addUserButton = element.querySelector('#add-people'); + addUserButton.click(); fixture.detectChanges(); fixture.whenStable() .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(); }); }); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.ts index e5425d136d..ffb6be6235 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people-search.component.ts @@ -32,21 +32,23 @@ declare var require: any; export class ActivitiPeopleSearch implements OnInit, AfterViewInit { - @Input() - iconImageUrl: string = require('../assets/images/user.jpg'); - @Input() results: Observable; @Output() - onSearch: EventEmitter = new EventEmitter(); + searchPeople: EventEmitter = new EventEmitter(); @Output() - onRowClicked: EventEmitter = new EventEmitter(); + success: EventEmitter = new EventEmitter(); + + @Output() + closeSearch = new EventEmitter(); searchUser: FormControl = new FormControl(); - userList: User[] = []; + users: User[] = []; + + selectedUser: User; constructor(private translateService: AlfrescoTranslationService) { if (translateService) { @@ -58,16 +60,16 @@ export class ActivitiPeopleSearch implements OnInit, AfterViewInit { .debounceTime(200) .subscribe((event: string) => { if (event && event.trim()) { - this.onSearch.emit(event); + this.searchPeople.emit(event); } else { - this.userList = []; + this.users = []; } }); } ngOnInit() { this.results.subscribe((list) => { - this.userList = list; + this.users = list; }); } @@ -85,17 +87,38 @@ export class ActivitiPeopleSearch implements OnInit, AfterViewInit { return isUpgraded; } - onRowClick(userClicked: User) { - this.onRowClicked.emit(userClicked); - this.userList = this.userList.filter((user) => { + onRowClick(user: User) { + this.selectedUser = 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(); - return user.id !== userClicked.id; + return user.id !== this.selectedUser.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; + getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string { + firstName = (firstName !== null ? firstName : ''); + lastName = (lastName !== null ? 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); } } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.css b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.css index c618a45766..a1bce0db70 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.css +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.css @@ -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%; } -.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-size: 18px; + font-family: Muli; + text-transform: uppercase } -.material-icons.people__icon:hover { - color: rgb(255, 152, 0); -} - -.add-people-dialog__content { - padding: 20px 24px 2px; -} - -.mdl-tooltip { - will-change: unset; -} - -.material-icons { - cursor: pointer; +activiti-people-list >>> alfresco-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{ + padding: 10px; } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.html index 2d7e3f0a50..409a1aace5 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.html @@ -1,36 +1,42 @@ -{{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }} -
add
-
- Add a person -
- -
- {{ 'TASK_DETAILS.PEOPLE.NONE' | translate }} -
- - -

Involve User

-
- +
+
+
+ {{ 'TASK_DETAILS.LABELS.PEOPLE' | translate }} {{ ' (' + people.length + ')' }} +
+
+ {{ 'TASK_DETAILS.PEOPLE.NONE' | translate }} +
+
+ person_add +
+
+
+
-
- +
+ + + + +
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}
+
+
+ + +
{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}
+
{{ entry.row.obj.email }}
+
can edit
+
+
+
+
-
+ diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.spec.ts index f1b00410ed..ee251b9b5f 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.spec.ts @@ -16,12 +16,14 @@ */ 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 { ActivitiPeopleService } from '../services/activiti-people.service'; -import { ActivitiPeople } from './activiti-people.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 { ActivitiPeopleService } from '../services/activiti-people.service'; declare let jasmine: any; @@ -32,7 +34,7 @@ const fakeUser: User = new User({ email: 'fake@mail.com' }); -const fakeUserToInvolve: User = new User({ +const fakeSecondUser: User = new User({ id: 'fake-involve-id', firstName: 'fake-involve-name', lastName: 'fake-involve-last', @@ -45,21 +47,25 @@ describe('ActivitiPeople', () => { let fixture: ComponentFixture; let element: HTMLElement; let componentHandler; + let userArray = [fakeUser, fakeSecondUser]; let logService: LogService; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - CoreModule.forRoot() + CoreModule.forRoot(), + DataTableModule ], declarations: [ - ActivitiPeople, - ActivitiPeopleSearch + ActivitiPeopleSearch, + ActivitiPeopleList, + ActivitiPeople ], providers: [ ActivitiPeopleService ] }).compileComponents().then(() => { + logService = TestBed.get(LogService); let translateService = TestBed.get(AlfrescoTranslationService); @@ -74,16 +80,24 @@ describe('ActivitiPeople', () => { ]); window['componentHandler'] = componentHandler; + + activitiPeopleComponent.people = []; + activitiPeopleComponent.readOnly = true; + fixture.detectChanges(); }); })); - it('should show people component title', () => { - expect(element.querySelector('#people-title')).toBeDefined(); - expect(element.querySelector('#people-title')).not.toBeNull(); - }); + it('should show people component title', async(() => { + activitiPeopleComponent.people = [...userArray]; + 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', () => { - fixture.detectChanges(); fixture.whenStable() .then(() => { 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 = 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 = element.querySelector('#userSearchText'); - userInputSearch.value = 'fake-search-value'; - activitiPeopleComponent.closeDialog(); - activitiPeopleComponent.showDialog(); - userInputSearch = element.querySelector('#userSearchText'); - - expect(userInputSearch).not.toBeNull(); - expect(userInputSearch.value).toBeFalsy(); - }); - }); - describe('when there are involved people', () => { beforeEach(() => { activitiPeopleComponent.taskId = 'fake-task-id'; - activitiPeopleComponent.people.push(fakeUser); + activitiPeopleComponent.people.push(...userArray); fixture.detectChanges(); }); @@ -147,11 +121,14 @@ describe('ActivitiPeople', () => { 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 show people involved', async(() => { + fixture.whenStable() + .then(() => { + 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(() => { activitiPeopleComponent.removeInvolvedUser(fakeUser); @@ -161,21 +138,23 @@ describe('ActivitiPeople', () => { fixture.whenStable() .then(() => { 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(() => { - activitiPeopleComponent.involveUser(fakeUserToInvolve); + activitiPeopleComponent.involveUser(fakeUser); 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'); + let gatewayElement: any = element.querySelector('#assignment-people-list tbody'); + expect(gatewayElement).not.toBeNull(); + expect(gatewayElement.children.length).toBe(3); }); })); @@ -226,6 +205,8 @@ describe('ActivitiPeople', () => { beforeEach(() => { jasmine.Ajax.install(); + activitiPeopleComponent.people.push(...userArray); + fixture.detectChanges(); }); afterEach(() => { @@ -243,8 +224,6 @@ describe('ActivitiPeople', () => { })); 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 @@ -252,22 +231,23 @@ describe('ActivitiPeople', () => { 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'); + let gatewayElement: any = element.querySelector('#assignment-people-list tbody'); + expect(gatewayElement).not.toBeNull(); + expect(gatewayElement.children.length).toBe(2); }); })); it('should not involve user if involve user fail', async(() => { - activitiPeopleComponent.involveUser(fakeUserToInvolve); + activitiPeopleComponent.involveUser(fakeUser); 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'); + let gatewayElement: any = element.querySelector('#assignment-people-list tbody'); + expect(gatewayElement).not.toBeNull(); + expect(gatewayElement.children.length).toBe(2); }); })); }); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.ts index da7a46e4ad..3bc010b3f8 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-people.component.ts @@ -15,13 +15,13 @@ * 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 { 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'; -declare let dialogPolyfill: any; +declare let componentHandler: any; declare var require: any; @Component({ @@ -29,7 +29,7 @@ declare var require: any; templateUrl: './activiti-people.component.html', styleUrls: ['./activiti-people.component.css'] }) -export class ActivitiPeople { +export class ActivitiPeople implements AfterViewInit { @Input() iconImageUrl: string = require('../assets/images/user.jpg'); @@ -43,11 +43,7 @@ export class ActivitiPeople { @Input() readOnly: boolean = false; - @ViewChild('dialog') - dialog: any; - - @ViewChild('activitipeoplesearch') - activitipeoplesearch: any; + showAssignment: boolean = false; private peopleSearchObserver: Observer; peopleSearch$: Observable; @@ -66,21 +62,18 @@ export class ActivitiPeople { this.peopleSearch$ = new Observable(observer => this.peopleSearchObserver = observer).share(); } - public showDialog() { - if (!this.dialog.nativeElement.showModal) { - dialogPolyfill.registerDialog(this.dialog.nativeElement); - } - if (this.dialog) { - this.dialog.nativeElement.showModal(); - } + ngAfterViewInit() { + this.setupMaterialComponents(componentHandler); } - public closeDialog() { - if (this.dialog) { - this.dialog.nativeElement.close(); - this.peopleSearchObserver.next([]); - this.activitipeoplesearch.searchUser.reset(); + setupMaterialComponents(handler?: any): boolean { + // workaround for MDL issues with dynamic components + let isUpgraded: boolean = false; + if (handler) { + handler.upgradeAllRegistered(); + isUpgraded = true; } + return isUpgraded; } searchUser(searchedWord: string) { @@ -91,9 +84,10 @@ export class ActivitiPeople { } involveUser(user: User) { + this.showAssignment = false; this.peopleService.involveUserWithTask(this.taskId, user.id.toString()) .subscribe(() => { - this.people.push(user); + this.people = [...this.people, user]; }, 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')); } - 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; + getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string { + firstName = (firstName !== null ? firstName : ''); + lastName = (lastName !== null ? 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; } } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/index.ts b/ng2-components/ng2-activiti-tasklist/src/components/index.ts index fcf5c34c79..4c7a7818b5 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/index.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/index.ts @@ -28,3 +28,4 @@ export * from './activiti-task-details.component'; export * from './activiti-start-task.component'; export * from './activiti-people-search.component'; export * from './adf-create-task-attachment.component'; +export * from './activiti-people-list.component'; diff --git a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json index f356102189..93942ee3d2 100644 --- a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json +++ b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json @@ -12,9 +12,10 @@ "ASSIGNEE": "Assignee", "DUE": "Due", "FORM": "Form", - "PEOPLE": "People", + "PEOPLE": "People this task is shared with", "COMMENTS": "Comments", - "CHECKLIST": "Checklist" + "CHECKLIST": "Checklist", + "ADD_PEOPLE": "Add people & groups" }, "BUTTON": { "COMPLETE": "Complete", @@ -84,6 +85,7 @@ }, "PEOPLE": { "DIALOG_CLOSE": "CLOSE", + "ADD_USER": "ADD", "SEARCH": { "NO_USERS": "No user found to involve" } diff --git a/ng2-components/ng2-activiti-tasklist/src/models/index.ts b/ng2-components/ng2-activiti-tasklist/src/models/index.ts index e3fe92d601..45b713f383 100644 --- a/ng2-components/ng2-activiti-tasklist/src/models/index.ts +++ b/ng2-components/ng2-activiti-tasklist/src/models/index.ts @@ -21,3 +21,4 @@ export * from './icon.model'; export * from './user.model'; export * from './task-details.model'; export * from './task-details.event'; +export * from './user-event.model'; diff --git a/ng2-components/ng2-activiti-tasklist/src/models/user-event.model.ts b/ng2-components/ng2-activiti-tasklist/src/models/user-event.model.ts new file mode 100644 index 0000000000..1837a25af8 --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/models/user-event.model.ts @@ -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 || {}; + } +}