Advanced Tables (formerly known as Filter Sets) is a premium plugin for Filament that supercharges your tables with powerful features like user customizable views, enhanced filter tabs, reorderable columns, convenient view management, filter builder, and more.
Check out a short video of some of the powerful features included in Advanced Tables
See all the functionality that Advanced Tables has to offer in an interactive demo. It also includes a Configuration Playground so you can see many of the configuration options you can use to adapt the plugin to your needs.
At its core, Advanced Tables allows you to combine filters, grouping, toggled columns, and more into custom views that are just one click away. Users no longer have to rebuild their views each time they need to focus on a certain subset of their data. Advanced Tables gives your users fast access to the information they need.
With Advanced Tables, views can be set up in advance by the developer or they can be created on-the-fly by your end-users using Quick Save. And with Advanced Table’s View Manager, your users will be able to conveniently create, apply, edit, share, and sort their views right from the resource or table.
Best of all, Advanced Tables works with all of your Filament tables including Resource Tables, Relation Managers, Table Widgets, and standalone Table Builder.
Favorites Bar
View Manager (New)
Quick Save (New)
Column Reordering (New)
User Views Resource with Approval System (New)
View Manager in Table Toolbar (New)
Dark mode
Github theme (New)
Filament theme (New)
Links theme
Links Simple theme
Tabs theme
Tabs Simple theme
Thank you for purchasing Advanced Tables!
Below you'll find extensive documentation on installing and using this plugin. Of course, if you have any questions, find a bug, need support, or have a feature request, please don't hesitate to reach out to me at advancedtables@gmail.com.
Advanced Tables requires PHP 8.1+
, MySQL 5.7.8+
or Postgres
, Filament 3.2.4+
, and Laravel 10+
.
Advanced Tables v1 is fully compatible with
Filament v2
. After purchasing a license here, please refer to the Filter Sets v1 documentation for installation and usage instructions.
AdvancedTables uses AnyStack to handle payment, licensing, and distribution.
During the purchasing process, AnyStack will provide you with a license key. You will also be asked by AnyStack to activate your license by providing a domain
. This is usually the domain of where your final project will live. You’ll use this same domain to install locally and in production. Once you have provide a domain, your license key will be activated and you can proceed with installing with composer below.
Tip: If you missed this step, or if you need to add additional domains for other projects, you can access the activation page by going to Transactions in your AnyStack account and then clicking
View details
on the Advanced Tables product.
Tip: You will need both your
license key
and yourdomain
to authenticate when you install the package with composer.
To install Advanced Tables you'll need to add the package to your composer.json
file:
{ "repositories": [ { "type": "composer", "url": "https://filament-filter-sets.composer.sh" } ],}
Advanced Tables was formerly named Filament Filter Sets, but for compatibility with previous versions, the repository has maintained its original name.
Once the repository has been added to your composer.json file, you can install Advanced Tables like any other composer package using the composer require command:
composer require archilex/filament-filter-sets
Next, you will be prompted to provide your username and password.
Loading composer repositories with package informationAuthentication required (filament-filter-sets.composer.sh):Username: [licensee-email]Password: [license-key]
Your username will be your email address and the password will is your license key, followed by a colon (:), followed by the domain you are activating. For example, let's say we have the following email and license activation:
You will need to enter the above information as follows when prompted for your credentials:
Loading composer repositories with package informationAuthentication required (filament-filter-sets.composer.sh):Username: my_email@gmail.comPassword: 8c21df8f-6273-4932-b4ba-8bcc723ef500:my_domain.com
The license key and fingerprint should be separated by a colon (:).
Tip: If you get a
402 error
, most likely you forgot to add the colon and fingerprint.
If using Filament's standalone Table Builder, please refer to the Filament Table Builder setup instructions
Publish and run the migrations
Important: If you are using a User class other than Laravel's default
User::class
or a user's table other than Laravel's defaultusers
you should update these configurations before migrating.
php artisan vendor:publish --tag="advanced-tables-migrations"php artisan migrate
Publish the language files
Optionally, you may publish the language files:
php artisan vendor:publish --tag="advanced-tables-translations"
Add Advanced Tables to your Filament Panel
Add Advanced Tables to a panel by instantiating the plugin class and passing it to the plugin()
method of the configuration:
use Archilex\AdvancedTables\Plugin\AdvancedTablesPlugin;Â public function panel(Panel $panel): Panel{ return $panel ->plugins([ AdvancedTablesPlugin::make() ])}
Add the HasViews
trait to your User::class
use Archilex\AdvancedTables\Concerns\HasViews;Â class User{ use HasViews;}
Integrate Filter Set's Tailwind and css files
Filament v3 recommends developers create a custom theme to better support a plugin's additional Tailwind classes. After you have created your custom theme, add Advanced Tables' views to your new theme's tailwind.config.js
file usually located in resources/css/filament/admin/tailwind.config.js
:
content: [ ... './vendor/archilex/filament-filter-sets/**/*.php',],
Next, import Advanced Tables's custom stylesheet into your theme's css file:
@import '../../../../vendor/archilex/filament-filter-sets/resources/css/plugin.css';
Compile
Next, compile your theme:
npm run build
Finally, run the Filament upgrade command:
php artisan filament:upgrade
Setting up tenancy
If you are installing Advanced Tables into a multi-tenancy application, please refer to the separate instructions to set up multi-tenancy.
After you've successfully installed Advanced Tables, you may review the Getting Started guide to learn how to add Advanced Tables to your resources, relation managers, pages, and/or table widgets.
If using Filament Panels, please refer to the Filament Panels setup instructions.
Important: Beyond the normal requirements, using Advanced Tables with Filament Table Builder requires you have some type of user authentication system such as Laravel Breeze since each view belongs to the currently authenticated user.
Publish the config files
While optional, it is recommended you publish the config file to be able to fully customize Advanced Table. However, If you are using a User class other than Laravel's default User::class
or a user's table other than Laravel's default users
you should publish the config file and update these configurations before migrating.
php artisan vendor:publish --tag="advanced-tables-config"
Publish the language files
Optionally, publish the language files:
php artisan vendor:publish --tag="advanced-tables-translations"
Publish and run the migrations
php artisan vendor:publish --tag="advanced-tables-migrations"php artisan migrate
Add the HasViews
trait to your User::class
use Archilex\AdvancedTables\Concerns\HasViews;Â class User{ use HasViews;}
Integrate Advanced Tables's custom css file
Add the following line to the top of your app.css
file:
@import '../../vendor/archilex/filament-filter-sets/resources/dist/advanced-tables.css';
Compile
Next, compile your theme:
npm run build
Finally, run the Filament upgrade command:
php artisan filament:upgrade
Setting up tenancy
If you are installing Advanced Tables into a multi-tenancy application, please refer to the separate instructions to set up multi-tenancy.
After you've successfully installed Advanced Tables, you may review the Getting Started guide to learn how to add Advanced Tables to your tables.
When deploying, it is not advised to store your `auth.json`` file inside your project's version control repository. To store your credentials on your deployment server you may create a Composer auth.json file in your project directory using the following command:
composer config http-basic.filament-filter-sets.composer.sh your_account_email your_license_key_including_your_fingerprint_domain
Important: Don't forget to append a colon (:) and your fingerprint domain to your password.
You can see your credentials in your Anystack account: Anystack > Transactions > View details
next to Filament Filter Sets.
Tip: Make sure the
auth.json
file is in.gitignore
to avoid leaking credentials into your git history.
If you are using Laravel Forge, you don't need to create the auth.json
file manually. Instead, you can set the credentials on the Composer Package Authentication
screen of your server.
The most common mistake when deploying, is not adding the colon (:) followed by the domain you registered. license_key:domain
. Please review the instructions above.
If you have set up everything correctly and are getting the error: ../advanced-tables-for-filament-3.7.29.zip' URL required authentication (HTTP 401). You must be using the interactive console to authenticate
error, you may need to ssh into your server and clear your composer global cache with composer clear-cache
Advanced Tables v3 is the biggest release since it's initial launch and contains numerous improvements over v1 and v2. Here are some of the exciting new features:
Color::class
Advanced Tables is almost a complete rewrite of previous releases and thus requires numerous changes to completely upgrade. I've tried to document every required change, but if you have issues or if I have missed a step, please reach out to me at advancedtables@gmail.com.
Before you begin, be sure to follow the setup instructions for Filament panels or Table Builder.
Due to the namespace changes, you may need to update your old migrations to use the new namespacing. If you are updating a local project and you have not yet deployed to production, you can just delete the old migrations and publish the new ones.
However, if you have already deployed to your production server, you will most likely need to update your local migrations so you don't run into errors when trying to migrate:fresh
:
In your local yyyy_mm_dd_xxxxxx_create_filament_filter_sets_table
and your yyyy_mm_dd_xxxxxx_create_filament_filter_set_user_table
migrations, change:
use Archilex\FilamentFilterSets\Support\Config;
to use Archilex\AdvancedTables\Support\Config;
If you wish you can also update the deprecated methods in both migration files:
Change $userClass = Config::getUserModelName();
to $userClass = Config::getUser();
Important: If you have already deployed to your production server, do NOT delete and republish these two migration files. Doing this will create new migration files and when deploying to production you will encounter errors as the database tables have already been created.
The previous FilterSetFilter
that lived in the filters
dropdown has replaced by the Quick Save button to save new views and the View Manager to select and manage them. This means you should remove the FilterSetFilter
and its imported class use Archilex\FilamentFilterSets\Filters\FilterSetFilter
from each of your tables.
It will also be important for you to educate your end-users accordingly.
The entry point to using Advanced Tables is now the AdvancedTables
trait which replaces the previous HasFavorites
trait. Remove the previous trait and class import and add the new one.
// use Archilex\FilamentFilterSets\Concerns\HasFavorites;use Archilex\AdvancedTables\AdvancedTables;Â class ListUsers extends ListRecords{ // use HasFavorites; use AdvancedTables;
Important: Previously, you would only need to use the
HasFavorites
trait if you wanted to use the Favorites Bar on a table. As of v3, theAdvancedTables
trait is the main entry point for the plugin. This means that anywhere you were usingFilterSetFilter
without the respectiveHasFavorite
trait you will now need to add theAdvancedTables
trait to the appropriate class, usuallyList*
orManage*
.
Filament v3 now uses Heroicons v2. If you are upgrading from Filter Sets v1 and you and/or your users were using icons with their views, these icons will need to be updated. Advanced Tables includes a helper service that you may enable to automatically convert icons stored in the database on the fly. You can enable this helper by adding the convertIcons()
method to the AdvancedTablesPlugin
object inside your PanelProvider
:
public function panel(Panel $panel): Panel{ return $panel ->plugins([ AdvancedTablesPlugin::make() ->convertIcons() ])
The helper service exists to get you up and running as quickly as possible. However, when convenient, it's recommended you implement your own script to update the icons directly in your database and then disable this helper.
Developer-created Filter Sets are now Preset Views and should be updated accordingly:
getFilterSets()
should be renamed to getPresetViews()
.FilterSet
object should be renamed to PresetView
and it's class imported.array key
.toggledColumns
has been renamed to defaultColumns
.favorite()
method.Before
use Archilex\FilamentFilterSets\Components\FilterSet;Â class ListUsers extends ListRecords{ public function getFilterSets(): array { return [ FilterSet::make('Delivered this month') ->query(fn ($query) => $query->where('status', 'delivered')) ->toggledColumns(['id', 'name']) ]; }}
After
use Archilex\AdvancedTables\Components\PresetView;Â class ListUsers extends ListRecords{ public function getPresetViews(): array { return [ 'delivered_this_month' => PresetView::make() ->label('Delivered') ->query(fn ($query) => $query->where('status', 'delivered')) ->defaultColumns(['id', 'name']) ->favorite() ]; }}
Important: Be sure that any column included in
defaultColumns
is present in on thecolumns
method of your table.
Since users can now edit, delete, and sort their views in the View Manager, the User Views Resource (formerly Filter Set Resource) has been updated to be a tool exclusively for admin users as it now lists every user's views. You will most likely want to limit access to this resource to admins.
Since the new View Manager displays all views, including Preset Views, combining Developer-created Filter Sets into a dropdown using the showDeveloperFilterSetsAsDropdown
method is now redundant. However, if needed, you may enable this functionality using the presetViewLegacyDropdown()
method:
AdvancedTablesPlugin::make() ->presetViewLegacyDropdown()
All of the customizations that were previously managed in the filament-filter-sets.php
config file are now managed on the AdvancedTablesPlugin
object inside your PanelProvider
. For easy reference, here are the previous customization options linked to their respective sections in the documentation:
Note: If you are using the standalone Table Builder the configurations are handled in the new
advanced-tables.php
config file.
The language files have been completely reworked to match the new terminology. Since the language files have been renamed, there isn't a risk of missing translations, but if you had previously published and modified your language files, you will need to publish and update the new ones.
Now that you've successfully upgraded, be sure to take a look at all the new features for additional options.
To use Advanced Tables you will need to add the AdvancedTables
trait to the appropriate class depending on whether you intend to use it on a Resource Table, Simple Resource Table, Table Widget, or Panel Page.
Important: For standalone Table Builder users, please refer to the documentation for using Advanced Tables with Table Builder.
To add Advanced Tables to a normal Resource table, add the AdvancedTables
trait to the List page of your Resource
:
use Archilex\AdvancedTables;Â class ListProducts extends ListRecords{ use AdvancedTables;
To add Advanced Tables to a Simple (modal) resource table, add the AdvancedTables
trait to the Manage page
:
use Archilex\AdvancedTables;Â class ManagesCustomers extends ListRecords{ use AdvancedTables;
To add Advanced Tables to a Table Widget, add the AdvancedTables
trait to the Table widget:
use Archilex\AdvancedTables;Â class LatestOrders extends BaseWidget{ use AdvancedTables;
To add Advanced Tables to a Panel Page, you need to add the AdvancedTables
trait to your component. However, as Advanced Tables overrides multiple methods in Filament's InteractsWithTables
trait, adding the AdvancedTables
trait to the table will cause a conflict.
For convenience, Advanced Tables includes a PanelPage
class which you can use to quickly get up and running:
use Archilex\AdvancedTables\AdvancedTables;use Archilex\AdvancedTables\Livewire\PanelPage;Â class CustomPage extends PanelPage{ use AdvancedTables;Â ...
Of course, there are multiple ways to prevent the trait conflict. The important part is to ensure that the AdvancedTables
trait is used on a class that extends another class which contains Filament's InteractsWithTables
trait.
You also need to add the Favorites Bar component to your panel page's blade file:
<div class="space-y-6">Â <x-advanced-tables::favorites-bar />Â {{ $this->table }}</div>
The Favorites Bar expects a space of 24px
to properly display it's links. This can easily be achieved with Tailwind's space-y-6
class as shown above.
Advanced Tables supports both User Views and Preset Views. Understanding the difference is important to choosing if one or both is appropriate for your application.
User Views are created by your end-users using your application's UI. An end-user chooses the appropriate filters, toggled columns, column order, column sort, table grouping, etc. to build the view they need. Then they use Advanced Tables to save that view so they have easy access to it in the future. Since each user has different needs, this allows for infinite customization within your application. (And less work for developers!)
Preset Views are views that you the developer write in code and are then available to all your users, (or the users you authorize). Preset Views exposes a query()
api which allows you to modify the underlying eloquent query. This means you can "filter" a table's data without needing to have that filter on your table.
However, while being able to modify the underlying eloquent query is powerful, and in some cases might be the only way to filter a table, Advanced Tables v3 introduces a new filters()
api which allows you to apply values to your existing table filters. This, in turn, offers a better UX for your end-users as they will then see filter indicators in the table and will better understand how a Preset View is modifying the data.
Whether used independently or together, User Views and Preset Views give your end-users quick access to the data they need.
User Views are views created by your end-users using your application's UI. An end-user chooses the appropriate filters, toggled columns, column order, column sort, table grouping, etc. to build the view they need. Then they use Advanced Tables to save that view so they have easy access to it in the future. Since each user has different needs, this allows for infinite customization within your application. (And less work for developers!)
To save a User View:
+
in the top right corner of the table.When creating a user view the following configurations will be saved:
The View Manager allows a user to edit a User View's name, icon, color, and/or visibility.
Edit view
.Save changes
To change the configuration of filters, columns, grouping, etc. see Editing a User View's table configuration
To update a User View's table configuration of filters, columns, grouping, etc. you can use the Replace view
action:
Replace view
.Replacing a view will overwrite the existing view with the current table's configuration.
If you would like to just update the name, icon, color, and/or visibility of a view, see Editing a User View's name, icon, color or visibility
User views can be deleted in the View Manager using the view's action button.
User views can be sorted in the View Manager. Refer to the section Sorting views of the View Manager for additional details.
Advanced Tables offers multiple ways to customize User Views. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
:
public function panel(Panel $panel): Panel{ return $panel ->plugins([ AdvancedTablesPlugin::make() ->userViewsEnabled(false) ])
User Views are enabled by default. However, if you are not going to use User Views, you should disable them to prevent unnecessary database queries:
AdvancedTablesPlugin::make() ->userViewsEnabled(false)
The UserView
model is responsable for storing all the configuration settings for each User View. If you need to extend this class, you may pass your custom class to userView()
:
AdvancedTablesPlugin::make() ->userView(MyCustomUserView::class)
The ManagedUserView
model is responsable for managing the visibility and sort order between a User
and a UserView
. If you need to extend this class, you may pass your custom class to managedUserView()
:
AdvancedTablesPlugin::make() ->managedUserView(myCustomManagedUserView::class)
You may disable the icon picker in the Save View/Edit View slideOver by passing false
to the quickSaveIconSelect()
method:
AdvancedTablesPlugin::make() ->quickSaveIconSelect(false)
You may also use policies to configure who can use the icon picker.
By default the icon picker loads all of heroicons solid and outline icons. You may exclude either solid or outline icons by passing false to either the quickSaveIncludeOutlineIcons()
or quickSaveIncludeSolidIcons()
methods:
AdvancedTablesPlugin::make() ->quickSaveIncludeSolidIcons(false)
Important: Since icons are cached, after updating you will need to clear your cache to see the change with
php artisan cache:clear
.
By default, the color picker will include Filament's default colors, primary
, success
, info
, warning
, danger
, gray
. To configure the available colors, pass an array of colors to ->quickSaveColors()
:
AdvancedTablesPlugin::make() ->quickSaveColors([ 'primary', 'warning', 'gray', ])
You may also include any extra colors you have previously registered in Filament:
AdvancedTablesPlugin::make() ->quickSaveColors([ 'primary', 'success', 'indigo', 'pink', 'zinc', ])
You may disable the color picker in the Save View/Edit View slideOver by passing false
to the ->quickSaveColorPicker()
method:
AdvancedTablesPlugin::make() ->quickSaveColorPicker(false)
You may also use policies to configure who can use the color picker.
By default, when creating/editing a view, users can favorite their views by toggling on Add to favorites
. Favorite views are added to the Favorites Bar and appear above the table. Refer to the Favorites Bar section for additional details.
You may disable the ability to make a User View favorite by passing false
to the ->quickSaveMakeFavorite()
method:
AdvancedTablesPlugin::make() ->quickSaveMakeFavorite(false)
You may also use policies to configure who can make views favorite.
By default, when creating/editing views, users can share their views with other users by toggling on make public
. Public views will appear in other user's View Manager where they can then be added to their favorites if they wish.
Advanced Tables also has an approval system so admins can approve public views before they are visible to other users.
You may disable the ability to make a User View public using the ->quickSaveMakePublic()
method:
AdvancedTablesPlugin::make() ->quickSaveMakePublic(false)
You may also use policies to configure who can make views public.
Making a User View a global favorite automatically adds it to every user's Favorites Bar. As this is an action usually reserved for admin users, this functionality is turned off by default. You may enable the ability to make a User View a global public using the ->quickSaveMakeGlobalFavorite()
method:
AdvancedTablesPlugin::make() ->quickSaveMakeGlobalFavorite()
After enabling, you may use policies to further configure who can make views global favorites.
Advanced Tables also has an approval system so admins can approve global favorite views before they are visible to other users.
As previously mentioned, when an admin or user creates a global favorite view, that view is added to all user's Favorites Bar. By default, these global views can then be managed (ie. sort and favorite/un-favorite) independently by each user. If you need to disable management of global User View you may do so by passing false
to the ->globalUserViewsManageable()
method:
AdvancedTablesPlugin::make() ->globalUserViewsManageable(false)
By disabling globalUserViewsManageable
, global favorites will be not be able to be sorted nor removed from a user's Favorites Bar.
When global favorite management is disabled, all global favorites are added before any User Views that a user has favorited. However, when global view management is enabled, a user is then free to reorder them, placing global views before, after, or in between their own user-favorited views. Now, when a new global view is created by an admin, a decision needs to be made as to whether this new global view should be placed before
or after
the user's previously ordered favorite views. By default new global views are positioned before
a user's favorited views, however this can be configured using the newGlobalUserViewSortPosition()
method:
AdvancedTablesPlugin::make() ->newGlobalUserViewSortPosition('after')
When creating/editing User Views you may show/hide helper text to help guide your end-users during the process. By default, helper text is only displayed for the Favorite, Public, and Global Favorite toggles.
AdvancedTablesPlugin::make() ->quickSaveNameHelperText(false) ->quickSaveFiltersHelperText(false) ->quickSavePublicHelperText(false) ->quickSaveFavoriteHelperText(false) ->quickSaveGlobalFavoriteHelperText(false)
You may configure the wording of each helper text by modifying the language file.
Advanced Tables includes a simple approval mechanism to allow admins to approve/reject public and global favorites before they are made available to other users.
Advanced Tables uses Filament's enum to define the Status
constants:
enum Status: string implements HasLabel, HasColor{ case Approved = 'approved'; case Pending = 'pending'; case Rejected = 'rejected';
To use the approval system, first, set the User View's initialStatus()
to either Status::Approved
, Status::Pending
, or Status::Rejected
. By default, each User View has an initial status of Status::Pending
:
AdvancedTablesPlugin::make() ->initialStatus(Archilex\AdvancedTables\Enums\Status::Rejected)
Then, set the minimumStatusForDisplay()
to either Status::Approved
, Status::Pending
, or Status::Rejected
. By default, the minimal status is Status::Pending
:
AdvancedTablesPlugin::make() ->minimumStatusForDisplay(Archilex\AdvancedTables\Enums\Status::Approved)
When a User View's status is the equal or greater than the minimumStatusForDisplay()
, it will be displayed to other users.
Advanced Tables default setting of Pending
for both Status
and minimumStatusForDisplay
means that all public and global User Views will automatically be displayed to other users, effectively bypassing the approval system. Changes only need to be made if you would like to enable the approval system.
To update the status of a User View, admin should use the User Views Resource.
Of course, Laravel's Observers can be implemented on the UserView
model to further expand the approval system with database or email notifications.
Persisting the active User View to the session allows a user to navigate away from the table and then return to the table with the same view selected. You may enable this by using the ->persistActiveViewInSession()
method:
AdvancedTablesPlugin::make() ->persistActiveViewInSession()
In addition to User Views, developers can also programmatically create Preset Views in code that can be deployed to all users. Preset Views exposes a query()
api which allows you to modify the underlying eloquent query. This means you can "filter" a table's data without needing to have that filter on your table.
However, while being able to modify the underlying eloquent query is powerful, and in some cases might be the only way to filter a table, Advanced Tables v3 introduces a new defaultFilters()
api which allows you to apply values to your table filters. This, in turn, offers a better UX for your end-users as they will then see filter indicators in the table and will better understand how a Preset View is modifying the data.
For more information on the difference between User Views and Preset Views please refer to Core Concept: User Views vs Preset Views
Filament v3 introduced Filter Tabs
which also allows developers to programmatically filter their data in tabs. While similar, Advanced Tables' Preset Views offers multiple additional features:
To create a Preset View, add the getPresetView()
method to your List*
, Manage*
, or table widget class.
use Archilex\AdvancedTables\Components\PresetView;use Archilex\AdvancedTables\AdvancedTables;Â class ListOrders extends ListRecords{ use AdvancedTables;Â public function getPresetViews(): array { return [ 'processing' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')), 'delivered' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->where('status', 'delivered')), ]; }}
The Preset View modifyQueryUsing()
method modifies your original eloquent query by applying the scopes and conditions you configure.
By default the array keys will be used as the labels for each Preset View. This may be configured by passing a label into the make()
method:
'processing' => PresetView::make('Processing orders') ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')) ->favorite(),
If you prefer, you may also use the label()
method:
'processing' => PresetView::make() ->label('Processing orders') ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')) ->favorite(),
By default, Preset Views are added to the View Manager in the Preset View section. To add a Preset View to the Favorites Bar use the favorite()
method:
'processing' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')) ->favorite(),
Due to the fundamental difference between User Views and Preset Views, favorited Preset Views always appear before a User Views in the Favorites Bar.
Similar to User Views, Preset Views may have icons:
'processing' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')) ->icon('heroicon-o-refresh'),
By default the icon will be displayed before the name. This can be configured in the Favorites Bar settings.
Similar to User Views, Preset Views may be displayed in a color.
'processing' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->where('status', 'processing')) ->color('warning'),
You may choose any of Filament's default colors, primary
, success
, info
, warning
, danger
, gray
.
You may also include any extra colors you have previously registered in Filament:
Preset Views can display a badge after the label by passing a string into the badge()
method:
'processing' => PresetView::make() ->badge(Order::query()->where('status', 'processing')->count())
The color of a badge may be changed using the badgeColor()
method:
'processing' => PresetView::make() ->badge(Order::query()->where('status', 'processing')->count()) ->badgeColor('warning')
Tip: If you want to display multiple badges, you should generate one query separately and then use Laravel collections to filter and count them.
Preset Views can display a tooltip when hovered over in the Favorites Bar by passing a string into the tooltip()
method.:
'lowStock' => PresetView::make() ->modifyQueryUsing(Product::query()->where('price', '>', 1000)->where('qty', '<', 5)) ->tooltip('High price products with low stock')
You may conditionally show or hide Preset Views for certain users using either the visible()
or hidden()
methods, passing a closure:
'processing' => PresetView::make() ->visible(fn (): bool => auth()->isAdmin())
You can also use a Laravel policy to manage visibility:
'processing' => PresetView::make() ->visible(fn (Order $record): bool => auth()->user()->can('viewProcessing', $record)),
And then in OrderPolicy
:
public function viewProcessing(User $user){ return $user->isAdmin();}
Tip: If your policy is not working, be sure to register it in
AuthServiceProvider
as sometimes Laravel does not successfully auto-register policies.
You can apply values to your table filters from your Preset Views with the defaultFilters()
method:
'new_this_quarter' => PresetView::make() ->defaultFilters([ 'status' => [ 'value' => 'new', ], 'created_at' => [ 'range' => 'this_quarter', ], ])
Using the defaultFilters()
api gives your users a better understanding of how a Preset View is filtering the data by turning on Filament's filter indicators.
Tip: The easiest way to know how to properly form your filter array is to apply the desired filter to your table and then
dd($this->tableFilters)
at the top of thegetPresetViews()
method.
If you are using Advanced Filter Builder, you should use the following syntax to define your default filters:
'follow_up' => PresetView::make() ->defaultFilters([ 'advanced_filter_builder' => [ [ // filter group 1 'status' => [ 'value' => 'new' ], 'created_at' => [ 'range' => 'this_month', ], ], [ // filter group 2 (ie: "or") 'status' => [ 'value' => 'cancelled' ], 'created_at' => [ 'range' => 'last_month', ], ], ], ])
If the example above, this will create the following query scope: new orders made this month
OR cancelled orders made last month
.
Tip: The easiest way to know how to properly form your filter array is to apply the desired filter to your table and then
dd($this->tableFilters)
at the top of thegetPresetViews()
method.
If you are using the builder's Column Filters, then you will need to add the applicable values. For example:
'this_quarter' => PresetView::make() ->defaultFilters([ 'advanced_filter_builder' => [ [ // filter group 1 'created_at' => [ 'column' => 'created_at', 'operator' => 'in_the_last', 'value' => 1, 'unit' => 'quarters', ], ], ], ])
Tip: Many of the column filters have multiple
keys
such asdate_start
,date_end
, etc. You only need to add the values that you are setting for the filter.
You can apply one of your table groupings to your Preset View with the defaultGrouping()
method:
'new_this_quarter' => PresetView::make() ->defaultGrouping('created_at', 'desc')
Preset Views can toggle columns, and, if Reorderable Columns are enabled, can reorder them as well using the defaultColumns()
method:
'processing' => PresetView::make() ->defaultColumns(['id', 'status', 'customer.name', 'created_at'])
Columns will be saved in the following ways:
defaultColumns()
array.toggleable()
, it will be hidden.toggleable()
, it will be added to the end of the table.If a column is sortable, you may choose it as the default sort column for your table using the defaultSort()
method:
'processing' => PresetView::make() ->defaultSort('total_price')
By default, sorting is ascending, but you may choose descending as well ->defaultSort('total_price', 'desc')
.
Tip: While it is possible to add
orderBy()
to your query to sort your table, usingdefaultSort()
is recommended as it will correctly show the sorting indicator on the table column.
If Multi-Sort is enabled, you may multi-sort your preset views through the same defaultSort()
method. Just pass an array of columns and their sort direction to defaultSort()
:
'processing' => PresetView::make() ->defaultSort([ 'is_visible' => 'desc', 'price' => 'asc' ])
You may choose one of your Preset Views as the default view when loading the page by using the default()
method:
'processing' => PresetView::make() ->default()
default()
can take a callback which can allow you to dynamically choose which Preset View is the default based on the conditions you choose. The first Preset View that returns true
will be the view that is loaded by default.
By default, when an end-users clicks a Preset View, the filters, toggled columns, sort column, and sort direction that a user has already applied to a table will be removed in favor of the Preset View's configuration. This is usually the desired behavior as Preset Views are meant to be customized views into data. However in some instances, you may wish to preserve the user's selected filters, columns, etc. To do this you may use preserveAll()
.
'processing' => PresetView::make() ->preserveAll()
If you need more fine-grained control you may use the individual methods:
'processing' => PresetView::make() ->preserveFilters() ->preserveToggledColumns() ->preserveSortColumn() ->preserveSortDirection()
Note: By preserving a user's selection you are in turn removing the option for a Preset View to always take a user to that view's predefined configuration as that view is now affected by the user.
Advanced Tables offers multiple ways to customize Preset Views. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
:
public function panel(Panel $panel): Panel{ return $panel ->plugins([ AdvancedTablesPlugin::make() ->createUsingPresetView(false) ])
The ManagedPresetView
class is responsable for storing the visibility and sorting configurations between a User
and a PresetView
If you need to extend this class, you may pass your custom class to managedPresetView()
:
AdvancedTablesPlugin::make() ->managedPresetView(myCustomManagedPresetView::class)
By default, Preset Views will be sorted in the order they are added to the getPresetViews()
array. Similarly, any Preset View that has the favorite()
method will be displayed by default in the end-user's Favorites Bar, and any Preset View without favorite()
will be displayed in the View Manager.
Advanced Tables v3 now allows Preset Views to be managed by the end-user. Users can sort Preset Views as well as add/remove them from the Favorites Bar.
If you need to disable Preset View management you may do so by passing false
to the ->globalUserViewsManageable()
method:
AdvancedTablesPlugin::make() ->presetViewsManageable(false)
By disabling presetViewsManageable
, Preset Views will be not be able to be sorted nor added/removed from a user's Favorites Bar.
When Preset View management is enabled, a user is free to reorder, add or remove them from their Favorites Bar. Now, when a new Preset View is added in code and then deployed to the user, a decision needs to be made as to whether this new Preset View should be placed before
or after
the user's previously ordered Preset Views. By default new Preset Views are positioned before
a user's current Preset View ordering, however this can be configured using the newPresetViewSortPosition()
method:
AdvancedTablesPlugin::make() ->newPresetViewSortPosition('after')
Persisting the active Preset View to the session allows a user to navigate away from the table and then return to the table with the same view selected. You may enable this by using the ->persistActiveViewInSession()
method in your Panel Provider
:
AdvancedTablesPlugin::make() ->persistActiveViewInSession()
Enabling both Preset Views and User Views has the potential of causing confusion with end-users if they create a User View on top of a Preset View. This is because a Preset View can "filter" the table using the query()
method which doesn't correspond to any filter on the table. This means that when a user builds a User View using a Preset View as its base, there's no way for the user to "turn off" the filter scope.
While Advanced Tables has multiple options you can use to mitigate these potential issues, the easiest way around this issue is to not use the query()
method and instead use the defaultFilters()
method. This way, even when a user creates a User View based on a Preset View, they are in full control of data.
However, if you still need, or prefer, to use the query()
method to filter your data, you can use these options to help avoid confusion. These configurations should be applied to the AdvancedTablesPlugin
in your Panel Provider
.
You can disable the creation of User Views all together when a Preset View is selected. If disabled, when a user clicks the Quick Save Button, a Filament notification will be displayed explaining that this action is not possible. The text of the notification can be configured in the language file.
AdvancedTablesPlugin::make() ->createUsingPresetView(false)
You can optionally display a divider line between Preset Views and User Views to help visually distinguish between the two.
AdvancedTablesPlugin::make() ->favoritesBarDivider()
You can optionally display an icon next to a Preset View to help visually distinguish between the two.
AdvancedTablesPlugin::make() ->presetViewLockIcon()
By default heroicon-o-lock-closed
will be used, however you may pass any heroicon icon to the method:
AdvancedTablesPlugin::make() ->presetViewLockIcon('heroicon-o-star')
Another option to help a user know how a Preset View is modifying the query is to use the ->indicator()
method on the Preset View:
'honor_roll_students' => PresetView::make() ->modifyQueryUsing(fn ($query) => $query->perfectAttendance() ->perfectGrades() ->withoutBehaviorReports() ) ->indicator('students with perfect attendance, grades, and behavior')
By adding a string of text to the indicator()
method, a new badge with the selected text will be displayed in the View Summary when creating a new view.
Finally, you can display helper text in the slideOver or modal that explains that the user has chosen a Preset View as the base for their User View and that the filtering applied in the Preset View set cannot be removed. This text can be configured in the language file.
AdvancedTablesPlugin::make() ->quickSaveActivePresetViewHelperText()
Version 1 of Advanced Tables (Filter Sets), introduced the ability to show Preset Views in a dropdown. This has been deprecated in favor of the View Manager, however if you would still like to display it you may do so with the presetViewLegacyDropdown()
method:
AdvancedTablesPlugin::make() ->presetViewLegacyDropdown()
If you using the legacy dropdown, you may also want to disable the view manager.
The Favorites Bar is home to all of a user's favorite views as well as Quick Save and View Manager. The Favorites Bar can be customized in a variety of ways to match the needs of your application.
Unless specified otherwise, these customizations can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
Advanced Tables includes six different themes for the Favorites Bar:
You can change the theme with the 'favoritesBarTheme()` method:
use Archilex\AdvancedTables\Enums\FavoritesBarTheme;Â AdvancedTablesPlugin::make() ->favoritesBarTheme(FavoritesBarTheme::Filament)
You may also use the corresponding string instead:
AdvancedTablesPlugin::make() ->favoritesBarTheme('filament')
Note: Since
links-simple
only has color to visually distinguish between active and in-active states, it is recommended you disable the ability to select a color for their User Views since it becomes difficult to know which link is active.
You may change the size of the Favorites Bar links to allow more links to be shown with the favoritesBarSize()
method:
use Filament\Support\Enums\ActionSize;Â AdvancedTablesPlugin::make() ->favoritesBarSize(ActionSize::Small)
Available sizes are: ActionSize::Small
and ActionSize::Medium
.
You may change the position of a view's icon in the Favorites Bar using the favoritesBarIconPosition()
method:
use Filament\Support\Enums\IconPosition;Â AdvancedTablesPlugin::make() ->favoritesBarIconPosition(IconPosition::Before)
By default, the Favorites Bar includes a Default View (previously named All). Clicking this will completely reset the table back to its default settings. You may disable the Default View using the favoritesBarDefaultView()
method:
AdvancedTablesPlugin::make() ->favoritesBarDefaultView(false)
You may also disable the Default View per resource by overriding the hasDefaultView()
method in the class where you have added the AdvancedTables trait:
public function hasDefaultView(): bool{ return false;}
Note: In prior versions this view was named
All
, however when clicking this view, it actually resets the table to it's default settings, which may or may not contain all the records. For this reason, it was renamed todefault
in version 3. However, you may change the name of the Default View in the language file.
Tip: If you need an
All
button in addition/instead of aDefault
button, you can easily create a Preset View that shows the data you need.
You may change the icon used for the Default View using the favoritesBarDefaultIcon()
method:
AdvancedTablesPlugin::make() ->favoritesBarDefaultIcon('heroicon-o-home')
To remove the Default View icon, don't pass anything to the method: favoritesBarDefaultIcon()
If using both Preset Views and User Views, it may be helpful to have a divider line to help users visually distinguish between the two. You may use the favoritesBarDivider()
method to enable this:
AdvancedTablesPlugin::make() ->favoritesBarDivider()
For more ways to distinguish between Preset Views and Users Views, please read the section Distinguishing between Preset Views and Users Views
You may show a loading indicator when switching between views by using the favoritesBarLoadingIndicator()
method:
AdvancedTablesPlugin::make() ->favoritesBarLoadingIndicator()
Advanced Tables offers a quick way for end-users to save User Views with the Quick Save button. Quick Save can be customized in a variety of ways to match the needs of your application.
Advanced Tables offers multiple ways to customize Quick Save. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
You may disable User Views entirely which will also remove the Quick Save button by passing false
to the userViewsEnabled()
method:
AdvancedTablesPlugin::make() ->userViewsEnabled(false)
However, by disabling User Views, you also disable public and global favorite User Views. If you wish to just hide the Quick Save button for certain users, you should use policies.
You can disable the Favorites Bar entirely (helpful if you only want to use reorderable columns) by passing false
to the favoritesBarEnabled()
method:
AdvancedTablesPlugin::make() ->favoritesBarEnabled(false)
You may also configure this per table by overriding the favoritesBarIsEnabled()
method on your List page:
class ListOrders extends ListRecords{ use AdvancedTables;Â public static function favoritesBarIsEnabled(): bool { return false; } ...
You may change the icon of the Quick Save button using the icon
argument of the quickSaveInFavoritesBar()
method:
AdvancedTablesPlugin::make() ->quickSaveInFavoritesBar(icon: 'heroicon-o-bookmark')
Note: The Quick Save icon only applies when the button is in the Favorites Bar.
By default, Quick Save is at the end of the Favorites Bar. You may position it at the start of the Favorites Bar using the quickSaveInFavoritesBar()
method:
AdvancedTablesPlugin::make() ->quickSaveInFavoritesBar(position: 'start')
By default, Quick Save is displayed in the Favorites Bar. You may display it in the toolbar by passing false
to the quickSaveInFavoritesBar()
method and adding the quickSaveInTable() method:
AdvancedTablesPlugin::make() ->quickSaveInFavoritesBar(false) ->quickSaveInTable()
By default, Quick Save will open it's form in a slideOver. You may display the form in a modal by passing false
to the quickSaveSlideOver()
method:
AdvancedTablesPlugin::make() ->quickSaveSlideOver(false)
Advanced Tables' View Manager is an easy and convenient way for your end-users to manage all of the views available for the table. Users can quickly search, apply, sort, edit, delete, add to favorites, and more, all from the View Manager. The View Manager can be customized in a variety of ways to match the needs of your application.
The View Manager allows end-users to access, apply, edit, sort, and manage all the available table views, including Preset Views, public views, and global favorites. Depending on which views are enabled, the view manager can display up to five different sections:
Next to each view is an action button that gives the user several options depending on the type of view:
User favorites, User views, and Preset views can be sorted by clicking the up/down arrows and then dragging/dropping the view to the desired location. Each view will be confined to it's section.
Important: If the User Favorites section contains both Preset Views and User Views, Preset Views will always come first, followed by User Views. These two types of views can only be sorted within their respective groupings. In other words, Preset Views can only be sorted among other Preset Views, and User Views can only be sorted among other User Views.
Advanced Tables offers multiple ways to customize the View Manager. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
By default, View Manager is displayed at the end of the Favorites Bar. You may position it at the start of the Favorites Bar using the viewManagerInFavoritesBar()
method:
AdvancedTablesPlugin::make() ->viewManagerInFavoritesBar(position: 'start')
By default, View Manager is displayed in the Favorites Bar. You may display it in the toolbar by passing false
to the viewManagerInFavoritesBar()
method and adding the viewManagerInTable() method:
AdvancedTablesPlugin::make() ->viewManagerInFavoritesBar(false) ->viewManagerInTable()
By default, View Manager is displayed after the search field. You may display at any of the tooldbar positions available via Filament's toolbar renderhooks by passing the renderhook to the position
property in the viewManagerInTable()
method:
AdvancedTablesPlugin::make() ->viewManagerInTable(position: 'tables::toolbar.toggle-column-trigger.before')
By default, View Manager is displayed as a icon button. You may display it as a button with a label by using the viewManagerButton()
method:
AdvancedTablesPlugin::make() ->viewManagerButton(label: 'Views')
You may change the size of the View Manager's button and icon using the viewManagerButtonSize()
method:
AdvancedTablesPlugin::make() ->viewManagerButtonSize('lg')
If you are displaying the View Manager as button you may display it outlined by using the viewManagerButtonOutlined()
method:
AdvancedTablesPlugin::make() ->viewManagerButtonOutlined()
By default, View Manager is displayed as a dropdown. You may display it as a slideOver by adding the viewManagerSlideOver()
method:
AdvancedTablesPlugin::make() ->viewManagerSlideOver()
Internally, when displaying View Manager as a slideOver, Advanced Tables only has to query and select from the database the user's favorite views as they are the only views show in the table. Since Filament only processes the content in slideOvers when they are triggered by an action button, the remaining views aren't queried until the View Manager is triggered. This helps reduce unnecessary memory usage by selecting a smaller dataset from the database.
However, this also means that when opening a slideOver there is a slight delay as Filament has to then query the database.
On the flip side, when displaying the View Manager as a dropdown, Advanced Tables has to query and select all the available views from the database. This is because dropdowns already load all the data and are simply hidden and shown in Alpine.
This in turn means that there is additional memory usage as all of the table's views are queried from the database and loaded into memory. However, it also means that opening the dropdown is instant as opposed to having a delay with the slideOver.
In most situations, the additional memory usage of the dropdown is worth the tradeoff to have the View Manager instantly available, but knowing how this works internally will help you decide which is best for your application.
You may disable the View Manager entirely which will also remove the View Manager button by setting both viewManagerInFavorites()
and viewManagerInTable()
to false
and displaying the View Manager as a slideOver. This hides the View Manager from the table and also ensures that only the user's favorites are queried from the database.
AdvancedTablesPlugin::make() ->viewManagerInFavoritesBar(false) ->viewManagerInTable(false) ->viewManagerSlideOver()
You may change the icon used for the View Manager using the viewManagerIcon()
method:
AdvancedTablesPlugin::make() ->viewManagerIcon('heroicon-o-bars-3')
You may change the position of the icon in the View Manager using the viewManagerIconPosition()
method:
use Filament\Support\Enums\IconPosition;Â AdvancedTablesPlugin::make() ->viewManagerIconPosition(IconPosition::After)
When displaying the View Manager as a dropdown, by default a badge indicator will be shown when there is an active View. You may disable the badge by passing false
to the viewManagerBadge()
method:
AdvancedTablesPlugin::make() ->viewManagerBadge(false)
Note: The active view badge indicator is only available when the View Manager is used as a dropdown.
By default the View Manager includes a search field to quickly search for views. You may disable the search field by passing false
to the viewManagerSearch()
method:
AdvancedTablesPlugin::make() ->viewManagerSearch(false)
You may include a Save View link inside the View Manager with the viewManagerSaveView()
method:
AdvancedTablesPlugin::make() ->viewManagerSaveView()
This also allows you to hide the Quick Save button from the Favorites Bar to maximize the space available in the Favorites Bar:
AdvancedTablesPlugin::make() ->quickSaveInFavoritesBar(false) ->viewManagerInFavoritesBar(false) ->viewManagerInTable() ->viewManagerSaveView()
Note: This option is only available when the View Manager is displayed as a dropdown. When displaying the View Manager as a slideOver,
viewManagerSaveView()
has no effect.
You may include a Reset link inside the View Manager that functions the same as clicking the Default View
button with the viewManagerResetView()
method:
AdvancedTablesPlugin::make() ->viewManagerResetView()
This also allows you to hide Default View button from the Favorites Bar to maximize the space available in the Favorites Bar.
By default a user may click on any of the Views in the View Manager to apply that view's configuration to the table. You may disable this by passing false
to the viewManagerClickToApply()
method:
AdvancedTablesPlugin::make() ->viewManagerClickToApply(false)
By default a View's action button includes an Apply View
button to apply that view's configuration to the table. You may hide this by passing false
to the viewManagerApplyButton()
method:
AdvancedTablesPlugin::make() ->viewManagerApplyButton(false)
By default the View Manager will display an indicator next to the currently active view. You may hide this by passing false
to the viewManagerActiveViewIndicator()
method:
AdvancedTablesPlugin::make() ->viewManagerActiveViewIndicator(false)
By default the View Manager will display the active view indicator as a small green dot next to the current active view. You may change this to be a badge with the viewManagerActiveViewBadge()
method:
AdvancedTablesPlugin::make() ->viewManagerActiveViewBadge()
The name of the badge can be modified in the language file.
Since different types of views have different available options, by default the View Manager will display view type icons next to each view. The icons that can be displayed are:
If you wish to hide these icons you can pass false
to the viewManagerViewTypeIcons()
method:
AdvancedTablesPlugin::make() ->viewManagerViewTypeIcons(false)
If you prefer to display view types as badges instead of icons you can use the viewManagerViewTypeBadges()
method:
AdvancedTablesPlugin::make() ->viewManagerViewTypeBadges()
By default, when a view is both public and a global favorite, the View Manager will only show the global favorite indicator, be it the icon or the badge. This helps reduce visual clutter as global favorites are already public. However, if you wish to display both you may do so with the viewManagerPublicIndicatorWhenGlobal()
method:
AdvancedTablesPlugin::make() ->viewManagerPublicIndicatorWhenGlobal()
By default the View Manager will display the chosen icon for User Views and Preset Views in the View Manager. You may hide this icon in the View Manager with the viewIcon()
method:
AdvancedTablesPlugin::make() ->viewIcon(false)
If there is no icon associated with the User View or Preset View, a default icon will be shown in the View Manager. You may change which icon is displayed with the defaultViewIcon()
method:
AdvancedTablesPlugin::make() ->defaultViewIcon('heroicon-o-queue-list')
Advanced Tables enhances Filament's toggleable columns dropdown with powerful column reordering. Now you and your users can move hide, show, and move columns to create a totally custom view. Best of all, when a user creates a new User View, their new column order is saved as well.
Note: When using a table with a column layout, the columns dropdown will not show the reorder button since columns cannot be reordered in this type of layout.
To reorder columns:
up/down arrow
button to enable reorderingNote: At least one column in your table must be
toggleable()
for Filament to display the toggle column button.
Advanced Tables offers multiple ways to customize Reorderable Columns. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
Advanced Tables enables column reordering by default. You may disable this and use Filament's native column toggling UI by passing false
to the reorderableColumnsEnabled()
method:
AdvancedTablesPlugin::make() ->reorderableColumnsEnabled(false)
You may also disable Reorderable Columns per resource by overriding the canReorderColumns()
method in the class where you have added the AdvancedTables trait:
public function canReorderColumns(): bool{ return false;}
By default, the enhanced toggle column dropdown will only display the Hidden
label when there are hidden columns. To always display the hidden label you may use the reorderableColumnsAlwaysDisplayHiddenLabel()
method:
AdvancedTablesPlugin::make() ->reorderableColumnsAlwaysDisplayHiddenLabel()
You may show the toggle column dropdown as two columns by using the columnToggleFormColumns()
method on your table:
public static function table(Table $table): Table{ return $table ->columns([ ... ]) ->columnToggleFormColumns(2)
You may change any of the icons used for Reorderable Columns by using the following methods:
AdvancedTablesPlugin::make() ->reorderIcon('heroicon-m-arrows-up-down') ->checkMarkIcon('heroicon-m-check') ->dragHandleIcon('heroicon-o-bars-2') ->visibleIcon('heroicon-s-eye') ->hiddenIcon('heroicon-o-eye-slash')
To remove any of the icon, don't pass anything to the the respective method: ->hiddenIcon()
Advanced Tables now allows your users to sort their tables by multiple columns. Using the new Multi-Sort dropdown, users can add additional columns to sort by, easily change sort direction, and even reorder the columns. And Multi-Sort is completely integrated with Preset Views and User Views.
Update to the beta
To update to the beta update your composer.json
file to:
"archilex/filament-filter-sets": "^3.8@beta",
Compile assets
After updating run npm run build
and php artisan filament:upgrade
.
To use multi-sort:
Add column
button to add a column to sort by. Only ->sortable()
table columns will be shown.up
and down
arrow buttons to change the sort direction.You can apply multi-sorting in your Preset Views through the defaultSort()
method:
'processing' => PresetView::make() ->defaultSort([ 'is_visible' => 'desc', 'price' => 'asc' ])
Advanced Tables offers multiple ways to customize Multi-Sort. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
Advanced Tables enables multi-sorting by default. You may disable this by passing false to the multiSortEnabled()
method:
AdvancedTablesPlugin::make() ->multiSortEnabled(false)
You may change the icon used for the Multi-Sort dropdown using the multiSortIcon()
method:
AdvancedTablesPlugin::make() ->multiSortIcon('heroicon-s-chevron-up-down')
By default, when one or more columns is being sorted, the Multi-Sort dropdown button will display a badge indicating the number of columns that are being sorted. You may hide the badge by passing false
to the multiSortBadge()
method:
AdvancedTablesPlugin::make() ->multiSortBadge(false)
You may customize Multi-Sort buttons, labels in the language file.
Important: Advanced Indicators is one of the biggest additions to Advanced Tables since it's initial launch and I'm very excited to be able to bring this functionality to Filament. However, since there are still outstanding features to be implemented, known limitations that are under development, and there may be custom Filament implementations that haven't been accounted for, I am launching this as a beta feature. Please read all the instructions fully to know what is currently supported, what is under development, and what may not be supported. If you do find an issue, please reach out to me on discord our through email.
Advanced Indicators gives your users quick access to their filters through Filament's indicator system. When enabled, each indicator can be clicked on to access that filter's settings. In addition, filters can be favorited and "pinned" so they always appear, even when not active.
Update to the beta
To update to the beta update your composer.json
file to:
"archilex/filament-filter-sets": "^3.8@beta",
Compile assets
After updating be sure to run npm run build
and php artisan filament:upgrade
.
Update Custom Filter Classes
Advanced Indicators automatically overrides any default Filament filters you have included in your resource or page. However, any custom filter classes that you have created that extends a Filament filter will need to be updated to use Advanced Table's versions. This can be easily accomplished by just updating your imported class with the plugins equivalent:
- use Filament\Tables\Filters\Filter+ use Archilex\AdvancedTables\Filament\Filter - use Filament\Tables\Filters\SelectFilter+ use Archilex\AdvancedTables\Filament\SelectFilter - use Filament\Tables\Filters\TernaryFilter+ use Archilex\AdvancedTables\Filament\TernaryFilter - use Filament\Tables\Filters\TrashedFilter+ use Archilex\AdvancedTables\Filament\TrashedFilter
Remember, you only need to override custom filter classes you have created. Filters used within Filament's resources and pages will be overridden automatically.
Enable Advanced Indicators
Advanced Indicators is disabled by default. To enable, add AdvancedIndicatorsEnabled()
to your panel provider:
AdvancedTablesPlugin::make() ->advancedIndicatorsEnabled()
Add the AdvancedTables trait
If you haven't already, add the AdvancedTables trait to your table.
Once enabled, Advanced Indicators should work right out the box with minimal configuration. Just click on any indicator to see the form field(s) associated with that filter. Any adjustments to that filter will be immediately reflected in the table and synced to filament's filter form.
When implementing custom filters with multiple form fields in Filament, there are two main ways to display the indicator(s). You could display a single indicator that adapts according to the fields that are set, or you could have individual indicators for each field. As an example, take the following date filter examples which have two date fields, but display the indicator differently.
Example 1 - Display as a single indicator:
Filter::make('created_at') ->form([ DatePicker::make('created_from'), DatePicker::make('created_until'), ]) ->query(function (Builder $query, array $data): Builder { ... }) ->indicateUsing(function (array $data): ?Indicator { if (($data['created_from'] ?? null) && (! ($data['created_until'] ?? null))) { return Indicator::make('Created from ' . Carbon::parse($data['created_from'])->toFormattedDateString()); }Â if ((! ($data['created_from'] ?? null)) && ($data['created_until'] ?? null)) { return Indicator::make('Created until ' . Carbon::parse($data['created_until'])->toFormattedDateString()); }Â if (($data['created_from'] ?? null) && ($data['created_until'] ?? null)) { return Indicator::make('Created between ' . Carbon::parse($data['created_from'])->toFormattedDateString() . ' and ' . Carbon::parse($data['created_until'])->toFormattedDateString()); }Â return null; })
Example 2 - Display as multiple indicators:
Filter::make('published_at') ->form([ DatePicker::make('published_from'), DatePicker::make('published_until'), ]) ->query(function (Builder $query, array $data): Builder { ... }) ->indicateUsing(function (array $data): array { $indicators = [];Â if ($data['published_from'] ?? null) { $indicators[] = Indicator::make('Published from ' . Carbon::parse($data['published_from'])->toFormattedDateString()) ->removeField('published_from'); }Â if ($data['published_until'] ?? null) { $indicators[] = Indicator::make('Published until ' . Carbon::parse($data['published_until'])->toFormattedDateString()) ->removeField('published_until'); }Â return $indicators; }),
Advanced Indicators supports both of these use cases. In the first example, only one indicator will be shown, but the form will include both fields. In the second, only the indicator's respective field will be displayed.
If you are using return types (and you should be) then Advanced Indicators will automatically detect how the indicators should be displayed. If you are not using return types, then you will need to be explicit about how Advanced Indicators should display your form fields using the ->multipleIndicators()
method:
Example 1 - Display as a single indicator:
Filter::make('created_at') ->multipleIndicators(false)
Example 2 - Display as multiple indicators:
Filter::make('created_at')` ->multipleIndicators()
Note: Displaying indicators outside of these two examples (ie. a single indicator for all form fields, or a one-to-one field/indicator setup), is not currently supported. If you have a filter set up like this, please contact me.
Advanced Indicators not only gives you quick access to applied filters, but also allows you to specify "favorite" filters which will always be displayed in the indicator bar, even when the filter is not active. You can make a filter a favorite by using the ->favorite()
method:
SelectFilter::make('brand') ->favorite()
Note: Support for Filament's
->columns()
method on filters is coming soon.
Advanced Indicators also introduces the ability to limit the number of labels that are shown on a Select Filter. Since you now have easy access to filters through the indicator, it may not be necessary to pollute the indicator bar with an excessively long indicator. To limit the indicator labels you may use the ->limitIndicatorLabels()
method:
SelectFilter::make('brand') ->limitIndicatorLabels(3)
By default, once the limit is reached Filament's localized version of & 3 more
will be displayed. However, you may change this by publishing and updating the plugin's language files and updating the more_indicator_labels
value in the advanced-tables.php
language file:
'indicators' => [ 'more_indicator_labels' => '+ :count', // display as "+ 4"],
If you are using Preset Views you may configure which filters should be displayed as favorites using the ->defaultFavoriteFilters()
method:
'recentlyCreated' => PresetView::make() ->favorite() ->defaultFavoriteFilters(['created_at']) ->defaultFilters([ 'created_at' => [ 'created_from' => now()->startOfWeek()->toDateString(), 'created_until' => now()->endOfWeek()->toDateString(), ], ])
Note: When defining default favorite filters, the order of the filters will be determined by the order they are in listed in Filament's ->filters() array. Support for ordering by the order of the ->defaultFavoriteFilters() array is coming.
User-specified favorite filters is currently under development and should be released soon. When released, your users will be able to favorite, rearrange, and even hide filters according to their needs and then save that configuration as a User View.
The current implementation of Advanced Indicators is for each indicator form to be live even if you are using Filament's filter deferring. Since each indicator is a subset of all the filters, deferring a single filter doesn't seem necessary.
However, if there is sufficient demand/need for it, I will look into bringing deferring to Advanced Indicators in the future. If implemented, each indicator dropdown would have it's own "Apply" button. Please contact me if this is a feature you need.
While Advanced Indicators should work for the majority of implementations, there are currently a few limitations and unknowns:
If you wish to disable Advanced Indicators, you may pass false to the ->advancedIndicatorsEnabled()
method:
AdvancedFilter::make() ->advancedIndicatorsEnabled(false)
Advanced Filter Builder is a custom filtering system that gives your users a simple, yet powerful way to quickly build custom queries. Each filter inside the builder can be used multiple times and grouped into or groups, allowing your users to drill down and find the data they need. Advanced Filter Builder was designed to make filtering easy for your users with a simple UI and natural filtering language.
For developers, Advanced Filter Builder couldn't be easier to implement. Advanced Filter Builder can automatically generates text
, numeric
, date
, boolean
, and select
filters from your table columns! You can also seamlessly integrate your existing filters or override the auto-generated ones allowing you to fully customize the filtering experience.
Important: Adding AdvancedTables to your table is required for Advanced Filter Builder to properly work.
To enable the Advanced Filter Builder, add AdvancedFilterBuilder
to your table's ->filter()
method:
return $table ->columns([ ... ]) ->filters([ AdvancedFilter::make(), ])
To automatically generate Column Filters for each of your table columns, you may use the ->includeColumns()
method. This will automatically map your table's compatible columns to the appropriate Column Filter and make them available in Advanced Filter Builder's picker:
AdvancedFilter::make() ->includeColumns()
Tip: If you wish to only use some Column Filters, you may use either include or exclude columns.
Advanced Filter Builder includes multiple different custom Column Filters, each with it's own set of operators:
The TextFilter
allows you to filter text strings with operators like is
, is not
, starts with
, does not end with
, contains
, etc.
When appropriate, the TextFilter
can also transform the is
and is not
operators into a multiple select dropdown:
The NumericFilter
allows you to filter numbers with operators like equal to
, greater than
, less than or equal to
, between
, positive
, etc.
The DateFilter
allows you to filter dates combining operators like yesterday
, in the next
, before
, between
, etc. with units like day
, week
, months ago
, years from now
, etc.
Advanced Table's custom SelectFilter
combines Filament's SelectFilter
with operators is
, is not
, is empty
, is not empty
.
Advanced Filter Builder will automatically map your table columns to the appropriate filter depending on the type of column:
TextColumn::make()->date()
and TextColumn::make()->dateTime()
columns will be mapped to the DateFilter.TextColumn::make()->numeric()
and TextColumn::make()->money()
columns will be mapped to the NumericFilter.count
, avg
, min
, max
, and sum
will be mapped to an aggregate NumericFilter.TextColumn
will be mapped to the TextFilter.SelectColumn
will be mapped to Advanced Filter's custom SelectFilter.CheckboxColumn
, ToggleColumn
, ImageColumn
, IconColumn
will be mapped to Filament's Ternary Filter
.Advanced Filter Builder uses the methods on your columns to automatically determine the appropriate filter to use. However, sometimes your table column may not match the type of filter you need. For example, if you are using a TextColumn
to display an numeric amount, but aren't using the ->numeric()
method, Advanced Filter Builder wouldn't know it's best to use a NumericFilter
. In these cases, it's easy to customize the filter manually using the ->filters()
method.
You may manually define a Column Filter for a particular column by passing the desired filter type to the ->filters()
method. The name
of the filter should be the column you wish to override.
Tip: Any filter you add to the
->filters()
array will be shown in the filters dropdown by default. To override this behavior you can use the->defaultFilters()
method to configure which filters, if any, are shown by default.
Note: When you are customizing a Column Filter the
name
of the filter must match the name of the column in your Filament table. If not, it will not appear in the Filter Picker.
AdvancedFilter::make() ->filters([ NumericFilter::make('shipping_price') // Use the NumericFilter on the shipping_price column ])
To enable the Select
field inside of the TextFilter
, you may use a TextFilter
and then pass in an array of options:
AdvancedFilter::make() ->filters([ TextFilter::make('country') ->options(fn () => Country::all()->pluck('name', 'id')), ])
You may also pass in a relationship to automatically load the available options:
AdvancedFilter::make() ->filters([ TextFilter::make('customer.name') ->relationship(name: 'customer', titleAttribute:'name') ->multiple() ->preload(), ])
Finally, if your table column only needs a dropdown of options to select from (ie, it doesn't need additional operators like starts with
, contains
, etc.), you may manually map your column to Advanced Filter Builder's custom SelectFilter
:
use Archilex\AdvancedTables\Filters\SelectFilter;Â AdvancedFilter::make() ->filters([ SelectFilter::make('status') ->options([ 'processing' => 'Processing', 'new' => 'New', 'shipped' => 'Shipped', 'delivered' => 'Delivered', 'cancelled' => 'Cancelled', ]) ->multiple(), ])
Important: Be sure to import
Archilex\AdvancedTables\Filters\SelectFilter
to see theis
,is not
,is empty
, andis not empty
operators.
You may customize a column filter's operators using either the ->includeOperators()
or ->excludeOperators()
methods:
AdvancedFilter::make() ->filters([ TextFilter::make('name') ->includeOperators([ TextOperator::CONTAINS, TextOperator::DOES_NOT_CONTAIN ]), SelectFilter::make('status') ->includeOperators([ TextOperator::IS, // The SelectFilter uses the TextOperator ]), DateFilter::make('created_at') ->excludeOperators([ DateOperator::YESTERDAY, DateOperator::TODAY, DateOperator::TOMORROW ]), NumericFilter::make('total_price') ->excludeOperators([ NumericOperator::EQUAL_TO, NumericOperator::NOT_EQUAL_TO ]), ])
To customize a column filter's operators globally, you can call the static configuringUsing()
method from the boot()
method of a service provider:
public function boot(){ TextFilter::configureUsing(function (TextFilter $filter) { return $filter->includeOperators([ TextOperator::CONTAINS, TextOperator::DOES_NOT_CONTAIN ]); });}
includeOperators()
and excludeOperators()
can also take a closure meaning you can further customize which operators are available:
TextFilter::configureUsing(function (TextFilter $filter) { return $filter->includeOperators(function (TextFilter $filter) { return $filter->getName() === 'currency' ? [TextOperator::CONTAINS, TextOperator::DOES_NOT_CONTAIN] : [TextOperator::IS, TextOperator::IS_NOT]; });});
To customize a column filter's default operator you may pass the name of the operator to the ->defaultOperator()
method:
AdvancedFilter::make() ->filters([ TextFilter::make('name') ->defaultOperator(TextOperator::CONTAINS), ])
To customize a column filter's default operator globally, you can call the static configuringUsing()
method from the boot()
method of a service provider:
public function boot(){ TextFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::CONTAINS)); DateFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(DateOperator::TODAY)); SelectFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::IS)); NumericFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(NumericOperator::GREATER_THAN));}
defaultOperator()
can also take a closure meaning you can further customize which operator is the default:
TextFilter::configureUsing(function (TextFilter $filter) { return $filter->defaultOperator(function (TextFilter $filter) { return $filter->getName() === 'currency' ? TextOperator::CONTAINS : TextOperator::IS; });});
Advanced Filter Builder can also seamlessly integrate any of Filament's filters, including custom filters. This allows a filter to be used multiple times as well as in "or groups".
Tip: Any filter you add to the
->filters()
array will be shown in the filters dropdown by default. To override this behavior you can use the->defaultFilters()
method to configure which filters, if any, are shown by default.
To add a filter to Advanced Filter Builder, pass the filter into the ->filters()
method:
AdvancedFilter::make() ->filters([ Filter::make('is_active') ->query(fn (Builder $query): Builder => $query->where('is_active', true)) ->toggle(), ])
Note: Any filter that has the same
name
as your table column, will be override the automatically mapped column filter. If the filter name does not match any of the table columns it will be added as an additional filter.
Important: If you are updating from a prior release and your users have already saved created User Views with filters, don't worry, Advanced Filter Builder will automatically map them to the first filter group.
However, if you are using Preset Views with default filters, you will need to adjust your filters to be compatible with Advanced Filter Builder.
You may still use any of Filament's filters alongside Advanced Filter Builder by adding it as you normally would to your table's ->filters()
method:
return $table ->columns([ ... ]) ->filters([ Filter::make('is_active') ->query(fn (Builder $query): Builder => $query->where('is_active', true)) ->toggle(), AdvancedFilter::make(), ])
The above will add a single Is active
toggle filter to the filter dropdown as well as display the Advanced Filter Builder below it.
To only filter some of your columns, you may pass an array of column names
you wish to include to the ->includeColumns()
method:
AdvancedFilter::make() ->includeColumns([ 'is_active', 'currency', 'address.city', ]);
Important: If you are customizing a Column Filter, that column must be included in the
->includesColumns()
method.
You may instead exclude columns by passing an array of columns names
to the ->excludeColumns()
method:
AdvancedFilter::make() ->excludeColumns([ 'status', 'customer.name', 'created_at', ]);
Important: If you are customizing a Column Filter, that column must not be excluded from the
->excludesColumns()
method.
By default, every filter included in Advanced Filter Builder's ->filters()
method will be shown in the table's filter dropdown. Column Filters that haven't been overriden in the ->filters()
method will be available in the filter picker. To not display any column filters you can pass an empty array to the ->defaultFilters()
method:
AdvancedFilter::make() ->filters([ ... ]) ->defaultFilters([])
To only display some filters by default, you may pass the name of your filter to the ->defaultFilters()
method inside a double array. You may also use this method to define Column Filters you wish to be displayed by default in the filter dropdown:
AdvancedFilter::make() ->filters([ ... ]) ->defaultFilters([['status']])
Important: Be sure to add your filters inside a double array.
You can also set up multiple default groups:
AdvancedFilter::make() ->filters([ ... ]) ->defaultFilters([['status'], ['status']])
By default, Advanced Filter Builder allows your filters to be used in "or groups". You may disable this feature by passing false
to the ->orGroups()
method:
AdvancedFilter::make() ->orGroups(false)
Advanced Filter Builder responsively adapts to any of the available FilterLayouts (AboveContent
, BelowContent
, AboveContentCollapsible
, Modal
, SlideOver
, Dropdown
). When the builder is used with the Dropdown
layout (Filament's default layout), the user will also be presented with an "Expand View" button that will allow the dropdown to expand into a slideOver.
If you using the Modal
layout, it's recommended you set the ->filtersFormWidth()
on the table to at least 3xl
so the form elements have space to flow:
use Archilex\AdvancedTables\Filters\AdvancedFilter;use Filament\Tables\Actions\Action;use Filament\Tables\Table;use Filament\Tables\Enums\FiltersLayout;Â public function table(Table $table): Table{ return $table ->filters([ AdvancedFilter::make(), ]) ->filtersLayout(FiltersLayout::Modal) ->filtersFormWidth('3xl')}
When using Filament's default Dropdown
filter layout, the user will also be presented with an "Expand View" button that will allow the dropdown to expand into a slideOver. The expand view link in this view is absolute
positioned (ugly...I know). If you are using translatable fields, this may cause the link to overlap. You may change the position of the expand view link by passing an array of styles to the ->filterBuilderExpandViewStyles()
method:
AdvancedTablesPlugin::make() ->filterBuilderExpandViewStyles(['right: 100px', 'top: 24px'])
This method also take a closure allowing you to set different positions based on a condition such as locale:
use Illuminate\Support\Facades\App;Â AdvancedTablesPlugin::make() ->filterBuilderExpandViewStyles(fn () => App::isLocale('es') ? ['right: 100px', 'top: 24px'] : ['right: 80px', 'top: 24px'])
If you would prefer Advanced Filter Builder to always open in a slideOver or modal, you may use Filament's filtersTriggerAction()
method:
use Archilex\AdvancedTables\Filters\AdvancedFilter;use Filament\Tables\Actions\Action;use Filament\Tables\Table;Â public function table(Table $table): Table{ return $table ->filters([ AdvancedFilter::make(), ]) ->filtersFormWidth('md') ->filtersTriggerAction( fn (Action $action) => $action ->slideOver() );}
You can add icons to the Filter Picker by passing an array of icons to the ->icons()
method where the name of your filter is the key
and the icon is the value
:
AdvancedFilter::make() ->filters([ ... ]) ->icons([ 'status' => 'heroicon-o-clock', 'currency' => 'heroicon-o-currency-euro', 'customer' => 'heroicon-o-user', 'created_at' => 'heroicon-o-calendar', ])
If the Filter Picker has a lot of available filters you can enable a search field using the ->filterPickerSearch()
method:
AdvancedFilter::make() ->filterPickerSearch()
To change the number of columns the Filter Picker may occupy, you may use the ->filterPickerColumns()
method:
AdvancedFilter::make() ->filterPickerColumns(2)
Passing an integer
will determine how many columns are displayed at the lg
breakpoint. You may also pass an array:
AdvancedFilter::make() ->filterPickerColumns(['sm' => 2])
To customize the width of the Filter Picker, you may use the ->filterPickerWidth()
method, and specify a width - xs
, sm
, md
, lg
, xl
, 2xl
, etc.
AdvancedFilter::make() ->filterPickerWidth('md')
Tip: Since the slideOver is confined to width
md
, it is recommended the Filter Picker not be set to a width larger thanmd
as larger sizes will cause the slideOver to horizontally scroll.
To add a maximum height to the Filter Picker, which, in turn, allows the picker to be scrolled, you may use the ->filterPickerMaxHeight()
method, passing a CSS length:
AdvancedFilter::make() ->filterPickerMaxHeight('240px')
When adding multiple filter groups ("or" groups), an the Filter Group number (ie "Filter Group 1") will be prepended to the indicator to help differentiate between the different filter groups. You may disable this by passing false
to the ->prependFilterGroupLabels()
method:
AdvancedFilter::make() ->prependFilterGroupLabels(false)
You may also hide the filter group label when there is only one filter group:
AdvancedFilter::make() ->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false)
And of course, this can be set globally in your service provider:
AdvancedFilter::configureUsing(function (AdvancedFilter $filter) { return $filter->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false);});
Tip: The name/translation of the label can be modified in the language file.
When adding multiple filter groups ("or" groups), the indicators will be displayed in different colors to help differentiate between the different filter groups. By default, the indicators will be colored in the following sequence: primary
, info
, gray
, success
, danger
, warning
. You may choose a different sequence by passing an array of colors to the ->indicatorColors()
method:
AdvancedFilter::make() ->indicatorColors(['info', 'success'])
Any default color that is not defined in the array will be appended after the last defined color.
You may customize Advanced Filter Builders buttons, labels, and filter operators in the language file.
Advanced Tables v3 has built in support for simple one-to-many tenancy, Filament's multi-tenancy as well as basic support for Spatie Multi-tenancy and Tenancy for Laravel. (Please see support section below).
Setting up tenancy with Advanced Tables will depend on your app and the tenancy implementation you are using. Please refer to the appropriate instructions for your setup:
Since in a simple one-to-many tenancy implementation, each user only belongs to one tenant (team, organization, company, etc.), it may not be necessary to set up tenancy in Advanced Tables as each User View is already scoped to a user. However, if are allowing users to share views or if your tenant will have admins that can create Global Favorite Views, you will need to enable tenancy so that each User View will be scoped to the appropriate tenant.
To set up simple tenancy with Filament Panels you will need to pass your Tenant::class
to the ->tenant()
method of the AdvancedTablesPlugin
object:
AdvancedTablesPlugin::make() ->tenant(Team::class)
After you have configured your tenant model you may proceed to run the AddTenancy
command:
php artisan advanced-tables:add-tenancy
This command will add and run the necessary migrations to finishing setting up multi-tenancy in Advanced Tables.
To set up simple tenancy with Filament's standalone Table Builder you will need to add your Tenant::class
to your advanced-tables.php
config file:
'tenancy' => [ 'tenant' => App\Models\Team::class,],
Inside your tenant model you need to include a getTenantId()
method so Advanced Tables knows which tenant to use for its scopes:
class Team extends Model{ public function getTenantId(): ?string { return auth()->user()?->team_id; }}
After you have configured your tenant model and the getTenantId()
method, you may proceed to run the AddTenancy
command:
php artisan advanced-tables:add-tenancy
This command will add and run the necessary migrations to finishing setting up multi-tenancy in Advanced Tables.
To set up multi-tenancy with Filament Panels and Filament's multi-tenancy implementation, first set up multi-tenancy in Filament per Filament's instructions.
After setting up tenancy in Filament, run the AddTenancy
command:
php artisan advanced-tables:add-tenancy
This command will add and run the necessary migrations to finishing setting up multi-tenancy in Advanced Tables.
To set up multi-tenancy with Filament Panels and Spatie Multi-tenancy or Tenancy For Laravel you will need to pass your Tenant::class
to the ->tenant()
method of the AdvancedTablesPlugin
object:
AdvancedTablesPlugin::make() // Spatie ->tenant(\Spatie\Multitenancy\Models\Tenant::class) // TenancyForLaravel ->tenant(\Stancl\Tenancy\Database\Models\Tenant::class)
After setting up tenancy, run the AddTenancy
command:
php artisan advanced-tables:add-tenancy
This command will add and run the necessary migrations to finishing setting up multi-tenancy in Advanced Tables.
To set up multi-tenancy with Filament's standalone Table Builder along with Spatie Multi-tenancy or Tenancy For Laravel you will need to add your Tenant::class
to your advanced-tables.php
config file:
'tenancy' => [ 'tenant' => \Spatie\Multitenancy\Models\Tenant::class,],
After you have configured your tenant model, you may proceed to run the AddTenancy
command:
php artisan advanced-tables:add-tenancy
This command will add and run the necessary migrations to finishing setting up multi-tenancy in Advanced Tables.
If you had previously manually implemented multi-tenancy in Advanced Tables and need to reference a table column other than the default tenant_id
, you may configure it by passing your column name to the ->tenantColumn()
method:
AdvancedTablesPlugin::make() ->tenantColumn('account_id')
If you are using multi-tenancy in your app, but would prefer User Views and Preset Views to not be scoped to each tenant (i.e. a user's views would be the same regardless of which tenant they are in), you may ignore multi-tenancy in the plugin by passing false
to the ->scopeToTenancy()
method:
AdvancedTablesPlugin::make() ->scopeToTenancy(false)
Advanced Tables only fully supports Filament's official multi-tenancy implementation. Since third-party multi-tenancy implementations with either Spatie or Tenancy for Laravel can vary dramatically from developer to developer, it is possible that Advanced Tables will not be fully compatible. Please be sure you have multi-tenancy fully working and tested before attempting to implement multi-tenancy in Advanced Tables. Support can only be provided for issues pertaining to Advanced Tables.
Starting in v3, the User Views Resource is a Filament table resource primarily for admins to be able to manage the User Views of all their users. It is also where admins can approve or reject User Views with the approval system.
Important: You will need to set up a policy to limit access to the User Views Resource. Without a policy, any user will be able to rename, update, or delete any User View. See the policy section for more information.
The icons in the rows are actionable and can be clicked to quickly toggle the setting.
Advanced Tables offers multiple ways to customize the User Views Resource. Unless specified otherwise, these options can be configured directly on the AdvancedTablesPlugin
object inside your PanelProvider
.
Advanced Tables enables the User Views Resource by default. If you are not using User Views, you may disable this by passing false
to the resourceEnabled()
method:
AdvancedTablesPlugin::make() ->resourceEnabled(false)
If you wish to just limit access to the User Views Resource, you should create a policy.
You may customize the model label
, plural model label
, and navigation label
in the language file.
You may customize the navigation icon by passing a heroicon
to the resourceNavigationIcon()
method:
AdvancedTablesPlugin::make() ->resourceNavigationIcon('heroicon-o-star')
You may customize the navigation group by passing a string
to the resourceNavigationGroup()
method:
AdvancedTablesPlugin::make() ->resourceNavigationGroup('Settings')
You may customize the navigation sort order by passing an int
to the resourceNavigationSort()
method:
AdvancedTablesPlugin::make() ->resourceNavigationSort(1)
By default, Advanced Tables shows a badge in the navigation of the number of unapproved views. You may disable this by passing false
to the resourceNavigationBadge()
method:
AdvancedTablesPlugin::make() ->resourceNavigationBadge(false)
By default, when filtering users in the User Views Resource all users will be loaded. This is fine for smaller applications with a handful of users, but if you application has hundreds or thousands of users, you may disable loading all users by passing false
to the resourceLoadAllUsers
method:
AdvancedTablesPlugin::make() ->resourceLoadAllUsers(false)
When using multiple panels the User Views Resource by default will only show the User Views associated with the current panel's resources. However, since the UserViewResource::class
is part of the plugin, if you create views on the User View Resource then those views will appear in every panel's User Views Resource. Sometimes, this maybe desired. For example, if you create an "Approved" view on the User View Resource, you may want that view to appear in the User Views Resource of every panel.
However, if you prefer each User Views Resource to be independent, you can follow the steps below:
Note: This will only affect future views created for the User Views Resource. It will not update views you previously created for your User Views Resource.
Copy archilex/filament-filter-sets/src/Resources/UserViewResource.php
and archilex/filament-filter-sets/src/Resources/UserViewResource/Pages/ManageUserViews.php
files to your panels directory:
+-- Filament│ +-- SecondaryPanel│ │ +-- Resources│ │ │ +-- UserViewResource.php│ │ │ +-- UserViewResource│ │ │ │ +-- Pages│ │ │ │ │ +-- ManageUserViews.php
Note: While you can extend the plugin's UserViewResource for each panel, it is also possible to use the plugin's UserViewResource for your main panel and only extend the resource for your secondary panels.
Extend UserViewResource.php:
namespace App\Filament\SecondaryPanel\Resources;Â use App\Filament\SecondaryPanel\Resources\UserViewResource\Pages\ManageUserViews;use Archilex\AdvancedTables\Resources\UserViewResource as Resource;Â class UserViewResource extends Resource{ public static function getPages(): array { return [ 'index' => ManageUserViews::route('/'), ]; }}
Update ManageUserViews.php
namespace App\Filament\SecondaryPanel\Resources\UserViewResource\Pages;Â use App\Filament\SecondaryPanel\Resources\UserViewResource;use Archilex\AdvancedTables\AdvancedTables;use Filament\Resources\Pages\ManageRecords;Â class ManageUserViews extends ManageRecords{ use AdvancedTables;Â protected static string $resource = UserViewResource::class;}
Now, when you create a view inside that panel's User Views Resource it will only appear in that panels' User Views Resource.
As mentioned, by default the User Views Resource will only show the User Views that are associated to that panel. However, if you would like to include views from other panels you can do that by passing an array of panel ids to the ->resourcePanels()
method.
AdvancedTablesPlugin::make() ->resourcePanels(['admin', 'secondaryPanel'])
Note: The
open
action will only be displayed for the current panel's user views.
Depending on your application, you may not want to give all of your users the ability to use all the functions. Here are a few example situations:
Advanced Tables handles authorization with Laravel policies. Beyond Filament's normal policy methods, Advanced Tables includes the following additional methods:
makePublic()
is used to control who can make a User View publicly available to the other users.
makeFavorite()
is used to control who can add a User View to their favorites. Usually this will be enabled for all users.
makeGlobalFavorite()
is used to control who can make a User View a global favorite for all users. Usually this would only be administrators.
selectIcon()
is used to control if you want to allow your users to select an icon for a User View.
selectColor()
is used to control if you want to allow your users to select colors for a User View.
To make setting up these policies easy Advanced Tables includes a sample UserViewPolicy
. To implement this policy, first create your own policy:
php artisan make:policy UserViewPolicy
Next, locate the newly created UserViewPolicy
and replace its contents with the contents in the example UserViewPolicy
located in this plugin's Policies
directory.
Finally, even though Laravel may automatically detect your policy, it is recommended you explicitly register it in App\Providers\AuthServiceProvider
:
use App\Policies\UserViewPolicy;use Archilex\AdvancedTables\Models\UserView;Â protected $policies = [ UserView::class => UserViewPolicy::class,];
The example policy assumes:
User::class
and that it's located in the App\Models\
directory as has been the default since Laravel 8.isAdmin()
method on your user model.The example policy will apply the following policies:
If you are using a User configuration other than Laravel's default, you should configure these before running your migrations:
You may customize the User::class
by passing your custom class to the user()
method:
AdvancedTablesPlugin::make() ->user(MyUser::class)
You may customize the users database table by passing the name of your table to the userTable()
method:
AdvancedTablesPlugin::make() ->userTable('my_users_table')
By default, Laravel's default users
table includes a name
column which Advanced Tables expects to exist. If you have modified your users
table to something such as first_name
and last_name
you may configure this using the userTableNameColumn()
method:
AdvancedTablesPlugin::make() ->userTableNameColumn('first_name')
If you have only have a first_name
and last_name
column, but still wish to show a user's full name in the User Views Resource, you may create a virtual column to support this:
$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
AdvancedTablesPlugin::make() ->userTableNameColumn('full_name')
If you are set your primary key on your User::class
model to something other than Laravel's default id
, you should also configure this in Advanced Tables using the userTableKeyColumn()
method:
AdvancedTablesPlugin::make() ->userTableKeyColumn('uuid')
By default, Advanced Tables will use whichever authentication guard is set on your Filament panel. If you are using standalone Table Builder, you may set the authentication guard in the advanced-tables
config file:
'users' => [ 'auth_guard' => 'web',],
Each text field in Advanced Tables has been added to the language file allowing you to customize the text to better fit your application needs. You can publish the language files with:
php artisan vendor:publish --tag=advanced-tables-translations
This will copy the language files to your resources\lang\vendor\advanced-tables
directory. Currently 🇺🇸 English, 🇲🇽 Spanish, and 🇫🇷 French translations are available.
Advanced Tables has full support for Filament's Table Builder.
Before proceeding, please refer to the setup instructions.
To use Advanced Tables, you need to add the AdvancedTables
trait to your component. However, as Advanced Tables overrides multiple methods in Filament's InteractsWithTables
trait, adding the AdvancedTables
trait to the table will cause a conflict.
For convenience, Advanced Tables includes a Page
class which you can use to quickly get up and running:
use Archilex\AdvancedTables\AdvancedTables;use Archilex\AdvancedTables\Livewire\Page;Â class ListUsers extends Page{ use AdvancedTables;Â ...
Of course, there are multiple ways to prevent the trait conflict. The important part is to ensure that the AdvancedTables
trait is used on a class that extends another class which contains Filament's InteractsWithTables
trait.
You also need to add the Favorites Bar component to your blade file:
<div class="space-y-6">Â <x-advanced-tables::favorites-bar />Â {{ $this->table }}</div>
The Favorites Bar expects a space of 24px
to properly display it's links. This can easily be achieved with Tailwind's space-y-6
class as shown above.
If you are using the Filament Panels, Advanced Tables comes with a UserViewResource
so admins can manage all of their user's views. If you are using Filament Tables, you can recreate this table:
Create a new Livewire component
php artisan make:livewire ListUserViews
Locate the ListUserViews.php
file in this plugins Livewire
directory and copy and paste its contents into your newly created ListFilterSets
component.
Add the Favorites Bar to your list-user-views
view component:
<div class="space-y-6">Â <x-advanced-tables::favorites-bar />Â {{ $this->table }}</div>
Finally add the route to routes/web.php
.
Route::get('/user-views', App\Livewire\ListUserViews::class)->middleware(['auth', 'verified']);
All of the configurations listed above are also available when using Filament's standalone Table Builder. However, these will need to be configured in the config file.
By combining Advanced Tables with the powerful Excel Export by Dennis Koch, you and your users can take full advantage of your custom views to generate customizable reports. Your view's filters, toggled columns, sorting, and reordered columns are automatically configured in your exported data. Advanced Tables and Excel Export make customizing, saving, and exporting reports easy, yet powerful.
ExportBulkAction
to your table:public static function table(Table $table): Table{ return $table ->bulkActions([ ExportBulkAction::make() ]);}
Create your custom view using either Preset Views or User Views. Use whichever combination of filters, sorting, and toggled columns you like. Remember, with Advanced Tables you can also reorder your columns as well!
Save your custom view. If this will be a report you generate frequently, you can add it to your Favorites Bar. Or just keep it in the View Manager for easy access later on.
Click the bulk select
button in the table header to select the records in your custom view and then choose Export
. Your selected records will be downloaded, sorted, filtered, and organized, just like you want.
Be sure to check out the rest of Excel Export's docs for further ways to customize your exports. And if Excel Export is helpful to your business, be sure to sponsor Dennis.
Filament v3 now makes it easy for you to have your widgets and charts automatically update when you filter your views using Advanced Tables. Now, when you choose one of your Views, your widgets and/or charts will update to reflect your filtered data.
Note: While you can use Filament's
ExposesTableToWidgets
andInteractsWithPageTable
traits, if you are using Preset View's->modifyQueryUsing()
method you must use Advanced Table's versions to fully support interactivity on the first click.
ExposesTableToWidgets
trait to your page class:use Archilex\AdvancedTables\Widgets\Concerns\ExposesTableToWidgets;Â class ListOrders extends ListRecords{ use ExposesTableToWidgets;}
InteractsWithPageTable
trait and return the name of the page class from the getTablePage()
method:use Archilex\AdvancedTables\Widgets\Concerns\InteractsWithPageTable;Â class OrderStats extends Widget{ use InteractsWithPageTable;Â protected function getTablePage(): string { return ListOrders::class; }}
$this->getPageTableQuery()
to access the query builder instance:use Filament\Widgets\StatsOverviewWidget\Stat;Â Stat::make('Orders', $this->getPageTableQuery()->count()),
That's it! Now when you click on one of your Views, the widgets will update accordingly. See Filament's docs for more details.
Question? Bug? Feature request? Comment or suggestion? Email me at advancedtables@gmail.com or join us on #advanced-tables on Discord. I'd love to hear from you.
Please see CHANGELOG for more information on what has changed recently.
Users with active licenses may access the private repo to contribute by visiting the Licenses
tab of your AnyStack account.
The Single License grants the Licensee permission to use Advanced Tables in a single project hosted on a single domain or subdomain. Examples include a personal website or a website for a single client.
If you would like to implement Advanced Tables in a SaaS application, you will need an Unlimited or Lifetime license.
The single license grants permission for up to 5 Employees and Contractors (i.e. developers) of the Licensee to access and use Advanced Tables.
You will be updates and bug fixes for one year from the date of purchase. Should you decide not to renew your license, you will only be able to install the package up to the last version available before the license expired. You can renew the license at a discounted price to continue receiving updates and new features.
The Unlimited License grants the Licensee permission to use Advanced Tables on unlimited domains and subdomains, including SaaS applications.
The unlimited license grants permission for up to 25 Employees and Contractors (i.e. developers) of the Licensee to access and use Advanced Tables.
You will be updates and bug fixes for one year from the date of purchase. Should you decide not to renew your license, you will only be able to install the package up to the last version available before the license expired. You can renew the license at a discounted price to continue receiving updates and new features.
The Lifetime License grants the Licensee permission the same benefits as the Unlimited License.
You will receive updates for the lifetime of the product.
The unlimited license grants permission for up to 25 Employees and Contractors (i.e. developers) of the Licensee to access and use Advanced Tables.
None of Advanced Tables' licenses allow the public distribution of its source code. So, you may not build an application using Advanced Tables and distribute that application publicly via an open source repository, hosting platforms, or any other code distribution platform.
Unsure which license you need? Email me at advancedtables@gmail.com with your questions.
Kenneth Sese is the director of Hope For Tomorrow Guatemala, a non-profit organization serving orphaned and at-risk children in Guatemala. As a full-stack developer, he is using Filament and the TALL stack to support Hope for Tomorrow and other non-profits with their development needs. He is also the author of Filter Sets, Toggle Icon Column, and Stacked Image Column.