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!
based on the quote in the title "Why Panel?". Can you please give an example of a case? I think in this article, admin & accountant are 2 entities that are on the same project, just in different roles
That would be the most typical case I've seen actually: different panels for different user roles. Admin and accountant sound similar, but it's more different, for example, if it's Admin and Customer of the shop.
Sorry I still don't understand
are 2 panels used for different projects, for example: panel 1 for performance management projects and the second panel for online shop projects? (assuming the example is in 1 project / composer create laravel command)
or are these 2 panels used for the same project but different for the actors? or how ?
and I still don't understand your sentence "This means you can create and deploy a single Laravel and Filament application but have multiple "projects" inside it". could you please explain to me?
sorry for my misunderstanding
I am using the different Panels currently in my project one for Admin, so admin can see certain resources and pages and Client, so client will see other pages and resources. I am doing this cause its another way around if you dont want to deal up with roles and permissions and give each role a different design. For example, the Admin Loans resources and the client Loans resources are both different in terms of the information i want to display. You can use roles and permissions to achieve the same thing but I prefer to use Panels as it keeps my work clean and clearer to understand that a set of code with roles and permissions.
If we have many accountants, how do we show only specific information related to that accountant in the list, create, edit and view resources?
I would use Eloquent global scopes for this. Here's my video about Tenancy in general, part of that video answers your question.
Got it to work.
public static function getEloquentQuery(): Builder { return parent::getEloquentQuery()->whereBelongsTo(auth()->user()); }
https://filamentphp.com/docs/2.x/admin/resources/getting-started#customising-the-eloquent-query
I see when you create a resource that it is associated with only one panel. What if you want to have multiple panels that are accessing the same models and database tables and doing basically the same things, but just for different users or in different contexts? Are these multiple panels and resources using the same models and tables?
Yes. Model is often just a database connector, so you can use it in as many different resources as you need.
Looking at this lesson and the example of two login pages, the question arises, if a person logs in on one panel, is that effective for all panels in the application? If I login as an accountant, I won't then have to login again in the admin panel, will I? My access or lack of will be determined by authorization at that point? We still only have one cookie for the overall web site?
Thanks.
Yes!
Login is shared between ALL panels, but authorization gates prevent access as needed