Skip to content

Commit 193a508

Browse files
committed
feat(admin): added tree view also to member-groups page
* Member groups page was extended by tree view (previously there was just list view). * Groups-tree component was extended by group status icon and expiration functionality (expiration can be edited also from tree view).
1 parent d29bb93 commit 193a508

File tree

10 files changed

+128
-40
lines changed

10 files changed

+128
-40
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ <h1 class="page-subtitle">{{'GROUP_DETAIL.SUBGROUPS.TITLE' | translate}}</h1>
5353
[groups]="groups"
5454
(moveGroup)="onMoveGroup($event)"
5555
(refreshTable)="refreshTable()"
56+
[displayedColumns]="['nameWithId', 'description', 'menu']"
5657
[hideCheckbox]="!deleteAuth"
5758
[filterValue]="filterValue"
5859
[selection]="selected">

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

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,45 @@ <h1 class="page-subtitle">{{'MEMBER_DETAIL.GROUPS.TITLE' | translate}}</h1>
2525
(filter)="applyFilter($event)"
2626
[placeholder]="'SHARED_LIB.PERUN.COMPONENTS.RESOURCES_LIST.TABLE_SEARCH'">
2727
</perun-web-apps-debounce-filter>
28+
<label class="slide-label" (click)="labelToggle()">
29+
{{'MEMBER_DETAIL.GROUPS.TREE_VIEW' | translate}}
30+
</label>
31+
<mat-slide-toggle #toggle (change)="selection.clear()" [(ngModel)]="showGroupList" class="me-1">
32+
</mat-slide-toggle>
33+
<label class="slide-label" (click)="labelToggle()">
34+
{{'MEMBER_DETAIL.GROUPS.LIST_VIEW' | translate}}
35+
</label>
2836
<ng-template #spinner>
2937
<perun-web-apps-loading-table></perun-web-apps-loading-table>
3038
</ng-template>
3139
<div class="position-relative">
32-
<perun-web-apps-groups-list
33-
*perunWebAppsLoader="loading; indicator: spinner"
34-
(refreshTable)="refreshTable()"
35-
[displayedColumns]="['select', 'id', 'name', 'description', 'expiration', 'groupStatus']"
36-
[memberId]="memberId"
37-
[disableRouting]="!routeAuth"
38-
[groups]="groups"
39-
[filter]="filterValue"
40-
[memberGroupStatus]="member?.groupStatus"
41-
[selection]="selection"
42-
[tableId]="tableId">
43-
</perun-web-apps-groups-list>
40+
<div *ngIf="!showGroupList">
41+
<perun-web-apps-groups-tree
42+
*perunWebAppsLoader="loading; indicator: spinner"
43+
(refreshTable)="refreshTable()"
44+
(changeExpiration)="changeExpiration($event)"
45+
[expandAll]="filtering"
46+
[disableRouting]="!routeAuth"
47+
[groups]="groups"
48+
[selection]="selection"
49+
[filterValue]="filterValue"
50+
[displayedColumns]="['nameWithId', 'description', 'expiration', 'status']"
51+
theme="member-theme">
52+
</perun-web-apps-groups-tree>
53+
</div>
54+
<div [hidden]="!showGroupList">
55+
<perun-web-apps-groups-list
56+
#list
57+
*perunWebAppsLoader="loading; indicator: spinner"
58+
(refreshTable)="refreshTable()"
59+
[displayedColumns]="['select', 'id', 'name', 'description', 'expiration', 'groupStatus']"
60+
[memberId]="memberId"
61+
[disableRouting]="!routeAuth"
62+
[groups]="groups"
63+
[filter]="filterValue"
64+
[memberGroupStatus]="member?.groupStatus"
65+
[selection]="selection"
66+
[tableId]="tableId">
67+
</perun-web-apps-groups-list>
68+
</div>
4469
</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.slide-label {
2+
display: inline;
3+
cursor: pointer;
4+
}

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

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, HostBinding, OnInit } from '@angular/core';
1+
import { Component, HostBinding, OnInit, ViewChild } from '@angular/core';
22
import { ActivatedRoute } from '@angular/router';
33
import {
44
Group,
@@ -17,6 +17,9 @@ import { GuiAuthResolver } from '@perun-web-apps/perun/services';
1717
import { Urns } from '@perun-web-apps/perun/urns';
1818
import { Observable } from 'rxjs';
1919
import { map, startWith } from 'rxjs/operators';
20+
import { MatSlideToggle } from '@angular/material/slide-toggle';
21+
import { GroupsListComponent } from '@perun-web-apps/perun/components';
22+
import { GroupWithStatus } from '@perun-web-apps/perun/models';
2023

2124
@Component({
2225
selector: 'app-member-groups',
@@ -28,14 +31,18 @@ export class MemberGroupsComponent implements OnInit {
2831

2932
// used for router animation
3033
@HostBinding('class.router-component') true;
34+
@ViewChild('toggle', { static: true }) toggle: MatSlideToggle;
35+
@ViewChild('list') private list: GroupsListComponent;
3136

3237
groups: Group[] = [];
3338
memberId: number;
3439
member: Member;
3540
allGroups: Group[];
3641
loading: boolean;
3742
filterValue = '';
43+
filtering = false;
3844
tableId = TABLE_MEMBER_DETAIL_GROUPS;
45+
showGroupList = false;
3946
selection = new SelectionModel<Group>(true, []);
4047
addAuth: boolean;
4148
routeAuth: boolean;
@@ -67,6 +74,16 @@ export class MemberGroupsComponent implements OnInit {
6774
this.groupsService.getAllGroups(this.member.voId).subscribe((allGroups) => {
6875
this.allGroups = allGroups;
6976
this.refreshTable();
77+
if (localStorage.getItem('preferedValue') === 'list') {
78+
this.toggle.toggle();
79+
this.showGroupList = true;
80+
}
81+
82+
this.toggle.change.subscribe(() => {
83+
const value = this.toggle.checked ? 'list' : 'tree';
84+
localStorage.setItem('preferedValue', value);
85+
this.refreshTable();
86+
});
7087
});
7188
});
7289
});
@@ -80,15 +97,19 @@ export class MemberGroupsComponent implements OnInit {
8097
Urns.MEMBER_GROUP_STATUS,
8198
Urns.MEMBER_GROUP_STATUS_INDIRECT,
8299
])
83-
.subscribe(
84-
(groups) => {
100+
.subscribe({
101+
next: (groups) => {
85102
this.selection.clear();
86103
this.groups = groups;
87104
this.setAuthRights();
88105
this.loading = false;
89106
},
90-
() => (this.loading = false)
91-
);
107+
error: () => (this.loading = false),
108+
});
109+
}
110+
111+
changeExpiration(group: GroupWithStatus): void {
112+
this.list.changeExpiration(group);
92113
}
93114

94115
setAuthRights(): void {
@@ -148,5 +169,11 @@ export class MemberGroupsComponent implements OnInit {
148169

149170
applyFilter(filterValue: string): void {
150171
this.filterValue = filterValue;
172+
this.filtering = filterValue !== '';
173+
}
174+
175+
labelToggle(): void {
176+
this.showGroupList = !this.showGroupList;
177+
this.refreshTable();
151178
}
152179
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ <h1 class="page-subtitle">{{'VO_DETAIL.GROUPS.TITLE' | translate}}</h1>
4242
*perunWebAppsLoader="loading$ | async; indicator: spinner"
4343
(moveGroup)="onMoveGroup($event)"
4444
(refreshTable)="refresh()"
45+
[displayedColumns]="['nameWithId', 'description', 'menu']"
4546
[expandAll]="filtering"
4647
[disableRouting]="!routeAuth"
4748
[groups]="groups"

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,9 @@
832832
"TITLE": "Member groups",
833833
"ADD": "Add",
834834
"REMOVE": "Remove",
835-
"REMOVE_PERMISSION_HINT": "You don't have permission to remove some of the selected groups."
835+
"REMOVE_PERMISSION_HINT": "You don't have permission to remove some of the selected groups.",
836+
"LIST_VIEW": "List view",
837+
"TREE_VIEW": "Tree view"
836838
},
837839
"APPLICATIONS": {
838840
"TITLE": "Application",

libs/perun/components/src/lib/groups-list/groups-list.component.html

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,18 @@
160160
{{'SHARED_LIB.PERUN.COMPONENTS.GROUPS_LIST.TABLE_GROUP_EXPIRATION' | translate}}
161161
</th>
162162
<td *matCellDef="let group" class="wrap-content" mat-cell>
163-
{{group | groupExpiration | parseDate}}
164-
<button
165-
*ngIf="group | canManageGroup"
166-
(click)="changeExpiration(group)"
167-
(mouseenter)="disabledRouting = true"
168-
(mouseleave)="disabledRouting = disableRouting"
169-
matTooltip="{{'SHARED_LIB.PERUN.COMPONENTS.GROUPS_LIST.CHANGE_EXPIRATION' | translate}}"
170-
mat-icon-button>
171-
<mat-icon>edit</mat-icon>
172-
</button>
163+
<span class="align-elements">
164+
{{group | groupExpiration | parseDate}}
165+
<button
166+
*ngIf="group | canManageGroup"
167+
(click)="changeExpiration(group)"
168+
(mouseenter)="disabledRouting = true"
169+
(mouseleave)="disabledRouting = disableRouting"
170+
matTooltip="{{'SHARED_LIB.PERUN.COMPONENTS.GROUPS_LIST.CHANGE_EXPIRATION' | translate}}"
171+
mat-icon-button>
172+
<mat-icon>edit</mat-icon>
173+
</button>
174+
</span>
173175
</td>
174176
</ng-container>
175177
<ng-container matColumnDef="menu">

libs/perun/components/src/lib/groups-list/groups-list.component.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import {
55
EditFacilityResourceGroupVoDialogOptions,
66
GroupSyncDetailDialogComponent,
77
} from '@perun-web-apps/perun/dialogs';
8-
import {
9-
Group,
10-
Member,
11-
PaginatedRichGroups,
12-
VosManagerService,
13-
} from '@perun-web-apps/perun/openapi';
8+
import { Group, PaginatedRichGroups, VosManagerService } from '@perun-web-apps/perun/openapi';
149
import { GuiAuthResolver, TableCheckbox } from '@perun-web-apps/perun/services';
1510
import {
1611
customDataSourceFilterPredicate,
@@ -259,8 +254,8 @@ export class GroupsListComponent {
259254
};
260255

261256
const dialogRef = this.dialog.open(ChangeGroupExpirationDialogComponent, config);
262-
dialogRef.afterClosed().subscribe((success: { success: boolean; member: Member }) => {
263-
if (success.success) {
257+
dialogRef.afterClosed().subscribe((success) => {
258+
if (success) {
264259
this.refreshTable.emit();
265260
}
266261
});

libs/perun/components/src/lib/groups-tree/groups-tree.component.html

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,49 @@
3737
{{treeControl.isExpanded(group) ? 'expand_more' : 'chevron_right'}}
3838
</mat-icon>
3939
</button>
40-
<div class="w-50">
40+
<div *ngIf="displayedColumns.includes('nameWithId')" class="w-50">
4141
<span attr.data-cy="{{group.name}}" class="me-2">
4242
{{group.name}}
4343
</span>
4444
<span *ngIf="authResolver.isPerunAdminOrObserver()" class="text-muted">
4545
#{{group.id}}
4646
</span>
4747
</div>
48-
<div class="w-50 text-muted description-text" #rootDescription>
48+
<div
49+
*ngIf="displayedColumns.includes('description')"
50+
class="w-50 text-muted description-text"
51+
#rootDescription>
4952
<span matTooltip="{{group.description}}" matTooltipPosition="before">
5053
{{group.description}}
5154
</span>
5255
</div>
5356
</a>
54-
<div class="group-buttons">
57+
<div *ngIf="displayedColumns.includes('expiration')" class="me-4 align-elements">
58+
{{group | groupExpiration | parseDate}}
59+
<button
60+
*ngIf="group | canManageGroup"
61+
(click)="changeExpiration.emit(group)"
62+
(mouseenter)="disabledRouting = true"
63+
(mouseleave)="disabledRouting = disableRouting"
64+
matTooltip="{{'SHARED_LIB.PERUN.COMPONENTS.GROUPS_LIST.CHANGE_EXPIRATION' | translate}}"
65+
mat-icon-button>
66+
<mat-icon>edit</mat-icon>
67+
</button>
68+
</div>
69+
<div *ngIf="displayedColumns.includes('status')" class="w-25">
70+
<i
71+
*ngIf="{status: group.attributes | findAttribute: 'groupStatus'} as groupStatus"
72+
(click)="$event.stopPropagation()"
73+
class="material-icons status-change {{groupStatus.status | groupStatusIconColor}} cursor-default me-4"
74+
matTooltip="{{groupStatus.status}}"
75+
matTooltipClass="status-tooltip"
76+
matTooltipPosition="left">
77+
<span>
78+
{{groupStatus.status | memberStatusIcon}}
79+
</span>
80+
</i>
81+
</div>
82+
<div *ngIf="displayedColumns.includes('menu')" class="group-buttons">
5583
<perun-web-apps-group-menu
5684
[disabled]="group.fullName === 'members'"
5785
(moveGroup)="onMoveGroup(group)"

libs/perun/components/src/lib/groups-tree/groups-tree.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'
1212
import { FlatTreeControl } from '@angular/cdk/tree';
1313
import { SelectionModel } from '@angular/cdk/collections';
1414
import { RichGroup, Vo } from '@perun-web-apps/perun/openapi';
15-
import { GroupFlatNode, TreeGroup } from '@perun-web-apps/perun/models';
15+
import { GroupFlatNode, GroupWithStatus, TreeGroup } from '@perun-web-apps/perun/models';
1616
import { MatDialog } from '@angular/material/dialog';
1717
import { findParent, getDefaultDialogConfig } from '@perun-web-apps/perun/utils';
1818
import { GroupSyncDetailDialogComponent } from '@perun-web-apps/perun/dialogs';
@@ -37,15 +37,18 @@ export class GroupsTreeComponent implements OnChanges {
3737
@Input() theme = 'group-theme';
3838
@Output() moveGroup = new EventEmitter<GroupFlatNode>();
3939
@Output() refreshTable = new EventEmitter<void>();
40+
@Output() changeExpiration = new EventEmitter<GroupWithStatus>();
4041
@Input() groups: RichGroup[];
4142
@Input() filterValue: string;
4243
@Input() expandAll = false;
4344
@Input() disableRouting = false;
4445
@Input() selection = new SelectionModel<GroupFlatNode>(true, []);
4546
@Input() hideCheckbox = false;
4647
@Input() vo: Vo;
48+
@Input() displayedColumns = ['nameWithId', 'description', 'menu', 'expiration', 'status'];
4749
@ViewChild('scrollViewport', { static: false }) scrollViewport: CdkVirtualScrollViewport;
4850

51+
disabledRouting = false;
4952
displayButtons = window.innerWidth > 600;
5053

5154
removeAuth: boolean;

0 commit comments

Comments
 (0)