Skip to content
This repository was archived by the owner on Mar 25, 2023. It is now read-only.

Commit 8f86cf8

Browse files
authored
fix: improve configureSidenav configuration (#1221)
PR Close #1166
1 parent 4a9a70a commit 8f86cf8

File tree

15 files changed

+216
-154
lines changed

15 files changed

+216
-154
lines changed

config-guide.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,24 @@ You can set a type of comparing and ignoring VM tags, when changing service offe
221221
}
222222
```
223223

224-
### Configure Sidebar
225-
This configuration allows a user to set a list of left-sidebar sections. Configure possible if property “allowReorderingSidebar” is true.
226-
For example,
224+
### Configure Sidenav
225+
Allows you to predefine the order and visibility of menu items. The order of the menu items is determined by the order of the elements in the array. The VMS menu item can not be made invisible, the visibility property will be ignored.
226+
For configuration, you must specify all menu items and the "allowReorderingSidebar" parameter must be true.
227+
228+
For example (default values),
227229
```
228-
"configureSidebar": [
229-
"vms",
230-
"volumes",
231-
"templates",
232-
"sgs",
233-
"events",
234-
"ssh",
235-
"accounts",
236-
"settings"
237-
]
230+
"allowReorderingSidebar": true,
231+
"configureSidenav": [
232+
{ "id": "VMS", "visible": true },
233+
{ "id": "VOLUMES", "visible": true },
234+
{ "id": "TEMPLATES", "visible": true },
235+
{ "id": "SNAPSHOTS", "visible": true },
236+
{ "id": "SGS", "visible": true },
237+
{ "id": "EVENTS", "visible": true },
238+
{ "id": "SSH", "visible": true },
239+
{ "id": "ACCOUNTS", "visible": true },
240+
{ "id": "SETTINGS", "visible": true }
241+
]
238242
```
239243

240244
### Default First Day Of Week
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface NavigationItem {
22
id: string;
3-
enabled: boolean;
3+
visible: boolean;
44
}
55

66
export interface SidenavRoute extends NavigationItem {
@@ -15,62 +15,62 @@ export const sidenavRoutes: Array<SidenavRoute> = [
1515
text: 'NAVIGATION_SIDEBAR.VMS',
1616
icon: 'mdi-cloud',
1717
id: 'VMS',
18-
enabled: true
18+
visible: true
1919
},
2020
{
2121
path: '/storage',
2222
text: 'NAVIGATION_SIDEBAR.STORAGE',
2323
icon: 'mdi-server',
2424
id: 'VOLUMES',
25-
enabled: true
25+
visible: true
2626
},
2727
{
2828
path: '/templates',
2929
text: 'NAVIGATION_SIDEBAR.IMAGES',
3030
icon: 'mdi-disk',
3131
id: 'TEMPLATES',
32-
enabled: true
32+
visible: true
3333
}, {
3434
path: '/snapshots',
3535
text: 'NAVIGATION_SIDEBAR.SNAPSHOTS',
3636
icon: 'mdi-camera',
3737
id: 'SNAPSHOTS',
38-
enabled: true
38+
visible: true
3939
},
4040
{
4141
path: '/security-group',
4242
text: 'NAVIGATION_SIDEBAR.FIREWALL_TEMPLATES',
4343
icon: 'mdi-security',
4444
id: 'SGS',
45-
enabled: true
45+
visible: true
4646
},
4747
{
4848
path: '/events',
4949
text: 'NAVIGATION_SIDEBAR.ACTIVITY_LOG',
5050
icon: 'mdi-calendar-text',
5151
id: 'EVENTS',
52-
enabled: true
52+
visible: true
5353
},
5454
{
5555
path: '/ssh-keys',
5656
text: 'NAVIGATION_SIDEBAR.SSH_KEYS',
5757
icon: 'mdi-key',
5858
id: 'SSH',
59-
enabled: true
59+
visible: true
6060
},
6161
{
6262
path: '/accounts',
6363
text: 'NAVIGATION_SIDEBAR.ACCOUNTS',
6464
icon: 'mdi-account',
6565
id: 'ACCOUNTS',
66-
enabled: true
66+
visible: true
6767
},
6868
{
6969
path: '/settings',
7070
text: 'NAVIGATION_SIDEBAR.SETTINGS',
7171
icon: 'mdi-settings',
7272
id: 'SETTINGS',
73-
enabled: true
73+
visible: true
7474
}
7575
];
7676

@@ -80,6 +80,6 @@ export const nonDraggableRoutes: Array<SidenavRoute> = [
8080
text: 'NAVIGATION_SIDEBAR.LOGOUT',
8181
icon: 'mdi-exit-to-app',
8282
id: 'LOGOUT',
83-
enabled: true
83+
visible: true
8484
}
8585
];

src/app/core/components/sidenav/sidenav.component.html

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,36 +43,43 @@
4343
[dragulaModel]="routes"
4444
>
4545
<ng-container *ngFor="let route of routes">
46-
<a
47-
*ngIf="!editing && route.enabled"
48-
class="navigation-link link-container"
49-
[routerLink]="route.path"
50-
routerLinkActive="link-active"
51-
(click)="linkClick(route.path)"
52-
>
53-
<mat-icon [@linkSlide]="'in'" class="link-element" [ngClass]="route.icon"></mat-icon>
54-
<div [@linkSlide]="'in'" class="link-element" [innerHTML]="route.text | translate"></div>
55-
</a>
56-
<div
57-
*ngIf="editing"
58-
class="drag navigation-link link-container"
59-
>
60-
<span
61-
class="handle"
62-
[@handleSlide]="'in'"
63-
></span>
64-
<mat-checkbox
65-
[(ngModel)]="route.enabled"
66-
(change)="handleRouteChecked($event)"
67-
[@handleSlide]="!editing ? 'in' : ''"
68-
></mat-checkbox>
69-
<div class="link-element-edit" [innerHTML]="route.text | translate"></div>
70-
</div>
46+
<ng-container *ngIf="editing; then editMode else normalMode"></ng-container>
47+
48+
<ng-template #editMode>
49+
<div class="drag navigation-link link-container">
50+
<span
51+
class="handle"
52+
[@handleSlide]="'in'"
53+
></span>
54+
<mat-checkbox
55+
*ngIf="!isAlwaysVisible(route)"
56+
[(ngModel)]="route.visible"
57+
(change)="handleRouteChecked($event)"
58+
[@handleSlide]="!editing ? 'in' : ''"
59+
></mat-checkbox>
60+
<div class="link-element-edit" [innerHTML]="route.text | translate"></div>
61+
</div>
62+
</ng-template>
63+
64+
<ng-template #normalMode>
65+
<a
66+
*ngIf="route.visible || isAlwaysVisible(route)"
67+
class="navigation-link link-container"
68+
[routerLink]="route.path"
69+
routerLinkActive="link-active"
70+
(click)="linkClick(route.path)"
71+
>
72+
<mat-icon [@linkSlide]="'in'" class="link-element" [ngClass]="route.icon"></mat-icon>
73+
<div [@linkSlide]="'in'" class="link-element" [innerHTML]="route.text | translate"></div>
74+
</a>
75+
</ng-template>
76+
7177
</ng-container>
7278
</div>
79+
7380
<ng-container *ngFor="let route of nonDraggableRoutes">
7481
<a
75-
*ngIf="!editing && route.enabled"
82+
*ngIf="!editing && route.visible"
7683
class="navigation-link link-container"
7784
[routerLink]="route.path"
7885
routerLinkActive="link-active"

src/app/core/components/sidenav/sidenav.component.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { WithUnsubscribe } from '../../../utils/mixins/with-unsubscribe';
1010
import { transformHandle, transformLinks } from './sidenav-animations';
1111
import { NavigationItem, nonDraggableRoutes, SidenavRoute, sidenavRoutes } from './sidenav-routes';
1212
import { layoutActions, State, UserTagsActions, UserTagsSelectors } from '../../../root-store';
13+
import { SidenavRouteId } from '../../config';
1314

1415

1516
@Component({
@@ -98,6 +99,11 @@ export class SidenavComponent extends WithUnsubscribe() implements OnInit, OnDes
9899
this.hasChanges = true;
99100
}
100101

102+
public isAlwaysVisible(route: SidenavRoute): boolean {
103+
const visibleRouteIds: SidenavRouteId[] = ['VMS'];
104+
return visibleRouteIds.findIndex((id => id === route.id)) >= 0;
105+
}
106+
101107
private setUpDragula(): void {
102108
this.dragula.setOptions(this.dragulaContainerName, {
103109
moves: () => this.editing
@@ -122,7 +128,7 @@ export class SidenavComponent extends WithUnsubscribe() implements OnInit, OnDes
122128
this.routes.forEach((
123129
route,
124130
i
125-
) => route.enabled = (!this.canEdit || (this.canEdit && order[i].enabled)));
131+
) => route.visible = (!this.canEdit || (this.canEdit && order[i].visible)));
126132
}
127133
});
128134
} else {
@@ -136,21 +142,30 @@ export class SidenavComponent extends WithUnsubscribe() implements OnInit, OnDes
136142

137143
public setUpRoutes() {
138144
if (this.canEdit) {
139-
const defaultOrder = this.configService.get('configureSidebar');
140-
if (defaultOrder) {
141-
this.routes = this.routes.filter(route =>
142-
defaultOrder.some(orderElement => orderElement.toUpperCase() === route.id));
143-
}
145+
const sidenavConfiguration = this.configService.get('configureSidenav');
146+
const routesMap = this.getRoutesMap();
147+
this.routes = sidenavConfiguration.map(confElement => {
148+
const route = routesMap[confElement.id];
149+
route.visible = confElement.visible;
150+
return route;
151+
});
144152
}
145153
}
146154

155+
private getRoutesMap(): { [id: string]: SidenavRoute } {
156+
return this.routes.reduce((map, route) => {
157+
map[route.id] = route;
158+
return map;
159+
}, {});
160+
}
161+
147162
private validateNavigationOrder(order: NavigationItem[]): boolean {
148163
if (order.length !== this.routes.length) {
149164
return false;
150165
}
151166

152167
return order.every(el =>
153-
el.enabled != null && el.id != null && !!this.routes.find(route => route.id === el.id));
168+
el.visible != null && el.id != null && !!this.routes.find(route => route.id === el.id));
154169
}
155170

156171
private navigationPredicate(order: NavigationItem[]) {
@@ -160,7 +175,7 @@ export class SidenavComponent extends WithUnsubscribe() implements OnInit, OnDes
160175

161176
private stringifyMenuState(routes: NavigationItem[]): string {
162177
return routes
163-
.map(el => `${el.id}:${+el.enabled}`)
178+
.map(el => `${el.id}:${+el.visible}`)
164179
.join(';');
165180
}
166181

@@ -169,10 +184,10 @@ export class SidenavComponent extends WithUnsubscribe() implements OnInit, OnDes
169184
.split(';')
170185
.filter(Boolean)
171186
.map((menuElement: string) => {
172-
const [id, enabled] = menuElement.split(':');
187+
const [id, visible] = menuElement.split(':');
173188
return {
174189
id,
175-
enabled: enabled === '1'
190+
visible: visible === '1'
176191
}
177192
});
178193
}

src/app/core/config/config-validation.service.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as AjvErrors from 'ajv-errors';
66
import * as omit from 'lodash/omit';
77

88
import { customizableProperties, defaultConfig } from './default-configuration';
9-
import { Config } from './config.interface';
9+
import { Config } from './interfaces';
1010
import * as validationSchemes from './validation-schemes';
1111

1212
enum ErrorType {
@@ -66,7 +66,8 @@ export class ConfigValidationService {
6666
defaultInterfaceLanguage: validationSchemes.defaultInterfaceLanguage,
6767
defaultTimeFormat: validationSchemes.defaultTimeFormat,
6868
defaultThemeName: validationSchemes.defaultThemeName,
69-
sessionTimeout: validationSchemes.sessionTimeout
69+
sessionTimeout: validationSchemes.sessionTimeout,
70+
configureSidenav: validationSchemes.configureSidenav,
7071
};
7172

7273
constructor() {

src/app/core/config/config.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from '@angular/core';
22

3-
import { Config } from './config.interface';
3+
import { Config } from './interfaces';
44
import { defaultConfig } from './default-configuration';
55

66

0 commit comments

Comments
 (0)