Free·
Custom Alert Widget - Records that need attention
Custom Alert Widget - Records that need attention
The intention is to show a widget on the dashboard, that may or may not be attention demanding. That depends on a database query with our conditions, and its result.
In this showcase, we're listing the Menu Items that were marked unavailable by the cooks, so that other staff can act on it.
Because of that, we want the widget to be very "flashy", so
that it demands the attention of the user.
Once they restock and mark as available, they will not be on the query, and the widget will be collapsed and be discreet.
Let's start.
Implementation
First, we run php artisan make:filament-widget , and will be asked:
- Widget name:
UnavailableItems - Type of Widget:
Table - Create in a resource: No - leave blank.
- Where to create? In the Panel
We get the Widget class created. These are the next steps:
- Define the Query and be able to get the count, to be in Alert mode or not.
- Define columns, including a URL to visit the record.
- Keep pagination at a small amount - it only paginates if that amount is surpassed, to keep the UI uncluttered.
- Create the view file, and add contents.
Find below the code.
app/Filament/Widgets/UnavailableItems.php
<?php
namespace App\Filament\Widgets;
use Filament\Tables;
use App\Models\MenuItem;
use Filament\Tables\Table;
use Illuminate\Support\HtmlString;
use Illuminate\Database\Eloquent\Builder;
use App\Filament\Resources\MenuItemResource;
use Filament\Widgets\TableWidget as BaseWidget;
class UnavailableItems extends BaseWidget
{
protected static string $view = 'filament.widgets.unavailable-items';
protected int $queryCount;
protected int $perPage = 5;
public function boot()
{
$this->queryCount = $this->getBaseQuery()->count();
}
protected function getBaseQuery(): Builder
{
return MenuItem::query()
->where('is_available', false);
}
protected function makeTable(): Table
{
return $this->makeBaseTable()
->heading(null);
}
public function table(Table $table): Table
{
return $table
->defaultPaginationPageOption($this->perPage)
->paginated(fn() => $this->queryCount > $this->perPage)
->query($this->getBaseQuery())
->columns([
Tables\Columns\TextColumn::make('name'),
])
->recordUrl($this->getRecordUrl(...))
->actions([
Tables\Actions\Action::make('view')
->url($this->getRecordUrl(...))
->color('gray')
->icon('heroicon-m-eye')
->label('View'),
]);
}
private function getRecordUrl(MenuItem $record)
{
return MenuItemResource::getUrl('edit', [
'record' => $record,
]);
}
protected function getViewData(): array
{
return [
'queryCount' => $this->queryCount,
'message' => $this->getMessage(),
'table' => $this->getTable(),
];
}
protected function getMessage(): HtmlString
{
if ($this->queryCount === 0) {
return new HtmlString(<<<HTML
<div class="text-gray-500">
All menu items are available.
</div>
HTML
);
}
return new HtmlString(<<<HTML
<div class="text-base tracking-[0.07rem] uppercase font-normal text-red-700 dark:text-red-400">
Unavailable menu items
</div>
HTML
);
}
}