mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-10779] User info component refactor (#8187)
* [AAE-10779] Update documentation * [AAE-10779] Update demo-shell user-info component call * [AAE-10779] Ecm user info component * [AAE-10779] Identity user info component * [AAE-10779] Bpm user info component * [AAE-10779] Remove ecm-panel id references * [AAE-10779] add stories and remove old component * [AAE-10779] Update doc version and remove leftover html tag * trigger travis * [AAE-10779] rename ecm-user-info to content-user-info and bpm-user-info to process-user-info * [AAE-10779] update docs * [AAE-10779] fix demo-shell user-info * [AAE-10779] add docs
This commit is contained in:
@@ -115,6 +115,7 @@ import localeSv from '@angular/common/locales/sv';
|
|||||||
import { setupAppNotifications } from './services/app-notifications-factory';
|
import { setupAppNotifications } from './services/app-notifications-factory';
|
||||||
import { AppNotificationsService } from './services/app-notifications.service';
|
import { AppNotificationsService } from './services/app-notifications.service';
|
||||||
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
||||||
|
import { UserInfoComponent } from './components/app-layout/user-info/user-info.component';
|
||||||
|
|
||||||
registerLocaleData(localeFr);
|
registerLocaleData(localeFr);
|
||||||
registerLocaleData(localeDe);
|
registerLocaleData(localeDe);
|
||||||
@@ -159,6 +160,7 @@ registerLocaleData(localeSv);
|
|||||||
AppComponent,
|
AppComponent,
|
||||||
LogoutComponent,
|
LogoutComponent,
|
||||||
AppLayoutComponent,
|
AppLayoutComponent,
|
||||||
|
UserInfoComponent,
|
||||||
HomeComponent,
|
HomeComponent,
|
||||||
SearchBarComponent,
|
SearchBarComponent,
|
||||||
SearchResultComponent,
|
SearchResultComponent,
|
||||||
|
@@ -22,8 +22,7 @@
|
|||||||
|
|
||||||
<div class="app-header-delimiexpandedSidenavter"></div>
|
<div class="app-header-delimiexpandedSidenavter"></div>
|
||||||
|
|
||||||
<adf-userinfo [menuPositionX]="'before'" [menuPositionY]="'above'">
|
<app-shell-user-info [menuPositionX]="'before'" [menuPositionY]="'above'"></app-shell-user-info>
|
||||||
</adf-userinfo>
|
|
||||||
|
|
||||||
<app-theme-picker></app-theme-picker>
|
<app-theme-picker></app-theme-picker>
|
||||||
<button data-automation-id="language-menu-button" mat-icon-button [matMenuTriggerFor]="langMenu">
|
<button data-automation-id="language-menu-button" mat-icon-button [matMenuTriggerFor]="langMenu">
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
<ng-container>
|
||||||
|
<adf-content-user-info
|
||||||
|
*ngIf="mode === userInfoMode.CONTENT || mode === userInfoMode.CONTENT_SSO"
|
||||||
|
[ecmUser]="ecmUser$ | async"
|
||||||
|
[identityUser]="identityUser$ | async"
|
||||||
|
[isLoggedIn]="isLoggedIn"
|
||||||
|
[mode]="mode"
|
||||||
|
></adf-content-user-info>
|
||||||
|
<adf-identity-user-info
|
||||||
|
*ngIf="mode === userInfoMode.SSO"
|
||||||
|
[identityUser]="identityUser$ | async"
|
||||||
|
[isLoggedIn]="isLoggedIn"
|
||||||
|
></adf-identity-user-info>
|
||||||
|
<adf-process-user-info
|
||||||
|
*ngIf="mode === userInfoMode.PROCESS || mode === userInfoMode.ALL"
|
||||||
|
[bpmUser]="bpmUser$ | async"
|
||||||
|
[ecmUser]="ecmUser$ | async"
|
||||||
|
[isLoggedIn]="isLoggedIn"
|
||||||
|
[mode]="mode"
|
||||||
|
></adf-process-user-info>
|
||||||
|
</ng-container>
|
@@ -15,34 +15,16 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
|
import { AuthenticationService, BpmUserModel, BpmUserService, EcmUserModel, IdentityUserModel, IdentityUserService, PeopleContentService, UserInfoMode } from '@alfresco/adf-core';
|
||||||
import { AuthenticationService } from '../../auth/services/authentication.service';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { BpmUserModel } from '../../models/bpm-user.model';
|
import { MenuPositionX, MenuPositionY } from '@angular/material/menu';
|
||||||
import { EcmUserModel } from '../../models/ecm-user.model';
|
import { Observable, of } from 'rxjs';
|
||||||
import { IdentityUserModel } from '../../auth/models/identity-user.model';
|
|
||||||
import { BpmUserService } from '../../services/bpm-user.service';
|
|
||||||
import { IdentityUserService } from '../../auth/services/identity-user.service';
|
|
||||||
import { of, Observable, Subject } from 'rxjs';
|
|
||||||
import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
|
|
||||||
import { PeopleContentService } from '../../services/people-content.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-userinfo',
|
selector: 'app-shell-user-info',
|
||||||
templateUrl: './user-info.component.html',
|
templateUrl: './user-info.component.html'
|
||||||
styleUrls: ['./user-info.component.scss'],
|
|
||||||
encapsulation: ViewEncapsulation.None
|
|
||||||
})
|
})
|
||||||
export class UserInfoComponent implements OnInit, OnDestroy {
|
export class UserInfoComponent implements OnInit {
|
||||||
|
|
||||||
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
|
||||||
|
|
||||||
/** Custom path for the background banner image for ACS users. */
|
|
||||||
@Input()
|
|
||||||
ecmBackgroundImage: string = './assets/images/ecm-background.png';
|
|
||||||
|
|
||||||
/** Custom path for the background banner image for APS users. */
|
|
||||||
@Input()
|
|
||||||
bpmBackgroundImage: string = './assets/images/bpm-background.png';
|
|
||||||
|
|
||||||
/** Custom choice for opening the menu at the bottom. Can be `before` or `after`. */
|
/** Custom choice for opening the menu at the bottom. Can be `before` or `after`. */
|
||||||
@Input()
|
@Input()
|
||||||
@@ -52,23 +34,12 @@ export class UserInfoComponent implements OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
menuPositionY: MenuPositionY = 'below';
|
menuPositionY: MenuPositionY = 'below';
|
||||||
|
|
||||||
/** Shows/hides the username next to the user info button. */
|
mode: UserInfoMode;
|
||||||
@Input()
|
|
||||||
showName: boolean = true;
|
|
||||||
|
|
||||||
/** When the username is shown, this defines its position relative to the user info button.
|
|
||||||
* Can be `right` or `left`.
|
|
||||||
*/
|
|
||||||
@Input()
|
|
||||||
namePosition: string = 'right';
|
|
||||||
|
|
||||||
mode: string;
|
|
||||||
|
|
||||||
ecmUser$: Observable<EcmUserModel>;
|
ecmUser$: Observable<EcmUserModel>;
|
||||||
bpmUser$: Observable<BpmUserModel>;
|
bpmUser$: Observable<BpmUserModel>;
|
||||||
identityUser$: Observable<IdentityUserModel>;
|
identityUser$: Observable<IdentityUserModel>;
|
||||||
selectedIndex: number;
|
selectedIndex: number;
|
||||||
private destroy$ = new Subject();
|
userInfoMode = UserInfoMode;
|
||||||
|
|
||||||
constructor(private peopleContentService: PeopleContentService,
|
constructor(private peopleContentService: PeopleContentService,
|
||||||
private bpmUserService: BpmUserService,
|
private bpmUserService: BpmUserService,
|
||||||
@@ -80,40 +51,26 @@ export class UserInfoComponent implements OnInit, OnDestroy {
|
|||||||
this.getUserInfo();
|
this.getUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.destroy$.next(true);
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserInfo() {
|
getUserInfo() {
|
||||||
if (this.authService.isOauth()) {
|
if (this.authService.isOauth()) {
|
||||||
this.loadIdentityUserInfo();
|
this.loadIdentityUserInfo();
|
||||||
this.mode = 'SSO';
|
this.mode = UserInfoMode.SSO;
|
||||||
|
|
||||||
if (this.authService.isECMProvider() && this.authService.isEcmLoggedIn()) {
|
if (this.authService.isECMProvider() && this.authService.isEcmLoggedIn()) {
|
||||||
|
this.mode = UserInfoMode.CONTENT_SSO;
|
||||||
this.loadEcmUserInfo();
|
this.loadEcmUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this.isAllLoggedIn()) {
|
} else if (this.isAllLoggedIn()) {
|
||||||
this.loadEcmUserInfo();
|
this.loadEcmUserInfo();
|
||||||
this.loadBpmUserInfo();
|
this.loadBpmUserInfo();
|
||||||
this.mode = 'ALL';
|
this.mode = UserInfoMode.ALL;
|
||||||
} else if (this.isEcmLoggedIn()) {
|
} else if (this.isEcmLoggedIn()) {
|
||||||
this.loadEcmUserInfo();
|
this.loadEcmUserInfo();
|
||||||
this.mode = 'CONTENT';
|
this.mode = UserInfoMode.CONTENT;
|
||||||
} else if (this.isBpmLoggedIn()) {
|
} else if (this.isBpmLoggedIn()) {
|
||||||
this.loadBpmUserInfo();
|
this.loadBpmUserInfo();
|
||||||
this.mode = 'PROCESS';
|
this.mode = UserInfoMode.PROCESS;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyPress(event: KeyboardEvent) {
|
|
||||||
this.closeUserModal(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeUserModal($event: KeyboardEvent) {
|
|
||||||
if ($event.keyCode === 27) {
|
|
||||||
this.trigger.closeMenu();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,20 +104,5 @@ export class UserInfoComponent implements OnInit, OnDestroy {
|
|||||||
private isEcmLoggedIn() {
|
private isEcmLoggedIn() {
|
||||||
return this.authService.isEcmLoggedIn() || (this.authService.isECMProvider() && this.authService.isKerberosEnabled());
|
return this.authService.isEcmLoggedIn() || (this.authService.isECMProvider() && this.authService.isKerberosEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
stopClosing(event: Event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
getEcmAvatar(avatarId: any): string {
|
|
||||||
return this.peopleContentService.getUserProfileImage(avatarId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBpmUserImage(): string {
|
|
||||||
return this.bpmUserService.getCurrentUserProfileImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
get showOnRight(): boolean {
|
|
||||||
return this.namePosition === 'right';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
Title: Content User Info component
|
||||||
|
Added: v6.0.0
|
||||||
|
Status: Active
|
||||||
|
Last reviewed: 2023-01-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# [Content User Info component](../../../lib/content-services/src/lib/content-user-info/content-user-info.component.ts "Defined in content-user-info.component.ts")
|
||||||
|
|
||||||
|
Shows user information for `CONTENT` and `CONTENT_SSO` mode.
|
||||||
|
|
||||||
|
## Basic usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-content-user-info></adf-content-user-info>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class members
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Default value | Description |
|
||||||
|
| ---- | ---- | ------------- | ----------- |
|
||||||
|
| isLoggedIn | `boolean` | Is user logged in |
|
||||||
|
| EcmUser | `EcmUserModel` | Ecm user model. |
|
||||||
|
| identityUser | `IdentityUserModel` | Identity user model. |
|
||||||
|
| mode | `UserInfoMode` | `UserInfoMode.CONTENT` | current mode. |
|
||||||
|
| bpmBackgroundImage | `string` | | Custom path for the background banner image for APS users. |
|
||||||
|
| EcmBackgroundImage | `string` | | Custom path for the background banner image for ACS users. |
|
||||||
|
| menuPositionX | [`MenuPositionX`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
||||||
|
| menuPositionY | [`MenuPositionY`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "below" | Custom choice for opening the menu at the bottom. Can be `above` or `below`. |
|
||||||
|
| namePosition | `string` | "right" | When the username is shown, this defines its position relative to the user info button. Can be `right` or `left`. |
|
||||||
|
| showName | `boolean` | true | Shows/hides the username next to the user info button. |
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
The component shows a round icon for the user and will show extra information about
|
||||||
|
the user when clicked.
|
@@ -1,18 +1,18 @@
|
|||||||
---
|
---
|
||||||
Title: User Info component
|
Title: Identity User Info component
|
||||||
Added: v2.0.0
|
Added: v6.0.0
|
||||||
Status: Active
|
Status: Active
|
||||||
Last reviewed: 2018-11-19
|
Last reviewed: 2023-01-24
|
||||||
---
|
---
|
||||||
|
|
||||||
# [User Info component](../../../lib/core/src/lib/userinfo/components/user-info.component.ts "Defined in user-info.component.ts")
|
# [Identity User Info component](../../../lib/core/src/lib/identity-user-info/identity-user-info.component.ts "Defined in identityuser-info.component.ts")
|
||||||
|
|
||||||
Shows user information.
|
Shows user information for SSO mode.
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<adf-userinfo></adf-userinfo>
|
<adf-identity-user-info></adf-identity-user-info>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Class members
|
## Class members
|
||||||
@@ -21,6 +21,8 @@ Shows user information.
|
|||||||
|
|
||||||
| Name | Type | Default value | Description |
|
| Name | Type | Default value | Description |
|
||||||
| ---- | ---- | ------------- | ----------- |
|
| ---- | ---- | ------------- | ----------- |
|
||||||
|
| isLoggedIn | `boolean` | Is user logged in |
|
||||||
|
| identityUser | `IdentityUserModel` | Identity user model. |
|
||||||
| bpmBackgroundImage | `string` | | Custom path for the background banner image for APS users. |
|
| bpmBackgroundImage | `string` | | Custom path for the background banner image for APS users. |
|
||||||
| ecmBackgroundImage | `string` | | Custom path for the background banner image for ACS users. |
|
| ecmBackgroundImage | `string` | | Custom path for the background banner image for ACS users. |
|
||||||
| menuPositionX | [`MenuPositionX`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
| menuPositionX | [`MenuPositionX`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
||||||
@@ -32,5 +34,3 @@ Shows user information.
|
|||||||
|
|
||||||
The component shows a round icon for the user and will show extra information about
|
The component shows a round icon for the user and will show extra information about
|
||||||
the user when clicked.
|
the user when clicked.
|
||||||
If user is logged in with both ACS and APS, the ACS image will be shown.
|
|
||||||
In case of SSO authentication, the information related to the user like firstname, lastname will be fetched using the Keycloak [`Api`](../../../lib/testing/src/lib/core/structure/api.ts)
|
|
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
Title: Process User Info component
|
||||||
|
Added: v6.0.0
|
||||||
|
Status: Active
|
||||||
|
Last reviewed: 2023-01-24
|
||||||
|
---
|
||||||
|
|
||||||
|
# [Process User Info component](../../../lib/process-services/src/lib/process-user-info/process-user-info.component.ts "Defined in process-user-info.component.ts")
|
||||||
|
|
||||||
|
Shows user information for `PROCESS` and `ALL` mode.
|
||||||
|
|
||||||
|
## Basic usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-process-user-info></adf-process-user-info>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class members
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Default value | Description |
|
||||||
|
| ---- | ---- | ------------- | ----------- |
|
||||||
|
| isLoggedIn | `boolean` | Is user logged in |
|
||||||
|
| bpmUser | `BpmUserModel` | Bpm user model. |
|
||||||
|
| ecmUser | `EpmUserModel` | Ecm user model. |
|
||||||
|
| mode | `UserInfoMode` | `UserInfoMode.PROCESS` | current mode. |
|
||||||
|
| bpmBackgroundImage | `string` | | Custom path for the background banner image for APS users. |
|
||||||
|
| BpmBackgroundImage | `string` | | Custom path for the background banner image for ACS users. |
|
||||||
|
| menuPositionX | [`MenuPositionX`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
||||||
|
| menuPositionY | [`MenuPositionY`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "below" | Custom choice for opening the menu at the bottom. Can be `above` or `below`. |
|
||||||
|
| namePosition | `string` | "right" | When the username is shown, this defines its position relative to the user info button. Can be `right` or `left`. |
|
||||||
|
| showName | `boolean` | true | Shows/hides the username next to the user info button. |
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
The component shows a round icon for the user and will show extra information about
|
||||||
|
the user when clicked.
|
@@ -86,6 +86,7 @@ How to fix it:
|
|||||||
| Class | Before | After |
|
| Class | Before | After |
|
||||||
| --- | -- | --- |
|
| --- | -- | --- |
|
||||||
| `LoginDialogService` | `@alfresco/adf-core`|
|
| `LoginDialogService` | `@alfresco/adf-core`|
|
||||||
|
| `UserInfoComponent` | `@alfresco/adf-core`|
|
||||||
|
|
||||||
### DataColumnModule
|
### DataColumnModule
|
||||||
|
|
||||||
@@ -225,6 +226,16 @@ The ```adf-comments``` has now two specialization in :
|
|||||||
From v.6.0.0 and after [`ViewerComponent`](../../docs/core/components/viewer.component.md) no longer show content from ACS, so instead of taking `nodeId` as `@Input`, it takes `blobFile` and `urlFile`. For more details check the [`PR`](https://github.com/Alfresco/alfresco-ng2-components/pull/7992).
|
From v.6.0.0 and after [`ViewerComponent`](../../docs/core/components/viewer.component.md) no longer show content from ACS, so instead of taking `nodeId` as `@Input`, it takes `blobFile` and `urlFile`. For more details check the [`PR`](https://github.com/Alfresco/alfresco-ng2-components/pull/7992).
|
||||||
If you need to display content from ACS you can use instead the new [`AlfrescoViewerComponent`](../../docs/content-services/components/alfresco-viewer.component.md)
|
If you need to display content from ACS you can use instead the new [`AlfrescoViewerComponent`](../../docs/content-services/components/alfresco-viewer.component.md)
|
||||||
|
|
||||||
|
### UserInfoComponent
|
||||||
|
From v.6.0.0 and after ```UserInfoComponent``` is no longer active.
|
||||||
|
|
||||||
|
In its place there are now 3 presentational components:
|
||||||
|
- [`IdentityUserInfoComponent`](../../docs/core/components/identity-user-info.component.md) present in core
|
||||||
|
- [`ContentUserInfoComponent`](../../docs/content-services/components/content-user-info.component.md) present in content-services
|
||||||
|
- [`ProcessUserInfoComponent`](../../docs/process-services/components/process-user-info.component.md) present in process-services
|
||||||
|
|
||||||
|
To build a similar logic to the one in ```UserInfoComponent``` check implementation on [`demo-shell`](../../demo-shell/src/app/components/app-layout/user-info/user-info.component.ts)
|
||||||
|
|
||||||
## Renamed items
|
## Renamed items
|
||||||
|
|
||||||
### New Classes or Services
|
### New Classes or Services
|
||||||
|
@@ -0,0 +1,111 @@
|
|||||||
|
<div
|
||||||
|
id="userinfo_container"
|
||||||
|
[class.adf-userinfo-name-right]="showOnRight"
|
||||||
|
(keyup)="onKeyPress($event)"
|
||||||
|
class="adf-userinfo-container"
|
||||||
|
*ngIf="canShow"
|
||||||
|
>
|
||||||
|
<span *ngIf="showName" id="adf-userinfo-ecm-name-display" class="adf-userinfo-name">
|
||||||
|
{{ecmUser | fullName}}
|
||||||
|
</span>
|
||||||
|
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button"
|
||||||
|
data-automation-id="adf-user-profile">
|
||||||
|
<div class="adf-userinfo-button-profile" id="user-profile">
|
||||||
|
<div *ngIf="identityUser; else showEcmUserImage" id="identity-user-image">
|
||||||
|
<div *ngIf="ecmUser?.avatarId; else initialTemplate">
|
||||||
|
<div class="adf-userinfo-profile-container">
|
||||||
|
<img id="logged-user-img" [src]="getEcmAvatar(ecmUser.avatarId)" alt="user-info-profile-button"
|
||||||
|
class="adf-userinfo-profile-image"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div [innerHTML]="identityUser | usernameInitials:'adf-userinfo-pic'"></div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
<ng-template #showEcmUserImage>
|
||||||
|
<div id="ecm-user-image">
|
||||||
|
<div *ngIf="ecmUser.avatarId; else initialTemplate" class="adf-userinfo-profile-container">
|
||||||
|
<img id="logged-user-img" [src]="getEcmAvatar(ecmUser.avatarId)" alt="user-info-profile-button"
|
||||||
|
class="adf-userinfo-profile-image"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div [outerHTML]="ecmUser | usernameInitials:'adf-userinfo-pic'"></div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
|
||||||
|
[overlapTrigger]="false" class="adf-userinfo-menu">
|
||||||
|
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0" role="menuitem"
|
||||||
|
class="adf-userinfo-tab adf-hide-tab">
|
||||||
|
<mat-tab label="{{ 'USER_PROFILE.TAB.CS' | translate }}" role="dialog"
|
||||||
|
*ngIf="mode === userInfoMode.CONTENT">
|
||||||
|
<mat-card class="adf-userinfo-card">
|
||||||
|
<mat-card-header class="adf-userinfo-card-header"
|
||||||
|
[style.background-image]="'url(' + ecmBackgroundImage + ')'">
|
||||||
|
<div *ngIf="ecmUser.avatarId; else initialTemplate"
|
||||||
|
class="adf-userinfo-profile-container adf-hide-small">
|
||||||
|
<img class="adf-userinfo-profile-picture" id="ecm-user-detail-image"
|
||||||
|
alt="ecm-profile-image" [src]="getEcmAvatar(ecmUser.avatarId)"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div
|
||||||
|
[outerHTML]="ecmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<div class="adf-userinfo-title" id="ecm-username">{{ecmUser | fullName}}</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="adf-userinfo-supporting-text">
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="ecm-full-name"
|
||||||
|
class="adf-userinfo__detail-title">{{ecmUser | fullName}}</span>
|
||||||
|
<span class="adf-userinfo__detail-profile" id="ecm-email"> {{ecmUser.email}} </span>
|
||||||
|
<a class="adf-userinfo__detail-profile" href="#/profile">
|
||||||
|
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span class="adf-userinfo__secondary-info" id="ecm-job-title-label">
|
||||||
|
{{ 'USER_PROFILE.LABELS.ECM.JOB_TITLE' | translate }}
|
||||||
|
<span id="ecm-job-title"
|
||||||
|
class="adf-userinfo__detail-profile"> {{ ecmUser.jobTitle ? ecmUser.jobTitle : 'N/A' }} </span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab id="identity-panel" role="dialog" *ngIf="mode === userInfoMode.CONTENT_SSO">
|
||||||
|
<mat-card class="adf-userinfo-card">
|
||||||
|
<mat-card-header class="adf-userinfo-card-header"
|
||||||
|
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
|
||||||
|
<div *ngIf="ecmUser.avatarId; else initialTemplate"
|
||||||
|
class="adf-userinfo-profile-container adf-hide-small">
|
||||||
|
<img class="adf-userinfo-profile-picture" id="ecm-user-detail-image"
|
||||||
|
alt="ecm-profile-image" [src]="getEcmAvatar(ecmUser.avatarId)"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div
|
||||||
|
[outerHTML]="identityUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||||
|
</ng-template>
|
||||||
|
<div class="adf-userinfo-title" id="identity-username">{{identityUser | fullName}}</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="adf-userinfo-supporting-text">
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="identity-full-name"
|
||||||
|
class="adf-userinfo__detail-title">{{identityUser | fullName}}</span>
|
||||||
|
<span class="adf-userinfo__detail-profile"
|
||||||
|
id="identity-email"> {{identityUser.email}} </span>
|
||||||
|
<a class="adf-userinfo__detail-profile" href="#/profile">
|
||||||
|
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
@@ -0,0 +1,272 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 {
|
||||||
|
CoreTestingModule,
|
||||||
|
fakeEcmEditedUser,
|
||||||
|
fakeEcmUser,
|
||||||
|
fakeEcmUserNoImage,
|
||||||
|
IdentityUserModel,
|
||||||
|
InitialUsernamePipe,
|
||||||
|
setupTestBed,
|
||||||
|
UserInfoMode
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { By, DomSanitizer } from '@angular/platform-browser';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||||
|
|
||||||
|
import { ContentUserInfoComponent } from './content-user-info.component';
|
||||||
|
|
||||||
|
class FakeSanitizer extends DomSanitizer {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize(html) {
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
bypassSecurityTrustHtml(value: string): any {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bypassSecurityTrustStyle(): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bypassSecurityTrustScript(): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bypassSecurityTrustUrl(): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bypassSecurityTrustResourceUrl(): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ContentUserInfoComponent', () => {
|
||||||
|
const profilePictureUrl = 'alfresco-logo.svg';
|
||||||
|
|
||||||
|
let component: ContentUserInfoComponent;
|
||||||
|
let fixture: ComponentFixture<ContentUserInfoComponent>;
|
||||||
|
let element: HTMLElement;
|
||||||
|
|
||||||
|
const identityUserMock = { firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
|
||||||
|
const identityUserWithOutLastNameMock = { firstName: 'fake-identity-first-name', lastName: null, email: 'fakeIdentity@email.com' };
|
||||||
|
|
||||||
|
const openUserInfo = () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const imageButton = element.querySelector<HTMLButtonElement>('#logged-user-img');
|
||||||
|
imageButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
const whenFixtureReady = async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule,
|
||||||
|
ContentTestingModule,
|
||||||
|
MatMenuModule
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ContentUserInfoComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
|
||||||
|
spyOn(window, 'requestAnimationFrame').and.returnValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show any image if the user is not logged in', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#logged-user-img')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT have users immediately after ngOnInit', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#ecm_username')).toBeNull();
|
||||||
|
expect(element.querySelector('#user-profile-lists')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when user is logged on ecm', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.ecmUser = fakeEcmUser as any;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ui', () => {
|
||||||
|
|
||||||
|
it('should show ecm only last name when user first name is null ', async () => {
|
||||||
|
component.ecmUser = fakeEcmEditedUser as any;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
openUserInfo();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
const ecmUsername = fixture.debugElement.query(By.css('#ecm-username'));
|
||||||
|
expect(ecmUsername).toBeDefined();
|
||||||
|
expect(ecmUsername).not.toBeNull();
|
||||||
|
expect(ecmUsername.nativeElement.textContent).not.toContain('fake-ecm-first-name');
|
||||||
|
expect(ecmUsername.nativeElement.textContent).not.toContain('null');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the username when showName attribute is true', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
expect(component.showName).toBeTruthy();
|
||||||
|
expect(element.querySelector('#adf-userinfo-ecm-name-display')).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide the username when showName attribute is false', async () => {
|
||||||
|
component.showName = false;
|
||||||
|
await whenFixtureReady();
|
||||||
|
expect(element.querySelector('#adf-userinfo-ecm-name-display')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the defined class to show the name on the right side', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
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 () => {
|
||||||
|
component.namePosition = 'left';
|
||||||
|
await whenFixtureReady();
|
||||||
|
expect(element.querySelector('#userinfo_container').classList).not.toContain('adf-userinfo-name-right');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and has image', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
component.ecmUser = fakeEcmUser as any;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
spyOn(component, 'getEcmAvatar').and.returnValue(profilePictureUrl);
|
||||||
|
await whenFixtureReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the ecm current user image', async () => {
|
||||||
|
openUserInfo();
|
||||||
|
const loggedImage = fixture.debugElement.query(By.css('#logged-user-img'));
|
||||||
|
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(loggedImage).not.toBeNull();
|
||||||
|
expect(loggedImage.properties.src).toContain(profilePictureUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the current user image if user has avatarId', () => {
|
||||||
|
openUserInfo();
|
||||||
|
const loggedImage = fixture.debugElement.query(By.css('#logged-user-img'));
|
||||||
|
expect(component.ecmUser).toBeDefined();
|
||||||
|
expect(component.ecmUser.avatarId).toBe('fake-avatar-id');
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(loggedImage).not.toBeNull();
|
||||||
|
expect(loggedImage.properties.src).toContain(profilePictureUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the ecm user information', async () => {
|
||||||
|
openUserInfo();
|
||||||
|
const ecmImage = fixture.debugElement.query(By.css('#ecm-user-detail-image'));
|
||||||
|
const ecmFullName = fixture.debugElement.query(By.css('#ecm-full-name'));
|
||||||
|
const ecmJobTitle = fixture.debugElement.query(By.css('#ecm-job-title-label'));
|
||||||
|
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(fixture.debugElement.query(By.css('#ecm-username'))).not.toBeNull();
|
||||||
|
expect(ecmImage).not.toBeNull();
|
||||||
|
expect(ecmImage.properties.src).toContain(profilePictureUrl);
|
||||||
|
expect(ecmFullName.nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name');
|
||||||
|
expect(ecmJobTitle.nativeElement.textContent).toContain('USER_PROFILE.LABELS.ECM.JOB_TITLE');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and has no image', () => {
|
||||||
|
|
||||||
|
beforeEach( async () => {
|
||||||
|
component.ecmUser = fakeEcmUserNoImage as any;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
await whenFixtureReady();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show N/A when the job title is null', () => {
|
||||||
|
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
|
||||||
|
imageButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
const ecmJobTitle = fixture.debugElement.query(By.css('#ecm-job-title'));
|
||||||
|
expect(ecmJobTitle).not.toBeNull();
|
||||||
|
expect(ecmJobTitle).not.toBeNull();
|
||||||
|
expect(ecmJobTitle.nativeElement.textContent).toContain('N/A');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show the tabs', () => {
|
||||||
|
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
|
||||||
|
imageButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
const tabHeader = fixture.debugElement.query(By.css('#tab-group-env'));
|
||||||
|
expect(tabHeader.classes['adf-hide-tab']).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the current user Initials if the user dose not have avatarId', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const pipe = new InitialUsernamePipe(new FakeSanitizer());
|
||||||
|
const expected = pipe.transform({
|
||||||
|
id: 13,
|
||||||
|
firstName: 'Wilbur',
|
||||||
|
lastName: 'Adams',
|
||||||
|
email: 'wilbur@app.com'
|
||||||
|
});
|
||||||
|
expect(expected).toBe('<div data-automation-id="user-initials-image" class="">WA</div>');
|
||||||
|
expect(component.ecmUser).toBeDefined();
|
||||||
|
expect(component.ecmUser.avatarId).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when identity user is logged in', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.ecmUser = fakeEcmUser as any;
|
||||||
|
component.identityUser = identityUserMock as unknown as IdentityUserModel;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
component.mode = UserInfoMode.CONTENT_SSO;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show initials if the user have avatar and provider is ECM', async () => {
|
||||||
|
component.identityUser = identityUserWithOutLastNameMock as unknown as IdentityUserModel;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
expect(element.querySelector('.adf-userinfo-pic')).toBeNull();
|
||||||
|
expect(element.querySelector('.adf-userinfo-profile-image')).toBeDefined();
|
||||||
|
expect(element.querySelector('.adf-userinfo-profile-image')).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,108 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { EcmUserModel, IdentityUserModel, PeopleContentService, UserInfoMode } from '@alfresco/adf-core';
|
||||||
|
import { Component, Input, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-content-user-info',
|
||||||
|
templateUrl: './content-user-info.component.html',
|
||||||
|
styleUrls: ['./content-user-info.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class ContentUserInfoComponent implements OnDestroy {
|
||||||
|
|
||||||
|
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
ecmUser: EcmUserModel;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
identityUser: IdentityUserModel;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
mode: UserInfoMode = UserInfoMode.CONTENT;
|
||||||
|
|
||||||
|
/** Custom path for the background banner image for ACS users. */
|
||||||
|
@Input()
|
||||||
|
ecmBackgroundImage: string = './assets/images/ecm-background.png';
|
||||||
|
|
||||||
|
/** Custom path for the background banner image for APS users. */
|
||||||
|
@Input()
|
||||||
|
bpmBackgroundImage: string = './assets/images/bpm-background.png';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `before` or `after`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionX: MenuPositionX = 'after';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `above` or `below`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionY: MenuPositionY = 'below';
|
||||||
|
|
||||||
|
/** Shows/hides the username next to the user info button. */
|
||||||
|
@Input()
|
||||||
|
showName: boolean = true;
|
||||||
|
|
||||||
|
/** When the username is shown, this defines its position relative to the user info button.
|
||||||
|
* Can be `right` or `left`.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
namePosition: string = 'right';
|
||||||
|
|
||||||
|
userInfoMode = UserInfoMode;
|
||||||
|
|
||||||
|
private destroy$ = new Subject();
|
||||||
|
|
||||||
|
constructor(private peopleContentService: PeopleContentService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next(true);
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPress(event: KeyboardEvent) {
|
||||||
|
this.closeUserModal(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private closeUserModal($event: KeyboardEvent) {
|
||||||
|
if ($event.keyCode === 27) {
|
||||||
|
this.trigger.closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopClosing(event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
getEcmAvatar(avatarId: string): string {
|
||||||
|
return this.peopleContentService.getUserProfileImage(avatarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOnRight(): boolean {
|
||||||
|
return this.namePosition === 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
get canShow(): boolean {
|
||||||
|
return this.isLoggedIn && !!this.ecmUser && !!this.mode;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ContentUserInfoComponent } from './content-user-info.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PipeModule } from '@alfresco/adf-core';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [ContentUserInfoComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatCardModule,
|
||||||
|
TranslateModule,
|
||||||
|
PipeModule
|
||||||
|
],
|
||||||
|
exports: [ContentUserInfoComponent]
|
||||||
|
})
|
||||||
|
export class ContentUserInfoModule {}
|
20
lib/content-services/src/lib/content-user-info/public-api.ts
Normal file
20
lib/content-services/src/lib/content-user-info/public-api.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './content-user-info.component';
|
||||||
|
|
||||||
|
export * from './content-user-info.module';
|
@@ -48,6 +48,7 @@ import { ContentPipeModule } from './pipes/content-pipe.module';
|
|||||||
import { NodeCommentsModule } from './node-comments/node-comments.module';
|
import { NodeCommentsModule } from './node-comments/node-comments.module';
|
||||||
import { TreeModule } from './tree/tree.module';
|
import { TreeModule } from './tree/tree.module';
|
||||||
import { AlfrescoViewerModule } from './viewer/alfresco-viewer.module';
|
import { AlfrescoViewerModule } from './viewer/alfresco-viewer.module';
|
||||||
|
import { ContentUserInfoModule } from './content-user-info/content-user-info.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -62,6 +63,7 @@ import { AlfrescoViewerModule } from './viewer/alfresco-viewer.module';
|
|||||||
DialogModule,
|
DialogModule,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
DocumentListModule,
|
DocumentListModule,
|
||||||
|
ContentUserInfoModule,
|
||||||
UploadModule,
|
UploadModule,
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
SitesDropdownModule,
|
SitesDropdownModule,
|
||||||
@@ -98,6 +100,7 @@ import { AlfrescoViewerModule } from './viewer/alfresco-viewer.module';
|
|||||||
TagModule,
|
TagModule,
|
||||||
WebScriptModule,
|
WebScriptModule,
|
||||||
DocumentListModule,
|
DocumentListModule,
|
||||||
|
ContentUserInfoModule,
|
||||||
UploadModule,
|
UploadModule,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
SitesDropdownModule,
|
SitesDropdownModule,
|
||||||
|
@@ -20,6 +20,7 @@ export * from './lib/social/index';
|
|||||||
export * from './lib/tag/index';
|
export * from './lib/tag/index';
|
||||||
export * from './lib/webscript/index';
|
export * from './lib/webscript/index';
|
||||||
export * from './lib/document-list/index';
|
export * from './lib/document-list/index';
|
||||||
|
export * from './lib/content-user-info/index';
|
||||||
export * from './lib/upload/index';
|
export * from './lib/upload/index';
|
||||||
export * from './lib/search/index';
|
export * from './lib/search/index';
|
||||||
export * from './lib/site-dropdown/index';
|
export * from './lib/site-dropdown/index';
|
||||||
|
@@ -27,6 +27,7 @@ export * from './services/thumbnail.service';
|
|||||||
export * from './services/sort-by-category.service';
|
export * from './services/sort-by-category.service';
|
||||||
|
|
||||||
export * from './models/log-levels.model';
|
export * from './models/log-levels.model';
|
||||||
|
export * from './models/user-info-mode.enum';
|
||||||
|
|
||||||
export * from './interface/search-component.interface';
|
export * from './interface/search-component.interface';
|
||||||
|
|
||||||
|
24
lib/core/src/lib/common/models/user-info-mode.enum.ts
Normal file
24
lib/core/src/lib/common/models/user-info-mode.enum.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum UserInfoMode {
|
||||||
|
ALL = 'ALL',
|
||||||
|
CONTENT = 'CONTENT',
|
||||||
|
PROCESS = 'PROCESS',
|
||||||
|
SSO = 'SSO',
|
||||||
|
CONTENT_SSO = 'CONTENT_SSO'
|
||||||
|
}
|
@@ -31,7 +31,6 @@ import { LanguageMenuModule } from './language-menu/language-menu.module';
|
|||||||
import { LoginModule } from './login/login.module';
|
import { LoginModule } from './login/login.module';
|
||||||
import { PaginationModule } from './pagination/pagination.module';
|
import { PaginationModule } from './pagination/pagination.module';
|
||||||
import { ToolbarModule } from './toolbar/toolbar.module';
|
import { ToolbarModule } from './toolbar/toolbar.module';
|
||||||
import { UserInfoModule } from './userinfo/userinfo.module';
|
|
||||||
import { ViewerModule } from './viewer/viewer.module';
|
import { ViewerModule } from './viewer/viewer.module';
|
||||||
import { FormBaseModule } from './form/form-base.module';
|
import { FormBaseModule } from './form/form-base.module';
|
||||||
import { SidenavLayoutModule } from './layout/layout.module';
|
import { SidenavLayoutModule } from './layout/layout.module';
|
||||||
@@ -64,6 +63,7 @@ import { RichTextEditorModule } from './rich-text-editor/rich-text-editor.module
|
|||||||
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
import { AuthenticationService } from './auth/services/authentication.service';
|
import { AuthenticationService } from './auth/services/authentication.service';
|
||||||
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
||||||
|
import { IdentityUserInfoModule } from './identity-user-info/identity-user-info.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -74,11 +74,11 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
|||||||
SidenavLayoutModule,
|
SidenavLayoutModule,
|
||||||
PipeModule,
|
PipeModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
IdentityUserInfoModule,
|
||||||
DirectiveModule,
|
DirectiveModule,
|
||||||
DownloadZipDialogModule,
|
DownloadZipDialogModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
UserInfoModule,
|
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
AppConfigModule,
|
AppConfigModule,
|
||||||
PaginationModule,
|
PaginationModule,
|
||||||
@@ -118,8 +118,8 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
|||||||
DownloadZipDialogModule,
|
DownloadZipDialogModule,
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
IdentityUserInfoModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
UserInfoModule,
|
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
AppConfigModule,
|
AppConfigModule,
|
||||||
PaginationModule,
|
PaginationModule,
|
||||||
|
@@ -0,0 +1,45 @@
|
|||||||
|
<div
|
||||||
|
id="userinfo_container"
|
||||||
|
[class.adf-userinfo-name-right]="showOnRight"
|
||||||
|
(keyup)="onKeyPress($event)"
|
||||||
|
class="adf-userinfo-container"
|
||||||
|
*ngIf="isLoggedIn"
|
||||||
|
>
|
||||||
|
<span *ngIf="showName" id="adf-userinfo-identity-name-display" class="adf-userinfo-name">
|
||||||
|
{{identityUser | fullName}}
|
||||||
|
</span>
|
||||||
|
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button"
|
||||||
|
data-automation-id="adf-user-profile">
|
||||||
|
<div class="adf-userinfo-button-profile" id="user-profile">
|
||||||
|
<div id="identity-user-image">
|
||||||
|
<div [innerHTML]="identityUser | usernameInitials:'adf-userinfo-pic'"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
|
||||||
|
[overlapTrigger]="false" class="adf-userinfo-menu">
|
||||||
|
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0" role="menuitem"
|
||||||
|
class="adf-userinfo-tab adf-hide-tab">
|
||||||
|
<mat-tab id="identity-panel" role="dialog">
|
||||||
|
<mat-card class="adf-userinfo-card">
|
||||||
|
<mat-card-header class="adf-userinfo-card-header"
|
||||||
|
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
|
||||||
|
<div class="adf-userinfo-title" id="identity-username">{{identityUser | fullName}}</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="adf-userinfo-supporting-text">
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="identity-full-name"
|
||||||
|
class="adf-userinfo__detail-title">{{identityUser | fullName}}</span>
|
||||||
|
<span class="adf-userinfo__detail-profile"
|
||||||
|
id="identity-email"> {{identityUser.email}} </span>
|
||||||
|
<a class="adf-userinfo__detail-profile" href="#/profile">
|
||||||
|
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
@@ -0,0 +1,188 @@
|
|||||||
|
.adf {
|
||||||
|
&-userinfo-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-name-right {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-name {
|
||||||
|
padding: 0 5px;
|
||||||
|
|
||||||
|
@media screen and (max-width: 959px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-pic {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 100px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: var(--theme-adf-picture-1-font-size);
|
||||||
|
text-transform: uppercase;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-image {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 90%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-right: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-container {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-menu_button.mat-button {
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: 90%;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-tab .mat-tab-header {
|
||||||
|
align-self: center;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-tab .mat-tab-label {
|
||||||
|
flex: auto;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: 48px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-card-header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: stretch;
|
||||||
|
line-height: normal;
|
||||||
|
height: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-card.mat-card {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-supporting-text {
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 32px;
|
||||||
|
column-count: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
@media screen and (max-width: 599px) {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-title {
|
||||||
|
font-size: var(--theme-title-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__detail-profile {
|
||||||
|
align-items: flex-start;
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__detail-title {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: var(--theme-subheading-2-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
line-height: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__secondary-info {
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-picture {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
background-size: cover;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-initials {
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-size: cover;
|
||||||
|
background-color: var(--adf-user-info-color);
|
||||||
|
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 {
|
||||||
|
display: inline-block;
|
||||||
|
border: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-detail {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-hide-tab .mat-tab-label-active {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-device-width: 480px) {
|
||||||
|
.mat-menu-panel.adf-userinfo-menu {
|
||||||
|
max-height: 450px;
|
||||||
|
min-width: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-menu-panel.adf-userinfo-menu .mat-menu-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
@@ -0,0 +1,139 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { IdentityUserInfoComponent } from './identity-user-info.component';
|
||||||
|
import { setupTestBed } from '../testing/setup-test-bed';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CoreTestingModule } from '../testing/core.testing.module';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { IdentityUserModel } from '../auth/models/identity-user.model';
|
||||||
|
|
||||||
|
describe('IdentityUserInfoComponent', () => {
|
||||||
|
let component: IdentityUserInfoComponent;
|
||||||
|
let fixture: ComponentFixture<IdentityUserInfoComponent>;
|
||||||
|
let element: HTMLElement;
|
||||||
|
|
||||||
|
const identityUserMock = { firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' } as unknown as IdentityUserModel;
|
||||||
|
const identityUserWithOutFirstNameMock = { firstName: null, lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' } as unknown as IdentityUserModel;
|
||||||
|
const identityUserWithOutLastNameMock = { firstName: 'fake-identity-first-name', lastName: null, email: 'fakeIdentity@email.com' } as unknown as IdentityUserModel;
|
||||||
|
|
||||||
|
const whenFixtureReady = async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule,
|
||||||
|
MatMenuModule
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(IdentityUserInfoComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
|
||||||
|
spyOn(window, 'requestAnimationFrame').and.returnValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show any image if the user is not logged in', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#logged-user-img')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT have users immediately after ngOnInit', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#ecm_username')).toBeNull();
|
||||||
|
expect(element.querySelector('#bpm_username')).toBeNull();
|
||||||
|
expect(element.querySelector('#user-profile-lists')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when identity user is logged in', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.identityUser = identityUserMock;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the identity user initials', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('[data-automation-id="user-initials-image"]')?.textContent).toContain('ff');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show full name next to the user image', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
const imageButton = element.querySelector<HTMLButtonElement>('#identity-user-image');
|
||||||
|
imageButton?.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
|
||||||
|
const identityUserName = fixture.debugElement.query(By.css('#identity-username'));
|
||||||
|
expect(identityUserName).toBeDefined();
|
||||||
|
expect(identityUserName).not.toBeNull();
|
||||||
|
expect(identityUserName.nativeElement.textContent).toContain('fake-identity-first-name fake-identity-last-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show last name if first name is null', async () => {
|
||||||
|
component.identityUser = identityUserWithOutFirstNameMock;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#adf-userinfo-identity-name-display')).not.toBeNull();
|
||||||
|
expect(fullNameElement?.textContent).toContain('fake-identity-last-name');
|
||||||
|
expect(fullNameElement?.textContent).not.toContain('fake-identity-first-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show first name if it is null string', async () => {
|
||||||
|
component.identityUser = identityUserWithOutFirstNameMock;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(fullNameElement).toBeDefined();
|
||||||
|
expect(fullNameElement?.textContent).toContain('fake-identity-last-name');
|
||||||
|
expect(fullNameElement?.textContent).not.toContain('null');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show last name if it is null string', async () => {
|
||||||
|
component.identityUser = identityUserWithOutLastNameMock;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(fullNameElement).toBeDefined();
|
||||||
|
expect(fullNameElement?.textContent).toContain('fake-identity-first-name');
|
||||||
|
expect(fullNameElement?.textContent).not.toContain('null');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,128 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 {
|
||||||
|
Meta,
|
||||||
|
moduleMetadata,
|
||||||
|
Story
|
||||||
|
} from '@storybook/angular';
|
||||||
|
import { CoreStoryModule } from '../testing/core.story.module';
|
||||||
|
import { IdentityUserInfoComponent } from './identity-user-info.component';
|
||||||
|
import { IdentityUserInfoModule } from './identity-user-info.module';
|
||||||
|
|
||||||
|
const fakeIdentityUser = {
|
||||||
|
familyName: 'Identity',
|
||||||
|
givenName: 'John',
|
||||||
|
email: 'john.identity@gmail.com',
|
||||||
|
username: 'johnyIdentity99'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
component: IdentityUserInfoComponent,
|
||||||
|
title: 'Core/Identity User Info/Identity User Info',
|
||||||
|
decorators: [
|
||||||
|
moduleMetadata({
|
||||||
|
imports: [CoreStoryModule, IdentityUserInfoModule]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
argTypes: {
|
||||||
|
isLoggedIn: {
|
||||||
|
description:
|
||||||
|
'Determines if user is logged in',
|
||||||
|
control: 'boolean',
|
||||||
|
defaultValue: true,
|
||||||
|
table: {
|
||||||
|
type: { summary: 'boolean' },
|
||||||
|
defaultValue: { summary: true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
identityUser: {
|
||||||
|
description:
|
||||||
|
'Identity User Info',
|
||||||
|
control: 'object',
|
||||||
|
table: {
|
||||||
|
type: { summary: 'IdentityUserModel' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
menuPositionX: {
|
||||||
|
description:
|
||||||
|
'Material Angular menu horizontal position in regard to User Info',
|
||||||
|
control: 'radio',
|
||||||
|
options: ['before', 'after'],
|
||||||
|
defaultValue: 'after',
|
||||||
|
table: {
|
||||||
|
type: { summary: 'MenuPositionX' },
|
||||||
|
defaultValue: { summary: 'after' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
menuPositionY: {
|
||||||
|
description:
|
||||||
|
'Material Angular menu vertical position in regard to User Info',
|
||||||
|
control: 'radio',
|
||||||
|
options: ['above', 'below'],
|
||||||
|
defaultValue: 'below',
|
||||||
|
table: {
|
||||||
|
type: { summary: 'MenuPositionY' },
|
||||||
|
defaultValue: { summary: 'below' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showName: {
|
||||||
|
description:
|
||||||
|
'Determines if name should be shown next to user avatar',
|
||||||
|
control: 'boolean',
|
||||||
|
defaultValue: true,
|
||||||
|
table: {
|
||||||
|
type: { summary: 'boolean' },
|
||||||
|
defaultValue: { summary: true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
namePosition: {
|
||||||
|
description: 'User name position in regard to avatar',
|
||||||
|
control: 'radio',
|
||||||
|
options: ['left', 'right'],
|
||||||
|
defaultValue: 'right',
|
||||||
|
table: {
|
||||||
|
type: { summary: 'string' },
|
||||||
|
defaultValue: { summary: 'right' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bpmBackgroundImage: {
|
||||||
|
description: 'Menu background banner image for APS users',
|
||||||
|
control: {
|
||||||
|
disable: true
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
type: {
|
||||||
|
summary: 'string'
|
||||||
|
},
|
||||||
|
defaultValue: {
|
||||||
|
summary: './assets/images/bpm-background.png'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const template: Story<IdentityUserInfoComponent> = (args: IdentityUserInfoComponent) => ({
|
||||||
|
props: args
|
||||||
|
});
|
||||||
|
|
||||||
|
export const loginWithSSO = template.bind({});
|
||||||
|
loginWithSSO.args = {
|
||||||
|
identityUser: fakeIdentityUser
|
||||||
|
};
|
||||||
|
loginWithSSO.parameters = { layout: 'centered' };
|
@@ -0,0 +1,89 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
|
||||||
|
import { IdentityUserModel } from '../auth/models/identity-user.model';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-identity-user-info',
|
||||||
|
templateUrl: './identity-user-info.component.html',
|
||||||
|
styleUrls: ['./identity-user-info.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class IdentityUserInfoComponent implements OnDestroy {
|
||||||
|
|
||||||
|
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
identityUser: IdentityUserModel;
|
||||||
|
|
||||||
|
/** Custom path for the background banner image for APS users. */
|
||||||
|
@Input()
|
||||||
|
bpmBackgroundImage: string = './assets/images/bpm-background.png';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `before` or `after`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionX: MenuPositionX = 'after';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `above` or `below`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionY: MenuPositionY = 'below';
|
||||||
|
|
||||||
|
/** Shows/hides the username next to the user info button. */
|
||||||
|
@Input()
|
||||||
|
showName: boolean = true;
|
||||||
|
|
||||||
|
/** When the username is shown, this defines its position relative to the user info button.
|
||||||
|
* Can be `right` or `left`.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
namePosition: string = 'right';
|
||||||
|
|
||||||
|
private destroy$ = new Subject();
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next(true);
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPress(event: KeyboardEvent) {
|
||||||
|
this.closeUserModal(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private closeUserModal($event: KeyboardEvent) {
|
||||||
|
if ($event.keyCode === 27) {
|
||||||
|
this.trigger.closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopClosing(event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOnRight(): boolean {
|
||||||
|
return this.namePosition === 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
get canShow(): boolean {
|
||||||
|
return this.isLoggedIn && !!this.identityUser;
|
||||||
|
}
|
||||||
|
}
|
@@ -15,17 +15,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { CommonModule } from '@angular/common';
|
||||||
import { PipeModule } from '../pipes/pipe.module';
|
import { IdentityUserInfoComponent } from './identity-user-info.component';
|
||||||
import { UserInfoComponent } from './components/user-info.component';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PipeModule } from '../pipes/pipe.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
declarations: [IdentityUserInfoComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
@@ -35,12 +36,6 @@ import { MatCardModule } from '@angular/material/card';
|
|||||||
TranslateModule,
|
TranslateModule,
|
||||||
PipeModule
|
PipeModule
|
||||||
],
|
],
|
||||||
declarations: [
|
exports: [IdentityUserInfoComponent]
|
||||||
UserInfoComponent
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
UserInfoComponent
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class UserInfoModule {
|
export class IdentityUserInfoModule {}
|
||||||
}
|
|
@@ -15,5 +15,4 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './components/user-info.component';
|
export * from './public-api';
|
||||||
export * from './userinfo.module';
|
|
20
lib/core/src/lib/identity-user-info/public-api.ts
Normal file
20
lib/core/src/lib/identity-user-info/public-api.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './identity-user-info.component';
|
||||||
|
|
||||||
|
export * from './identity-user-info.module';
|
@@ -1,76 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright 2019 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 { Inject, Injectable } from '@angular/core';
|
|
||||||
import { ReplaySubject } from 'rxjs';
|
|
||||||
import { AlfrescoApiService } from './../../../services/alfresco-api.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class AuthenticationServiceMock {
|
|
||||||
onLogin: ReplaySubject<any> = new ReplaySubject<any>(1);
|
|
||||||
|
|
||||||
onLogout: ReplaySubject<any> = new ReplaySubject<any>(1);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private alfrescoApi: AlfrescoApiService,
|
|
||||||
@Inject('MODE') public loginMode: string
|
|
||||||
) {}
|
|
||||||
|
|
||||||
isLoggedIn(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoggedInWith(provider: string): boolean {
|
|
||||||
if (provider === 'BPM') {
|
|
||||||
return this.isBpmLoggedIn();
|
|
||||||
} else if (provider === 'ECM') {
|
|
||||||
return this.isEcmLoggedIn();
|
|
||||||
} else {
|
|
||||||
return this.isLoggedIn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isKerberosEnabled(): boolean {
|
|
||||||
return this.loginMode === 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
isOauth(): boolean {
|
|
||||||
return this.loginMode === 'default' || this.loginMode === 'defaultEcm';
|
|
||||||
}
|
|
||||||
|
|
||||||
isECMProvider(): boolean {
|
|
||||||
return this.alfrescoApi.getInstance().isEcmConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
isBPMProvider(): boolean {
|
|
||||||
return this.alfrescoApi.getInstance().isBpmConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
isALLProvider(): boolean {
|
|
||||||
return this.loginMode === 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
isEcmLoggedIn(): boolean {
|
|
||||||
return this.loginMode === 'ecm' || this.loginMode === 'defaultEcm';
|
|
||||||
}
|
|
||||||
|
|
||||||
isBpmLoggedIn(): boolean {
|
|
||||||
return this.loginMode === 'bpm';
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,78 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright 2019 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 {
|
|
||||||
BpmUserModel,
|
|
||||||
EcmUserModel
|
|
||||||
} from './../../../models';
|
|
||||||
import {
|
|
||||||
IdentityUserModel
|
|
||||||
} from './../../../auth/models/identity-user.model';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
|
|
||||||
export class PeopleContentServiceMock {
|
|
||||||
private fakeEcmUser = new EcmUserModel({
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Ecm',
|
|
||||||
avatarId: 'fake-avatar-id',
|
|
||||||
email: 'john.ecm@gmail.com',
|
|
||||||
jobTitle: 'Product Manager'
|
|
||||||
});
|
|
||||||
|
|
||||||
getCurrentUserInfo = () => of(this.fakeEcmUser);
|
|
||||||
|
|
||||||
getUserProfileImage = () => './assets/images/alfresco-logo.svg';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EcmUserServiceMock {
|
|
||||||
private fakeEcmUser = new EcmUserModel({
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Ecm',
|
|
||||||
avatarId: 'fake-avatar-id',
|
|
||||||
email: 'john.ecm@gmail.com',
|
|
||||||
jobTitle: 'Product Manager'
|
|
||||||
});
|
|
||||||
|
|
||||||
getCurrentUserInfo = () => of(this.fakeEcmUser);
|
|
||||||
|
|
||||||
getUserProfileImage = () => './assets/images/alfresco-logo.svg';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BpmUserServiceMock {
|
|
||||||
private fakeBpmUser = new BpmUserModel({
|
|
||||||
email: 'john.bpm@gmail.com',
|
|
||||||
firstName: 'John',
|
|
||||||
lastName: 'Bpm',
|
|
||||||
pictureId: 12,
|
|
||||||
tenantName: 'Name of Tenant'
|
|
||||||
});
|
|
||||||
|
|
||||||
getCurrentUserInfo = () => of(this.fakeBpmUser);
|
|
||||||
|
|
||||||
getCurrentUserProfileImage = () => './assets/images/alfresco-logo.svg';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class IdentityUserServiceMock {
|
|
||||||
private fakeIdentityUser = {
|
|
||||||
familyName: 'Identity',
|
|
||||||
givenName: 'John',
|
|
||||||
email: 'john.identity@gmail.com',
|
|
||||||
username: 'johnyIdentity99'
|
|
||||||
};
|
|
||||||
|
|
||||||
getCurrentUserInfo = (): IdentityUserModel => this.fakeIdentityUser;
|
|
||||||
}
|
|
@@ -1,162 +0,0 @@
|
|||||||
<div id="userinfo_container" [class.adf-userinfo-name-right]="showOnRight" (keyup)="onKeyPress($event)"
|
|
||||||
class="adf-userinfo-container" *ngIf="isLoggedIn">
|
|
||||||
|
|
||||||
<ng-container *ngIf="showName">
|
|
||||||
<span *ngIf="identityUser$ | async as identityUser; else showBpmAndEcmUserFullNames"
|
|
||||||
id="adf-userinfo-identity-name-display"
|
|
||||||
class="adf-userinfo-name">{{identityUser | fullName}}</span>
|
|
||||||
<ng-template #showBpmAndEcmUserFullNames>
|
|
||||||
<span *ngIf="ecmUser$ | async as ecmUser; else showBpmUserFullName" id="adf-userinfo-ecm-name-display"
|
|
||||||
class="adf-userinfo-name">{{ecmUser | fullName}}</span>
|
|
||||||
<ng-template #showBpmUserFullName>
|
|
||||||
<span *ngIf="bpmUser$ | async as bpmUser" id="adf-userinfo-bpm-name-display"
|
|
||||||
class="adf-userinfo-name">{{bpmUser | fullName}}</span>
|
|
||||||
</ng-template>
|
|
||||||
</ng-template>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button"
|
|
||||||
data-automation-id="adf-user-profile">
|
|
||||||
<div class="adf-userinfo-button-profile" id="user-profile">
|
|
||||||
<div *ngIf="identityUser$ | async as identityUser; else showBpmAndEcmUserImage" id="identity-user-image">
|
|
||||||
<div *ngIf="(ecmUser$ | async)?.avatarId as avatarId; else initialTemplate">
|
|
||||||
<div class="adf-userinfo-profile-container">
|
|
||||||
<img id="logged-user-img" [src]="getEcmAvatar(avatarId)" alt="user-info-profile-button"
|
|
||||||
class="adf-userinfo-profile-image"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div [innerHTML]="identityUser | usernameInitials:'adf-userinfo-pic'"></div>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
<ng-template #showBpmAndEcmUserImage>
|
|
||||||
<div *ngIf="ecmUser$ | async as ecmUser; else showBpmUserImage" id="ecm-user-image">
|
|
||||||
<div *ngIf="ecmUser.avatarId; else initialTemplate" class="adf-userinfo-profile-container">
|
|
||||||
<img id="logged-user-img" [src]="getEcmAvatar(ecmUser.avatarId)" alt="user-info-profile-button"
|
|
||||||
class="adf-userinfo-profile-image"/>
|
|
||||||
</div>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div [outerHTML]="ecmUser | usernameInitials:'adf-userinfo-pic'"></div>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
<ng-template #showBpmUserImage>
|
|
||||||
<div *ngIf="bpmUser$ | async as bpmUser" id="bpm-user-image">
|
|
||||||
<div *ngIf="bpmUser.pictureId; else initialTemplate" class="adf-userinfo-profile-container">
|
|
||||||
<img id="logged-user-img" [src]="getBpmUserImage()" alt="user-info-profile-button"
|
|
||||||
class="adf-userinfo-profile-image"/>
|
|
||||||
</div>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div [outerHTML]="bpmUser | usernameInitials:'adf-userinfo-pic'"></div>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
|
|
||||||
[overlapTrigger]="false" class="adf-userinfo-menu">
|
|
||||||
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0" role="menuitem"
|
|
||||||
class="adf-userinfo-tab" [class.adf-hide-tab]="!(bpmUser$ | async) || !(ecmUser$ | async)">
|
|
||||||
<mat-tab id="ecm-panel" label="{{ 'USER_PROFILE.TAB.CS' | translate }}" role="dialog"
|
|
||||||
*ngIf="mode==='CONTENT' || mode==='ALL'">
|
|
||||||
<mat-card class="adf-userinfo-card" *ngIf="ecmUser$ | async as ecmUser">
|
|
||||||
<mat-card-header class="adf-userinfo-card-header"
|
|
||||||
[style.background-image]="'url(' + ecmBackgroundImage + ')'">
|
|
||||||
<div *ngIf="ecmUser.avatarId; else initialTemplate"
|
|
||||||
class="adf-userinfo-profile-container adf-hide-small">
|
|
||||||
<img class="adf-userinfo-profile-picture" id="ecm-user-detail-image"
|
|
||||||
alt="ecm-profile-image" [src]="getEcmAvatar(ecmUser.avatarId)"/>
|
|
||||||
</div>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div
|
|
||||||
[outerHTML]="ecmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<div class="adf-userinfo-title" id="ecm-username">{{ecmUser | fullName}}</div>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<div class="adf-userinfo-supporting-text">
|
|
||||||
<div class="adf-userinfo-detail">
|
|
||||||
<span id="ecm-full-name"
|
|
||||||
class="adf-userinfo__detail-title">{{ecmUser | fullName}}</span>
|
|
||||||
<span class="adf-userinfo__detail-profile" id="ecm-email"> {{ecmUser.email}} </span>
|
|
||||||
<a *ngIf="mode==='CONTENT'" class="adf-userinfo__detail-profile" href="#/profile">
|
|
||||||
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
|
||||||
</div>
|
|
||||||
<div class="adf-userinfo-detail">
|
|
||||||
<span class="adf-userinfo__secondary-info" id="ecm-job-title-label">
|
|
||||||
{{ 'USER_PROFILE.LABELS.ECM.JOB_TITLE' | translate }}
|
|
||||||
<span id="ecm-job-title"
|
|
||||||
class="adf-userinfo__detail-profile"> {{ ecmUser.jobTitle ? ecmUser.jobTitle : 'N/A' }} </span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</mat-tab>
|
|
||||||
<mat-tab id="bpm-panel" label="{{ 'USER_PROFILE.TAB.PS' | translate }}" role="dialog"
|
|
||||||
*ngIf="mode==='PROCESS' || mode==='ALL'">
|
|
||||||
<mat-card class="adf-userinfo-card" *ngIf="bpmUser$ | async as bpmUser">
|
|
||||||
<mat-card-header class="adf-userinfo-card-header"
|
|
||||||
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
|
|
||||||
<img *ngIf="bpmUser.pictureId; else initialTemplate"
|
|
||||||
class="adf-userinfo-profile-picture adf-hide-small" id="bpm-user-detail-image"
|
|
||||||
alt="bpm-profile-image" [src]="getBpmUserImage()"/>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div
|
|
||||||
[outerHTML]="bpmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
|
||||||
</ng-template>
|
|
||||||
<div class="adf-userinfo-title" id="bpm-username">{{bpmUser | fullName}}</div>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<div class="adf-userinfo-supporting-text">
|
|
||||||
<div class="adf-userinfo-detail">
|
|
||||||
<span id="bpm-full-name"
|
|
||||||
class="adf-userinfo__detail-title">{{ bpmUser | fullName }}</span>
|
|
||||||
<span class="adf-userinfo__detail-profile" id="bpm-email"> {{bpmUser.email}} </span>
|
|
||||||
</div>
|
|
||||||
<div class="adf-userinfo-detail">
|
|
||||||
<span id="bpm-tenant" class="adf-userinfo__secondary-info">
|
|
||||||
{{ 'USER_PROFILE.LABELS.BPM.TENANT' | translate }}
|
|
||||||
<span
|
|
||||||
class="adf-userinfo__detail-profile">{{ bpmUser.tenantName ? bpmUser.tenantName : '' }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</mat-tab>
|
|
||||||
<mat-tab id="identity-panel" role="dialog" *ngIf="mode==='SSO'">
|
|
||||||
<mat-card class="adf-userinfo-card" *ngIf="identityUser$ | async as identityUser">
|
|
||||||
<mat-card-header class="adf-userinfo-card-header"
|
|
||||||
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
|
|
||||||
<div *ngIf="ecmUser$ | async as ecmUser">
|
|
||||||
<div *ngIf="ecmUser.avatarId; else initialTemplate"
|
|
||||||
class="adf-userinfo-profile-container adf-hide-small">
|
|
||||||
<img class="adf-userinfo-profile-picture" id="ecm-user-detail-image"
|
|
||||||
alt="ecm-profile-image" [src]="getEcmAvatar(ecmUser.avatarId)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ng-template #initialTemplate>
|
|
||||||
<div
|
|
||||||
[outerHTML]="identityUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
|
||||||
</ng-template>
|
|
||||||
<div class="adf-userinfo-title" id="identity-username">{{identityUser | fullName}}</div>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<div class="adf-userinfo-supporting-text">
|
|
||||||
<div class="adf-userinfo-detail">
|
|
||||||
<span id="identity-full-name"
|
|
||||||
class="adf-userinfo__detail-title">{{identityUser | fullName}}</span>
|
|
||||||
<span class="adf-userinfo__detail-profile"
|
|
||||||
id="identity-email"> {{identityUser.email}} </span>
|
|
||||||
<a class="adf-userinfo__detail-profile" href="#/profile">
|
|
||||||
{{ 'USER_PROFILE.LABELS.MY_PROFILE' | translate }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
|
||||||
</mat-tab>
|
|
||||||
</mat-tab-group>
|
|
||||||
</mat-menu>
|
|
||||||
</div>
|
|
@@ -1,592 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright 2019 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 } from '@angular/core/testing';
|
|
||||||
import { By, DomSanitizer } from '@angular/platform-browser';
|
|
||||||
import { ContentService, PeopleContentService } from '../../services';
|
|
||||||
import { AuthenticationService } from '../../auth/services/authentication.service';
|
|
||||||
import { IdentityUserService } from '../../auth/services/identity-user.service';
|
|
||||||
import { InitialUsernamePipe } from '../../pipes';
|
|
||||||
import { fakeBpmUser } from '../../mock/bpm-user.service.mock';
|
|
||||||
import { fakeEcmEditedUser, fakeEcmUser, fakeEcmUserNoImage } from '../../mock/ecm-user.service.mock';
|
|
||||||
import { BpmUserService } from '../../services/bpm-user.service';
|
|
||||||
import { BpmUserModel } from '../../models/bpm-user.model';
|
|
||||||
import { EcmUserModel } from '../../models/ecm-user.model';
|
|
||||||
import { UserInfoComponent } from './user-info.component';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
|
||||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
|
||||||
|
|
||||||
class FakeSanitizer extends DomSanitizer {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
sanitize(html) {
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
bypassSecurityTrustHtml(value: string): any {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bypassSecurityTrustStyle(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bypassSecurityTrustScript(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bypassSecurityTrustUrl(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bypassSecurityTrustResourceUrl(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('User info component', () => {
|
|
||||||
const profilePictureUrl = 'alfresco-logo.svg';
|
|
||||||
|
|
||||||
let component: UserInfoComponent;
|
|
||||||
let fixture: ComponentFixture<UserInfoComponent>;
|
|
||||||
let element: HTMLElement;
|
|
||||||
let authService: AuthenticationService;
|
|
||||||
let contentService: ContentService;
|
|
||||||
let peopleContentService: PeopleContentService;
|
|
||||||
let bpmUserService: BpmUserService;
|
|
||||||
let identityUserService: IdentityUserService;
|
|
||||||
|
|
||||||
const identityUserMock = { firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
|
|
||||||
const identityUserWithOutFirstNameMock = { firstName: null, lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
|
|
||||||
const identityUserWithOutLastNameMock = { firstName: 'fake-identity-first-name', lastName: null, email: 'fakeIdentity@email.com' };
|
|
||||||
|
|
||||||
const openUserInfo = () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
const imageButton = element.querySelector<HTMLButtonElement>('#logged-user-img');
|
|
||||||
imageButton.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
};
|
|
||||||
|
|
||||||
const whenFixtureReady = async () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
fixture.detectChanges();
|
|
||||||
};
|
|
||||||
|
|
||||||
setupTestBed({
|
|
||||||
imports: [
|
|
||||||
TranslateModule.forRoot(),
|
|
||||||
CoreTestingModule,
|
|
||||||
MatMenuModule
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(UserInfoComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
element = fixture.nativeElement;
|
|
||||||
|
|
||||||
authService = TestBed.inject(AuthenticationService);
|
|
||||||
peopleContentService = TestBed.inject(PeopleContentService);
|
|
||||||
bpmUserService = TestBed.inject(BpmUserService);
|
|
||||||
contentService = TestBed.inject(ContentService);
|
|
||||||
identityUserService = TestBed.inject(IdentityUserService);
|
|
||||||
|
|
||||||
spyOn(window, 'requestAnimationFrame').and.returnValue(1);
|
|
||||||
spyOn(bpmUserService, 'getCurrentUserProfileImage').and.returnValue(profilePictureUrl);
|
|
||||||
spyOn(contentService, 'getContentUrl').and.returnValue(profilePictureUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
fixture.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show any image if the user is not logged in', () => {
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('#logged-user-img')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should NOT have users immediately after ngOnInit', () => {
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('#ecm_username')).toBeNull();
|
|
||||||
expect(element.querySelector('#bpm_username')).toBeNull();
|
|
||||||
expect(element.querySelector('#user-profile-lists')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when user is logged on ecm', () => {
|
|
||||||
|
|
||||||
let getCurrenEcmtUserInfoStub;
|
|
||||||
let isOauthStub;
|
|
||||||
let isEcmLoggedInStub;
|
|
||||||
let isLoggedInStub;
|
|
||||||
let isBpmLoggedInStub;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
isOauthStub = spyOn(authService, 'isOauth').and.returnValue(false);
|
|
||||||
isEcmLoggedInStub = spyOn(authService, 'isEcmLoggedIn').and.returnValue(true);
|
|
||||||
isLoggedInStub = spyOn(authService, 'isLoggedIn').and.returnValue(true);
|
|
||||||
isBpmLoggedInStub = spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
|
|
||||||
getCurrenEcmtUserInfoStub = spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of(fakeEcmUser as any));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ui ', () => {
|
|
||||||
|
|
||||||
it('should able to fetch ecm userInfo', (done) => {
|
|
||||||
component.getUserInfo();
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.ecmUser$.subscribe((response: EcmUserModel) => {
|
|
||||||
expect(response).toBeDefined();
|
|
||||||
expect(response.firstName).toBe('fake-ecm-first-name');
|
|
||||||
expect(response.lastName).toBe('fake-ecm-last-name');
|
|
||||||
expect(response.email).toBe('fakeEcm@ecmUser.com');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show ecm only last name when user first name is null ', async () => {
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmEditedUser));
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
openUserInfo();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
const ecmUsername = fixture.debugElement.query(By.css('#ecm-username'));
|
|
||||||
expect(ecmUsername).toBeDefined();
|
|
||||||
expect(ecmUsername).not.toBeNull();
|
|
||||||
expect(ecmUsername.nativeElement.textContent).not.toContain('fake-ecm-first-name');
|
|
||||||
expect(ecmUsername.nativeElement.textContent).not.toContain('null');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the username when showName attribute is true', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
expect(component.showName).toBeTruthy();
|
|
||||||
expect(element.querySelector('#adf-userinfo-ecm-name-display')).not.toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should hide the username when showName attribute is false', async () => {
|
|
||||||
component.showName = false;
|
|
||||||
await whenFixtureReady();
|
|
||||||
expect(element.querySelector('#adf-userinfo-ecm-name-display')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have the defined class to show the name on the right side', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
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 () => {
|
|
||||||
component.namePosition = 'left';
|
|
||||||
await whenFixtureReady();
|
|
||||||
expect(element.querySelector('#userinfo_container').classList).not.toContain('adf-userinfo-name-right');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('and has image', () => {
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
isOauthStub.and.returnValue(false);
|
|
||||||
isEcmLoggedInStub.and.returnValue(true);
|
|
||||||
isLoggedInStub.and.returnValue(true);
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUser));
|
|
||||||
await whenFixtureReady();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should get the ecm current user image from the service', async () => {
|
|
||||||
openUserInfo();
|
|
||||||
const loggedImage = fixture.debugElement.query(By.css('#logged-user-img'));
|
|
||||||
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(loggedImage).not.toBeNull();
|
|
||||||
expect(loggedImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the current user image if user has avatarId', (done) => {
|
|
||||||
openUserInfo();
|
|
||||||
const loggedImage = fixture.debugElement.query(By.css('#logged-user-img'));
|
|
||||||
component.ecmUser$.subscribe((response: EcmUserModel) => {
|
|
||||||
expect(response).toBeDefined();
|
|
||||||
expect(response.avatarId).toBe('fake-avatar-id');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(loggedImage).not.toBeNull();
|
|
||||||
expect(loggedImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should get the ecm user information from the service', async () => {
|
|
||||||
openUserInfo();
|
|
||||||
const ecmImage = fixture.debugElement.query(By.css('#ecm-user-detail-image'));
|
|
||||||
const ecmFullName = fixture.debugElement.query(By.css('#ecm-full-name'));
|
|
||||||
const ecmJobTitle = fixture.debugElement.query(By.css('#ecm-job-title-label'));
|
|
||||||
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(fixture.debugElement.query(By.css('#ecm-username'))).not.toBeNull();
|
|
||||||
expect(ecmImage).not.toBeNull();
|
|
||||||
expect(ecmImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
expect(ecmFullName.nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name');
|
|
||||||
expect(ecmJobTitle.nativeElement.textContent).toContain('USER_PROFILE.LABELS.ECM.JOB_TITLE');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('and has no image', () => {
|
|
||||||
|
|
||||||
beforeEach( async () => {
|
|
||||||
isOauthStub.and.returnValue(false);
|
|
||||||
isEcmLoggedInStub.and.returnValue(true);
|
|
||||||
isLoggedInStub.and.returnValue(true);
|
|
||||||
isBpmLoggedInStub.and.returnValue(false);
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUserNoImage));
|
|
||||||
await whenFixtureReady();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show N/A when the job title is null', () => {
|
|
||||||
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
|
|
||||||
imageButton.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
const ecmJobTitle = fixture.debugElement.query(By.css('#ecm-job-title'));
|
|
||||||
expect(ecmJobTitle).not.toBeNull();
|
|
||||||
expect(ecmJobTitle).not.toBeNull();
|
|
||||||
expect(ecmJobTitle.nativeElement.textContent).toContain('N/A');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show the tabs', () => {
|
|
||||||
const imageButton = element.querySelector<HTMLButtonElement>('[data-automation-id="user-initials-image"]');
|
|
||||||
imageButton.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
const tabHeader = fixture.debugElement.query(By.css('#tab-group-env'));
|
|
||||||
expect(tabHeader.classes['adf-hide-tab']).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the current user Initials if the user dose not have avatarId', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
const pipe = new InitialUsernamePipe(new FakeSanitizer());
|
|
||||||
const expected = pipe.transform({
|
|
||||||
id: 13,
|
|
||||||
firstName: 'Wilbur',
|
|
||||||
lastName: 'Adams',
|
|
||||||
email: 'wilbur@app.com'
|
|
||||||
});
|
|
||||||
expect(expected).toBe('<div data-automation-id="user-initials-image" class="">WA</div>');
|
|
||||||
component.ecmUser$.subscribe((response: EcmUserModel) => {
|
|
||||||
expect(response).toBeDefined();
|
|
||||||
expect(response.avatarId).toBeNull();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when user is logged on bpm', () => {
|
|
||||||
|
|
||||||
let getCurrentUserInfoStub: jasmine.Spy;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
isOauthStub.and.returnValue(false);
|
|
||||||
isBpmLoggedInStub.and.returnValue(true);
|
|
||||||
isLoggedInStub.and.returnValue(true);
|
|
||||||
isEcmLoggedInStub.and.returnValue(false);
|
|
||||||
getCurrentUserInfoStub = spyOn(bpmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeBpmUser));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fetch bpm userInfo', (done) => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(of(fakeBpmUser));
|
|
||||||
fixture.detectChanges();
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.bpmUser$.subscribe((response: BpmUserModel) => {
|
|
||||||
expect(response).toBeDefined();
|
|
||||||
expect(response.firstName).toBe('fake-bpm-first-name');
|
|
||||||
expect(response.lastName).toBe('fake-bpm-last-name');
|
|
||||||
expect(response.email).toBe('fakeBpm@fake.com');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show full name next the user image', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
const bpmUserName = fixture.debugElement.query(By.css('#bpm-username'));
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(bpmUserName).toBeDefined();
|
|
||||||
expect(bpmUserName).not.toBeNull();
|
|
||||||
expect(bpmUserName.nativeElement.innerHTML).toContain('fake-bpm-first-name fake-bpm-last-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should get the bpm current user image from the service', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(element.querySelector('#logged-user-img')).not.toBeNull();
|
|
||||||
expect(element.querySelector('#logged-user-img').getAttribute('src')).toContain(profilePictureUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show last name if first name is null', async () => {
|
|
||||||
const wrongBpmUser: BpmUserModel = new BpmUserModel({
|
|
||||||
firstName: null,
|
|
||||||
lastName: 'fake-last-name'
|
|
||||||
});
|
|
||||||
getCurrentUserInfoStub.and.returnValue(of(wrongBpmUser));
|
|
||||||
await whenFixtureReady();
|
|
||||||
const fullNameElement = (element.querySelector('#adf-userinfo-bpm-name-display'));
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('#adf-userinfo-bpm-name-display')).not.toBeNull();
|
|
||||||
expect(fullNameElement.textContent).toContain('fake-last-name');
|
|
||||||
expect(fullNameElement.textContent).not.toContain('fake-first-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show the tabs', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
await fixture.whenStable();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(fixture.debugElement.query(By.css('#tab-group-env')).classes['adf-hide-tab']).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when user is logged on bpm and ecm', () => {
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
isOauthStub.and.returnValue(false);
|
|
||||||
isEcmLoggedInStub.and.returnValue(true);
|
|
||||||
isBpmLoggedInStub.and.returnValue(true);
|
|
||||||
isLoggedInStub.and.returnValue(true);
|
|
||||||
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUser));
|
|
||||||
spyOn(bpmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeBpmUser));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should get the bpm user information from the service', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
const bpmTab = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'))[1];
|
|
||||||
bpmTab.triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
const bpmUsername = fixture.debugElement.query(By.css('#bpm-username'));
|
|
||||||
const bpmImage = fixture.debugElement.query(By.css('#bpm-user-detail-image'));
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
expect(bpmUsername).not.toBeNull();
|
|
||||||
expect(bpmImage).not.toBeNull();
|
|
||||||
expect(bpmImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
expect(bpmUsername.nativeElement.textContent).toContain('fake-bpm-first-name fake-bpm-last-name');
|
|
||||||
expect(fixture.debugElement.query(By.css('#bpm-tenant')).nativeElement.textContent).toContain('fake-tenant-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should get the ecm user information from the service', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
const ecmUsername = fixture.debugElement.query(By.css('#ecm-username'));
|
|
||||||
const ecmImage = fixture.debugElement.query(By.css('#ecm-user-detail-image'));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(ecmUsername).not.toBeNull();
|
|
||||||
expect(ecmImage).not.toBeNull();
|
|
||||||
expect(ecmImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
expect(fixture.debugElement.query(By.css('#ecm-full-name')).nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name');
|
|
||||||
expect(fixture.debugElement.query(By.css('#ecm-job-title')).nativeElement.textContent).toContain('job-ecm-test');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the ecm image if exists', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('#logged-user-img')).toBeDefined();
|
|
||||||
expect(element.querySelector('#logged-user-img').getAttribute('src')).toEqual(profilePictureUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the ecm initials if the ecm user has no image', async () => {
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUserNoImage));
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('ff');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the tabs for the env', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
const tabGroup = fixture.debugElement.query(By.css('#tab-group-env'));
|
|
||||||
const tabs = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'));
|
|
||||||
|
|
||||||
expect(tabGroup).not.toBeNull();
|
|
||||||
expect(tabGroup.classes['adf-hide-tab']).toBeFalsy();
|
|
||||||
expect(tabs.length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not close the menu when a tab is clicked', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
openUserInfo();
|
|
||||||
const tabGroup = fixture.debugElement.query(By.css('#tab-group-env'));
|
|
||||||
const tabs = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'));
|
|
||||||
|
|
||||||
expect(tabGroup).not.toBeNull();
|
|
||||||
tabs[1].triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(fixture.debugElement.query(By.css('#user-profile-lists'))).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when identity user is logged in', () => {
|
|
||||||
|
|
||||||
let getCurrentUserInfoStub: jasmine.Spy;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
isOauthStub.and.returnValue(true);
|
|
||||||
isLoggedInStub.and.returnValue(true);
|
|
||||||
isEcmLoggedInStub.and.returnValue(false);
|
|
||||||
getCurrentUserInfoStub = spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(identityUserMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the identity user initials if is not ecm user', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('ff');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should able to fetch identity userInfo', (done) => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
component.identityUser$.subscribe(response => {
|
|
||||||
expect(response).toBeDefined();
|
|
||||||
expect(response.firstName).toBe('fake-identity-first-name');
|
|
||||||
expect(response.lastName).toBe('fake-identity-last-name');
|
|
||||||
expect(response.email).toBe('fakeIdentity@email.com');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show full name next the user image', async () => {
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
const imageButton = element.querySelector<HTMLButtonElement>('#identity-user-image');
|
|
||||||
imageButton.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
|
||||||
const bpmUserName = fixture.debugElement.query(By.css('#identity-username'));
|
|
||||||
expect(bpmUserName).toBeDefined();
|
|
||||||
expect(bpmUserName).not.toBeNull();
|
|
||||||
expect(bpmUserName.nativeElement.textContent).toContain('fake-identity-first-name fake-identity-last-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show last name if first name is null', async () => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(identityUserWithOutFirstNameMock);
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(element.querySelector('#adf-userinfo-identity-name-display')).not.toBeNull();
|
|
||||||
expect(fullNameElement.textContent).toContain('fake-identity-last-name');
|
|
||||||
expect(fullNameElement.textContent).not.toContain('fake-identity-first-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show first name if it is null string', async () => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(identityUserWithOutFirstNameMock);
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(fullNameElement).toBeDefined();
|
|
||||||
expect(fullNameElement.textContent).toContain('fake-identity-last-name');
|
|
||||||
expect(fullNameElement.textContent).not.toContain('null');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show last name if it is null string', async () => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(identityUserWithOutLastNameMock);
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
const fullNameElement = element.querySelector('#adf-userinfo-identity-name-display');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
|
||||||
expect(fullNameElement).toBeDefined();
|
|
||||||
expect(fullNameElement.textContent).toContain('fake-identity-first-name');
|
|
||||||
expect(fullNameElement.textContent).not.toContain('null');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show initials if the user have avatar and provider is ECM', async () => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(identityUserWithOutLastNameMock);
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUser));
|
|
||||||
isEcmLoggedInStub.and.returnValue(true);
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
expect(element.querySelector('.adf-userinfo-pic')).toBeNull();
|
|
||||||
expect(element.querySelector('.adf-userinfo-profile-image')).toBeDefined();
|
|
||||||
expect(element.querySelector('.adf-userinfo-profile-image')).not.toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show initials if the user has avatar but provider is not ECM', async () => {
|
|
||||||
getCurrentUserInfoStub.and.returnValue(identityUserWithOutLastNameMock);
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUser));
|
|
||||||
isEcmLoggedInStub.and.returnValue(false);
|
|
||||||
await whenFixtureReady();
|
|
||||||
|
|
||||||
expect(element.querySelector('.adf-userinfo-pic')).not.toBeNull();
|
|
||||||
expect(element.querySelector('.adf-userinfo-profile-image')).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('kerberos', () => {
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
isOauthStub.and.returnValue(false);
|
|
||||||
isEcmLoggedInStub.and.returnValue(false);
|
|
||||||
isBpmLoggedInStub.and.returnValue(false);
|
|
||||||
isLoggedInStub.and.returnValue(false);
|
|
||||||
spyOn(authService, 'isKerberosEnabled').and.returnValue(true);
|
|
||||||
spyOn(authService, 'isALLProvider').and.returnValue(true);
|
|
||||||
spyOn(bpmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeBpmUser));
|
|
||||||
getCurrenEcmtUserInfoStub.and.returnValue(of(fakeEcmUser));
|
|
||||||
|
|
||||||
await whenFixtureReady();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the bpm user information', async () => {
|
|
||||||
openUserInfo();
|
|
||||||
const bpmTab = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'))[1];
|
|
||||||
bpmTab.triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
const bpmUsername = fixture.debugElement.query(By.css('#bpm-username'));
|
|
||||||
const bpmImage = fixture.debugElement.query(By.css('#bpm-user-detail-image'));
|
|
||||||
expect(bpmImage.properties.src).toContain(profilePictureUrl);
|
|
||||||
expect(bpmUsername.nativeElement.textContent).toContain('fake-bpm-first-name fake-bpm-last-name');
|
|
||||||
expect(fixture.debugElement.query(By.css('#bpm-tenant')).nativeElement.textContent).toContain('fake-tenant-name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the ecm user information', async () => {
|
|
||||||
openUserInfo();
|
|
||||||
const ecmTab = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'))[0];
|
|
||||||
ecmTab.triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
await fixture.whenStable();
|
|
||||||
expect(fixture.debugElement.query(By.css('#ecm-full-name')).nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name');
|
|
||||||
expect(fixture.debugElement.query(By.css('#ecm-job-title')).nativeElement.textContent).toContain('job-ecm-test');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,200 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright 2019 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 {
|
|
||||||
Meta,
|
|
||||||
moduleMetadata,
|
|
||||||
Story
|
|
||||||
} from '@storybook/angular';
|
|
||||||
import { CoreStoryModule } from '../../testing/core.story.module';
|
|
||||||
import { UserInfoComponent } from './user-info.component';
|
|
||||||
import { UserInfoModule } from '../userinfo.module';
|
|
||||||
import { PeopleContentService } from './../../services/people-content.service';
|
|
||||||
import { BpmUserService } from './../../services/bpm-user.service';
|
|
||||||
import { IdentityUserService } from '../../auth/services/identity-user.service';
|
|
||||||
import { AuthenticationService } from '../../auth/services/authentication.service';
|
|
||||||
import { AuthenticationServiceMock } from './mocks/authentication.service.mock';
|
|
||||||
import {
|
|
||||||
BpmUserServiceMock,
|
|
||||||
IdentityUserServiceMock,
|
|
||||||
PeopleContentServiceMock
|
|
||||||
} from './mocks/user.service.mock';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
component: UserInfoComponent,
|
|
||||||
title: 'Core/User Info/User Info',
|
|
||||||
decorators: [
|
|
||||||
moduleMetadata({
|
|
||||||
imports: [CoreStoryModule, UserInfoModule],
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: PeopleContentService,
|
|
||||||
useClass: PeopleContentServiceMock
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: BpmUserService,
|
|
||||||
useClass: BpmUserServiceMock
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: IdentityUserService,
|
|
||||||
useClass: IdentityUserServiceMock
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: AuthenticationService,
|
|
||||||
useClass: AuthenticationServiceMock
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
],
|
|
||||||
argTypes: {
|
|
||||||
menuPositionX: {
|
|
||||||
description:
|
|
||||||
'Material Angular menu horizontal position in regard to User Info',
|
|
||||||
control: 'radio',
|
|
||||||
options: ['before', 'after'],
|
|
||||||
defaultValue: 'after',
|
|
||||||
table: {
|
|
||||||
type: { summary: 'MenuPositionX' },
|
|
||||||
defaultValue: { summary: 'after' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
menuPositionY: {
|
|
||||||
description:
|
|
||||||
'Material Angular menu vertical position in regard to User Info',
|
|
||||||
control: 'radio',
|
|
||||||
options: ['above', 'below'],
|
|
||||||
defaultValue: 'below',
|
|
||||||
table: {
|
|
||||||
type: { summary: 'MenuPositionY' },
|
|
||||||
defaultValue: { summary: 'below' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showName: {
|
|
||||||
description:
|
|
||||||
'Determines if name should be shown next to user avatar',
|
|
||||||
control: 'boolean',
|
|
||||||
defaultValue: true,
|
|
||||||
table: {
|
|
||||||
type: { summary: 'boolean' },
|
|
||||||
defaultValue: { summary: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
namePosition: {
|
|
||||||
description: 'User name position in regard to avatar',
|
|
||||||
control: 'radio',
|
|
||||||
options: ['left', 'right'],
|
|
||||||
defaultValue: 'right',
|
|
||||||
table: {
|
|
||||||
type: { summary: 'string' },
|
|
||||||
defaultValue: { summary: 'right' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ecmBackgroundImage: {
|
|
||||||
description: 'Menu background banner image for ACS users',
|
|
||||||
control: {
|
|
||||||
disable: true
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
type: { summary: 'string' },
|
|
||||||
defaultValue: { summary: './assets/images/ecm-background.png' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bpmBackgroundImage: {
|
|
||||||
description: 'Menu background banner image for APS users',
|
|
||||||
control: {
|
|
||||||
disable: true
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
type: {
|
|
||||||
summary: 'string'
|
|
||||||
},
|
|
||||||
defaultValue: {
|
|
||||||
summary: './assets/images/bpm-background.png'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} as Meta;
|
|
||||||
|
|
||||||
const template: Story<UserInfoComponent> = (args: UserInfoComponent) => ({
|
|
||||||
props: args
|
|
||||||
});
|
|
||||||
|
|
||||||
export const loginWithSSO = template.bind({});
|
|
||||||
loginWithSSO.decorators = [
|
|
||||||
moduleMetadata({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: 'MODE',
|
|
||||||
useValue: 'default'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
];
|
|
||||||
loginWithSSO.parameters = { layout: 'centered' };
|
|
||||||
|
|
||||||
export const loginWithSSOAndACS = template.bind({});
|
|
||||||
loginWithSSOAndACS.decorators = [
|
|
||||||
moduleMetadata({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: 'MODE',
|
|
||||||
useValue: 'defaultEcm'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
];
|
|
||||||
loginWithSSOAndACS.parameters = { layout: 'centered' };
|
|
||||||
|
|
||||||
export const loginWithAPSAndACS = template.bind({});
|
|
||||||
loginWithAPSAndACS.decorators = [
|
|
||||||
moduleMetadata({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: 'MODE',
|
|
||||||
useValue: 'all'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
];
|
|
||||||
loginWithAPSAndACS.parameters = { layout: 'centered' };
|
|
||||||
|
|
||||||
export const loginWithACS = template.bind({});
|
|
||||||
loginWithACS.decorators = [
|
|
||||||
moduleMetadata({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: 'MODE',
|
|
||||||
useValue: 'ecm'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
];
|
|
||||||
loginWithACS.parameters = { layout: 'centered' };
|
|
||||||
|
|
||||||
export const loginWithAPS = template.bind({});
|
|
||||||
loginWithAPS.decorators = [
|
|
||||||
moduleMetadata({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: 'MODE',
|
|
||||||
useValue: 'bpm'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
];
|
|
||||||
loginWithAPS.parameters = { layout: 'centered' };
|
|
@@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
export * from './lib/about/index';
|
export * from './lib/about/index';
|
||||||
export * from './lib/viewer/index';
|
export * from './lib/viewer/index';
|
||||||
export * from './lib/userinfo/index';
|
|
||||||
export * from './lib/toolbar/index';
|
export * from './lib/toolbar/index';
|
||||||
export * from './lib/pagination/index';
|
export * from './lib/pagination/index';
|
||||||
export * from './lib/login/index';
|
export * from './lib/login/index';
|
||||||
export * from './lib/language-menu/index';
|
export * from './lib/language-menu/index';
|
||||||
export * from './lib/info-drawer/index';
|
export * from './lib/info-drawer/index';
|
||||||
|
export * from './lib/identity-user-info/index';
|
||||||
export * from './lib/datatable/data-column/index';
|
export * from './lib/datatable/data-column/index';
|
||||||
export * from './lib/datatable/index';
|
export * from './lib/datatable/index';
|
||||||
export * from './lib/context-menu/index';
|
export * from './lib/context-menu/index';
|
||||||
|
18
lib/process-services/src/lib/process-user-info/index.ts
Normal file
18
lib/process-services/src/lib/process-user-info/index.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './public-api';
|
@@ -0,0 +1,109 @@
|
|||||||
|
<div
|
||||||
|
id="userinfo_container"
|
||||||
|
[class.adf-userinfo-name-right]="showOnRight"
|
||||||
|
(keyup)="onKeyPress($event)"
|
||||||
|
class="adf-userinfo-container"
|
||||||
|
*ngIf="canShow"
|
||||||
|
>
|
||||||
|
<span *ngIf="showName" id="adf-userinfo-bpm-name-display" class="adf-userinfo-name">
|
||||||
|
{{bpmUser | fullName}}
|
||||||
|
</span>
|
||||||
|
<button mat-button [matMenuTriggerFor]="menu" class="adf-userinfo-menu_button"
|
||||||
|
data-automation-id="adf-user-profile">
|
||||||
|
<div class="adf-userinfo-button-profile" id="user-profile">
|
||||||
|
<div *ngIf="ecmUser; else showBpmUserImage" id="ecm-user-image">
|
||||||
|
<div *ngIf="ecmUser.avatarId; else initialTemplate" class="adf-userinfo-profile-container">
|
||||||
|
<img id="logged-user-img" [src]="getEcmAvatar(ecmUser.avatarId)" alt="user-info-profile-button"
|
||||||
|
class="adf-userinfo-profile-image"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div [outerHTML]="ecmUser | usernameInitials:'adf-userinfo-pic'"></div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
<ng-template #showBpmUserImage>
|
||||||
|
<div *ngIf="bpmUser" id="bpm-user-image">
|
||||||
|
<div *ngIf="bpmUser.pictureId; else initialTemplate" class="adf-userinfo-profile-container">
|
||||||
|
<img id="logged-user-img" [src]="getBpmUserImage()" alt="user-info-profile-button"
|
||||||
|
class="adf-userinfo-profile-image"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div [outerHTML]="bpmUser | usernameInitials:'adf-userinfo-pic'"></div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu" id="user-profile-lists" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
|
||||||
|
[overlapTrigger]="false" class="adf-userinfo-menu">
|
||||||
|
<mat-tab-group id="tab-group-env" (click)="stopClosing($event)" selectedIndex="0" role="menuitem"
|
||||||
|
class="adf-userinfo-tab" [class.adf-hide-tab]="!ecmUser">
|
||||||
|
<mat-tab label="{{ 'USER_PROFILE.TAB.CS' | translate }}" role="dialog"
|
||||||
|
*ngIf="mode===userInfoMode.ALL">
|
||||||
|
<mat-card class="adf-userinfo-card" *ngIf="ecmUser">
|
||||||
|
<mat-card-header class="adf-userinfo-card-header"
|
||||||
|
[style.background-image]="'url(' + ecmBackgroundImage + ')'">
|
||||||
|
<div *ngIf="ecmUser.avatarId; else initialTemplate"
|
||||||
|
class="adf-userinfo-profile-container adf-hide-small">
|
||||||
|
<img class="adf-userinfo-profile-picture" id="ecm-user-detail-image"
|
||||||
|
alt="ecm-profile-image" [src]="getEcmAvatar(ecmUser.avatarId)"/>
|
||||||
|
</div>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div
|
||||||
|
[outerHTML]="ecmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<div class="adf-userinfo-title" id="ecm-username">{{ecmUser | fullName}}</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="adf-userinfo-supporting-text">
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="ecm-full-name"
|
||||||
|
class="adf-userinfo__detail-title">{{ecmUser | fullName}}</span>
|
||||||
|
<span class="adf-userinfo__detail-profile" id="ecm-email"> {{ecmUser.email}} </span>
|
||||||
|
</div>
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span class="adf-userinfo__secondary-info" id="ecm-job-title-label">
|
||||||
|
{{ 'USER_PROFILE.LABELS.ECM.JOB_TITLE' | translate }}
|
||||||
|
<span id="ecm-job-title"
|
||||||
|
class="adf-userinfo__detail-profile"> {{ ecmUser.jobTitle ? ecmUser.jobTitle : 'N/A' }} </span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab id="bpm-panel" label="{{ 'USER_PROFILE.TAB.PS' | translate }}" role="dialog"
|
||||||
|
*ngIf="mode===userInfoMode.PROCESS || mode===userInfoMode.ALL">
|
||||||
|
<mat-card class="adf-userinfo-card">
|
||||||
|
<mat-card-header class="adf-userinfo-card-header"
|
||||||
|
[style.background-image]="'url(' + bpmBackgroundImage + ')'">
|
||||||
|
<img *ngIf="bpmUser.pictureId; else initialTemplate"
|
||||||
|
class="adf-userinfo-profile-picture adf-hide-small" id="bpm-user-detail-image"
|
||||||
|
alt="bpm-profile-image" [src]="getBpmUserImage()"/>
|
||||||
|
<ng-template #initialTemplate>
|
||||||
|
<div
|
||||||
|
[outerHTML]="bpmUser | usernameInitials:'adf-userinfo-profile-initials adf-hide-small'"></div>
|
||||||
|
</ng-template>
|
||||||
|
<div class="adf-userinfo-title" id="bpm-username">{{bpmUser | fullName}}</div>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="adf-userinfo-supporting-text">
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="bpm-full-name"
|
||||||
|
class="adf-userinfo__detail-title">{{ bpmUser | fullName }}</span>
|
||||||
|
<span class="adf-userinfo__detail-profile" id="bpm-email"> {{bpmUser.email}} </span>
|
||||||
|
</div>
|
||||||
|
<div class="adf-userinfo-detail">
|
||||||
|
<span id="bpm-tenant" class="adf-userinfo__secondary-info">
|
||||||
|
{{ 'USER_PROFILE.LABELS.BPM.TENANT' | translate }}
|
||||||
|
<span
|
||||||
|
class="adf-userinfo__detail-profile">{{ bpmUser.tenantName ? bpmUser.tenantName : '' }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
@@ -0,0 +1,188 @@
|
|||||||
|
.adf {
|
||||||
|
&-userinfo-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-name-right {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-name {
|
||||||
|
padding: 0 5px;
|
||||||
|
|
||||||
|
@media screen and (max-width: 959px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-pic {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 100px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: var(--theme-adf-picture-1-font-size);
|
||||||
|
text-transform: uppercase;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-image {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 90%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-right: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-container {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-menu_button.mat-button {
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: 90%;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-tab .mat-tab-header {
|
||||||
|
align-self: center;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-tab .mat-tab-label {
|
||||||
|
flex: auto;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: 48px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-card-header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: stretch;
|
||||||
|
line-height: normal;
|
||||||
|
height: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-card.mat-card {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-supporting-text {
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 32px;
|
||||||
|
column-count: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
@media screen and (max-width: 599px) {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-title {
|
||||||
|
font-size: var(--theme-title-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__detail-profile {
|
||||||
|
align-items: flex-start;
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__detail-title {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: var(--theme-subheading-2-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
line-height: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo__secondary-info {
|
||||||
|
font-size: var(--theme-body-1-font-size);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 18px;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-picture {
|
||||||
|
background: var(--adf-user-info-color);
|
||||||
|
background-size: cover;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-profile-initials {
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-size: cover;
|
||||||
|
background-color: var(--adf-user-info-color);
|
||||||
|
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 {
|
||||||
|
display: inline-block;
|
||||||
|
border: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-userinfo-detail {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-hide-tab .mat-tab-label-active {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-device-width: 480px) {
|
||||||
|
.mat-menu-panel.adf-userinfo-menu {
|
||||||
|
max-height: 450px;
|
||||||
|
min-width: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-menu-panel.adf-userinfo-menu .mat-menu-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
@@ -0,0 +1,228 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 {
|
||||||
|
CoreTestingModule,
|
||||||
|
fakeBpmUser,
|
||||||
|
BpmUserModel,
|
||||||
|
setupTestBed,
|
||||||
|
fakeEcmUser,
|
||||||
|
fakeEcmUserNoImage,
|
||||||
|
UserInfoMode
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { ProcessUserInfoComponent } from './process-user-info.component';
|
||||||
|
|
||||||
|
describe('ProcessUserInfoComponent', () => {
|
||||||
|
const profilePictureUrl = 'alfresco-logo.svg';
|
||||||
|
|
||||||
|
let component: ProcessUserInfoComponent;
|
||||||
|
let fixture: ComponentFixture<ProcessUserInfoComponent>;
|
||||||
|
let element: HTMLElement;
|
||||||
|
|
||||||
|
const openUserInfo = () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const imageButton = element.querySelector<HTMLButtonElement>('#logged-user-img');
|
||||||
|
imageButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
const whenFixtureReady = async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule,
|
||||||
|
MatMenuModule
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProcessUserInfoComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
|
||||||
|
spyOn(window, 'requestAnimationFrame').and.returnValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show any image if the user is not logged in', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#logged-user-img')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT have users immediately after ngOnInit', () => {
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#ecm_username')).toBeNull();
|
||||||
|
expect(element.querySelector('#bpm_username')).toBeNull();
|
||||||
|
expect(element.querySelector('#user-profile-lists')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when user is logged on bpm', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
component.bpmUser = fakeBpmUser;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show full name next the user image', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
const bpmUserName = fixture.debugElement.query(By.css('#bpm-username'));
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(bpmUserName).toBeDefined();
|
||||||
|
expect(bpmUserName).not.toBeNull();
|
||||||
|
expect(bpmUserName.nativeElement.innerHTML).toContain('fake-bpm-first-name fake-bpm-last-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the bpm current user image from the service', async () => {
|
||||||
|
spyOn(component, 'getBpmUserImage').and.returnValue(profilePictureUrl);
|
||||||
|
await whenFixtureReady();
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(element.querySelector('#logged-user-img')).not.toBeNull();
|
||||||
|
expect(element.querySelector('#logged-user-img').getAttribute('src')).toContain(profilePictureUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show last name if first name is null', async () => {
|
||||||
|
const wrongBpmUser: BpmUserModel = new BpmUserModel({
|
||||||
|
firstName: null,
|
||||||
|
lastName: 'fake-last-name'
|
||||||
|
});
|
||||||
|
component.bpmUser = wrongBpmUser;
|
||||||
|
await whenFixtureReady();
|
||||||
|
const fullNameElement = (element.querySelector('#adf-userinfo-bpm-name-display'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#adf-userinfo-bpm-name-display')).not.toBeNull();
|
||||||
|
expect(fullNameElement.textContent).toContain('fake-last-name');
|
||||||
|
expect(fullNameElement.textContent).not.toContain('fake-first-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show the tabs', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
await fixture.whenStable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.query(By.css('#tab-group-env')).classes['adf-hide-tab']).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when user is logged on bpm and ecm', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
component.bpmUser = fakeBpmUser;
|
||||||
|
component.ecmUser = fakeEcmUser as any;
|
||||||
|
component.isLoggedIn = true;
|
||||||
|
component.mode = UserInfoMode.ALL;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the tabs', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
await fixture.whenStable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.query(By.css('#tab-group-env')).classes['adf-hide-tab']).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the bpm user information', async () => {
|
||||||
|
spyOn(component, 'getBpmUserImage').and.returnValue(profilePictureUrl);
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
const bpmTab = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'))[1];
|
||||||
|
bpmTab.triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
const bpmUsername = fixture.debugElement.query(By.css('#bpm-username'));
|
||||||
|
const bpmImage = fixture.debugElement.query(By.css('#bpm-user-detail-image'));
|
||||||
|
expect(element.querySelector('#userinfo_container')).not.toBeNull();
|
||||||
|
expect(bpmUsername).not.toBeNull();
|
||||||
|
expect(bpmImage).not.toBeNull();
|
||||||
|
expect(bpmImage.properties.src).toContain(profilePictureUrl);
|
||||||
|
expect(bpmUsername.nativeElement.textContent).toContain('fake-bpm-first-name fake-bpm-last-name');
|
||||||
|
expect(fixture.debugElement.query(By.css('#bpm-tenant')).nativeElement.textContent).toContain('fake-tenant-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the ecm user information', async () => {
|
||||||
|
spyOn(component, 'getEcmAvatar').and.returnValue(profilePictureUrl);
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
const ecmUsername = fixture.debugElement.query(By.css('#ecm-username'));
|
||||||
|
const ecmImage = fixture.debugElement.query(By.css('#ecm-user-detail-image'));
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(ecmUsername).not.toBeNull();
|
||||||
|
expect(ecmImage).not.toBeNull();
|
||||||
|
expect(ecmImage.properties.src).toContain(profilePictureUrl);
|
||||||
|
expect(fixture.debugElement.query(By.css('#ecm-full-name')).nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name');
|
||||||
|
expect(fixture.debugElement.query(By.css('#ecm-job-title')).nativeElement.textContent).toContain('job-ecm-test');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the ecm image if exists', async () => {
|
||||||
|
spyOn(component, 'getEcmAvatar').and.returnValue(profilePictureUrl);
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('#logged-user-img')).toBeDefined();
|
||||||
|
expect(element.querySelector('#logged-user-img').getAttribute('src')).toEqual(profilePictureUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the ecm initials if the ecm user has no image', async () => {
|
||||||
|
component.ecmUser = fakeEcmUserNoImage as any;
|
||||||
|
await whenFixtureReady();
|
||||||
|
|
||||||
|
expect(element.querySelector('#userinfo_container')).toBeDefined();
|
||||||
|
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('ff');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the tabs for the env', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
const tabGroup = fixture.debugElement.query(By.css('#tab-group-env'));
|
||||||
|
const tabs = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'));
|
||||||
|
|
||||||
|
expect(tabGroup).not.toBeNull();
|
||||||
|
expect(tabGroup.classes['adf-hide-tab']).toBeFalsy();
|
||||||
|
expect(tabs.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not close the menu when a tab is clicked', async () => {
|
||||||
|
await whenFixtureReady();
|
||||||
|
openUserInfo();
|
||||||
|
const tabGroup = fixture.debugElement.query(By.css('#tab-group-env'));
|
||||||
|
|
||||||
|
const tabs = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'));
|
||||||
|
|
||||||
|
expect(tabGroup).not.toBeNull();
|
||||||
|
tabs[1].triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.query(By.css('#user-profile-lists'))).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,112 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { BpmUserModel, BpmUserService, EcmUserModel, PeopleContentService, UserInfoMode } from '@alfresco/adf-core';
|
||||||
|
import { Component, Input, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-process-user-info',
|
||||||
|
templateUrl: './process-user-info.component.html',
|
||||||
|
styleUrls: ['./process-user-info.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class ProcessUserInfoComponent implements OnDestroy {
|
||||||
|
|
||||||
|
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
bpmUser: BpmUserModel;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
ecmUser: EcmUserModel;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
mode: UserInfoMode = UserInfoMode.PROCESS;
|
||||||
|
|
||||||
|
/** Custom path for the background banner image for APS users. */
|
||||||
|
@Input()
|
||||||
|
bpmBackgroundImage: string = './assets/images/bpm-background.png';
|
||||||
|
|
||||||
|
/** Custom path for the background banner image for ACS users. */
|
||||||
|
@Input()
|
||||||
|
ecmBackgroundImage: string = './assets/images/ecm-background.png';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `before` or `after`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionX: MenuPositionX = 'after';
|
||||||
|
|
||||||
|
/** Custom choice for opening the menu at the bottom. Can be `above` or `below`. */
|
||||||
|
@Input()
|
||||||
|
menuPositionY: MenuPositionY = 'below';
|
||||||
|
|
||||||
|
/** Shows/hides the username next to the user info button. */
|
||||||
|
@Input()
|
||||||
|
showName: boolean = true;
|
||||||
|
|
||||||
|
/** When the username is shown, this defines its position relative to the user info button.
|
||||||
|
* Can be `right` or `left`.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
namePosition: string = 'right';
|
||||||
|
|
||||||
|
userInfoMode = UserInfoMode;
|
||||||
|
|
||||||
|
private destroy$ = new Subject();
|
||||||
|
|
||||||
|
constructor(private bpmUserService: BpmUserService, private peopleContentService: PeopleContentService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next(true);
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPress(event: KeyboardEvent) {
|
||||||
|
this.closeUserModal(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private closeUserModal($event: KeyboardEvent) {
|
||||||
|
if ($event.keyCode === 27) {
|
||||||
|
this.trigger.closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopClosing(event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
getBpmUserImage(): string {
|
||||||
|
return this.bpmUserService.getCurrentUserProfileImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
getEcmAvatar(avatarId: string): string {
|
||||||
|
return this.peopleContentService.getUserProfileImage(avatarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOnRight(): boolean {
|
||||||
|
return this.namePosition === 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
get canShow(): boolean {
|
||||||
|
return this.isLoggedIn && !!this.bpmUser && !!this.mode;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ProcessUserInfoComponent } from './process-user-info.component';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PipeModule } from '@alfresco/adf-core';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [ProcessUserInfoComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatCardModule,
|
||||||
|
TranslateModule,
|
||||||
|
PipeModule
|
||||||
|
],
|
||||||
|
exports: [ProcessUserInfoComponent]
|
||||||
|
})
|
||||||
|
export class ProcessUserInfoModule {}
|
20
lib/process-services/src/lib/process-user-info/public-api.ts
Normal file
20
lib/process-services/src/lib/process-user-info/public-api.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './process-user-info.component';
|
||||||
|
|
||||||
|
export * from './process-user-info.module';
|
@@ -32,6 +32,7 @@ import { FormModule } from './form/form.module';
|
|||||||
import { ProcessFormRenderingService } from './form/process-form-rendering.service';
|
import { ProcessFormRenderingService } from './form/process-form-rendering.service';
|
||||||
import { ProcessServicesPipeModule } from './pipes/process-services-pipe.module';
|
import { ProcessServicesPipeModule } from './pipes/process-services-pipe.module';
|
||||||
import { TaskCommentsModule } from './task-comments/task-comments.module';
|
import { TaskCommentsModule } from './task-comments/task-comments.module';
|
||||||
|
import { ProcessUserInfoModule } from './process-user-info/process-user-info.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -45,6 +46,7 @@ import { TaskCommentsModule } from './task-comments/task-comments.module';
|
|||||||
TaskListModule,
|
TaskListModule,
|
||||||
TaskCommentsModule,
|
TaskCommentsModule,
|
||||||
AppsListModule,
|
AppsListModule,
|
||||||
|
ProcessUserInfoModule,
|
||||||
AttachmentModule,
|
AttachmentModule,
|
||||||
PeopleModule,
|
PeopleModule,
|
||||||
FormModule,
|
FormModule,
|
||||||
@@ -69,6 +71,7 @@ import { TaskCommentsModule } from './task-comments/task-comments.module';
|
|||||||
TaskListModule,
|
TaskListModule,
|
||||||
TaskCommentsModule,
|
TaskCommentsModule,
|
||||||
AppsListModule,
|
AppsListModule,
|
||||||
|
ProcessUserInfoModule,
|
||||||
AttachmentModule,
|
AttachmentModule,
|
||||||
PeopleModule,
|
PeopleModule,
|
||||||
FormModule,
|
FormModule,
|
||||||
|
@@ -19,6 +19,7 @@ export * from './lib/process-list/index';
|
|||||||
export * from './lib/task-list/index';
|
export * from './lib/task-list/index';
|
||||||
export * from './lib/app-list/index';
|
export * from './lib/app-list/index';
|
||||||
export * from './lib/attachment/index';
|
export * from './lib/attachment/index';
|
||||||
|
export * from './lib/process-user-info/index';
|
||||||
export * from './lib/process-comments/index';
|
export * from './lib/process-comments/index';
|
||||||
export * from './lib/people/index';
|
export * from './lib/people/index';
|
||||||
export * from './lib/form/index';
|
export * from './lib/form/index';
|
||||||
|
Reference in New Issue
Block a user