diff --git a/docs/user-info.component.md b/docs/user-info.component.md index 07e4158624..c8d72132b5 100644 --- a/docs/user-info.component.md +++ b/docs/user-info.component.md @@ -26,7 +26,8 @@ | bpmBackgroundImage | string | (alfresco image) | Custom path for the background banner image for BPM users | | menuPositionX | string | | Custom choice for opening the menu bottom : `before` or `after` | | menuPositionY | string | | Custom choice for opening the menu bottom : `above` or `below` | -| fallBackThumbnailImage | string | (alfresco image) | Fallback image for profile when thumbnail is missing| +| namePosition | string | `right` | When the username is showed this define his position relatively the user info button. It can be two values : `right` or `left`| +| showName | boolean | true | Show/Hide the username next the user info button| ## Details diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.html index f9b3859a13..d2e0795558 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.html @@ -19,9 +19,7 @@
-
- {{getInitialUserName(user.firstName, user.lastName)}} -
+
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.scss b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.scss index 679af7d309..90220b02a3 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.scss +++ b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.scss @@ -28,7 +28,7 @@ } &-people-widget-image { - margin-left: -45px; + margin-left: -44px; left: 21px; background: mat-color($background, dialog); border-radius: 100px; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.ts index 217adb1a0e..3a5e7a0995 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/people/people.widget.ts @@ -116,16 +116,4 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit { this.field.value = item; } } - - getInitialUserName(firstName: string, lastName: string) { - firstName = (firstName !== null && firstName !== '' ? firstName[0] : ''); - lastName = (lastName !== null && lastName !== '' ? lastName[0] : ''); - return this.getDisplayUser(firstName, lastName, ''); - } - - getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string { - firstName = (firstName !== null ? firstName : ''); - lastName = (lastName !== null ? lastName : ''); - return firstName + delimiter + lastName; - } } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/people.component.html b/ng2-components/ng2-activiti-tasklist/src/components/people.component.html index 4c96e96296..69aa1c2c4a 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/people.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/people.component.html @@ -29,7 +29,7 @@ -
+
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}
{ + + let pipe: InitialUsernamePipe; + let fakeUser: LightUserRepresentation; + + beforeEach(() => { + pipe = new InitialUsernamePipe(new FakeSanitazer()); + fakeUser = new LightUserRepresentation(); + }); + + it('should return a div with the user initials', () => { + fakeUser.firstName = 'FAKE-NAME'; + fakeUser.lastName = 'FAKE-SURNAME'; + let result = pipe.transform(fakeUser); + expect(result).toBe('
FF
'); + }); + + it('should apply the style class passed in input', () => { + fakeUser.firstName = 'FAKE-NAME'; + fakeUser.lastName = 'FAKE-SURNAME'; + let result = pipe.transform(fakeUser, 'fake-class-to-check'); + expect(result).toBe('
FF
'); + }); + + it('should return a single letter into div when lastname is undefined', () => { + fakeUser.firstName = 'FAKE-NAME'; + fakeUser.lastName = undefined; + let result = pipe.transform(fakeUser); + expect(result).toBe('
F
'); + }); + + it('should return a single letter into div when firstname is null', () => { + fakeUser.firstName = undefined; + fakeUser.lastName = 'FAKE-SURNAME'; + let result = pipe.transform(fakeUser); + expect(result).toBe('
F
'); + }); + + it('should return an empty string when user is null', () => { + let result = pipe.transform(null); + expect(result).toBe(''); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/pipes/user-initial.pipe.ts b/ng2-components/ng2-alfresco-core/src/pipes/user-initial.pipe.ts new file mode 100644 index 0000000000..9ee5a8ce65 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/pipes/user-initial.pipe.ts @@ -0,0 +1,43 @@ +/*! + * @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 { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { LightUserRepresentation } from '../models/user-process.model'; + +@Pipe({ + name: 'usernameInitials' +}) +export class InitialUsernamePipe implements PipeTransform { + + constructor(private sanitized: DomSanitizer) {} + + transform(user: LightUserRepresentation, className: string = '', delimiter: string = ''): SafeHtml { + let result: SafeHtml = ''; + if (user) { + let initialResult = this.getInitialUserName(user.firstName, user.lastName, delimiter); + result = this.sanitized.bypassSecurityTrustHtml(`
${initialResult}
`); + } + return result; + } + + getInitialUserName(firstName: string, lastName: string, delimiter: string) { + firstName = (firstName ? firstName[0] : ''); + lastName = (lastName ? lastName[0] : ''); + return firstName + delimiter + lastName; + } +} diff --git a/ng2-components/ng2-alfresco-userinfo/README.md b/ng2-components/ng2-alfresco-userinfo/README.md index 8392661557..a04af8bcb7 100644 --- a/ng2-components/ng2-alfresco-userinfo/README.md +++ b/ng2-components/ng2-alfresco-userinfo/README.md @@ -20,7 +20,7 @@ Contains the Alfresco User Info component. ## Documentation -See the [ADF Analytics](../../docs/README.md#adf-analytics) section of the [docs index](../../docs/README.md) +See the [ADF Userinfo](../../docs/README.md#adf-userinfo) section of the [docs index](../../docs/README.md) for all available documentation on this library. ## Prerequisites diff --git a/ng2-components/ng2-alfresco-userinfo/src/assets/fake-bpm-user.service.mock.ts b/ng2-components/ng2-alfresco-userinfo/src/assets/fake-bpm-user.service.mock.ts index 4278c09d51..7005c09b16 100644 --- a/ng2-components/ng2-alfresco-userinfo/src/assets/fake-bpm-user.service.mock.ts +++ b/ng2-components/ng2-alfresco-userinfo/src/assets/fake-bpm-user.service.mock.ts @@ -57,7 +57,7 @@ export let fakeBpmUser = { lastUpdate: 'fake-update-date', latestSyncTimeStamp: 'fake-timestamp', password: 'fake-password', - pictureId: 'src/assets/bpmImg.gif', + pictureId: 12, status: 'fake-status', tenantId: 'fake-tenant-id', tenantName: 'fake-tenant-name', diff --git a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.html b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.html index e070cd719e..4f50094feb 100644 --- a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.html +++ b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.html @@ -1,9 +1,26 @@ -
+
+ {{ecmUser.fullNameDisplay}} + {{bpmUser.fullNameDisplay}} @@ -12,11 +29,11 @@ - ecm-profile-image +
+
+ ecm-profile-image +
{{ecmUser.fullNameDisplay}}
@@ -38,11 +55,9 @@ - bpm-profile-image +
+ bpm-profile-image
{{bpmUser.fullNameDisplay}}
diff --git a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.scss b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.scss index 384605aecb..12492c210f 100644 --- a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.scss +++ b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.scss @@ -2,9 +2,38 @@ $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); + $foreground: map-get($theme, foreground); .adf { + &-userinfo-container { + display: flex; + align-items: center; + padding: 0 5px 0 5px; + } + + &-userinfo-name-right { + flex-direction: row-reverse; + } + + &-userinfo-name { + padding: 0 5px 0 5px; + } + + &-userinfo-pic { + background: mat-color($primary, 300); + display: inline-block; + width: 40px; + height: 40px; + border-radius: 100px; + text-align: center; + font-weight: bolder; + font-size: 18px; + text-transform: uppercase; + vertical-align: middle; + line-height: 40px + } + &-userinfo-profile-image { text-align: center; border-radius: 90%; @@ -13,6 +42,11 @@ margin-right: 0; cursor: pointer; vertical-align: middle; + margin-left: -45px; + } + + &-userinfo-profile-container{ + display: inline-block; } &-userinfo-menu_button.mat-button { @@ -101,9 +135,25 @@ border-radius: 50%; height: 80px; width: 80px; - z-index: 3; + margin-left: -88px; + margin-right: 8px; + } + + &-userinfo-profile-initials { + background-size: cover; + background: mat-color($primary, 300); + border-radius: 50%; + height: 80px; + width: 80px; margin-left: 0; margin-right: 8px; + font-size: 35px; + font-weight: 400; + letter-spacing: 0; + line-height: 78px; + overflow: hidden; + display: flex; + justify-content: space-around; } &-userinfo-button-profile { diff --git a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.spec.ts b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.spec.ts index 71f4f8f6fa..bcdd0a7939 100644 --- a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.spec.ts +++ b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.spec.ts @@ -81,17 +81,6 @@ describe('User info component', () => { expect(element.querySelector('#user-profile-lists')).toBeNull(); }); - it('should return the anonymous avatar when users do not have images', () => { - let event = { - target: { - src: '' - } - }; - userInfoComp.onImageLoadingError(event); - expect(event.target.src).toContain('assets/images/anonymous'); - expect(event.target.src).toContain('.gif'); - }); - describe('when user is logged on ecm', () => { beforeEach(() => { @@ -113,6 +102,7 @@ describe('User info component', () => { }); fixture.whenStable().then(() => { + fixture.detectChanges(); let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); imageButton.click(); fixture.detectChanges(); @@ -125,6 +115,65 @@ describe('User info component', () => { }); })); + it('should show the username when showName attribute is true', async(() => { + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'application/json', + responseText: JSON.stringify({entry: fakeEcmEditedUser}) + }); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(userInfoComp.showName).toBeTruthy(); + expect(element.querySelector('#adf-userinfo-ecm-name-display')).not.toBeNull(); + }); + })); + + it('should hide the username when showName attribute is false', async(() => { + userInfoComp.showName = false; + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'application/json', + responseText: JSON.stringify({entry: fakeEcmEditedUser}) + }); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(element.querySelector('#adf-userinfo-ecm-name-display')).toBeNull(); + }); + })); + + it('should have the defined class to show the name on the right side', async(() => { + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'application/json', + responseText: JSON.stringify({entry: fakeEcmEditedUser}) + }); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(element.querySelector('#userinfo_container').classList).toContain('adf-userinfo-name-right'); + }); + })); + + it('should not have the defined class to show the name on the left side', async(() => { + userInfoComp.namePosition = 'left'; + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'application/json', + responseText: JSON.stringify({entry: fakeEcmEditedUser}) + }); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(element.querySelector('#userinfo_container').classList).not.toContain('adf-userinfo-name-right'); + }); + })); + describe('and has image', () => { beforeEach(async(() => { @@ -139,6 +188,7 @@ describe('User info component', () => { it('should get the ecm current user image from the service', async(() => { fixture.whenStable().then(() => { + fixture.detectChanges(); let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); imageButton.click(); fixture.detectChanges(); @@ -152,6 +202,7 @@ describe('User info component', () => { it('should get the ecm user informations from the service', () => { fixture.whenStable().then(() => { + fixture.detectChanges(); let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); imageButton.click(); fixture.detectChanges(); @@ -172,17 +223,17 @@ describe('User info component', () => { describe('and has no image', () => { beforeEach(async(() => { - userInfoComp.anonymousImageUrl = userInfoComp.anonymousImageUrl.replace('/base/dist', ''); fixture.detectChanges(); jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'application/json', responseText: JSON.stringify({entry: fakeEcmUserNoImage}) }); + fixture.whenStable().then(() => fixture.detectChanges()); })); it('should show N/A when the job title is null', async(() => { - let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); + let imageButton: HTMLButtonElement = element.querySelector('#user-initials-image'); imageButton.click(); fixture.detectChanges(); expect(element.querySelector('#userinfo_container')).not.toBeNull(); @@ -193,7 +244,7 @@ describe('User info component', () => { })); it('should not show the tabs', () => { - let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); + let imageButton: HTMLButtonElement = element.querySelector('#user-initials-image'); imageButton.click(); fixture.detectChanges(); let tabHeader = fixture.debugElement.query(By.css('#tab-group-env')); @@ -209,8 +260,6 @@ describe('User info component', () => { spyOn(stubAuthService, 'isBpmLoggedIn').and.returnValue(true); spyOn(stubAuthService, 'isLoggedIn').and.returnValue(true); jasmine.Ajax.install(); - - userInfoComp.anonymousImageUrl = userInfoComp.anonymousImageUrl.replace('/base/dist', ''); })); afterEach(() => { @@ -226,6 +275,7 @@ describe('User info component', () => { }); fixture.whenStable().then(() => { + fixture.detectChanges(); let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); imageButton.click(); fixture.detectChanges(); @@ -323,7 +373,6 @@ describe('User info component', () => { spyOn(stubAuthService, 'isBpmLoggedIn').and.returnValue(true); spyOn(stubAuthService, 'isLoggedIn').and.returnValue(true); spyOn(stubContent, 'getContentUrl').and.returnValue('src/assets/images/ecmImg.gif'); - userInfoComp.anonymousImageUrl = userInfoComp.anonymousImageUrl.replace('/base/dist', ''); jasmine.Ajax.install(); })); @@ -342,6 +391,7 @@ describe('User info component', () => { })); beforeEach(() => { + fixture.detectChanges(); let imageButton: HTMLButtonElement = element.querySelector('#logged-user-img'); imageButton.click(); fixture.detectChanges(); @@ -387,9 +437,12 @@ describe('User info component', () => { it('should show the bpm image if ecm does not have it', () => { userInfoComp.ecmUserImage = null; fixture.detectChanges(); - expect(element.querySelector('#userinfo_container')).toBeDefined(); - expect(element.querySelector('#logged-user-img')).toBeDefined(); - expect(element.querySelector('#logged-user-img').getAttribute('src')).toContain('rest/admin/profile-picture'); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(element.querySelector('#userinfo_container')).toBeDefined(); + expect(element.querySelector('#logged-user-img')).toBeDefined(); + expect(element.querySelector('#logged-user-img').getAttribute('src')).toContain('rest/admin/profile-picture'); + }); }); it('should show the tabs for the env', () => { diff --git a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.ts b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.ts index 5a28d05463..ea51f8ae8e 100644 --- a/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.ts +++ b/ng2-components/ng2-alfresco-userinfo/src/components/user-info.component.ts @@ -45,7 +45,10 @@ export class UserInfoComponent implements OnInit { menuPositionY: string = 'below'; @Input() - fallBackThumbnailImage: string; + showName: boolean = true; + + @Input() + namePosition: string = 'right'; ecmUser: EcmUserModel; bpmUser: BpmUserModel; @@ -78,9 +81,9 @@ export class UserInfoComponent implements OnInit { if (this.authService.isEcmLoggedIn()) { this.ecmUserService.getCurrentUserInfo() .subscribe((res) => { - this.ecmUser = new EcmUserModel(res); - this.getEcmAvatar(); - } + this.ecmUser = new EcmUserModel(res); + this.getEcmAvatar(); + } ); } else { this.ecmUser = null; @@ -101,13 +104,6 @@ export class UserInfoComponent implements OnInit { } } - onImageLoadingError(event) { - if (event) { - let element = event.target; - element.src = this.fallBackThumbnailImage || this.anonymousImageUrl; - } - } - stopClosing(event) { event.stopPropagation(); } @@ -116,15 +112,7 @@ export class UserInfoComponent implements OnInit { this.ecmUserImage = this.ecmUserService.getUserProfileImage(this.ecmUser.avatarId); } - getUserAvatar() { - return this.ecmUserImage || this.bpmUserImage; - } - - getBpmUserAvatar() { - return this.bpmUserImage; - } - - getEcmUserAvatar() { - return this.ecmUserImage; + showOnRight() { + return this.namePosition === 'right'; } }