mlsolutions/nova-dashboard is a Laravel package for the missing dashboard for nova..
It currently has 1 GitHub stars and 7.439 downloads on Packagist (latest version v1.1.1).
Install it with composer require mlsolutions/nova-dashboard.
Discover more Laravel packages by mlsolutions
or browse all Laravel packages to compare alternatives.
Last updated
The missing dashboard for Laravel Nova!
You can install the package via composer:
composer require mlsolutions/nova-dashboard
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'],
);
}),
];
}
}
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().
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);
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.
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: either csv or excel.Filters $filters: the same filter object used by widgets.array $filterValues: all current filters serialized as class, name, and value.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\Builder or Query\Builder: the package runs the query and exports the current result set.Collection, array or 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.rows, optional columns, and optional filename.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.
Please give a ⭐️ if this project helped you!
Help card that comes with Nova.The MIT License (MIT). Please see License File for more information.