Skip to content

Commit 48f433e

Browse files
committed
feat(admin): display also indirect managers
* Under the group on the managers page there is now available to optionally display also indirect managers of this group.
1 parent f9b66c0 commit 48f433e

File tree

6 files changed

+100
-30
lines changed

6 files changed

+100
-30
lines changed

apps/admin-gui/src/app/shared/components/managers-page/managers-page.component.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ <h1 class="page-subtitle">
3434

3535
<mat-form-field data-cy="role-filter" class="me-2 mt-2">
3636
<mat-label>{{'SHARED.COMPONENTS.MANAGERS_PAGE.SELECT_ROLE' | translate}}</mat-label>
37-
<mat-select (selectionChange)="refreshUsers()" [(value)]="selectedRole">
37+
<mat-select (selectionChange)="refreshUsers(true)" [(value)]="selectedRole">
3838
<mat-option
3939
attr.data-cy="{{role.roleName | lowercase}}"
4040
*ngFor="let role of availableRoles"
@@ -44,13 +44,22 @@ <h1 class="page-subtitle">
4444
</mat-select>
4545
</mat-form-field>
4646

47+
<mat-checkbox
48+
*ngIf="complementaryObject.beanName.includes('Group')"
49+
(change)="showIndirectAdmins = !showIndirectAdmins; refreshUsers()"
50+
[checked]="showIndirectAdmins"
51+
color="primary">
52+
{{'SHARED.COMPONENTS.MANAGERS_PAGE.SHOW_INDIRECT_ADMINS' | translate}}
53+
</mat-checkbox>
54+
4755
<ng-template #spinner>
4856
<perun-web-apps-loading-table></perun-web-apps-loading-table>
4957
</ng-template>
5058
<div class="position-relative" *ngIf="managers">
5159
<app-users-list
5260
*perunWebAppsLoader="loading; indicator: spinner"
5361
[disableSelf]="disableSelf"
62+
[directAdmins]="directAdminsIds"
5463
[tableId]="tableId"
5564
[disableRouting]="!routeAuth || disableRouting"
5665
[displayedColumns]="displayedUserColumns"

apps/admin-gui/src/app/shared/components/managers-page/managers-page.component.ts

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import { MatTabChangeEvent } from '@angular/material/tabs';
2222
import { ActivatedRoute, Router } from '@angular/router';
2323
import { ReloadEntityDetailService } from '../../../core/services/common/reload-entity-detail.service';
2424
import { AuthPrivilege } from '@perun-web-apps/perun/models';
25+
import { Observable } from 'rxjs';
26+
import { mergeMap, tap } from 'rxjs/operators';
2527

2628
@Component({
2729
selector: 'app-managers-page',
@@ -42,10 +44,13 @@ export class ManagersPageComponent implements OnInit {
4244

4345
groups: Group[] = [];
4446
managers: RichUser[] = null;
47+
managers$: Observable<Array<RichUser>> = null;
4548
selectionUsers = new SelectionModel<RichUser>(true, []);
4649
selectionGroups = new SelectionModel<Group>(true, []);
4750
selectedMode = '';
4851
selectedRole: string;
52+
showIndirectAdmins = false;
53+
directAdminsIds: number[] = null;
4954
loading = false;
5055
tableId = TABLE_GROUP_MANAGERS_PAGE;
5156
routeAuth: boolean;
@@ -124,13 +129,39 @@ export class ManagersPageComponent implements OnInit {
124129
}
125130
}
126131

127-
refreshUsers(): void {
132+
refreshUsers(refreshDirectAdmins = false): void {
128133
this.loading = true;
129134
this.changeRolePrivileges();
130135

131136
let attributes = [Urns.USER_DEF_ORGANIZATION, Urns.USER_DEF_PREFERRED_MAIL];
132137
attributes = attributes.concat(this.storeService.getLoginAttributeNames());
133-
this.authzService
138+
139+
if (this.showIndirectAdmins) {
140+
if (refreshDirectAdmins) {
141+
this.managers$ = this.getDirectAdmins(attributes).pipe(
142+
mergeMap(() => this.getIndirectAdmins(attributes))
143+
);
144+
} else {
145+
this.managers$ = this.getIndirectAdmins(attributes);
146+
}
147+
} else {
148+
this.managers$ = this.getDirectAdmins(attributes);
149+
}
150+
151+
this.managers$.subscribe({
152+
next: (managers) => {
153+
this.managers = managers;
154+
this.selectionUsers.clear();
155+
this.loading = false;
156+
},
157+
error: () => {
158+
this.loading = false;
159+
},
160+
});
161+
}
162+
163+
getDirectAdmins(attributes: string[]): Observable<Array<RichUser>> {
164+
return this.authzService
134165
.getAuthzRichAdmins(
135166
this.selectedRole,
136167
this.complementaryObject.id,
@@ -139,16 +170,19 @@ export class ManagersPageComponent implements OnInit {
139170
false,
140171
true
141172
)
142-
.subscribe({
143-
next: (managers) => {
144-
this.managers = managers;
145-
this.selectionUsers.clear();
146-
this.loading = false;
147-
},
148-
error: () => {
149-
this.loading = false;
150-
},
151-
});
173+
.pipe(tap((managers) => (this.directAdminsIds = managers.map((manager) => manager.id))));
174+
}
175+
176+
getIndirectAdmins(attributes: string[]): Observable<Array<RichUser>> {
177+
this.loading = true;
178+
return this.authzService.getAuthzRichAdmins(
179+
this.selectedRole,
180+
this.complementaryObject.id,
181+
this.complementaryObjectType,
182+
attributes,
183+
false,
184+
false
185+
);
152186
}
153187

154188
refreshGroups(): void {
@@ -187,7 +221,7 @@ export class ManagersPageComponent implements OnInit {
187221

188222
dialogRef.afterClosed().subscribe((result) => {
189223
if (result) {
190-
this.refreshUsers();
224+
this.refreshUsers(true);
191225
}
192226
});
193227
}

apps/admin-gui/src/app/shared/components/users-list/users-list.component.html

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
matSortDisableClear>
1818
<ng-container
1919
matColumnDef="select"
20-
*ngIf="{all: dataSource | isAllSelected: selection.selected.length} as selected">
20+
*ngIf="{all: dataSource | isAllSelected: selection.selected.length :canBeSelected} as selected">
2121
<th *matHeaderCellDef class="align-checkbox" mat-header-cell>
2222
<mat-checkbox
2323
(change)="$event ? masterToggle() : null"
@@ -28,16 +28,27 @@
2828
color="primary">
2929
</mat-checkbox>
3030
</th>
31-
<td *matCellDef="let row" class="static-column-size align-checkbox" mat-cell>
32-
<mat-checkbox
33-
(change)="$event ? selection.toggle(row) : null"
34-
(click)="$event.stopPropagation()"
35-
[aria-label]="selection.isSelected(row) | checkboxLabel | translate: {name: row | userFullName}"
36-
[checked]="selection.isSelected(row)"
37-
[disabled]="disableSelf && row.id === principalId && !authResolver.isPerunAdmin()"
38-
attr.data-cy="{{row.firstName | lowercase}}-checkbox"
39-
color="primary">
40-
</mat-checkbox>
31+
<td
32+
*matCellDef="let row"
33+
class="static-column-size align-checkbox"
34+
mat-cell
35+
(mouseenter)="disabledRouting = true"
36+
(mouseleave)="disabledRouting = disableRouting"
37+
[class.cursor-default]="!canBeSelected(row)">
38+
<span
39+
matTooltip="{{'MANAGERS_LIST.INDIRECT_DISABLED_TOOLTIP' | translate}}"
40+
[matTooltipPosition]="'above'"
41+
[matTooltipDisabled]="canBeSelected(row)">
42+
<mat-checkbox
43+
(change)="$event ? selection.toggle(row) : null"
44+
(click)="$event.stopPropagation()"
45+
[aria-label]="selection.isSelected(row) | checkboxLabel | translate: {name: row | userFullName}"
46+
[checked]="selection.isSelected(row)"
47+
[disabled]="disableSelf && row.id === principalId && !authResolver.isPerunAdmin() || !canBeSelected(row)"
48+
attr.data-cy="{{row.firstName | lowercase}}-checkbox"
49+
color="primary">
50+
</mat-checkbox>
51+
</span>
4152
</td>
4253
</ng-container>
4354
<ng-container matColumnDef="user">
@@ -99,8 +110,8 @@
99110
<tr
100111
*matRowDef="let user; columns: displayedColumns;"
101112
[class.cursor-pointer]="!disableRouting"
102-
[routerLink]="disableRouting ? null : (routeToAdmin ? ['/admin/users', user.id] : ['/myProfile/service-identities', user.id])"
103-
[perunWebAppsMiddleClickRouterLink]="disableRouting ? null : (routeToAdmin ? ['/admin/users', user.id] : ['/myProfile/service-identities', user.id])"
113+
[routerLink]="disableRouting || disabledRouting ? null : (routeToAdmin ? ['/admin/users', user.id] : ['/myProfile/service-identities', user.id])"
114+
[perunWebAppsMiddleClickRouterLink]="disableRouting || disabledRouting ? null : (routeToAdmin ? ['/admin/users', user.id] : ['/myProfile/service-identities', user.id])"
104115
class="dark-hover-list-item"
105116
mat-row></tr>
106117
</table>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
.cursor-pointer {
22
cursor: pointer;
33
}
4+
5+
.cursor-default {
6+
cursor: default;
7+
}

apps/admin-gui/src/app/shared/components/users-list/users-list.component.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ export class UsersListComponent implements OnChanges {
4242
noUsersFoundLabel: string;
4343
@Input()
4444
disableSelf = false;
45+
@Input() directAdmins: number[] = null;
4546

4647
svgIcon = 'perun-service-identity-black';
4748
dataSource: MatTableDataSource<RichUser>;
4849
principalId: number;
4950
pageSizeOptions = TABLE_ITEMS_COUNT_OPTIONS;
51+
disabledRouting = false;
5052
private sort: MatSort;
5153

5254
constructor(
@@ -103,6 +105,9 @@ export class UsersListComponent implements OnChanges {
103105
}
104106
}
105107

108+
canBeSelected = (row: RichUser): boolean =>
109+
this.directAdmins === null || this.directAdmins.includes(row.id);
110+
106111
exportAllData(format: string): void {
107112
downloadData(
108113
getDataForExport(
@@ -157,7 +162,11 @@ export class UsersListComponent implements OnChanges {
157162
}
158163

159164
isAllSelected(): boolean {
160-
return this.tableCheckbox.isAllSelected(this.selection.selected.length, this.dataSource);
165+
return this.tableCheckbox.isAllSelected(
166+
this.selection.selected.length,
167+
this.dataSource,
168+
this.canBeSelected
169+
);
161170
}
162171

163172
masterToggle(): void {
@@ -169,7 +178,8 @@ export class UsersListComponent implements OnChanges {
169178
this.sort,
170179
this.child.paginator.pageSize,
171180
this.child.paginator.pageIndex,
172-
false
181+
true,
182+
this.canBeSelected
173183
);
174184
}
175185
}

apps/admin-gui/src/assets/i18n/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2451,7 +2451,8 @@
24512451
"EMAIL": "Email",
24522452
"LOGINS": "Logins",
24532453
"PERSON": "Person",
2454-
"SERVICE": "Service"
2454+
"SERVICE": "Service",
2455+
"INDIRECT_DISABLED_TOOLTIP": "Indirect manager cannot be deleted"
24552456
},
24562457
"AUDIT_MESSAGES_LIST": {
24572458
"ID": "Id",
@@ -2722,6 +2723,7 @@
27222723
"REMOVE": "Remove",
27232724
"SELECT_MODE": "Select mode",
27242725
"SELECT_ROLE": "Select role",
2726+
"SHOW_INDIRECT_ADMINS": "Show also indirect managers",
27252727
"USER": "Users",
27262728
"GROUP": "Groups",
27272729
"NO_MANAGERS": "This role has no managers.",

0 commit comments

Comments
 (0)