mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-14 01:45:12 +00:00
fix(console): text color shades, ui fixes, state handle restore (#3698)
* common project grant dialog, info box, label policy * text styles, statehandler fix * dialog, btn alignment, i18n * search-user theme colors * filter formfield sizing * redirect uris * shortcut layout * settings grid type rest, shortcuts linking * login policy, reset button consistency, metadata * permission checks
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
<div class="max-width-container">
|
||||
<cnsl-meta-layout>
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList">
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList" queryParam="id">
|
||||
<ng-container *ngIf="currentSetting === 'general'">
|
||||
<cnsl-card
|
||||
*ngIf="user && user.human && user.human.profile"
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
opacity: 0.6;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
color: map-get($foreground, base);
|
||||
color: map-get($foreground, text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
|
||||
+10
-1
@@ -2,8 +2,9 @@ import { MediaMatcher } from '@angular/cdk/layout';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Subscription, take } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
|
||||
import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource';
|
||||
@@ -57,7 +58,15 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
private mediaMatcher: MediaMatcher,
|
||||
private _location: Location,
|
||||
activatedRoute: ActivatedRoute,
|
||||
) {
|
||||
activatedRoute.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
const { id } = params;
|
||||
if (id) {
|
||||
this.currentSetting = id;
|
||||
}
|
||||
});
|
||||
|
||||
const mediaq: string = '(max-width: 500px)';
|
||||
const small = this.mediaMatcher.matchMedia(mediaq).matches;
|
||||
if (small) {
|
||||
|
||||
+30
-17
@@ -1,42 +1,55 @@
|
||||
<div mat-dialog-title class="title-row">
|
||||
<h1 class="title">{{'USER.METADATA.TITLE' | translate}}</h1>
|
||||
<div class="title-row">
|
||||
<h1 class="metadata-title">{{ 'USER.METADATA.TITLE' | translate }}</h1>
|
||||
<span class="fill-space"></span>
|
||||
<p *ngIf="ts" class="ts cnsl-secondary-text">{{ts | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</p>
|
||||
<p *ngIf="ts" class="ts cnsl-secondary-text">{{ ts | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }}</p>
|
||||
<mat-spinner *ngIf="loading" diameter="20"></mat-spinner>
|
||||
<button class="icon-button" mat-icon-button (click)="load()">
|
||||
<mat-icon class="icon">refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<p class="desc">{{'USER.METADATA.DESCRIPTION' | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<p class="desc">{{ 'USER.METADATA.DESCRIPTION' | translate }}</p>
|
||||
<div mat-dialog-content class="metadata-dialog-content">
|
||||
<form *ngFor="let md of metadata; index as i" (ngSubmit)="saveElement(i)">
|
||||
<div class="content">
|
||||
<cnsl-form-field #key id="key{{i}}" class="formfield">
|
||||
<cnsl-form-field #key id="key{{ i }}" class="formfield">
|
||||
<cnsl-label>{{ 'USER.METADATA.KEY' | translate }}</cnsl-label>
|
||||
<input cnslInput [(ngModel)]="md.key" [ngModelOptions]="{standalone: true}" />
|
||||
<input cnslInput [(ngModel)]="md.key" [ngModelOptions]="{ standalone: true }" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field #value id="value{{i}}" class="formfield">
|
||||
<cnsl-form-field #value id="value{{ i }}" class="formfield">
|
||||
<cnsl-label>{{ 'USER.METADATA.VALUE' | translate }}</cnsl-label>
|
||||
<input cnslInput [(ngModel)]="md.value" [ngModelOptions]="{standalone: true}" />
|
||||
<input cnslInput [(ngModel)]="md.value" [ngModelOptions]="{ standalone: true }" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<button mat-icon-button [disabled]="!(md.key && md.value)" class="set-button" type="submit" color="primary"
|
||||
matTooltip="{{ 'ACTIONS.SAVE' | translate }}">
|
||||
<button
|
||||
mat-icon-button
|
||||
[disabled]="!(md.key && md.value)"
|
||||
class="set-button"
|
||||
type="submit"
|
||||
color="primary"
|
||||
matTooltip="{{ 'ACTIONS.SAVE' | translate }}"
|
||||
>
|
||||
<i class="las la-save"></i>
|
||||
</button>
|
||||
<button mat-icon-button (click)="removeEntry(i)" [disabled]="metadata.length < 2 && i === 0 && !md.key"
|
||||
class="rm-button" type="button" color="warn" matTooltip="{{ 'ACTIONS.REMOVE' | translate }}">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="removeEntry(i)"
|
||||
[disabled]="metadata.length < 2 && i === 0 && !md.key"
|
||||
class="rm-button"
|
||||
type="button"
|
||||
color="warn"
|
||||
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
|
||||
>
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<button color="primary" (click)="addEntry()" mat-stroked-button color="primary" class="continue-button" type="button">
|
||||
<button (click)="addEntry()" mat-stroked-button class="continue-button" type="button">
|
||||
<mat-icon>add</mat-icon>
|
||||
{{ 'ACTIONS.ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button cdkFocusInitial color="primary" mat-stroked-button class="ok-button" (click)="closeDialog()">
|
||||
{{'ACTIONS.CLOSE' | translate}}
|
||||
<button cdkFocusInitial mat-stroked-button class="ok-button" (click)="closeDialog()">
|
||||
{{ 'ACTIONS.CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+19
-15
@@ -2,8 +2,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
.metadata-title {
|
||||
font-size: 1.3rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -23,23 +23,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 -0.5rem;
|
||||
.metadata-dialog-content {
|
||||
min-width: 400px;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
margin: 0 0.5rem;
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 -0.5rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
flex-basis: 100%;
|
||||
.formfield {
|
||||
flex: 1;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rm-button,
|
||||
.set-button {
|
||||
margin-top: 14px;
|
||||
.rm-button,
|
||||
.set-button {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
<cnsl-card class="metadata-details" title="{{ 'USER.METADATA.TITLE' | translate }}">
|
||||
<div card-actions class="actions">
|
||||
<div class="metadata-actions">
|
||||
<mat-spinner class="spinner" diameter="20" *ngIf="loading"></mat-spinner>
|
||||
<button mat-raised-button color="primary" class="edit" (click)="editMetadata()">{{'ACTIONS.EDIT' |
|
||||
translate}}</button>
|
||||
<button matTooltip="{{'ACTIONS.REFRESH' | translate}}" class="refresh-btn" (click)="loadMetadata()" mat-icon-button
|
||||
aria-label="refresh contributors">
|
||||
<mat-icon class="icon">refresh</mat-icon>
|
||||
</button>
|
||||
<button mat-raised-button color="primary" class="edit" (click)="editMetadata()">{{ 'ACTIONS.EDIT' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="metadata?.length; else emptyList">
|
||||
<div class="metadata-set" *ngFor="let md of metadata">
|
||||
<span class="first cnsl-secondary-text">{{md.key}}</span>
|
||||
<span class="first cnsl-secondary-text">{{ md.key }}</span>
|
||||
<span class="second">{{ md.value }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #emptyList>
|
||||
<p class="empty-desc cnsl-secondary-text">{{'USER.METADATA.EMPTY' | translate}}</p>
|
||||
<p class="empty-desc cnsl-secondary-text">{{ 'USER.METADATA.EMPTY' | translate }}</p>
|
||||
</ng-template>
|
||||
</cnsl-card>
|
||||
</cnsl-card>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
.metadata-details {
|
||||
padding-bottom: 1rem;
|
||||
|
||||
.actions {
|
||||
.metadata-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.edit {
|
||||
font-size: 14px;
|
||||
@@ -53,6 +54,7 @@
|
||||
.empty-desc {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
|
||||
@@ -16,8 +16,7 @@ export class MetadataComponent implements OnInit {
|
||||
public metadata: Metadata.AsObject[] = [];
|
||||
public loading: boolean = false;
|
||||
|
||||
constructor(private dialog: MatDialog, private service: ManagementService, private toast: ToastService,
|
||||
) { }
|
||||
constructor(private dialog: MatDialog, private service: ManagementService, private toast: ToastService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadMetadata();
|
||||
@@ -37,17 +36,20 @@ export class MetadataComponent implements OnInit {
|
||||
|
||||
public loadMetadata(): Promise<any> {
|
||||
this.loading = true;
|
||||
return (this.service as ManagementService).listUserMetadata(this.userId).then(resp => {
|
||||
this.loading = false;
|
||||
this.metadata = resp.resultList.map(md => {
|
||||
return {
|
||||
key: md.key,
|
||||
value: atob(md.value as string),
|
||||
};
|
||||
return (this.service as ManagementService)
|
||||
.listUserMetadata(this.userId)
|
||||
.then((resp) => {
|
||||
this.loading = false;
|
||||
this.metadata = resp.resultList.map((md) => {
|
||||
return {
|
||||
key: md.key,
|
||||
value: atob(md.value as string),
|
||||
};
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
</cnsl-top-view>
|
||||
|
||||
<div *ngIf="loading" class="max-width-container">
|
||||
<mat-progress-spinner diameter="25" color="primary" mode="indeterminate"></mat-progress-spinner>
|
||||
<div class="sp-wrapper">
|
||||
<mat-progress-spinner diameter="25" color="primary" mode="indeterminate"></mat-progress-spinner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!loading && !user" class="max-width-container">
|
||||
@@ -46,7 +48,7 @@
|
||||
|
||||
<div class="max-width-container" *ngIf="user && (['user.write$', 'user.write:' + user.id] | hasRole) as canWrite$">
|
||||
<cnsl-meta-layout>
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList">
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList" queryParam="id">
|
||||
<div *ngIf="error" class="max-width-container">
|
||||
<p>{{ error }}</p>
|
||||
</div>
|
||||
|
||||
@@ -42,3 +42,7 @@
|
||||
.resendemail {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.sp-wrapper {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
@@ -65,9 +65,17 @@ export class UserDetailComponent implements OnInit {
|
||||
private _location: Location,
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
activatedRoute: ActivatedRoute,
|
||||
private mediaMatcher: MediaMatcher,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
activatedRoute.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
const { id } = params;
|
||||
if (id) {
|
||||
this.currentSetting = id;
|
||||
}
|
||||
});
|
||||
|
||||
breadcrumbService.setBreadcrumb([
|
||||
new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
<ng-container *ngSwitchCase="Type.TYPE_HUMAN">
|
||||
<div class="users-title-row">
|
||||
<h1>{{ 'USER.PAGES.LIST' | translate }}</h1>
|
||||
<a mat-icon-button href="https://docs.zitadel.com/docs/concepts/structure/users" rel="noreferrer"
|
||||
target="_blank">
|
||||
<a mat-icon-button href="https://docs.zitadel.com/docs/concepts/structure/users" rel="noreferrer" target="_blank">
|
||||
<i class="las la-info-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<p class="user-list-sub cnsl-secondary-text">{{ 'USER.PAGES.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<cnsl-user-table [type]="Type.TYPE_HUMAN" [disabled]="(['user.write$'] | hasRole | async) === false">
|
||||
<cnsl-user-table
|
||||
[type]="Type.TYPE_HUMAN"
|
||||
[canWrite]="!!(['user.write$'] | hasRole | async)"
|
||||
[canDelete]="!!(['user.delete$'] | hasRole | async)"
|
||||
>
|
||||
</cnsl-user-table>
|
||||
</ng-container>
|
||||
|
||||
@@ -18,8 +21,12 @@
|
||||
<h1>{{ 'USER.PAGES.LISTMACHINE' | translate }}</h1>
|
||||
<p class="user-list-sub cnsl-secondary-text">{{ 'USER.PAGES.DESCRIPTIONMACHINE' | translate }}</p>
|
||||
|
||||
<cnsl-user-table [type]="Type.TYPE_MACHINE" [disabled]="(['user.write$'] | hasRole | async) === false">
|
||||
<cnsl-user-table
|
||||
[type]="Type.TYPE_MACHINE"
|
||||
[canWrite]="!!(['user.write$'] | hasRole | async)"
|
||||
[canDelete]="!!(['user.delete$'] | hasRole | async)"
|
||||
>
|
||||
</cnsl-user-table>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
}
|
||||
|
||||
.user-list-sub {
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -1,35 +1,64 @@
|
||||
<cnsl-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="totalResult"
|
||||
[hideRefresh]="true" [timestamp]="viewTimestamp" [selection]="selection"
|
||||
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [showBorder]="true">
|
||||
|
||||
<cnsl-refresh-table
|
||||
[loading]="loading$ | async"
|
||||
(refreshed)="refreshPage()"
|
||||
[dataSize]="totalResult"
|
||||
[hideRefresh]="true"
|
||||
[timestamp]="viewTimestamp"
|
||||
[selection]="selection"
|
||||
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes"
|
||||
[showBorder]="true"
|
||||
>
|
||||
<div leftActions class="user-table-left-actions">
|
||||
<button class="type-button" [ngClass]="{'active': type === Type.TYPE_HUMAN}"
|
||||
(click)="setType(Type.TYPE_HUMAN)">{{'USER.TABLE.TYPES.HUMAN' | translate}}</button>
|
||||
<button class="type-button" [ngClass]="{'active': type === Type.TYPE_MACHINE}"
|
||||
(click)="setType(Type.TYPE_MACHINE)">{{'USER.TABLE.TYPES.MACHINE' | translate}}</button>
|
||||
<button class="type-button" [ngClass]="{ active: type === Type.TYPE_HUMAN }" (click)="setType(Type.TYPE_HUMAN)">
|
||||
{{ 'USER.TABLE.TYPES.HUMAN' | translate }}
|
||||
</button>
|
||||
<button class="type-button" [ngClass]="{ active: type === Type.TYPE_MACHINE }" (click)="setType(Type.TYPE_MACHINE)">
|
||||
{{ 'USER.TABLE.TYPES.MACHINE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ng-template cnslHasRole [hasRole]="['user.write']" actions>
|
||||
<button (click)="deactivateSelectedUsers()" class="cnsl-action-button bg-state inactive" mat-raised-button
|
||||
*ngIf="selection.hasValue() && multipleDeactivatePossible" [disabled]="disabled" color="primary">
|
||||
<span class="">{{'USER.TABLE.DEACTIVATE' | translate}}</span>
|
||||
<cnsl-action-keys (actionTriggered)="deactivateSelectedUsers()" [type]="ActionKeysType.DEACTIVATE">
|
||||
</cnsl-action-keys>
|
||||
<button
|
||||
(click)="deactivateSelectedUsers()"
|
||||
class="cnsl-action-button bg-state inactive"
|
||||
mat-raised-button
|
||||
*ngIf="selection.hasValue() && multipleDeactivatePossible"
|
||||
[disabled]="!canWrite"
|
||||
color="primary"
|
||||
>
|
||||
<span class="">{{ 'USER.TABLE.DEACTIVATE' | translate }}</span>
|
||||
<cnsl-action-keys (actionTriggered)="deactivateSelectedUsers()" [type]="ActionKeysType.DEACTIVATE"> </cnsl-action-keys>
|
||||
</button>
|
||||
<button (click)="reactivateSelectedUsers()" class="cnsl-action-button bg-state active margin-left" mat-raised-button
|
||||
*ngIf="selection.hasValue() && multipleActivatePossible" [disabled]="disabled" color="primary">
|
||||
<span class="">{{'USER.TABLE.ACTIVATE' | translate}}</span>
|
||||
<cnsl-action-keys (actionTriggered)="reactivateSelectedUsers()" [type]="ActionKeysType.REACTIVATE">
|
||||
</cnsl-action-keys>
|
||||
<button
|
||||
(click)="reactivateSelectedUsers()"
|
||||
class="cnsl-action-button bg-state active margin-left"
|
||||
mat-raised-button
|
||||
*ngIf="selection.hasValue() && multipleActivatePossible"
|
||||
[disabled]="!canWrite"
|
||||
color="primary"
|
||||
>
|
||||
<span class="">{{ 'USER.TABLE.ACTIVATE' | translate }}</span>
|
||||
<cnsl-action-keys (actionTriggered)="reactivateSelectedUsers()" [type]="ActionKeysType.REACTIVATE"> </cnsl-action-keys>
|
||||
</button>
|
||||
<cnsl-filter-user *ngIf="!selection.hasValue()" (filterChanged)="applySearchQuery($any($event))"
|
||||
(filterOpen)="filterOpen = $event"></cnsl-filter-user>
|
||||
<a *ngIf="!selection.hasValue()" [routerLink]="[ '/users',type === Type.TYPE_HUMAN ? 'create' : 'create-machine']"
|
||||
color="primary" mat-raised-button [disabled]="disabled" class="cnsl-action-button">
|
||||
<cnsl-filter-user
|
||||
*ngIf="!selection.hasValue()"
|
||||
(filterChanged)="applySearchQuery($any($event))"
|
||||
(filterOpen)="filterOpen = $event"
|
||||
></cnsl-filter-user>
|
||||
<a
|
||||
*ngIf="!selection.hasValue()"
|
||||
[routerLink]="['/users', type === Type.TYPE_HUMAN ? 'create' : 'create-machine']"
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
[disabled]="!canWrite"
|
||||
class="cnsl-action-button"
|
||||
>
|
||||
<mat-icon class="icon">add</mat-icon>
|
||||
<span>{{ 'ACTIONS.NEW' | translate }}</span>
|
||||
<cnsl-action-keys *ngIf="!filterOpen"
|
||||
(actionTriggered)="gotoRouterLink([ '/users',type === Type.TYPE_HUMAN ? 'create' : 'create-machine'])">
|
||||
<cnsl-action-keys
|
||||
*ngIf="!filterOpen"
|
||||
(actionTriggered)="gotoRouterLink(['/users', type === Type.TYPE_HUMAN ? 'create' : 'create-machine'])"
|
||||
>
|
||||
</cnsl-action-keys>
|
||||
</a>
|
||||
</ng-template>
|
||||
@@ -38,19 +67,37 @@
|
||||
<table class="table" mat-table [dataSource]="dataSource" matSort (matSortChange)="sortChange($event)">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef class="selection">
|
||||
<mat-checkbox [disabled]="disabled" color="primary" (change)="$event ? masterToggle() : null"
|
||||
<mat-checkbox
|
||||
[disabled]="!canWrite"
|
||||
color="primary"
|
||||
(change)="$event ? masterToggle() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let user" class="selection">
|
||||
<mat-checkbox [disabled]="disabled" color="primary" (click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(user) : null" [checked]="selection.isSelected(user)">
|
||||
|
||||
<mat-checkbox
|
||||
[disabled]="!canWrite"
|
||||
color="primary"
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(user) : null"
|
||||
[checked]="selection.isSelected(user)"
|
||||
>
|
||||
<cnsl-avatar
|
||||
*ngIf="user.human && user.human.profile.displayName && user.human?.profile.firstName && user.human?.profile.lastName; else cog"
|
||||
class="avatar" [name]="user.human.profile.displayName" [avatarUrl]="user.human?.profile?.avatarUrl || ''"
|
||||
[forColor]="user?.preferredLoginName" [size]="32">
|
||||
*ngIf="
|
||||
user.human &&
|
||||
user.human.profile.displayName &&
|
||||
user.human?.profile.firstName &&
|
||||
user.human?.profile.lastName;
|
||||
else cog
|
||||
"
|
||||
class="avatar"
|
||||
[name]="user.human.profile.displayName"
|
||||
[avatarUrl]="user.human?.profile?.avatarUrl || ''"
|
||||
[forColor]="user?.preferredLoginName"
|
||||
[size]="32"
|
||||
>
|
||||
</cnsl-avatar>
|
||||
<ng-template #cog>
|
||||
<cnsl-avatar [forColor]="user?.preferredLoginName" [isMachine]="true">
|
||||
@@ -62,58 +109,74 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="displayName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header
|
||||
[ngClass]="{'search-active': this.userSearchKey === UserListSearchKey.DISPLAY_NAME}">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
[ngClass]="{ 'search-active': this.userSearchKey === UserListSearchKey.DISPLAY_NAME }"
|
||||
>
|
||||
{{ 'USER.PROFILE.DISPLAYNAME' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
<span *ngIf="user.human">{{user.human.profile?.displayName}}</span>
|
||||
<span *ngIf="user.machine">{{user.machine.name}}</span>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
<span *ngIf="user.human">{{ user.human.profile?.displayName }}</span>
|
||||
<span *ngIf="user.machine">{{ user.machine.name }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="username">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header
|
||||
[ngClass]="{'search-active': this.userSearchKey === UserListSearchKey.USER_NAME}">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
[ngClass]="{ 'search-active': this.userSearchKey === UserListSearchKey.USER_NAME }"
|
||||
>
|
||||
{{ 'USER.PROFILE.USERNAME' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
{{user.userName}} </td>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
{{ user.userName }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="email">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header
|
||||
[ngClass]="{'search-active': this.UserListSearchKey === UserListSearchKey.EMAIL}">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
[ngClass]="{ 'search-active': this.UserListSearchKey === UserListSearchKey.EMAIL }"
|
||||
>
|
||||
{{ 'USER.EMAIL' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
<span *ngIf="user.human?.email?.email">{{user.human?.email.email}}</span>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
<span *ngIf="user.human?.email?.email">{{ user.human?.email.email }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="state">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ 'USER.DATA.STATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
<span class="state"
|
||||
[ngClass]="{'active': user.state === UserState.USER_STATE_ACTIVE, 'inactive': user.state === UserState.USER_STATE_INACTIVE}">
|
||||
{{ 'USER.DATA.STATE'+user.state | translate }}
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'USER.DATA.STATE' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
<span
|
||||
class="state"
|
||||
[ngClass]="{
|
||||
active: user.state === UserState.USER_STATE_ACTIVE,
|
||||
inactive: user.state === UserState.USER_STATE_INACTIVE
|
||||
}"
|
||||
>
|
||||
{{ 'USER.DATA.STATE' + user.state | translate }}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'USER.TABLE.CREATIONDATE' | translate}} </th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
<span class="no-break">{{user.details.creationDate | timestampToDate | localizedDate: 'fromNow'
|
||||
}}</span>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'USER.TABLE.CREATIONDATE' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
<span class="no-break">{{ user.details.creationDate | timestampToDate | localizedDate: 'fromNow' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="changeDate">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'USER.TABLE.CHANGEDATE' | translate }} </th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id ]: null">
|
||||
<span class="no-break">{{user.details.changeDate | timestampToDate | localizedDate: 'fromNow'
|
||||
}}</span>
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'USER.TABLE.CHANGEDATE' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let user" [routerLink]="user.id ? ['/users', user.id] : null">
|
||||
<span class="no-break">{{ user.details.changeDate | timestampToDate | localizedDate: 'fromNow' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -121,28 +184,41 @@
|
||||
<th mat-header-cell *matHeaderCellDef class="user-tr-actions"></th>
|
||||
<td mat-cell *matCellDef="let user" class="user-tr-actions">
|
||||
<cnsl-table-actions>
|
||||
<button actions matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" (click)="deleteUser(user)"
|
||||
mat-icon-button>
|
||||
<button
|
||||
actions
|
||||
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
|
||||
color="warn"
|
||||
(click)="deleteUser(user)"
|
||||
[disabled]="!canWrite || !canDelete"
|
||||
mat-icon-button
|
||||
>
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
</cnsl-table-actions>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="type === Type.TYPE_HUMAN ? displayedColumnsHuman : displayedColumnsMachine">
|
||||
</tr>
|
||||
<tr class="highlight pointer" mat-row
|
||||
*matRowDef="let user; columns: (type === Type.TYPE_HUMAN ? displayedColumnsHuman : displayedColumnsMachine);">
|
||||
</tr>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="type === Type.TYPE_HUMAN ? displayedColumnsHuman : displayedColumnsMachine"></tr>
|
||||
<tr
|
||||
class="highlight pointer"
|
||||
mat-row
|
||||
*matRowDef="let user; columns: type === Type.TYPE_HUMAN ? displayedColumnsHuman : displayedColumnsMachine"
|
||||
></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row">
|
||||
<i class="las la-exclamation"></i>
|
||||
<span>{{'USER.TABLE.EMPTY' | translate}}</span>
|
||||
<span>{{ 'USER.TABLE.EMPTY' | translate }}</span>
|
||||
</div>
|
||||
<cnsl-paginator #paginator class="paginator" [timestamp]="viewTimestamp" [length]="totalResult || 0"
|
||||
[pageSize]="INITIAL_PAGE_SIZE" [timestamp]="viewTimestamp" [pageSizeOptions]="[10, 20, 50, 100]"
|
||||
(page)="changePage($event)"></cnsl-paginator>
|
||||
</cnsl-refresh-table>
|
||||
<cnsl-paginator
|
||||
#paginator
|
||||
class="paginator"
|
||||
[timestamp]="viewTimestamp"
|
||||
[length]="totalResult || 0"
|
||||
[pageSize]="INITIAL_PAGE_SIZE"
|
||||
[timestamp]="viewTimestamp"
|
||||
[pageSizeOptions]="[10, 20, 50, 100]"
|
||||
(page)="changePage($event)"
|
||||
></cnsl-paginator>
|
||||
</cnsl-refresh-table>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
opacity: 0.6;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
color: map-get($foreground, base);
|
||||
color: map-get($foreground, text);
|
||||
|
||||
&:first-child {
|
||||
margin-right: 1rem;
|
||||
|
||||
@@ -37,7 +37,7 @@ export class UserTableComponent implements OnInit {
|
||||
public Type: any = Type;
|
||||
@Input() public type: Type = Type.TYPE_HUMAN;
|
||||
@Input() refreshOnPreviousRoutes: string[] = [];
|
||||
@Input() disabled: boolean = false;
|
||||
@Input() canWrite: boolean = false;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
@ViewChild(MatSort) public sort!: MatSort;
|
||||
public INITIAL_PAGE_SIZE: number = 20;
|
||||
@@ -77,6 +77,7 @@ export class UserTableComponent implements OnInit {
|
||||
public filterOpen: boolean = false;
|
||||
|
||||
private searchQueries: SearchQuery[] = [];
|
||||
@Input() public canDelete: boolean = false;
|
||||
constructor(
|
||||
private router: Router,
|
||||
public translate: TranslateService,
|
||||
|
||||
Reference in New Issue
Block a user