PHP code example of wezlo / filament-kanban

1. Go to this page and download the library: Download wezlo/filament-kanban library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

wezlo / filament-kanban example snippets


use Wezlo\FilamentKanban\FilamentKanbanPlugin;

->plugins([
    FilamentKanbanPlugin::make(),
])

use Wezlo\FilamentKanban\Concerns\HasKanbanBoard;
use Wezlo\FilamentKanban\KanbanBoard;

class ListLeads extends ListRecords
{
    use HasKanbanBoard;

    protected static string $resource = LeadResource::class;

    public function kanban(KanbanBoard $kanban): KanbanBoard
    {
        return $kanban
            ->enumColumn('status', LeadStatus::class)
            ->cardTitle(fn ($record) => $record->title)
            ->cardDescription(fn ($record) => $record->assignee?->name);
    }
}

use Filament\Support\Contracts\HasIcon;
use Filament\Support\Icons\Heroicon;
use Wezlo\FilamentKanban\Contracts\KanbanStatusEnum;

enum LeadStatus: string implements HasIcon, KanbanStatusEnum
{
    case New = 'new';
    case Contacted = 'contacted';
    case SiteVisit = 'site_visit';
    case Negotiation = 'negotiation';
    case Won = 'won';
    case Lost = 'lost';

    // Required by HasLabel (via KanbanStatusEnum)
    public function getLabel(): string
    {
        return match ($this) {
            self::New => 'New',
            self::Contacted => 'Contacted',
            // ...
        };
    }

    // Required by HasColor (via KanbanStatusEnum)
    public function getColor(): string
    {
        return match ($this) {
            self::New => 'info',
            self::Contacted => 'warning',
            // ...
        };
    }

    // Optional: HasIcon
    public function getIcon(): Heroicon
    {
        return match ($this) {
            self::New => Heroicon::Sparkles,
            // ...
        };
    }

    // Define which statuses each status can transition to.
    // Return null to allow all transitions.
    public function getAllowedTransitions(): ?array
    {
        return match ($this) {
            self::New => [self::Contacted, self::Lost],
            self::Contacted => [self::SiteVisit, self::Lost],
            self::SiteVisit => [self::Negotiation, self::Lost],
            self::Negotiation => [self::Won, self::Lost],
            self::Won => null,  // no constraints
            self::Lost => null,
        };
    }

    // Set max cards per column. Return null for unlimited.
    public function getWipLimit(): ?int
    {
        return match ($this) {
            self::Negotiation => 10,
            default => null,
        };
    }
}

->enumColumn('status', LeadStatus::class)

->relationshipColumn('stage', 'name', Stage::class, orderAttribute: 'sort_order')

->cardTitle(fn ($record) => $record->title)
->cardDescription(fn ($record) => $record->assignee?->name)
->cardBadges(fn ($record) => [
    ['label' => $record->priority->getLabel(), 'color' => $record->priority->getColor()],
])

use Filament\Actions\Action;
use Filament\Infolists\Components\TextEntry;

->cardAction(
    Action::make('view')
        ->slideOver()
        ->schema([
            TextEntry::make('title'),
            TextEntry::make('status')->badge(),
        ])
        ->fillForm(fn ($record) => $record->toArray())
        ->modalSubmitAction(false)
        ->modalCancelActionLabel('Close')
)

use Filament\Actions\Action;
use Filament\Support\Icons\Heroicon;

->cardFooterActions([
    Action::make('edit')
        ->icon(Heroicon::PencilSquare)
        ->color('gray')
        ->url(fn ($record) => LeadResource::getUrl('edit', ['record' => $record])),
    Action::make('delete')
        ->icon(Heroicon::Trash)
        ->color('danger')
        ->

use Filament\Actions\CreateAction;

->columnHeaderAction(CreateAction::make())

use Filament\Forms\Components\Select;

->filters([
    Select::make('priority')
        ->options(LeadPriority::class)
        ->placeholder('All Priorities'),
    Select::make('assigned_to')
        ->relationship('assignee', 'name')
        ->placeholder('All Assignees'),
])
->filtersColumns(2) // grid columns inside the dropdown

->searchable(['title', 'client.user.name'])

->collapsible()

->wipLimits(['new' => 5, 'in_progress' => 10])
->defaultWipLimit(20)

->columnSummary(function ($records, $column) {
    $total = $records->sum('estimated_budget');
    return $total > 0 ? 'SAR ' . number_format($total, 0) : null;
})

->emptyState('No leads', 'Drag leads here or create a new one')

->dragConstraints([
    'new' => [LeadStatus::Contacted, LeadStatus::Lost],
    'contacted' => [LeadStatus::SiteVisit, LeadStatus::Lost],
])

->canMove(function ($record, $oldStatus, $newStatus) {
    if ($newStatus === 'won') {
        return auth()->user()->hasRole('project-manager');
    }
    return true;
})

->onRecordMoved(function ($record, $fromValue, $toValue) {
    activity()->performedOn($record)->log("Moved from {$fromValue} to {$toValue}");
})

->modifyQueryUsing(fn ($query) => $query->where('company_id', auth()->user()->company_id))
->recordsPerColumn(50)
->excludeColumns([LeadStatus::Lost])

->columnWidth('320px')
->columnColor(fn ($column) => $column->color ?? 'gray')

->cardView('leads.kanban.card')     // receives $record, $board, $column
->columnView('leads.kanban.column') // receives $column, $board
->boardView('leads.kanban.board')

->loading(false) // disable
bash
php artisan vendor:publish --tag=filament-kanban-views
bash
php artisan test --filter=KanbanBoard