fix(console): datepicker, formfield cleanup, member role help, domain layout (#3765)

* key datepicker, formfield cleanup, member role help, domain layout

* accounts card template overlay

* fix account card trigger

* chore(deps-dev): bump @typescript-eslint/parser from 5.26.0 to 5.27.0 in /console (#3752)

chore(deps-dev): bump @typescript-eslint/parser in /console

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.26.0 to 5.27.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.27.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* deps, i18n, feature info section

* lint

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Max Peintner
2022-06-07 11:08:05 +02:00
committed by GitHub
co-authored by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
parent 5e4b38d69b
commit c1f59c7950
45 changed files with 648 additions and 456 deletions
@@ -1,4 +1,4 @@
<div class="accounts-card" cnslOutsideClick (clickOutside)="closeCard($event)">
<div class="accounts-card">
<cnsl-avatar
(click)="editUserProfile()"
*ngIf="user.human?.profile && user.human?.profile?.displayName"
@@ -35,7 +35,14 @@
<div class="col">
<span class="user-title">{{ session.displayName ? session.displayName : session.userName }} </span>
<span class="loginname">{{ session.loginName }}</span>
<span class="email">{{ 'USER.STATE.' + session.authState | translate }}</span>
<span
class="state"
[ngClass]="{
active: session.authState === UserState.USER_STATE_ACTIVE,
inactive: session.authState === UserState.USER_STATE_INACTIVE
}"
>{{ 'USER.STATE.' + session.authState | translate }}</span
>
</div>
<span class="fill-space"></span>
<mat-icon>keyboard_arrow_right</mat-icon>
@@ -28,6 +28,7 @@
align-items: center;
padding: 1rem 0;
position: relative;
color: map-get($foreground, text);
.avatar {
font-size: 80px;
@@ -47,7 +48,7 @@
.u-email {
font-size: 0.8rem;
margin-top: 0;
margin: 0.5rem 0;
}
button {
@@ -96,6 +97,7 @@
border-radius: 50%;
margin: 0 1rem;
text-align: center;
display: flex;
i {
margin: auto;
@@ -112,13 +114,26 @@
font-weight: 500;
font-size: 0.9rem;
line-height: 1rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.email,
.state,
.loginname {
color: $secondary-text;
font-size: 0.8rem;
line-height: 1rem;
width: fit-content;
}
.loginname {
color: $secondary-text;
}
.state {
margin-top: 3px;
font-size: 11px;
padding: 1px 0.5rem;
}
}
@@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Router } from '@angular/router';
import { AuthConfig } from 'angular-oauth2-oidc';
import { Session, User } from 'src/app/proto/generated/zitadel/user_pb';
import { Session, User, UserState } from 'src/app/proto/generated/zitadel/user_pb';
import { AuthenticationService } from 'src/app/services/authentication.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@@ -17,6 +17,7 @@ export class AccountsCardComponent implements OnInit {
@Output() public closedCard: EventEmitter<void> = new EventEmitter();
public sessions: Session.AsObject[] = [];
public loadingUsers: boolean = false;
public UserState: any = UserState;
constructor(public authService: AuthenticationService, private router: Router, private userService: GrpcAuthService) {
this.userService
.listMyUserSessions()
@@ -34,7 +35,7 @@ export class AccountsCardComponent implements OnInit {
});
}
public ngOnInit(): void {
ngOnInit(): void {
this.loadingUsers = true;
}
@@ -49,10 +50,6 @@ export class AccountsCardComponent implements OnInit {
}
}
public close(): void {
this.closedCard.emit();
}
public selectAccount(loginHint?: string): void {
const configWithPrompt: Partial<AuthConfig> = {
customQueryParams: {
@@ -5,23 +5,13 @@ import { MatIconModule } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { OutsideClickModule } from 'src/app/directives/outside-click/outside-click.module';
import { AvatarModule } from '../avatar/avatar.module';
import { AccountsCardComponent } from './accounts-card.component';
@NgModule({
declarations: [AccountsCardComponent],
imports: [
CommonModule,
MatIconModule,
MatButtonModule,
MatProgressBarModule,
OutsideClickModule,
RouterModule,
AvatarModule,
TranslateModule,
],
imports: [CommonModule, MatIconModule, MatButtonModule, MatProgressBarModule, RouterModule, AvatarModule, TranslateModule],
exports: [AccountsCardComponent],
})
export class AccountsCardModule {}
@@ -1,34 +1,39 @@
<span class="title" mat-dialog-title>{{'USER.MACHINE.ADD.TITLE' | translate}}</span>
<span class="title" mat-dialog-title>{{ 'USER.MACHINE.ADD.TITLE' | translate }}</span>
<div mat-dialog-content>
<p class="desc cnsl-secondary-text"> {{'USER.MACHINE.ADD.DESCRIPTION' | translate}}</p>
<p class="desc cnsl-secondary-text">{{ 'USER.MACHINE.ADD.DESCRIPTION' | translate }}</p>
<cnsl-form-field class="form-field" appearance="outline">
<cnsl-label>{{'USER.MACHINE.TYPE' | translate}}</cnsl-label>
<cnsl-form-field class="form-field">
<cnsl-label>{{ 'USER.MACHINE.TYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="type">
<mat-option *ngFor="let t of types" [value]="t">
{{'USER.MACHINE.KEYTYPES.'+t | translate}}
{{ 'USER.MACHINE.KEYTYPES.' + t | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="add-key-form-field" appearance="outline">
<cnsl-label>{{'USER.MACHINE.CHOOSEEXPIRY' | translate}} (optional)</cnsl-label>
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl">
<mat-datepicker-toggle style="top: 0;" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker startView="year" [startAt]="startDate"></mat-datepicker>
<cnsl-form-field class="add-key-form-field">
<cnsl-label>{{ 'USER.MACHINE.CHOOSEEXPIRY' | translate }} (optional)</cnsl-label>
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker [startAt]="startDate"></mat-datepicker>
<span cnslError *ngIf="dateControl?.errors?.matDatepickerMin?.min">
{{'USER.MACHINE.CHOOSEDATEAFTER' | translate}}:
{{dateControl?.errors?.matDatepickerMin.min.toDate() | localizedDate: 'EEE dd. MMM'}}
{{ 'USER.MACHINE.CHOOSEDATEAFTER' | translate }}:
{{ dateControl?.errors?.matDatepickerMin.min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
</cnsl-form-field>
</div>
<div mat-dialog-actions class=" action">
<div mat-dialog-actions class="action">
<button mat-stroked-button (click)="closeDialog()">
{{'ACTIONS.CANCEL' | translate}}
{{ 'ACTIONS.CANCEL' | translate }}
</button>
<button color="primary" mat-raised-button class="ok-button" [disabled]="type === undefined || dateControl.invalid"
(click)="closeDialogWithSuccess()">
{{'ACTIONS.ADD' | translate}}
<button
color="primary"
mat-raised-button
class="ok-button"
[disabled]="type === undefined || dateControl.invalid"
(click)="closeDialogWithSuccess()"
>
{{ 'ACTIONS.ADD' | translate }}
</button>
</div>
</div>
@@ -1,24 +1,32 @@
<h1 mat-dialog-title>
<span class="title">{{'MEMBER.ADD' | translate}}</span>
<span class="title">{{ 'MEMBER.ADD' | translate }}</span>
</h1>
<p class="desc cnsl-secondary-text"> {{'ORG_DETAIL.MEMBER.ADDDESCRIPTION' | translate}}</p>
<p class="desc cnsl-secondary-text">{{ 'ORG_DETAIL.MEMBER.ADDDESCRIPTION' | translate }}</p>
<div mat-dialog-content>
<ng-container *ngIf="showCreationTypeSelector">
<cnsl-form-field class="full-width" appearance="outline">
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'MEMBER.CREATIONTYPE' | translate }}</cnsl-label>
<mat-select [(ngModel)]="creationType" (selectionChange)="loadRoles()">
<mat-option *ngFor="let type of creationTypes" [value]="type.type"
[disabled]="(type.disabled$ | async) === false">
{{ 'MEMBER.CREATIONTYPES.'+type.type | translate}}
<mat-option *ngFor="let type of creationTypes" [value]="type.type" [disabled]="(type.disabled$ | async) === false">
{{ 'MEMBER.CREATIONTYPES.' + type.type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<ng-container *ngIf="creationType === CreationType.PROJECT_OWNED || creationType === CreationType.PROJECT_GRANTED">
<p>{{'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate}}</p>
<cnsl-search-project-autocomplete class="block" (selectionChanged)="selectProject($event)"
[autocompleteType]="creationType === CreationType.PROJECT_OWNED ? ProjectAutocompleteType.PROJECT_OWNED : creationType === CreationType.PROJECT_GRANTED ? ProjectAutocompleteType.PROJECT_GRANTED : undefined">
<p>{{ 'PROJECT.GRANT.CREATE.SEL_PROJECT' | translate }}</p>
<cnsl-search-project-autocomplete
class="block"
(selectionChanged)="selectProject($event)"
[autocompleteType]="
creationType === CreationType.PROJECT_OWNED
? ProjectAutocompleteType.PROJECT_OWNED
: creationType === CreationType.PROJECT_GRANTED
? ProjectAutocompleteType.PROJECT_GRANTED
: undefined
"
>
</cnsl-search-project-autocomplete>
</ng-container>
</ng-container>
@@ -27,23 +35,33 @@
</cnsl-search-user-autocomplete>
<div class="roles-selection">
<mat-checkbox class="role-cb" *ngFor="let role of memberRoleOptions" color="primary" (change)="toggleRole(role)"
[checked]="roles.includes(role)">
<mat-checkbox
class="role-cb"
*ngFor="let role of memberRoleOptions"
color="primary"
(change)="toggleRole(role)"
[checked]="roles.includes(role)"
>
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{role | roletransform}}</span>
<span>{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
</div>
</div>
<div mat-dialog-actions class="action">
<button mat-stroked-button (click)="closeDialog()">
{{'ACTIONS.CANCEL' | translate}}
{{ 'ACTIONS.CANCEL' | translate }}
</button>
<button [disabled]="users.length === 0 || roles.length === 0" color="primary" mat-raised-button class="ok-button"
(click)="closeDialogWithSuccess()">
{{'ACTIONS.ADD' | translate}}
<button
[disabled]="users.length === 0 || roles.length === 0"
color="primary"
mat-raised-button
class="ok-button"
(click)="closeDialogWithSuccess()"
>
{{ 'ACTIONS.ADD' | translate }}
</button>
</div>
</div>
@@ -22,6 +22,11 @@
display: flex;
flex-direction: row;
align-items: center;
.info-hover {
font-size: 1.2rem;
margin-left: 0.5rem;
}
}
}
}
@@ -6,6 +6,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatDialogModule } from '@angular/material/dialog';
import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { InputModule } from 'src/app/modules/input/input.module';
import { SearchUserAutocompleteModule } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.module';
@@ -24,6 +25,7 @@ import { MemberCreateDialogComponent } from './member-create-dialog.component';
MatChipsModule,
TranslateModule,
InputModule,
MatTooltipModule,
MatSelectModule,
RoleTransformPipeModule,
FormsModule,
@@ -12,6 +12,7 @@
<div class="role-cb-content">
<div class="cnsl-chip-dot" [style.background]="getColor(role)"></div>
<span>{{ role | roletransform }}</span>
<i class="info-hover las la-question-circle" matTooltip="{{ 'MEMBERROLES.' + role | translate }}"></i>
</div>
</mat-checkbox>
</div>
@@ -19,6 +19,11 @@
display: flex;
flex-direction: row;
align-items: center;
.info-hover {
font-size: 1.2rem;
margin-left: 0.5rem;
}
}
}
}
@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { RoleTransformPipeModule } from 'src/app/pipes/role-transform/role-transform.module';
@@ -17,6 +18,7 @@ import { AddMemberRolesDialogComponent } from './add-member-roles-dialog.compone
MatCheckboxModule,
MatButtonModule,
LocalizedDatePipeModule,
MatTooltipModule,
RoleTransformPipeModule,
TimestampToDatePipeModule,
],
@@ -1,25 +1,30 @@
<span class="title" mat-dialog-title>{{'USER.PERSONALACCESSTOKEN.ADD.TITLE' | translate}}</span>
<span class="title" mat-dialog-title>{{ 'USER.PERSONALACCESSTOKEN.ADD.TITLE' | translate }}</span>
<div mat-dialog-content>
<cnsl-info-section class="desc"> {{'USER.PERSONALACCESSTOKEN.ADD.DESCRIPTION' | translate}}</cnsl-info-section>
<cnsl-info-section class="desc"> {{ 'USER.PERSONALACCESSTOKEN.ADD.DESCRIPTION' | translate }}</cnsl-info-section>
<cnsl-form-field class="form-field" appearance="outline">
<cnsl-label>{{'USER.PERSONALACCESSTOKEN.ADD.CHOOSEEXPIRY' | translate}} (optional)</cnsl-label>
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl">
<mat-datepicker-toggle style="top: 0;" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<cnsl-form-field>
<cnsl-label>{{ 'USER.PERSONALACCESSTOKEN.ADD.CHOOSEEXPIRY' | translate }} (optional)</cnsl-label>
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker startView="year" [startAt]="startDate"></mat-datepicker>
<span cnslError *ngIf="dateControl?.errors?.matDatepickerMin?.min">
{{'USER.PERSONALACCESSTOKEN.ADD.CHOOSEDATEAFTER' | translate}}:
{{dateControl?.errors?.matDatepickerMin.min.toDate() | localizedDate: 'EEE dd. MMM'}}
{{ 'USER.PERSONALACCESSTOKEN.ADD.CHOOSEDATEAFTER' | translate }}:
{{ dateControl?.errors?.matDatepickerMin.min.toDate() | localizedDate: 'EEE dd. MMM' }}
</span>
</cnsl-form-field>
</div>
<div mat-dialog-actions class=" action">
<div mat-dialog-actions class="action">
<button mat-button (click)="closeDialog()">
{{'ACTIONS.CANCEL' | translate}}
{{ 'ACTIONS.CANCEL' | translate }}
</button>
<button color="primary" mat-raised-button class="ok-button" [disabled]="dateControl.invalid"
(click)="closeDialogWithSuccess()">
{{'ACTIONS.ADD' | translate}}
<button
color="primary"
mat-raised-button
class="ok-button"
[disabled]="dateControl.invalid"
(click)="closeDialogWithSuccess()"
>
{{ 'ACTIONS.ADD' | translate }}
</button>
</div>
</div>
@@ -3,10 +3,6 @@
margin-top: 0;
}
.form-field {
width: 100%;
}
.action {
display: flex;
justify-content: flex-end;
@@ -13,7 +13,7 @@
{{ 'FILTER.METHODS.1' | translate }}
</span>
<cnsl-form-field class="filter-select-value" appearance="outline">
<cnsl-form-field class="filter-select-value">
<mat-select [value]="sq.getState()" (selectionChange)="setValue(SubQuery.STATE, sq, $event)">
<mat-option *ngFor="let state of states" [value]="state">
{{ 'USER.STATE.' + state | translate }}
@@ -32,7 +32,7 @@
>{{ 'FILTER.DISPLAYNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.DISPLAYNAME) as dnq">
<cnsl-form-field class="filter-select-method" appearance="outline">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="dnq.getMethod()" (selectionChange)="setMethod(dnq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
@@ -40,7 +40,7 @@
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value" appearance="outline">
<cnsl-form-field class="filter-input-value">
<input
cnslInput
name="value"
@@ -60,7 +60,7 @@
>{{ 'FILTER.EMAIL' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.EMAIL) as eq">
<cnsl-form-field class="filter-select-method" appearance="outline">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="eq.getMethod()" (selectionChange)="setMethod(eq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
@@ -68,7 +68,7 @@
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value" appearance="outline">
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="eq.getEmailAddress()" (change)="setValue(SubQuery.EMAIL, eq, $event)" />
</cnsl-form-field>
</div>
@@ -83,7 +83,7 @@
>{{ 'FILTER.USERNAME' | translate }}
</mat-checkbox>
<div class="subquery" *ngIf="getSubFilter(SubQuery.USERNAME) as unq">
<cnsl-form-field class="filter-select-method" appearance="outline">
<cnsl-form-field class="filter-select-method">
<mat-select [value]="unq.getMethod()" (selectionChange)="setMethod(unq, $event)">
<mat-option *ngFor="let method of methods" [value]="method">
{{ 'FILTER.METHODS.' + method | translate }}
@@ -91,7 +91,7 @@
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="filter-input-value" appearance="outline">
<cnsl-form-field class="filter-input-value">
<input cnslInput name="value" [value]="unq.getUserName()" (change)="setValue(SubQuery.USERNAME, unq, $event)" />
</cnsl-form-field>
</div>
@@ -7,7 +7,6 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatIconModule } from '@angular/material/icon';
import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { OutsideClickModule } from 'src/app/directives/outside-click/outside-click.module';
import { ActionKeysModule } from '../action-keys/action-keys.module';
import { InputModule } from '../input/input.module';
@@ -26,7 +25,6 @@ import { FilterComponent } from './filter.component';
MatCheckboxModule,
InputModule,
MatSelectModule,
OutsideClickModule,
],
exports: [FilterComponent],
})
@@ -196,30 +196,46 @@
</a>
</div>
<div
cnslOutsideClick
(clickOutside)="closeAccountCard()"
class="icon-container"
[ngClass]="{ 'iam-user': (['iam.write$'] | hasRole | async) }"
>
<cnsl-avatar
id="avatartoggle"
*ngIf="
user && (user.human?.profile?.displayName || (user.human?.profile?.firstName && user.human?.profile?.lastName))
"
class="avatar-toggle dontcloseonclick"
<div class="account-card-wrapper">
<button
cdkOverlayOrigin
#accounttrigger="cdkOverlayOrigin"
class="icon-container"
(click)="showAccount = !showAccount"
[active]="showAccount"
[avatarUrl]="user.human?.profile?.avatarUrl || ''"
[forColor]="user?.preferredLoginName || ''"
[name]="
user.human?.profile?.displayName
? user.human?.profile?.displayName ?? ''
: user.human?.profile?.firstName + ' ' + user.human?.profile?.lastName
"
[size]="38"
[ngClass]="{ 'iam-user': (['iam.write$'] | hasRole | async) }"
>
</cnsl-avatar>
<cnsl-avatar
id="avatartoggle"
*ngIf="
user && (user.human?.profile?.displayName || (user.human?.profile?.firstName && user.human?.profile?.lastName))
"
class="avatar-toggle dontcloseonclick"
[active]="showAccount"
[avatarUrl]="user.human?.profile?.avatarUrl || ''"
[forColor]="user?.preferredLoginName || ''"
[name]="
user.human?.profile?.displayName
? user.human?.profile?.displayName ?? ''
: user.human?.profile?.firstName + ' ' + user.human?.profile?.lastName
"
[size]="38"
>
</cnsl-avatar>
</button>
</div>
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="accounttrigger"
[flexibleDimensions]="true"
[lockPosition]="true"
[cdkConnectedOverlayOffsetY]="10"
[cdkConnectedOverlayHasBackdrop]="true"
[cdkConnectedOverlayPositions]="accountCardPositions"
cdkConnectedOverlayBackdropClass="transparent-backdrop"
[cdkConnectedOverlayOpen]="showAccount"
(backdropClick)="showAccount = false"
(detach)="showAccount = false"
>
<cnsl-accounts-card
@accounts
class="a_card"
@@ -229,6 +245,6 @@
[iamuser]="['iam.write$'] | hasRole | async"
>
</cnsl-accounts-card>
</div>
</ng-template>
</div>
</mat-toolbar>
@@ -250,47 +250,56 @@
}
}
.icon-container {
display: flex;
justify-content: space-between;
.account-card-wrapper {
position: relative;
user-select: none;
border: 2px solid #ffffff80;
border-radius: 50%;
transition: border ease 0.15s;
&.iam-user {
border: 2px solid $primary-color;
}
.icon-container {
display: flex;
justify-content: space-between;
position: relative;
user-select: none;
border-radius: 50%;
transition: border ease 0.15s;
padding: 0;
border: 2px solid if($is-dark-theme, #ffffff80, #00000010);
outline: none;
background: none;
&:hover {
border-color: if($is-dark-theme, #fff, #00000050);
}
&.iam-user {
border: 2px solid $primary-color;
}
.docs {
text-decoration: none;
font-size: 1.4rem;
}
&:hover,
&:focus {
border: 2px solid if($is-dark-theme, #fff, map-get($primary, 200));
}
.avatar-toggle {
display: block;
margin: auto;
cursor: pointer;
}
.docs {
text-decoration: none;
font-size: 1.4rem;
}
.name {
font-size: 1rem;
font-weight: 400;
}
.avatar-toggle {
display: block;
margin: auto;
cursor: pointer;
border: none;
}
.a_card {
position: absolute;
z-index: 300;
top: 55px;
right: 0;
overflow: hidden;
box-shadow: 0 0 15px 0 rgb(0 0 0 / 10%);
border-radius: 0.5rem;
.name {
font-size: 1rem;
font-weight: 400;
}
.a_card {
position: absolute;
z-index: 300;
top: 55px;
right: 0;
overflow: hidden;
box-shadow: 0 0 15px 0 rgb(0 0 0 / 10%);
border-radius: 0.5rem;
}
}
}
}
@@ -38,6 +38,11 @@ export class HeaderComponent implements OnDestroy {
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
new ConnectionPositionPair({ originX: 'end', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' }, 0, 10),
];
public accountCardPositions: ConnectedPosition[] = [
new ConnectionPositionPair({ originX: 'end', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' }, 0, 10),
new ConnectionPositionPair({ originX: 'end', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' }, 0, 10),
];
constructor(
public authenticationService: AuthenticationService,
private authService: GrpcAuthService,
@@ -1,37 +1,48 @@
<div class="info-row" *ngIf="user">
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.PAGES.STATE' | translate }}</p>
<p *ngIf="user && user.state !== undefined" class="state"
[ngClass]="{'active': user.state === UserState.USER_STATE_ACTIVE, 'inactive': user.state === UserState.USER_STATE_INACTIVE}">
{{'USER.DATA.STATE'+user.state
| translate}}</p>
<p
*ngIf="user && user.state !== undefined"
class="state"
[ngClass]="{
active: user.state === UserState.USER_STATE_ACTIVE,
inactive: user.state === UserState.USER_STATE_INACTIVE
}"
>
{{ 'USER.DATA.STATE' + user.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.ID' | translate }}</p>
<p *ngIf="user && user.id" class="info-row-desc">{{user.id }}</p>
<p *ngIf="user && user.id" class="info-row-desc">{{ user.id }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECREATED' | translate }}</p>
<p *ngIf="user && user.details && user.details.creationDate" class="info-row-desc">{{user.details.creationDate |
timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="user && user.details && user.details.creationDate" class="info-row-desc">
{{ user.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'USER.DETAILS.DATECHANGED' | translate }}</p>
<p *ngIf="user && user.details && user.details.changeDate" class="info-row-desc">{{user.details.changeDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="user && user.details && user.details.changeDate" class="info-row-desc">
{{ user.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'USER.PAGES.LOGINNAMES' | translate }}</p>
<div class="copy-row" *ngFor="let login of user?.loginNamesList">
<button [disabled]="copied === login"
[matTooltip]="(copied !== login ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate" cnslCopyToClipboard
[valueToCopy]="login" (copiedValue)="copied = $event">
{{login}}
<button
[disabled]="copied === login"
[matTooltip]="(copied !== login ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="login"
(copiedValue)="copied = $event"
>
{{ login }}
</button>
</div>
</div>
@@ -40,99 +51,117 @@
<div class="info-row" *ngIf="org">
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.STATE' | translate }}</p>
<p *ngIf="org && org.state !== undefined" class="state"
[ngClass]="{'active': org.state === OrgState.ORG_STATE_ACTIVE, 'inactive': org.state === OrgState.ORG_STATE_INACTIVE}">
{{'ORG.STATE.'+org.state
| translate}}</p>
<p
*ngIf="org && org.state !== undefined"
class="state"
[ngClass]="{ active: org.state === OrgState.ORG_STATE_ACTIVE, inactive: org.state === OrgState.ORG_STATE_INACTIVE }"
>
{{ 'ORG.STATE.' + org.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'RESOURCEID' | translate }}</p>
<p *ngIf="org && org.id" class="info-row-desc">{{org.id }}</p>
<p *ngIf="org && org.id" class="info-row-desc">{{ org.id }}</p>
</div>
<div class="info-wrapper width">
<p class="info-row-title">{{ 'ORG.PAGES.PRIMARYDOMAIN' | translate }}</p>
<div class="copy-row" *ngIf="org.primaryDomain">
<button [disabled]="copied === org.primaryDomain"
[matTooltip]="(copied !== org.primaryDomain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate"
cnslCopyToClipboard [valueToCopy]="org.primaryDomain" (copiedValue)="copied = $event">
{{org.primaryDomain}}
<button
[disabled]="copied === org.primaryDomain"
[matTooltip]="(copied !== org.primaryDomain ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="org.primaryDomain"
(copiedValue)="copied = $event"
>
{{ org.primaryDomain }}
</button>
</div>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.CREATIONDATE' | translate }}</p>
<p *ngIf="org && org.details && org.details.creationDate" class="info-row-desc">{{org.details.creationDate |
timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="org && org.details && org.details.creationDate" class="info-row-desc">
{{ org.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'ORG.PAGES.DATECHANGED' | translate }}</p>
<p *ngIf="org && org.details && org.details.changeDate" class="info-row-desc">{{org.details.changeDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="org && org.details && org.details.changeDate" class="info-row-desc">
{{ org.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
</div>
<div class="info-row" *ngIf="project">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
<p *ngIf="project && project.state !== undefined" class="state"
[ngClass]="{'active': project.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': project.state === ProjectState.PROJECT_STATE_INACTIVE}">
{{'PROJECT.STATE.'+project.state
| translate}}</p>
<p
*ngIf="project && project.state !== undefined"
class="state"
[ngClass]="{
active: project.state === ProjectState.PROJECT_STATE_ACTIVE,
inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE
}"
>
{{ 'PROJECT.STATE.' + project.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'RESOURCEID' | translate }}</p>
<p *ngIf="project && project.id" class="info-row-desc">{{project.id }}</p>
<p *ngIf="project && project.id" class="info-row-desc">{{ project.id }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
<p *ngIf="project && project.details && project.details.creationDate" class="info-row-desc">
{{project.details.creationDate |
timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
{{ project.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
<p *ngIf="project && project.details && project.details.changeDate" class="info-row-desc">
{{project.details.changeDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
{{ project.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
</div>
<div class="info-row" *ngIf="grantedProject">
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.STATE.TITLE' | translate }}</p>
<p *ngIf="grantedProject && grantedProject.state !== undefined" class="state"
[ngClass]="{'active': grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE, 'inactive': grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE}">
{{'PROJECT.STATE.'+grantedProject.state
| translate}}</p>
<p
*ngIf="grantedProject && grantedProject.state !== undefined"
class="state"
[ngClass]="{
active: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE,
inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE
}"
>
{{ 'PROJECT.STATE.' + grantedProject.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'RESOURCEID' | translate }}</p>
<p *ngIf="grantedProject && grantedProject.projectId" class="info-row-desc">{{grantedProject.projectId }}</p>
<p *ngIf="grantedProject && grantedProject.projectId" class="info-row-desc">{{ grantedProject.projectId }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.CREATEDON' | translate }}</p>
<p *ngIf="grantedProject && grantedProject.details && grantedProject.details.creationDate" class="info-row-desc">
{{grantedProject.details.creationDate |
timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
{{ grantedProject.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'PROJECT.PAGES.LASTMODIFIED' | translate }}</p>
<p *ngIf="grantedProject && grantedProject.details && grantedProject.details.changeDate" class="info-row-desc">
{{grantedProject.details.changeDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
{{ grantedProject.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
</div>
@@ -140,84 +169,95 @@
<div class="info-row">
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.STATE' | translate }}</p>
<p *ngIf="app && app.state !== undefined" class="state"
[ngClass]="{'active': app.state === AppState.APP_STATE_ACTIVE, 'inactive': app.state === AppState.APP_STATE_INACTIVE}">
{{'APP.PAGES.DETAIL.STATE.'+app.state
| translate}}</p>
<p
*ngIf="app && app.state !== undefined"
class="state"
[ngClass]="{ active: app.state === AppState.APP_STATE_ACTIVE, inactive: app.state === AppState.APP_STATE_INACTIVE }"
>
{{ 'APP.PAGES.DETAIL.STATE.' + app.state | translate }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.ID' | translate }}</p>
<p *ngIf="app && app.id" class="info-row-desc">{{app.id }}</p>
<p *ngIf="app && app.id" class="info-row-desc">{{ app.id }}</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.DATECREATED' | translate }}</p>
<p *ngIf="app && app.details && app.details.creationDate" class="info-row-desc">{{app.details.creationDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="app && app.details && app.details.creationDate" class="info-row-desc">
{{ app.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.PAGES.DATECHANGED' | translate }}</p>
<p *ngIf="app && app.details && app.details.changeDate" class="info-row-desc">{{app.details.changeDate |
timestampToDate |
localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p *ngIf="app && app.details && app.details.changeDate" class="info-row-desc">
{{ app.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'APP.OIDC.INFO.CLIENTID' | translate }}</p>
<div class="copy-row" *ngIf="app?.oidcConfig?.clientId">
<button *ngIf="app.oidcConfig && app.oidcConfig?.clientId" [disabled]="copied === app.oidcConfig?.clientId"
[matTooltip]="(copied !== app.oidcConfig?.clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate"
cnslCopyToClipboard [valueToCopy]="app.oidcConfig.clientId" (copiedValue)="copied = $event">
{{app.oidcConfig?.clientId}}
<button
*ngIf="app.oidcConfig && app.oidcConfig?.clientId"
[disabled]="copied === app.oidcConfig?.clientId"
[matTooltip]="(copied !== app.oidcConfig?.clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="app.oidcConfig.clientId"
(copiedValue)="copied = $event"
>
{{ app.oidcConfig?.clientId }}
</button>
</div>
<div class="copy-row" *ngIf="app?.apiConfig?.clientId">
<button *ngIf="app && app.apiConfig && app.apiConfig.clientId" [disabled]="copied === app.apiConfig?.clientId"
[matTooltip]="(copied !== app.apiConfig?.clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate"
cnslCopyToClipboard [valueToCopy]="app.apiConfig.clientId" (copiedValue)="copied = $event">
{{app.apiConfig?.clientId}}
<button
*ngIf="app && app.apiConfig && app.apiConfig.clientId"
[disabled]="copied === app.apiConfig?.clientId"
[matTooltip]="(copied !== app.apiConfig?.clientId ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="app.apiConfig.clientId"
(copiedValue)="copied = $event"
>
{{ app.apiConfig?.clientId }}
</button>
</div>
</div>
</div>
</ng-container>
<div class="info-row" *ngIf="idp">
<div class="info-wrapper width">
<p class="info-row-title">{{ 'IDP.ID' | translate }}</p>
<div class="copy-row">
<button [disabled]="copied === idp.id"
[matTooltip]="(copied !== idp.id ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate" cnslCopyToClipboard
[valueToCopy]="idp.id" (copiedValue)="copied = $event">
{{idp.id}}
</button>
</div>
<p class="info-row-desc">
{{ idp.id }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'IDP.DETAIL.DATECREATED' | translate }}</p>
<p class="info-row-desc" *ngIf="idp && idp.details && idp.details.creationDate">{{idp.details.creationDate |
timestampToDate
| localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p class="info-row-desc" *ngIf="idp && idp.details && idp.details.creationDate">
{{ idp.details.creationDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'IDP.DETAIL.DATECHANGED' | translate }}</p>
<p class="info-row-desc" *ngIf="idp && idp.details && idp.details.changeDate">{{idp.details.changeDate |
timestampToDate |
localizedDate: 'dd. MMMM YYYY, HH:mm' }}</p>
<p class="info-row-desc" *ngIf="idp && idp.details && idp.details.changeDate">
{{ idp.details.changeDate | timestampToDate | localizedDate: 'dd. MMMM YYYY, HH:mm' }}
</p>
</div>
<div class="info-wrapper">
<p class="info-row-title">{{ 'IDP.STATE' | translate }}</p>
<p *ngIf="idp && idp.state !== undefined" class="state"
[ngClass]="{'active': idp.state === IDPState.IDP_STATE_ACTIVE, 'inactive': idp.state === IDPState.IDP_STATE_INACTIVE}">
{{'IDP.STATES.'+idp.state
| translate}}</p>
<p
*ngIf="idp && idp.state !== undefined"
class="state"
[ngClass]="{ active: idp.state === IDPState.IDP_STATE_ACTIVE, inactive: idp.state === IDPState.IDP_STATE_INACTIVE }"
>
{{ 'IDP.STATES.' + idp.state | translate }}
</p>
</div>
</div>
</div>
@@ -12,7 +12,7 @@
>{{ pageIndex * pageSize }} - {{ pageIndex * pageSize + pageSize }}
</span>
<div class="row" *ngIf="!hidePagination">
<cnsl-form-field class="size" appearance="outline">
<cnsl-form-field class="size">
<mat-select class="paginator-select" [(ngModel)]="pageSize" (selectionChange)="emitChange()">
<mat-option *ngFor="let sizeOption of pageSizeOptions" [value]="sizeOption">
{{ sizeOption }}
@@ -1,5 +1,3 @@
<!-- <cnsl-info-section *ngIf="isDefault"> {{ 'POLICY.DEFAULTLABEL' | translate }}</cnsl-info-section> -->
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
</div>
@@ -23,7 +23,7 @@
</button>
</div>
<form *ngIf="form" class="top-actions" [formGroup]="form">
<cnsl-form-field class="keys" appearance="outline">
<cnsl-form-field class="keys">
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.KEYNAME' | translate }}</cnsl-label>
<mat-select formControlName="currentSubMap" name="currentSubMap">
<mat-option *ngFor="let key of KeyNamesArray" [value]="key">
@@ -24,7 +24,6 @@
(detach)="submitColor()"
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isOpen"
(overlayOutsideClick)="isOpen = false"
>
<color-chrome class="picker" [color]="previewColor" (onChangeComplete)="changeComplete($event)"> </color-chrome>
<button class="close-icon" mat-mini-fab color="primary" (click)="submitColor()"><mat-icon>check</mat-icon></button>
@@ -1,8 +1,7 @@
<form>
<cnsl-form-field appearance="outline" class="full-width">
<cnsl-label>{{'USER.GRANTS.PROJECTNAME' | translate}}</cnsl-label>
<input cnslInput type="text" placeholder="Project XY" #nameInput [formControl]="myControl"
[matAutocomplete]="auto" />
<cnsl-form-field class="full-width">
<cnsl-label>{{ 'USER.GRANTS.PROJECTNAME' | translate }}</cnsl-label>
<input cnslInput type="text" placeholder="Project XY" #nameInput [formControl]="myControl" [matAutocomplete]="auto" />
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
<mat-option *ngIf="isLoading" class="is-loading">
@@ -11,14 +10,15 @@
<mat-option *ngFor="let project of filteredProjects" [value]="project">
<div class="project-option">
<div class="project-option-column">
<span>{{project?.name ? project?.name : project?.projectName ? project?.projectName : ''}}</span>
<span>{{ project?.name ? project?.name : project?.projectName ? project?.projectName : '' }}</span>
<span class="fill-space"></span>
<span class="smaller cnsl-secondary-text">{{(project.name ? 'USER.GRANTS.PROJECT-OWNED' :
project?.projectName ? 'USER.GRANTS.PROJECT-GRANTED' : '') |
translate}}</span>
<span class="smaller cnsl-secondary-text">{{
(project.name ? 'USER.GRANTS.PROJECT-OWNED' : project?.projectName ? 'USER.GRANTS.PROJECT-GRANTED' : '')
| translate
}}</span>
</div>
</div>
</mat-option>
</mat-autocomplete>
</cnsl-form-field>
</form>
</form>
@@ -1,27 +1,47 @@
<form>
<cnsl-form-field appearance="outline" class="full-width">
<cnsl-label>Role Name</cnsl-label>
<input cnslInput *ngIf="singleOutput" type="text" placeholder="Search for the role name" #nameInput
[formControl]="myControl" [matAutocomplete]="auto" />
<cnsl-form-field class="full-width">
<cnsl-label>Role Name</cnsl-label>
<input
cnslInput
*ngIf="singleOutput"
type="text"
placeholder="Search for the role name"
#nameInput
[formControl]="myControl"
[matAutocomplete]="auto"
/>
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="name selection">
<mat-chip class="chip" *ngFor="let selectedRole of roles" [selectable]="selectable" [removable]="removable"
(removed)="remove(selectedRole)">
{{selectedRole.displayName}}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input cnslInput placeholder="Role Name" #nameInput [formControl]="myControl" [matAutocomplete]="auto"
[matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur" (matChipInputTokenEnd)="add($event)" />
</mat-chip-list>
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="name selection">
<mat-chip
class="chip"
*ngFor="let selectedRole of roles"
[selectable]="selectable"
[removable]="removable"
(removed)="remove(selectedRole)"
>
{{ selectedRole.displayName }}
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip>
<input
cnslInput
placeholder="Role Name"
#nameInput
[formControl]="myControl"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)"
/>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
<mat-option *ngIf="isLoading" class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
<mat-option *ngFor="let role of filteredRoles" [value]="role.key">
{{role.displayName}}
</mat-option>
</mat-autocomplete>
</cnsl-form-field>
</form>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)" [displayWith]="displayFn">
<mat-option *ngIf="isLoading" class="is-loading">
<mat-spinner diameter="30"></mat-spinner>
</mat-option>
<mat-option *ngFor="let role of filteredRoles" [value]="role.key">
{{ role.displayName }}
</mat-option>
</mat-autocomplete>
</cnsl-form-field>
</form>