Преглед изворни кода

feat(admin-ui): Nav menu requirePermissions accepts predicate fn

Closes #651
Michael Bromley пре 5 година
родитељ
комит
c74765d558

+ 2 - 2
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.html

@@ -5,7 +5,7 @@
                 class="nav-group"
                 [attr.data-section-id]="section.id"
                 [class.collapsible]="section.collapsible"
-                *vdrIfPermissions="section.requiresPermission"
+                *ngIf="shouldDisplayLink(section)"
             >
                 <ng-container *ngIf="navBuilderService.sectionBadges[section.id] | async as sectionBadge">
                     <div *ngIf="sectionBadge !== 'none'" class="status-badge" [class]="sectionBadge"></div>
@@ -14,7 +14,7 @@
                 <label [for]="section.id">{{ section.label | translate }}</label>
                 <ul class="nav-list">
                     <ng-container *ngFor="let item of section.items">
-                        <li *vdrIfPermissions="item.requiresPermission">
+                        <li *ngIf="shouldDisplayLink(item)">
                             <a
                                 class="nav-link"
                                 [attr.data-item-id]="section.id"

+ 45 - 8
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.ts

@@ -1,8 +1,10 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { Subscription } from 'rxjs';
 import { map, startWith } from 'rxjs/operators';
 
+import { DataService } from '../../data/providers/data.service';
 import { HealthCheckService } from '../../providers/health-check/health-check.service';
 import { JobQueueService } from '../../providers/job-queue/job-queue.service';
 import { NavMenuBadge, NavMenuItem } from '../../providers/nav-builder/nav-builder-types';
@@ -13,16 +15,55 @@ import { NavBuilderService } from '../../providers/nav-builder/nav-builder.servi
     templateUrl: './main-nav.component.html',
     styleUrls: ['./main-nav.component.scss'],
 })
-export class MainNavComponent implements OnInit {
+export class MainNavComponent implements OnInit, OnDestroy {
     constructor(
         private route: ActivatedRoute,
         private router: Router,
         public navBuilderService: NavBuilderService,
         private healthCheckService: HealthCheckService,
         private jobQueueService: JobQueueService,
+        private dataService: DataService,
     ) {}
 
+    private userPermissions: string[];
+    private subscription: Subscription;
+
+    shouldDisplayLink(menuItem: Pick<NavMenuItem, 'requiresPermission'>) {
+        if (!this.userPermissions) {
+            return false;
+        }
+        if (!menuItem.requiresPermission) {
+            return true;
+        }
+        if (typeof menuItem.requiresPermission === 'string') {
+            return this.userPermissions.includes(menuItem.requiresPermission);
+        }
+        if (typeof menuItem.requiresPermission === 'function') {
+            return menuItem.requiresPermission(this.userPermissions);
+        }
+    }
+
     ngOnInit(): void {
+        this.defineNavMenu();
+        this.subscription = this.dataService.client
+            .userStatus()
+            .mapStream(({ userStatus }) => {
+                this.userPermissions = userStatus.permissions;
+            })
+            .subscribe();
+    }
+
+    ngOnDestroy() {
+        if (this.subscription) {
+            this.subscription.unsubscribe();
+        }
+    }
+
+    getRouterLink(item: NavMenuItem) {
+        return this.navBuilderService.getRouterLink(item, this.route);
+    }
+
+    private defineNavMenu() {
         this.navBuilderService.defineNavMenuSections([
             {
                 requiresPermission: 'ReadCatalog',
@@ -186,7 +227,7 @@ export class MainNavComponent implements OnInit {
                         statusBadge: this.jobQueueService.activeJobs$.pipe(
                             startWith([]),
                             map(
-                                (jobs) =>
+                                jobs =>
                                     ({
                                         type: jobs.length === 0 ? 'none' : 'info',
                                         propagateToSection: jobs.length > 0,
@@ -200,7 +241,7 @@ export class MainNavComponent implements OnInit {
                         routerLink: ['/system', 'system-status'],
                         icon: 'rack-server',
                         statusBadge: this.healthCheckService.status$.pipe(
-                            map((status) => ({
+                            map(status => ({
                                 type: status === 'ok' ? 'success' : 'error',
                                 propagateToSection: status === 'error',
                             })),
@@ -210,8 +251,4 @@ export class MainNavComponent implements OnInit {
             },
         ]);
     }
-
-    getRouterLink(item: NavMenuItem) {
-        return this.navBuilderService.getRouterLink(item, this.route);
-    }
 }

+ 8 - 2
packages/admin-ui/src/lib/core/src/providers/nav-builder/nav-builder-types.ts

@@ -30,7 +30,10 @@ export interface NavMenuItem {
     routerLink: RouterLinkDefinition;
     onClick?: (event: MouseEvent) => void;
     icon?: string;
-    requiresPermission?: string;
+    /**
+     * Control the display of this item based on the user permissions.
+     */
+    requiresPermission?: string | ((userPermissions: string[]) => boolean);
     statusBadge?: Observable<NavMenuBadge>;
 }
 
@@ -42,7 +45,10 @@ export interface NavMenuSection {
     id: string;
     label: string;
     items: NavMenuItem[];
-    requiresPermission?: string;
+    /**
+     * Control the display of this item based on the user permissions.
+     */
+    requiresPermission?: string | ((userPermissions: string[]) => boolean);
     collapsible?: boolean;
     collapsedByDefault?: boolean;
 }