cmsmaxinc/filament-system-versions
Filament System Versions adds a convenient admin page for viewing PHP, Laravel, Filament, database, and Composer package versions at a glance. Quickly audit environments, troubleshoot support requests, and keep deployments in sync without leaving your Filament panel.
Install the package with Composer and let Filament discover it:
composer require cmsmaxinc/filament-system-versions
If the package ships a config or migrations, publish them explicitly:
php artisan vendor:publish --tag="filament-system-versions-config"
Where to look first:
src/ directory — start with the service provider to see what it registers (widgets, views, config, blade components).getViewData() methods tell you exactly what data is exposed and how it's fetched.resources/views folder — if you want to change the layout, overriding the Blade view is usually faster than subclassing.First use case: add a "System Information" widget to an admin-only dashboard so support/ops staff can see the PHP version, Laravel version, Filament version, and installed Composer packages without SSHing into the server.
Register it in your panel provider:
public function panel(Panel $panel): Panel
{
return $panel
->id('admin')
->widgets([
\Cmsmaxinc\FilamentSystemVersions\Widgets\SystemVersions::class,
]);
}
Confirm the exact widget namespace against the package README or src/Widgets/ before wiring it up — the class name is the one thing that changes between versions.
Gate it behind authorization. This is the single most important pattern. Dependency versions are a fingerprint of known CVEs; don't render this on a customer-facing panel.
// In the widget subclass
public static function canView(): bool
{
return auth()->user()?->hasRole('super_admin') ?? false;
}
Alternatively, only register the widget inside an admin panel provider and leave your user-facing panels untouched.
Wrap data collection in a cached service. Reading composer.lock / vendor/composer/installed.json on every dashboard load is wasteful and can be slow on large dependency trees. If the package doesn't already cache, decorate it:
// app/Support/SystemVersionsCache.php
public function packages(): array
{
return Cache::remember('system-versions.packages', now()->addHours(6), function () {
// delegate to the package's data source or parse installed.json yourself
});
}
Then subclass the widget and feed it your cached data. Clear the cache as part of your deploy script so a fresh composer install is reflected immediately.
Use it on a dedicated page, not just the dashboard. A common pattern is a custom Filament Page (SystemInfo) that hosts several of the package's widgets as a "health/status" screen, keeping the main dashboard clean:
protected static string $view = 'filament.pages.system-info';
protected function getHeaderWidgets(): array
{
return [
SystemVersionsWidget::class,
// other health widgets
];
}
This is also where you'd add complementary info (queue worker status, last deploy time, disk usage) so ops has one place to look.
Register per panel, not globally. If you have admin and app panels, register only in admin. Don't rely on discoverWidgets() blindly if the widget lives in a directory shared by multiple panels.
Control placement with $sort, $columnSpan. These are standard Filament stat/widget properties; use them to make the widget sit alongside your other dashboard cards rather than pushing them around.
Subclass for customization. Rather than editing published views, extend the widget and override getViewData() or getStats() — it survives package updates:
class MySystemVersions extends SystemVersionsWidget
{
protected static ?int $sort = 100;
protected int|string|array $columnSpan = 'full';
}
canView() on every panel where it's registered.getStats() return types, static vs instance properties). Pin the package version and check the composer constraints before upgrading Filament. With a 14-star package, expect the maintainer to lag behind major Filament releases — test the widget renders before rolling out a Filament upgrade.vendor/composer/installed.json may not exist on stripped production builds, and composer.lock is often excluded from deploys if you composer install from a committed lock. Verify which file the package reads and that it's present in your deployment artifact. If it fails, you'll typically get an empty or partially empty package list rather than an exception — make sure the widget shows a clear "unavailable" state.discoverWidgets() and an explicit ->widgets([...]) list, you can register the widget twice. Pick one strategy.installed.json parser in an afternoon if it's abandoned. The underlying data is trivial to source yourself.phpversion(), app()->version()) the first time you deploy — if the widget reads from a lockfile or a config value rather than the live runtime, it can drift from what's actually executing (e.g. when your CLI and FPM PHP versions differ).How can I help you explore Laravel packages today?