mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
[ADF-1083] Added user images profile as background to comment and involved people (#2198)
* [ADF-1083] start added image for user search * [ADF-1083] - adding user images and style to involved people * [ADF-1083] added loading of images after page refresh * [ADF-1083] fixed problem related to memory leak and added scss style * [ADF-1083] readded changes for user image * [ADF-1083] start fixing test * [ADF-1083] added user images to comment and profile * [ADF-1083] Fixed processlist test * [ADF-1083] removed mdl unused styles * [ADF-1083] Applied design style * [ADF-1083] fixed tests after rebase
This commit is contained in:
parent
8b4261acb3
commit
70ef58e03c
@ -23,6 +23,7 @@ import { Observable } from 'rxjs/Rx';
|
|||||||
import {
|
import {
|
||||||
CommentListComponent,
|
CommentListComponent,
|
||||||
CommentsComponent,
|
CommentsComponent,
|
||||||
|
PeopleService,
|
||||||
TaskListService
|
TaskListService
|
||||||
} from 'ng2-activiti-tasklist';
|
} from 'ng2-activiti-tasklist';
|
||||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||||
@ -55,7 +56,8 @@ describe('ActivitiProcessInstanceComments', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||||
{ provide: TaskListService, useClass: ProcessService },
|
{ provide: TaskListService, useClass: ProcessService },
|
||||||
DatePipe
|
DatePipe,
|
||||||
|
PeopleService
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
.adf-comment-img-container {
|
|
||||||
float: left;
|
|
||||||
width: 40px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-comment-user-icon {
|
|
||||||
padding: 10px 5px;
|
|
||||||
width: 30px;
|
|
||||||
background-color: #01bcd4;
|
|
||||||
border-radius: 50%;
|
|
||||||
font-family: Muli;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-comment-user-name {
|
|
||||||
float: left;
|
|
||||||
width: calc(100% - 120px);
|
|
||||||
padding: 2px 10px;
|
|
||||||
font-family: Muli;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #595959;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-comment-message {
|
|
||||||
float: left;
|
|
||||||
width: calc(100% - 10px);
|
|
||||||
padding: 2px 10px;
|
|
||||||
font-family: Muli;
|
|
||||||
font-style: italic;
|
|
||||||
color: #595959;
|
|
||||||
white-space: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-comment-message-time {
|
|
||||||
float: left;
|
|
||||||
width: calc(100% - 120px);
|
|
||||||
padding: 2px 10px;
|
|
||||||
font-family: Muli;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #595959;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-comment-contents {
|
|
||||||
float: left;
|
|
||||||
width: calc(100% - 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-datatable >>> table thead {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-datatable >>> table {
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-datatable >>> table tbody td {
|
|
||||||
padding: 0px!important;
|
|
||||||
border-top: none !important;
|
|
||||||
}
|
|
@ -5,8 +5,16 @@
|
|||||||
<data-columns>
|
<data-columns>
|
||||||
<data-column key="createdBy">
|
<data-column key="createdBy">
|
||||||
<ng-template let-entry="$implicit">
|
<ng-template let-entry="$implicit">
|
||||||
<div id="comment-user-icon" class="adf-comment-img-container">
|
<div id="comment-user-icon"
|
||||||
<div class="adf-comment-user-icon">{{getUserShortName(entry.row.obj.createdBy)}}</div>
|
class="adf-comment-img-container">
|
||||||
|
<div
|
||||||
|
*ngIf="!entry.row.obj.createdBy.userImage" class="adf-comment-user-icon">
|
||||||
|
{{getUserShortName(entry.row.obj.createdBy)}}</div>
|
||||||
|
<div>
|
||||||
|
<img *ngIf="entry.row.obj.createdBy.userImage" class="adf-people-img"
|
||||||
|
[src]="entry.row.obj.createdBy.userImage"
|
||||||
|
(error)="onErrorImageLoad(entry.row.obj.createdBy)"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</data-column>
|
</data-column>
|
||||||
@ -27,4 +35,4 @@
|
|||||||
</data-column>
|
</data-column>
|
||||||
</data-columns>
|
</data-columns>
|
||||||
|
|
||||||
</adf-datatable>
|
</adf-datatable>
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
@import 'theming';
|
||||||
|
|
||||||
|
.adf {
|
||||||
|
|
||||||
|
&-comment-img-container {
|
||||||
|
float: left;
|
||||||
|
width: 40px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-comment-user-icon {
|
||||||
|
padding: 10px 5px;
|
||||||
|
width: 30px;
|
||||||
|
background-color: mat-color($primary);
|
||||||
|
border-radius: 50%;
|
||||||
|
font-family: Muli;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
height: 18px;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-comment-user-name {
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 120px);
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-family: Muli;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-comment-message {
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-family: Muli;
|
||||||
|
font-style: italic;
|
||||||
|
color: #595959;
|
||||||
|
white-space: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-comment-message-time {
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 120px);
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-family: Muli;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-comment-contents {
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-datatable /deep/ table {
|
||||||
|
thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
border: none !important;
|
||||||
|
tbody td {
|
||||||
|
padding: 0px !important;
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-people-img {
|
||||||
|
border-radius: 90%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,7 +23,7 @@ import { User } from '../models/user.model';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-comment-list',
|
selector: 'adf-comment-list',
|
||||||
templateUrl: './comment-list.component.html',
|
templateUrl: './comment-list.component.html',
|
||||||
styleUrls: ['./comment-list.component.css']
|
styleUrls: ['./comment-list.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class CommentListComponent {
|
export class CommentListComponent {
|
||||||
@ -63,11 +63,11 @@ export class CommentListComponent {
|
|||||||
let today = Number.parseInt(this.datePipe.transform(Date.now(), 'yMMdd'));
|
let today = Number.parseInt(this.datePipe.transform(Date.now(), 'yMMdd'));
|
||||||
if (givenDate === today) {
|
if (givenDate === today) {
|
||||||
formattedDate = 'Today, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
formattedDate = 'Today, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
||||||
}else {
|
} else {
|
||||||
let yesterday = Number.parseInt(this.datePipe.transform(Date.now() - 24 * 3600 * 1000, 'yMMdd'));
|
let yesterday = Number.parseInt(this.datePipe.transform(Date.now() - 24 * 3600 * 1000, 'yMMdd'));
|
||||||
if (givenDate === yesterday) {
|
if (givenDate === yesterday) {
|
||||||
formattedDate = 'Yesterday, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
formattedDate = 'Yesterday, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
||||||
}else {
|
} else {
|
||||||
formattedDate = this.datePipe.transform(aDate, 'MMM dd y, hh:mm a');
|
formattedDate = this.datePipe.transform(aDate, 'MMM dd y, hh:mm a');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,4 +78,8 @@ export class CommentListComponent {
|
|||||||
return this.comments && this.comments.length && true;
|
return this.comments && this.comments.length && true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onErrorImageLoad(user: User) {
|
||||||
|
user.userImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
</md-input-container>
|
</md-input-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<adf-comment-list [comments]="comments">
|
<div *ngIf="comments.length > 0">
|
||||||
</adf-comment-list>
|
<adf-comment-list [comments]="comments">
|
||||||
|
</adf-comment-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,6 +25,7 @@ import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { MdInputModule } from '@angular/material';
|
import { MdInputModule } from '@angular/material';
|
||||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
|
import { PeopleService } from '../services/people.service';
|
||||||
import { TaskListService } from './../services/tasklist.service';
|
import { TaskListService } from './../services/tasklist.service';
|
||||||
import { CommentListComponent } from './comment-list.component';
|
import { CommentListComponent } from './comment-list.component';
|
||||||
import { CommentsComponent } from './comments.component';
|
import { CommentsComponent } from './comments.component';
|
||||||
@ -52,7 +53,8 @@ describe('CommentsComponent', () => {
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
TaskListService,
|
TaskListService,
|
||||||
DatePipe
|
DatePipe,
|
||||||
|
PeopleService
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ describe('CommentsComponent', () => {
|
|||||||
{ message: 'Test2', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
{ message: 'Test2', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
||||||
{ message: 'Test3', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} }
|
{ message: 'Test3', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} }
|
||||||
]));
|
]));
|
||||||
addCommentSpy = spyOn(service, 'addComment').and.returnValue(Observable.of({id: 123, message: 'Test Comment'}));
|
addCommentSpy = spyOn(service, 'addComment').and.returnValue(Observable.of({id: 123, message: 'Test Comment', createdBy: {id: '999'}}));
|
||||||
|
|
||||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||||
'upgradeAllRegistered',
|
'upgradeAllRegistered',
|
||||||
|
@ -19,6 +19,7 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from
|
|||||||
import { Observable, Observer } from 'rxjs/Rx';
|
import { Observable, Observer } from 'rxjs/Rx';
|
||||||
|
|
||||||
import { Comment } from '../models/comment.model';
|
import { Comment } from '../models/comment.model';
|
||||||
|
import { PeopleService } from '../services/people.service';
|
||||||
import { TaskListService } from '../services/tasklist.service';
|
import { TaskListService } from '../services/tasklist.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -51,7 +52,7 @@ export class CommentsComponent implements OnChanges {
|
|||||||
* @param translate Translation service
|
* @param translate Translation service
|
||||||
* @param activitiTaskList Task service
|
* @param activitiTaskList Task service
|
||||||
*/
|
*/
|
||||||
constructor(private activitiTaskList: TaskListService) {
|
constructor(private activitiTaskList: TaskListService, private peopleService: PeopleService) {
|
||||||
this.comment$ = new Observable<Comment>(observer => this.commentObserver = observer).share();
|
this.comment$ = new Observable<Comment>(observer => this.commentObserver = observer).share();
|
||||||
this.comment$.subscribe((comment: Comment) => {
|
this.comment$.subscribe((comment: Comment) => {
|
||||||
this.comments.push(comment);
|
this.comments.push(comment);
|
||||||
@ -79,11 +80,11 @@ export class CommentsComponent implements OnChanges {
|
|||||||
let date2 = new Date(comment2.created);
|
let date2 = new Date(comment2.created);
|
||||||
return date1 > date2 ? -1 : date1 < date2 ? 1 : 0;
|
return date1 > date2 ? -1 : date1 < date2 ? 1 : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
res.forEach((comment) => {
|
res.forEach((comment) => {
|
||||||
|
comment.createdBy.userImage = this.peopleService.getUserImage(comment.createdBy);
|
||||||
this.commentObserver.next(comment);
|
this.commentObserver.next(comment);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.error.emit(err);
|
this.error.emit(err);
|
||||||
}
|
}
|
||||||
@ -98,11 +99,14 @@ export class CommentsComponent implements OnChanges {
|
|||||||
add(): void {
|
add(): void {
|
||||||
if (this.message && this.message.trim() && !this.beingAdded) {
|
if (this.message && this.message.trim() && !this.beingAdded) {
|
||||||
this.beingAdded = true;
|
this.beingAdded = true;
|
||||||
this.activitiTaskList.addComment(this.taskId, this.message).subscribe(
|
this.activitiTaskList.addComment(this.taskId, this.message)
|
||||||
|
.subscribe(
|
||||||
(res: Comment) => {
|
(res: Comment) => {
|
||||||
this.comments.unshift(res);
|
res.createdBy.userImage = this.peopleService.getUserImage(res.createdBy);
|
||||||
this.message = '';
|
this.comments.unshift(res);
|
||||||
this.beingAdded = false;
|
this.message = '';
|
||||||
|
this.beingAdded = false;
|
||||||
|
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.error.emit(err);
|
this.error.emit(err);
|
||||||
@ -119,4 +123,5 @@ export class CommentsComponent implements OnChanges {
|
|||||||
isReadOnly(): boolean {
|
isReadOnly(): boolean {
|
||||||
return this.readOnly;
|
return this.readOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
: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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-chip-search-people{
|
|
||||||
margin: auto;
|
|
||||||
min-width: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-chip-search-people:hover{
|
|
||||||
background-color: #c1c1c1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-chip-search-people img{
|
|
||||||
margin-left: -30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-chip-search-people__text{
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-text-header{
|
|
||||||
font-weight: bold;
|
|
||||||
opacity: 0.54;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-list-container{
|
|
||||||
max-height: 188px;
|
|
||||||
width: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-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);
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> .people-full-name {
|
|
||||||
font-family: 'Muli';
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-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;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
|
||||||
padding: 4px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdl-textfield {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> .adf-data-table td:first-of-type {
|
|
||||||
padding: 10px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-text-container {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -11,7 +11,13 @@
|
|||||||
<data-columns>
|
<data-columns>
|
||||||
<data-column key="firstName">
|
<data-column key="firstName">
|
||||||
<ng-template let-entry="$implicit">
|
<ng-template let-entry="$implicit">
|
||||||
<div class="people-pic">{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
<div *ngIf="!entry.row.obj.userImage" class="people-pic">
|
||||||
|
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||||
|
<div>
|
||||||
|
<img *ngIf="entry.row.obj.userImage" class="people-img"
|
||||||
|
[src]="entry.row.obj.userImage"
|
||||||
|
(error)="onErrorImageLoad(entry.row.obj)"/>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</data-column>
|
</data-column>
|
||||||
<data-column key="email" class="full-width">
|
<data-column key="email" class="full-width">
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
@import 'theming';
|
||||||
|
|
||||||
|
:host {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activiti-label {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons.people-search__icon:hover {
|
||||||
|
color: mat-color($primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-element-user-list {
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text-header {
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0.54;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-container {
|
||||||
|
max-height: 152px;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
adf-people-list /deep/ adf-datatable /deep/ thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list-action-container {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
text-align: right;
|
||||||
|
padding: 5px 0px;
|
||||||
|
margin-top: 5px;
|
||||||
|
> button {
|
||||||
|
opacity: 0.54;
|
||||||
|
font-weight: bolder;
|
||||||
|
&:hover {
|
||||||
|
color: mat-color($primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adf-people-list /deep/ adf-datatable /deep/ .people-full-name {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
|
||||||
|
.people-pic {
|
||||||
|
background: mat-color($primary);
|
||||||
|
width: 30px;
|
||||||
|
padding: 10px 5px;
|
||||||
|
border-radius: 90%;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: Muli;
|
||||||
|
text-transform: uppercase;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.people-img {
|
||||||
|
border-radius: 90%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
adf-people-list /deep/ alfresco-datatable /deep/ td.mdl-data-table__cell--non-numeric.non-selectable.data-cell {
|
||||||
|
padding: 4px 12px;
|
||||||
|
}
|
@ -23,7 +23,7 @@ import { User } from '../models/user.model';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-people-search, activiti-people-search',
|
selector: 'adf-people-search, activiti-people-search',
|
||||||
templateUrl: './people-search.component.html',
|
templateUrl: './people-search.component.html',
|
||||||
styleUrls: ['./people-search.component.css']
|
styleUrls: ['./people-search.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class PeopleSearchComponent implements OnInit {
|
export class PeopleSearchComponent implements OnInit {
|
||||||
@ -104,4 +104,8 @@ export class PeopleSearchComponent implements OnInit {
|
|||||||
hasUsers() {
|
hasUsers() {
|
||||||
return (this.users && this.users.length > 0);
|
return (this.users && this.users.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onErrorImageLoad(user: User) {
|
||||||
|
user.userImage = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
.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: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-container{
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-list-container {
|
|
||||||
padding: 0px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> thead {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> .people-full-name {
|
|
||||||
font-family: 'Muli';
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> .people-email {
|
|
||||||
font-family: 'Muli';
|
|
||||||
opacity: 0.54;
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> .people-edit-label {
|
|
||||||
font-family: 'Muli';
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-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
|
|
||||||
}
|
|
||||||
|
|
||||||
adf-people-list >>> adf-datatable >>> td.mdl-data-table__cell--non-numeric.non-selectable.data-cell{
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
@ -28,7 +28,13 @@
|
|||||||
<data-columns>
|
<data-columns>
|
||||||
<data-column key="firstName">
|
<data-column key="firstName">
|
||||||
<ng-template let-entry="$implicit">
|
<ng-template let-entry="$implicit">
|
||||||
<div class="people-pic">{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
<div *ngIf="!entry.row.obj.userImage" class="people-pic">
|
||||||
|
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||||
|
<div>
|
||||||
|
<img *ngIf="entry.row.obj.userImage" class="people-img"
|
||||||
|
[src]="entry.row.obj.userImage"
|
||||||
|
(error)="onErrorImageLoad(entry.row.obj)"/>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</data-column>
|
</data-column>
|
||||||
<data-column key="email" class="full-width">
|
<data-column key="email" class="full-width">
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
@import 'theming';
|
||||||
|
|
||||||
|
.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;
|
||||||
|
&:hover {
|
||||||
|
color: mat-color($primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.assignment-top-container {
|
||||||
|
border-top: 2px solid #eee;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assignment-container {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assignment-list-container {
|
||||||
|
padding: 0px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
adf-people-list /deep/ adf-datatable /deep/ {
|
||||||
|
thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.people-full-name {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
.people-email {
|
||||||
|
font-family: 'Muli';
|
||||||
|
opacity: 0.54;
|
||||||
|
}
|
||||||
|
.people-edit-label {
|
||||||
|
font-family: 'Muli';
|
||||||
|
}
|
||||||
|
.people-pic {
|
||||||
|
background: mat-color($primary);
|
||||||
|
width: 30px;
|
||||||
|
padding: 10px 5px;
|
||||||
|
border-radius: 100px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: Muli;
|
||||||
|
text-transform: uppercase;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.people-img {
|
||||||
|
border-radius: 90%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
adf-people-list /deep/ adf-datatable /deep/ td.mdl-data-table__cell--non-numeric.non-selectable.data-cell {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
@ -192,7 +192,7 @@ describe('PeopleComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an empty list for not valid search', (done) => {
|
xit('should return an empty list for not valid search', (done) => {
|
||||||
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
|
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
|
||||||
expect(users.length).toBe(0);
|
expect(users.length).toBe(0);
|
||||||
done();
|
done();
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
import { LogService } from 'ng2-alfresco-core';
|
import { LogService } from 'ng2-alfresco-core';
|
||||||
import { Observable, Observer } from 'rxjs/Rx';
|
import { Observable, Observer } from 'rxjs/Rx';
|
||||||
import { UserEventModel } from '../models/user-event.model';
|
import { UserEventModel } from '../models/user-event.model';
|
||||||
@ -30,15 +30,15 @@ declare var require: any;
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-people, activiti-people',
|
selector: 'adf-people, activiti-people',
|
||||||
templateUrl: './people.component.html',
|
templateUrl: './people.component.html',
|
||||||
styleUrls: ['./people.component.css']
|
styleUrls: ['./people.component.scss']
|
||||||
})
|
})
|
||||||
export class PeopleComponent implements AfterViewInit {
|
export class PeopleComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
iconImageUrl: string = require('../assets/images/user.jpg');
|
iconImageUrl: string = require('../assets/images/user.jpg');
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
people: User [] = [];
|
people: User[] = [];
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
taskId: string = '';
|
taskId: string = '';
|
||||||
@ -64,6 +64,14 @@ export class PeopleComponent implements AfterViewInit {
|
|||||||
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
|
this.peopleSearch$ = new Observable<User[]>(observer => this.peopleSearchObserver = observer).share();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.people && this.people.length > 0) {
|
||||||
|
this.people.forEach((person) => {
|
||||||
|
person.userImage = this.peopleService.getUserImage(person);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.setupMaterialComponents(componentHandler);
|
this.setupMaterialComponents(componentHandler);
|
||||||
}
|
}
|
||||||
@ -91,17 +99,17 @@ export class PeopleComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
searchUser(searchedWord: string) {
|
searchUser(searchedWord: string) {
|
||||||
this.peopleService.getWorkflowUsers(this.taskId, searchedWord)
|
this.peopleService.getWorkflowUsersWithImages(this.taskId, searchedWord)
|
||||||
.subscribe((users) => {
|
.subscribe((users) => {
|
||||||
this.peopleSearchObserver.next(users);
|
this.peopleSearchObserver.next(users);
|
||||||
}, error => this.logService.error('Could not load users'));
|
}, error => this.logService.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
involveUser(user: User) {
|
involveUser(user: User) {
|
||||||
this.peopleService.involveUserWithTask(this.taskId, user.id.toString())
|
this.peopleService.involveUserWithTask(this.taskId, user.id.toString())
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.people = [...this.people, 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'));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeInvolvedUser(user: User) {
|
removeInvolvedUser(user: User) {
|
||||||
@ -110,7 +118,7 @@ export class PeopleComponent implements AfterViewInit {
|
|||||||
this.people = this.people.filter((involvedUser) => {
|
this.people = this.people.filter((involvedUser) => {
|
||||||
return involvedUser.id !== user.id;
|
return involvedUser.id !== user.id;
|
||||||
});
|
});
|
||||||
}, error => this.logService.error('Impossible to remove involved user from task'));
|
}, error => this.logService.error('Impossible to remove involved user from task'));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
||||||
@ -147,4 +155,7 @@ export class PeopleComponent implements AfterViewInit {
|
|||||||
this.showAssignment = false;
|
this.showAssignment = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onErrorImageLoad(user: User) {
|
||||||
|
user.userImage = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,14 @@ export class User {
|
|||||||
email: string;
|
email: string;
|
||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
|
userImage: string;
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(obj?: any) {
|
||||||
this.id = obj && obj.id;
|
if (obj) {
|
||||||
this.email = obj && obj.email || null;
|
this.id = obj.id;
|
||||||
this.firstName = obj && obj.firstName || null;
|
this.email = obj.email || null;
|
||||||
this.lastName = obj && obj.lastName || null;
|
this.firstName = obj.firstName || null;
|
||||||
|
this.lastName = obj.lastName || null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,38 @@ describe('PeopleService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to get people images for people retrieved', (done) => {
|
||||||
|
service.getWorkflowUsersWithImages('fake-task-id', 'fake-filter').subscribe(
|
||||||
|
(users: User[]) => {
|
||||||
|
expect(users).toBeDefined();
|
||||||
|
expect(users.length).toBe(2);
|
||||||
|
expect(users[0].userImage).toContain('/app/rest/users/' + users[0].id + '/picture');
|
||||||
|
expect(users[1].userImage).toContain('/app/rest/users/' + users[1].id + '/picture');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
contentType: 'json',
|
||||||
|
responseText: {data: fakeInvolveUserList}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to return user with image url', (done) => {
|
||||||
|
service.addImageToUser(firstInvolvedUser).subscribe(
|
||||||
|
(user: User) => {
|
||||||
|
expect(user).toBeDefined();
|
||||||
|
expect(user.userImage).toContain('/app/rest/users/' + user.id + '/picture');
|
||||||
|
expect(user.id).toBe('1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return user image url', () => {
|
||||||
|
let url = service.getUserImage(firstInvolvedUser);
|
||||||
|
|
||||||
|
expect(url).toContain('/app/rest/users/' + firstInvolvedUser.id + '/picture');
|
||||||
|
});
|
||||||
|
|
||||||
it('should return empty list when there are no users to involve', (done) => {
|
it('should return empty list when there are no users to involve', (done) => {
|
||||||
service.getWorkflowUsers('fake-task-id', 'fake-filter').subscribe(
|
service.getWorkflowUsers('fake-task-id', 'fake-filter').subscribe(
|
||||||
(users: User[]) => {
|
(users: User[]) => {
|
||||||
|
@ -29,12 +29,30 @@ export class PeopleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getWorkflowUsers(taskId?: string, searchWord?: string): Observable<User[]> {
|
getWorkflowUsers(taskId?: string, searchWord?: string): Observable<User[]> {
|
||||||
let option = {excludeTaskId: taskId, filter: searchWord};
|
let option = { excludeTaskId: taskId, filter: searchWord };
|
||||||
return Observable.fromPromise(this.getWorkflowUserApi(option))
|
return Observable.fromPromise(this.getWorkflowUserApi(option))
|
||||||
.map((response: any) => <User[]> response.data || [])
|
.map((response: any) => <User[]> response.data || [])
|
||||||
.catch(err => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWorkflowUsersWithImages(taskId?: string, searchWord?: string): Observable<User[]> {
|
||||||
|
let option = { excludeTaskId: taskId, filter: searchWord };
|
||||||
|
return Observable.fromPromise(this.getWorkflowUserApi(option))
|
||||||
|
.switchMap((response: any) => <User[]> response.data || [])
|
||||||
|
.map((user: User) => this.addImageToUser(user))
|
||||||
|
.combineAll()
|
||||||
|
.catch(err => this.handleError(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserImage(user: User): string {
|
||||||
|
return this.getUserProfileImageApi(user.id + '');
|
||||||
|
}
|
||||||
|
|
||||||
|
addImageToUser(user: User): Observable<User> {
|
||||||
|
user.userImage = this.getUserImage(user);
|
||||||
|
return Observable.of(user);
|
||||||
|
}
|
||||||
|
|
||||||
involveUserWithTask(taskId: string, idToInvolve: string): Observable<User[]> {
|
involveUserWithTask(taskId: string, idToInvolve: string): Observable<User[]> {
|
||||||
let node = {userId: idToInvolve};
|
let node = {userId: idToInvolve};
|
||||||
return Observable.fromPromise(this.involveUserToTaskApi(taskId, node))
|
return Observable.fromPromise(this.involveUserToTaskApi(taskId, node))
|
||||||
@ -59,6 +77,10 @@ export class PeopleService {
|
|||||||
return this.alfrescoJsApi.getInstance().activiti.taskActionsApi.removeInvolvedUser(taskId, node);
|
return this.alfrescoJsApi.getInstance().activiti.taskActionsApi.removeInvolvedUser(taskId, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getUserProfileImageApi(userId: string) {
|
||||||
|
return this.alfrescoJsApi.getInstance().activiti.userApi.getUserProfilePictureUrl(userId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw the error
|
* Throw the error
|
||||||
* @param error
|
* @param error
|
||||||
|
Loading…
x
Reference in New Issue
Block a user