From 3be1f51e48c7deb09165f0321b5b2178ed0c20b9 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 11 Jan 2023 11:20:12 +0100 Subject: [PATCH] fix(console): member table updates (#4984) * fix: members table refresh, delete with single role * trigger update after change * remove event propagation handler Co-authored-by: Livio Spring --- .../members-table/members-table.component.ts | 43 +++-- .../project-members.component.ts | 177 ++++++++++-------- .../instance-members.component.ts | 11 +- .../orgs/org-members/org-members.component.ts | 23 ++- .../project-grant-detail.component.ts | 25 ++- console/src/assets/i18n/de.json | 6 + console/src/assets/i18n/en.json | 6 + console/src/assets/i18n/fr.json | 6 + console/src/assets/i18n/it.json | 6 + console/src/assets/i18n/zh.json | 6 + 10 files changed, 203 insertions(+), 106 deletions(-) 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 9f32c8cf9..1489bcea9 100644 --- a/console/src/app/modules/members-table/members-table.component.ts +++ b/console/src/app/modules/members-table/members-table.component.ts @@ -69,27 +69,32 @@ export class MembersTableComponent implements OnInit, OnDestroy { } public removeRole(member: Member.AsObject, role: string) { - const dialogRef = this.dialog.open(WarnDialogComponent, { - data: { - confirmKey: 'ACTIONS.DELETE', - cancelKey: 'ACTIONS.CANCEL', - titleKey: 'GRANTS.DIALOG.DELETE_TITLE', - descriptionKey: 'GRANTS.DIALOG.DELETE_DESCRIPTION', - }, - width: '400px', - }); + if (member.rolesList.length === 1) { + this.triggerDeleteMember(member); + } else { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.DELETE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'ROLES.DIALOG.DELETE_TITLE', + descriptionKey: 'ROLES.DIALOG.DELETE_DESCRIPTION', + }, + width: '400px', + }); - dialogRef.afterClosed().subscribe((resp) => { - if (resp) { - const newRoles = Object.assign([], member.rolesList); - const index = newRoles.findIndex((r) => r === role); - if (index > -1) { - newRoles.splice(index, 1); - member.rolesList = newRoles; - this.updateRoles.emit({ member: member, change: newRoles }); + dialogRef.afterClosed().subscribe((resp) => { + if (resp) { + const newRoles = Object.assign([], member.rolesList); + + const index = newRoles.findIndex((r) => r === role); + if (index > -1) { + newRoles.splice(index, 1); + member.rolesList = newRoles; + this.updateRoles.emit({ member: member, change: newRoles }); + } } - } - }); + }); + } } public addRole(member: Member.AsObject) { diff --git a/console/src/app/modules/project-members/project-members.component.ts b/console/src/app/modules/project-members/project-members.component.ts index b608cf170..90a7a6c94 100644 --- a/console/src/app/modules/project-members/project-members.component.ts +++ b/console/src/app/modules/project-members/project-members.component.ts @@ -23,6 +23,7 @@ export class ProjectMembersComponent { public INITIALPAGESIZE: number = 25; public project!: Project.AsObject | GrantedProject.AsObject; public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED; + public projectId: string = ''; public grantId: string = ''; public projectName: string = ''; public dataSource!: ProjectMembersDataSource; @@ -40,7 +41,7 @@ export class ProjectMembersComponent { private mgmtService: ManagementService, private dialog: MatDialog, private toast: ToastService, - breadcrumbService: BreadcrumbService, + private breadcrumbService: BreadcrumbService, private route: ActivatedRoute, ) { this.route.data.pipe(take(1)).subscribe((data) => { @@ -49,78 +50,85 @@ export class ProjectMembersComponent { this.getRoleOptions(); this.route.params.subscribe((params) => { + this.projectId = params.projectid; this.grantId = params.grantid; - if (this.projectType === ProjectType.PROJECTTYPE_OWNED) { - 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.loadMembers(); + }); + }); + } - 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, - ); - }; + public loadMembers(): Promise { + if (this.projectType === ProjectType.PROJECTTYPE_OWNED) { + return this.mgmtService.getProjectByID(this.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.mgmtService.getIAM().then((iam) => { - const isZitadel = iam.iamProjectId === (this.project as Project.AsObject).id; - const breadcrumbs = [ - new Breadcrumb({ - type: BreadcrumbType.ORG, - routerLink: ['/org'], - }), - new Breadcrumb({ - type: BreadcrumbType.PROJECT, - param: { key: 'projectid', value: (this.project as Project.AsObject).id }, - routerLink: ['/projects', (this.project as Project.AsObject).id], - isZitadel: isZitadel, - }), - ]; - breadcrumbService.setBreadcrumb(breadcrumbs); - }); - } - }); - } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { - 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, 0, 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, + ); + }; - 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, - ); - }; - - const breadcrumbs = [ - new Breadcrumb({ - type: BreadcrumbType.ORG, - routerLink: ['/org'], - }), - new Breadcrumb({ - type: BreadcrumbType.GRANTEDPROJECT, - param: { key: 'projectid', value: (this.project as GrantedProject.AsObject).projectId }, - routerLink: ['/projects', (this.project as GrantedProject.AsObject).projectId], - }), - ]; - breadcrumbService.setBreadcrumb(breadcrumbs); - } + this.mgmtService.getIAM().then((iam) => { + const isZitadel = iam.iamProjectId === (this.project as Project.AsObject).id; + const breadcrumbs = [ + new Breadcrumb({ + type: BreadcrumbType.ORG, + routerLink: ['/org'], + }), + new Breadcrumb({ + type: BreadcrumbType.PROJECT, + param: { key: 'projectid', value: (this.project as Project.AsObject).id }, + routerLink: ['/projects', (this.project as Project.AsObject).id], + isZitadel: isZitadel, + }), + ]; + this.breadcrumbService.setBreadcrumb(breadcrumbs); }); } }); - }); + } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { + return this.mgmtService.getGrantedProjectByID(this.projectId, this.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, 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, + ); + }; + + const breadcrumbs = [ + new Breadcrumb({ + type: BreadcrumbType.ORG, + routerLink: ['/org'], + }), + new Breadcrumb({ + type: BreadcrumbType.GRANTEDPROJECT, + param: { key: 'projectid', value: (this.project as GrantedProject.AsObject).projectId }, + routerLink: ['/projects', (this.project as GrantedProject.AsObject).projectId], + }), + ]; + this.breadcrumbService.setBreadcrumb(breadcrumbs); + } + }); + } else { + return Promise.reject(); + } } public getRoleOptions(): void { @@ -149,32 +157,29 @@ export class ProjectMembersComponent { Promise.all( this.selection.map((member) => { if (this.projectType === ProjectType.PROJECTTYPE_OWNED) { - 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); - }); + return this.mgmtService.removeProjectMember((this.project as Project.AsObject).id, member.userId).then(() => { + this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true); + }); } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { return this.mgmtService .removeProjectGrantMember((this.project as GrantedProject.AsObject).projectId, this.grantId, member.userId) .then(() => { this.toast.showInfo('PROJECT.TOAST.MEMBERREMOVED', true); - }) - .catch((error) => { - this.toast.showError(error); }); } else { return Promise.reject(); } }), - ).then(() => { - setTimeout(() => { + ) + .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); + }) + .catch((error) => { + this.toast.showError(error); this.changePage.emit(); - }, 1000); - }); + }); } public removeProjectMember(member: Member.AsObject | Member.AsObject): void { @@ -189,6 +194,7 @@ export class ProjectMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { this.mgmtService @@ -201,6 +207,7 @@ export class ProjectMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } } @@ -255,10 +262,14 @@ export class ProjectMembersComponent { this.mgmtService .updateProjectMember((this.project as Project.AsObject).id, member.userId, selectionChange) .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } else if (this.projectType === ProjectType.PROJECTTYPE_GRANTED) { this.mgmtService @@ -269,10 +280,14 @@ export class ProjectMembersComponent { selectionChange, ) .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); this.toast.showInfo('PROJECT.TOAST.MEMBERCHANGED', true); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } } diff --git a/console/src/app/pages/instance/instance-members/instance-members.component.ts b/console/src/app/pages/instance/instance-members/instance-members.component.ts index 3d51c74d7..2fb9755d4 100644 --- a/console/src/app/pages/instance/instance-members/instance-members.component.ts +++ b/console/src/app/pages/instance/instance-members/instance-members.component.ts @@ -66,9 +66,13 @@ export class InstanceMembersComponent { .updateIAMMember(member.userId, selectionChange) .then(() => { this.toast.showInfo('ORG.TOAST.MEMBERCHANGED', true); + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } @@ -79,10 +83,13 @@ export class InstanceMembersComponent { .removeIAMMember(member.userId) .then(() => { this.toast.showInfo('IAM.TOAST.MEMBERREMOVED', true); - this.changePage.emit(); + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); }), ); @@ -99,6 +106,7 @@ export class InstanceMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } @@ -129,6 +137,7 @@ export class InstanceMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } } diff --git a/console/src/app/pages/orgs/org-members/org-members.component.ts b/console/src/app/pages/orgs/org-members/org-members.component.ts index fd618e0e5..1c1851911 100644 --- a/console/src/app/pages/orgs/org-members/org-members.component.ts +++ b/console/src/app/pages/orgs/org-members/org-members.component.ts @@ -64,6 +64,7 @@ export class OrgMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } @@ -72,8 +73,12 @@ export class OrgMembersComponent { .updateOrgMember(member.userId, selectionChange) .then(() => { this.toast.showInfo('ORG.TOAST.MEMBERCHANGED', true); + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } @@ -85,16 +90,24 @@ export class OrgMembersComponent { .removeOrgMember(member.userId) .then(() => { this.toast.showInfo('ORG.TOAST.MEMBERREMOVED', true); + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { this.toast.showError(error); }); }), - ).then(() => { - setTimeout(() => { + ) + .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); + }) + .catch((error) => { + this.toast.showError(error); this.changePage.emit(); - }, 1000); - }); + }); } public removeOrgMember(member: Member.AsObject): void { @@ -109,6 +122,7 @@ export class OrgMembersComponent { }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } @@ -138,6 +152,7 @@ export class OrgMembersComponent { }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } diff --git a/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-detail.component.ts b/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-detail.component.ts index 13d0d10cb..402a38430 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-detail.component.ts +++ b/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-detail.component.ts @@ -112,9 +112,13 @@ export class ProjectGrantDetailComponent { .then(() => { this.toast.showInfo('PROJECT.TOAST.DEACTIVATED', true); this.grant.state = newState; + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } } @@ -141,9 +145,13 @@ export class ProjectGrantDetailComponent { .updateProjectGrant(this.grant.grantId, this.grant.projectId, selectionChange) .then(() => { this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTUPDATED', true); + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { this.toast.showError(error); + this.changePage.emit(); }); } @@ -159,6 +167,7 @@ export class ProjectGrantDetailComponent { }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); }), @@ -175,6 +184,7 @@ export class ProjectGrantDetailComponent { }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } @@ -203,9 +213,10 @@ export class ProjectGrantDetailComponent { this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERADDED', true); setTimeout(() => { this.changePage.emit(); - }, 3000); + }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } @@ -217,9 +228,13 @@ export class ProjectGrantDetailComponent { this.mgmtService .updateProjectGrantMember(this.grant.projectId, this.grant.grantId, member.userId, selectionChange) .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTMEMBERCHANGED', true); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } @@ -232,9 +247,13 @@ export class ProjectGrantDetailComponent { this.mgmtService .updateProjectGrant(this.grant.grantId, this.grant.projectId, this.grant.grantedRoleKeysList) .then(() => { + setTimeout(() => { + this.changePage.emit(); + }, 1000); this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTUPDATED', true); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } @@ -257,8 +276,12 @@ export class ProjectGrantDetailComponent { .then(() => { this.toast.showInfo('PROJECT.GRANT.TOAST.PROJECTGRANTUPDATED', true); this.grant.grantedRoleKeysList = resp.roles; + setTimeout(() => { + this.changePage.emit(); + }, 1000); }) .catch((error) => { + this.changePage.emit(); this.toast.showError(error); }); } diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index e47f93a48..2f2e80c1d 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -1484,6 +1484,12 @@ "DELETED": "Projekt gelöscht." } }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Rolle löschen", + "DELETE_DESCRIPTION": "Sie sind im Begriff eine Rolle zu entfernen. Wollen Sie fortfahren?" + } + }, "NEXTSTEPS": { "TITLE": "Nächste Schritte" }, diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 648ac5c86..27e4f28c3 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -1484,6 +1484,12 @@ "DELETED": "Project deleted." } }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Delete role", + "DELETE_DESCRIPTION": "You are about to delete a role. Are you sure?" + } + }, "NEXTSTEPS": { "TITLE": "Next Steps" }, diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index 72141ff84..461ae7b2b 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -1484,6 +1484,12 @@ "DELETED": "Projet supprimé." } }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Supprimer un rôle", + "DELETE_DESCRIPTION": "Vous êtes sur le point de supprimer un rôle. Êtes-vous sûr ?" + } + }, "NEXTSTEPS": { "TITLE": "Étapes suivantes" }, diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index 44aeee27e..685d0bbf7 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -1485,6 +1485,12 @@ "DELETED": "Progetto eliminato con successo." } }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "Elima ruolo", + "DELETE_DESCRIPTION": "Stai per eliminare un ruolo. Vuoi davvero continuare?" + } + }, "NEXTSTEPS": { "TITLE": "Passi successivi" }, diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index 5f1da216f..97aaad6c4 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -1483,6 +1483,12 @@ "DELETED": "项目已删除" } }, + "ROLES": { + "DIALOG": { + "DELETE_TITLE": "删除角色", + "DELETE_DESCRIPTION": "您即将删除一个角色。你确定吗?" + } + }, "NEXTSTEPS": { "TITLE": "下一步" },