Weave 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 Gridstack Dashboard Laravel Package

invaders-xx/filament-gridstack-dashboard

A Filament plugin that brings GridStack.js drag-and-drop dashboards to your admin panel, letting users arrange, resize, and persist widget layouts with ease.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Filament panel plugin that swaps the stock dashboard for a GridStack.js canvas, so users can drag/resize dashboard widgets and have their layout persist. v1.9 is a small additive release — three new plugin options (canAccess, shouldRegisterNavigation, navigationLabel) — so there is nothing to migrate, but it's a good moment to tighten how the dashboard is exposed per panel/role.

Minimal path:

composer require invaders-xx/filament-gridstack-dashboard
php artisan vendor:publish --tag="filament-gridstack-dashboard-config"   # if a config is shipped
php artisan migrate                                                     # if the layout table isn't already present

Register the plugin on the panel you want it on (usually app/Providers/Filament/AdminPanelProvider.php):

use InvadersXX\FilamentGridstackDashboard\GridStackDashboardPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(GridStackDashboardPlugin::make());
}

Where to look first, in order:

  1. src/GridStackDashboardPlugin.php — the plugin class is the whole public API surface; confirm the exact signatures of the three new setters here before wiring them up (whether canAccess takes a bool or a Closure, and whether it's evaluated per-request).
  2. resources/views/ — the Blade view that mounts GridStack and the container the JS binds to.
  3. config/filament-gridstack-dashboard.php (if published) — column counts, breakpoints, persistence settings.
  4. resources/js/ — the GridStack init; this is where drag handlers and the save call live.

First use case: replace the default Dashboard page so an authenticated user sees their own widgets, reorders them once, and finds the same arrangement on their next login.

Implementation Patterns

Per-panel registration. Register the plugin only on the panels that should have a grid dashboard. Filament resolves navigation from registered pages, so if the plugin is added to a panel that also renders the stock Dashboard, you'll end up with two entries — remove or disable the built-in one.

Gating with the new v1.9 options. The natural pattern is to define the dashboard once and vary exposure by role:

GridStackDashboardPlugin::make()
    ->canAccess(fn (): bool => auth()->user()?->can('view_grid_dashboard') ?? false)
    ->shouldRegisterNavigation(fn (): bool => auth()->user()?->isInternal() ?? false)
    ->navigationLabel('My Workspace'),

Think of these as three independent switches rather than one: canAccess controls authorisation, shouldRegisterNavigation controls whether the page appears in the sidebar, and navigationLabel only matters when navigation is registered. Using canAccess(false) with navigation still on gives you a hidden-but-reachable route that 403s — sometimes exactly what you want (deep links from emails), usually a bug.

Layout persistence as a first-class concern. The typical integration is: a widget list is declared (via Filament's getWidgets() / getHeaderWidgets() or the plugin's own registration method), the JS serialises {id, x, y, w, h} on change, and the server stores it keyed by user (and team/tenant if applicable). Treat the saved layout as hints, not as the source of truth for which widgets exist — always render the declared widget set and apply stored coordinates where an id matches.

Role-scoped dashboards. Combine the plugin with per-role widget resolution: canAccess on the dashboard plus canView() on individual widgets. Because GridStack persists positions by widget id, a saved layout containing widgets a user can no longer see should degrade gracefully — filter before handing the layout to the front end.

Multi-panel / tenant setups. If one panel serves multiple teams, key persistence by user_id and the current tenant. Reusing a single key means switching tenants silently reshuffles someone's dashboard.

Testing. The persistence endpoint is the piece worth unit-testing: assert that a posted layout is validated (widget ids belong to the user, coordinates are integers within bounds) and scoped to the authenticated user. The JS behaviour is better covered by a quick Dusk/browser smoke test on drag-and-resize than by trying to assert on GridStack internals.

Gotchas and Tips

  • Confirm the new signatures before shipping. The release note lists method names only. canAccess accepting a Closure vs a bool changes whether you can do per-request role checks; read GridStackDashboardPlugin.php and don't assume symmetry with Filament's Page::canAccess().
  • canAccess returning false does not remove the route. If navigation is registered, users see a menu item that errors on click. Pair access gating with shouldRegisterNavigation (or hidden()) unless the hidden-but-linkable behaviour is deliberate.
  • Navigation is cached in production. After changing shouldRegisterNavigation/navigationLabel, clear caches (php artisan filament:optimize-clear / optimize:clear) before concluding the option "doesn't work" — Filament caches component and navigation metadata.
  • Widgets without a saved position. Newly added widgets that aren't in a user's stored layout need a deterministic default, otherwise GridStack auto-places them and can overlap existing items. Append unknown widgets to the bottom rather than letting the library guess.
  • Coordinates drift across breakpoints. GridStack's responsive column counts mean a saved 12-column layout can look wrong at smaller breakpoints. Check whether the package persists per-breakpoint layouts or a single set; if single, restrict to one column count via config.
  • Asset loading. GridStack's JS/CSS must be registered through Filament's asset pipeline. If drag handles are dead, check the browser console for a missing GridStack global and whether published assets are stale after a package upgrade (php artisan filament:assets).
  • Lazy widgets and measurement. Widgets that lazy-load content can render at zero height inside the grid. Set an explicit min-height on the grid item, or disable lazy loading for widgets placed by this plugin.
  • Validation on the save endpoint. Layout payloads are user-supplied JSON. Validate the shape and clamp coordinates server-side; don't trust widths/heights from the request, or you'll get unrenderable dashboards saved permanently.
  • Extension points. Rather than editing the vendor view, subclass the plugin (or override the view via ->view()) and publish what you need. Any custom widget needs to be id-stable across deploys — deriving ids from class names is fine, deriving them from array indices will scramble everyone's layout on the next reorder.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect