Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Dynamic Dashboard Laravel Package

mddev31/filament-dynamic-dashboard

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require mddev31/filament-dynamic-dashboard
    php artisan vendor:publish --tag=filament-dynamic-dashboard-migrations
    php artisan migrate
    php artisan filament:assets
    
  2. 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
    {
        // Override methods like getDashboardFilters() if needed
    }
    
  3. Create a Dynamic Widget: Implement DynamicWidget and use helper traits:

    use MDDev\DynamicDashboard\Concerns\HasSizeDefaults;
    use MDDev\DynamicDashboard\Contracts\DynamicWidget;
    
    class MyWidget extends Filament\Widgets\StatsOverviewWidget implements DynamicWidget
    {
        use HasSizeDefaults;
    
        public static function getWidgetLabel(): string
        {
            return 'My Widget';
        }
    }
    
  4. Register the Widget: Add it to your Filament panel's widget list (via widgets() method in your panel provider).

  5. Access the Dashboard: Visit the dashboard page in your Filament admin panel. Drag widgets onto the canvas to start customizing.


First Use Case

Create a Personalized Analytics Dashboard:

  • Add a SalesChartWidget and StatsOverviewWidget to your dashboard.
  • Configure the SalesChartWidget with settings (e.g., resultType, groupBy).
  • Drag the widgets into a Split layout (template key: split-6-6).
  • Save the dashboard as personal (visible only to you) or global (shared with others).

Implementation Patterns

Workflows

  1. Widget Development:

    • No Settings: Use HasEmptySettings trait for widgets without configurable options.
    • Custom Settings: Define getSettingsFormSchema() and getSettingsCasts() for typed settings (e.g., BackedEnums, arrays).
    • Size Constraints: Override getDynamicDashboardMin/MaxWidth/Height() to lock or limit resizing. Example:
      public static function getDynamicDashboardMinWidth(): int { return 4; }
      public static function getDynamicDashboardMaxHeight(): int { return 1; } // Lock height
      
  2. Dashboard Management:

    • Templates: Switch between layouts (e.g., standard-12, split-6-6) via the dashboard manager.
    • Filters: Use getDashboardFilters() to add global filters (e.g., date range, user role) that apply to all widgets.
    • Personal vs. Global: Toggle is_personal in the dashboard manager to control visibility.
  3. Integration with Filament:

    • Page Filters: Use InteractsWithPageFilters to pass filter values to widgets:
      protected function getStats(): array
      {
          return [
              Stat::make('Users', $this->pageFilters['country'] ?? 'All'),
          ];
      }
      
    • Permissions: Integrate with spatie/laravel-permission to restrict dashboard access by role:
      public static function canDisplay(): bool
      {
          return auth()->user()->hasRole('analyst');
      }
      
  4. Layout Customization:

    • JSON Templates: Add custom layouts by publishing the config/filament-dynamic-dashboard.php file and extending the templates array. Example:
      'templates' => [
          'custom-layout' => [
              'sections' => [
                  'main' => ['columns' => 12],
                  'sidebar' => ['columns' => 4, 'width' => 300],
              ],
          ],
      ],
      
    • Dynamic Sections: Use section_slug in widget placement logic to group related widgets.

Integration Tips

  1. Livewire Widgets:

    • For widgets with async data (e.g., charts), enable showWidgetLoader() to show loading states:
      public static function showWidgetLoader(): bool { return true; }
      
    • Use wire:ignore on the widget’s root element to prevent full-page reloads during resizing.
  2. Shared State:

    • Pass dashboard-level filters to widgets via resolveFilterDefaults():
      public static function resolveFilterDefaults(): array
      {
          return [
              'date_range' => now()->subDays(7)->format('Y-m-d'),
          ];
      }
      
  3. Widget Settings Persistence:

    • Settings are stored as JSON and hydrated as typed properties. Example:
      public ResultTypeEnum $resultType; // Automatically cast from JSON
      
  4. GridStack.js Customization:

    • Extend the GridStack configuration by publishing the config file and overriding the gridstack key:
      'gridstack' => [
          'float' => true, // Allow widgets to float outside sections
          'acceptWidgets' => true, // Enable widget dropping
      ],
      

Gotchas and Tips

Pitfalls

  1. Upgrade Migration:

    • The upgrade from v1.x to v2.x is not reversible. Backup your database before running:
      php artisan migrate --pretend  # Dry run to verify
      
    • After upgrading, clear caches:
      php artisan view:clear
      php artisan cache:clear
      
  2. Widget Size Conflicts:

    • If a widget’s getMaxHeight() (Filament’s method) conflicts with getDynamicDashboardMaxHeight() (static), rename the latter to avoid PHP collisions.
    • Fix: Use the getDynamicDashboard... prefix explicitly:
      public static function getDynamicDashboardMaxHeight(): int { return 2; }
      
  3. Template Key Mismatch:

    • If widgets disappear after switching templates, ensure the new template includes the section_slug where the widgets are stored.
    • Debug: Check the dashboard_widgets table for section_slug values matching your template’s sections.
  4. Permission Denied:

    • If canEdit() or canDisplay() return false, verify:
      • The user has the correct Spatie roles (if using permissions).
      • The dashboard is not locked (is_locked flag in the manager).
      • The created_by field is null for global dashboards.
  5. Settings Not Saving:

    • If widget settings reset on refresh, ensure:
      • getSettingsCasts() includes all typed properties (e.g., BackedEnums).
      • The widget implements DynamicWidget and uses HasSizeDefaults or HasEmptySettings.

Debugging

  1. Layout Rendering Issues:

    • Check the browser’s console for GridStack.js errors (e.g., missing section_slug).
    • Verify the template JSON is valid by inspecting config/filament-dynamic-dashboard.php.
  2. Widget Not Appearing:

    • Ensure the widget is registered in the Filament panel’s widgets() method.
    • Check the dashboard_widgets table for the widget’s type (should match the class name).
  3. Filter Not Applying:

    • Override resolveFilterDefaults() to transform stored defaults into filter-compatible values:
      public static function resolveFilterDefaults(): array
      {
          return [
              'date_from' => Carbon::parse($defaults['date_range'] ?? now()->subDays(30)),
          ];
      }
      

Tips

  1. Default Layouts:

    • Use preset templates (standard-12, split-6-6) for quick setup. Customize via the dashboard manager.
  2. Widget Organization:

    • Group related widgets in named sections (e.g., main, sidebar) for better UX:
      // In your template JSON:
      'sections' => [
          'main' => ['columns' => 8],
          'sidebar' => ['columns' => 4, 'width' => 300],
      ],
      
  3. Performance:

    • For dashboards with many widgets, lazy-load data in widgets using wire:ignore and wire:load:
      <div wire:ignore>
          {{ $widget->render() }}
      </div>
      
  4. Extending GridStack:

    • Customize the drag-and-drop behavior by publishing the config and overriding the gridstack options:
      'gridstack' => [
          'cellHeight' => 50, // Adjust row height
          'minRow' => 1,      // Minimum rows per widget
      ],
      
  5. Personal Dashboards:

    • Mark dashboards as personal (is_personal = true) to hide them from others. Useful for user-specific views:
      public static function canDisplay(): bool
      {
          return auth()->user()->id === $dashboard->created_by;
      }
      
  6. Backup Layouts:

    • Export dashboard
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony