feat: protos refactoring

* start with user

* user first try done in all services

* user, org, idp for discussion

* remove unused stuff

* bla

* dockerbuild

* rename search, get multiple to list...

* add annotation

* update proto dependencies

* update proto dependencies

* change proto imports

* replace all old imports

* fix go out

* remove unused lines

* correct protoc flags

* grpc and openapi flags

* go out source path relative

* -p

* remove dead code

* sourcepath relative

* ls

* is onenapi the problem?

* hobla

* authoption output

* wrong field name

* gopf

* correct option, add correct flags

* small improvments

* SIMPLYFY

* relative path

* gopf bin ich en tubel

* correct path

* default policies in admin

* grpc generation in one file

* remove non ascii

* metadata on manipulations

* correct auth_option import

* fixes

* larry

* idp provider to idp

* fix generate

* admin and auth nearly done

* admin and auth nearly done

* gen

* healthz

* imports

* deleted too much imports

* fix org

* add import

* imports

* import

* naming

* auth_opt

* gopf

* management

* imports

* _TYPE_UNSPECIFIED

* improts

* auth opts

* management policies

* imports

* passwordlessType to MFAType

* auth_opt

* add user grant calls

* add missing messages

* result

* fix option

* improvements

* ids

* fix http

* imports

* fixes

* fields

* body

* add fields

* remove wrong member query

* fix request response

* fixes

* add copy files

* variable versions

* generate all files

* improvements

* add dependencies

* factors

* user session

* oidc information, iam

* remove unused file

* changes

* enums

* dockerfile

* fix build

* remove unused folder

* update readme for build

* move old server impl

* add event type to change

* some changes

* start admin

* remove wrong field

* admin only list calls missing

* fix proto numbers

* surprisingly it compiles

* service ts changes

* admin mgmt

* mgmt

* auth manipulation and gets done, lists missing

* validations and some field changes

* validations

* enum validations

* remove todo

* move proto files to proto/zitadel

* change proto path in dockerfile

* it compiles!

* add validate import

* remove duplicate import

* fix protos

* fix import

* tests

* cleanup

* remove unimplemented methods

* iam member multiple queries

* all auth and admin calls

* add initial password on crate human

* message names

* management user server

* machine done

* fix: todos (#1346)

* fix: pub sub in new eventstore

* fix: todos

* fix: todos

* fix: todos

* fix: todos

* fix: todos

* fix tests

* fix: search method domain

* admin service, user import type typescript

* admin changes

* admin changes

* fix: search method domain

* more user grpc and begin org, fix configs

* fix: return object details

* org grpc

* remove creation date add details

* app

* fix: return object details

* fix: return object details

* mgmt service, project members

* app

* fix: convert policies

* project, members, granted projects, searches

* fix: convert usergrants

* fix: convert usergrants

* auth user detail, user detail, mfa, second factor, auth

* fix: convert usergrants

* mfa, memberships, password, owned proj detail

* fix: convert usergrants

* project grant

* missing details

* changes, userview

* idp table, keys

* org list and user table filter

* unify rest paths (#1381)

* unify rest paths

* post for all searches,
mfa to multi_factor,
secondfactor to second_factor

* remove v1

* fix tests

* rename api client key to app key

* machine keys, age policy

* user list, machine keys, changes

* fix: org states

* add default flag to policy

* second factor to type

* idp id

* app type

* unify ListQuery, ListDetails, ObjectDetails field names

* user grants, apps, memberships

* fix type params

* metadata to detail, linke idps

* api create, membership, app detail, create

* idp, app, policy

* queries, multi -> auth factors and missing fields

* update converters

* provider to user, remove old mgmt refs

* temp remove authfactor dialog, build finish

Co-authored-by: Max Peintner <[email protected]>
Co-authored-by: Fabi <[email protected]>
Co-authored-by: Livio Amstutz <[email protected]>
Co-authored-by: Fabiennne <[email protected]>
This commit is contained in:
Silvan
2021-03-09 10:30:11 +01:00
committed by GitHub
co-authored by Max Peintner Fabi Livio Amstutz Fabiennne
parent 9f417f3957
commit dabd5920dc
372 changed files with 17879 additions and 22034 deletions
@@ -1,24 +1,27 @@
<div class="card" appOutsideClick (clickOutside)="closeCard($event)">
<app-avatar *ngIf="profile && (profile.displayName || (profile.firstName && profile.lastName))" class="avatar"
[name]="profile.displayName ? profile.displayName : (profile.firstName + ' '+ profile.lastName)" [size]="80">
<app-avatar
*ngIf="user.human?.profile && (user.human?.profile?.displayName || (user.human?.profile?.firstName && user.human?.profile?.lastName))"
class="avatar"
[name]="user.human?.profile?.displayName ? user.human?.profile?.displayName : (user.human?.profile?.firstName + ' '+ user.human?.profile?.lastName)"
[size]="80">
</app-avatar>
<span class="u-name">{{profile.displayName ? profile.displayName : profile.preferredLoginName}}</span>
<span class="u-email">{{profile?.preferredLoginName}}</span>
<span class="u-name">{{user.human?.profile?.displayName ? user.human?.profile?.displayName : 'A'}}</span>
<span class="u-email">{{user.human?.profile?.preferredLoginName}}</span>
<span class="iamuser" *ngIf="iamuser">IAM USER</span>
<button color="primary" (click)="editUserProfile()" mat-stroked-button>{{'USER.EDITACCOUNT' | translate}}</button>
<div class="l-accounts">
<mat-progress-bar *ngIf="loadingUsers" color="primary" mode="indeterminate"></mat-progress-bar>
<a class="row" *ngFor="let user of users" (click)="selectAccount(user.loginName)">
<app-avatar *ngIf="user && user.displayName" class="small-avatar"
[name]="user.displayName ? user.displayName : ''" [size]="32">
<a class="row" *ngFor="let session of sessions" (click)="selectAccount(session.loginName)">
<app-avatar *ngIf="session && session.displayName" class="small-avatar"
[name]="session.displayName ? session.displayName : ''" [size]="32">
</app-avatar>
<div class="col">
<span class="user-title">{{user.displayName ? user.displayName : user.userName}} </span>
<span class="loginname">{{user.loginName}}</span>
<span class="email">{{'USER.STATE.'+user.authState | translate}}</span>
<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>
</div>
<span class="fill-space"></span>
<mat-icon>keyboard_arrow_right</mat-icon>
@@ -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 { UserProfileView, UserSessionView } from 'src/app/proto/generated/auth_pb';
import { Session, User } 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';
@@ -11,18 +11,18 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
styleUrls: ['./accounts-card.component.scss'],
})
export class AccountsCardComponent implements OnInit {
@Input() public profile!: UserProfileView.AsObject;
@Input() public user!: User.AsObject;
@Input() public iamuser: boolean = false;
@Output() public close: EventEmitter<void> = new EventEmitter();
public users: UserSessionView.AsObject[] = [];
public sessions: Session.AsObject[] = [];
public loadingUsers: boolean = false;
constructor(public authService: AuthenticationService, private router: Router, private userService: GrpcAuthService) {
this.userService.getMyUserSessions().then(sessions => {
this.users = sessions.toObject().userSessionsList;
const index = this.users.findIndex(user => user.loginName === this.profile.preferredLoginName);
this.userService.listMyUserSessions().then(sessions => {
this.sessions = sessions.resultList;
const index = this.sessions.findIndex(user => user.loginName === this.user.preferredLoginName);
if (index > -1) {
this.users.splice(index, 1);
this.sessions.splice(index, 1);
}
this.loadingUsers = false;
@@ -1,7 +1,7 @@
import { Component, Inject } from '@angular/core';
import { FormControl } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AuthNKeyType, MachineKeyType } from 'src/app/proto/generated/management_pb';
import { KeyType } from 'src/app/proto/generated/zitadel/auth_n_key_pb';
export enum AddKeyDialogType {
MACHINE = "MACHINE",
@@ -15,21 +15,16 @@ export enum AddKeyDialogType {
})
export class AddKeyDialogComponent {
public startDate: Date = new Date();
types: MachineKeyType[] | AuthNKeyType[] = [];
public type!: MachineKeyType | AuthNKeyType;
types: KeyType[] = [];
public type!: KeyType;
public dateControl: FormControl = new FormControl('', []);
constructor(
public dialogRef: MatDialogRef<AddKeyDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {
if (data.type = AddKeyDialogType.MACHINE) {
this.types = [MachineKeyType.MACHINEKEY_JSON];
this.type = MachineKeyType.MACHINEKEY_JSON;
} else if (data.type = AddKeyDialogType.AUTHNKEY) {
this.types = [AuthNKeyType.AUTHNKEY_JSON];
this.type = AuthNKeyType.AUTHNKEY_JSON;
}
this.types = [KeyType.KEY_TYPE_JSON];
this.type = KeyType.KEY_TYPE_JSON;
const today = new Date();
this.startDate.setDate(today.getDate() + 1);
}
@@ -1,7 +1,8 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Observable } from 'rxjs';
import { ProjectGrantView, ProjectRole, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
import { GrantedProject, Project, Role } from 'src/app/proto/generated/zitadel/project_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -23,7 +24,7 @@ export enum CreationType {
export class MemberCreateDialogComponent {
private projectId: string = '';
private grantId: string = '';
public preselectedUsers: Array<UserView.AsObject> = [];
public preselectedUsers: Array<User.AsObject> = [];
public creationType!: CreationType;
@@ -38,8 +39,8 @@ export class MemberCreateDialogComponent {
{ type: CreationType.PROJECT_OWNED, disabled$: this.authService.isAllowed(['project.member.write']) },
{ type: CreationType.PROJECT_GRANTED, disabled$: this.authService.isAllowed(['project.grant.member.write']) },
];
public users: Array<UserView.AsObject> = [];
public roles: Array<ProjectRole.AsObject> | string[] = [];
public users: Array<User.AsObject> = [];
public roles: Array<Role.AsObject> | string[] = [];
public CreationType: any = CreationType;
public ProjectAutocompleteType: any = ProjectAutocompleteType;
public memberRoleOptions: string[] = [];
@@ -72,22 +73,22 @@ export class MemberCreateDialogComponent {
public loadRoles(): void {
switch (this.creationType) {
case CreationType.PROJECT_GRANTED:
this.mgmtService.GetProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;
this.mgmtService.listProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.resultList;
}).catch(error => {
this.toastService.showError(error);
});
break;
case CreationType.PROJECT_OWNED:
this.mgmtService.GetProjectMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;
this.mgmtService.listProjectMemberRoles().then(resp => {
this.memberRoleOptions = resp.resultList;
}).catch(error => {
this.toastService.showError(error);
});
break;
case CreationType.IAM:
this.adminService.GetIamMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;
this.adminService.listIAMMemberRoles().then(resp => {
this.memberRoleOptions = resp.rolesList;
}).catch(error => {
this.toastService.showError(error);
});
@@ -95,7 +96,7 @@ export class MemberCreateDialogComponent {
}
}
public selectProject(project: ProjectView.AsObject | ProjectGrantView.AsObject | any): void {
public selectProject(project: Project.AsObject | GrantedProject.AsObject | any): void {
this.projectId = project.projectId;
if (project.id) {
this.grantId = project.id;
@@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core';
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
import { OIDCAppType } from 'src/app/proto/generated/zitadel/app_pb';
@Component({
selector: 'cnsl-app-card',
@@ -8,7 +8,7 @@ import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
})
export class AppCardComponent {
@Input() public outline: boolean = false;
@Input() public type!: OIDCApplicationType;
@Input() public type!: OIDCAppType;
@Input() public isApiApp: boolean = false;
public OIDCApplicationType: any = OIDCApplicationType;
public OIDCApplicationType: any = OIDCAppType;
}
@@ -1,5 +1,10 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { APIAuthMethodType, OIDCAuthMethodType, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import {
APIAuthMethodType,
OIDCAuthMethodType,
OIDCGrantType,
OIDCResponseType,
} from 'src/app/proto/generated/zitadel/app_pb';
export interface RadioItemAuthType {
key: string;
@@ -11,8 +11,9 @@
hist.values[0]?.dates[0]| timestampToDate | localizedDate: 'dd. MMMM YYYY' }}</span>
<div class="item" *ngFor="let dayelement of hist.values; index as i">
<div class="row">
<app-avatar matTooltip="{{ dayelement.editorName }}" *ngIf="dayelement.editorName; else spacer"
class="avatar" [name]="dayelement.editorName" [size]="32">
<app-avatar matTooltip="{{ dayelement.editorDisplayName }}"
*ngIf="dayelement.editorDisplayName; else spacer" class="avatar"
[name]="dayelement.editorDisplayName" [size]="32">
</app-avatar>
<ng-template #spacer>
<div class="spacer"></div>
@@ -1,11 +1,18 @@
import { KeyValue } from '@angular/common';
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, from, Observable, of, Subject } from 'rxjs';
import { catchError, debounceTime, scan, take, takeUntil, tap } from 'rxjs/operators';
import { Change, Changes } from 'src/app/proto/generated/management_pb';
import { ListMyUserChangesResponse } from 'src/app/proto/generated/zitadel/auth_pb';
import { Change } from 'src/app/proto/generated/zitadel/change_pb';
import {
ListAppChangesResponse,
ListOrgChangesResponse,
ListProjectChangesResponse,
ListUserChangesResponse,
} from 'src/app/proto/generated/zitadel/management_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { KeyValue } from '@angular/common';
export enum ChangeType {
MYUSER = 'myuser',
@@ -27,6 +34,8 @@ export interface MappedChange {
}>;
}
type ListChanges = ListMyUserChangesResponse.AsObject | ListUserChangesResponse.AsObject | ListProjectChangesResponse.AsObject | ListOrgChangesResponse.AsObject | ListAppChangesResponse.AsObject;
@Component({
selector: 'app-changes',
templateUrl: './changes.component.html',
@@ -46,7 +55,7 @@ export class ChangesComponent implements OnInit, OnDestroy {
loading: Observable<boolean> = this._loading.asObservable();
public data!: Observable<MappedChange[]>;
public changes!: Changes.AsObject;
public changes!: ListChanges;
private destroyed$: Subject<void> = new Subject();
constructor(private mgmtUserService: ManagementService, private authUserService: GrpcAuthService) {
@@ -73,17 +82,17 @@ export class ChangesComponent implements OnInit, OnDestroy {
}
public init(): void {
let first: Promise<Changes>;
let first: Promise<ListChanges>;
switch (this.changeType) {
case ChangeType.MYUSER: first = this.authUserService.GetMyUserChanges(20, 0);
case ChangeType.MYUSER: first = this.authUserService.listMyUserChanges(20, 0);
break;
case ChangeType.USER: first = this.mgmtUserService.UserChanges(this.id, 20, 0);
case ChangeType.USER: first = this.mgmtUserService.listUserChanges(this.id, 20, 0);
break;
case ChangeType.PROJECT: first = this.mgmtUserService.ProjectChanges(this.id, 20, 0);
case ChangeType.PROJECT: first = this.mgmtUserService.listProjectChanges(this.id, 20, 0);
break;
case ChangeType.ORG: first = this.mgmtUserService.OrgChanges(this.id, 20, 0);
case ChangeType.ORG: first = this.mgmtUserService.listOrgChanges(20, 0);
break;
case ChangeType.APP: first = this.mgmtUserService.ApplicationChanges(this.id, this.secId, 20, 0);
case ChangeType.APP: first = this.mgmtUserService.listAppChanges(this.id, this.secId, 20, 0);
break;
}
@@ -100,18 +109,18 @@ export class ChangesComponent implements OnInit, OnDestroy {
const cursor = this.getCursor();
console.log('cursor' + cursor);
let more: Promise<Changes>;
let more: Promise<ListChanges>;
switch (this.changeType) {
case ChangeType.MYUSER: more = this.authUserService.GetMyUserChanges(20, cursor);
case ChangeType.MYUSER: more = this.authUserService.listMyUserChanges(20, cursor);
break;
case ChangeType.USER: more = this.mgmtUserService.UserChanges(this.id, 20, cursor);
case ChangeType.USER: more = this.mgmtUserService.listUserChanges(this.id, 20, cursor);
break;
case ChangeType.PROJECT: more = this.mgmtUserService.ProjectChanges(this.id, 20, cursor);
case ChangeType.PROJECT: more = this.mgmtUserService.listProjectChanges(this.id, 20, cursor);
break;
case ChangeType.ORG: more = this.mgmtUserService.OrgChanges(this.id, 20, cursor);
case ChangeType.ORG: more = this.mgmtUserService.listOrgChanges(20, cursor);
break;
case ChangeType.APP: more = this.mgmtUserService.ApplicationChanges(this.id, this.secId, 20, cursor);
case ChangeType.APP: more = this.mgmtUserService.listAppChanges(this.id, this.secId, 20, cursor);
break;
}
@@ -131,7 +140,7 @@ export class ChangesComponent implements OnInit, OnDestroy {
}
// Maps the snapshot to usable format the updates source
private mapAndUpdate(col: Promise<Changes>): any {
private mapAndUpdate(col: Promise<ListChanges>): any {
if (this._done.value || this._loading.value) { return; }
// Map snapshot with doc ref (needed for cursor)
@@ -141,8 +150,8 @@ export class ChangesComponent implements OnInit, OnDestroy {
return from(col).pipe(
take(1),
tap((res: Changes) => {
const values = res.toObject().changesList;
tap((res: ListChanges) => {
const values = res.resultList;
const mapped = this.mapChanges(values);
// update source with new values, done loading
// this._data.next(values);
@@ -173,19 +182,19 @@ export class ChangesComponent implements OnInit, OnDestroy {
if (index) {
if (splitted[index]) {
const userData: any = {
editor: change.editor,
editor: change.editorDisplayName,
editorId: change.editorId,
editorName: change.editor,
editorName: change.editorDisplayName,
dates: [change.changeDate],
data: [change.data],
// data: [change.data],
eventTypes: [change.eventType],
sequences: [change.sequence],
};
const lastIndex = splitted[index].length - 1;
if (lastIndex > -1 && splitted[index][lastIndex].editor === change.editor) {
if (lastIndex > -1 && splitted[index][lastIndex].editor === change.editorDisplayName) {
splitted[index][lastIndex].dates.push(change.changeDate);
splitted[index][lastIndex].data.push(change.data);
// splitted[index][lastIndex].data.push(change.data);
splitted[index][lastIndex].eventTypes.push(change.eventType);
splitted[index][lastIndex].sequences.push(change.sequence);
} else {
@@ -194,12 +203,12 @@ export class ChangesComponent implements OnInit, OnDestroy {
} else {
splitted[index] = [
{
editor: change.editor,
editor: change.editorDisplayName,
editorId: change.editorId,
editorName: change.editor,
editorName: change.editorDisplayName,
dates: [change.changeDate],
data: [change.data],
// data: [change.data],
eventTypes: [change.eventType],
sequences: [change.sequence],
}
@@ -1,5 +1,5 @@
<app-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length"
[timestamp]="keyResult?.viewTimestamp" [selection]="selection">
[timestamp]="keyResult?.details?.viewTimestamp" [selection]="selection">
<div actions>
<button color="warn"
[disabled]="([('project.app.write:' + projectId), 'project.app.write'] | hasRole | async) == false"
@@ -60,7 +60,7 @@
</tr>
</table>
<mat-paginator #paginator class="paginator" [length]="keyResult?.totalResult || 0" [pageSize]="10"
<mat-paginator #paginator class="paginator" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
</div>
</app-refresh-table>
@@ -7,12 +7,12 @@ import { TranslateService } from '@ngx-translate/core';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { Moment } from 'moment';
import { BehaviorSubject, Observable } from 'rxjs';
import { AuthNKeyType, ClientKeySearchResponse, ClientKeyView, MachineKeySearchResponse, MachineKeyType, MachineKeyView } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { AddKeyDialogComponent, AddKeyDialogType } from 'src/app/modules/add-key-dialog/add-key-dialog.component';
import { ShowKeyDialogComponent } from 'src/app/modules/show-key-dialog/show-key-dialog.component';
import { Key, KeyType } from 'src/app/proto/generated/zitadel/auth_n_key_pb';
import { ListAppKeysResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'app-client-keys',
@@ -24,14 +24,14 @@ export class ClientKeysComponent implements OnInit {
@Input() appId!: string;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public dataSource: MatTableDataSource<ClientKeyView.AsObject> = new MatTableDataSource<ClientKeyView.AsObject>();
public selection: SelectionModel<ClientKeyView.AsObject> = new SelectionModel<ClientKeyView.AsObject>(true, []);
public keyResult!: MachineKeySearchResponse.AsObject | ClientKeySearchResponse.AsObject;
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
public keyResult!: ListAppKeysResponse.AsObject;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@Input() public displayedColumns: string[] = ['select', 'id', 'type', 'creationDate', 'expirationDate'];
@Output() public changedSelection: EventEmitter<Array<ClientKeyView.AsObject>> = new EventEmitter();
@Output() public changedSelection: EventEmitter<Array<Key.AsObject>> = new EventEmitter();
constructor(public translate: TranslateService, private mgmtService: ManagementService, private dialog: MatDialog,
private toast: ToastService) {
@@ -64,7 +64,7 @@ export class ClientKeysComponent implements OnInit {
public deleteSelectedKeys(): void {
const mappedDeletions = this.selection.selected.map(value => {
return this.mgmtService.DeleteClientKey(value.id, this.projectId, this.appId);
return this.mgmtService.removeAppKey(this.projectId, this.appId, value.id);
});
Promise.all(mappedDeletions).then(() => {
this.selection.clear();
@@ -83,7 +83,7 @@ export class ClientKeysComponent implements OnInit {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
const type: AuthNKeyType = resp.type;
const type: KeyType = resp.type;
let date: Timestamp | undefined;
@@ -99,7 +99,7 @@ export class ClientKeysComponent implements OnInit {
}
if (type) {
return this.mgmtService.addClientKey(this.projectId, this.appId, type, date).then((response) => {
return this.mgmtService.addAppKey(this.projectId, this.appId, type, date ? date : undefined).then((response) => {
if (response) {
setTimeout(() => {
this.refreshPage();
@@ -107,7 +107,7 @@ export class ClientKeysComponent implements OnInit {
this.dialog.open(ShowKeyDialogComponent, {
data: {
key: response.toObject(),
key: response,
type: AddKeyDialogType.AUTHNKEY
},
width: '400px',
@@ -124,8 +124,8 @@ export class ClientKeysComponent implements OnInit {
private async getData(limit: number, offset: number): Promise<void> {
this.loadingSubject.next(true);
if (this.projectId && this.appId) {
this.mgmtService.SearchClientKeys(this.projectId, this.appId, limit, offset).then(resp => {
this.keyResult = resp.toObject();
this.mgmtService.listAppKeys(this.projectId, this.appId, limit, offset).then(resp => {
this.keyResult = resp;
this.dataSource.data = this.keyResult.resultList;
this.loadingSubject.next(false);
}).catch((error: any) => {
@@ -6,18 +6,13 @@ import { MatChipInputEvent } from '@angular/material/chips';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import {
OidcIdpConfigCreate as AdminOidcIdpConfigCreate,
OIDCMappingField as authMappingFields,
} from 'src/app/proto/generated/admin_pb';
import { AddOIDCIDPRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { OIDCMappingField } from 'src/app/proto/generated/zitadel/idp_pb';
import { AddOrgOIDCIDPRequest } from 'src/app/proto/generated/zitadel/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import {
OidcIdpConfigCreate as MgmtOidcIdpConfigCreate,
OIDCMappingField as mgmtMappingFields,
} from '../../proto/generated/management_pb';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
@Component({
@@ -29,7 +24,7 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
private service!: ManagementService | AdminService;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public mappingFields: mgmtMappingFields[] | authMappingFields[] = [];
public mappingFields: OIDCMappingField[] = [];
private subscription?: Subscription;
public projectId: string = '';
@@ -61,14 +56,14 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.mappingFields = [
mgmtMappingFields.OIDCMAPPINGFIELD_PREFERRED_USERNAME,
mgmtMappingFields.OIDCMAPPINGFIELD_EMAIL];
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
this.mappingFields = [
authMappingFields.OIDCMAPPINGFIELD_PREFERRED_USERNAME,
authMappingFields.OIDCMAPPINGFIELD_EMAIL];
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
break;
}
});
@@ -87,36 +82,50 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
}
public addIdp(): void {
let req: AdminOidcIdpConfigCreate | MgmtOidcIdpConfigCreate;
if (this.serviceType == PolicyComponentServiceType.MGMT) {
const req = new AddOrgOIDCIDPRequest();
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
req = new MgmtOidcIdpConfigCreate();
break;
case PolicyComponentServiceType.ADMIN:
req = new AdminOidcIdpConfigCreate();
break;
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as ManagementService).addOrgOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
} else if (PolicyComponentServiceType.ADMIN) {
const req = new AddOIDCIDPRequest();
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
(this.service as AdminService).addOIDCIDP(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
}
req.setName(this.name?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setIdpDisplayNameMapping(this.idpDisplayNameMapping?.value);
req.setUsernameMapping(this.usernameMapping?.value);
this.loading = true;
this.service.CreateOidcIdp(req).then((idp) => {
setTimeout(() => {
this.loading = false;
this.router.navigate([
(this.serviceType === PolicyComponentServiceType.MGMT ? 'org' :
this.serviceType === PolicyComponentServiceType.ADMIN ? 'iam' : ''),
'policy', 'login']);
}, 2000);
}).catch(error => {
this.toast.showError(error);
});
}
public close(): void {
@@ -1,5 +1,6 @@
<app-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length"
[emitRefreshOnPreviousRoutes]="['/iam/idp/create']" [timestamp]="idpResult?.viewTimestamp" [selection]="selection">
[emitRefreshOnPreviousRoutes]="['/iam/idp/create']" [timestamp]="idpResult?.details?.viewTimestamp"
[selection]="selection">
<div actions>
<button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button"
mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled">
@@ -30,7 +31,7 @@
</th>
<td mat-cell *matCellDef="let idp">
<mat-checkbox color="primary" (click)="$event.stopPropagation()" class="chbox"
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.providerType == IdpProviderType.IDPPROVIDERTYPE_SYSTEM"
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.providerType == IDPOwnerType.IDPPROVIDERTYPE_SYSTEM"
(change)="$event ? selection.toggle(idp) : null" [checked]="selection.isSelected(idp)">
<img src="../../../assets/images/google.png"
*ngIf="idp.stylingType == IdpStylingType.IDPSTYLINGTYPE_GOOGLE" alt="google" />
@@ -58,7 +59,7 @@
<th mat-header-cell *matHeaderCellDef> {{ 'IDP.STATE' | translate }} </th>
<td [routerLink]="routerLinkForRow(idp)" mat-cell *matCellDef="let idp">
<span class="state"
[ngClass]="{'active': idp.state === IdpState.IDPCONFIGSTATE_ACTIVE, 'inactive': idp.state === IdpState.IDPCONFIGSTATE_INACTIVE}">{{
[ngClass]="{'active': idp.state === IDPState.IDP_STATE_ACTIVE, 'inactive': idp.state === IDPState.IDP_STATE_INACTIVE}">{{
'IDP.STATES.'+idp.state | translate }}</span>
</td>
</ng-container>
@@ -87,7 +88,7 @@
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let idp">
<button
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.providerType == IdpProviderType.IDPPROVIDERTYPE_SYSTEM"
[disabled]="serviceType==PolicyComponentServiceType.MGMT && idp?.providerType == IDPOwnerType.IDP_OWNER_TYPE_ORG"
mat-icon-button color="warn" matTooltip="{{'IAM.VIEWS.CLEAR' | translate}}"
(click)="removeIdp(idp)">
<i class="las la-trash"></i>
@@ -97,11 +98,11 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight"
[ngClass]="{'disabled': serviceType==PolicyComponentServiceType.MGMT && row?.providerType == IdpProviderType.IDPPROVIDERTYPE_SYSTEM}"
[ngClass]="{'disabled': serviceType==PolicyComponentServiceType.MGMT && row?.providerType == IDPOwnerType.IDP_OWNER_TYPE_SYSTEM}"
mat-row *matRowDef="let row; columns: displayedColumns;">
</tr>
</table>
</div>
<mat-paginator #paginator class="paginator" [length]="idpResult?.totalResult || 0" [pageSize]="10"
<mat-paginator #paginator class="paginator" [length]="idpResult?.details?.totalResult || 0" [pageSize]="10"
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
</app-refresh-table>
@@ -5,10 +5,10 @@ import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
import { BehaviorSubject, Observable } from 'rxjs';
import { IdpSearchResponse as AdminIdpSearchResponse, IdpState, IdpStylingType, IdpView as AdminIdpView } from 'src/app/proto/generated/admin_pb';
import { IdpProviderType, IdpView as MgmtIdpView } from 'src/app/proto/generated/management_pb';
import { ListIDPsResponse } from 'src/app/proto/generated/zitadel/admin_pb';
import { IDP, IDPOwnerType, IDPState, IDPStylingType } from 'src/app/proto/generated/zitadel/idp_pb';
import { ListOrgIDPsResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -26,20 +26,20 @@ export class IdpTableComponent implements OnInit {
@Input() service!: AdminService | ManagementService;
@Input() disabled: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public dataSource: MatTableDataSource<AdminIdpView.AsObject | MgmtIdpView.AsObject>
= new MatTableDataSource<AdminIdpView.AsObject | MgmtIdpView.AsObject>();
public selection: SelectionModel<AdminIdpView.AsObject | MgmtIdpView.AsObject>
= new SelectionModel<AdminIdpView.AsObject | MgmtIdpView.AsObject>(true, []);
public idpResult!: AdminIdpSearchResponse.AsObject;
public dataSource: MatTableDataSource<IDP.AsObject>
= new MatTableDataSource<IDP.AsObject>();
public selection: SelectionModel<IDP.AsObject>
= new SelectionModel<IDP.AsObject>(true, []);
public idpResult!: ListIDPsResponse.AsObject | ListOrgIDPsResponse.AsObject;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public IdpProviderType: any = IdpProviderType;
public IdpState: any = IdpState;
public IdpStylingType: any = IdpStylingType;
public IDPOwnerType: any = IDPOwnerType;
public IDPState: any = IDPState;
public IdpStylingType: any = IDPStylingType;
@Input() public displayedColumns: string[] = ['select', 'name', 'config', 'dates', 'state'];
@Output() public changedSelection: EventEmitter<Array<AdminIdpView.AsObject | MgmtIdpView.AsObject>>
@Output() public changedSelection: EventEmitter<Array<IDP.AsObject>>
= new EventEmitter();
constructor(public translate: TranslateService, private toast: ToastService, private dialog: MatDialog) {
@@ -77,8 +77,12 @@ export class IdpTableComponent implements OnInit {
}
public deactivateSelectedIdps(): void {
const map: Promise<Empty>[] = this.selection.selected.map(value => {
return this.service.DeactivateIdpConfig(value.id);
const map: Promise<any>[] = this.selection.selected.map(value => {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.service as ManagementService).deactivateOrgIDP(value.id);
} else {
return (this.service as AdminService).deactivateIDP(value.id);
}
});
Promise.all(map).then(() => {
this.selection.clear();
@@ -90,8 +94,12 @@ export class IdpTableComponent implements OnInit {
}
public reactivateSelectedIdps(): void {
const map: Promise<Empty>[] = this.selection.selected.map(value => {
return this.service.ReactivateIdpConfig(value.id);
const map: Promise<any>[] = this.selection.selected.map(value => {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.service as ManagementService).reactivateOrgIDP(value.id);
} else {
return (this.service as AdminService).reactivateIDP(value.id);
}
});
Promise.all(map).then(() => {
this.selection.clear();
@@ -116,9 +124,12 @@ export class IdpTableComponent implements OnInit {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
this.selection.clear();
Promise.all(this.selection.selected.map(value => {
return this.service.RemoveIdpConfig(value.id);
if (this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.service as ManagementService).removeOrgIDP(value.id);
} else {
return (this.service as AdminService).removeIDP(value.id);
}
})).then(() => {
this.toast.showInfo('IDP.TOAST.SELECTEDDEACTIVATED', true);
this.refreshPage();
@@ -127,7 +138,7 @@ export class IdpTableComponent implements OnInit {
});
}
public removeIdp(idp: AdminIdpView.AsObject | MgmtIdpView.AsObject): void {
public removeIdp(idp: IDP.AsObject): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
@@ -140,12 +151,21 @@ export class IdpTableComponent implements OnInit {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
this.service.RemoveIdpConfig(idp.id).then(() => {
this.toast.showInfo('IDP.TOAST.REMOVED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
});
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).removeOrgIDP(idp.id).then(() => {
this.toast.showInfo('IDP.TOAST.REMOVED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
});
} else {
(this.service as AdminService).removeIDP(idp.id).then(() => {
this.toast.showInfo('IDP.TOAST.REMOVED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
});
}
}
});
}
@@ -153,14 +173,26 @@ export class IdpTableComponent implements OnInit {
private async getData(limit: number, offset: number): Promise<void> {
this.loadingSubject.next(true);
this.service.SearchIdps(limit, offset).then(resp => {
this.idpResult = resp.toObject();
this.dataSource.data = this.idpResult.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).listOrgIDPs(limit, offset).then(resp => {
this.idpResult = resp;
this.dataSource.data = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
} else {
(this.service as AdminService).listIDPs(limit, offset).then(resp => {
this.idpResult = resp;
this.dataSource.data = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
}
}
public refreshPage(): void {
@@ -175,14 +207,14 @@ export class IdpTableComponent implements OnInit {
}
}
public routerLinkForRow(row: MgmtIdpView.AsObject | AdminIdpView.AsObject): any {
public routerLinkForRow(row: IDP.AsObject): any {
if (row.id) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
switch ((row as MgmtIdpView.AsObject).providerType) {
case IdpProviderType.IDPPROVIDERTYPE_SYSTEM:
switch (row.owner) {
case IDPOwnerType.IDP_OWNER_TYPE_SYSTEM:
return ['/iam', 'idp', row.id];
case IdpProviderType.IDPPROVIDERTYPE_ORG:
case IDPOwnerType.IDP_OWNER_TYPE_ORG:
return ['/org', 'idp', row.id];
}
break;
+93 -75
View File
@@ -6,18 +6,9 @@ import { MatChipInputEvent } from '@angular/material/chips';
import { ActivatedRoute, Params } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap, take } from 'rxjs/operators';
import {
IdpStylingType as adminIdpStylingType,
IdpUpdate as AdminIdpConfigUpdate,
OidcIdpConfigUpdate as AdminOidcIdpConfigUpdate,
OIDCMappingField as adminMappingFields,
} from 'src/app/proto/generated/admin_pb';
import {
IdpStylingType as mgmtIdpStylingType,
IdpUpdate as MgmtIdpConfigUpdate,
OidcIdpConfigUpdate as MgmtOidcIdpConfigUpdate,
OIDCMappingField as mgmtMappingFields,
} from 'src/app/proto/generated/management_pb';
import { UpdateIDPOIDCConfigRequest, UpdateIDPRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { IDPStylingType, OIDCMappingField } from 'src/app/proto/generated/zitadel/idp_pb';
import { UpdateOrgIDPOIDCConfigRequest, UpdateOrgIDPRequest } from 'src/app/proto/generated/zitadel/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -30,8 +21,8 @@ import { PolicyComponentServiceType } from '../policies/policy-component-types.e
styleUrls: ['./idp.component.scss'],
})
export class IdpComponent implements OnInit, OnDestroy {
public mappingFields: mgmtMappingFields[] | adminMappingFields[] = [];
public styleFields: mgmtIdpStylingType[] | adminIdpStylingType[] = [];
public mappingFields: OIDCMappingField[] = [];
public styleFields: IDPStylingType[] = [];
public showIdSecretSection: boolean = false;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
@@ -70,35 +61,46 @@ export class IdpComponent implements OnInit, OnDestroy {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.mappingFields = [
mgmtMappingFields.OIDCMAPPINGFIELD_PREFERRED_USERNAME,
mgmtMappingFields.OIDCMAPPINGFIELD_EMAIL];
this.styleFields = [
mgmtIdpStylingType.IDPSTYLINGTYPE_UNSPECIFIED,
mgmtIdpStylingType.IDPSTYLINGTYPE_GOOGLE];
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
this.mappingFields = [
adminMappingFields.OIDCMAPPINGFIELD_PREFERRED_USERNAME,
adminMappingFields.OIDCMAPPINGFIELD_EMAIL];
this.styleFields = [
adminIdpStylingType.IDPSTYLINGTYPE_UNSPECIFIED,
adminIdpStylingType.IDPSTYLINGTYPE_GOOGLE];
break;
}
this.mappingFields = [
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL];
this.styleFields = [
IDPStylingType.STYLING_TYPE_UNSPECIFIED,
IDPStylingType.STYLING_TYPE_GOOGLE];
return this.route.params.pipe(take(1));
})).subscribe((params) => {
const { id } = params;
if (id) {
this.service.IdpByID(id).then(idp => {
const idpObject = idp.toObject();
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
});
if (this.serviceType == PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).getOrgIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
});
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
(this.service as AdminService).getIDPByID(id).then(resp => {
if (resp.idp) {
const idpObject = resp.idp;
this.idpForm.patchValue(idpObject);
if (idpObject.oidcConfig) {
this.oidcConfigForm.patchValue(idpObject.oidcConfig);
}
}
});
}
}
});
}
@@ -116,55 +118,71 @@ export class IdpComponent implements OnInit, OnDestroy {
}
public updateIdp(): void {
let req: AdminIdpConfigUpdate | MgmtIdpConfigUpdate;
if (this.serviceType == PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPRequest();
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
req = new MgmtIdpConfigUpdate();
break;
case PolicyComponentServiceType.ADMIN:
req = new AdminIdpConfigUpdate();
break;
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as ManagementService).updateOrgIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPRequest();
req.setIdpId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
(this.service as AdminService).updateIDP(req).then(() => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
req.setId(this.id?.value);
req.setName(this.name?.value);
req.setStylingType(this.stylingType?.value);
this.service.UpdateIdp(req).then((idp) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
public updateOidcConfig(): void {
let req: AdminOidcIdpConfigUpdate | MgmtOidcIdpConfigUpdate;
if (this.serviceType == PolicyComponentServiceType.MGMT) {
const req = new UpdateOrgIDPOIDCConfigRequest();
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
req = new MgmtOidcIdpConfigUpdate();
break;
case PolicyComponentServiceType.ADMIN:
req = new AdminOidcIdpConfigUpdate();
break;
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as ManagementService).updateOrgIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.serviceType == PolicyComponentServiceType.ADMIN) {
const req = new UpdateIDPOIDCConfigRequest();
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
(this.service as AdminService).updateIDPOIDCConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
req.setIdpId(this.id?.value);
req.setClientId(this.clientId?.value);
req.setClientSecret(this.clientSecret?.value);
req.setIssuer(this.issuer?.value);
req.setScopesList(this.scopesList?.value);
req.setUsernameMapping(this.usernameMapping?.value);
req.setIdpDisplayNameMapping(this.idpDisplayNameMapping?.value);
this.service.UpdateOidcIdpConfig(req).then((oidcConfig) => {
this.toast.showInfo('IDP.TOAST.SAVED', true);
// this.router.navigate(['idp', ]);
}).catch(error => {
this.toast.showError(error);
});
}
public close(): void {
@@ -1,5 +1,5 @@
<app-refresh-table [loading]="loading$ | async" (refreshed)="refreshPage()" [dataSize]="dataSource.data.length"
[timestamp]="keyResult?.viewTimestamp" [selection]="selection">
[timestamp]="keyResult?.details?.viewTimestamp" [selection]="selection">
<div actions>
<button color="warn" [disabled]="([('user.write:' + userId), 'user.write'] | hasRole | async) == false"
(click)="deleteSelectedKeys()" matTooltip="{{'ACTIONS.DELETE' | translate}}" class="icon-button"
@@ -58,7 +58,7 @@
</tr>
</table>
<mat-paginator #paginator class="paginator" [length]="keyResult?.totalResult || 0" [pageSize]="10"
<mat-paginator #paginator class="paginator" [length]="keyResult?.details?.totalResult || 0" [pageSize]="10"
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
</div>
</app-refresh-table>
@@ -7,12 +7,12 @@ import { TranslateService } from '@ngx-translate/core';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { Moment } from 'moment';
import { BehaviorSubject, Observable } from 'rxjs';
import { ClientKeySearchResponse, MachineKeySearchResponse, MachineKeyType, MachineKeyView } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { AddKeyDialogComponent, AddKeyDialogType } from 'src/app/modules/add-key-dialog/add-key-dialog.component';
import { ShowKeyDialogComponent } from 'src/app/modules/show-key-dialog/show-key-dialog.component';
import { Key, KeyType } from 'src/app/proto/generated/zitadel/auth_n_key_pb';
import { ListMachineKeysResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'app-machine-keys',
@@ -23,14 +23,14 @@ export class MachineKeysComponent implements OnInit {
@Input() userId!: string;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public dataSource: MatTableDataSource<MachineKeyView.AsObject> = new MatTableDataSource<MachineKeyView.AsObject>();
public selection: SelectionModel<MachineKeyView.AsObject> = new SelectionModel<MachineKeyView.AsObject>(true, []);
public keyResult!: MachineKeySearchResponse.AsObject | ClientKeySearchResponse.AsObject;
public dataSource: MatTableDataSource<Key.AsObject> = new MatTableDataSource<Key.AsObject>();
public selection: SelectionModel<Key.AsObject> = new SelectionModel<Key.AsObject>(true, []);
public keyResult!: ListMachineKeysResponse.AsObject;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@Input() public displayedColumns: string[] = ['select', 'id', 'type', 'creationDate', 'expirationDate'];
@Output() public changedSelection: EventEmitter<Array<MachineKeyView.AsObject>> = new EventEmitter();
@Output() public changedSelection: EventEmitter<Array<Key.AsObject>> = new EventEmitter();
constructor(public translate: TranslateService, private mgmtService: ManagementService, private dialog: MatDialog,
private toast: ToastService) {
@@ -63,7 +63,7 @@ export class MachineKeysComponent implements OnInit {
public deleteSelectedKeys(): void {
const mappedDeletions = this.selection.selected.map(value => {
return this.mgmtService.DeleteMachineKey(value.id, this.userId);
return this.mgmtService.removeMachineKey(value.id, this.userId);
});
Promise.all(mappedDeletions).then(() => {
this.selection.clear();
@@ -82,7 +82,7 @@ export class MachineKeysComponent implements OnInit {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
const type: MachineKeyType = resp.type;
const type: KeyType = resp.type;
let date: Timestamp | undefined;
@@ -98,7 +98,7 @@ export class MachineKeysComponent implements OnInit {
}
if (type) {
return this.mgmtService.AddMachineKey(this.userId, type, date).then((response) => {
return this.mgmtService.addMachineKey(this.userId, type, date).then((response) => {
if (response) {
setTimeout(() => {
this.refreshPage();
@@ -106,7 +106,7 @@ export class MachineKeysComponent implements OnInit {
this.dialog.open(ShowKeyDialogComponent, {
data: {
key: response.toObject(),
key: response,
type: AddKeyDialogType.MACHINE
},
width: '400px',
@@ -124,9 +124,11 @@ export class MachineKeysComponent implements OnInit {
this.loadingSubject.next(true);
if (this.userId) {
this.mgmtService.SearchMachineKeys(this.userId, limit, offset).then(resp => {
this.keyResult = resp.toObject();
this.dataSource.data = this.keyResult.resultList;
this.mgmtService.listMachineKeys(this.userId, limit, offset).then(resp => {
this.keyResult = resp;
if (resp.resultList) {
this.dataSource.data = resp.resultList;
}
this.loadingSubject.next(false);
}).catch((error: any) => {
this.toast.showError(error);
@@ -7,12 +7,10 @@ import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { IamMembersDataSource } from 'src/app/pages/iam/iam-members/iam-members-datasource';
import { OrgMembersDataSource } from 'src/app/pages/orgs/org-members/org-members-datasource';
import { IamMemberView } from 'src/app/proto/generated/admin_pb';
import { OrgMemberView, ProjectMemberView } from 'src/app/proto/generated/management_pb';
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
import { ProjectMembersDataSource } from '../project-members/project-members-datasource';
type View = OrgMemberView.AsObject | ProjectMemberView.AsObject | IamMemberView.AsObject;
type MemberDatasource = OrgMembersDataSource | ProjectMembersDataSource | IamMembersDataSource;
@Component({
@@ -25,15 +23,15 @@ export class MembersTableComponent implements OnInit, OnDestroy {
@Input() public canDelete: boolean = false;
@Input() public canWrite: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
@ViewChild(MatTable) public table!: MatTable<View>;
@ViewChild(MatTable) public table!: MatTable<Member>;
@Input() public dataSource!: MemberDatasource;
public selection: SelectionModel<any> = new SelectionModel<any>(true, []);
@Input() public memberRoleOptions: string[] = [];
@Input() public factoryLoadFunc!: Function;
@Input() public refreshTrigger!: Observable<void>;
@Output() public updateRoles: EventEmitter<{ member: View, change: MatSelectChange; }> = new EventEmitter();
@Output() public updateRoles: EventEmitter<{ member: Member, change: MatSelectChange; }> = new EventEmitter();
@Output() public changedSelection: EventEmitter<any[]> = new EventEmitter();
@Output() public deleteMember: EventEmitter<View> = new EventEmitter();
@Output() public deleteMember: EventEmitter<Member> = new EventEmitter();
private destroyed: Subject<void> = new Subject();
@@ -2,18 +2,18 @@
<div mat-dialog-content>
<p class="desc">{{data.desc | translate}}</p>
<cnsl-form-field class="form-field" label="Access Code" required="true">
<!-- <cnsl-form-field class="form-field" label="Access Code" required="true">
<cnsl-label>{{'MFA.TYPE' | translate}}</cnsl-label>
<mat-select [(ngModel)]="newMfaType">
<mat-option *ngFor="let mfa of availableMfaTypes" [value]="mfa">
<mat-option *ngFor="let mfa of []" [value]="mfa">
{{(data.componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.': LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
</mat-option>
</mat-select>
</cnsl-form-field>
</cnsl-form-field> -->
</div>
<div mat-dialog-actions class="action">
<button mat-button (click)="closeDialog()"><span>{{'ACTIONS.CLOSE' | translate}}</span></button>
<button [disabled]="newMfaType == undefined" mat-raised-button class="ok-button" color="primary"
<button [disabled]="false" mat-raised-button class="ok-button" color="primary"
(click)="closeDialogWithCode()"><span>{{'ACTIONS.OK' | translate}}</span>
</button>
</div>
@@ -1,9 +1,6 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MultiFactorType as AdminMultiFactorType } from 'src/app/proto/generated/admin_pb';
import { MultiFactorType as MgmtMultiFactorType } from 'src/app/proto/generated/management_pb';
enum LoginMethodComponentType {
MultiFactor = 1,
SecondFactor = 2,
@@ -16,11 +13,10 @@ enum LoginMethodComponentType {
})
export class DialogAddTypeComponent {
public LoginMethodComponentType: any = LoginMethodComponentType;
public newMfaType!: AdminMultiFactorType | MgmtMultiFactorType;
public availableMfaTypes: Array<AdminMultiFactorType | MgmtMultiFactorType> = [];
// public availableMfaTypes: Array<AdminMultiFactorType | MgmtMultiFactorType> = [];
constructor(public dialogRef: MatDialogRef<DialogAddTypeComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.availableMfaTypes = data.types;
// this.availableMfaTypes = data.types;
}
public closeDialog(): void {
@@ -28,6 +24,6 @@ export class DialogAddTypeComponent {
}
public closeDialogWithCode(): void {
this.dialogRef.close(this.newMfaType);
// this.dialogRef.close(this.newMfaType);
}
}
@@ -4,24 +4,20 @@ import { MatPaginator } from '@angular/material/paginator';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Observable } from 'rxjs';
import {
MultiFactor as AdminMultiFactor,
MultiFactorType as AdminMultiFactorType,
SecondFactor as AdminSecondFactor,
SecondFactorType as AdminSecondFactorType,
} from 'src/app/proto/generated/admin_pb';
RemoveMultiFactorFromLoginPolicyRequest as AdminRemoveMultiFactorFromLoginPolicyRequest,
RemoveSecondFactorFromLoginPolicyRequest as AdminRemoveSecondFactorFromLoginPolicyRequest,
} from 'src/app/proto/generated/zitadel/admin_pb';
import {
MultiFactor as MgmtMultiFactor,
MultiFactorType as MgmtMultiFactorType,
SecondFactor as MgmtSecondFactor,
SecondFactorType as MgmtSecondFactorType,
} from 'src/app/proto/generated/management_pb';
RemoveMultiFactorFromLoginPolicyRequest as MgmtRemoveMultiFactorFromLoginPolicyRequest,
RemoveSecondFactorFromLoginPolicyRequest as MgmtRemoveSecondFactorFromLoginPolicyRequest,
} from 'src/app/proto/generated/zitadel/management_pb';
import { MultiFactorType, SecondFactorType } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
import { DialogAddTypeComponent } from './dialog-add-type/dialog-add-type.component';
export enum LoginMethodComponentType {
MultiFactor = 1,
@@ -40,7 +36,7 @@ export class MfaTableComponent implements OnInit {
@Input() service!: AdminService | ManagementService;
@Input() disabled: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public mfas: Array<AdminMultiFactorType | MgmtMultiFactorType | MgmtSecondFactorType | AdminSecondFactorType> = [];
public mfas: Array<MultiFactorType | SecondFactorType> = [];
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@@ -53,7 +49,7 @@ export class MfaTableComponent implements OnInit {
this.getData();
}
public removeMfa(type: MgmtMultiFactorType | AdminMultiFactorType | MgmtSecondFactorType | AdminSecondFactorType): void {
public removeMfa(type: MultiFactorType | SecondFactorType): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
@@ -68,32 +64,32 @@ export class MfaTableComponent implements OnInit {
if (resp) {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
const req = new MgmtMultiFactor();
req.setMultiFactor(type as MgmtMultiFactorType);
(this.service as ManagementService).RemoveMultiFactorFromLoginPolicy(req).then(() => {
const req = new MgmtRemoveMultiFactorFromLoginPolicyRequest();
req.setType(type as MultiFactorType);
(this.service as ManagementService).removeMultiFactorFromLoginPolicy(req).then(() => {
this.toast.showInfo('MFA.TOAST.DELETED', true);
this.refreshPageAfterTimout(2000);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
const req = new MgmtSecondFactor();
req.setSecondFactor(type as MgmtSecondFactorType);
(this.service as ManagementService).RemoveSecondFactorFromLoginPolicy(req).then(() => {
const req = new MgmtRemoveSecondFactorFromLoginPolicyRequest();
req.setType(type as SecondFactorType);
(this.service as ManagementService).removeSecondFactorFromLoginPolicy(req).then(() => {
this.toast.showInfo('MFA.TOAST.DELETED', true);
this.refreshPageAfterTimout(2000);
});
}
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
const req = new AdminMultiFactor();
req.setMultiFactor(type as AdminMultiFactorType);
(this.service as AdminService).RemoveMultiFactorFromDefaultLoginPolicy(req).then(() => {
const req = new AdminRemoveMultiFactorFromLoginPolicyRequest();
req.setType(type as MultiFactorType);
(this.service as AdminService).removeMultiFactorFromLoginPolicy(req).then(() => {
this.toast.showInfo('MFA.TOAST.DELETED', true);
this.refreshPageAfterTimout(2000);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
const req = new AdminSecondFactor();
req.setSecondFactor(type as AdminSecondFactorType);
(this.service as AdminService).RemoveSecondFactorFromDefaultLoginPolicy(req).then(() => {
const req = new AdminRemoveSecondFactorFromLoginPolicyRequest();
req.setType(type as SecondFactorType);
(this.service as AdminService).removeSecondFactorFromLoginPolicy(req).then(() => {
this.toast.showInfo('MFA.TOAST.DELETED', true);
this.refreshPageAfterTimout(2000);
});
@@ -108,17 +104,9 @@ export class MfaTableComponent implements OnInit {
let selection: any[] = [];
if (this.componentType === LoginMethodComponentType.MultiFactor) {
selection = this.serviceType === PolicyComponentServiceType.MGMT ?
[MgmtMultiFactorType.MULTIFACTORTYPE_U2F_WITH_PIN] :
this.serviceType === PolicyComponentServiceType.ADMIN ?
[AdminMultiFactorType.MULTIFACTORTYPE_U2F_WITH_PIN] :
[];
selection = [MultiFactorType.MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION];
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
selection = this.serviceType === PolicyComponentServiceType.MGMT ?
[MgmtSecondFactorType.SECONDFACTORTYPE_U2F, MgmtSecondFactorType.SECONDFACTORTYPE_OTP] :
this.serviceType === PolicyComponentServiceType.ADMIN ?
[AdminSecondFactorType.SECONDFACTORTYPE_OTP, AdminSecondFactorType.SECONDFACTORTYPE_U2F] :
[];
selection = [SecondFactorType.SECOND_FACTOR_TYPE_U2F, SecondFactorType.SECOND_FACTOR_TYPE_OTP];
}
this.mfas.forEach(mfa => {
@@ -128,58 +116,57 @@ export class MfaTableComponent implements OnInit {
}
});
const dialogRef = this.dialog.open(DialogAddTypeComponent, {
data: {
title: 'MFA.CREATE.TITLE',
desc: 'MFA.CREATE.DESCRIPTION',
componentType: this.componentType,
types: selection,
},
width: '400px',
});
// const dialogRef = this.dialog.open(DialogAddTypeComponent, {
// data: {
// title: 'MFA.CREATE.TITLE',
// desc: 'MFA.CREATE.DESCRIPTION',
// componentType: this.componentType,
// types: selection,
// },
// width: '400px',
// });
dialogRef.afterClosed().subscribe((mfaType: AdminMultiFactorType | MgmtMultiFactorType |
AdminSecondFactorType | MgmtSecondFactorType) => {
if (mfaType) {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
const req = new MgmtMultiFactor();
req.setMultiFactor(mfaType as MgmtMultiFactorType);
(this.service as ManagementService).AddMultiFactorToLoginPolicy(req).then(() => {
this.refreshPageAfterTimout(2000);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
const req = new MgmtSecondFactor();
req.setSecondFactor(mfaType as MgmtSecondFactorType);
(this.service as ManagementService).AddSecondFactorToLoginPolicy(req).then(() => {
this.refreshPageAfterTimout(2000);
}).catch(error => {
this.toast.showError(error);
});
}
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
const req = new AdminMultiFactor();
req.setMultiFactor(mfaType as AdminMultiFactorType);
(this.service as AdminService).addMultiFactorToDefaultLoginPolicy(req).then(() => {
this.refreshPageAfterTimout(2000);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
const req = new AdminSecondFactor();
req.setSecondFactor(mfaType as AdminSecondFactorType);
(this.service as AdminService).AddSecondFactorToDefaultLoginPolicy(req).then(() => {
this.refreshPageAfterTimout(2000);
}).catch(error => {
this.toast.showError(error);
});
}
}
}
});
// dialogRef.afterClosed().subscribe((mfaType: ) => {
// if (mfaType) {
// if (this.serviceType === PolicyComponentServiceType.MGMT) {
// if (this.componentType === LoginMethodComponentType.MultiFactor) {
// const req = new MgmtAddMultiFactorToLoginPolicyRequest();
// req.setType(mfaType as MultiFactorType);
// (this.service as ManagementService).addMultiFactorToLoginPolicy(req).then(() => {
// this.refreshPageAfterTimout(2000);
// }).catch(error => {
// this.toast.showError(error);
// });
// } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
// const req = new MgmtAddSecondFactorToLoginPolicyRequest();
// req.setType(mfaType as SecondFactorType);
// (this.service as ManagementService).addSecondFactorToLoginPolicy(req).then(() => {
// this.refreshPageAfterTimout(2000);
// }).catch(error => {
// this.toast.showError(error);
// });
// }
// } else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
// if (this.componentType === LoginMethodComponentType.MultiFactor) {
// const req = new AdminAddMultiFactorToLoginPolicyRequest();
// req.setType(mfaType as MultiFactorType);
// (this.service as AdminService).addMultiFactorToLoginPolicy(req).then(() => {
// this.refreshPageAfterTimout(2000);
// }).catch(error => {
// this.toast.showError(error);
// });
// } else if (this.componentType === LoginMethodComponentType.SecondFactor) {
// const req = new AdminAddSecondFactorToLoginPolicyRequest();
// req.setType(mfaType as SecondFactorType);
// (this.service as AdminService).addSecondFactorToLoginPolicy(req).then(() => {
// this.refreshPageAfterTimout(2000);
// }).catch(error => {
// this.toast.showError(error);
// });
// }
// }
// }
// });
}
private async getData(): Promise<void> {
@@ -187,16 +174,16 @@ export class MfaTableComponent implements OnInit {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
(this.service as ManagementService).GetLoginPolicyMultiFactors().then(resp => {
this.mfas = resp.toObject().multiFactorsList;
(this.service as ManagementService).listLoginPolicyMultiFactors().then(resp => {
this.mfas = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
(this.service as ManagementService).GetLoginPolicySecondFactors().then(resp => {
this.mfas = resp.toObject().secondFactorsList;
(this.service as ManagementService).listLoginPolicySecondFactors().then(resp => {
this.mfas = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
@@ -205,16 +192,16 @@ export class MfaTableComponent implements OnInit {
}
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
if (this.componentType === LoginMethodComponentType.MultiFactor) {
(this.service as AdminService).getDefaultLoginPolicyMultiFactors().then(resp => {
this.mfas = resp.toObject().multiFactorsList;
(this.service as AdminService).listLoginPolicyMultiFactors().then(resp => {
this.mfas = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
(this.service as AdminService).GetDefaultLoginPolicySecondFactors().then(resp => {
this.mfas = resp.toObject().secondFactorsList;
(this.service as AdminService).listLoginPolicySecondFactors().then(resp => {
this.mfas = resp.resultList;
this.loadingSubject.next(false);
}).catch(error => {
this.toast.showError(error);
@@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/management_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
@Component({
selector: 'app-password-complexity-view',
@@ -1,12 +1,13 @@
import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { DefaultLabelPolicyUpdate, DefaultLabelPolicyView } from 'src/app/proto/generated/admin_pb';
import { GetLabelPolicyResponse, UpdateLabelPolicyRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
import { CnslLinks } from '../../links/links.component';
import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK } from '../../policy-grid/policy-links';
import { CnslLinks } from '../../links/links.component';
import { IAM_COMPLEXITY_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK } from '../../policy-grid/policy-links';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@@ -16,7 +17,7 @@ import { PolicyComponentServiceType } from '../policy-component-types.enum';
styleUrls: ['./label-policy.component.scss'],
})
export class LabelPolicyComponent implements OnDestroy {
public labelData!: DefaultLabelPolicyView.AsObject;
public labelData!: LabelPolicy.AsObject;
private sub: Subscription = new Subscription();
@@ -33,8 +34,8 @@ export class LabelPolicyComponent implements OnDestroy {
) {
this.route.params.subscribe(() => {
this.getData().then(data => {
if (data) {
this.labelData = data.toObject();
if (data?.policy) {
this.labelData = data.policy;
}
});
});
@@ -44,15 +45,15 @@ export class LabelPolicyComponent implements OnDestroy {
this.sub.unsubscribe();
}
private async getData(): Promise<DefaultLabelPolicyView> {
return this.adminService.GetDefaultLabelPolicy();
private async getData(): Promise<GetLabelPolicyResponse.AsObject> {
return this.adminService.getLabelPolicy();
}
public savePolicy(): void {
const req = new DefaultLabelPolicyUpdate();
const req = new UpdateLabelPolicyRequest();
req.setPrimaryColor(this.labelData.primaryColor);
req.setSecondaryColor(this.labelData.secondaryColor);
this.adminService.UpdateDefaultLabelPolicy(req).then(() => {
this.adminService.updateLabelPolicy(req).then(() => {
this.toast.showInfo('POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
@@ -1,14 +1,7 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { IdpView as AdminIdpView } from 'src/app/proto/generated/admin_pb';
import {
Idp,
IdpProviderType,
IdpSearchKey,
IdpSearchQuery,
IdpView as MgmtIdpView,
SearchMethod,
} from 'src/app/proto/generated/management_pb';
import { IDP, IDPOwnerType, IDPOwnerTypeQuery } from 'src/app/proto/generated/zitadel/idp_pb';
import { IDPQuery } from 'src/app/proto/generated/zitadel/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -23,15 +16,15 @@ export class AddIdpDialogComponent {
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public idpType!: IdpProviderType;
public idpTypes: IdpProviderType[] = [
IdpProviderType.IDPPROVIDERTYPE_SYSTEM,
IdpProviderType.IDPPROVIDERTYPE_ORG,
public idpType!: IDPOwnerType;
public idpTypes: IDPOwnerType[] = [
IDPOwnerType.IDP_OWNER_TYPE_SYSTEM,
IDPOwnerType.IDP_OWNER_TYPE_ORG,
];
public idp: Idp.AsObject | undefined = undefined;
public availableIdps: Array<AdminIdpView.AsObject | MgmtIdpView.AsObject> | string[] = [];
public IdpProviderType: any = IdpProviderType;
public idp: IDP.AsObject | undefined = undefined;
public availableIdps: Array<IDP.AsObject[] | IDP.AsObject> | string[] = [];
public IdpProviderType: any = IDPOwnerType;
constructor(
private mgmtService: ManagementService,
@@ -43,10 +36,10 @@ export class AddIdpDialogComponent {
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.idpType = IdpProviderType.IDPPROVIDERTYPE_ORG;
this.idpType = IDPOwnerType.IDP_OWNER_TYPE_ORG;
break;
case PolicyComponentServiceType.ADMIN:
this.idpType = IdpProviderType.IDPPROVIDERTYPE_SYSTEM;
this.idpType = IDPOwnerType.IDP_OWNER_TYPE_SYSTEM;
break;
}
}
@@ -57,17 +50,17 @@ export class AddIdpDialogComponent {
public loadIdps(): void {
this.idp = undefined;
if (this.serviceType === PolicyComponentServiceType.MGMT) {
const query: IdpSearchQuery = new IdpSearchQuery();
query.setKey(IdpSearchKey.IDPSEARCHKEY_PROVIDER_TYPE);
query.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
query.setValue(this.idpType.toString());
const query: IDPQuery = new IDPQuery();
const idpOTQ: IDPOwnerTypeQuery = new IDPOwnerTypeQuery();
idpOTQ.setOwnerType(this.idpType);
query.setOwnerTypeQuery(idpOTQ);
this.mgmtService.SearchIdps(undefined, undefined, [query]).then(idps => {
this.availableIdps = idps.toObject().resultList;
this.mgmtService.listOrgIDPs(undefined, undefined, [query]).then(resp => {
this.availableIdps = resp.resultList;
});
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
this.adminService.SearchIdps().then(idps => {
this.availableIdps = idps.toObject().resultList;
this.adminService.listIDPs().then(resp => {
this.availableIdps = resp.resultList;
});
}
}
@@ -102,7 +102,7 @@
</button>
<div class="line">
<img src="../../../assets/images/google.png"
*ngIf="idp.stylingType == IdpStylingType.IDPSTYLINGTYPE_GOOGLE" alt="google" />
*ngIf="idp.stylingType == IDPStylingType.STYLING_TYPE_GOOGLE" alt="google" />
<div>
<span class="name">{{idp.name}}</span>
<span class="meta-info">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }}</span>
@@ -5,29 +5,28 @@ import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { LoginMethodComponentType } from 'src/app/modules/mfa-table/mfa-table.component';
import {
DefaultLoginPolicy,
DefaultLoginPolicyRequest,
DefaultLoginPolicyView,
IdpProviderView as AdminIdpProviderView,
IdpStylingType,
IdpView as AdminIdpView,
PasswordlessType as AdminPasswordlessType,
} from 'src/app/proto/generated/admin_pb';
GetLoginPolicyResponse as AdminGetLoginPolicyResponse,
UpdateLoginPolicyRequest,
UpdateLoginPolicyResponse,
} from 'src/app/proto/generated/zitadel/admin_pb';
import { IDP, IDPLoginPolicyLink, IDPStylingType } from 'src/app/proto/generated/zitadel/idp_pb';
import {
IdpProviderType,
IdpProviderView as MgmtIdpProviderView,
IdpView as MgmtIdpView,
LoginPolicy,
LoginPolicyRequest,
LoginPolicyView,
PasswordlessType as MgmtPasswordlessType,
} from 'src/app/proto/generated/management_pb';
AddCustomLoginPolicyRequest,
GetLoginPolicyResponse as MgmtGetLoginPolicyResponse,
} from 'src/app/proto/generated/zitadel/management_pb';
import { LoginPolicy, PasswordlessType } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { CnslLinks } from '../../links/links.component';
import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK, ORG_COMPLEXITY_LINK, ORG_IAM_POLICY_LINK } from '../../policy-grid/policy-links';
import { CnslLinks } from '../../links/links.component';
import {
IAM_COMPLEXITY_LINK,
IAM_LABEL_LINK,
IAM_POLICY_LINK,
ORG_COMPLEXITY_LINK,
ORG_IAM_POLICY_LINK,
} from '../../policy-grid/policy-links';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
import { AddIdpDialogComponent } from './add-idp-dialog/add-idp-dialog.component';
@@ -38,19 +37,19 @@ import { AddIdpDialogComponent } from './add-idp-dialog/add-idp-dialog.component
})
export class LoginPolicyComponent implements OnDestroy {
public LoginMethodComponentType: any = LoginMethodComponentType;
public passwordlessTypes: Array<AdminPasswordlessType | MgmtPasswordlessType> = [];
public loginData!: LoginPolicyView.AsObject | DefaultLoginPolicyView.AsObject;
public passwordlessTypes: Array<PasswordlessType> = [];
public loginData!: LoginPolicy.AsObject;
private sub: Subscription = new Subscription();
public service!: ManagementService | AdminService;
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public idps: MgmtIdpProviderView.AsObject[] | AdminIdpProviderView.AsObject[] = [];
public idps: IDPLoginPolicyLink.AsObject[] = [];
public loading: boolean = false;
public disabled: boolean = true;
public IdpStylingType: any = IdpStylingType;
public IDPStylingType: any = IDPStylingType;
public nextLinks: CnslLinks[] = [];
constructor(
private route: ActivatedRoute,
@@ -63,8 +62,10 @@ export class LoginPolicyComponent implements OnDestroy {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
this.passwordlessTypes = [MgmtPasswordlessType.PASSWORDLESSTYPE_ALLOWED,
MgmtPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED];
this.passwordlessTypes = [
PasswordlessType.PASSWORDLESS_TYPE_ALLOWED,
PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED,
];
this.nextLinks = [
ORG_COMPLEXITY_LINK,
ORG_IAM_POLICY_LINK,
@@ -72,8 +73,10 @@ export class LoginPolicyComponent implements OnDestroy {
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
this.passwordlessTypes = [AdminPasswordlessType.PASSWORDLESSTYPE_ALLOWED,
AdminPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED];
this.passwordlessTypes = [
PasswordlessType.PASSWORDLESS_TYPE_ALLOWED,
PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED,
];
this.nextLinks = [
IAM_COMPLEXITY_LINK,
IAM_POLICY_LINK,
@@ -89,15 +92,15 @@ export class LoginPolicyComponent implements OnDestroy {
}
private fetchData(): void {
this.getData().then(data => {
if (data) {
this.loginData = data.toObject();
this.getData().then(resp => {
if (resp.policy) {
this.loginData = resp.policy;
this.loading = false;
this.disabled = ((this.loginData as LoginPolicyView.AsObject)?.pb_default) ?? false;
this.disabled = ((this.loginData as LoginPolicy.AsObject)?.isDefault) ?? false;
}
});
this.getIdps().then(idps => {
this.idps = idps;
this.getIdps().then(resp => {
this.idps = resp;
});
}
@@ -106,48 +109,48 @@ export class LoginPolicyComponent implements OnDestroy {
}
private async getData():
Promise<LoginPolicyView | DefaultLoginPolicyView> {
Promise<AdminGetLoginPolicyResponse.AsObject | MgmtGetLoginPolicyResponse.AsObject> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetLoginPolicy();
return (this.service as ManagementService).getLoginPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultLoginPolicy();
return (this.service as AdminService).getLoginPolicy();
}
}
private async getIdps(): Promise<MgmtIdpProviderView.AsObject[] | AdminIdpProviderView.AsObject[]> {
private async getIdps(): Promise<IDPLoginPolicyLink.AsObject[]> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetLoginPolicyIdpProviders()
.then((providers) => {
return providers.toObject().resultList;
return (this.service as ManagementService).listLoginPolicyIDPs()
.then((resp) => {
return resp.resultList;
});
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultLoginPolicyIdpProviders()
return (this.service as AdminService).listLoginPolicyIDPs()
.then((providers) => {
return providers.toObject().resultList;
return providers.resultList;
});
}
}
private async updateData():
Promise<LoginPolicy | DefaultLoginPolicy> {
Promise<UpdateLoginPolicyResponse.AsObject> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
const mgmtreq = new LoginPolicyRequest();
const mgmtreq = new AddCustomLoginPolicyRequest();
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
mgmtreq.setAllowRegister(this.loginData.allowRegister);
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
mgmtreq.setForceMfa(this.loginData.forceMfa);
mgmtreq.setPasswordlessType(this.loginData.passwordlessType);
// console.log(mgmtreq.toObject());
if ((this.loginData as LoginPolicyView.AsObject).pb_default) {
return (this.service as ManagementService).CreateLoginPolicy(mgmtreq);
if ((this.loginData as LoginPolicy.AsObject).isDefault) {
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
} else {
return (this.service as ManagementService).UpdateLoginPolicy(mgmtreq);
return (this.service as ManagementService).updateCustomLoginPolicy(mgmtreq);
}
case PolicyComponentServiceType.ADMIN:
const adminreq = new DefaultLoginPolicyRequest();
const adminreq = new UpdateLoginPolicyRequest();
adminreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
adminreq.setAllowRegister(this.loginData.allowRegister);
adminreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
@@ -156,7 +159,7 @@ export class LoginPolicyComponent implements OnDestroy {
// console.log(adminreq.toObject());
return (this.service as AdminService).UpdateDefaultLoginPolicy(adminreq);
return (this.service as AdminService).updateLoginPolicy(adminreq);
}
}
@@ -174,7 +177,7 @@ export class LoginPolicyComponent implements OnDestroy {
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).RemoveLoginPolicy().then(() => {
(this.service as ManagementService).resetLoginPolicyToDefault().then(() => {
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
this.loading = true;
setTimeout(() => {
@@ -195,8 +198,8 @@ export class LoginPolicyComponent implements OnDestroy {
});
dialogRef.afterClosed().subscribe(resp => {
if (resp && resp.idp && resp.type) {
this.addIdp(resp.idp, resp.type).then(() => {
if (resp && resp.idp) {
this.addIdp(resp.idp).then(() => {
this.loading = true;
setTimeout(() => {
this.fetchData();
@@ -208,29 +211,28 @@ export class LoginPolicyComponent implements OnDestroy {
});
}
private addIdp(idp: AdminIdpView.AsObject | MgmtIdpView.AsObject,
type: IdpProviderType = IdpProviderType.IDPPROVIDERTYPE_SYSTEM): Promise<any> {
private addIdp(idp: IDP.AsObject | IDP.AsObject): Promise<any> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).addIdpProviderToLoginPolicy(idp.id, type);
return (this.service as ManagementService).addIDPToLoginPolicy(idp.id);
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).AddIdpProviderToDefaultLoginPolicy(idp.id);
return (this.service as AdminService).addIDPToLoginPolicy(idp.id);
}
}
public removeIdp(idp: AdminIdpProviderView.AsObject | MgmtIdpProviderView.AsObject): void {
public removeIdp(idp: IDPLoginPolicyLink.AsObject): void {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
(this.service as ManagementService).RemoveIdpProviderFromLoginPolicy(idp.idpConfigId).then(() => {
const index = (this.idps as MgmtIdpProviderView.AsObject[]).findIndex(temp => temp === idp);
(this.service as ManagementService).removeIDPFromLoginPolicy(idp.idpId).then(() => {
const index = this.idps.findIndex(temp => temp === idp);
if (index > -1) {
this.idps.splice(index, 1);
}
});
break;
case PolicyComponentServiceType.ADMIN:
(this.service as AdminService).RemoveIdpProviderFromDefaultLoginPolicy(idp.idpConfigId).then(() => {
const index = (this.idps as AdminIdpProviderView.AsObject[]).findIndex(temp => temp === idp);
(this.service as AdminService).removeIDPFromLoginPolicy(idp.idpId).then(() => {
const index = this.idps.findIndex(temp => temp === idp);
if (index > -1) {
this.idps.splice(index, 1);
}
@@ -241,7 +243,7 @@ export class LoginPolicyComponent implements OnDestroy {
public get isDefault(): boolean {
if (this.loginData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.loginData as LoginPolicyView.AsObject).pb_default;
return (this.loginData as LoginPolicy.AsObject).isDefault;
} else {
return false;
}
@@ -2,16 +2,23 @@ import { Component, Injector, Input, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { OrgIamPolicyView as AdminOrgIamPolicyView } from 'src/app/proto/generated/admin_pb';
import { Org } from 'src/app/proto/generated/auth_pb';
import { OrgIamPolicyView as MgmtOrgIamPolicyView } from 'src/app/proto/generated/management_pb';
import { GetCustomOrgIAMPolicyResponse } from 'src/app/proto/generated/zitadel/admin_pb';
import { GetOrgIAMPolicyResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { OrgIAMPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { StorageService } from 'src/app/services/storage.service';
import { ToastService } from 'src/app/services/toast.service';
import { CnslLinks } from '../../links/links.component';
import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, ORG_LOGIN_POLICY_LINK, ORG_COMPLEXITY_LINK } from '../../policy-grid/policy-links';
import { CnslLinks } from '../../links/links.component';
import {
IAM_COMPLEXITY_LINK,
IAM_LABEL_LINK,
IAM_LOGIN_POLICY_LINK,
ORG_COMPLEXITY_LINK,
ORG_LOGIN_POLICY_LINK,
} from '../../policy-grid/policy-links';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
@@ -24,7 +31,7 @@ export class OrgIamPolicyComponent implements OnDestroy {
private managementService!: ManagementService;
public serviceType!: PolicyComponentServiceType;
public iamData!: AdminOrgIamPolicyView.AsObject | MgmtOrgIamPolicyView.AsObject;
public iamData!: OrgIAMPolicy.AsObject;
private sub: Subscription = new Subscription();
private org!: Org.AsObject;
@@ -68,20 +75,20 @@ export class OrgIamPolicyComponent implements OnDestroy {
}
public fetchData(): void {
this.getData().then(data => {
if (data) {
this.iamData = data.toObject();
this.getData().then(resp => {
if (resp?.policy) {
this.iamData = resp.policy;
}
});
}
private async getData(): Promise<AdminOrgIamPolicyView | MgmtOrgIamPolicyView | undefined> {
private async getData(): Promise<GetCustomOrgIAMPolicyResponse.AsObject | GetOrgIAMPolicyResponse.AsObject | undefined> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return this.managementService.GetMyOrgIamPolicy();
return this.managementService.getOrgIAMPolicy();
case PolicyComponentServiceType.ADMIN:
if (this.org?.id) {
return this.adminService.GetOrgIamPolicy(this.org.id);
return this.adminService.getCustomOrgIAMPolicy(this.org.id);
}
break;
}
@@ -90,8 +97,8 @@ export class OrgIamPolicyComponent implements OnDestroy {
public savePolicy(): void {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.iamData as MgmtOrgIamPolicyView.AsObject).pb_default) {
this.adminService.CreateOrgIamPolicy(
if ((this.iamData as OrgIAMPolicy.AsObject).isDefault) {
this.adminService.addCustomOrgIAMPolicy(
this.org.id,
this.iamData.userLoginMustBeDomain,
).then(() => {
@@ -101,7 +108,7 @@ export class OrgIamPolicyComponent implements OnDestroy {
});
break;
} else {
this.adminService.UpdateOrgIamPolicy(
this.adminService.updateCustomOrgIAMPolicy(
this.org.id,
this.iamData.userLoginMustBeDomain,
).then(() => {
@@ -113,8 +120,7 @@ export class OrgIamPolicyComponent implements OnDestroy {
}
case PolicyComponentServiceType.ADMIN:
// update Default org iam policy?
this.adminService.UpdateOrgIamPolicy(
this.org.id,
this.adminService.updateOrgIAMPolicy(
this.iamData.userLoginMustBeDomain,
).then(() => {
this.toast.showInfo('POLICY.TOAST.SET', true);
@@ -127,7 +133,7 @@ export class OrgIamPolicyComponent implements OnDestroy {
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
this.adminService.RemoveOrgIamPolicy(this.org.id).then(() => {
this.adminService.resetCustomOrgIAMPolicyToDefault(this.org.id).then(() => {
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.fetchData();
@@ -140,7 +146,7 @@ export class OrgIamPolicyComponent implements OnDestroy {
public get isDefault(): boolean {
if (this.iamData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.iamData as MgmtOrgIamPolicyView.AsObject).pb_default;
return (this.iamData as OrgIAMPolicy.AsObject).isDefault;
} else {
return false;
}
@@ -2,8 +2,11 @@ import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DefaultPasswordAgePolicyView } from 'src/app/proto/generated/admin_pb';
import { PasswordAgePolicyView } from 'src/app/proto/generated/management_pb';
import { GetPasswordAgePolicyResponse as AdminGetPasswordAgePolicyResponse } from 'src/app/proto/generated/zitadel/admin_pb';
import {
GetPasswordAgePolicyResponse as MgmtGetPasswordAgePolicyResponse,
} from 'src/app/proto/generated/zitadel/management_pb';
import { PasswordAgePolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -20,7 +23,7 @@ export class PasswordAgePolicyComponent implements OnDestroy {
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public service!: AdminService | ManagementService;
public ageData!: PasswordAgePolicyView.AsObject | DefaultPasswordAgePolicyView.AsObject;
public ageData!: PasswordAgePolicy.AsObject | PasswordAgePolicy.AsObject;
private sub: Subscription = new Subscription();
@@ -43,9 +46,9 @@ export class PasswordAgePolicyComponent implements OnDestroy {
return this.route.params;
})).subscribe(() => {
this.getData().then(data => {
if (data) {
this.ageData = data.toObject();
this.getData().then(resp => {
if (resp.policy) {
this.ageData = resp.policy;
}
});
});
@@ -56,19 +59,19 @@ export class PasswordAgePolicyComponent implements OnDestroy {
}
private async getData():
Promise<PasswordAgePolicyView | DefaultPasswordAgePolicyView> {
Promise<MgmtGetPasswordAgePolicyResponse.AsObject | AdminGetPasswordAgePolicyResponse.AsObject> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordAgePolicy();
return (this.service as ManagementService).getPasswordAgePolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordAgePolicy();
return (this.service as AdminService).getPasswordAgePolicy();
}
}
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).RemovePasswordAgePolicy().then(() => {
(this.service as ManagementService).resetPasswordAgePolicyToDefault().then(() => {
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
@@ -106,8 +109,8 @@ export class PasswordAgePolicyComponent implements OnDestroy {
public savePolicy(): void {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.ageData as PasswordAgePolicyView.AsObject).pb_default) {
(this.service as ManagementService).CreatePasswordAgePolicy(
if (this.ageData.isDefault) {
(this.service as ManagementService).addCustomPasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).then(() => {
@@ -116,7 +119,7 @@ export class PasswordAgePolicyComponent implements OnDestroy {
this.toast.showError(error);
});
} else {
(this.service as ManagementService).UpdatePasswordAgePolicy(
(this.service as ManagementService).updateCustomPasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).then(() => {
@@ -127,7 +130,7 @@ export class PasswordAgePolicyComponent implements OnDestroy {
}
break;
case PolicyComponentServiceType.ADMIN:
(this.service as AdminService).UpdateDefaultPasswordAgePolicy(
(this.service as AdminService).updatePasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).then(() => {
@@ -141,7 +144,7 @@ export class PasswordAgePolicyComponent implements OnDestroy {
public get isDefault(): boolean {
if (this.ageData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.ageData as PasswordAgePolicyView.AsObject).pb_default;
return (this.ageData as PasswordAgePolicy.AsObject).isDefault;
} else {
return false;
}
@@ -2,14 +2,25 @@ import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DefaultPasswordComplexityPolicy } from 'src/app/proto/generated/admin_pb';
import { PasswordComplexityPolicyView } from 'src/app/proto/generated/management_pb';
import {
GetPasswordComplexityPolicyResponse as AdminGetPasswordComplexityPolicyResponse,
} from 'src/app/proto/generated/zitadel/admin_pb';
import {
GetPasswordComplexityPolicyResponse as MgmtGetPasswordComplexityPolicyResponse,
} from 'src/app/proto/generated/zitadel/management_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { CnslLinks } from '../../links/links.component';
import { IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK, ORG_IAM_POLICY_LINK, ORG_LOGIN_POLICY_LINK } from '../../policy-grid/policy-links';
import { CnslLinks } from '../../links/links.component';
import {
IAM_LABEL_LINK,
IAM_LOGIN_POLICY_LINK,
IAM_POLICY_LINK,
ORG_IAM_POLICY_LINK,
ORG_LOGIN_POLICY_LINK,
} from '../../policy-grid/policy-links';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
@@ -21,7 +32,7 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public service!: ManagementService | AdminService;
public complexityData!: PasswordComplexityPolicyView.AsObject | DefaultPasswordComplexityPolicy.AsObject;
public complexityData!: PasswordComplexityPolicy.AsObject;
private sub: Subscription = new Subscription();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
@@ -64,8 +75,8 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
this.loading = true;
this.getData().then(data => {
if (data) {
this.complexityData = data.toObject();
if (data.policy) {
this.complexityData = data.policy;
this.loading = false;
}
});
@@ -76,18 +87,18 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
}
private async getData():
Promise<PasswordComplexityPolicyView | DefaultPasswordComplexityPolicy> {
Promise<MgmtGetPasswordComplexityPolicyResponse.AsObject | AdminGetPasswordComplexityPolicyResponse.AsObject> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordComplexityPolicy();
return (this.service as ManagementService).getPasswordComplexityPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordComplexityPolicy();
return (this.service as AdminService).getPasswordComplexityPolicy();
}
}
public removePolicy(): void {
if (this.service instanceof ManagementService) {
this.service.removePasswordComplexityPolicy().then(() => {
this.service.resetPasswordComplexityPolicyToDefault().then(() => {
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.fetchData();
@@ -113,8 +124,8 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
public savePolicy(): void {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.complexityData as PasswordComplexityPolicyView.AsObject).pb_default) {
(this.service as ManagementService).CreatePasswordComplexityPolicy(
if ((this.complexityData as PasswordComplexityPolicy.AsObject).isDefault) {
(this.service as ManagementService).addCustomPasswordComplexityPolicy(
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
@@ -127,7 +138,7 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
this.toast.showError(error);
});
} else {
(this.service as ManagementService).UpdatePasswordComplexityPolicy(
(this.service as ManagementService).updateCustomPasswordComplexityPolicy(
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
@@ -141,7 +152,7 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
}
break;
case PolicyComponentServiceType.ADMIN:
(this.service as AdminService).UpdateDefaultPasswordComplexityPolicy(
(this.service as AdminService).updatePasswordComplexityPolicy(
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
@@ -158,7 +169,7 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
public get isDefault(): boolean {
if (this.complexityData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.complexityData as PasswordComplexityPolicyView.AsObject).pb_default;
return (this.complexityData as PasswordComplexityPolicy.AsObject).isDefault;
} else {
return false;
}
@@ -3,8 +3,13 @@ import { FormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DefaultPasswordLockoutPolicyView } from 'src/app/proto/generated/admin_pb';
import { PasswordLockoutPolicyView } from 'src/app/proto/generated/management_pb';
import {
GetPasswordLockoutPolicyResponse as AdminGetPasswordLockoutPolicyResponse,
} from 'src/app/proto/generated/zitadel/admin_pb';
import {
GetPasswordLockoutPolicyResponse as MgmtGetPasswordLockoutPolicyResponse,
} from 'src/app/proto/generated/zitadel/management_pb';
import { PasswordLockoutPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -22,7 +27,7 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
public lockoutForm!: FormGroup;
public lockoutData!: PasswordLockoutPolicyView.AsObject;
public lockoutData!: PasswordLockoutPolicy.AsObject;
private sub: Subscription = new Subscription();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
@@ -54,25 +59,25 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
}
private fetchData(): void {
this.getData().then(data => {
if (data) {
this.lockoutData = data.toObject() as PasswordLockoutPolicyView.AsObject;
this.getData().then(resp => {
if (resp.policy) {
this.lockoutData = resp.policy;
}
});
}
private getData(): Promise<PasswordLockoutPolicyView | DefaultPasswordLockoutPolicyView> {
private getData(): Promise<AdminGetPasswordLockoutPolicyResponse.AsObject | MgmtGetPasswordLockoutPolicyResponse.AsObject> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordLockoutPolicy();
return (this.service as ManagementService).getPasswordLockoutPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordLockoutPolicy();
return (this.service as AdminService).getPasswordLockoutPolicy();
}
}
public removePolicy(): void {
if (this.service instanceof ManagementService) {
this.service.RemovePasswordLockoutPolicy().then(() => {
this.service.resetPasswordLockoutPolicyToDefault().then(() => {
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
this.fetchData();
}).catch(error => {
@@ -96,7 +101,7 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
public savePolicy(): void {
let promise: Promise<any>;
if (this.service instanceof AdminService) {
promise = this.service.UpdateDefaultPasswordLockoutPolicy(
promise = this.service.updatePasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockoutFailure,
).then(() => {
@@ -105,8 +110,8 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
this.toast.showError(error);
});
} else {
if ((this.lockoutData as PasswordLockoutPolicyView.AsObject).pb_default) {
promise = this.service.CreatePasswordLockoutPolicy(
if ((this.lockoutData as PasswordLockoutPolicy.AsObject).isDefault) {
promise = this.service.addCustomPasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockoutFailure,
).then(() => {
@@ -115,7 +120,7 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
this.toast.showError(error);
});
} else {
promise = this.service.UpdatePasswordLockoutPolicy(
promise = this.service.updateCustomPasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockoutFailure,
).then(() => {
@@ -129,7 +134,7 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
public get isDefault(): boolean {
if (this.lockoutData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.lockoutData as PasswordLockoutPolicyView.AsObject).pb_default;
return (this.lockoutData as PasswordLockoutPolicy.AsObject).isDefault;
} else {
return false;
}
@@ -1,9 +1,8 @@
import { Component, Input, OnInit } from '@angular/core';
import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
import { PasswordComplexityPolicyView as MgmtPasswordComplexityPolicyView } from 'src/app/proto/generated/management_pb';
import { DefaultPasswordComplexityPolicyView as AdminPasswordComplexityPolicyView } from 'src/app/proto/generated/admin_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
export enum PolicyGridType {
ORG,
@@ -20,18 +19,22 @@ export class PolicyGridComponent implements OnInit {
public PolicyComponentType: any = PolicyComponentType;
public PolicyGridType: any = PolicyGridType;
public complexityPolicy!: MgmtPasswordComplexityPolicyView.AsObject | AdminPasswordComplexityPolicyView.AsObject | any;
public complexityPolicy!: PasswordComplexityPolicy.AsObject;
constructor(private mgmtService: ManagementService, private adminService: AdminService) { }
public ngOnInit(): void {
if (this.type == PolicyGridType.ORG) {
this.mgmtService.GetDefaultPasswordComplexityPolicy().then((policy) => {
this.complexityPolicy = policy.toObject();
this.mgmtService.getPasswordComplexityPolicy().then((resp) => {
if (resp.policy) {
this.complexityPolicy = resp.policy;
}
});
} else if (this.type == PolicyGridType.IAM) {
this.adminService.GetDefaultPasswordComplexityPolicy().then((policy) => {
this.complexityPolicy = policy.toObject();
this.adminService.getPasswordComplexityPolicy().then((resp) => {
if (resp.policy) {
this.complexityPolicy = resp.policy;
}
});
}
}
@@ -2,19 +2,22 @@ import { DataSource } from '@angular/cdk/collections';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators';
import { ProjectMember, ProjectMemberSearchResponse, ProjectType } from 'src/app/proto/generated/management_pb';
import { ListProjectGrantMembersResponse, ListProjectMembersResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ProjectType } from './project-members.component';
/**
* Data source for the ProjectMembers view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject> {
export class ProjectMembersDataSource extends DataSource<Member.AsObject> {
public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject;
public membersSubject: BehaviorSubject<ProjectMember.AsObject[]> = new BehaviorSubject<ProjectMember.AsObject[]>([]);
public membersSubject: BehaviorSubject<Member.AsObject[]> = new BehaviorSubject<Member.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@@ -29,21 +32,22 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
this.loadingSubject.next(true);
const promise: Promise<ProjectMemberSearchResponse> | undefined =
const promise: Promise<ListProjectMembersResponse.AsObject> | Promise<ListProjectGrantMembersResponse.AsObject> | undefined =
projectType === ProjectType.PROJECTTYPE_OWNED ?
this.mgmtService.SearchProjectMembers(projectId, pageSize, offset) :
this.mgmtService.listProjectMembers(projectId, pageSize, offset) :
projectType === ProjectType.PROJECTTYPE_GRANTED && grantId ?
this.mgmtService.SearchProjectGrantMembers(projectId,
this.mgmtService.listProjectGrantMembers(projectId,
grantId, pageSize, offset) : undefined;
if (promise) {
from(promise).pipe(
map(resp => {
const response = resp.toObject();
this.totalResult = response.totalResult;
if (response.viewTimestamp) {
this.viewTimestamp = response.viewTimestamp;
if (resp.details?.totalResult) {
this.totalResult = resp.details?.totalResult;
}
return response.resultList;
if (resp.details?.viewTimestamp) {
this.viewTimestamp = resp.details.viewTimestamp;
}
return resp.resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
@@ -59,7 +63,7 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
public connect(): Observable<ProjectMember.AsObject[]> {
public connect(): Observable<Member.AsObject[]> {
return this.membersSubject.asObservable();
}
@@ -1,14 +1,14 @@
<app-detail-layout *ngIf="project" [backRouterLink]="[ '/projects', project?.projectId]"
<app-detail-layout *ngIf="project" [backRouterLink]="[ '/projects', (projectType === ProjectType.PROJECTTYPE_OWNED) ? $any(project)?.id : (projectType === ProjectType.PROJECTTYPE_GRANTED) ? $any(project)?.projectId: '']"
title="{{projectName}} {{ 'PROJECT.MEMBER.TITLE' | translate }}"
description="{{ 'PROJECT.MEMBER.DESCRIPTION' | translate }}">
<app-members-table *ngIf="project" [dataSource]="dataSource" [memberRoleOptions]="memberRoleOptions"
(updateRoles)="updateRoles($event.member, $event.change)" [factoryLoadFunc]="changePageFactory"
(changedSelection)="selection = $event" [refreshTrigger]="changePage"
[canWrite]="['project.member.write$', 'project.member.write:'+ project.projectId] | hasRole | async"
[canDelete]="['project.member.delete$', 'project.member.delete:'+project.projectId] | hasRole | async"
[canWrite]="['project.member.write$', 'project.member.write:'+ (projectType === ProjectType.PROJECTTYPE_OWNED) ? $any(project)?.id : (projectType === ProjectType.PROJECTTYPE_GRANTED) ? $any(project)?.projectId: ''] | hasRole | async"
[canDelete]="['project.member.delete$', 'project.member.delete:'+(projectType === ProjectType.PROJECTTYPE_OWNED) ? $any(project)?.id : (projectType === ProjectType.PROJECTTYPE_GRANTED) ? $any(project)?.projectId: ''] | hasRole | async"
(deleteMember)="removeProjectMember($event)">
<ng-template appHasRole selectactions
[appHasRole]="['project.member.delete:' + project.projectId, 'project.member.delete']">
[appHasRole]="['project.member.delete:' + (projectType === ProjectType.PROJECTTYPE_OWNED) ? $any(project)?.id : (projectType === ProjectType.PROJECTTYPE_GRANTED) ? $any(project)?.projectId: '', 'project.member.delete']">
<button (click)="removeProjectMemberSelection()" color="warn"
matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}" class="del-button" mat-raised-button>
<i class="las la-trash"></i>
@@ -16,7 +16,7 @@
</button>
</ng-template>
<ng-template appHasRole writeactions
[appHasRole]="['project.member.write:'+project.projectId,'project.member.write']">
[appHasRole]="['project.member.write:'+(projectType === ProjectType.PROJECTTYPE_OWNED) ? $any(project)?.id : (projectType === ProjectType.PROJECTTYPE_GRANTED) ? $any(project)?.projectId: '','project.member.write']">
<a color="primary" (click)="openAddMember()" color="primary" mat-raised-button>
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
</a>
@@ -4,21 +4,19 @@ import { PageEvent } from '@angular/material/paginator';
import { MatSelectChange } from '@angular/material/select';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs/operators';
import {
ProjectGrantMemberView,
ProjectGrantView,
ProjectMember,
ProjectMemberView,
ProjectType,
ProjectView,
UserView,
} from 'src/app/proto/generated/management_pb';
import { Member } from 'src/app/proto/generated/zitadel/member_pb';
import { GrantedProject, Project } from 'src/app/proto/generated/zitadel/project_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { CreationType, MemberCreateDialogComponent } from '../add-member-dialog/member-create-dialog.component';
import { ProjectMembersDataSource } from './project-members-datasource';
export enum ProjectType {
PROJECTTYPE_OWNED = "OWNED",
PROJECTTYPE_GRANTED = "GRANTED"
}
@Component({
selector: 'app-project-members',
@@ -27,7 +25,7 @@ import { ProjectMembersDataSource } from './project-members-datasource';
})
export class ProjectMembersComponent {
public INITIALPAGESIZE: number = 25;
public project!: ProjectView.AsObject | ProjectGrantView.AsObject;
public project!: Project.AsObject | GrantedProject.AsObject;
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
public grantId: string = '';
public projectName: string = '';
@@ -36,7 +34,9 @@ export class ProjectMembersComponent {
public changePageFactory!: Function;
public changePage: EventEmitter<void> = new EventEmitter();
public selection: Array<ProjectMemberView.AsObject | ProjectGrantMemberView.AsObject> = [];
public selection: Array<Member.AsObject> = [];
public ProjectType: any = ProjectType;
constructor(
private mgmtService: ManagementService,
private dialog: MatDialog,
@@ -50,43 +50,47 @@ export class ProjectMembersComponent {
this.route.params.subscribe(params => {
this.grantId = params.grantid;
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
this.mgmtService.GetProjectById(params.projectid).then(project => {
this.project = project.toObject();
this.projectName = this.project.name;
this.dataSource = new ProjectMembersDataSource(this.mgmtService);
this.dataSource.loadMembers(this.project.projectId, this.projectType, 0, this.INITIALPAGESIZE);
this.mgmtService.getProjectByID(params.projectid).then(resp => {
if (resp.project) {
this.project = resp.project;
this.projectName = this.project.name;
this.dataSource = new ProjectMembersDataSource(this.mgmtService);
this.dataSource.loadMembers(this.project.id, this.projectType, 0, this.INITIALPAGESIZE);
this.changePageFactory = (event?: PageEvent) => {
return this.dataSource.loadMembers(
this.project.projectId,
this.projectType,
event?.pageIndex ?? 0,
event?.pageSize ?? this.INITIALPAGESIZE,
this.grantId,
);
};
this.changePageFactory = (event?: PageEvent) => {
return this.dataSource.loadMembers(
(this.project as Project.AsObject).id,
this.projectType,
event?.pageIndex ?? 0,
event?.pageSize ?? this.INITIALPAGESIZE,
this.grantId,
);
};
}
});
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
this.mgmtService.GetGrantedProjectByID(params.projectid, params.grantid).then(project => {
this.project = project.toObject();
this.projectName = this.project.projectName;
this.dataSource = new ProjectMembersDataSource(this.mgmtService);
this.dataSource.loadMembers(this.project.projectId,
this.projectType,
0,
this.INITIALPAGESIZE,
this.grantId,
);
this.changePageFactory = (event?: PageEvent) => {
return this.dataSource.loadMembers(
this.project.projectId,
this.mgmtService.getGrantedProjectByID(params.projectid, params.grantid).then(resp => {
if (resp.grantedProject) {
this.project = resp.grantedProject;
this.projectName = this.project.projectName;
this.dataSource = new ProjectMembersDataSource(this.mgmtService);
this.dataSource.loadMembers(this.project.projectId,
this.projectType,
event?.pageIndex ?? 0,
event?.pageSize ?? this.INITIALPAGESIZE,
0,
this.INITIALPAGESIZE,
this.grantId,
);
};
this.changePageFactory = (event?: PageEvent) => {
return this.dataSource.loadMembers(
(this.project as GrantedProject.AsObject).projectId,
this.projectType,
event?.pageIndex ?? 0,
event?.pageSize ?? this.INITIALPAGESIZE,
this.grantId,
);
};
}
});
}
});
@@ -95,14 +99,14 @@ export class ProjectMembersComponent {
public getRoleOptions(): void {
if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
this.mgmtService.GetProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;
this.mgmtService.listProjectGrantMemberRoles().then(resp => {
this.memberRoleOptions = resp.resultList;
}).catch(error => {
this.toast.showError(error);
});
} else if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
this.mgmtService.GetProjectMemberRoles().then(resp => {
this.memberRoleOptions = resp.toObject().rolesList;
this.mgmtService.listProjectMemberRoles().then(resp => {
this.memberRoleOptions = resp.resultList;
}).catch(error => {
this.toast.showError(error);
});
@@ -112,13 +116,13 @@ export class ProjectMembersComponent {
public removeProjectMemberSelection(): void {
Promise.all(this.selection.map(member => {
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
return this.mgmtService.RemoveProjectMember(this.project.projectId, member.userId).then(() => {
return this.mgmtService.removeProjectMember((this.project as Project.AsObject).id, member.userId).then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
return this.mgmtService.RemoveProjectGrantMember(this.project.projectId, this.grantId,
return this.mgmtService.removeProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId,
member.userId).then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true);
}).catch(error => {
@@ -132,9 +136,9 @@ export class ProjectMembersComponent {
});
}
public removeProjectMember(member: ProjectMemberView.AsObject | ProjectGrantMemberView.AsObject): void {
public removeProjectMember(member: Member.AsObject | Member.AsObject): void {
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
this.mgmtService.RemoveProjectMember(this.project.projectId, member.userId).then(() => {
this.mgmtService.removeProjectMember((this.project as Project.AsObject).id, member.userId).then(() => {
setTimeout(() => {
this.changePage.emit();
}, 1000);
@@ -143,7 +147,7 @@ export class ProjectMembersComponent {
this.toast.showError(error);
});
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
this.mgmtService.RemoveProjectGrantMember(this.project.projectId, this.grantId,
this.mgmtService.removeProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId,
member.userId).then(() => {
setTimeout(() => {
this.changePage.emit();
@@ -165,16 +169,16 @@ export class ProjectMembersComponent {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
const users: UserView.AsObject[] = resp.users;
const users: User.AsObject[] = resp.users;
const roles: string[] = resp.roles;
if (users && users.length && roles && roles.length) {
Promise.all(users.map(user => {
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
return this.mgmtService.AddProjectMember(this.project.projectId, user.id, roles);
return this.mgmtService.addProjectMember((this.project as Project.AsObject).id, user.id, roles);
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
return this.mgmtService.AddProjectGrantMember(this.project.projectId, this.grantId,
return this.mgmtService.addProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId,
user.id, roles);
}
})).then(() => {
@@ -190,18 +194,18 @@ export class ProjectMembersComponent {
});
}
updateRoles(member: ProjectMember.AsObject, selectionChange: MatSelectChange): void {
updateRoles(member: Member.AsObject, selectionChange: MatSelectChange): void {
if (this.projectType === ProjectType.PROJECTTYPE_OWNED) {
this.mgmtService.ChangeProjectMember(this.project.projectId, member.userId, selectionChange.value)
.then((_: ProjectMember) => {
this.mgmtService.updateProjectMember((this.project as Project.AsObject).id, member.userId, selectionChange.value)
.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) {
this.mgmtService.ChangeProjectGrantMember(this.project.projectId,
this.mgmtService.updateProjectGrantMember((this.project as GrantedProject.AsObject).projectId,
this.grantId, member.userId, selectionChange.value)
.then((_: ProjectMember) => {
.then(() => {
this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true);
}).catch(error => {
this.toast.showError(error);
@@ -29,7 +29,7 @@ export class ProjectRoleDetailComponent {
submitForm(): void {
if (this.formGroup.valid && this.key?.value && this.group?.value && this.displayName?.value) {
this.mgmtService.ChangeProjectRole(this.projectId, this.key.value, this.displayName.value, this.group.value)
this.mgmtService.updateProjectRole(this.projectId, this.key.value, this.displayName.value, this.group.value)
.then(() => {
this.toast.showInfo('PROJECT.TOAST.ROLECHANGED', true);
this.dialogRef.close(true);
@@ -2,7 +2,7 @@ import { DataSource } from '@angular/cdk/collections';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators';
import { ProjectRole } from 'src/app/proto/generated/management_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
/**
@@ -10,11 +10,11 @@ import { ManagementService } from 'src/app/services/mgmt.service';
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
export class ProjectRolesDataSource extends DataSource<ProjectRole.AsObject> {
export class ProjectRolesDataSource extends DataSource<Role.AsObject> {
public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject;
public rolesSubject: BehaviorSubject<ProjectRole.AsObject[]> = new BehaviorSubject<ProjectRole.AsObject[]>([]);
public rolesSubject: BehaviorSubject<Role.AsObject[]> = new BehaviorSubject<Role.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@@ -26,14 +26,15 @@ export class ProjectRolesDataSource extends DataSource<ProjectRole.AsObject> {
const offset = pageIndex * pageSize;
this.loadingSubject.next(true);
from(this.mgmtService.SearchProjectRoles(projectId, pageSize, offset)).pipe(
from(this.mgmtService.listProjectRoles(projectId, pageSize, offset)).pipe(
map(resp => {
const response = resp.toObject();
this.totalResult = response.totalResult;
if (response.viewTimestamp) {
this.viewTimestamp = response.viewTimestamp;
if (resp.details?.totalResult !== undefined) {
this.totalResult = resp.details.totalResult;
}
return resp.toObject().resultList;
if (resp.details?.viewTimestamp) {
this.viewTimestamp = resp.details.viewTimestamp;
}
return resp.resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
@@ -48,7 +49,7 @@ export class ProjectRolesDataSource extends DataSource<ProjectRole.AsObject> {
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
public connect(): Observable<ProjectRole.AsObject[]> {
public connect(): Observable<Role.AsObject[]> {
return this.rolesSubject.asObservable();
}
@@ -4,7 +4,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatTable } from '@angular/material/table';
import { tap } from 'rxjs/operators';
import { ProjectRole } from 'src/app/proto/generated/management_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -22,10 +22,10 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
@Input() public disabled: boolean = false;
@Input() public actionsVisible: boolean = false;
@ViewChild(MatPaginator) public paginator!: MatPaginator;
@ViewChild(MatTable) public table!: MatTable<ProjectRole.AsObject>;
@ViewChild(MatTable) public table!: MatTable<Role.AsObject>;
public dataSource!: ProjectRolesDataSource;
public selection: SelectionModel<ProjectRole.AsObject> = new SelectionModel<ProjectRole.AsObject>(true, []);
@Output() public changedSelection: EventEmitter<Array<ProjectRole.AsObject>> = new EventEmitter();
public selection: SelectionModel<Role.AsObject> = new SelectionModel<Role.AsObject>(true, []);
@Output() public changedSelection: EventEmitter<Array<Role.AsObject>> = new EventEmitter();
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
public displayedColumns: string[] = ['select', 'key', 'displayname', 'group', 'creationDate'];
@@ -51,7 +51,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
}
public selectAllOfGroup(group: string): void {
const groupRoles: ProjectRole.AsObject[] = this.dataSource.rolesSubject.getValue()
const groupRoles: Role.AsObject[] = this.dataSource.rolesSubject.getValue()
.filter(role => role.group === group);
this.selection.select(...groupRoles);
}
@@ -73,7 +73,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
public masterToggle(): void {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.rolesSubject.value.forEach((row: ProjectRole.AsObject) => this.selection.select(row));
this.dataSource.rolesSubject.value.forEach((row: Role.AsObject) => this.selection.select(row));
}
public deleteSelectedRoles(): Promise<any> {
@@ -83,7 +83,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
});
return Promise.all(this.selection.selected.map(role => {
return this.mgmtService.RemoveProjectRole(role.projectId, role.key);
return this.mgmtService.removeProjectRole(this.projectId, role.key);
})).then(() => {
this.toast.showInfo('PROJECT.TOAST.ROLEREMOVED', true);
indexes.forEach(index => {
@@ -98,9 +98,9 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
});
}
public removeRole(role: ProjectRole.AsObject, index: number): void {
public removeRole(role: Role.AsObject, index: number): void {
this.mgmtService
.RemoveProjectRole(role.projectId, role.key)
.removeProjectRole(this.projectId, role.key)
.then(() => {
this.toast.showInfo('PROJECT.TOAST.ROLEREMOVED', true);
this.dataSource.rolesSubject.value.splice(index, 1);
@@ -111,7 +111,7 @@ export class ProjectRolesComponent implements AfterViewInit, OnInit {
});
}
public openDetailDialog(role: ProjectRole.AsObject): void {
public openDetailDialog(role: Role.AsObject): void {
this.dialog.open(ProjectRoleDetailComponent, {
data: {
role,
@@ -5,15 +5,8 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material
import { MatChipInputEvent } from '@angular/material/chips';
import { forkJoin, from, Subject } from 'rxjs';
import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators';
import {
ProjectGrantSearchResponse,
ProjectGrantView,
ProjectSearchKey,
ProjectSearchQuery,
ProjectSearchResponse,
ProjectView,
SearchMethod,
} from 'src/app/proto/generated/management_pb';
import { ListProjectGrantsResponse, ListProjectsResponse } from 'src/app/proto/generated/zitadel/management_pb';
import { GrantedProject, Project, ProjectNameQuery, ProjectQuery } from 'src/app/proto/generated/zitadel/project_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -34,18 +27,18 @@ export class SearchProjectAutocompleteComponent implements OnDestroy {
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public projects: Array<ProjectGrantView.AsObject | ProjectView.AsObject | any> = [];
public filteredProjects: Array<ProjectGrantView.AsObject | ProjectView.AsObject | any> = [];
public projects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public filteredProjects: Array<GrantedProject.AsObject | Project.AsObject | any> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public singleOutput: boolean = false;
@Input() public autocompleteType!: ProjectAutocompleteType;
@Output() public selectionChanged: EventEmitter<
ProjectGrantView.AsObject[]
| ProjectGrantView.AsObject
| ProjectView.AsObject
| ProjectView.AsObject[]
GrantedProject.AsObject[]
| GrantedProject.AsObject
| Project.AsObject
| Project.AsObject[]
> = new EventEmitter();
private unsubscribed$: Subject<void> = new Subject();
@@ -56,20 +49,20 @@ export class SearchProjectAutocompleteComponent implements OnDestroy {
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new ProjectSearchQuery();
query.setKey(ProjectSearchKey.PROJECTSEARCHKEY_PROJECT_NAME);
query.setValue(value);
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
const query = new ProjectQuery();
const nameQuery = new ProjectNameQuery();
nameQuery.setName(value);
query.setNameQuery(nameQuery);
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
return from(this.mgmtService.SearchGrantedProjects(10, 0, [query]));
return from(this.mgmtService.listGrantedProjects(10, 0, [query]));
case ProjectAutocompleteType.PROJECT_OWNED:
return from(this.mgmtService.SearchProjects(10, 0, [query]));
return from(this.mgmtService.listProjects(10, 0, [query]));
default:
return forkJoin([
from(this.mgmtService.SearchGrantedProjects(10, 0, [query])),
from(this.mgmtService.SearchProjects(10, 0, [query])),
from(this.mgmtService.listGrantedProjects(10, 0, [query])),
from(this.mgmtService.listProjects(10, 0, [query])),
]);
}
}),
@@ -77,19 +70,19 @@ export class SearchProjectAutocompleteComponent implements OnDestroy {
switch (this.autocompleteType) {
case ProjectAutocompleteType.PROJECT_GRANTED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ProjectGrantSearchResponse).toObject().resultList];
this.filteredProjects = [...(returnValue as ListProjectGrantsResponse.AsObject).resultList];
break;
case ProjectAutocompleteType.PROJECT_OWNED:
this.isLoading = false;
this.filteredProjects = [...(returnValue as ProjectSearchResponse).toObject().resultList];
this.filteredProjects = [...(returnValue as ListProjectsResponse.AsObject).resultList];
break;
default:
this.isLoading = false;
this.filteredProjects = [
...(returnValue as (ProjectSearchResponse | ProjectGrantSearchResponse)[])[0]
.toObject().resultList,
...(returnValue as (ProjectSearchResponse | ProjectGrantSearchResponse)[])[1]
.toObject().resultList,
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[0]
.resultList,
...(returnValue as (ListProjectsResponse.AsObject | ListProjectGrantsResponse.AsObject)[])[1]
.resultList,
];
break;
}
@@ -133,7 +126,7 @@ export class SearchProjectAutocompleteComponent implements OnDestroy {
}
}
public remove(project: ProjectGrantView.AsObject): void {
public remove(project: GrantedProject.AsObject): void {
const index = this.projects.indexOf(project);
if (index >= 0) {
@@ -5,12 +5,7 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material
import { MatChipInputEvent } from '@angular/material/chips';
import { from, Subject } from 'rxjs';
import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators';
import {
ProjectRole,
ProjectRoleSearchKey,
ProjectRoleSearchQuery,
SearchMethod,
} from 'src/app/proto/generated/management_pb';
import { Role, RoleDisplayNameQuery, RoleQuery } from 'src/app/proto/generated/zitadel/project_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -26,14 +21,14 @@ export class SearchRolesAutocompleteComponent implements OnDestroy {
public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl();
public names: string[] = [];
public roles: Array<ProjectRole.AsObject> = [];
public filteredRoles: Array<ProjectRole.AsObject> = [];
public roles: Array<Role.AsObject> = [];
public filteredRoles: Array<Role.AsObject> = [];
public isLoading: boolean = false;
@ViewChild('nameInput') public nameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Input() public projectId: string = '';
@Input() public singleOutput: boolean = false;
@Output() public selectionChanged: EventEmitter<ProjectRole.AsObject[] | ProjectRole.AsObject> = new EventEmitter();
@Output() public selectionChanged: EventEmitter<Role.AsObject[] | Role.AsObject> = new EventEmitter();
private unsubscribed$: Subject<void> = new Subject();
constructor(private mgmtService: ManagementService) {
@@ -43,15 +38,21 @@ export class SearchRolesAutocompleteComponent implements OnDestroy {
debounceTime(200),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new ProjectRoleSearchQuery();
query.setKey(ProjectRoleSearchKey.PROJECTROLESEARCHKEY_DISPLAY_NAME);
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
query.setValue(value);
return from(this.mgmtService.SearchProjectRoles(this.projectId, 10, 0, [query]));
const query = new RoleQuery();
// const key = new RoleKeyQuery();
// key.setKey(key)
// query.setKey(key)
const dQuery = new RoleDisplayNameQuery();
dQuery.setDisplayName(value);
query.setDisplayNameQuery(dQuery);
return from(this.mgmtService.listProjectRoles(this.projectId, 10, 0, [query]));
}),
).subscribe((roles) => {
).subscribe((resp) => {
this.isLoading = false;
this.filteredRoles = roles.toObject().resultList;
this.filteredRoles = resp.resultList;
}, error => {
this.isLoading = false;
});
@@ -61,7 +62,7 @@ export class SearchRolesAutocompleteComponent implements OnDestroy {
this.unsubscribed$.next();
}
public displayFn(project?: ProjectRole.AsObject): string | undefined {
public displayFn(project?: Role.AsObject): string | undefined {
return project ? `${project.displayName}` : undefined;
}
@@ -91,7 +92,7 @@ export class SearchRolesAutocompleteComponent implements OnDestroy {
}
}
public remove(role: ProjectRole.AsObject): void {
public remove(role: Role.AsObject): void {
const index = this.roles.indexOf(role);
if (index >= 0) {
@@ -15,7 +15,8 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material
import { MatChipInputEvent } from '@angular/material/chips';
import { from, of, Subject } from 'rxjs';
import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators';
import { SearchMethod, UserSearchKey, UserSearchQuery, UserView } from 'src/app/proto/generated/management_pb';
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
import { SearchQuery, User, UserNameQuery } from 'src/app/proto/generated/zitadel/user_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -39,15 +40,15 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
public globalLoginNameControl: FormControl = new FormControl();
public loginNames: string[] = [];
@Input() public users: Array<UserView.AsObject> = [];
public filteredUsers: Array<UserView.AsObject> = [];
@Input() public users: Array<User.AsObject> = [];
public filteredUsers: Array<User.AsObject> = [];
public isLoading: boolean = false;
@Input() public target: UserTarget = UserTarget.SELF;
public hint: string = '';
public UserTarget: any = UserTarget;
@ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Output() public selectionChanged: EventEmitter<UserView.AsObject | UserView.AsObject[]> = new EventEmitter();
@Output() public selectionChanged: EventEmitter<User.AsObject | User.AsObject[]> = new EventEmitter();
@Input() public singleOutput: boolean = false;
private unsubscribed$: Subject<void> = new Subject();
@@ -71,14 +72,15 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
takeUntil(this.unsubscribed$),
tap(() => this.isLoading = true),
switchMap(value => {
const query = new UserSearchQuery();
query.setKey(UserSearchKey.USERSEARCHKEY_USER_NAME);
query.setValue(value);
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
const query = new SearchQuery();
const unQuery = new UserNameQuery();
unQuery.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setUserNameQuery(value);
if (this.target === UserTarget.SELF) {
return from(this.userService.SearchUsers(10, 0, [query]));
return from(this.userService.listUsers(10, 0, [query]));
} else {
return of(); // from(this.userService.GetUserByEmailGlobal(value));
return of();
}
}),
).subscribe((userresp: any) => {
@@ -89,7 +91,7 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
});
}
public displayFn(user?: UserView.AsObject): string | undefined {
public displayFn(user?: User.AsObject): string | undefined {
return user ? `${user.preferredLoginName}` : undefined;
}
@@ -119,7 +121,7 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
}
}
public remove(user: UserView.AsObject): void {
public remove(user: User.AsObject): void {
const index = this.users.indexOf(user);
if (index >= 0) {
@@ -163,12 +165,12 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec
}
public getGlobalUser(): void {
this.userService.GetUserByLoginNameGlobal(this.globalLoginNameControl.value).then(user => {
if (this.singleOutput) {
this.users = [user.toObject()];
this.userService.getUserByLoginNameGlobal(this.globalLoginNameControl.value).then(resp => {
if (this.singleOutput && resp.user) {
this.users = [resp.user];
this.selectionChanged.emit(this.users[0]);
} else {
this.users.push(user.toObject());
} else if (resp.user) {
this.users.push(resp.user);
this.selectionChanged.emit(this.users);
}
}).catch(error => {
@@ -1,23 +1,22 @@
<span class="title" mat-dialog-title>{{'USER.MACHINE.ADDED.TITLE' | translate}}</span>
<div mat-dialog-content>
<p class="desc"> {{'USER.MACHINE.ADDED.DESCRIPTION' | translate}}</p>
<ng-container *ngIf="addedKey">
<ng-container *ngIf="keyResponse">
<div class="row">
<p class="left">{{'USER.MACHINE.ID' | translate}}</p>
<p class="right">{{addedKey?.id}}</p>
</div>
<div class="row">
<p class="left">{{'USER.MACHINE.TYPE' | translate}}</p>
<p class="right">{{'USER.MACHINE.KEYTYPES.'+addedKey?.type | translate}}</p>
<p class="right">{{keyResponse?.keyId}}</p>
</div>
<div class="row">
<p class="left">{{'USER.MACHINE.CREATIONDATE' | translate}}</p>
<p class="right">{{addedKey?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm' }}
<p class="right">{{keyResponse?.details?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY,
HH:mm' }}
</p>
</div>
<div class="row">
<p class="left">{{'USER.MACHINE.EXPIRATIONDATE' | translate}}</p>
<p class="right">{{addedKey?.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY, HH:mm'}}
<p class="right">{{keyResponse?.details.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM YYYY,
HH:mm'}}
</p>
</div>
<button class="download-button" mat-stroked-button color="primary" (click)="saveFile()">Download</button>
@@ -1,7 +1,7 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { saveAs } from 'file-saver';
import { AddMachineKeyResponse } from 'src/app/proto/generated/management_pb';
import { AddMachineKeyResponse } from 'src/app/proto/generated/zitadel/management_pb';
@Component({
selector: 'app-show-key-dialog',
@@ -9,19 +9,19 @@ import { AddMachineKeyResponse } from 'src/app/proto/generated/management_pb';
styleUrls: ['./show-key-dialog.component.scss'],
})
export class ShowKeyDialogComponent {
public addedKey!: AddMachineKeyResponse.AsObject;
public keyResponse!: AddMachineKeyResponse.AsObject;
constructor(
public dialogRef: MatDialogRef<ShowKeyDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {
this.addedKey = data.key;
this.keyResponse = data.key;
}
public saveFile(): void {
const json = atob(this.addedKey.keyDetails.toString());
const json = atob(this.keyResponse.keyDetails.toString());
const blob = new Blob([json], { type: 'text/plain;charset=utf-8' });
saveAs(blob, `${this.addedKey.id}.json`);
saveAs(blob, `${this.keyResponse.keyId}.json`);
}
public closeDialog(): void {
@@ -2,14 +2,14 @@ import { DataSource } from '@angular/cdk/collections';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators';
import { ListUserGrantResponse } from 'src/app/proto/generated/zitadel/management_pb';
import {
SearchMethod,
UserGrant,
UserGrantSearchKey,
UserGrantSearchQuery,
UserGrantSearchResponse,
UserGrantView,
} from 'src/app/proto/generated/management_pb';
UserGrantProjectGrantIDQuery,
UserGrantProjectIDQuery,
UserGrantQuery,
UserGrantUserIDQuery,
} from 'src/app/proto/generated/zitadel/user_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
export enum UserGrantContext {
@@ -23,7 +23,7 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
public totalResult: number = 0;
public viewTimestamp!: Timestamp.AsObject;
public grantsSubject: BehaviorSubject<UserGrantView.AsObject[]> = new BehaviorSubject<UserGrantView.AsObject[]>([]);
public grantsSubject: BehaviorSubject<UserGrant.AsObject[]> = new BehaviorSubject<UserGrant.AsObject[]>([]);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@@ -40,40 +40,44 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
grantId?: string;
userId?: string;
},
queries?: UserGrantSearchQuery[],
queries?: UserGrantQuery[],
): void {
switch (context) {
case UserGrantContext.USER:
if (data && data.userId) {
this.loadingSubject.next(true);
const userfilter = new UserGrantSearchQuery();
userfilter.setKey(UserGrantSearchKey.USERGRANTSEARCHKEY_USER_ID);
userfilter.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
userfilter.setValue(data.userId);
const userfilter = new UserGrantQuery();
const ugUiq = new UserGrantUserIDQuery();
ugUiq.setUserId(data.userId);
userfilter.setUserIdQuery(ugUiq);
if (queries) {
queries.push(userfilter);
} else {
queries = [userfilter];
}
const promise = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, queries);
const promise = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
this.loadResponse(promise);
}
break;
case UserGrantContext.OWNED_PROJECT:
if (data && data.projectId) {
this.loadingSubject.next(true);
const projectfilter = new UserGrantSearchQuery();
projectfilter.setKey(UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID);
projectfilter.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
projectfilter.setValue(data.projectId);
const projectfilter = new UserGrantQuery();
const ugPfq = new UserGrantProjectIDQuery();
ugPfq.setProjectId(data.projectId);
projectfilter.setProjectIdQuery(ugPfq);
if (queries) {
queries.push(projectfilter);
} else {
queries = [projectfilter];
}
const promise1 = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, queries);
const promise1 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
this.loadResponse(promise1);
}
break;
@@ -81,43 +85,45 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
if (data && data.grantId && data.projectId) {
this.loadingSubject.next(true);
const grantquery: UserGrantSearchQuery = new UserGrantSearchQuery();
grantquery.setKey(UserGrantSearchKey.USERGRANTSEARCHKEY_GRANT_ID);
grantquery.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
grantquery.setValue(data.grantId);
const grantfilter = new UserGrantQuery();
const projectfilter = new UserGrantSearchQuery();
projectfilter.setKey(UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_ID);
projectfilter.setValue(data.projectId);
const uggiq = new UserGrantProjectGrantIDQuery();
uggiq.setProjectGrantId(data.grantId);
grantfilter.setProjectGrantIdQuery(uggiq);
const projectfilter = new UserGrantQuery();
const ugPfq = new UserGrantProjectIDQuery();
ugPfq.setProjectId(data.projectId);
projectfilter.setProjectIdQuery(ugPfq);
if (queries) {
queries.push(projectfilter);
queries.push(grantquery);
queries.push(grantfilter);
} else {
queries = [projectfilter, grantquery];
queries = [grantfilter];
}
const promise2 = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, queries);
const promise2 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries);
this.loadResponse(promise2);
}
break;
default:
this.loadingSubject.next(true);
const promise3 = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, queries ?? []);
const promise3 = this.userService.listUserGrants(pageSize, pageSize * pageIndex, queries ?? []);
this.loadResponse(promise3);
break;
}
}
private loadResponse(promise: Promise<UserGrantSearchResponse>): void {
private loadResponse(promise: Promise<ListUserGrantResponse.AsObject>): void {
from(promise).pipe(
map(resp => {
const response = resp.toObject();
this.totalResult = response.totalResult;
if (response.viewTimestamp) {
this.viewTimestamp = response.viewTimestamp;
if (resp.details?.totalResult) {
this.totalResult = resp.details.totalResult;
}
return response.resultList;
if (resp.details?.viewTimestamp) {
this.viewTimestamp = resp.details.viewTimestamp;
}
return resp.resultList;
}),
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
@@ -132,7 +138,7 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
public connect(): Observable<UserGrantView.AsObject[]> {
public connect(): Observable<UserGrant.AsObject[]> {
return this.grantsSubject.asObservable();
}
@@ -1,9 +1,9 @@
<app-refresh-table [loading]="dataSource?.loading$ | async" (refreshed)="changePage()"
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [timestamp]="dataSource?.viewTimestamp"
[dataSize]="dataSource?.totalResult" [selection]="selection">
<cnsl-form-field @appearfade *ngIf="userGrantSearchKey != undefined" actions class="filtername">
<cnsl-form-field @appearfade *ngIf="userGrantListSearchKey != undefined" actions class="filtername">
<input cnslInput (keyup)="applyFilter($event)"
[placeholder]="('USER.TABLE.FILTER.' + userGrantSearchKey.toString()) | translate" #input>
[placeholder]="('USER.TABLE.FILTER.' + userGrantListSearchKey.toString()) | translate" #input>
</cnsl-form-field>
<button color="warn" matTooltip="{{'GRANTS.DELETE' | translate}}" class="icon-button" mat-icon-button actions
@@ -40,7 +40,7 @@
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.USER' | translate }}
<template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_DISPLAY_NAME}"></template>
[ngTemplateOutletContext]="{key: UserGrantListSearchKey.DISPLAY_NAME}"></template>
</th>
<td mat-cell *matCellDef="let grant">
{{grant?.displayName}}</td>
@@ -49,7 +49,7 @@
<ng-container matColumnDef="org">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }}
<template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_ORG_NAME}"></template>
[ngTemplateOutletContext]="{key: UserGrantListSearchKey.ORG_NAME}"></template>
</th>
<td mat-cell *matCellDef="let grant">
{{grant.orgName}} </td>
@@ -58,7 +58,7 @@
<ng-container matColumnDef="projectId">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.PROJECTNAME' | translate }}
<template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_NAME}"></template>
[ngTemplateOutletContext]="{key: UserGrantListSearchKey.PROJECT_NAME}"></template>
</th>
<td mat-cell *matCellDef="let grant">
{{grant.projectName}} </td>
@@ -82,7 +82,7 @@
<th mat-header-cell *matHeaderCellDef class="role-data">
{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}
<template [ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_ROLE_KEY}"></template>
[ngTemplateOutletContext]="{key: UserGrantListSearchKey.ROLE_KEY}"></template>
</th>
<td mat-cell *matCellDef="let grant; let i = index" class="role-data">
<ng-container
@@ -161,7 +161,7 @@
<ng-template #templateRef let-key="key">
<button class="search-button" mat-icon-button (click)="setFilter(key)">
<mat-icon class="icon" *ngIf="this.userGrantSearchKey != key">search</mat-icon>
<mat-icon class="icon" *ngIf="this.userGrantSearchKey == key">search_off</mat-icon>
<mat-icon class="icon" *ngIf="this.userGrantListSearchKey != key">search</mat-icon>
<mat-icon class="icon" *ngIf="this.userGrantListSearchKey == key">search_off</mat-icon>
</button>
</ng-template>
@@ -6,19 +6,27 @@ import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table';
import { tap } from 'rxjs/operators';
import { enterAnimations } from 'src/app/animations';
import { TextQueryMethod } from 'src/app/proto/generated/zitadel/object_pb';
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
import {
ProjectRoleView,
SearchMethod,
UserGrant,
UserGrantSearchKey,
UserGrantSearchQuery,
UserGrantView,
} from 'src/app/proto/generated/management_pb';
UserGrantDisplayNameQuery,
UserGrantOrgNameQuery,
UserGrantProjectNameQuery,
UserGrantQuery,
UserGrantRoleKeyQuery,
} from 'src/app/proto/generated/zitadel/user_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource';
export enum UserGrantListSearchKey {
DISPLAY_NAME,
ORG_NAME,
PROJECT_NAME,
ROLE_KEY,
}
@Component({
selector: 'app-user-grants',
templateUrl: './user-grants.component.html',
@@ -28,17 +36,17 @@ import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource
],
})
export class UserGrantsComponent implements OnInit, AfterViewInit {
public userGrantSearchKey: UserGrantSearchKey | undefined = undefined;
public UserGrantSearchKey: any = UserGrantSearchKey;
public userGrantListSearchKey: UserGrantListSearchKey | undefined = undefined;
public UserGrantListSearchKey: any = UserGrantListSearchKey;
public INITIAL_PAGE_SIZE: number = 50;
@Input() context: UserGrantContext = UserGrantContext.NONE;
@Input() refreshOnPreviousRoutes: string[] = [];
public dataSource!: UserGrantsDataSource;
public selection: SelectionModel<UserGrantView.AsObject> = new SelectionModel<UserGrantView.AsObject>(true, []);
public selection: SelectionModel<UserGrant.AsObject> = new SelectionModel<UserGrant.AsObject>(true, []);
@ViewChild(MatPaginator) public paginator!: MatPaginator;
@ViewChild(MatTable) public table!: MatTable<UserGrantView.AsObject>;
@ViewChild(MatTable) public table!: MatTable<UserGrant.AsObject>;
@Input() disableWrite: boolean = false;
@Input() disableDelete: boolean = false;
@@ -49,7 +57,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
@ViewChild('input') public filter!: MatInput;
public grantRoleOptions: string[] = [];
public projectRoleOptions: ProjectRoleView.AsObject[] = [];
public projectRoleOptions: Role.AsObject[] = [];
public routerLink: any = [''];
public loadedGrantId: string = '';
@@ -106,12 +114,36 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
private loadGrantsPage(filterValue?: string): void {
let queries: UserGrantSearchQuery[] = [];
if (this.userGrantSearchKey !== undefined && filterValue) {
const query = new UserGrantSearchQuery();
query.setKey(this.userGrantSearchKey);
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
query.setValue(filterValue);
let queries: UserGrantQuery[] = [];
if (this.userGrantListSearchKey !== undefined && filterValue) {
const query = new UserGrantQuery();
switch (this.userGrantListSearchKey) {
case UserGrantListSearchKey.DISPLAY_NAME:
const ugDnQ = new UserGrantDisplayNameQuery();
ugDnQ.setDisplayName(filterValue);
ugDnQ.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setDisplayNameQuery(ugDnQ);
break;
case UserGrantListSearchKey.ORG_NAME:
const ugOnQ = new UserGrantOrgNameQuery();
ugOnQ.setOrgName(filterValue);
ugOnQ.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setOrgNameQuery(ugOnQ);
break;
case UserGrantListSearchKey.PROJECT_NAME:
const ugPnQ = new UserGrantProjectNameQuery();
ugPnQ.setProjectName(filterValue);
ugPnQ.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setProjectNameQuery(ugPnQ);
break;
case UserGrantListSearchKey.ROLE_KEY:
const ugRkQ = new UserGrantRoleKeyQuery();
ugRkQ.setRoleKey(filterValue);
ugRkQ.setMethod(TextQueryMethod.TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE);
query.setRoleKeyQuery(ugRkQ);
break;
}
queries = [query];
}
@@ -140,8 +172,8 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.dataSource.grantsSubject.value.forEach(row => this.selection.select(row));
}
public loadGrantOptions(grant: UserGrantView.AsObject): void {
this.grantToEdit = grant.id;
public loadGrantOptions(grant: UserGrant.AsObject): void {
this.grantToEdit = grant.grantId;
if (grant.grantId && grant.projectId) {
this.getGrantRoleOptions(grant.grantId, grant.projectId);
} else if (grant.projectId) {
@@ -150,23 +182,25 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
private getGrantRoleOptions(grantId: string, projectId: string): void {
this.mgmtService.GetGrantedProjectByID(projectId, grantId).then(resp => {
this.loadedGrantId = grantId;
this.grantRoleOptions = resp.toObject().roleKeysList;
this.mgmtService.getGrantedProjectByID(projectId, grantId).then(resp => {
if (resp.grantedProject) {
this.loadedGrantId = grantId;
this.grantRoleOptions = resp.grantedProject?.grantedRoleKeysList;
}
}).catch(error => {
this.toast.showError(error);
});
}
private getProjectRoleOptions(projectId: string): void {
this.mgmtService.SearchProjectRoles(projectId, 100, 0).then(resp => {
this.mgmtService.listProjectRoles(projectId, 100, 0).then(resp => {
this.loadedProjectId = projectId;
this.projectRoleOptions = resp.toObject().resultList;
this.projectRoleOptions = resp.resultList;
});
}
updateRoles(grant: UserGrant.AsObject, selectionChange: MatSelectChange): void {
this.userService.UpdateUserGrant(grant.id, grant.userId, selectionChange.value)
this.userService.updateUserGrant(grant.grantId, grant.userId, selectionChange.value)
.then(() => {
this.toast.showInfo('GRANTS.TOAST.UPDATED', true);
}).catch(error => {
@@ -175,11 +209,11 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
}
deleteGrantSelection(): void {
this.userService.BulkRemoveUserGrant(this.selection.selected.map(grant => grant.id)).then(() => {
this.userService.bulkRemoveUserGrant(this.selection.selected.map(grant => grant.grantId)).then(() => {
this.toast.showInfo('GRANTS.TOAST.BULKREMOVED', true);
const data = this.dataSource.grantsSubject.getValue();
this.selection.selected.forEach((item) => {
const index = data.findIndex(i => i.id === item.id);
const index = data.findIndex(i => i.grantId === item.grantId);
if (index > -1) {
data.splice(index, 1);
this.dataSource.grantsSubject.next(data);
@@ -211,17 +245,17 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
this.loadGrantsPage(filterValue);
}
public setFilter(key: UserGrantSearchKey): void {
public setFilter(key: UserGrantListSearchKey): void {
setTimeout(() => {
if (this.filter) {
(this.filter as any).nativeElement.focus();
}
}, 100);
if (this.userGrantSearchKey !== key) {
this.userGrantSearchKey = key;
if (this.userGrantListSearchKey !== key) {
this.userGrantListSearchKey = key;
} else {
this.userGrantSearchKey = undefined;
this.userGrantListSearchKey = undefined;
this.loadGrantsPage();
}
}