chore(console): dependencies, type checks (#4264)

* cli, core

* material cdk

* schematics

* chore(deps): bump ngx-color from 7.3.3 to 8.0.2 in /console (#4228)

Bumps [ngx-color](https://github.com/scttcper/ngx-color) from 7.3.3 to 8.0.2.
- [Release notes](https://github.com/scttcper/ngx-color/releases)
- [Commits](https://github.com/scttcper/ngx-color/compare/v7.3.3...v8.0.2)

---
updated-dependencies:
- dependency-name: ngx-color
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

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

* eslint-plugin

* chore(deps): bump moment from 2.29.3 to 2.29.4 in /console (#3926)

Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

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

* chore(deps): bump codemirror from 5.65.6 to 6.0.1 in /console (#3928)

Bumps [codemirror](https://github.com/codemirror/basic-setup) from 5.65.6 to 6.0.1.
- [Release notes](https://github.com/codemirror/basic-setup/releases)
- [Changelog](https://github.com/codemirror/basic-setup/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/basic-setup/commits/6.0.1)

---
updated-dependencies:
- dependency-name: codemirror
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

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

* lock

* use codemirror 5

* remove redundant null undefined checks

* i18n, undefined checks

* remove redundant null and undefined checks

* checks

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Max Peintner 2022-08-30 07:43:23 +02:00 committed by GitHub
parent 60b2092d2c
commit 70b3d80b37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 4026 additions and 4327 deletions

8043
console/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,18 +11,18 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^14.0.4", "@angular/animations": "^14.2.0",
"@angular/cdk": "^14.0.4", "@angular/cdk": "^14.2.0",
"@angular/common": "^14.0.4", "@angular/common": "^14.2.0",
"@angular/compiler": "^14.0.4", "@angular/compiler": "^14.2.0",
"@angular/core": "^14.0.4", "@angular/core": "^14.2.0",
"@angular/forms": "^14.0.4", "@angular/forms": "^14.2.0",
"@angular/material": "^14.0.4", "@angular/material": "^14.2.0",
"@angular/material-moment-adapter": "^14.0.4", "@angular/material-moment-adapter": "^14.2.0",
"@angular/platform-browser": "^14.0.4", "@angular/platform-browser": "^14.2.0",
"@angular/platform-browser-dynamic": "^14.0.4", "@angular/platform-browser-dynamic": "^14.2.0",
"@angular/router": "^14.0.4", "@angular/router": "^14.2.0",
"@angular/service-worker": "^14.0.4", "@angular/service-worker": "^14.2.0",
"@ctrl/ngx-codemirror": "^5.1.1", "@ctrl/ngx-codemirror": "^5.1.1",
"@grpc/grpc-js": "^1.5.7", "@grpc/grpc-js": "^1.5.7",
"@ngx-translate/core": "^14.0.0", "@ngx-translate/core": "^14.0.0",
@ -32,7 +32,7 @@
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"angular-oauth2-oidc": "^13.0.1", "angular-oauth2-oidc": "^13.0.1",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"codemirror": "^5.65.0", "codemirror": "^5.65.8",
"cors": "^2.8.5", "cors": "^2.8.5",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"google-proto-files": "^3.0.0", "google-proto-files": "^3.0.0",
@ -40,9 +40,9 @@
"grpc-web": "^1.3.0", "grpc-web": "^1.3.0",
"libphonenumber-js": "^1.10.6", "libphonenumber-js": "^1.10.6",
"material-design-icons-iconfont": "^6.1.1", "material-design-icons-iconfont": "^6.1.1",
"moment": "^2.29.1", "moment": "^2.29.4",
"ng-qrcode": "^7.0.0", "ng-qrcode": "^7.0.0",
"ngx-color": "^7.2.0", "ngx-color": "^8.0.2",
"ngx-quicklink": "^0.2.6", "ngx-quicklink": "^0.2.6",
"rxjs": "~7.5.2", "rxjs": "~7.5.2",
"tinycolor2": "^1.4.2", "tinycolor2": "^1.4.2",
@ -51,20 +51,20 @@
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^14.0.4", "@angular-devkit/build-angular": "^14.2.1",
"@angular-eslint/builder": "^14.0.0", "@angular-eslint/builder": "^14.0.3",
"@angular-eslint/eslint-plugin": "^14.0.0", "@angular-eslint/eslint-plugin": "^14.0.3",
"@angular-eslint/eslint-plugin-template": "^14.0.0", "@angular-eslint/eslint-plugin-template": "^14.0.3",
"@angular-eslint/schematics": "^14.0.0", "@angular-eslint/schematics": "^14.0.3",
"@angular-eslint/template-parser": "^14.0.0", "@angular-eslint/template-parser": "^14.0.3",
"@angular/cli": "^14.0.4", "@angular/cli": "^14.2.1",
"@angular/compiler-cli": "^14.0.4", "@angular/compiler-cli": "^14.2.0",
"@angular/language-service": "^14.0.4", "@angular/language-service": "^14.2.0",
"@types/jasmine": "~4.0.3", "@types/jasmine": "~4.0.3",
"@types/jasminewd2": "~2.0.10", "@types/jasminewd2": "~2.0.10",
"@types/jsonwebtoken": "^8.5.5", "@types/jsonwebtoken": "^8.5.5",
"@types/node": "^17.0.42", "@types/node": "^17.0.42",
"@typescript-eslint/eslint-plugin": "5.30.4", "@typescript-eslint/eslint-plugin": "5.35.1",
"@typescript-eslint/parser": "5.30.4", "@typescript-eslint/parser": "5.30.4",
"codelyzer": "^6.0.0", "codelyzer": "^6.0.0",
"eslint": "^8.18.0", "eslint": "^8.18.0",

View File

@ -4,7 +4,7 @@
[dataSize]="dataSource.totalResult" [dataSize]="dataSource.totalResult"
[timestamp]="dataSource.viewTimestamp" [timestamp]="dataSource.viewTimestamp"
[selection]="selection" [selection]="selection"
[loading]="dataSource?.loading$ | async" [loading]="dataSource.loading$ | async"
> >
<ng-container actions *ngIf="selection.hasValue()"> <ng-container actions *ngIf="selection.hasValue()">
<ng-content select="[selectactions]"></ng-content> <ng-content select="[selectactions]"></ng-content>
@ -139,7 +139,7 @@
*ngIf="dataSource" *ngIf="dataSource"
class="paginator" class="paginator"
#paginator #paginator
[timestamp]="dataSource?.viewTimestamp" [timestamp]="dataSource.viewTimestamp"
[pageSize]="INITIALPAGESIZE" [pageSize]="INITIALPAGESIZE"
[length]="dataSource.totalResult" [length]="dataSource.totalResult"
[pageSizeOptions]="[25, 50, 100, 250]" [pageSizeOptions]="[25, 50, 100, 250]"

View File

@ -32,7 +32,7 @@ export class MembersTableComponent implements OnInit, OnDestroy {
@Input() public canWrite: boolean | null = false; @Input() public canWrite: boolean | null = false;
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; @ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
@ViewChild(MatTable) public table!: MatTable<Member.AsObject>; @ViewChild(MatTable) public table!: MatTable<Member.AsObject>;
@Input() public dataSource!: MemberDatasource; @Input() public dataSource?: MemberDatasource;
public selection: SelectionModel<any> = new SelectionModel<any>(true, []); public selection: SelectionModel<any> = new SelectionModel<any>(true, []);
@Input() public memberRoleOptions: string[] = []; @Input() public memberRoleOptions: string[] = [];
@Input() public factoryLoadFunc!: Function; @Input() public factoryLoadFunc!: Function;
@ -112,14 +112,14 @@ export class MembersTableComponent implements OnInit, OnDestroy {
public isAllSelected(): boolean { public isAllSelected(): boolean {
const numSelected = this.selection.selected.length; const numSelected = this.selection.selected.length;
const numRows = this.dataSource.membersSubject.value.length; const numRows = this.dataSource?.membersSubject.value.length;
return numSelected === numRows; return numSelected === numRows;
} }
public masterToggle(): void { public masterToggle(): void {
this.isAllSelected() this.isAllSelected()
? this.selection.clear() ? this.selection.clear()
: this.dataSource.membersSubject.value.forEach((row: Member.AsObject) => this.selection.select(row)); : this.dataSource?.membersSubject.value.forEach((row: Member.AsObject) => this.selection.select(row));
} }
public changePage(event?: PageEvent): any { public changePage(event?: PageEvent): any {

View File

@ -125,8 +125,8 @@
*ngIf="(mgmtService?.ownedProjectsCount | async) && (mgmtService?.grantedProjectsCount | async)" *ngIf="(mgmtService?.ownedProjectsCount | async) && (mgmtService?.grantedProjectsCount | async)"
class="count" class="count"
>({{ >({{
((mgmtService?.ownedProjectsCount | async) ?? 0) + ((mgmtService.ownedProjectsCount | async) ?? 0) +
((mgmtService?.grantedProjectsCount | async) ?? 0) ((mgmtService.grantedProjectsCount | async) ?? 0)
}})</small }})</small
> >
</div> </div>

View File

@ -20,7 +20,7 @@
class="org-button-with-pin" class="org-button-with-pin"
mat-button mat-button
[ngClass]="{ [ngClass]="{
active: pinnedorg.id === org?.id, active: pinnedorg.id === org.id,
'border-bottom': pinned.selected.length && i === pinned.selected.length - 1 'border-bottom': pinned.selected.length && i === pinned.selected.length - 1
}" }"
[disabled]="!pinnedorg.id" [disabled]="!pinnedorg.id"
@ -37,7 +37,7 @@
*ngIf="!pinned.isSelected(temporg)" *ngIf="!pinned.isSelected(temporg)"
class="org-button-with-pin" class="org-button-with-pin"
mat-button mat-button
[ngClass]="{ active: temporg.id === org?.id }" [ngClass]="{ active: temporg.id === org.id }"
[disabled]="!temporg.id" [disabled]="!temporg.id"
(click)="setActiveOrg(temporg)" (click)="setActiveOrg(temporg)"
> >

View File

@ -1,8 +1,17 @@
<cnsl-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length" <cnsl-refresh-table
[timestamp]="keyResult?.details?.viewTimestamp" [selection]="selection"> [loading]="loading$ | async"
(refreshed)="refreshPage()"
[dataSize]="dataSource.data.length"
[timestamp]="keyResult?.details?.viewTimestamp"
[selection]="selection"
>
<div actions> <div actions>
<a [disabled]="([('user.write:' + userId), 'user.write'] | hasRole | async) === false" color="primary" <a
mat-raised-button (click)="openAddKey()"> [disabled]="(['user.write:' + userId, 'user.write'] | hasRole | async) === false"
color="primary"
mat-raised-button
(click)="openAddKey()"
>
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }} <mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
</a> </a>
</div> </div>
@ -11,34 +20,41 @@
<table class="table" mat-table [dataSource]="dataSource"> <table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="select"> <ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null" <mat-checkbox
color="primary"
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()" [checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"> [indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox> </mat-checkbox>
</th> </th>
<td mat-cell *matCellDef="let key"> <td mat-cell *matCellDef="let key">
<mat-checkbox color="primary" (click)="$event.stopPropagation()" <mat-checkbox
(change)="$event ? selection.toggle(key) : null" [checked]="selection.isSelected(key)"> color="primary"
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(key) : null"
[checked]="selection.isSelected(key)"
>
</mat-checkbox> </mat-checkbox>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PERSONALACCESSTOKEN.ID' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.PERSONALACCESSTOKEN.ID' | translate }}</th>
<td mat-cell *matCellDef="let key"> {{key?.id}} </td> <td mat-cell *matCellDef="let key">{{ key?.id }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="creationDate"> <ng-container matColumnDef="creationDate">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.CREATIONDATE' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.MACHINE.CREATIONDATE' | translate }}</th>
<td mat-cell *matCellDef="let key"> <td mat-cell *matCellDef="let key">
{{key.details?.creationDate | timestampToDate | localizedDate: 'fromNow'}} {{ key.details?.creationDate | timestampToDate | localizedDate: 'fromNow' }}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="expirationDate"> <ng-container matColumnDef="expirationDate">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MACHINE.EXPIRATIONDATE' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.MACHINE.EXPIRATIONDATE' | translate }}</th>
<td mat-cell *matCellDef="let key"> <td mat-cell *matCellDef="let key">
{{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}} {{ key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm' }}
</td> </td>
</ng-container> </ng-container>
@ -46,8 +62,14 @@
<th mat-header-cell *matHeaderCellDef></th> <th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let key"> <td mat-cell *matCellDef="let key">
<cnsl-table-actions> <cnsl-table-actions>
<button actions [disabled]="([('user.write:' + userId), 'user.write'] | hasRole | async) === false" <button
mat-icon-button color="warn" matTooltip="{{'ACTIONS.DELETE' | translate}}" (click)="deleteKey(key)"> actions
[disabled]="(['user.write:' + userId, 'user.write'] | hasRole | async) === false"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.DELETE' | translate }}"
(click)="deleteKey(key)"
>
<i class="las la-trash"></i> <i class="las la-trash"></i>
</button> </button>
</cnsl-table-actions> </cnsl-table-actions>
@ -55,12 +77,16 @@
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"> <tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</tr>
</table> </table>
<cnsl-paginator #paginator class="paginator" [timestamp]="keyResult?.details?.viewTimestamp" <cnsl-paginator
[length]="keyResult?.details?.totalResult || 0" [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" #paginator
(page)="changePage($event)"></cnsl-paginator> class="paginator"
[timestamp]="keyResult?.details?.viewTimestamp"
[length]="keyResult?.details?.totalResult || 0"
[pageSize]="10"
[pageSizeOptions]="[5, 10, 20]"
(page)="changePage($event)"
></cnsl-paginator>
</div> </div>
</cnsl-refresh-table> </cnsl-refresh-table>

View File

@ -26,13 +26,14 @@ export class PersonalAccessTokensComponent implements OnInit {
@Input() userId!: string; @Input() userId!: string;
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; @ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
public dataSource: MatTableDataSource<PersonalAccessToken.AsObject> = public dataSource: MatTableDataSource<PersonalAccessToken.AsObject> = new MatTableDataSource<PersonalAccessToken.AsObject>(
new MatTableDataSource<PersonalAccessToken.AsObject>(); [],
);
public selection: SelectionModel<PersonalAccessToken.AsObject> = new SelectionModel<PersonalAccessToken.AsObject>( public selection: SelectionModel<PersonalAccessToken.AsObject> = new SelectionModel<PersonalAccessToken.AsObject>(
true, true,
[], [],
); );
public keyResult!: ListPersonalAccessTokensResponse.AsObject; public keyResult: ListPersonalAccessTokensResponse.AsObject | undefined = undefined;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable(); public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@Input() public displayedColumns: string[] = ['id', 'creationDate', 'expirationDate', 'actions']; @Input() public displayedColumns: string[] = ['id', 'creationDate', 'expirationDate', 'actions'];

View File

@ -24,9 +24,9 @@ export class ProjectRolesTableComponent implements OnInit {
@Input() public actionsVisible: boolean = false; @Input() public actionsVisible: boolean = false;
@Input() public selectedKeys: string[] = []; @Input() public selectedKeys: string[] = [];
@Input() public showSelectionActionButton: boolean = true; @Input() public showSelectionActionButton: boolean = true;
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; @ViewChild(PaginatorComponent) public paginator?: PaginatorComponent;
@ViewChild(MatTable) public table!: MatTable<Role.AsObject>; @ViewChild(MatTable) public table?: MatTable<Role.AsObject>;
public dataSource!: ProjectRolesDataSource; public dataSource: ProjectRolesDataSource = new ProjectRolesDataSource(this.mgmtService);
public selection: SelectionModel<Role.AsObject> = new SelectionModel<Role.AsObject>(true, []); public selection: SelectionModel<Role.AsObject> = new SelectionModel<Role.AsObject>(true, []);
@Output() public changedSelection: EventEmitter<Array<Role.AsObject>> = new EventEmitter(); @Output() public changedSelection: EventEmitter<Array<Role.AsObject>> = new EventEmitter();
@Input() public displayedColumns: string[] = ['key', 'displayname', 'group', 'creationDate', 'changeDate', 'actions']; @Input() public displayedColumns: string[] = ['key', 'displayname', 'group', 'creationDate', 'changeDate', 'actions'];
@ -36,9 +36,7 @@ export class ProjectRolesTableComponent implements OnInit {
private toast: ToastService, private toast: ToastService,
private dialog: MatDialog, private dialog: MatDialog,
private router: Router, private router: Router,
) { ) {}
this.dataSource = new ProjectRolesDataSource(this.mgmtService);
}
public gotoRouterLink(rL: any) { public gotoRouterLink(rL: any) {
this.router.navigate(rL); this.router.navigate(rL);
@ -63,7 +61,7 @@ export class ProjectRolesTableComponent implements OnInit {
} }
private loadRolesPage(): void { private loadRolesPage(): void {
this.dataSource.loadRoles(this.projectId, this.grantId, this.paginator.pageIndex, this.paginator.pageSize); this.dataSource.loadRoles(this.projectId, this.grantId, this.paginator?.pageIndex ?? 0, this.paginator?.pageSize ?? 25);
} }
public changePage(): void { public changePage(): void {
@ -134,7 +132,7 @@ export class ProjectRolesTableComponent implements OnInit {
} }
public refreshPage(): void { public refreshPage(): void {
this.dataSource.loadRoles(this.projectId, this.grantId, this.paginator.pageIndex, this.paginator.pageSize); this.dataSource.loadRoles(this.projectId, this.grantId, this.paginator?.pageIndex ?? 0, this.paginator?.pageSize ?? 25);
} }
public get selectionAllowed(): boolean { public get selectionAllowed(): boolean {

View File

@ -128,7 +128,7 @@ export class DialogPasswordlessComponent {
this.service this.service
.sendMyPasswordlessLink() .sendMyPasswordlessLink()
.then(() => { .then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT'); this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT', true);
this.showSent = true; this.showSent = true;
}) })
.catch((error) => { .catch((error) => {

View File

@ -1,32 +1,50 @@
<cnsl-card title="{{'USER.PASSWORDLESS.TITLE' | translate}}" <cnsl-card
description="{{'USER.PASSWORDLESS.DESCRIPTION' | translate}}"> title="{{ 'USER.PASSWORDLESS.TITLE' | translate }}"
description="{{ 'USER.PASSWORDLESS.DESCRIPTION' | translate }}"
<button card-actions mat-icon-button (click)="getPasswordless()" class="icon-button" >
matTooltip="{{'ACTIONS.REFRESH' | translate}}"> <button
card-actions
mat-icon-button
(click)="getPasswordless()"
class="icon-button"
matTooltip="{{ 'ACTIONS.REFRESH' | translate }}"
>
<mat-icon class="icon">refresh</mat-icon> <mat-icon class="icon">refresh</mat-icon>
</button> </button>
<cnsl-refresh-table [hideRefresh]="true" [loading]="loading$ | async" [dataSize]="dataSource?.data?.length ?? 0"> <cnsl-refresh-table [hideRefresh]="true" [loading]="loading$ | async" [dataSize]="dataSource.data.length">
<button actions [disabled]="user && disabled" class="button cnsl-action-button" <button
(click)="sendPasswordlessRegistration()" mat-raised-button color="primary" actions
matTooltip="{{'ACTIONS.NEW' | translate}}"> [disabled]="user && disabled"
class="button cnsl-action-button"
(click)="sendPasswordlessRegistration()"
mat-raised-button
color="primary"
matTooltip="{{ 'ACTIONS.NEW' | translate }}"
>
<i class="icon las la-paper-plane"></i> <i class="icon las la-paper-plane"></i>
<span>{{'USER.PASSWORDLESS.SEND' | translate}}</span> <span>{{ 'USER.PASSWORDLESS.SEND' | translate }}</span>
</button> </button>
<table class="table" mat-table [dataSource]="dataSource"> <table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.NAME' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.PASSWORDLESS.NAME' | translate }}</th>
<td mat-cell *matCellDef="let mfa"><span *ngIf="mfa?.name" class="centered"> <td mat-cell *matCellDef="let mfa">
<span *ngIf="mfa?.name" class="centered">
{{ mfa?.name }} {{ mfa?.name }}
</span> </span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="state"> <ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.TABLESTATE' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.PASSWORDLESS.TABLESTATE' | translate }}</th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<span class="state" <span
[ngClass]="{'active': mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY, 'inactive': mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY }">{{'USER.PASSWORDLESS.STATE.'+ class="state"
mfa.state | translate}}</span> [ngClass]="{
active: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY,
inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY
}"
>{{ 'USER.PASSWORDLESS.STATE.' + mfa.state | translate }}</span
>
</td> </td>
</ng-container> </ng-container>
@ -34,8 +52,13 @@
<th mat-header-cell *matHeaderCellDef></th> <th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<cnsl-table-actions> <cnsl-table-actions>
<button actions matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" mat-icon-button <button
(click)="deletePasswordless(mfa.id)"> actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
mat-icon-button
(click)="deletePasswordless(mfa.id)"
>
<i class="las la-trash"></i> <i class="las la-trash"></i>
</button> </button>
</cnsl-table-actions> </cnsl-table-actions>
@ -43,11 +66,11 @@
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
<div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row"> <div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row">
<i class="las la-exclamation"></i> <i class="las la-exclamation"></i>
<span>{{'USER.PASSWORDLESS.EMPTY' | translate}}</span> <span>{{ 'USER.PASSWORDLESS.EMPTY' | translate }}</span>
</div> </div>
</cnsl-refresh-table> </cnsl-refresh-table>
@ -56,4 +79,4 @@
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
</div> </div>
</cnsl-card> </cnsl-card>

View File

@ -32,7 +32,7 @@ export class PasswordlessComponent implements OnInit, OnDestroy {
@ViewChild(MatTable) public table!: MatTable<WebAuthNToken.AsObject>; @ViewChild(MatTable) public table!: MatTable<WebAuthNToken.AsObject>;
@ViewChild(MatSort) public sort!: MatSort; @ViewChild(MatSort) public sort!: MatSort;
public dataSource!: MatTableDataSource<WebAuthNToken.AsObject>; public dataSource: MatTableDataSource<WebAuthNToken.AsObject> = new MatTableDataSource<WebAuthNToken.AsObject>([]);
public AuthFactorState: any = AuthFactorState; public AuthFactorState: any = AuthFactorState;
public error: string = ''; public error: string = '';
@ -89,7 +89,7 @@ export class PasswordlessComponent implements OnInit, OnDestroy {
this.service this.service
.sendPasswordlessRegistration(this.user.id) .sendPasswordlessRegistration(this.user.id)
.then(() => { .then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT'); this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT', true);
}) })
.catch((error) => { .catch((error) => {
this.toast.showError(error); this.toast.showError(error);

View File

@ -1,15 +1,15 @@
<cnsl-top-view <cnsl-top-view
*ngIf="user" *ngIf="user"
title="{{ user?.human ? user.human?.profile?.displayName : user?.machine?.name }}" title="{{ user.human ? user.human.profile?.displayName : user.machine?.name }}"
docLink="https://docs.zitadel.com/docs/guides/basics/projects" docLink="https://docs.zitadel.com/docs/guides/basics/projects"
sub="{{ user?.preferredLoginName }}" sub="{{ user.preferredLoginName }}"
[isActive]="user?.state === UserState.USER_STATE_ACTIVE" [isActive]="user.state === UserState.USER_STATE_ACTIVE"
[isInactive]="user?.state === UserState.USER_STATE_INACTIVE" [isInactive]="user.state === UserState.USER_STATE_INACTIVE"
stateTooltip="{{ 'USER.STATE.' + user?.state | translate }}" stateTooltip="{{ 'USER.STATE.' + user.state | translate }}"
(backClicked)="navigateBack()" (backClicked)="navigateBack()"
[hasActions]="['user.write$', 'user.write:' + user?.id] | hasRole | async" [hasActions]="['user.write$', 'user.write:' + user.id] | hasRole | async"
> >
<ng-template topActions cnslHasRole [hasRole]="['user.write$', 'user.write:' + user?.id]"> <ng-template topActions cnslHasRole [hasRole]="['user.write$', 'user.write:' + user.id]">
<button mat-menu-item color="warn" *ngIf="user?.state === UserState.USER_STATE_LOCKED" (click)="unlockUser()"> <button mat-menu-item color="warn" *ngIf="user?.state === UserState.USER_STATE_LOCKED" (click)="unlockUser()">
{{ 'USER.PAGES.UNLOCK' | translate }} {{ 'USER.PAGES.UNLOCK' | translate }}
</button> </button>
@ -27,7 +27,7 @@
> >
{{ 'USER.PAGES.REACTIVATE' | translate }} {{ 'USER.PAGES.REACTIVATE' | translate }}
</button> </button>
<ng-template cnslHasRole [hasRole]="['user.delete$', 'user.delete:' + user?.id]"> <ng-template cnslHasRole [hasRole]="['user.delete$', 'user.delete:' + user.id]">
<button mat-menu-item matTooltip="{{ 'USER.PAGES.DELETE' | translate }}" (click)="deleteUser()"> <button mat-menu-item matTooltip="{{ 'USER.PAGES.DELETE' | translate }}" (click)="deleteUser()">
<span [style.color]="'var(--warn)'">{{ 'USER.PAGES.DELETE' | translate }}</span> <span [style.color]="'var(--warn)'">{{ 'USER.PAGES.DELETE' | translate }}</span>
</button> </button>
@ -60,7 +60,7 @@
<span *ngIf="!loading && !user">{{ 'USER.PAGES.NOUSER' | translate }}</span> <span *ngIf="!loading && !user">{{ 'USER.PAGES.NOUSER' | translate }}</span>
<ng-container *ngIf="currentSetting === 'general'"> <ng-container *ngIf="currentSetting === 'general'">
<ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user?.id]"> <ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user.id]">
<cnsl-card *ngIf="user.human" title="{{ 'USER.PROFILE.TITLE' | translate }}"> <cnsl-card *ngIf="user.human" title="{{ 'USER.PROFILE.TITLE' | translate }}">
<cnsl-detail-form <cnsl-detail-form
[preferredLoginName]="user.preferredLoginName" [preferredLoginName]="user.preferredLoginName"
@ -92,7 +92,7 @@
<cnsl-contact <cnsl-contact
[disablePhoneCode]="true" [disablePhoneCode]="true"
[state]="user.state" [state]="user.state"
[canWrite]="['user.write:' + user?.id, 'user.write$'] | hasRole | async" [canWrite]="['user.write:' + user.id, 'user.write$'] | hasRole | async"
*ngIf="user?.human" *ngIf="user?.human"
[human]="user.human" [human]="user.human"
(editType)="openEditDialog($event)" (editType)="openEditDialog($event)"
@ -146,7 +146,7 @@
</ng-container> </ng-container>
<ng-container *ngIf="currentSetting && currentSetting === 'pat'"> <ng-container *ngIf="currentSetting && currentSetting === 'pat'">
<ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user?.id]"> <ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user.id]">
<cnsl-card <cnsl-card
*ngIf="user.machine && user.id" *ngIf="user.machine && user.id"
title="{{ 'USER.MACHINE.TOKENSTITLE' | translate }}" title="{{ 'USER.MACHINE.TOKENSTITLE' | translate }}"
@ -158,7 +158,7 @@
</ng-container> </ng-container>
<ng-container *ngIf="currentSetting && currentSetting === 'keys'"> <ng-container *ngIf="currentSetting && currentSetting === 'keys'">
<ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user?.id]"> <ng-template cnslHasRole [hasRole]="['user.read$', 'user.read:' + user.id]">
<cnsl-card <cnsl-card
*ngIf="user.machine && user.id" *ngIf="user.machine && user.id"
title="{{ 'USER.MACHINE.KEYSTITLE' | translate }}" title="{{ 'USER.MACHINE.KEYSTITLE' | translate }}"

View File

@ -1,13 +1,22 @@
<cnsl-card title="{{'USER.MFA.TITLE' | translate}}" description="{{'USER.MFA.DESCRIPTION' | translate}}"> <cnsl-card title="{{ 'USER.MFA.TITLE' | translate }}" description="{{ 'USER.MFA.DESCRIPTION' | translate }}">
<button card-actions mat-icon-button (click)="getMFAs()" class="icon-button" <button
matTooltip="{{'ACTIONS.REFRESH' | translate}}"> card-actions
mat-icon-button
(click)="getMFAs()"
class="icon-button"
matTooltip="{{ 'ACTIONS.REFRESH' | translate }}"
>
<mat-icon class="icon">refresh</mat-icon> <mat-icon class="icon">refresh</mat-icon>
</button> </button>
<cnsl-refresh-table [hideRefresh]="true" [loading]="loading$ | async" (refreshed)="getMFAs()" <cnsl-refresh-table
[dataSize]="dataSource?.data?.length ?? 0"> [hideRefresh]="true"
[loading]="loading$ | async"
(refreshed)="getMFAs()"
[dataSize]="dataSource.data.length"
>
<table class="table" mat-table [dataSource]="dataSource"> <table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="type"> <ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.TABLETYPE' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLETYPE' | translate }}</th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<span *ngIf="mfa.otp !== undefined">OTP (One-Time Password)</span> <span *ngIf="mfa.otp !== undefined">OTP (One-Time Password)</span>
<span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span> <span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span>
@ -15,7 +24,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.NAME' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.NAME' | translate }}</th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<span *ngIf="mfa?.u2f?.name" class="centered"> <span *ngIf="mfa?.u2f?.name" class="centered">
{{ mfa.u2f.name }} {{ mfa.u2f.name }}
@ -24,11 +33,16 @@
</ng-container> </ng-container>
<ng-container matColumnDef="state"> <ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.TABLESTATE' | translate }} </th> <th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLESTATE' | translate }}</th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<span class="state" <span
[ngClass]="{'active': mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY, 'inactive': mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY}"> class="state"
{{'USER.MFA.STATE.'+ mfa.state | translate}} [ngClass]="{
active: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY,
inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY
}"
>
{{ 'USER.MFA.STATE.' + mfa.state | translate }}
</span> </span>
</td> </td>
</ng-container> </ng-container>
@ -37,8 +51,13 @@
<th mat-header-cell *matHeaderCellDef></th> <th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let mfa"> <td mat-cell *matCellDef="let mfa">
<cnsl-table-actions> <cnsl-table-actions>
<button actions matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" mat-icon-button <button
(click)="deleteMFA(mfa)"> actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn"
mat-icon-button
(click)="deleteMFA(mfa)"
>
<i class="las la-trash"></i> <i class="las la-trash"></i>
</button> </button>
</cnsl-table-actions> </cnsl-table-actions>
@ -46,12 +65,11 @@
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"> <tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</tr>
</table> </table>
<div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row"> <div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row">
<i class="las la-exclamation"></i> <i class="las la-exclamation"></i>
<span>{{'USER.MFA.EMPTY' | translate}}</span> <span>{{ 'USER.MFA.EMPTY' | translate }}</span>
</div> </div>
</cnsl-refresh-table> </cnsl-refresh-table>
<div class="table-wrapper"> <div class="table-wrapper">
@ -59,4 +77,4 @@
<mat-spinner diameter="50"></mat-spinner> <mat-spinner diameter="50"></mat-spinner>
</div> </div>
</div> </div>
</cnsl-card> </cnsl-card>

View File

@ -27,7 +27,7 @@ export class UserMfaComponent implements OnInit, OnDestroy {
@ViewChild(MatTable) public table!: MatTable<AuthFactor.AsObject>; @ViewChild(MatTable) public table!: MatTable<AuthFactor.AsObject>;
@ViewChild(MatSort) public sort!: MatSort; @ViewChild(MatSort) public sort!: MatSort;
public dataSource!: MatTableDataSource<AuthFactor.AsObject>; public dataSource: MatTableDataSource<AuthFactor.AsObject> = new MatTableDataSource<AuthFactor.AsObject>([]);
public AuthFactorState: any = AuthFactorState; public AuthFactorState: any = AuthFactorState;