fix(console): use authService for auth user page (#5233)

* auth grant

* fix: add missing attributes to ListMyUserGrantsResponse

* user grants typing

* typing

* auth grant link

* disable without role

* edit with auth grant

* chore(console): auto organize imports (#5293)

fix(console): auto organize imports

* Update console/src/app/modules/user-grants/user-grants-datasource.ts

Co-authored-by: Elio Bischof <eliobischof@gmail.com>

* Update console/src/app/modules/user-grants/user-grants-datasource.ts

Co-authored-by: Elio Bischof <eliobischof@gmail.com>

* Update console/src/app/modules/user-grants/user-grants-datasource.ts

Co-authored-by: Elio Bischof <eliobischof@gmail.com>

* linter, rm unused import

* add examples again

* lint

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Elio Bischof <eliobischof@gmail.com>
This commit is contained in:
Max Peintner 2023-02-27 12:03:44 +01:00 committed by GitHub
parent c4ca72fe68
commit 9396e8b2f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 117 additions and 118 deletions

View File

@ -1,6 +1,5 @@
{ {
"printWidth": 125, "printWidth": 125,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all"
"organizeImportsSkipDestructiveCodeActions": true
} }

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
import { GrpcAuthService } from '../services/grpc-auth.service'; import { GrpcAuthService } from '../services/grpc-auth.service';

View File

@ -1,8 +1,6 @@
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay'; import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { MatLegacyOptionSelectionChange } from '@angular/material/legacy-core';
import { MatLegacySelectChange } from '@angular/material/legacy-select';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { take } from 'rxjs'; import { take } from 'rxjs';

View File

@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core'; import { Component } from '@angular/core';
import { LabelPolicy, PrivacyPolicy } from 'src/app/proto/generated/zitadel/policy_pb'; import { PrivacyPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@Component({ @Component({

View File

@ -3,7 +3,6 @@ import { Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChil
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs'; import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb'; import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { AuthenticationService } from 'src/app/services/authentication.service'; import { AuthenticationService } from 'src/app/services/authentication.service';
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';

View File

@ -3,10 +3,8 @@ import {
MatLegacyDialogRef as MatDialogRef, MatLegacyDialogRef as MatDialogRef,
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
} from '@angular/material/legacy-dialog'; } from '@angular/material/legacy-dialog';
import { Buffer } from 'buffer';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { Metadata } from 'src/app/proto/generated/zitadel/metadata_pb'; import { Metadata } from 'src/app/proto/generated/zitadel/metadata_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@Component({ @Component({

View File

@ -5,7 +5,7 @@ import { HttpClient } from '@angular/common/http';
import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core'; import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms'; import { UntypedFormControl } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BehaviorSubject, combineLatest, map, Observable, Subject, take, tap } from 'rxjs'; import { BehaviorSubject, combineLatest, map, Observable, Subject, take } from 'rxjs';
import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb'; import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';

View File

@ -1,18 +1,12 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MatRippleModule } from '@angular/material/core';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip'; import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { ShortcutsModule } from 'src/app/modules/shortcuts/shortcuts.module';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { EventPipeModule } from 'src/app/pipes/event-pipe/event-pipe.module'; import { EventPipeModule } from 'src/app/pipes/event-pipe/event-pipe.module';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
import { OnboardingCardComponent } from './onboarding-card.component'; import { OnboardingCardComponent } from './onboarding-card.component';
@NgModule({ @NgModule({

View File

@ -5,7 +5,7 @@ import { MatSort, Sort } from '@angular/material/sort';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, catchError, finalize, from, map, Observable, of, Subject, switchMap, take, takeUntil } from 'rxjs'; import { BehaviorSubject, catchError, finalize, from, map, Observable, of, Subject, switchMap, takeUntil } from 'rxjs';
import { Org, OrgFieldName, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb'; import { Org, OrgFieldName, OrgQuery, OrgState } from 'src/app/proto/generated/zitadel/org_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';

View File

@ -1,5 +1,4 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { EventManager } from '@angular/platform-browser';
import { Timestamp } from 'src/app/proto/generated/google/protobuf/timestamp_pb'; import { Timestamp } from 'src/app/proto/generated/google/protobuf/timestamp_pb';
export interface PageEvent { export interface PageEvent {

View File

@ -8,7 +8,6 @@ import {
AddSMTPConfigResponse, AddSMTPConfigResponse,
UpdateSMSProviderTwilioRequest, UpdateSMSProviderTwilioRequest,
UpdateSMTPConfigPasswordRequest, UpdateSMTPConfigPasswordRequest,
UpdateSMTPConfigPasswordResponse,
UpdateSMTPConfigRequest, UpdateSMTPConfigRequest,
UpdateSMTPConfigResponse, UpdateSMTPConfigResponse,
} from 'src/app/proto/generated/zitadel/admin_pb'; } from 'src/app/proto/generated/zitadel/admin_pb';

View File

@ -1,5 +1,5 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { MatLegacyTable as MatTable } from '@angular/material/legacy-table'; import { MatLegacyTable as MatTable } from '@angular/material/legacy-table';
import { Router } from '@angular/router'; import { Router } from '@angular/router';

View File

@ -3,7 +3,6 @@ import {
MatLegacyDialogRef as MatDialogRef, MatLegacyDialogRef as MatDialogRef,
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
} from '@angular/material/legacy-dialog'; } from '@angular/material/legacy-dialog';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
@Component({ @Component({
selector: 'cnsl-user-grant-role-dialog', selector: 'cnsl-user-grant-role-dialog',

View File

@ -1,33 +1,37 @@
import { DataSource } from '@angular/cdk/collections'; import { DataSource } from '@angular/cdk/collections';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, from, Observable, of } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators'; import { ListMyUserGrantsResponse, UserGrant as AuthUserGrant } from 'src/app/proto/generated/zitadel/auth_pb';
import { ListUserGrantResponse } from 'src/app/proto/generated/zitadel/management_pb'; import { ListUserGrantResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { import {
UserGrant, UserGrant as MgmtUserGrant,
UserGrantProjectGrantIDQuery, UserGrantProjectGrantIDQuery,
UserGrantProjectIDQuery, UserGrantProjectIDQuery,
UserGrantQuery, UserGrantQuery,
UserGrantUserIDQuery, UserGrantUserIDQuery,
} from 'src/app/proto/generated/zitadel/user_pb'; } from 'src/app/proto/generated/zitadel/user_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
export enum UserGrantContext { export enum UserGrantContext {
NONE = 'none', NONE = 'none',
AUTHUSER = 'authuser',
USER = 'user', USER = 'user',
OWNED_PROJECT = 'owned', OWNED_PROJECT = 'owned',
GRANTED_PROJECT = 'granted', GRANTED_PROJECT = 'granted',
} }
export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> { type UserGrantAsObject = AuthUserGrant.AsObject | MgmtUserGrant.AsObject;
export class UserGrantsDataSource extends DataSource<UserGrantAsObject> {
public totalResult: number = 0; public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject; public viewTimestamp!: Timestamp.AsObject;
public grantsSubject: BehaviorSubject<UserGrant.AsObject[]> = new BehaviorSubject<UserGrant.AsObject[]>([]); public grantsSubject: BehaviorSubject<Array<UserGrantAsObject>> = new BehaviorSubject<Array<UserGrantAsObject>>([]);
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();
constructor(private userService: ManagementService) { constructor(private authService: GrpcAuthService, private userService: ManagementService) {
super(); super();
} }
@ -43,6 +47,13 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
queries?: UserGrantQuery[], queries?: UserGrantQuery[],
): void { ): void {
switch (context) { switch (context) {
case UserGrantContext.AUTHUSER:
if (data && data.userId) {
this.loadingSubject.next(true);
const promise = this.authService.listMyUserGrants(pageSize, pageSize * pageIndex);
this.loadResponse(promise);
}
break;
case UserGrantContext.USER: case UserGrantContext.USER:
if (data && data.userId) { if (data && data.userId) {
this.loadingSubject.next(true); this.loadingSubject.next(true);
@ -114,34 +125,33 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
} }
} }
private loadResponse(promise: Promise<ListUserGrantResponse.AsObject>): void { private loadResponse(promise: Promise<ListUserGrantResponse.AsObject | ListMyUserGrantsResponse.AsObject>): void {
from(promise) promise
.pipe( .then((resp) => {
map((resp) => { this.loadingSubject.next(false);
if (resp.details?.totalResult) { if (resp.resultList) {
this.totalResult = resp.details.totalResult; this.grantsSubject.next(resp.resultList);
} else { }
this.totalResult = 0; if (resp.details) {
} this.totalResult = resp.details.totalResult;
if (resp.details?.viewTimestamp) { if (resp.details.viewTimestamp) {
this.viewTimestamp = resp.details.viewTimestamp; this.viewTimestamp = resp.details.viewTimestamp;
} }
return resp.resultList; }
}), })
catchError(() => of([])), .catch((error) => {
finalize(() => this.loadingSubject.next(false)), console.error(error);
) this.grantsSubject.next([]);
.subscribe((grants) => { this.loadingSubject.next(false);
this.grantsSubject.next(grants);
}); });
} }
/** /**
* Connect this data source to the table. The table will only update when * Connect this data source to the table. The table will only update when
* the returned stream emits new items. * the returned stream emits new lists of items.
* @returns A stream of the items to be rendered. * @returns A stream of item lists to be rendered.
*/ */
public connect(): Observable<UserGrant.AsObject[]> { public connect(): Observable<Array<UserGrantAsObject>> {
return this.grantsSubject.asObservable(); return this.grantsSubject.asObservable();
} }

View File

@ -155,6 +155,7 @@
actions actions
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}" matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
color="warn" color="warn"
[disabled]="disableDelete"
(click)="deleteGrant($event, grant)" (click)="deleteGrant($event, grant)"
mat-icon-button mat-icon-button
> >
@ -170,8 +171,8 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr <tr
(click)="openEditDialog(grant)" (click)="!disableWrite ? openEditDialog(grant) : null"
class="highlight pointer" [ngClass]="{ 'highlight pointer': !disableWrite }"
mat-row mat-row
*matRowDef="let grant; columns: displayedColumns" *matRowDef="let grant; columns: displayedColumns"
></tr> ></tr>

View File

@ -2,13 +2,14 @@ import { SelectionModel } from '@angular/cdk/collections';
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { MatLegacyInput as MatInput } from '@angular/material/legacy-input'; import { MatLegacyInput as MatInput } from '@angular/material/legacy-input';
import { MatLegacySelectChange as MatSelectChange } from '@angular/material/legacy-select';
import { MatLegacyTable as MatTable } from '@angular/material/legacy-table'; import { MatLegacyTable as MatTable } from '@angular/material/legacy-table';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { enterAnimations } from 'src/app/animations'; import { enterAnimations } from 'src/app/animations';
import { UserGrant as AuthUserGrant } from 'src/app/proto/generated/zitadel/auth_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb'; import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import { Type, UserGrant, UserGrantQuery } from 'src/app/proto/generated/zitadel/user_pb'; import { Type, UserGrant as MgmtUserGrant, UserGrantQuery } from 'src/app/proto/generated/zitadel/user_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@ -24,6 +25,9 @@ export enum UserGrantListSearchKey {
PROJECT_NAME, PROJECT_NAME,
ROLE_KEY, ROLE_KEY,
} }
type UserGrantAsObject = AuthUserGrant.AsObject | MgmtUserGrant.AsObject;
@Component({ @Component({
selector: 'cnsl-user-grants', selector: 'cnsl-user-grants',
templateUrl: './user-grants.component.html', templateUrl: './user-grants.component.html',
@ -38,10 +42,10 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
@Input() context: UserGrantContext = UserGrantContext.NONE; @Input() context: UserGrantContext = UserGrantContext.NONE;
@Input() refreshOnPreviousRoutes: string[] = []; @Input() refreshOnPreviousRoutes: string[] = [];
public dataSource: UserGrantsDataSource = new UserGrantsDataSource(this.userService); public dataSource: UserGrantsDataSource = new UserGrantsDataSource(this.authService, this.userService);
public selection: SelectionModel<UserGrant.AsObject> = new SelectionModel<UserGrant.AsObject>(true, []); public selection: SelectionModel<UserGrantAsObject> = new SelectionModel<UserGrantAsObject>(true, []);
@ViewChild(PaginatorComponent) public paginator?: PaginatorComponent; @ViewChild(PaginatorComponent) public paginator?: PaginatorComponent;
@ViewChild(MatTable) public table?: MatTable<UserGrant.AsObject>; @ViewChild(MatTable) public table?: MatTable<UserGrantAsObject>;
@Input() disableWrite: boolean = false; @Input() disableWrite: boolean = false;
@Input() disableDelete: boolean = false; @Input() disableDelete: boolean = false;
@ -66,6 +70,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
public filterOpen: boolean = false; public filterOpen: boolean = false;
constructor( constructor(
private authService: GrpcAuthService,
private userService: ManagementService, private userService: ManagementService,
private toast: ToastService, private toast: ToastService,
private dialog: MatDialog, private dialog: MatDialog,
@ -88,14 +93,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
switch (this.context) { switch (this.context) {
case UserGrantContext.OWNED_PROJECT: case UserGrantContext.OWNED_PROJECT:
if (this.projectId) { if (this.projectId) {
// this.getProjectRoleOptions(this.projectId);
this.routerLink = ['/grant-create', 'project', this.projectId]; this.routerLink = ['/grant-create', 'project', this.projectId];
} }
break; break;
case UserGrantContext.GRANTED_PROJECT: case UserGrantContext.GRANTED_PROJECT:
if (this.grantId) { if (this.grantId) {
this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId]; this.routerLink = ['/grant-create', 'project', this.projectId, 'grant', this.grantId];
// this.getGrantRoleOptions(this.grantId, this.projectId);
} }
break; break;
case UserGrantContext.USER: case UserGrantContext.USER:
@ -103,6 +106,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.routerLink = ['/grant-create', 'user', this.userId]; this.routerLink = ['/grant-create', 'user', this.userId];
} }
break; break;
case UserGrantContext.AUTHUSER:
if (this.grantId) {
this.routerLink = ['/grant-create', 'user', this.userId];
}
break;
case UserGrantContext.NONE: case UserGrantContext.NONE:
this.routerLink = ['/grant-create']; this.routerLink = ['/grant-create'];
} }
@ -119,7 +127,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.loadGrantsPage(type); this.loadGrantsPage(type);
} }
public getType(grant: UserGrant.AsObject): string { public getType(grant: UserGrantAsObject): string {
if (grant.projectGrantId) { if (grant.projectGrantId) {
return 'Project Grant'; return 'Project Grant';
} else if (grant.projectId) { } else if (grant.projectId) {
@ -161,11 +169,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
: this.dataSource.grantsSubject.value.forEach((row) => this.selection.select(row)); : this.dataSource.grantsSubject.value.forEach((row) => this.selection.select(row));
} }
public openEditDialog(grant: UserGrant.AsObject): void { public openEditDialog(grant: UserGrantAsObject): void {
const dialogRef = this.dialog.open(UserGrantRoleDialogComponent, { const dialogRef = this.dialog.open(UserGrantRoleDialogComponent, {
data: { data: {
projectId: grant.projectId, projectId: grant.projectId,
grantId: grant.projectGrantId, grantId: grant?.projectGrantId,
selectedRoleKeysList: grant.roleKeysList, selectedRoleKeysList: grant.roleKeysList,
i18nTitle: 'GRANTS.EDIT.TITLE', i18nTitle: 'GRANTS.EDIT.TITLE',
}, },
@ -175,7 +183,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
dialogRef.afterClosed().subscribe((resp) => { dialogRef.afterClosed().subscribe((resp) => {
if (resp && resp.roles) { if (resp && resp.roles) {
this.userService this.userService
.updateUserGrant(grant.id, grant.userId, resp.roles) .updateUserGrant(
(grant as MgmtUserGrant.AsObject).id ?? (grant as AuthUserGrant.AsObject).grantId,
grant.userId,
resp.roles,
)
.then(() => { .then(() => {
this.toast.showInfo('GRANTS.TOAST.UPDATED', true); this.toast.showInfo('GRANTS.TOAST.UPDATED', true);
grant.roleKeysList = resp.roles; grant.roleKeysList = resp.roles;
@ -187,18 +199,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}); });
} }
updateRoles(grant: UserGrant.AsObject, selectionChange: MatSelectChange): void { public deleteGrant(event: any, grant: MgmtUserGrant.AsObject): void {
this.userService
.updateUserGrant(grant.id, grant.userId, selectionChange.value)
.then(() => {
this.toast.showInfo('GRANTS.TOAST.UPDATED', true);
})
.catch((error) => {
this.toast.showError(error);
});
}
public deleteGrant(event: any, grant: UserGrant.AsObject): void {
event.stopPropagation(); event.stopPropagation();
const dialogRef = this.dialog.open(WarnDialogComponent, { const dialogRef = this.dialog.open(WarnDialogComponent, {
@ -219,7 +220,9 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.toast.showInfo('GRANTS.TOAST.REMOVED', true); this.toast.showInfo('GRANTS.TOAST.REMOVED', true);
const data = this.dataSource.grantsSubject.getValue(); const data = this.dataSource.grantsSubject.getValue();
const index = data.findIndex((i) => i.id === grant.id); const index = data.findIndex(
(i) => (i as MgmtUserGrant.AsObject).id && (i as MgmtUserGrant.AsObject).id === grant.id,
);
if (index > -1) { if (index > -1) {
data.splice(index, 1); data.splice(index, 1);
this.dataSource.grantsSubject.next(data); this.dataSource.grantsSubject.next(data);
@ -246,12 +249,12 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
dialogRef.afterClosed().subscribe((resp) => { dialogRef.afterClosed().subscribe((resp) => {
if (resp) { if (resp) {
this.userService this.userService
.bulkRemoveUserGrant(this.selection.selected.map((grant) => grant.id)) .bulkRemoveUserGrant(this.selection.selected.map((grant) => (grant as MgmtUserGrant.AsObject).id))
.then(() => { .then(() => {
this.toast.showInfo('GRANTS.TOAST.BULKREMOVED', true); this.toast.showInfo('GRANTS.TOAST.BULKREMOVED', true);
const data = this.dataSource.grantsSubject.getValue(); const data = this.dataSource.grantsSubject.getValue();
this.selection.selected.forEach((item) => { this.selection.selected.forEach((item) => {
const index = data.findIndex((i) => i.id === item.id); const index = data.findIndex((i) => (i as MgmtUserGrant.AsObject).id === (item as MgmtUserGrant.AsObject).id);
if (index > -1) { if (index > -1) {
data.splice(index, 1); data.splice(index, 1);
this.dataSource.grantsSubject.next(data); this.dataSource.grantsSubject.next(data);

View File

@ -1,14 +1,6 @@
import { animate, style, transition, trigger } from '@angular/animations';
import { Location } from '@angular/common';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { take } from 'rxjs/operators';
import { ProjectAutocompleteType } from 'src/app/modules/search-project-autocomplete/search-project-autocomplete.component'; import { ProjectAutocompleteType } from 'src/app/modules/search-project-autocomplete/search-project-autocomplete.component';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators';
import { SetUpOrgRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { Project } from 'src/app/proto/generated/zitadel/project_pb'; import { Project } from 'src/app/proto/generated/zitadel/project_pb';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';

View File

@ -1,9 +1,9 @@
import { LiveAnnouncer } from '@angular/cdk/a11y'; import { LiveAnnouncer } from '@angular/cdk/a11y';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Component, OnDestroy, ViewChild } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { MatLegacyTableDataSource as MatTableDataSource } from '@angular/material/legacy-table'; import { MatLegacyTableDataSource as MatTableDataSource } from '@angular/material/legacy-table';
import { MatSort, Sort } from '@angular/material/sort'; import { MatSort, Sort } from '@angular/material/sort';
import { BehaviorSubject, distinctUntilChanged, Observable, Subject, takeUntil } from 'rxjs'; import { BehaviorSubject, Observable, Subject, takeUntil } from 'rxjs';
import { DisplayJsonDialogComponent } from 'src/app/modules/display-json-dialog/display-json-dialog.component'; import { DisplayJsonDialogComponent } from 'src/app/modules/display-json-dialog/display-json-dialog.component';
import { PaginatorComponent } from 'src/app/modules/paginator/paginator.component'; import { PaginatorComponent } from 'src/app/modules/paginator/paginator.component';
import { ListEventsRequest, ListEventsResponse } from 'src/app/proto/generated/zitadel/admin_pb'; import { ListEventsRequest, ListEventsResponse } from 'src/app/proto/generated/zitadel/admin_pb';

View File

@ -4,14 +4,12 @@ import { Component } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms'; import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle'; import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { take } from 'rxjs/operators';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators'; import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators';
import { SetUpOrgRequest } from 'src/app/proto/generated/zitadel/admin_pb'; import { SetUpOrgRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb'; import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { Gender } from 'src/app/proto/generated/zitadel/user_pb'; import { Gender } from 'src/app/proto/generated/zitadel/user_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';

View File

@ -3,7 +3,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subject, takeUntil } from 'rxjs'; import { Subject, takeUntil } from 'rxjs';
import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';

View File

@ -6,7 +6,7 @@ import { ProjectType } from 'src/app/modules/project-members/project-members-dat
import { UserTarget } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.component'; import { UserTarget } from 'src/app/modules/search-user-autocomplete/search-user-autocomplete.component';
import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource'; import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource';
import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { GrantedProject, Project, Role } from 'src/app/proto/generated/zitadel/project_pb'; import { GrantedProject, Project } from 'src/app/proto/generated/zitadel/project_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb'; import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';

View File

@ -2,7 +2,6 @@ import { Location } from '@angular/common';
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms'; import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { CountryCode, parsePhoneNumber } from 'libphonenumber-js';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { AddHumanUserRequest } from 'src/app/proto/generated/zitadel/management_pb'; import { AddHumanUserRequest } from 'src/app/proto/generated/zitadel/management_pb';
import { Domain } from 'src/app/proto/generated/zitadel/org_pb'; import { Domain } from 'src/app/proto/generated/zitadel/org_pb';

View File

@ -127,16 +127,7 @@
<cnsl-user-grants <cnsl-user-grants
[userId]="user.id" [userId]="user.id"
[context]="USERGRANTCONTEXT" [context]="USERGRANTCONTEXT"
[displayedColumns]="[ [displayedColumns]="['org', 'projectId', 'type', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
'select',
'org',
'projectId',
'type',
'creationDate',
'changeDate',
'roleNamesList',
'actions'
]"
[disableWrite]="(['user.grant.write$'] | hasRole | async) === false" [disableWrite]="(['user.grant.write$'] | hasRole | async) === false"
[disableDelete]="(['user.grant.delete$'] | hasRole | async) === false" [disableDelete]="(['user.grant.delete$'] | hasRole | async) === false"
> >

View File

@ -42,7 +42,7 @@ export class AuthUserDetailComponent implements OnDestroy {
public userLoginMustBeDomain: boolean = false; public userLoginMustBeDomain: boolean = false;
public UserState: any = UserState; public UserState: any = UserState;
public USERGRANTCONTEXT: UserGrantContext = UserGrantContext.USER; public USERGRANTCONTEXT: UserGrantContext = UserGrantContext.AUTHUSER;
public refreshChanges$: EventEmitter<void> = new EventEmitter(); public refreshChanges$: EventEmitter<void> = new EventEmitter();
public metadata: Metadata.AsObject[] = []; public metadata: Metadata.AsObject[] = [];

View File

@ -4,7 +4,6 @@ import {
MatLegacyDialogRef as MatDialogRef, MatLegacyDialogRef as MatDialogRef,
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
} from '@angular/material/legacy-dialog'; } from '@angular/material/legacy-dialog';
import { CountryCode, parsePhoneNumber } from 'libphonenumber-js';
import { CountryCallingCodesService, CountryPhoneCode } from 'src/app/services/country-calling-codes.service'; import { CountryCallingCodesService, CountryPhoneCode } from 'src/app/services/country-calling-codes.service';
import { formatPhone } from 'src/app/utils/formatPhone'; import { formatPhone } from 'src/app/utils/formatPhone';

View File

@ -1,5 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { JavaScriptValue, Struct } from 'google-protobuf/google/protobuf/struct_pb'; import { JavaScriptValue } from 'google-protobuf/google/protobuf/struct_pb';
import { Event } from 'src/app/proto/generated/zitadel/event_pb'; import { Event } from 'src/app/proto/generated/zitadel/event_pb';
@Pipe({ @Pipe({

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc'; import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
import { BehaviorSubject, from, lastValueFrom, Observable } from 'rxjs'; import { BehaviorSubject, from, lastValueFrom, Observable } from 'rxjs';
import { GrpcAuthService } from './grpc-auth.service';
import { StatehandlerService } from './statehandler/statehandler.service'; import { StatehandlerService } from './statehandler/statehandler.service';

View File

@ -9,10 +9,8 @@ import {
finalize, finalize,
map, map,
mergeMap, mergeMap,
pairwise,
switchMap, switchMap,
take, take,
tap,
timeout, timeout,
withLatestFrom, withLatestFrom,
} from 'rxjs/operators'; } from 'rxjs/operators';
@ -29,7 +27,6 @@ import {
GetMyEmailRequest, GetMyEmailRequest,
GetMyEmailResponse, GetMyEmailResponse,
GetMyLabelPolicyRequest, GetMyLabelPolicyRequest,
GetMyLabelPolicyResponse,
GetMyLoginPolicyRequest, GetMyLoginPolicyRequest,
GetMyLoginPolicyResponse, GetMyLoginPolicyResponse,
GetMyPasswordComplexityPolicyRequest, GetMyPasswordComplexityPolicyRequest,
@ -426,11 +423,7 @@ export class GrpcAuthService {
return this.grpcService.auth.listMyUserSessions(req, null).then((resp) => resp.toObject()); return this.grpcService.auth.listMyUserSessions(req, null).then((resp) => resp.toObject());
} }
public listMyUserGrants( public listMyUserGrants(limit?: number, offset?: number, asc?: boolean): Promise<ListMyUserGrantsResponse.AsObject> {
limit?: number,
offset?: number,
queryList?: ListQuery[],
): Promise<ListMyUserGrantsResponse.AsObject> {
const req = new ListMyUserGrantsRequest(); const req = new ListMyUserGrantsRequest();
const query = new ListQuery(); const query = new ListQuery();
if (limit) { if (limit) {
@ -439,6 +432,9 @@ export class GrpcAuthService {
if (offset) { if (offset) {
query.setOffset(offset); query.setOffset(offset);
} }
if (asc !== undefined) {
query.setAsc(asc);
}
req.setQuery(query); req.setQuery(query);
return this.grpcService.auth.listMyUserGrants(req, null).then((resp) => resp.toObject()); return this.grpcService.auth.listMyUserGrants(req, null).then((resp) => resp.toObject());
} }

View File

@ -4,8 +4,6 @@ import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { FlowType, TriggerType } from '../proto/generated/zitadel/action_pb';
import { RemoveLabelPolicyLogoDarkRequest } from '../proto/generated/zitadel/admin_pb';
import { AppQuery } from '../proto/generated/zitadel/app_pb'; import { AppQuery } from '../proto/generated/zitadel/app_pb';
import { KeyType } from '../proto/generated/zitadel/auth_n_key_pb'; import { KeyType } from '../proto/generated/zitadel/auth_n_key_pb';
import { ChangeQuery } from '../proto/generated/zitadel/change_pb'; import { ChangeQuery } from '../proto/generated/zitadel/change_pb';

View File

@ -2,8 +2,6 @@ import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { LabelPolicy } from '../proto/generated/zitadel/policy_pb'; import { LabelPolicy } from '../proto/generated/zitadel/policy_pb';
import { GrpcAuthService } from './grpc-auth.service';
declare const tinycolor: any; declare const tinycolor: any;
export interface Color { export interface Color {

View File

@ -43,5 +43,15 @@ func UserGrantToPb(grant *query.UserGrant) *auth_pb.UserGrant {
ProjectId: grant.ProjectID, ProjectId: grant.ProjectID,
UserId: grant.UserID, UserId: grant.UserID,
Roles: grant.Roles, Roles: grant.Roles,
Details: object.ToViewDetailsPb(
grant.Sequence,
grant.CreationDate,
grant.ChangeDate,
grant.ResourceOwner,
),
OrgDomain: grant.OrgPrimaryDomain,
ProjectName: grant.ProjectName,
ProjectGrantId: grant.GrantID,
RoleKeys: grant.Roles,
} }
} }

View File

@ -1429,9 +1429,10 @@ message UserGrant {
example: "\"28746028909593987\"" example: "\"28746028909593987\""
} }
]; ];
// Deprecated: user role_keys
repeated string roles = 4 [ repeated string roles = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[\"RoleKey1\", \"RoleKey2\"]" example: "[\"RoleKey1\", \"RoleKey2\"]",
} }
]; ];
string org_name = 5 [ string org_name = 5 [
@ -1444,6 +1445,27 @@ message UserGrant {
example: "\"\"" example: "\"\""
} }
]; ];
zitadel.v1.ObjectDetails details = 7;
string org_domain = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"zitadel.cloud\""
}
];
string project_name = 9 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"ZITADEL\""
}
];
string project_grant_id = 10 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"28746028909586246\""
}
];
repeated string role_keys = 11 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[\"RoleKey1\", \"RoleKey2\"]",
}
];
} }
message ListMyProjectOrgsRequest { message ListMyProjectOrgsRequest {