Kaynağa Gözat

feat(admin-ui): Display permissions by Channel in Admin detail view

Michael Bromley 6 yıl önce
ebeveyn
işleme
586f2d7a31

+ 18 - 20
packages/admin-ui/src/app/data/definitions/administrator-definitions.ts

@@ -1,5 +1,21 @@
 import gql from 'graphql-tag';
 
+export const ROLE_FRAGMENT = gql`
+    fragment Role on Role {
+        id
+        createdAt
+        updatedAt
+        code
+        description
+        permissions
+        channels {
+            id
+            code
+            token
+        }
+    }
+`;
+
 export const ADMINISTRATOR_FRAGMENT = gql`
     fragment Administrator on Administrator {
         id
@@ -13,29 +29,11 @@ export const ADMINISTRATOR_FRAGMENT = gql`
             identifier
             lastLogin
             roles {
-                id
-                code
-                description
-                permissions
+                ...Role
             }
         }
     }
-`;
-
-export const ROLE_FRAGMENT = gql`
-    fragment Role on Role {
-        id
-        createdAt
-        updatedAt
-        code
-        description
-        permissions
-        channels {
-            id
-            code
-            token
-        }
-    }
+    ${ROLE_FRAGMENT}
 `;
 
 export const GET_ADMINISTRATORS = gql`

+ 40 - 8
packages/admin-ui/src/app/settings/components/admin-detail/admin-detail.component.html

@@ -6,7 +6,7 @@
         <vdr-action-bar-items locationId="administrator-detail"></vdr-action-bar-items>
         <button
             class="btn btn-primary"
-            *ngIf="(isNew$ | async); else updateButton"
+            *ngIf="isNew$ | async; else updateButton"
             (click)="create()"
             [disabled]="detailForm.invalid || detailForm.pristine"
         >
@@ -27,16 +27,31 @@
 
 <form class="form" [formGroup]="detailForm">
     <vdr-form-field [label]="'settings.email-address' | translate" for="emailAddress">
-        <input id="emailAddress" type="text" formControlName="emailAddress" [readonly]="!('UpdateAdministrator' | hasPermission)"/>
+        <input
+            id="emailAddress"
+            type="text"
+            formControlName="emailAddress"
+            [readonly]="!('UpdateAdministrator' | hasPermission)"
+        />
     </vdr-form-field>
     <vdr-form-field [label]="'settings.first-name' | translate" for="firstName">
-        <input id="firstName" type="text" formControlName="firstName" [readonly]="!('UpdateAdministrator' | hasPermission)"/>
+        <input
+            id="firstName"
+            type="text"
+            formControlName="firstName"
+            [readonly]="!('UpdateAdministrator' | hasPermission)"
+        />
     </vdr-form-field>
     <vdr-form-field [label]="'settings.last-name' | translate" for="lastName">
-        <input id="lastName" type="text" formControlName="lastName" [readonly]="!('UpdateAdministrator' | hasPermission)"/>
+        <input
+            id="lastName"
+            type="text"
+            formControlName="lastName"
+            [readonly]="!('UpdateAdministrator' | hasPermission)"
+        />
     </vdr-form-field>
-    <vdr-form-field *ngIf="(isNew$ | async)" [label]="'settings.password' | translate" for="password">
-        <input id="password" type="password" formControlName="password"/>
+    <vdr-form-field *ngIf="isNew$ | async" [label]="'settings.password' | translate" for="password">
+        <input id="password" type="password" formControlName="password" />
     </vdr-form-field>
     <vdr-form-field
         *ngIf="!(isNew$ | async) && ('UpdateAdministrator' | hasPermission)"
@@ -44,7 +59,7 @@
         for="password"
         [readOnlyToggle]="true"
     >
-        <input id="password" type="password" formControlName="password"/>
+        <input id="password" type="password" formControlName="password" />
     </vdr-form-field>
     <label class="clr-control-label">{{ 'settings.roles' | translate }}</label>
     <ng-select
@@ -56,5 +71,22 @@
         bindLabel="description"
     ></ng-select>
 
-    <vdr-permission-grid [permissions]="selectedRolePermissions" [readonly]="true"></vdr-permission-grid>
+    <ul class="nav" role="tablist">
+        <li role="presentation" class="nav-item" *ngFor="let channel of getAvailableChannels()">
+            <button
+                [id]="channel.channelId"
+                (click)="selectedChannelId = channel.channelId"
+                class="btn btn-link nav-link"
+                [class.active]="selectedChannelId === channel.channelId"
+                [attr.aria-selected]="selectedChannelId === channel.channelId"
+                type="button"
+            >
+                {{ channel.channelCode | channelCodeToLabel | translate }}
+            </button>
+        </li>
+    </ul>
+    <vdr-permission-grid
+        [permissions]="getPermissionsForSelectedChannel()"
+        [readonly]="true"
+    ></vdr-permission-grid>
 </form>

+ 61 - 9
packages/admin-ui/src/app/settings/components/admin-detail/admin-detail.component.ts

@@ -8,9 +8,11 @@ import { BaseDetailComponent } from '../../../common/base-detail.component';
 import {
     Administrator,
     CreateAdministratorInput,
+    GetAdministrator,
     LanguageCode,
     Permission,
     Role,
+    RoleFragment,
     UpdateAdministratorInput,
 } from '../../../common/generated-types';
 import { _ } from '../../../core/providers/i18n/mark-for-extraction';
@@ -18,18 +20,30 @@ import { NotificationService } from '../../../core/providers/notification/notifi
 import { DataService } from '../../../data/providers/data.service';
 import { ServerConfigService } from '../../../data/server-config';
 
+export interface PermissionsByChannel {
+    channelId: string;
+    channelCode: string;
+    permissions: { [K in Permission]: boolean };
+}
+
 @Component({
     selector: 'vdr-admin-detail',
     templateUrl: './admin-detail.component.html',
     styleUrls: ['./admin-detail.component.scss'],
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class AdminDetailComponent extends BaseDetailComponent<Administrator> implements OnInit, OnDestroy {
-    administrator$: Observable<Administrator>;
+export class AdminDetailComponent extends BaseDetailComponent<GetAdministrator.Administrator>
+    implements OnInit, OnDestroy {
+    administrator$: Observable<GetAdministrator.Administrator>;
     allRoles$: Observable<Role.Fragment[]>;
     selectedRoles: Role.Fragment[] = [];
     detailForm: FormGroup;
-    selectedRolePermissions: { [K in Permission]: boolean } = {} as any;
+    selectedRolePermissions: { [channelId: string]: PermissionsByChannel } = {} as any;
+    selectedChannelId: string | null = null;
+
+    getAvailableChannels(): PermissionsByChannel[] {
+        return Object.values(this.selectedRolePermissions);
+    }
 
     constructor(
         router: Router,
@@ -72,6 +86,21 @@ export class AdminDetailComponent extends BaseDetailComponent<Administrator> imp
         this.buildPermissionsMap();
     }
 
+    getPermissionsForSelectedChannel() {
+        if (this.selectedChannelId) {
+            const selectedChannel = this.selectedRolePermissions[this.selectedChannelId];
+            if (selectedChannel) {
+                return this.selectedRolePermissions[this.selectedChannelId].permissions;
+            }
+        }
+        const channels = Object.values(this.selectedRolePermissions);
+        if (0 < channels.length) {
+            this.selectedChannelId = channels[0].channelId;
+            return channels[0].permissions;
+        }
+        return [];
+    }
+
     create() {
         const formValue = this.detailForm.value;
         const administrator: CreateAdministratorInput = {
@@ -152,13 +181,36 @@ export class AdminDetailComponent extends BaseDetailComponent<Administrator> imp
     private buildPermissionsMap() {
         const permissionsControl = this.detailForm.get('roles');
         if (permissionsControl) {
-            const permissions = permissionsControl.value.reduce(
-                (output, role: Role) => [...output, ...role.permissions],
-                [],
-            );
+            const roles: RoleFragment[] = permissionsControl.value;
+            const channelIdPermissionsMap = new Map<string, Set<Permission>>();
+            const channelIdCodeMap = new Map<string, string>();
+
+            for (const role of roles) {
+                for (const channel of role.channels) {
+                    const channelPermissions = channelIdPermissionsMap.get(channel.id);
+                    const permissionSet = channelPermissions || new Set<Permission>();
+
+                    role.permissions.forEach(p => permissionSet.add(p));
+                    channelIdPermissionsMap.set(channel.id, permissionSet);
+                    channelIdCodeMap.set(channel.id, channel.code);
+                }
+            }
+
             this.selectedRolePermissions = {} as any;
-            for (const permission of Object.keys(Permission)) {
-                this.selectedRolePermissions[permission] = permissions.includes(permission);
+            for (const channelId of Array.from(channelIdPermissionsMap.keys())) {
+                // tslint:disable-next-line:no-non-null-assertion
+                const permissionSet = channelIdPermissionsMap.get(channelId)!;
+                const permissionsHash: { [K in Permission]: boolean } = {} as any;
+                for (const permission of Object.keys(Permission)) {
+                    permissionsHash[permission] = permissionSet.has(permission as Permission);
+                }
+                this.selectedRolePermissions[channelId] = {
+                    // tslint:disable:no-non-null-assertion
+                    channelId,
+                    channelCode: channelIdCodeMap.get(channelId)!,
+                    permissions: permissionsHash,
+                    // tslint:enable:no-non-null-assertion
+                };
             }
         }
     }