1. Go to this page and download the library: Download relaticle/flowforge 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/ */
namespace App\Filament\Pages;
use App\Models\Task;
use Relaticle\Flowforge\Board;
use Relaticle\Flowforge\BoardPage;
use Relaticle\Flowforge\Column;
class TaskBoard extends BoardPage
{
protected static ?string $navigationIcon = 'heroicon-o-view-columns';
public function board(Board $board): Board
{
return $board
->query(Task::query())
->columnIdentifier('status')
->positionIdentifier('position')
->columns([
Column::make('todo')->label('To Do')->color('gray'),
Column::make('in_progress')->label('In Progress')->color('blue'),
Column::make('completed')->label('Completed')->color('green'),
]);
}
}
namespace App\Filament\Resources\CampaignResource\Pages;
use App\Filament\Resources\CampaignResource;
use App\Models\Campaign;
use Relaticle\Flowforge\Board;
use Relaticle\Flowforge\BoardResourcePage;
use Relaticle\Flowforge\Column;
class CampaignTaskBoard extends BoardResourcePage
{
protected static string $resource = CampaignResource::class;
public function board(Board $board): Board
{
return $board
->query(
// Get tasks for this specific campaign and current user's team
$this->getRecord()
->tasks()
->whereHas('team', fn($q) => $q->where('id', auth()->user()->current_team_id))
->getQuery()
)
->columnIdentifier('status')
->positionIdentifier('position')
->columns([
Column::make('backlog')->label('Backlog')->color('gray'),
Column::make('in_progress')->label('In Progress')->color('blue'),
Column::make('review')->label('Review')->color('amber'),
Column::make('completed')->label('Completed')->color('green'),
]);
}
}
// Register in your CampaignResource
public static function getPages(): array
{
return [
'index' => Pages\ListCampaigns::route('/'),
'create' => Pages\CreateCampaign::route('/create'),
'edit' => Pages\EditCampaign::route('/{record}/edit'),
'tasks' => Pages\CampaignTaskBoard::route('/{record}/tasks'), // Add this line
];
}
namespace App\Livewire;
use App\Models\Task;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;
use Relaticle\Flowforge\Board;
use Relaticle\Flowforge\Column;
use Relaticle\Flowforge\Concerns\InteractsWithBoard;
use Relaticle\Flowforge\Contracts\HasBoard;
class TaskBoard extends Component implements HasBoard, HasActions, HasForms
{
use InteractsWithBoard;
use InteractsWithActions;
use InteractsWithForms;
public function board(Board $board): Board
{
return $board
->query(Task::query())
->columnIdentifier('status')
->positionIdentifier('position')
->columns([
Column::make('todo')->label('To Do')->color('gray'),
Column::make('in_progress')->label('In Progress')->color('blue'),
Column::make('completed')->label('Completed')->color('green'),
]);
}
public function render()
{
return view('livewire.task-board');
}
}
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Schema;
public function board(Board $board): Board
{
return $board
->cardSchema(fn (Schema $schema) => $schema->components([
TextEntry::make('priority')->badge()->color(fn ($state) => match($state) {
'high' => 'danger',
'medium' => 'warning',
'low' => 'success',
default => 'gray'
}),
TextEntry::make('due_date')->date()->icon('heroicon-o-calendar'),
TextEntry::make('assignee.name')->icon('heroicon-o-user'),
]));
}
use Filament\Actions\CreateAction;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
public function board(Board $board): Board
{
return $board
->columnActions([
CreateAction::make()
->label('Add Task')
->model(Task::class)
->form([
TextInput::make('title')->s'] = $arguments['column'];
$data['position'] = $this->getBoardPositionInColumn($arguments['column']);
}
return $data;
}),
]);
}
use Filament\Actions\EditAction;
use Filament\Actions\DeleteAction;
public function board(Board $board): Board
{
return $board
->cardActions([
EditAction::make()->model(Task::class),
DeleteAction::make()->model(Task::class),
])
->cardAction('edit'); // Makes cards clickable
}
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\Filter;
public function board(Board $board): Board
{
return $board
->searchable(['title', 'description', 'assignee.name'])
->filters([
SelectFilter::make('priority')
->options(TaskPriority::class)
->multiple(),
SelectFilter::make('assigned_to')
->relationship('assignee', 'name')
->searchable()
->preload(),
Filter::make('overdue')
->label('Overdue')
->query(fn (Builder $query) => $query->where('due_date', '<', now()))
->toggle(),
]);
}