Back to Course |
Filament 3 From Scratch: Practical Course

Multiple Panels: Admin and Accountant

Filament 3 also comes with the ability to create more than one Panel with it:

These panels are running on the same Filament project, using the same database. But they are completely independent of each other. This means that we can control the content of each Panel separately, and we can also control the layout of each Panel separately.


Why Panels?

Before we go into the details of how to create a multi-panel Filament project, let's first understand what a panel is and why we need it.

You can treat panels as independent projects inside your application. This means you can create and deploy a single Laravel and Filament application but have multiple "projects" inside it. Each project can have its own access level, configuration, design, and logic. This is very useful if you don't want to mess around with disabling and enabling specific actions. Your actions between panels might differ so much that it would be a pain to manage them in a single project.


Creating a New Panel

Creating a new panel is very simple. All you need to do is run the following command:

php artisan make:filament-panel {name}

In our case, we create a new panel named Accountant:

php artisan make:filament-panel Accountant

This will create a new file in app/Providers/Filament called AccountantPanelProvider. This file is responsible for registering the new Panel in Filament and configuring it:

app/Providers/Filament/AccountantPanelProvider.php

class AccountantPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('accountant')
->path('accountant')
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Accountant/Resources'), for: 'App\\Filament\\Accountant\\Resources')
->discoverPages(in: app_path('Filament/Accountant/Pages'), for: 'App\\Filament\\Accountant\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Accountant/Widgets'), for: 'App\\Filament\\Accountant\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}

Now, you can instantly access your new Panel by going to /accountant in your application:

From here, we can customize the Panel to our liking. In our case, we ended up with the following:

app/Providers/Filament/AccountantPanelProvider.php

public function panel(Panel $panel): Panel
{
return $panel
->id('accountant')
->path('accountant')
->login()
->brandName('Accounting Interface')
->colors([
'primary' => Color::Amber,
'primary' => Color::Green,
])
->topNavigation()
->discoverResources(in: app_path('Filament/Accountant/Resources'), for: 'App\\Filament\\Accountant\\Resources')
->discoverPages(in: app_path('Filament/Accountant/Pages'), for: 'App\\Filament\\Accountant\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Accountant/Widgets'), for: 'App\\Filament\\Accountant\\Widgets')
->widgets([])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}

Creating New Resources

Now that we have multiple panels - resource creation will look a bit different:

php artisan make:filament-resource Order --generate

This will ask us for the Panel we want to create the resource in:

We have typed accountant, and it created a new resource in app/Filament/Accountant/Resources/OrderResource.php:

Remember that it's not on the root of the app/Filament/Resources folder, but rather in the app/Filament/Accountant/Resources folder. This is because it is now separated per Panel! How cool is that?

Note: This also applies to pages and widgets!


Authorization

Loading our Accountant panel, we can see that there's no Orders resource. This is because we haven't authorized it yet:

We can use the same OrderPolicy class for both panels:

app/Policies/OrderPolicy.php

// ...
public function viewAny(User $user): bool
{
return $user->is_admin == 1 || $user->is_accountant == 1;
}
// ...

Or even better, we can do checks based on the Panel:

app/Policies/OrderPolicy.php

use Filament\Facades\Filament;
 
// ...
 
public function viewAny(User $user): bool
{
if (Filament::getCurrentPanel()->getId() === 'admin') {
return $user->is_admin == 1;
}
 
if (Filament::getCurrentPanel()->getId() === 'accountant') {
return $user->is_accountant == 1 || $user->is_admin == 1;
}
 
return false;
}

Once this is done, our new navigation item will appear:

That's it! We now have a multi-panel Filament project!