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? (30 h 01 min)

You also get:

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

Already a member? Login here

Comments & Discussion

S
Stefan ✓ Link copied!

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();
}),
M
mjhcremer ✓ Link copied!

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?

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.