aymanalhattami/filament-context-menu

context menu (right click menu) for filament

1.0.3 2024-09-22 10:47 UTC

This package is auto-updated.

Last update: 2024-10-27 13:10:13 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Add a context menu (right click menu) for resource pages, custom pages and table cells of Filament Admin Panel.

  • It uses Filament Actions to set menu actions.
  • It supports dark and light modes.
  • It supports left-to-right and right-to-left direction.
  • You can set a divider between menu actions.
  • It supports resource pages and custom pages.
  • You can set a context menu for table cells.
  • Three actions are available for usage in the page context menu:
    • AymanAlhattami\FilamentContextMenu\Actions\RefreshAction to refresh the page.
    • AymanAlhattami\FilamentContextMenu\Actions\GoBackAction to go back to the previous page.
    • AymanAlhattami\FilamentContextMenu\Actions\GoForward to go back to the forward page.

Demo project | Youtube video | Laravel Daily (Povilas Korop) Video

Installation

You can install the package via Composer:

composer require aymanalhattami/filament-context-menu

Usage 1: resource pages and custom pages

  1. Add the trait AymanAlhattami\FilamentContextMenu\PageHasContextMenu to the page you want to add the context menu.
  2. Then, define a getContextMenuActions method inside the page, the method should return an array of Filament Actions
use App\Filament\Resources\UserResource\Pages\CreateUser;
use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Actions\Action;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;
    
    public function getContextMenuActions(): array
    {
        return [
            Action::make('Create user')
                ->url(CreateUser::getUrl())
        ];
    }
    
    // 
}

Divider

You can use AymanAlhattami\FilamentContextMenu\ContextMenuDivider to set divider between menu actions

use App\Filament\Resources\UserResource\Pages\CreateUser;
use App\Filament\Resources\UserResource\Pages\TrashedUsers;
use AymanAlhattami\FilamentContextMenu\ContextMenuDivider;
use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Actions\Action;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            Action::make('Create user')
                ->url(CreateUser::getUrl()),
            ContextMenuDivider::make(),
            Action::make('Trashed user')
                ->url(TrashedUsers::getUrl()),
        ];
    }
    
    // 
}

Create Action

You can use Filament\Actions\CreateAction, visit filament create action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\CreateAction::make()
                ->model(App\Models\User::class)
                 ->form([
                    TextInput::make('name')
                        ->required(),
                    // ...
                ])
        ];
    }
    
    // 
}

Edit Action

You can use Filament\Actions\EditAction, visit filament edit action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\EditAction::make()
                ->record($this->user)
                ->form([
                    TextInput::make('name')
                        ->required(),
                    // ...
                ])
        ];
    }
    
    // 
}

View Action

You can use Filament\Actions\ViewAction, visit filament view action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\EditRecord;

class EditUser extends EditRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\ViewAction::make()
                ->record($this->user)
                 ->form([
                    TextInput::make('name')
                        ->required(),
                    // ...
                ])
                
        ];
    }
    
    // 
}

Delete Action

You can use Filament\Actions\DeleteAction, visit filament delete action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\DeleteAction::make()
                ->record($this->user)
        ];
    }
    
    // 
}

Replicate Action

You can use Filament\Actions\ReplicateAction, visit filament replicate action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\ReplicateAction::make()
                ->record($this->user)
        ];
    }
    
    // 
}

Force Delete Action

You can use Filament\Actions\ForceDeleteAction, visit filament force delete action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\ForceDeleteAction::make()
                ->record($this->user)
        ];
    }
    
    // 
}

Restore Action

You can use Filament\Actions\RestoreAction, visit filament restore action for more information.

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\RestoreAction::make()
                ->record($this->user)
        ];
    }
    
    // 
}

Import Action

You can use Filament\Actions\ImportAction, visit filament import action for more information.

use App\Filament\Imports\UserImporter;
use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\ImportAction::make()
                ->importer(UserImporter::class)
        ];
    }
    
    // 
}

Export Action

You can use Filament\Actions\ExportAction, visit filament export action for more information.

use App\Filament\Exports\UserExporter;
use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ListRecords;

class ListUsers extends ListRecords
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            \Filament\Actions\ExportAction::make()
                ->exporter(UserExporter::class)
        ];
    }
    
    // 
}

Example: action with modal

You can use filament action with modal

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;
use Filament\Actions\Action;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            Action::make('Quick edit user')
                ->form([
                    \Filament\Forms\Components\Grid::make(2)
                        ->schema([
                            TextInput::make('name'),
                            TextInput::make('email'),
                        ])
                ])
                ->action(function($data){
                    $this->getRecord()->update([
                        'name' => $data['name'],
                        'email' => $data['email'],
                    ]);
                })
        ];
    }
    
    // 
}

Example: refresh, go back and go forward actions

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;
use Filament\Resources\Pages\ViewRecord;
use AymanAlhattami\FilamentContextMenu\Actions\{ RefreshAction, GoBackAction, GoForwardAction}; 

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [
            RefreshAction::make(),
            GoBackAction::make(),
            GoForwardAction::make()
        ];
    }
    
    // 
}

Enable / Disable context menu in resource pages and custom pages

Method 1: To globally enable or disable the context menu, you need to define an env variable called CONTEXT_MENU_ENABLED and to set the value to true or false.

Method 2: You can also define a static variable called public static bool $contextMenuEnabled in the page and set the value to true or false;

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;
    
    # enable / disable context menu
    public static bool $contextMenuEnabled = true;

    // 
    
    public static function getContextMenuActions(): array
    {
        return [];
    }
    
    // 
}

Method 3: define a static method called isContextMenuEnabled in the page

use AymanAlhattami\FilamentContextMenu\Traits\PageHasContextMenu;use Filament\Resources\Pages\ViewRecord;

class ViewUser extends ViewRecord
{
    use PageHasContextMenu;
    
    public static function isContextMenuEnabled(): bool
    {
        return true;
    }

    // 
    
    public static function getContextMenuActions(): array
    {
        return [];
    }
    
    // 
}

Usage 2: table cells

To add a context menu to the table cell, you can use the following columns:

 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuTextColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuCheckboxColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuSelectColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuColorColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuIconColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuImageColumn; 
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuTextInputColumn;
 AymanAlhattami\FilamentContextMenu\Columns\ContextMenuToggleColumn;
use Filament\Tables\Table;
use Filament\Tables\Actions\Action;
use AymanAlhattami\FilamentContextMenu\Columns\ContextMenuTextColumn;
use App\Filament\Resources\UserResource\Pages\{ ViewUser, EditUser };

//
public static function table(Table $table): Table
    {
        return $table
            ->columns([
                ContextMenuTextColumn::make('id')
                    ->searchable()
                    ->contextMenuActions(fn (Model $record) => [
                        Action::make('View user')
                            ->url(ViewUser::getUrl(['record' => $record]))
                            ->link()
                            ->icon('heroicon-o-user'),
                    ]),
                ContextMenuTextColumn::make('name')
                    ->searchable()
                    ->contextMenuActions(fn (Model $record) => [
                        Action::make('View user')
                            ->url(Pages\ViewUser::getUrl(['record' => $record]))
                            ->link()
                            ->icon('heroicon-o-user'),
                        Action::make('Edit user')
                            ->url(Pages\EditUser::getUrl(['record' => $record]))
                            ->link()
                            ->icon('heroicon-o-pencil'),
                    ])
                    ,
                ,
            ])
}

Use AymanAlhattami\FilamentContextMenu\ContextMenuDivider to set a divider between menu actions.

enable / disable table cell context menu

Use ->contextMenuEnabled() method to enable/disable the context menu for the table cell.

//
public static function table(Table $table): Table
    {
        return $table
            ->columns([
                ContextMenuTextColumn::make('id')
                    ->contextMenuEnabled(false)
                    ->contextMenuActions(fn (Model $record) => [
                        Action::make('View user')
                            ->url(ViewUser::getUrl(['record' => $record]))
                            ->link()
                            ->icon('heroicon-o-user'),
                    ]),
//

Note

For action to have a nice style, use ->link() method of the action, more information

public static function getContextMenuActions(): array
{
    return [
        Action::make('Create user')
            ->url(CreateUser::getUrl())
            ->link()
        ];
}

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.