Skip to content

Commit a4f529b

Browse files
sarkapalkovicovaxflord
authored andcommitted
feat(admin): filter groups by role
Enables filter groups by role and its assignment type on vo-groups, group-subgroups, and member-groups page.
1 parent 6f6c05a commit a4f529b

23 files changed

+452
-46
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<mat-form-field class="me-2">
2+
<mat-label>{{'SHARED.COMPONENTS.GROUP_ROLES_FILTER.FILTER_ROLES' | translate}}</mat-label>
3+
<mat-select (selectionChange)="changeRoles()" [formControl]="roles" multiple>
4+
<mat-select-trigger>
5+
{{roles.value | selectedRoleFilterValues : rolesList.length | groupRole}}
6+
</mat-select-trigger>
7+
<mat-option
8+
class="{{theme}}"
9+
*ngFor="let role of rolesList"
10+
[value]="role"
11+
>{{role | groupRole}}</mat-option
12+
>
13+
</mat-select>
14+
</mat-form-field>
15+
16+
<mat-form-field class="filter-field me-2">
17+
<mat-label>{{'SHARED.COMPONENTS.GROUP_ROLES_FILTER.FILTER_ROLE_TYPES' | translate}}</mat-label>
18+
<mat-select (selectionChange)="changeRoleTypes()" [formControl]="roleTypes" multiple>
19+
<mat-select-trigger>
20+
{{roleTypes.value | selectedRoleFilterValues : roleTypesList.length | groupRoleType}}
21+
</mat-select-trigger>
22+
<mat-option
23+
class="{{theme}}"
24+
*ngFor="let type of roleTypesList"
25+
[value]="type"
26+
>{{type | groupRoleType}}</mat-option
27+
>
28+
</mat-select>
29+
</mat-form-field>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.filter-field {
2+
max-width: 250px !important;
3+
width: 100% !important;
4+
min-width: initial !important;
5+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Component, EventEmitter, Output, Input } from '@angular/core';
2+
import { FormControl } from '@angular/forms';
3+
import { GroupAdminRoles, RoleAssignmentType } from '@perun-web-apps/perun/openapi';
4+
5+
@Component({
6+
selector: 'app-group-roles-filter',
7+
templateUrl: './group-roles-filter.component.html',
8+
styleUrls: ['./group-roles-filter.component.scss'],
9+
})
10+
export class GroupRolesFilterComponent {
11+
@Input()
12+
theme = '';
13+
@Output()
14+
filterRoles = new EventEmitter<GroupAdminRoles[]>();
15+
@Output()
16+
filterRoleTypes = new EventEmitter<RoleAssignmentType[]>();
17+
roles = new FormControl<GroupAdminRoles[]>([]);
18+
roleTypes = new FormControl<RoleAssignmentType[]>([]);
19+
rolesList: GroupAdminRoles[] = [
20+
GroupAdminRoles.GROUPADMIN,
21+
GroupAdminRoles.GROUPOBSERVER,
22+
GroupAdminRoles.GROUPMEMBERSHIPMANAGER,
23+
];
24+
roleTypesList: RoleAssignmentType[] = [RoleAssignmentType.DIRECT, RoleAssignmentType.INDIRECT];
25+
26+
changeRoleTypes(): void {
27+
this.filterRoleTypes.emit(this.roleTypes.value);
28+
}
29+
30+
changeRoles(): void {
31+
this.filterRoles.emit(this.roles.value);
32+
}
33+
}

apps/admin-gui/src/app/shared/shared.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ import { AddGroupToVoRegistrationComponent } from './components/dialogs/add-grou
191191
import { AddGroupToGroupRegistrationComponent } from './components/dialogs/add-group-to-group-registration/add-group-to-group-registration.component';
192192
import { ApplicationActionsComponent } from './components/application-actions/application-actions.component';
193193
import { ApplicationsBulkOperationDialogComponent } from './components/dialogs/applications-bulk-operation-dialog/applications-bulk-operation-dialog.component';
194+
import { GroupRolesFilterComponent } from './components/group-roles-filter/group-roles-filter.component';
194195

195196
@NgModule({
196197
imports: [
@@ -323,6 +324,7 @@ import { ApplicationsBulkOperationDialogComponent } from './components/dialogs/a
323324
AddVoBanDialogComponent,
324325
ApplicationActionsComponent,
325326
ApplicationsBulkOperationDialogComponent,
327+
GroupRolesFilterComponent,
326328
],
327329
declarations: [
328330
SideMenuComponent,
@@ -474,6 +476,7 @@ import { ApplicationsBulkOperationDialogComponent } from './components/dialogs/a
474476
AddGroupToGroupRegistrationComponent,
475477
ApplicationActionsComponent,
476478
ApplicationsBulkOperationDialogComponent,
479+
GroupRolesFilterComponent,
477480
],
478481
providers: [AnyToStringPipe, ExtSourceTypePipe, ConsentRelatedAttributePipe],
479482
})

apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ <h1 class="page-subtitle">{{'GROUP_DETAIL.SUBGROUPS.TITLE' | translate}}</h1>
2525
{{'GROUP_DETAIL.SUBGROUPS.DELETE_GROUP' | translate}}
2626
</button>
2727
</span>
28+
29+
<app-group-roles-filter
30+
[theme]="'group-theme'"
31+
(filterRoles)="applyRoles($event)"
32+
(filterRoleTypes)="applyRoleTypes($event)">
33+
</app-group-roles-filter>
34+
2835
<perun-web-apps-debounce-filter
2936
(filter)="applyFilter($event)"
3037
[placeholder]="'GROUP_DETAIL.SUBGROUPS.FILTER'">

apps/admin-gui/src/app/vos/pages/group-detail-page/group-subgroups/group-subgroups.component.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { CreateGroupDialogComponent } from '../../../../shared/components/dialog
44
import { SelectionModel } from '@angular/cdk/collections';
55
import { DeleteGroupDialogComponent } from '../../../../shared/components/dialogs/delete-group-dialog/delete-group-dialog.component';
66
import { getDefaultDialogConfig } from '@perun-web-apps/perun/utils';
7-
import { Group, GroupsManagerService } from '@perun-web-apps/perun/openapi';
7+
import {
8+
Group,
9+
GroupAdminRoles,
10+
GroupsManagerService,
11+
RoleAssignmentType,
12+
} from '@perun-web-apps/perun/openapi';
813
import { Urns } from '@perun-web-apps/perun/urns';
914
import { TABLE_GROUP_SUBGROUPS } from '@perun-web-apps/config/table-config';
1015
import { MatSlideToggle } from '@angular/material/slide-toggle';
@@ -29,6 +34,8 @@ export class GroupSubgroupsComponent implements OnInit {
2934
group: Group;
3035
groups: Group[] = [];
3136
selected = new SelectionModel<Group>(true, []);
37+
selectedRoles: GroupAdminRoles[] = [];
38+
selectedRoleTypes: RoleAssignmentType[] = [];
3239
showGroupList = false;
3340
loading: boolean;
3441
filtering = false;
@@ -120,15 +127,20 @@ export class GroupSubgroupsComponent implements OnInit {
120127
refreshTable(): void {
121128
this.loading = true;
122129
this.groupService
123-
.getAllRichSubGroupsWithGroupAttributesByNames(this.group.id, [
124-
Urns.GROUP_DEF_MAIL_FOOTER,
125-
Urns.GROUP_SYNC_ENABLED,
126-
Urns.GROUP_LAST_SYNC_STATE,
127-
Urns.GROUP_LAST_SYNC_TIMESTAMP,
128-
Urns.GROUP_STRUCTURE_SYNC_ENABLED,
129-
Urns.GROUP_LAST_STRUCTURE_SYNC_STATE,
130-
Urns.GROUP_LAST_STRUCTURE_SYNC_TIMESTAMP,
131-
])
130+
.getAllRichSubGroupsWithGroupAttributesByNames(
131+
this.group.id,
132+
[
133+
Urns.GROUP_DEF_MAIL_FOOTER,
134+
Urns.GROUP_SYNC_ENABLED,
135+
Urns.GROUP_LAST_SYNC_STATE,
136+
Urns.GROUP_LAST_SYNC_TIMESTAMP,
137+
Urns.GROUP_STRUCTURE_SYNC_ENABLED,
138+
Urns.GROUP_LAST_STRUCTURE_SYNC_STATE,
139+
Urns.GROUP_LAST_STRUCTURE_SYNC_TIMESTAMP,
140+
],
141+
this.selectedRoles,
142+
this.selectedRoleTypes
143+
)
132144
.subscribe((groups) => {
133145
this.groups = groups;
134146
this.selected.clear();
@@ -142,6 +154,16 @@ export class GroupSubgroupsComponent implements OnInit {
142154
this.filtering = filterValue !== '';
143155
}
144156

157+
applyRoles(roles: GroupAdminRoles[]): void {
158+
this.selectedRoles = roles;
159+
this.refreshTable();
160+
}
161+
162+
applyRoleTypes(types: RoleAssignmentType[]): void {
163+
this.selectedRoleTypes = types;
164+
this.refreshTable();
165+
}
166+
145167
onMoveGroup(group: GroupFlatNode | Group): void {
146168
const config = getDefaultDialogConfig();
147169
config.width = '550px';

apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,16 @@ <h1 class="page-subtitle">{{'MEMBER_DETAIL.GROUPS.TITLE' | translate}}</h1>
2121
{{'MEMBER_DETAIL.GROUPS.REMOVE' | translate}}
2222
</button>
2323
</span>
24+
25+
<app-group-roles-filter
26+
[theme]="'member-theme'"
27+
(filterRoles)="applyRoles($event)"
28+
(filterRoleTypes)="applyRoleTypes($event)">
29+
</app-group-roles-filter>
30+
2431
<perun-web-apps-debounce-filter
2532
(filter)="applyFilter($event)"
26-
[placeholder]="'SHARED_LIB.PERUN.COMPONENTS.RESOURCES_LIST.TABLE_SEARCH'">
33+
[placeholder]="'MEMBER_DETAIL.GROUPS.FILTER'">
2734
</perun-web-apps-debounce-filter>
2835
<label class="slide-label" (click)="labelToggle()">
2936
{{'MEMBER_DETAIL.GROUPS.TREE_VIEW' | translate}}

apps/admin-gui/src/app/vos/pages/member-detail-page/member-groups/member-groups.component.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { Component, HostBinding, OnInit, ViewChild } from '@angular/core';
22
import { ActivatedRoute } from '@angular/router';
33
import {
44
Group,
5+
GroupAdminRoles,
56
GroupsManagerService,
67
Member,
78
MembersManagerService,
9+
RoleAssignmentType,
810
} from '@perun-web-apps/perun/openapi';
911
import { TABLE_MEMBER_DETAIL_GROUPS } from '@perun-web-apps/config/table-config';
1012
import { SelectionModel } from '@angular/cdk/collections';
@@ -42,6 +44,8 @@ export class MemberGroupsComponent implements OnInit {
4244
tableId = TABLE_MEMBER_DETAIL_GROUPS;
4345
showGroupList = false;
4446
selection = new SelectionModel<Group>(true, []);
47+
selectedRoles: GroupAdminRoles[] = [];
48+
selectedRoleTypes: RoleAssignmentType[] = [];
4549
addAuth: boolean;
4650
routeAuth: boolean;
4751
removeAuth$: Observable<boolean> = this.selection.changed.pipe(
@@ -92,11 +96,16 @@ export class MemberGroupsComponent implements OnInit {
9296
refreshTable(): void {
9397
this.loading = true;
9498
this.groupsService
95-
.getMemberRichGroupsWithAttributesByNames(this.member.id, [
96-
Urns.MEMBER_DEF_GROUP_EXPIRATION,
97-
Urns.MEMBER_GROUP_STATUS,
98-
Urns.MEMBER_GROUP_STATUS_INDIRECT,
99-
])
99+
.getMemberRichGroupsWithAttributesByNames(
100+
this.member.id,
101+
[
102+
Urns.MEMBER_DEF_GROUP_EXPIRATION,
103+
Urns.MEMBER_GROUP_STATUS,
104+
Urns.MEMBER_GROUP_STATUS_INDIRECT,
105+
],
106+
this.selectedRoles,
107+
this.selectedRoleTypes
108+
)
100109
.subscribe({
101110
next: (groups) => {
102111
this.selection.clear();
@@ -160,6 +169,16 @@ export class MemberGroupsComponent implements OnInit {
160169
this.filtering = filterValue !== '';
161170
}
162171

172+
applyRoles(roles: GroupAdminRoles[]): void {
173+
this.selectedRoles = roles;
174+
this.refreshTable();
175+
}
176+
177+
applyRoleTypes(types: RoleAssignmentType[]): void {
178+
this.selectedRoleTypes = types;
179+
this.refreshTable();
180+
}
181+
163182
labelToggle(): void {
164183
this.showGroupList = !this.showGroupList;
165184
this.refreshTable();

apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ <h1 class="page-subtitle">{{'VO_DETAIL.GROUPS.TITLE' | translate}}</h1>
2424
{{'VO_DETAIL.GROUPS.DELETE_GROUP' | translate}}
2525
</button>
2626
</span>
27+
28+
<app-group-roles-filter
29+
[theme]="'vo-theme'"
30+
(filterRoles)="applyRoles($event)"
31+
(filterRoleTypes)="applyRoleTypes($event)">
32+
</app-group-roles-filter>
33+
2734
<perun-web-apps-debounce-filter
2835
(filter)="applyFilter($event)"
2936
[placeholder]="'VO_DETAIL.GROUPS.FILTER'">

apps/admin-gui/src/app/vos/pages/vo-detail-page/vo-groups/vo-groups.component.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import {
1111
} from '@perun-web-apps/perun/utils';
1212
import {
1313
Group,
14+
GroupAdminRoles,
1415
GroupsManagerService,
1516
GroupsOrderColumn,
1617
PaginatedRichGroups,
1718
RichGroup,
19+
RoleAssignmentType,
1820
Vo,
1921
} from '@perun-web-apps/perun/openapi';
2022
import { GroupFlatNode, GroupWithStatus, PageQuery } from '@perun-web-apps/perun/models';
@@ -50,6 +52,8 @@ export class VoGroupsComponent implements OnInit {
5052
offset: pageQuery.offset,
5153
searchString: pageQuery.searchString,
5254
sortColumn: pageQuery.sortColumn as GroupsOrderColumn,
55+
roles: this.selectedRoles,
56+
types: this.selectedRoleTypes,
5357
},
5458
})
5559
),
@@ -74,7 +78,8 @@ export class VoGroupsComponent implements OnInit {
7478
filterValue = '';
7579
tableId = TABLE_VO_GROUPS;
7680
displayedColumns = ['select', 'id', 'name', 'description', 'menu'];
77-
81+
selectedRoles: GroupAdminRoles[] = [];
82+
selectedRoleTypes: RoleAssignmentType[] = [];
7883
createAuth: boolean;
7984
routeAuth: boolean;
8085
removeAuth$: Observable<boolean> = this.selected.changed.pipe(
@@ -188,7 +193,12 @@ export class VoGroupsComponent implements OnInit {
188193

189194
loadAllGroups(): void {
190195
this.groupService
191-
.getAllRichGroupsWithAttributesByNames(this.vo.id, this.attrNames)
196+
.getAllRichGroupsWithAttributesByNames(
197+
this.vo.id,
198+
this.attrNames,
199+
this.selectedRoles,
200+
this.selectedRoleTypes
201+
)
192202
.subscribe((groups) => {
193203
this.groups = groups;
194204
this.selected.clear();
@@ -202,6 +212,16 @@ export class VoGroupsComponent implements OnInit {
202212
this.filtering = filterValue !== '';
203213
}
204214

215+
applyRoles(roles: GroupAdminRoles[]): void {
216+
this.selectedRoles = roles;
217+
this.refresh();
218+
}
219+
220+
applyRoleTypes(types: RoleAssignmentType[]): void {
221+
this.selectedRoleTypes = types;
222+
this.refresh();
223+
}
224+
205225
refresh(): void {
206226
this.loadingSubject$.next(true);
207227
if (this.showGroupList) {
@@ -227,6 +247,8 @@ export class VoGroupsComponent implements OnInit {
227247
offset: 0,
228248
searchString: query.searchString,
229249
sortColumn: query.sortColumn as GroupsOrderColumn,
250+
roles: this.selectedRoles,
251+
types: this.selectedRoleTypes,
230252
},
231253
})
232254
.subscribe({

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@
347347
"TITLE_SUBGROUPS": "Subgroups",
348348
"LIST_VIEW": "List view",
349349
"TREE_VIEW": "Tree view",
350-
"FILTER": "Filter",
350+
"FILTER": "Search by name, id, description",
351351
"NO_GROUPS": "No groups found",
352352
"GROUP_SYNCED": "Synchronized",
353353
"GROUP_NOT_SYNCED": "Not synchronized",
@@ -893,7 +893,8 @@
893893
"REMOVE": "Remove",
894894
"REMOVE_PERMISSION_HINT": "You don't have permission to remove some of the selected groups.",
895895
"LIST_VIEW": "List view",
896-
"TREE_VIEW": "Tree view"
896+
"TREE_VIEW": "Tree view",
897+
"FILTER": "Search by name, id, description"
897898
},
898899
"APPLICATIONS": {
899900
"TITLE": "Application",
@@ -2908,6 +2909,10 @@
29082909
"LOGIN_SHORT": "Login is too short",
29092910
"LOGIN_DISABLED": "To enter the login, you need to select a namespace first",
29102911
"LOGIN_DISABLED_FOR_NAMESPACE": "Logins in this namespace are generated automatically."
2912+
},
2913+
"GROUP_ROLES_FILTER": {
2914+
"FILTER_ROLES": "Filter by role",
2915+
"FILTER_ROLE_TYPES": "Filter by role assigment"
29112916
}
29122917
},
29132918
"IDENTITY_DETAIL": {

libs/perun/openapi/src/lib/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ model/genMemberDataNode.ts
9191
model/graphDTO.ts
9292
model/graphFileFormat.ts
9393
model/group.ts
94+
model/groupAdminRoles.ts
9495
model/groupMemberData.ts
9596
model/groupMemberRelation.ts
9697
model/groupResourceStatus.ts
@@ -263,6 +264,7 @@ model/richMember.ts
263264
model/richResource.ts
264265
model/richUser.ts
265266
model/richUserExtSource.ts
267+
model/roleAssignmentType.ts
266268
model/roleManagementRules.ts
267269
model/roleObject.ts
268270
model/securityTeam.ts

0 commit comments

Comments
 (0)