This commit is contained in:
Adina Țeudan 2021-10-20 02:25:54 +03:00
parent be9988ca11
commit c71a3e65b6
8 changed files with 56 additions and 27 deletions

View File

@ -76,7 +76,11 @@
</div> </div>
<div class="cell user-column"> <div class="cell user-column">
<redaction-initials-avatar [user]="dossierTemplate.createdBy" [withName]="true"></redaction-initials-avatar> <redaction-initials-avatar
[defaultValue]="'unknown' | translate"
[user]="dossierTemplate.createdBy"
[withName]="true"
></redaction-initials-avatar>
</div> </div>
<div class="cell small-label"> <div class="cell small-label">

View File

@ -1,5 +1,5 @@
<button [class.overlay]="showDot" mat-button> <button [class.overlay]="showDot" mat-button>
<redaction-initials-avatar [user]="userId" [withName]="true" size="small"></redaction-initials-avatar> <redaction-initials-avatar [user]="userService.currentUser$ | async" [withName]="true" size="small"></redaction-initials-avatar>
<mat-icon svgIcon="iqser:arrow-down"></mat-icon> <mat-icon svgIcon="iqser:arrow-down"></mat-icon>
</button> </button>
<div *ngIf="showDot" class="dot"></div> <div *ngIf="showDot" class="dot"></div>

View File

@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { UserService } from '@services/user.service';
@Component({ @Component({
selector: 'redaction-user-button', selector: 'redaction-user-button',
@ -9,4 +10,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
export class UserButtonComponent { export class UserButtonComponent {
@Input() userId: string; @Input() userId: string;
@Input() showDot = false; @Input() showDot = false;
constructor(readonly userService: UserService) {}
} }

View File

@ -4,7 +4,7 @@
[matTooltipPosition]="tooltipPosition" [matTooltipPosition]="tooltipPosition"
[matTooltip]="userName" [matTooltip]="userName"
> >
{{ _user | name: { showInitials: true, defaultValue: ('initials-avatar.unassigned' | translate) } }} {{ _user | name: { showInitials: true } }}
</div> </div>
<div *ngIf="withName" [class.disabled]="disabled" class="clamp-2 username"> <div *ngIf="withName" [class.disabled]="disabled" class="clamp-2 username">
{{ userName }} {{ userName }}

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnDestroy } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { UserService } from '@services/user.service'; import { UserService } from '@services/user.service';
import { AutoUnsubscribe } from '@iqser/common-ui'; import { AutoUnsubscribe } from '@iqser/common-ui';
import { User } from '@models/user'; import { User } from '@models/user';
@ -11,18 +11,16 @@ import { NamePipeOptions } from '@shared/pipes/name.pipe';
styleUrls: ['./initials-avatar.component.scss'], styleUrls: ['./initials-avatar.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChanges, OnDestroy { export class InitialsAvatarComponent extends AutoUnsubscribe implements OnInit, OnChanges, OnDestroy {
@Input() color = 'lightgray'; @Input() color = 'lightgray';
@Input() size: 'small' | 'large' = 'small'; @Input() size: 'small' | 'large' = 'small';
@Input() withName = false; @Input() withName = false;
@Input() showYou = false; @Input() showYou = false;
@Input() tooltipPosition: 'below' | 'above' = 'above'; @Input() tooltipPosition: 'below' | 'above' = 'above';
@Input() defaultValue = this._translateService.instant('initials-avatar.unassigned');
colorClass: string; colorClass: string;
readonly namePipeOptions: NamePipeOptions = { namePipeOptions: NamePipeOptions;
showYou: this.showYou,
defaultValue: this._translateService.instant('initials-avatar.unassigned'),
};
constructor(private readonly _userService: UserService, private readonly _translateService: TranslateService) { constructor(private readonly _userService: UserService, private readonly _translateService: TranslateService) {
super(); super();
@ -44,7 +42,7 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange
} }
get disabled(): boolean { get disabled(): boolean {
return this._user && !this._user.isActive; return this._user && !this._isSystemUser && !this._user.isActive;
} }
get isCurrentUser(): boolean { get isCurrentUser(): boolean {
@ -65,13 +63,23 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange
return `${this.color}-dark`; return `${this.color}-dark`;
} }
private get _isSystemUser() {
return this._user?.id?.toLowerCase() === 'system';
}
ngOnChanges(): void { ngOnChanges(): void {
const isSystemUser = this._user?.id?.toLowerCase() === 'system'; if (this._isSystemUser) {
if (isSystemUser) {
this.colorClass = 'primary-white primary'; this.colorClass = 'primary-white primary';
return; return;
} }
this.colorClass = this._colorClass; this.colorClass = this._colorClass;
} }
ngOnInit(): void {
this.namePipeOptions = {
showYou: this.showYou,
defaultValue: this.defaultValue,
};
}
} }

View File

@ -36,12 +36,13 @@ export class NamePipe implements PipeTransform {
transform(value?: User | string, options = this._defaultOptions): string { transform(value?: User | string, options = this._defaultOptions): string {
let name; let name;
if (!value || !isSystemUser(value)) {
name = this._getName(value) || options?.defaultValue; if (!value && options?.showInitials) {
} else { return '?';
name = 'System';
} }
name = this._getName(value) || options?.defaultValue;
if (options?.showYou && this._isCurrentUser(value)) { if (options?.showYou && this._isCurrentUser(value)) {
name = `${name} (${this._translateService.instant('initials-avatar.you')})`; name = `${name} (${this._translateService.instant('initials-avatar.you')})`;
} }

View File

@ -4,7 +4,7 @@ import jwt_decode from 'jwt-decode';
import { CreateUserRequest, IUser, ResetPasswordRequest, UpdateMyProfileRequest, UpdateProfileRequest } from '@redaction/red-ui-http'; import { CreateUserRequest, IUser, ResetPasswordRequest, UpdateMyProfileRequest, UpdateProfileRequest } from '@redaction/red-ui-http';
import { wipeCaches } from '@redaction/red-cache'; import { wipeCaches } from '@redaction/red-cache';
import { BASE_HREF } from '../tokens'; import { BASE_HREF } from '../tokens';
import { Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { User } from '@models/user'; import { User } from '@models/user';
import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
@ -21,18 +21,20 @@ export interface ProfileModel {
providedIn: 'root', providedIn: 'root',
}) })
export class UserService extends EntitiesService<User, IUser> { export class UserService extends EntitiesService<User, IUser> {
readonly currentUser$: Observable<User>;
private readonly _currentUser$ = new BehaviorSubject<User>(null);
constructor( constructor(
protected readonly _injector: Injector, protected readonly _injector: Injector,
@Inject(BASE_HREF) private readonly _baseHref: string, @Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _keycloakService: KeycloakService, private readonly _keycloakService: KeycloakService,
) { ) {
super(_injector, User, 'user'); super(_injector, User, 'user');
this.currentUser$ = this._currentUser$.asObservable();
} }
private _currentUser: User;
get currentUser(): User { get currentUser(): User {
return this._currentUser; return this._currentUser$.value;
} }
get managerUsers(): User[] { get managerUsers(): User[] {
@ -49,7 +51,7 @@ export class UserService extends EntitiesService<User, IUser> {
} }
loadAll() { loadAll() {
const all$ = this._currentUser.isUserAdmin ? this.getUsers() : this.getUsers(true); const all$ = this.currentUser.isUserAdmin ? this.getUsers() : this.getUsers(true);
return all$.pipe( return all$.pipe(
mapEach(user => new User(user, user.roles, user.userId)), mapEach(user => new User(user, user.roles, user.userId)),
@ -59,16 +61,20 @@ export class UserService extends EntitiesService<User, IUser> {
async loadCurrentUser() { async loadCurrentUser() {
const token = await this._keycloakService.getToken(); const token = await this._keycloakService.getToken();
const decoded: { sub: string } = jwt_decode(token); const decoded = jwt_decode(token);
const userId = decoded.sub; const userId = (<{ sub: string }>decoded).sub;
this._currentUser = new User(await this._keycloakService.loadUserProfile(true), this._keycloakService.getUserRoles(true), userId);
const roles = this._keycloakService.getUserRoles(true).filter(role => role.startsWith('RED_'));
this.replace(new User(await this._keycloakService.loadUserProfile(true), roles, userId));
this._currentUser$.next(this.find(userId));
} }
getNameForId(userId: string): string | undefined { getNameForId(userId: string): string | undefined {
return this.find(userId)?.name; return this.find(userId)?.name;
} }
hasAnyRole(requiredRoles: string[], user = this._currentUser): boolean { hasAnyRole(requiredRoles: string[], user = this.currentUser): boolean {
if (requiredRoles?.length > 0) { if (requiredRoles?.length > 0) {
for (const role of requiredRoles) { for (const role of requiredRoles) {
if (user.roles.indexOf(role) >= 0) { if (user.roles.indexOf(role) >= 0) {
@ -111,4 +117,11 @@ export class UserService extends EntitiesService<User, IUser> {
const queryParams = userIds.map<QueryParam>(userId => ({ key: 'userId', value: userId })); const queryParams = userIds.map<QueryParam>(userId => ({ key: 'userId', value: userId }));
return super.delete(userIds, this._defaultModelPath, queryParams); return super.delete(userIds, this._defaultModelPath, queryParams);
} }
find(id: string): User | undefined {
if (id?.toLowerCase() === 'system') {
return new User({ email: 'System' }, [], 'system');
}
return super.find(id);
}
} }

View File

@ -19,11 +19,11 @@ export class AppStateGuard implements CanActivate {
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> { async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
if (this._userService.currentUser.isUserAdmin) { if (this._userService.currentUser.isUserAdmin) {
await this._userService.loadAllIfEmpty(); await this._userService.loadAll().toPromise();
} }
if (this._userService.currentUser.isUser || this._userService.currentUser.isAdmin) { if (this._userService.currentUser.isUser || this._userService.currentUser.isAdmin) {
await this._userService.loadAllIfEmpty(); await this._userService.loadAll().toPromise();
await this._dossierTemplatesService.loadAllIfEmpty(); await this._dossierTemplatesService.loadAllIfEmpty();
await this._appStateService.loadDictionaryDataIfNecessary(); await this._appStateService.loadDictionaryDataIfNecessary();
} }