diff --git a/console/src/app/app.component.html b/console/src/app/app.component.html index 36c104ab87..ced4b37c8a 100644 --- a/console/src/app/app.component.html +++ b/console/src/app/app.component.html @@ -1,5 +1,5 @@ - + diff --git a/console/src/app/modules/accounts-card/accounts-card.component.ts b/console/src/app/modules/accounts-card/accounts-card.component.ts index 932625e4ea..eb5728de5c 100644 --- a/console/src/app/modules/accounts-card/accounts-card.component.ts +++ b/console/src/app/modules/accounts-card/accounts-card.component.ts @@ -21,7 +21,9 @@ export class AccountsCardComponent implements OnInit { this.userService.getMyUserSessions().then(sessions => { this.users = sessions.toObject().userSessionsList; const index = this.users.findIndex(user => user.loginName === this.profile.preferredLoginName); - this.users.splice(index, 1); + if (index > -1) { + this.users.splice(index, 1); + } this.loadingUsers = false; }).catch(() => { diff --git a/console/src/app/modules/add-member-dialog/member-create-dialog.component.html b/console/src/app/modules/add-member-dialog/member-create-dialog.component.html index 78af0e6e34..6a53607b27 100644 --- a/console/src/app/modules/add-member-dialog/member-create-dialog.component.html +++ b/console/src/app/modules/add-member-dialog/member-create-dialog.component.html @@ -9,8 +9,9 @@ {{ 'MEMBER.CREATIONTYPE' | translate }} - - {{ 'MEMBER.CREATIONTYPES.'+type | translate}} + + {{ 'MEMBER.CREATIONTYPES.'+type.type | translate}} diff --git a/console/src/app/modules/add-member-dialog/member-create-dialog.component.ts b/console/src/app/modules/add-member-dialog/member-create-dialog.component.ts index 615358307d..5d41429284 100644 --- a/console/src/app/modules/add-member-dialog/member-create-dialog.component.ts +++ b/console/src/app/modules/add-member-dialog/member-create-dialog.component.ts @@ -1,7 +1,9 @@ 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 { AdminService } from 'src/app/services/admin.service'; +import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -24,11 +26,17 @@ export class MemberCreateDialogComponent { public preselectedUsers: Array = []; public creationType!: CreationType; - public creationTypes: CreationType[] = [ - CreationType.IAM, - CreationType.ORG, - CreationType.PROJECT_OWNED, - CreationType.PROJECT_GRANTED, + + /** + * Specifies options for creating members, + * without ending $, to enable write event permission even if user is allowed + * to create members for only one specific project. + */ + public creationTypes: Array<{ type: CreationType, disabled$: Observable; }> = [ + { type: CreationType.IAM, disabled$: this.authService.isAllowed(['iam.member.write$']) }, + { type: CreationType.ORG, disabled$: this.authService.isAllowed(['org.member.write$']) }, + { 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 = []; public roles: Array | string[] = []; @@ -40,6 +48,7 @@ export class MemberCreateDialogComponent { constructor( private mgmtService: ManagementService, private adminService: AdminService, + private authService: GrpcAuthService, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, private toastService: ToastService, diff --git a/console/src/app/modules/members-table/members-table.component.html b/console/src/app/modules/members-table/members-table.component.html index e371dd64a2..cd85a13f20 100644 --- a/console/src/app/modules/members-table/members-table.component.html +++ b/console/src/app/modules/members-table/members-table.component.html @@ -13,13 +13,13 @@ - - @@ -77,7 +77,7 @@ {{ 'ROLESLABEL' | translate }} - {{ role }} diff --git a/console/src/app/modules/members-table/members-table.component.ts b/console/src/app/modules/members-table/members-table.component.ts index 5d61d82b42..1e70dd3a0f 100644 --- a/console/src/app/modules/members-table/members-table.component.ts +++ b/console/src/app/modules/members-table/members-table.component.ts @@ -22,8 +22,8 @@ type MemberDatasource = OrgMembersDataSource | ProjectMembersDataSource | IamMem }) export class MembersTableComponent implements OnInit, OnDestroy { public INITIALPAGESIZE: number = 25; - @Input() public disableWrite: boolean = false; @Input() public canDelete: boolean = false; + @Input() public canWrite: boolean = false; @ViewChild(MatPaginator) public paginator!: MatPaginator; @ViewChild(MatTable) public table!: MatTable; @Input() public dataSource!: MemberDatasource; diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html index fc1a780ee5..245b8f18e6 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.html +++ b/console/src/app/modules/policies/login-policy/login-policy.component.html @@ -1,11 +1,11 @@ - - - + + --> @@ -56,7 +56,7 @@ + [disabled]="(['iam.idp.write$'] | hasRole | async) == false"> diff --git a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html index 8402e9ec17..598788a46c 100644 --- a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html +++ b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html @@ -1,6 +1,6 @@ - + {{'ORG.POLICY.DELETE' | translate}} diff --git a/console/src/app/modules/project-members/project-members.component.html b/console/src/app/modules/project-members/project-members.component.html index 5f8cce98b6..7d845b04fb 100644 --- a/console/src/app/modules/project-members/project-members.component.html +++ b/console/src/app/modules/project-members/project-members.component.html @@ -4,7 +4,8 @@ diff --git a/console/src/app/modules/project-roles/project-roles.component.html b/console/src/app/modules/project-roles/project-roles.component.html index 922aa5fc0c..c1209de9cf 100644 --- a/console/src/app/modules/project-roles/project-roles.component.html +++ b/console/src/app/modules/project-roles/project-roles.component.html @@ -19,13 +19,13 @@ - - diff --git a/console/src/app/pages/iam/iam-members/iam-members.component.html b/console/src/app/pages/iam/iam-members/iam-members.component.html index 55b46e1a69..8fb9535bcf 100644 --- a/console/src/app/pages/iam/iam-members/iam-members.component.html +++ b/console/src/app/pages/iam/iam-members/iam-members.component.html @@ -4,7 +4,8 @@ + [canWrite]="['iam.member.write$'] | hasRole | async" [canDelete]="['iam.member.delete$'] | hasRole | async" + (deleteMember)="removeMember($event)"> {{org?.name}} {{'ORG_DETAIL.DESCRIPTION' | translate}} - + diff --git a/console/src/app/pages/orgs/org-members/org-members.component.html b/console/src/app/pages/orgs/org-members/org-members.component.html index 921ea9f0b0..8086cfafa8 100644 --- a/console/src/app/pages/orgs/org-members/org-members.component.html +++ b/console/src/app/pages/orgs/org-members/org-members.component.html @@ -3,8 +3,8 @@ + [canDelete]="['org.member.delete:'+org?.id,'org.member.delete$'] | hasRole | async" + [canWrite]="['org.member.write$'] | hasRole | async" (deleteMember)="removeOrgMember($event)"> diff --git a/console/src/app/pages/orgs/policy-grid/policy-grid.component.html b/console/src/app/pages/orgs/policy-grid/policy-grid.component.html index 72533ea2ff..94daf05770 100644 --- a/console/src/app/pages/orgs/policy-grid/policy-grid.component.html +++ b/console/src/app/pages/orgs/policy-grid/policy-grid.component.html @@ -22,11 +22,12 @@ - - {{'ORG.POLICY.BTN_INSTALL' | translate}} - + {{'ORG.POLICY.BTN_INSTALL' | translate}} + {{'ORG.POLICY.BTN_EDIT' | translate}} @@ -51,14 +52,14 @@ - - - {{'ORG.POLICY.BTN_INSTALL' | translate}} - {{'ORG.POLICY.BTN_EDIT' | translate}} - + + + {{'ORG.POLICY.BTN_INSTALL' | translate}} + {{'ORG.POLICY.BTN_EDIT' | translate}} @@ -81,14 +82,13 @@ - - - {{'ORG.POLICY.BTN_INSTALL' | translate}} - {{'ORG.POLICY.BTN_EDIT' | translate}} - + + {{'ORG.POLICY.BTN_INSTALL' | translate}} + {{'ORG.POLICY.BTN_EDIT' | translate}} diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html index 49645bbeef..9225d22d13 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html @@ -43,7 +43,7 @@ - {{'APP.OIDC.REGENERATESECRET' | translate}} @@ -109,7 +109,7 @@ {{ 'APP.OIDC.REDIRECT' | translate }} - + {{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }} - + - {{ 'ACTIONS.SAVE' | translate }} diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss index cf49e13705..4c9e10687d 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss @@ -86,11 +86,16 @@ } .toggle { + outline: none; align-self: flex-start; margin-bottom: 1rem; margin-right: 1rem; border-radius: .5rem; + * { + outline: none; + } + i { margin-right: 1rem; } diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts index a8cf22ce6f..fc91c387a8 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts @@ -1,13 +1,14 @@ import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes'; import { Location } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; -import { AbstractControl, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; +import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { MatChipInputEvent } from '@angular/material/chips'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; +import { take } from 'rxjs/operators'; import { Application, AppState, @@ -18,6 +19,7 @@ import { OIDCResponseType, ZitadelDocs, } from 'src/app/proto/generated/management_pb'; +import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; @@ -34,6 +36,7 @@ enum RedirectType { styleUrls: ['./app-detail.component.scss'], }) export class AppDetailComponent implements OnInit, OnDestroy { + public canWrite: boolean = false; public errorMessage: string = ''; public removable: boolean = true; public addOnBlur: boolean = true; @@ -78,8 +81,8 @@ export class AppDetailComponent implements OnInit, OnDestroy { public OIDCApplicationType: any = OIDCApplicationType; public OIDCAuthMethodType: any = OIDCAuthMethodType; - public redirectControl: FormControl = new FormControl(''); - public postRedirectControl: FormControl = new FormControl(''); + public redirectControl: FormControl = new FormControl({ value: '', disabled: true }); + public postRedirectControl: FormControl = new FormControl({ value: '', disabled: true }); constructor( @@ -90,18 +93,19 @@ export class AppDetailComponent implements OnInit, OnDestroy { private _location: Location, private dialog: MatDialog, private mgmtService: ManagementService, + private authService: GrpcAuthService, ) { this.appNameForm = this.fb.group({ - state: ['', []], - name: ['', [Validators.required]], + state: [{ value: '', disabled: true }, []], + name: [{ value: '', disabled: true }, [Validators.required]], }); this.appForm = this.fb.group({ - devMode: [false, []], + devMode: [{ value: false, disabled: true }, []], clientId: [{ value: '', disabled: true }], - responseTypesList: [], - grantTypesList: [], - applicationType: [], - authMethodType: [], + responseTypesList: [{ value: [], disabled: true }], + grantTypesList: [{ value: [], disabled: true }], + applicationType: [{ value: '', disabled: true }], + authMethodType: [{ value: '', disabled: true }], }); } @@ -118,36 +122,35 @@ export class AppDetailComponent implements OnInit, OnDestroy { this.mgmtService.GetIam().then(iam => { this.isZitadel = iam.toObject().iamProjectId === this.projectId; }); + this.authService.isAllowed(['project.app.write$', 'project.app.write:' + id]).pipe(take(1)).subscribe((allowed) => { + this.canWrite = allowed; + this.mgmtService.GetApplicationById(projectid, id).then(app => { + this.app = app.toObject(); + this.appNameForm.patchValue(this.app); + if (allowed) { + this.appNameForm.enable(); + this.appForm.enable(); + this.redirectControl.enable(); + this.postRedirectControl.enable(); + } - this.mgmtService.GetApplicationById(projectid, id).then(app => { - this.app = app.toObject(); - this.appNameForm.patchValue(this.app); - - if (this.app.state !== AppState.APPSTATE_ACTIVE) { - this.appNameForm.controls['name'].disable(); - this.appForm.disable(); - } else { - this.appNameForm.controls['name'].enable(); - this.appForm.enable(); - } - if (this.app.oidcConfig?.redirectUrisList) { - this.redirectUrisList = this.app.oidcConfig.redirectUrisList; - - // this.redirectControl = new FormControl('', [nativeValidator as ValidatorFn]); - } - if (this.app.oidcConfig?.postLogoutRedirectUrisList) { - this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList; - // this.postRedirectControl = new FormControl('', [nativeValidator as ValidatorFn]); - } - if (this.app.oidcConfig) { - this.appForm.patchValue(this.app.oidcConfig); - } - }).catch(error => { - console.error(error); - this.toast.showError(error); - this.errorMessage = error.message; + if (this.app.oidcConfig?.redirectUrisList) { + this.redirectUrisList = this.app.oidcConfig.redirectUrisList; + } + if (this.app.oidcConfig?.postLogoutRedirectUrisList) { + this.postLogoutRedirectUrisList = this.app.oidcConfig.postLogoutRedirectUrisList; + } + if (this.app.oidcConfig) { + this.appForm.patchValue(this.app.oidcConfig); + } + }).catch(error => { + console.error(error); + this.toast.showError(error); + this.errorMessage = error.message; + }); }); + this.docs = (await this.mgmtService.GetZitadelDocs()).toObject(); } @@ -160,20 +163,11 @@ export class AppDetailComponent implements OnInit, OnDestroy { }); } else if (event.value === AppState.APPSTATE_INACTIVE) { this.mgmtService.DeactivateApplication(this.projectId, this.app.id).then(() => { - this.toast.showInfo('APP.TOAST.REACTIVATED', true); + this.toast.showInfo('APP.TOAST.DEACTIVATED', true); }).catch((error: any) => { this.toast.showError(error); }); } - - if (event.value !== AppState.APPSTATE_ACTIVE) { - this.appNameForm.controls['name'].disable(); - this.appForm.disable(); - } else { - this.appNameForm.controls['name'].enable(); - this.appForm.enable(); - this.clientId?.disable(); - } } public add(event: MatChipInputEvent, target: RedirectType): void { diff --git a/console/src/app/pages/projects/granted-projects/granted-project-detail/granted-project-detail.component.html b/console/src/app/pages/projects/granted-projects/granted-project-detail/granted-project-detail.component.html index fd4cc345ef..f35cf23bbb 100644 --- a/console/src/app/pages/projects/granted-projects/granted-project-detail/granted-project-detail.component.html +++ b/console/src/app/pages/projects/granted-projects/granted-project-detail/granted-project-detail.component.html @@ -18,8 +18,8 @@ @@ -40,7 +40,7 @@ [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" - [disabled]="(['project.grant.member.write', 'project.grant.member.write:'+ project.projectId]| hasRole | async) == false"> + [disabled]="(['project.grant.member.write$', 'project.grant.member.write:'+ project.projectId]| hasRole | async) == false"> diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html index 9c5e88fc88..aa406f0fbd 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/owned-project-detail.component.html @@ -22,11 +22,11 @@ {{'PROJECT.TABLE.DEACTIVATE' | translate}} {{'PROJECT.TABLE.ACTIVATE' | translate}} @@ -69,7 +69,7 @@ @@ -79,7 +79,7 @@ @@ -90,8 +90,8 @@ description="{{'GRANTS.PROJECT.DESCRIPTION' | translate }}"> + [allowWrite]="(['user.grant.write$', 'user.grant.write:'+projectId] | hasRole) | async" + [allowDelete]="(['user.grant.delete$','user.grant.delete:'+projectId] | hasRole) | async"> @@ -113,7 +113,7 @@ [membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()" (showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" - [disabled]="(['project.member.write', 'project.member.write:'+ project.projectId]| hasRole | async) == false"> + [disabled]="(['project.member.write$', 'project.member.write:'+ project.projectId]| hasRole | async) == false"> diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/project-grants/project-grants.component.html b/console/src/app/pages/projects/owned-projects/owned-project-detail/project-grants/project-grants.component.html index 496ec019c3..1c111641aa 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/project-grants/project-grants.component.html +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/project-grants/project-grants.component.html @@ -21,13 +21,13 @@ - - diff --git a/console/src/app/pages/users/user-detail/memberships/memberships.component.html b/console/src/app/pages/users/user-detail/memberships/memberships.component.html index 31a3c666bb..095f4cca09 100644 --- a/console/src/app/pages/users/user-detail/memberships/memberships.component.html +++ b/console/src/app/pages/users/user-detail/memberships/memberships.component.html @@ -3,8 +3,7 @@ - - + - {{memberships.totalResult}} + + {{memberships.totalResult}} + + @@ -55,7 +55,7 @@ @@ -70,7 +70,7 @@ description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}"> diff --git a/console/src/app/pages/users/user-list/user-list.component.html b/console/src/app/pages/users/user-list/user-list.component.html index d8e2f77a77..4565cf8af0 100644 --- a/console/src/app/pages/users/user-list/user-list.component.html +++ b/console/src/app/pages/users/user-list/user-list.component.html @@ -3,7 +3,7 @@ {{ 'USER.PAGES.LIST' | translate }} {{ 'USER.PAGES.DESCRIPTION' | translate }} - + @@ -13,7 +13,7 @@ + [disabled]="(['user.write$'] | hasRole | async) == false"> \ No newline at end of file diff --git a/console/src/app/pages/users/user-list/user-table/user-table.component.html b/console/src/app/pages/users/user-list/user-table/user-table.component.html index f07927cd33..4a0572e96f 100644 --- a/console/src/app/pages/users/user-list/user-table/user-table.component.html +++ b/console/src/app/pages/users/user-list/user-table/user-table.component.html @@ -26,13 +26,13 @@ - -
{{'ORG_DETAIL.DESCRIPTION' | translate}}
{{ 'USER.PAGES.DESCRIPTION' | translate }}