Create Custom Page in Filament: Role Permission Management Page

with Filament Admin Panel you can create custom pages however you want.

here I am going to create a Role-Permission management page. it looks like this:

Create a view and a class file for the page

with this artisan command start creating the page

php artisan make:filament-page ManageRolePermissions --type=custom

You will have a class named ManageRolePermissions.php in app\Filament\Pages and a view file manage-role-permissions.blade.php in resources\views\filament\pages

a sidebar item is created and the page is empty.

empty custom page created in filament php

using laravel-permissions package.

I am using spatie/laravel/permission package becasue makes it easy for us to assign roles and permissions.

 composer require spatie/laravel-permission

publish and run the migrations

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan optimize:clear
php artisan migrate

now the database table is ready.

we need to seed some default roles and permissions to work with.

so let’s create a RoleSeeder and a PermissionSeeder.

php artisan make:seeder RoleSeeder
php artisan make:seeder PermissionSeeder
//RoleSeeder.php

use Spatie\Permission\Models\Role;

class RoleSeeder extends Seeder
{
 
    public function run()
    {

        $roles = ['admin', 'author', 'editor', 'moderator'];
        foreach ($roles as $role) {
            Role::create(['name' => 'admin',]);
        }

    }
}
//PermissionSeeder.php

use Spatie\Permission\Models\Permission;

class PermissionSeeder extends Seeder
{

    public function run()
    {
        $permissions = ['create post', 'edit post', 'delete post', 'create user', 'delete user', 'delete comment'];
        foreach ($permissions as $permission) {
            Permission::create(['name' => $permission]);
        }

    }
}

then run the seeders:

php artisan db:seed --class=RoleSeeder
php artisan db:seed --class=PermissionSeeder

Preparing the UI

first, in the Page Class we have to get all roles and permissions to show them in the view page:

// ManageRolePermissions.php
 public $roles;
 public $permissions;    
public function mount()
    {
        $this->roles = Role::all();
        $this->permissions = Permission::all()->pluck('name')->toArray();
       

    }

$roles and $permissions are for showing roles and permissions inside the page.

Filament pages are just like livewire components. so in the class we can use mount() method to set an initial value for the properties.

On this page, I want to have two boxes. in one box there is a list of permissions and in another one list of roles.

<x-filament::page>
   
 <div class="grid grid-cols-2 " >
        <div class="mr-6">
            <div class="text-2xl mb-6 font-bold">Roles</div>
            <div class="bg-white border-2 rounded-lg border-primary-500 p-1.5 w-full ">
                <ul>
                    <select  multiple class="w-full border-0">
                        @foreach($roles as $role)
                            <option >
                                {{$role->name}}

                            </option>

                        @endforeach

                    </select>
                </ul>
            </div>
        </div>

        <div>
            <div class="text-2xl mb-6 font-bold">Roles</div>
            <div class=" bg-white border-2 rounded-lg border-primary-500 p-1.5 w-full ">
                <ul >
                    @foreach($permissions as $permission)
                        <li class="mb-6"><span>
                                <input type="checkbox"
                                       value="{{$permission}}"
                                       class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
                                >
                            </span>
                            {{$permission}}
                        </li>

                    @endforeach

                </ul>


            </div>

        </div>

    </div>

    <div>
        <button 
                class="text-white  bg-danger-500 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg text-lg px-6 py-4">
            Save
        </button>
    </div>
</x-filament::page>

here we created two columns one for listing roles and another for listing permissions.

in the first column, roles are shown in a <select> element. the multiple attribute makes it a box in which we can select each role without a dropdown.

the second column shows permissions in a list. every permission has a checkbox we can use to select and assign the permission to a role.

at the bottom of the page, there is a button to save the permissions we assigned to each role.

Here is the UI:

UI for managing roles and permissions in Filament Admin Panel.

now we have to implement:

  • assigning permissions to a role
  • showing each role’s permissions dynamically.

Assign Permissions to a Role

we want to click on a role then select permissions and finally click on the save button to assign permissions.

so first we add two properties to the class.


public $selectedRole;
public $selectedPermissions;
 public function mount()
    {
        $this->roles = Role::all();
        $this->permissions = Permission::all()->pluck('name')->toArray();

        $this->selectedPermissions = [];

    }

because $selectedPermissions is an array we set its initial value inside the mount method.

the role that we click on, will be in $selectedRole and permissions will be in $selectedPermissions.

we have to change the view code like this:

in the Roles section.

 <select  wire:model="selectedRole" multiple class="w-full border-0">
                        @foreach($roles as $role)
                            <option>
                                {{$role->name}}

                            </option>

                        @endforeach

   </select>

we used wire:model attribute to bind the selected role value to $selectedRole property.

and for the permissions:

 <ul>
                    @foreach($permissions as $permission)
                        <li class="mb-6"><span>
                                <input
                                    value="{{$permission}}"
                                     wire:model="selectedPermissions"
                                    type="checkbox"
                                       class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
                                >
                            </span>
                            {{$permission}}
                        </li>

                    @endforeach

                </ul>

just like the roles section, we use wire:model="selectedPermissions" to put selected permissions in an array.

now we have the role and the permissions. we need to do the permission assignment.

for that we use livewire actions. define an action on the save button. like so:

<button wire:click="saveRolePermissions"
                class="text-white bg-danger-500 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg text-lg px-6 py-4">
            Save
</button>

wire:click="saveRolePermissions" means when you click on this element a method called saveRolePermissions will run in the component class.

therefore we need to define this function in the RolePermissionManagemen class:

    public function saveRolePermissions()
    {
        $selectedRoleModel = Role::where('name', $this->selectedRole)->first();

        $selectedRoleModel->syncPermissions($this->selectedPermissions);


    }

since we installed and used spatie/laravel-permission package it is very easy to assign an array of permissions to a role using syncPermissions method.

now if you click on a role, select permissions, and click on the save button the selected permissions will be assigned to the role.

we managed to assign permissions to a role.

if we refresh the page and click on a role no item is checked in thw Permissions box.

for this to work we need to add an action to the role so that by clicking on it, the related permissions in the permissions box show up.

Showing Each Role’s Permissions Dynamically

the Roles section code will change like this:

        <ul>
                    <select  wire:model="selectedRole" multiple class="w-full border-0">
                        @foreach($roles as $role)
                            <option wire:click="showPermissions('{{$role->name}}')">
                                {{$role->name}}

                            </option>

                        @endforeach

                    </select>

                </ul>

we only added wire:click attribute to run an action and inside the action we passed the role’s name.

finally, we define the action in the class:

public function showPermissions($roleName)
    {
        $this->selectedRole = $roleName;
        $this->selectedPermissions = Role::where('name', $roleName)->first()->permissions->pluck('name')->toArray();
      
    }

in this method first, we set the $selectedRole property. then we get the role’s permissions as an array to set the $selectedPermissions value.

check the page again we can see the related permissions for every role by clicking on them.

Full Code of View File and Page Class

view file:

<x-filament::page>


    <div class="grid grid-cols-2 " >
        <div class="mr-6">
            <div class="text-2xl mb-6 font-bold">Roles</div>
            <div class=" bg-white border-2 rounded-lg border-primary-500 p-1.5 w-full ">
                <ul>
                    <select  wire:model="selectedRole" multiple class="w-full border-0">
                        @foreach($roles as $role)
                            <option wire:click="showPermissions('{{$role->name}}')">
                                {{$role->name}}

                            </option>

                        @endforeach

                    </select>

                </ul>


            </div>

        </div>

        <div>
            <div class="text-2xl mb-6 font-bold">Permissions</div>
            <div class=" bg-white border-2 rounded-lg border-primary-500 p-1.5 w-full ">
                <ul >
                    @foreach($permissions as $permission)
                        <li class="mb-6"><span>
                                <input
                                    value="{{$permission}}"  wire:model="selectedPermissions"

                                    type="checkbox"
                                       class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
                                >
                            </span>
                            {{$permission}}
                        </li>

                    @endforeach

                </ul>


            </div>

        </div>

    </div>

    <div>
        <button wire:click="saveRolePermissions"
                class="text-white bg-danger-500 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg text-lg px-6 py-4">
            Save
        </button>
    </div>


</x-filament::page>

class:

<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class ManageRolePermissions extends Page
{
    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    protected static string $view = 'filament.pages.manage-role-permissions';

    public $roles;
    public $permissions;

    public $selectedRole;
    public $selectedPermissions;

    public function mount()
    {
        $this->roles = Role::all();
        $this->permissions = Permission::all()->pluck('name')->toArray();

        $this->selectedPermissions = [];

    }

    public function saveRolePermissions()
    {
        $selectedRoleModel = Role::where('name', $this->selectedRole)->first();

        $selectedRoleModel->syncPermissions($this->selectedPermissions);


    }

    public function showPermissions($roleName)
    {

        $this->selectedRole = $roleName; // Set the selectedRole
        $this->selectedPermissions = Role::where('name', $roleName)->first()->permissions->pluck('name')->toArray();


    }



}

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *