Skip to main content

Pipeline Stages Resource: Reorderable

Premium
7 min read

Next up, each of our Customers has to go in a Pipeline to advance from one status to another. For example, we start at Contact Made and then progress to Meeting Scheduled. To do this, we need to create a new resource Pipeline Stages:

In this lesson, we will:

  • Create pipeline_stages DB structure: Model/Migration and a hasMany relationship to customers
  • Create Seeds with semi-real data without factories
  • Create a Filament Resource for Pipeline Stages
  • Auto-assign the new position to a new Pipeline Stage
  • Make the table reorderable with the position field
  • Add a Custom Action Set Default with confirmation
  • Add a DeleteAction to the table with validation if that record is used
  • Add pipeline stage information to the Customer Resource table/form

Creating Pipeline Stages Database

These are the fields for our DB:

  • id
  • name
  • position - Order of the stages
  • is_default

This will be seeded by default workflow but can be changed by admins to suit their needs.

Let's start with our migration:

Migration

Schema::create('pipeline_stages', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('position');
$table->boolean('is_default')->default(false);
$table->timestamps();
});

Then, we need to create a model:

app/Models/PipelineStage.php

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
 
class PipelineStage extends Model
{
protected $fillable = [
'name',
'position',
'is_default',
];
 
public function customers(): HasMany
{
return $this->hasMany(Customer::class);
}
}

Next, we will make sure that we have some Default data in our database:

database/seeders/DatabaseSeeder.php

public function run(): void
{
User::factory()->create([
'name' => 'Test Admin',
'email' => '[email protected]',
]);
 
Customer::factory()
->count(10)
->create();
 
$leadSources = [
'Website',
'Online AD',
'Twitter',
'LinkedIn',
'Webinar',
'Trade Show',
'Referral',
];
 
foreach ($leadSources as $leadSource) {
LeadSource::create(['name' => $leadSource]);
}
 
$tags = [
'Priority',
'VIP'
];
 
foreach ($tags as $tag) {
Tag::create(['name' => $tag]);
}
 
$pipelineStages = [
[
'name' => 'Lead',
'position' => 1,
'is_default' => true,
],
[
'name' => 'Contact Made',
'position' => 2,
],
[
'name' => 'Proposal Made',
'position' => 3,
],
[
'name' => 'Proposal Rejected',
'position' => 4,
],
[
'name' => 'Customer',
'position' => 5,
]
];
 
foreach ($pipelineStages as $stage) {
PipelineStage::create($stage);
}
 
$defaultPipelineStage = PipelineStage::where('is_default', true)->first()->id;
Customer::factory()->count(10)->create([
'pipeline_stage_id' => $defaultPipelineStage,
]);
}

One thing to note here is that we have...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (36 h 00 min)

You also get:

61 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Stefan avatar

Hi, thanks for this great tutorial. I learn a lot! There is an alterantive to make the "set default" action that I think is a bit simpler:

Tables\Actions\Action::make('Set Default')
->icon('heroicon-o-star')
->hidden(fn($record) => $record->is_default) // hidden action, if is_default = 1 (true)
->requiresConfirmation()
->modalHeading(fn ($record) => 'Set "' . $record->name . '" as Default')
->modalDescription('Are you sure you want to set this as the default pipeline stage?')
->action(function (PipelineStage $record) {
PipelineStage::where('is_default', true)->update(['is_default' => false]);
$record->is_default = true;
$record->save();
}),
mjhcremer avatar

This works also, but the column "Is default" in the table still shows te wrong icon. There must be a refresh after save. How will we do that?