mlsolutions / nova-dashboard
The missing dashboard for nova.
Fund package maintenance!
Requires
- php: >=8.1
- laravel/nova: ^4.28.0|^5.0
README
The missing dashboard for Laravel Nova!
Installation
You can install the package via composer:
composer require mlsolutions/nova-dashboard
List of current available widgets:
- Value Widget: https://github.com/ml-solutions-ltda/value-widget
- Table Widget: https://github.com/ml-solutions-ltda/table-widget
- ChartJs Widget: https://github.com/ml-solutions-ltda/chartjs-widget
- Add your widget here.
Usage
The dashboard itself is simply a standard Laravel Nova card, so you can use it either as a card on any resource or within the default Nova dashboard functionality.
use App\Models\User; use MlSolutions\NovaDashboard\Card\NovaDashboard; use MlSolutions\NovaDashboard\Card\View; use MlSolutions\NovaDashboard\Filters; use Laravel\Nova\Dashboards\Main as Dashboard; class Main extends Dashboard { public function cards(): array { return [ NovaDashboard::make() ->addView('Website Performance', function (View $view) { return $view ->icon('window') ->addWidgets([ BounceRate::make(), ConversionRate::make(), WebsiteTraffic::make(), SessionDuration::make(), ]) ->addFilters([ LocationFilter::make(), UserTypeFilter::make(), DateRangeFilter::make(), ]) ->download( resolver: function ($request, View $view, string $format, Filters $filters) { return $filters ->applyToQueryBuilder(User::query()) ->select('name', 'email', 'created_at'); }, label: 'Download Report', filename: 'website-performance', formats: ['csv', 'excel'], ); }), ]; } }
Static
By default, each widget is draggable, and the user is able to rearrange it to their liking.
This behavior can be disabled by calling $view->static().
Widgets
The widgets are responsible for displaying your data on your views; they are essentially standard Nova cards. However, they respond to dashboard events and reload their data whenever the filters change.
Once you have a widget, they are usually configured like this:
class MyCustomWidget extends ValueWidget { /** * Here you can configure your widget by calling whatever options are available for each widget */ public function configure(NovaRequest $request): void { $this->icon('<svg>...</svg>'); $this->title('Session Duration'); $this->textColor('#f95738'); $this->backgroundColor('#f957384f'); } /** * This function is responsible for returning the actual data that will be shown on the widget, * each widget expects its own format, so please refer to the widget documentation */ public function value(Filters $filters): mixed { /** * $filters contain all the set values from the filters that were shown on the frontend. * You can retrieve them and implement any custom logic you may have. */ $filterValue = $filters->getFilterValue(LikesFilter::class); return 'example'; } }
All widgets have common methods to configure their size and position.
The value is not in pixels but in grid units, ranging from 1 to 12 (corresponding to 12 columns).
$widget->layout(width: 2, height: 1, x: 0, y: 1); $widget->minWidth(2); $widget->minHeight(1);
Filters
These are standard nova filter classes with 1 simple difference, the method ->apply() does not get called by default. Why?
use Illuminate\Http\Request; use Laravel\Nova\Filters\BooleanFilter; class ExampleFilter extends BooleanFilter { public function apply(Request $request, $query, $value) { // this function is required however it is not used by the nova-dashboard } }
Usually your widget ->value() function will receive an instance of MlSolutions\NovaDashboard\Filters this class
contains a method for retrieving the value of any given filter, for example:
class SessionDuration extends ValueWidget { public function value(Filters $filters): mixed { $filterA = $filters->getFilterValue(YourFilterClass::class); $filterB = $filters->getFilterValue(YourSecondFilterClass::class); } }
However, if you want to reuse the logic that you have previously set on your filters or share existing filters with
the dashboard you can call the method ->applyToQueryBuilder() to get the same behavior:
class SessionDuration extends ValueWidget { public function value(Filters $filters): mixed { $result = $filters->applyToQueryBuilder(User::query())->get(); } }
->applyToQueryBuilder() will run every filter through the default filter logic of nova.
Downloads
Views can expose a report download button that always uses the filters currently applied in the dashboard.
use App\Models\User; use MlSolutions\NovaDashboard\Card\View; use MlSolutions\NovaDashboard\Downloads\DownloadResult; use MlSolutions\NovaDashboard\Filters; use Laravel\Nova\Http\Requests\NovaRequest; $view->download( resolver: function (Filters $filters, NovaRequest $request, View $view, string $format) { return $filters ->applyToQueryBuilder(User::query()) ->select('name', 'email', 'created_at'); }, label: 'Download Users', filename: 'users-report', formats: ['csv', 'excel'], );
The resolver receives the current dashboard filter state, not a prebuilt query result.
Available callback arguments:
NovaRequest $request: the active Nova request.View $view: the current dashboard view.string $format: eithercsvorexcel.Filters $filters: the same filter object used by widgets.array $filterValues: all current filters serialized asclass,name, andvalue.
This matches how dashboards are commonly built in real projects such as socialnexa-nova: widgets read filter values and then assemble the query or service call that produces the final dataset.
Accepted resolver return types:
Eloquent\BuilderorQuery\Builder: the package runs the query and exports the current result set.Collection,arrayor any iterable list of rows: columns are inferred automatically.DownloadResult: use it when you want full control over columns, row order or the exported filename.- An array with
rows, optionalcolumns, and optionalfilename.
Example with custom column order:
$view->download( resolver: function (Filters $filters, NovaRequest $request, View $view, string $format) { $rows = $filters ->applyToQueryBuilder(User::query()) ->get() ->map(fn (User $user) => [ 'Name' => $user->name, 'Email' => $user->email, 'Joined At' => $user->created_at?->toDateString(), ]); return DownloadResult::make( columns: ['Name', 'Email', 'Joined At'], rows: $rows, filename: 'filtered-users', ); }, );
Example using the raw serialized filter values:
$view->download( resolver: function (array $filterValues) { $dateRange = data_get($filterValues, App\Nova\Filters\CreateAtDateFilter::class . '.value'); // Build your own query/service call from the active filter values. return []; }, );
excel exports a native Excel-compatible .xls file, while csv exports UTF-8 CSV with BOM for spreadsheet compatibility.
⭐️ Show Your Support
Please give a ⭐️ if this project helped you!
Other Packages You Might Like
- Nova Dashboard - The missing dashboard for Laravel Nova!
- Nova Welcome Card - A configurable version of the
Help cardthat comes with Nova. - Icon Action Toolbar - Replaces the default boring action menu with an inline row of icon-based actions.
- Expandable Table Row - Provides an easy way to append extra data to each row of your resource tables.
- Collapsible Resource Manager - Provides an easy way to order and group your resources on the sidebar.
- Resource Navigation Tab - Organize your resource fields into tabs.
- Resource Navigation Link - Create links to internal or external resources.
- Nova Mega Filter - Display all your filters in a card instead of a tiny dropdown!
- Nova Pill Filter - A Laravel Nova filter that renders into clickable pills.
- Nova Slider Filter - A Laravel Nova filter for picking range between a min/max value.
- Nova Range Input Filter - A Laravel Nova range input filter.
- Nova FilePond - A Nova field for uploading File, Image and Video using Filepond.
- Custom Relationship Field - Emulate HasMany relationship without having a real relationship set between resources.
- Column Toggler - A Laravel Nova package that allows you to hide/show columns in the index view.
- Batch Edit Toolbar - Allows you to update a single column of a resource all at once directly from the index page.
License
The MIT License (MIT). Please see License File for more information.