-
-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Description
I don't really have the time to submit a proper PR, but here is what it takes to make a tenant switcher for Nova.
My use cas is the following:
- Product landing page at http://example.com
- Admin interface at http://admin.example.com (one particular tenant)
- Tenants at http://xyz.example.com
- Nova is plugged only on the admin tenant. This means http://admin.example.com/nova will work, but http://xyz.example.com/nova will 404.
I needed that:
- Nova only shows "system" resources when viewing the admin tenant
- Nova only shows "tenant" resources when virtually switched to a client tenant
New Middleware
namespace App\Nova\Middleware;
use Closure;
use Domain\CustomerAccounts\Models\Website;
use Hyn\Tenancy\Environment;
class TenantSwitcherMiddleware
{
/** @var \Hyn\Tenancy\Environment */
private $environment;
public function __construct(Environment $environment)
{
$this->environment = $environment;
}
public function handle($request, Closure $next)
{
$currentTenant = Website::find(session()->get('nova.tenant', 0))
?? Website::whereUuid(Website::ADMIN_TENANT_UUID)->first();
$this->environment->tenant($currentTenant);
$this->environment->hostname($currentTenant->hostname);
config()->set('tenancy.hostname.auto-identification', false);
return $next($request);
}
}
New view for the switcher dropdown
Create a new file resources/views/vendor/nova/partials/tenant-switcher.blade.php
@php($currentWebsite = app(Hyn\Tenancy\Environment::class)->website())
@php($websites = Domain\CustomerAccounts\Models\Website::get())
<dropdown-trigger class="h-9 flex items-center" slot-scope="{toggle}" :handle-click="toggle">
<span class="text-90">
@if($currentWebsite->is_admin_tenant)
Switch tenant...
@else
{{-- We have an extra customer table for billing, could use hostname->first()->fqdn instead of customer->name --}}
{{ $currentWebsite->customer->name ?? $currentWebsite->uuid }}
@endif
</span>
</dropdown-trigger>
<dropdown-menu slot="menu" width="200" direction="rtl">
<ul class="list-reset">
<li>
<a href="{{ route('web.nova.tenant.switch') }}" class="block no-underline text-90 hover:bg-30 p-3">
Admin tenant
</a>
</li>
@foreach($websites->reject->is_admin_tenant as $website)
<li>
<a href="{{ route('web.nova.tenant.switch', $website) }}" class="block no-underline text-90 hover:bg-30 p-3">
{{ $website->customer->name ?? $website->uuid }}
</a>
</li>
@endforeach
</ul>
</dropdown-menu>
New controller to make the switch
namespace App\Nova\Web\Controllers;
use App\Shared\Http\Controllers\Controller;
use Domain\CustomerAccounts\Models\Website;
use Illuminate\Http\Request;
class TenantController extends Controller
{
public function switchTo(Request $request, ?Website $website = null)
{
session()->put('nova.tenant', $website->id ?? 0);
return \redirect()->back();
}
}
New route to that controller
You should add that route so that it is only accessible to the admin middleware. We have automatted
Route::domain('admin.' . env('APP_DOMAIN'))->prefix('/nova')->group(function () {
Route::get('/switch-tenant/{website?}')->name('tenant.switch')->uses([TenantController::class, 'switchTo']);
});
Nova configuration
Add our manual tenant switcher middleware as last item in the nova configuration entry: nova.middleware
Nova layout
We need to change the Nova default layout in order to include our tenant switcher dropdown in the top bar.
Copy vendor/laravel/nova/resources/views/layout.blade.php to resources/views/vendor/nova/layout.blade.php
Then you can replace:
<dropdown class="ml-auto h-9 flex items-center dropdown-right">
@include('nova::partials.user')
</dropdown>
with
<div class="ml-auto flex">
<dropdown class="h-9 items-center dropdown-right">
@include('nova::partials.tenant-switcher')
</dropdown>
<dropdown class="h-9 ml-6 items-center dropdown-right">
@include('nova::partials.user')
</dropdown>
</div>
Metadata
Metadata
Assignees
Labels
No labels