Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Kanban Laravel Package

wezlo/filament-kanban

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require wezlo/filament-kanban
    

    Register the plugin in your PanelProvider:

    FilamentKanbanPlugin::make(),
    
  2. Enable Kanban on a Resource Add HasKanbanBoard trait to your resource and define the kanban() method:

    use Wezlo\FilamentKanban\Concerns\HasKanbanBoard;
    
    class TaskResource extends Resource
    {
        use HasKanbanBoard;
    
        public static function kanban(): Kanban
        {
            return Kanban::make()
                ->columns([
                    'todo' => Column::make('To Do'),
                    'in_progress' => Column::make('In Progress'),
                    'done' => Column::make('Done'),
                ])
                ->statusField('status'); // Your status field (enum or string)
        }
    }
    
  3. First Use Case Replace the default table view with the Kanban board by setting view in your table() method:

    public static function table(Table $table): Table
    {
        return $table->view('filament-kanban::board');
    }
    

Implementation Patterns

Core Workflows

  1. Enum-Based Columns (Recommended) Define a KanbanStatusEnum with transitions and WIP limits:

    use Wezlo\FilamentKanban\Enums\KanbanStatusEnum;
    
    enum TaskStatus: string implements KanbanStatusEnum
    {
        case TODO = 'todo';
        case IN_PROGRESS = 'in_progress';
        case DONE = 'done';
    
        public function transitions(): array
        {
            return [
                self::TODO => [self::IN_PROGRESS],
                self::IN_PROGRESS => [self::TODO, self::DONE],
                self::DONE => [self::IN_PROGRESS],
            ];
        }
    
        public function wipLimit(): int|null
        {
            return match($this) {
                self::IN_PROGRESS => 3,
                default => null,
            };
        }
    }
    

    Use it in kanban():

    Kanban::make()
        ->columns(TaskStatus::cases())
        ->statusField('status');
    
  2. Relationship-Based Columns For dynamic columns tied to a relationship (e.g., project):

    Kanban::make()
        ->columns(fn () => Project::query()->pluck('name', 'id'))
        ->statusField('project_id');
    
  3. Card Actions Customize card interactions:

    Kanban::make()
        ->cardClickAction(KanbanCardClickAction::Modal) // or SlideOver, Custom
        ->cardFooterActions([
            KanbanCardFooterAction::Edit,
            KanbanCardFooterAction::Delete,
            KanbanCardFooterAction::Url('view', fn ($record) => route('tasks.view', $record)),
        ]);
    
  4. Column-Specific Actions Add actions to column headers (e.g., "Create Task"):

    Kanban::make()
        ->columnHeaderActions([
            'todo' => [
                KanbanColumnHeaderAction::Make('Create Task')
                    ->form([
                        TextInput::make('title'),
                    ])
                    ->mutateFormDataUsing(fn (array $data) => [
                        'status' => 'todo',
                        ...$data,
                    ]),
            ],
        ]);
    
  5. Search and Filters Enable search with relationship support:

    Kanban::make()
        ->searchable(['title', 'description'])
        ->searchRelationships(['assigned_to']);
    
  6. Authorization Restrict moves with canMove():

    Kanban::make()
        ->canMoveUsing(fn ($record, $from, $to) => auth()->user()->can('update-task', $record));
    

Integration Tips

  1. Hybrid Views Combine Kanban with other Filament features (e.g., tabs):

    public static function table(Table $table): Table
    {
        return $table
            ->view('filament-kanban::board')
            ->tabs([
                'kanban' => Tab::make('Kanban'),
                'list' => Tab::make('List View'),
            ]);
    }
    
  2. Custom Views Publish and override Blade views:

    php artisan vendor:publish --tag=filament-kanban-views
    

    Extend resources/views/vendor/filament-kanban/board.blade.php.

  3. Server-Side Logic Handle moves in a KanbanMoveHandler:

    Kanban::make()
        ->moveHandler(KanbanMoveHandler::make()
            ->onMove(fn ($record, $from, $to) => $record->update(['status' => $to]))
        );
    
  4. WIP Limits Enforce limits server-side:

    Kanban::make()
        ->wipLimitHandler(KanbanWipLimitHandler::make()
            ->onExceed(fn ($column, $count) => notify('WIP limit exceeded for ' . $column)
        );
    
  5. Accessibility Ensure keyboard navigation by using the default ARIA attributes or extending the published views.


Gotchas and Tips

Pitfalls

  1. Status Field Mismatch

    • Issue: Cards disappear after drag if the statusField doesn’t match the enum/column names.
    • Fix: Ensure statusField() returns the exact field name used in your model (e.g., status, task_status).
  2. WIP Limits Not Triggering

    • Issue: Client-side WIP warnings appear, but server-side enforcement fails.
    • Fix: Verify wipLimitHandler() is registered and the canMove() callback respects limits:
      ->canMoveUsing(fn ($record, $from, $to) => $to->wipLimit() === null || $to->records()->count() < $to->wipLimit())
      
  3. Relationship-Based Columns Caching

    • Issue: Dynamic columns (e.g., from a relationship) don’t update.
    • Fix: Use a closure for columns and ensure the query is fresh:
      ->columns(fn () => Project::query()->where('active', true)->pluck('name', 'id'))
      
  4. SortableJS Conflicts

    • Issue: Drag-and-drop fails due to conflicting SortableJS instances.
    • Fix: Isolate the Kanban board in a unique container or disable other SortableJS instances on the page.
  5. LocalStorage Persistence

    • Issue: Collapsed columns reset on page refresh.
    • Fix: Ensure localStorage isn’t blocked (e.g., in incognito mode) or use a fallback:
      Kanban::make()
          ->persistCollapsedColumns(false) // Disable if needed
      
  6. Authorization Bypass

    • Issue: Moves succeed despite canMove() returning false.
    • Fix: Double-check that Filament::authorize() is not overriding the handler. Use:
      ->canMoveUsing(fn ($record, $from, $to) => auth()->user()->can('update', $record))
      

Debugging Tips

  1. Log Moves Add debug logs to the moveHandler:

    ->moveHandler(KanbanMoveHandler::make()
        ->onMove(fn ($record, $from, $to) => Log::debug("Moved from {$from} to {$to}", ['record' => $record->id]))
    )
    
  2. Check Network Requests

    • Failed moves may trigger silent HTTP requests. Inspect the Network tab in DevTools for POST /filament-kanban/move.
  3. Disable JavaScript

    • Test with JS disabled to verify server-side fallbacks (e.g., WIP limits).
  4. Clear LocalStorage

    • Reset browser storage to test default states:
      localStorage.removeItem('filament-kanban-collapsed-columns');
      

Extension Points

  1. Custom Card Views Override the card template:

    Kanban::make()
        ->cardView('custom.card')
        ->cardViewData(fn ($record) => ['extra' => 'data']);
    
  2. Dynamic Column Headers Use a closure for column titles/actions:

    ->columns([
        'todo' => Column::make(fn () => __('To Do ({$this->count} items)')),
    ])
    
  3. Event Listeners Listen to Kanban events (e.g., kanban.moved):

    event(new KanbanMoved($record, $from, $to));
    
  4. Testing Use the KanbanTestCase helper:

    use Wezlo\FilamentKanban\Testing\KanbanTestCase;
    
    public function testKanbanMove()
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope