gabelbart/nova-toolbar-tools

Adds toolbar tools and toolbar resources to laravel nova.

0.3.0 2021-09-19 16:52 UTC

This package is auto-updated.

Last update: 2022-05-22 09:19:30 UTC


README

Nova Toolbar Tools

A composer package for laravel nova. It enables you to globally select and persist resources.

Example use-cases:

  • Base for developing your own toolbar-tools
  • Select a model you want to filter for in some resources without applying the filter every time but only once every session
  • Customize the menu based on the selection
    • Hide or show resources
    • Hide or show tools
  • Customize tool behaviour based on global selection

Requirements

  • Laravel Nova 3

Installation

composer require gabelbart/nova-toolbar-tools

Add the component to the Nova template

Copy vendor/laravel/nova/resources/views/layout.blade.php to resources/views/vendor/nova/layout.blade.php

Add the following:

<toolbar-tool-list class="mx-3"></toolbar-tool-list>

To the top toolbar (body > #nova > .flex > .content > .flex:first-child) on a position you like and adjust the margins. The result could look like this:

<!-- ... SNIP -->

<!-- Content -->
<div class="content">
    <div class="flex items-center relative shadow h-header bg-white z-20 px-view">
        <a v-if="@json(\Laravel\Nova\Nova::name() !== null)" href="{{ \Illuminate\Support\Facades\Config::get('nova.url') }}" class="no-underline dim font-bold text-90 mr-6">
            {{ \Laravel\Nova\Nova::name() }}
        </a>

        @if (count(\Laravel\Nova\Nova::globallySearchableResources(request())) > 0)
            <global-search dusk="global-search-component"></global-search>
        @endif

        <!-- TOOLS GO HERE: before the 'user-dropdown', auto-margin left, med margin right -->
        <toolbar-tool-list class="ml-auto mr-3"></toolbar-tool-list>

        <dropdown class="ml-3 h-9 flex items-center dropdown-right">
            @include('nova::partials.user')
        </dropdown>
    </div>

    <div data-testid="content" class="px-view py-view mx-auto">
        @yield('content')

        @include('nova::partials.footer')
    </div>
</div>

<!-- SNIP ... -->

Add the middleware to the nova config

Add \Gabelbart\Laravel\Nova\ToolbarTools\Http\Middleware\BootToolbarTools::class to the middleware list in config/nova.php

Load tools in your \App\Providers\NovaServiceProvider

Add this method:

public function toolbarTools()
{
    return [
    ];
}

Add these lines to the boot method:

Nova::serving(function () {
    \Gabelbart\Laravel\Nova\ToolbarTools\ToolbarTools::toolbarTools($this->toolbarTools());
});

If you already have a Nova::serving block, you might just combine the contsnts.

Usage

Toolbar resources

Set up toolbar resource

Let's say you have a Resource \App\Nova\Publisher, to create a toolbar-dropdown you need to creat an instance of \Gabelbart\Laravel\Nova\ToolbarTools\Tools\ToolbarResource. Add the following to the toolbarTools method of your NovaServiceProvider:

ToolbarResource::make(\App\Nova\Publisher::class)

It might look like this then:

public function toolbarTools()
{
    return [
        ToolbarResource::make(\App\Nova\Publisher::class)
    ];
}

Access the value

Anywhere in nova you can now access the value with the static sessionValueFor method of \Gabelbart\Laravel\Nova\ToolbarTools\Tools\ToolbarResource. For example:

/** @var ?\App\Models\Publisher $publisher */
$publisher = ToolbarResource::sessionValueFor(\App\Nova\Publisher::class);

In addition, you can use the \Gabelbart\Laravel\Nova\ToolbarTools\Traits\HasToolbarSelection trait. This enables you to call the getToolbarSelection and getToolbarSelectionOrFail static methods of your resources.

class Publisher extends \Laravel\Nova\Resource
{
    use \Gabelbart\Laravel\Nova\ToolbarTools\Traits\HasToolbarSelection;
}

/** @var ?\App\Models\Publisher $model */
$model = Publisher::getToolbarSelection();

Options

Label

By default the label of your nova-resource will be used, this can be customized:

ToolbarResource::make(\App\Nova\Publisher::class)
    ->withLabel(__('my_own_label'))

Searchable

By default all possible options will be displayed. If you rather want the user to search you can use the searchable option.

ToolbarResource::make(\App\Nova\Publisher::class)
    ->searchable()

Search - Hotkey

If you want to assign a hotkey to the search you can provide an Mousetrap option (https://craig.is/killing/mice). As second parameter you can optionally provide an alternative label.

ToolbarResource::make(\App\Nova\Publisher::class)
    ->withSearchHotkey('alt+p', '[Alt] + [p]')

Selection

By default the value from the session will be used, if you turned that off you might want to set the selected value yourself.

ToolbarResource::make(\App\Nova\Publisher::class)
    ->selection(\Auth::user()->favoritePublisher())

Saving to session

By default the value from the selection will be remembered within the session. If you want to change that call the saveToSession method with false as parameter. You might want to consider persisting the value and providing the selection yourself then, have a look at selection and onChange.

ToolbarResource::make(\App\Nova\Publisher::class)
    ->saveToSession(false)

Reacting to selection

If you want to customize the behaviour for a selection change you can do this within a custom callback. The request will have a parameter called id containing the primary key of the selection.

ToolbarResource::make(\App\Nova\Publisher::class)
    ->onChange(fn (\Illuminate\Http\Request $request) => \App\Nova\Publisher::onChangeToolbarSelection($request))

Manipulating the index-query

Note: This will not work for the search option since it's using the global search of nova.

If you want to customize the list of available options you can use the withIndexQuery method. It receives the internal query builder as parameter. However, you can return your own query builder instance if you want to replace the internal query builder.

ToolbarResource::make(\App\Nova\Book::class)
    ->withIndexQuery(fn (\Illuminate\Database\Eloquent\Builder $builder) => $builder->where('publisher_id', \Auth::user()->id))