Dashboard Widgets
Introduction
Dashboard widgets are customizable components that display information on the admin dashboard. Botble CMS provides two types of dashboard widgets:
- Stats Widgets: Small, card-like widgets that display a single statistic with an icon, color, and optional link.
- Content Widgets: Larger widgets that can display complex content, tables, charts, or other interactive elements.
Widgets are stored in the database and can be customized by users (enabled/disabled, reordered, etc.). The DashboardWidgetInstance
class provides a fluent interface for creating and configuring widgets.
Widget Architecture
Dashboard widgets are implemented using the following components:
- DashboardWidget: Model that stores basic widget information (name).
- DashboardWidgetSetting: Model that stores widget settings (status, order, user-specific settings).
- DashboardWidgetInstance: Helper class for creating and configuring widgets.
Stats Widgets
Stats widgets display a single statistic with an icon and color. They are typically used to show counts or other key metrics.
Creating a Stats Widget
To add a stats widget, use the DashboardWidgetInstance
class with the setType('stats')
method:
use Botble\Dashboard\Supports\DashboardWidgetInstance;
use Illuminate\Support\Collection;
add_filter(DASHBOARD_FILTER_ADMIN_LIST, function (array $widgets, Collection $widgetSettings) {
return (new DashboardWidgetInstance())
->setType('stats')
->setPermission('your.permission')
->setKey('widget_your_unique_key')
->setTitle(trans('your-plugin::your-plugin.widget_title'))
->setIcon('ti ti-chart-bar')
->setColor('primary')
->setStatsTotal(fn () => YourModel::query()->count())
->setRoute(route('your.route'))
->setColumn('col-12 col-md-6 col-lg-3')
->setPriority(99)
->init($widgets, $widgetSettings);
}, 99, 2);
Stats Widget Options
- setType('stats'): Specifies this is a stats widget (required for stats widgets).
- setPermission(): Permission required to view the widget.
- setKey(): Unique identifier for the widget (should start with 'widget_').
- setTitle(): Display name of the widget.
- setIcon(): Icon to display (using Tabler icons or Font Awesome).
- setColor(): Color of the widget (primary, success, warning, danger, info, etc.).
- setStatsTotal(): The statistic to display (can be a number or a closure that returns a number).
- setRoute(): URL to navigate to when the widget is clicked.
- setColumn(): Bootstrap column classes for responsive layout.
- setPriority(): Order priority (lower numbers appear first).
Example Stats Widget
Here's a real-world example from the Users plugin:
public static function addUserStatsWidget(array $widgets, Collection $widgetSettings): array
{
$users = fn () => User::query()->count();
return (new DashboardWidgetInstance())
->setType('stats')
->setPermission('users.index')
->setTitle(trans('core/acl::users.users'))
->setKey('widget_total_users')
->setIcon('ti ti-users')
->setColor('info')
->setStatsTotal($users)
->setRoute(route('users.index'))
->setColumn('col-12 col-md-6 col-lg-3')
->init($widgets, $widgetSettings);
}
Content Widgets
Content widgets can display complex information such as tables, charts, or other interactive elements. They load their content via AJAX from a specified route.
Creating a Content Widget
To add a content widget, use the DashboardWidgetInstance
class without setting a type (the default type is 'widget'):
use Botble\Dashboard\Supports\DashboardWidgetInstance;
use Illuminate\Support\Collection;
add_filter(DASHBOARD_FILTER_ADMIN_LIST, function (array $widgets, Collection $widgetSettings) {
return (new DashboardWidgetInstance())
->setPermission('your.permission')
->setKey('widget_your_unique_key')
->setTitle(trans('your-plugin::your-plugin.widget_title'))
->setIcon('ti ti-list')
->setColor('success')
->setRoute(route('your.widget.data'))
->setBodyClass('scroll-table')
->setColumn('col-md-6 col-sm-6')
->setPriority(99)
->init($widgets, $widgetSettings);
}, 99, 2);
Content Widget Options
- setPermission(): Permission required to view the widget.
- setKey(): Unique identifier for the widget (should start with 'widget_').
- setTitle(): Display name of the widget.
- setIcon(): Icon to display in the widget header.
- setColor(): Color accent for the widget.
- setRoute(): AJAX route that will return the widget content.
- setBodyClass(): CSS classes to add to the widget body.
- setColumn(): Bootstrap column classes for responsive layout.
- setPriority(): Order priority (lower numbers appear first).
- setHasLoadCallback(true): Indicates the widget has a JavaScript callback after loading.
- setIsEqualHeight(false): Disables equal height enforcement for the widget.
- setSettings(): Additional settings for the widget.
Creating the Widget Content Controller
You need to create a controller method to handle the AJAX request and return the widget content:
use Botble\Base\Http\Responses\BaseHttpResponse;
use Illuminate\Http\Request;
public function getWidgetData(Request $request, BaseHttpResponse $response)
{
// Get data for the widget
$data = YourModel::query()
->latest()
->with('relation')
->limit(10)
->get();
// Return the rendered view as the widget content
return $response->setData(view('your-plugin::widgets.your-widget', compact('data'))->render());
}
Example Content Widget
Here's a real-world example from the Request Log plugin:
public function registerDashboardWidgets(array $widgets, Collection $widgetSettings): array
{
if (! Auth::guard()->user()->hasPermission('request-log.index')) {
return $widgets;
}
Assets::addScriptsDirectly(['vendor/core/plugins/request-log/js/request-log.js']);
return (new DashboardWidgetInstance())
->setPermission('request-log.index')
->setKey('widget_request_errors')
->setTitle(trans('plugins/request-log::request-log.widget_request_errors'))
->setRoute(route('request-log.widget.request-errors'))
->setColumn('col-md-6 col-sm-6')
->init($widgets, $widgetSettings);
}
And the corresponding controller method:
public function getRequestErrors(Request $request, BaseHttpResponse $response)
{
$limit = $request->integer('limit', 10);
$limit = $limit > 0 ? $limit : 10;
$requests = RequestLog::query()
->orderBy('created_at', 'desc')
->limit($limit)
->get();
return $response->setData(view('plugins/request-log::widgets.request-errors', compact('requests', 'limit'))->render());
}
Widget Settings
Widgets can have settings that allow users to customize their behavior. These settings are stored in the dashboard_widget_settings
table.
Adding Settings to a Widget
Use the setSettings()
method to add default settings to a widget:
->setSettings([
'show_predefined_ranges' => true,
'limit' => 10,
'state' => 'expanded',
])
Date Range Settings
For widgets that display time-based data, you can add predefined date ranges:
->setSettings(['show_predefined_ranges' => true])
->setPredefinedRanges([
'today' => [
'key' => 'today',
'label' => trans('core/dashboard::dashboard.predefined_ranges.today'),
'startDate' => Carbon::today()->startOfDay(),
'endDate' => Carbon::today()->endOfDay(),
],
'this_week' => [
'key' => 'this_week',
'label' => trans('core/dashboard::dashboard.predefined_ranges.this_week'),
'startDate' => Carbon::now()->startOfWeek(),
'endDate' => Carbon::now()->endOfWeek(),
],
])
Saving Widget Settings
You can save widget settings programmatically using the saveSettings()
method:
$widgetInstance = new DashboardWidgetInstance();
$widgetInstance->saveSettings('widget_your_unique_key', [
'limit' => 20,
'state' => 'collapsed',
]);
Managing Widgets
Removing a Widget by ID
To remove a specific widget:
add_filter(DASHBOARD_FILTER_ADMIN_LIST, function (array $widgets) {
\Illuminate\Support\Arr::forget($widgets, 'widget_your_unique_key');
return $widgets;
}, 120, 1);
Removing All Widgets
To remove all dashboard widgets:
remove_filter(DASHBOARD_FILTER_ADMIN_LIST);
Widget Events and Actions
Botble CMS provides events and actions for dashboard widgets:
- RenderingDashboardWidgets: Event dispatched before rendering dashboard widgets.
- DASHBOARD_FILTER_ADMIN_LIST: Filter to add or modify dashboard widgets.
- DASHBOARD_ACTION_REGISTER_SCRIPTS: Action to register additional scripts for dashboard widgets.
Example: Adding Scripts for Widgets
add_action(DASHBOARD_ACTION_REGISTER_SCRIPTS, function () {
Assets::addScriptsDirectly(['vendor/core/plugins/your-plugin/js/your-widget.js']);
});
Best Practices
Unique Keys: Always use unique keys for your widgets, preferably prefixed with 'widget_' and your plugin name.
Permissions: Always check permissions to ensure users only see widgets they have access to.
Responsive Design: Use appropriate column classes to ensure widgets look good on all screen sizes.
Performance: For stats widgets that query the database, consider using closures to defer execution until needed.
Caching: For widgets with expensive data operations, consider caching the results.
Asset Management: Register any required CSS or JavaScript files using the DASHBOARD_ACTION_REGISTER_SCRIPTS action.
Translations: Use translation strings for widget titles and content for better localization support.