Skip to content

Permissions Tool

The Permissions Tool allows developers to override user permissions at runtime for testing different access control scenarios. This enables testing permission-based UI and functionality without changing user roles or backend configuration.

  • Testing Access Control: Verify that UI elements and features are properly hidden/shown based on permissions
  • Role Simulation: Test application behavior as different user roles (admin, editor, viewer) without switching accounts
  • Security Testing: Ensure restricted features are properly protected when permissions are denied
app.component.ts
import { Component, inject, signal } from '@angular/core';
import { ToolbarPermissionsService } from 'ngx-dev-toolbar';
@Component({
selector: 'app-root',
template: `
@if (canEdit()) {
<button>Edit</button>
}
@if (canDelete()) {
<button>Delete</button>
}
`
})
export class AppComponent {
private permissionsService = inject(ToolbarPermissionsService);
canEdit = signal(false);
canDelete = signal(false);
ngOnInit() {
// Define available permissions
this.permissionsService.setAvailableOptions([
{
id: 'can-edit',
name: 'Can Edit',
description: 'Permission to edit records',
isGranted: false,
isForced: false
},
{
id: 'can-delete',
name: 'Can Delete',
description: 'Permission to delete records',
isGranted: false,
isForced: false
}
]);
// Subscribe to forced permission values
this.permissionsService.getForcedValues().subscribe(permissions => {
const edit = permissions.find(p => p.id === 'can-edit');
const del = permissions.find(p => p.id === 'can-delete');
this.canEdit.set(edit?.isGranted || false);
this.canDelete.set(del?.isGranted || false);
});
}
}

You can persist forced permission values back to your actual data source. When configured, each permission item shows an “apply” button.

Call setApplyToSource() on the service — right alongside setAvailableOptions():

permissions.service.ts
import { Injectable, inject } from '@angular/core';
import { ToolbarPermissionsService } from 'ngx-dev-toolbar';
@Injectable({ providedIn: 'root' })
export class PermissionsService {
private toolbarService = inject(ToolbarPermissionsService);
constructor() {
this.toolbarService.setAvailableOptions([...]); // [!code highlight]
this.toolbarService.setApplyToSource(async (permissionId, value) => { // [!code highlight]
await fetch(`/api/permissions/${permissionId}`, { // [!code highlight]
method: 'PUT', // [!code highlight]
body: JSON.stringify({ granted: value }), // [!code highlight]
}); // [!code highlight]
}); // [!code highlight]
}
}

The toolbar automatically manages loading, success, and error states for each item.

Organize related permissions into collapsible sections by adding an optional group field to each permission. Groups appear as headers in the toolbar UI and can be expanded or collapsed; collapsed state persists across reloads.

permissions.service.ts
this.permissionsService.setAvailableOptions([
{
id: 'can-add-users',
name: 'Add Users',
isGranted: false,
isForced: false,
group: 'Admin', // [!code highlight]
},
{
id: 'can-add-permissions',
name: 'Add Permissions',
isGranted: false,
isForced: false,
group: 'Admin', // [!code highlight]
},
{
id: 'can-view-dashboard',
name: 'View Dashboard',
isGranted: true,
isForced: false,
group: 'Dashboard', // [!code highlight]
},
]);

Behavior:

  • Pinned permissions always appear at the top in a dedicated Pinned section, regardless of their group
  • Named groups render alphabetically with each group’s permissions sorted alphabetically inside
  • Permissions without a group field appear under an Other section at the bottom
  • Each group header shows the item count and is collapsible

Backward compatible: if no permission has a group field, the toolbar renders the flat list exactly as before — no headers, no behavioral change.