Enable/Disable button dynamically (based on Job Status)

I have created an Action inside my ListPage Header (headerActions). This action is firing a Batch Job. What I really would like is some way to disable the button (and show a loading indicator icon) during the time this job runs. When it is finished, it should be enabled again. Not sure how to achieve this. I can of course check if the job runs and prevent users from starting another one, but it would be nice to make it visible. I tried something with the ->disabled(fn () => $this->checkIfJobIsRunning), but how can I make this dynamic?
/**
* @return bool
* Simple version
*/
protected function checkIfJobIsRunning(): bool
{
$batchName = 'URL check';
$batch = DB::table('job_batches')->where('name', $batchName)->first();

return $batch && ! $batch->cancelled && ! $batch->finished_at;
}
/**
* @return bool
* Simple version
*/
protected function checkIfJobIsRunning(): bool
{
$batchName = 'URL check';
$batch = DB::table('job_batches')->where('name', $batchName)->first();

return $batch && ! $batch->cancelled && ! $batch->finished_at;
}

Any ideas?
30 Replies
LeandroFerreira
LeandroFerreira11mo ago
Packagist
The PHP Package Repository
Daniel Plomp
Daniel Plomp11mo ago
Thanks! I indeed looked into Job Status repo's. For me the issue is that I'm wondering how to update the button itself? Is that disabled the right way? Would it be possible to dispatch a classic Laravel Event, like e.g.: event(new JobFinishedEvent()); And then listen to that on my ListPage, somewhere? Not sure if that is the right approach...
Dennis Koch
Dennis Koch11mo ago
Would only work when you have Laravel Echo set up with Webhooks
Daniel Plomp
Daniel Plomp11mo ago
Hi Dennis. Thanks. Is there any other way to achieve such behavior? I saw this behavior also in Filapanel, but not sure how it is done
Daniel Plomp
Daniel Plomp11mo ago
@Dennis if you could help me with this? 🙂
Dennis
Dennis11mo ago
Ah yes You mean disabling actions inside a table? For these simple things, listening on sockets and stuff is really overengineered IMHO sorry, doing 100 things at the same time here Do you want to know how I update the table?
Daniel Plomp
Daniel Plomp11mo ago
I mean, I don't know what happens in the background, but if I can disable a button, show an indicator and then re-enable a button?
Dennis
Dennis11mo ago
Or how I disable it?
Daniel Plomp
Daniel Plomp11mo ago
Yes. And how you monitor the status of that project build.
Dennis
Dennis11mo ago
The status of a project is just being updated in the jobs in the final job It's set to "finished" Then, on the $table property:
->poll(function () use ($table) {
if (
$table->getRecords()
->whereIn('status', [ProjectStatus::Building, ProjectStatus::UploadingToGit])
->count() > 0
) {
return '5s';
}

return null;
})
->poll(function () use ($table) {
if (
$table->getRecords()
->whereIn('status', [ProjectStatus::Building, ProjectStatus::UploadingToGit])
->count() > 0
) {
return '5s';
}

return null;
})
I just check if I need to poll If I do, it updates every 5s The disabling, is just a disabled() methdo on the action:
->disabled(fn (Project $record) => $record->status === ProjectStatus::Building)
->disabled(fn (Project $record) => $record->status === ProjectStatus::Building)
Daniel Plomp
Daniel Plomp11mo ago
So I could poll e.g. my batch table re-enable the button/action, once it is done?
Dennis
Dennis11mo ago
And that updates automatically because of polling If you use job batches, you need to update a status column in the finally() method For a project (or what ever entity)
Daniel Plomp
Daniel Plomp11mo ago
Hmm... I'm going to investigate a bit more :). And is that status badge column a custom animated gif?
Dennis
Dennis11mo ago
Ah yes Rather easy though Sec
Daniel Plomp
Daniel Plomp11mo ago
I would aim for a Filapanel private fork 😉 Just so much stuff to learn... 🫣
Dennis
Dennis11mo ago
Tables\Columns\TextColumn::make('status')
->badge()
->icon(function (ProjectStatus $state) {
if ($state === ProjectStatus::Building || $state === ProjectStatus::UploadingToGit) {
return 'heroicon-o-arrow-path';
}

return null;
})
->extraAttributes(['class' => 'filament-icon-spin'])
->color(fn (ProjectStatus $state): string => match ($state->value) {
'finished', 'downloaded' => 'success',
'building', 'uploading-to-git' => 'gray',
'failed' => 'danger',
default => 'primary'
})
Tables\Columns\TextColumn::make('status')
->badge()
->icon(function (ProjectStatus $state) {
if ($state === ProjectStatus::Building || $state === ProjectStatus::UploadingToGit) {
return 'heroicon-o-arrow-path';
}

return null;
})
->extraAttributes(['class' => 'filament-icon-spin'])
->color(fn (ProjectStatus $state): string => match ($state->value) {
'finished', 'downloaded' => 'success',
'building', 'uploading-to-git' => 'gray',
'failed' => 'danger',
default => 'primary'
})
I just set the icon if it's building, but that needs an animation, I've done that in CSS:
.filament-icon-spin svg {
@apply animate-spin;
}
.filament-icon-spin svg {
@apply animate-spin;
}
Pretty easy 😄
Daniel Plomp
Daniel Plomp11mo ago
Cool. Tnx!
Dennis
Dennis11mo ago
Haha it's closed I'm afraid, but you'll learn quickly enough, just keep building And I don't mind sharing a few bits
Daniel Plomp
Daniel Plomp11mo ago
Fair enough. Thanks Dennis. ... and @Dennis Koch Quick question: where did you put this CSS? I don't have a custom theme, so I created a custom css file and used the FilamentAsset::register command, but it generates the css file without transpiling I think?
Dennis Koch
Dennis Koch11mo ago
Yes. There is no "we do the Tailwind for you" magic 😅 Either create a theme or don't use @apply in that file
Daniel Plomp
Daniel Plomp11mo ago
Ah ok 🙂. But I do need to register that file?
Dennis Koch
Dennis Koch11mo ago
A theme? Yes
Daniel Plomp
Daniel Plomp11mo ago
No, I mean can I use this method to load in custom css:
FilamentAsset::register([
Css::make('custom-stylesheet', __DIR__ . '/../../resources/css/custom.css'),
]);
FilamentAsset::register([
Css::make('custom-stylesheet', __DIR__ . '/../../resources/css/custom.css'),
]);
Without a theme?
Dennis Koch
Dennis Koch11mo ago
Sure. You just did, didn't you?
Daniel Plomp
Daniel Plomp11mo ago
Yes 😉
Dennis
Dennis11mo ago
Did you work it out @Daniel Plomp ?
Daniel Plomp
Daniel Plomp11mo ago
I think I have it almost ready! Works great. I had to use the transpiled css, since I do not have a custom theme.
krekas
krekas11mo ago
When using enums you don't need ->color() can define them in enum file 😉 Also this one with poll is really cool
Dennis
Dennis11mo ago
I know, I like this better
trovster
trovster11mo ago
Filament Daily
YouTube
Filament: Enum Classes to Re-Use and Auto-Style
If you have a set of key-value options in the forms and tables, you may use PHP Enum classes to avoid repeating those options. Official docs: https://filamentphp.com/docs/3.x/support/enums