mddev31/filament-dynamic-dashboard
Installation:
composer require mddev31/filament-dynamic-dashboard
php artisan vendor:publish --tag=filament-dynamic-dashboard-migrations
php artisan migrate
php artisan filament:assets
Create a Dashboard Page:
Extend MDDev\DynamicDashboard\Pages\DynamicDashboard in your Filament panel:
namespace App\Filament\Pages;
use MDDev\DynamicDashboard\Pages\DynamicDashboard;
class MyDashboard extends DynamicDashboard {}
Create a Dynamic Widget:
Implement DynamicWidget and use helper traits:
use MDDev\DynamicDashboard\Concerns\{HasEmptySettings, HasSizeDefaults};
use MDDev\DynamicDashboard\Contracts\DynamicWidget;
class MyWidget extends Filament\Widgets\StatsOverviewWidget implements DynamicWidget {
use HasEmptySettings, HasSizeDefaults;
public static function getWidgetLabel(): string { return 'My Widget'; }
}
Register Widget:
Add the widget to your Filament panel’s widget list (via getWidgets() in your panel provider).
Access Dashboard: Visit the dashboard page in Filament. Click + Widget to add your dynamic widget to the canvas.
Build a customizable analytics dashboard:
SalesChartWidget with configurable settings (e.g., time range, metrics).getDynamicDashboardDefaultWidth() to set a default 6-column width.getDynamicDashboardMinHeight()/getDynamicDashboardMaxHeight().Widget Development:
getSettingsFormSchema() to expose widget-specific configs (e.g., chart type, data source).
public static function getSettingsFormSchema(): array {
return [Select::make('chartType')->options(['line', 'bar'])];
}
public static function getDynamicDashboardMaxHeight(): int { return 3; }
InteractsWithPageFilters for dashboard-wide filters:
use Filament\Widgets\Concerns\InteractsWithPageFilters;
Dashboard Layouts:
template_key (e.g., 'split-6') to a dashboard via the manager UI.'main', 'sidebar') to organize widgets logically.'standard-12', 'kpi-4') and customize via JSON templates.Access Control:
laravel-permission to restrict dashboard visibility:
public static function canDisplay(): bool {
return auth()->user()->hasRole('analyst');
}
is_personal to scope them to the creator.Filter Management:
getDefaultFilterSchema():
public static function getDefaultFilterSchema(): array {
return [TextInput::make('date')->default('2024-01-01')];
}
showWidgetLoader() to control loading states:
public static function showWidgetLoader(): bool { return true; }
resources/json/dynamic-dashboard/ (e.g., custom-8.json).canEdit() to disable edits for read-only dashboards:
public static function canEdit(): bool { return false; }
php artisan filament:assets
Upgrade Migrations:
php artisan migrate --pretend # Review changes first
HasSizeDefaults or implement size methods manually.Size Method Conflicts:
getMaxHeight()). Use the getDynamicDashboard... prefix.GridStack.js Quirks:
getDynamicDashboardMaxWidth() to enforce limits.getDynamicDashboardMinWidth()/getDynamicDashboardMinHeight() to 1 to prevent widgets from collapsing.Filter Persistence:
resolveFilterDefaults() to transform them (e.g., convert strings to Carbon instances):
public static function resolveFilterDefaults(): array {
return ['date' => Carbon::parse($defaults['date'])];
}
Performance:
showWidgetLoader() to mask delays.Layout Issues:
template_key in the database (dashboards table). Verify the JSON file exists in resources/json/dynamic-dashboard/.php artisan view:clear
Widget Settings:
getSettingsCasts() matches the form schema. Mismatched types cause silent failures.dd($this->settings); // Inside widget's mount() or render() methods
Permission Errors:
laravel-permission is installed if using role-based access:
composer require spatie/laravel-permission
dd(auth()->user()->getAllPermissions());
Asset Loading:
filament:assets publish step ran:
php artisan filament:assets
/vendor/gridstack/gridstack.js.Custom Templates:
resources/json/dynamic-dashboard/:
{
"key": "custom-6",
"label": "Custom 6-Column",
"columns": 6,
"sections": [
{"slug": "main", "columns": 6, "rowHeight": 20}
]
}
Widget Settings Validation:
getSettingsFormSchema() with validation rules:
TextInput::make('limit')
->required()
->integer()
->min(1)
->max(100)
Dynamic Sections:
DynamicDashboard class:
protected function getDefaultTemplateKey(): string {
return 'custom-template';
}
Event Listeners:
use MDDev\DynamicDashboard\Events\DashboardWidgetAdded;
DashboardWidgetAdded::listen(function (DashboardWidgetAdded $event) {
// Log or process widget additions
});
API Access:
DynamicDashboard resource:
public function toArray($request): array {
return [
'layout' => $this->layout,
'widgets' => $this->widgets,
];
}
How can I help you explore Laravel packages today?