Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tenant switcher #5

Open
vpratfr opened this issue Dec 13, 2018 · 2 comments
Open

Tenant switcher #5

vpratfr opened this issue Dec 13, 2018 · 2 comments

Comments

@vpratfr
Copy link

vpratfr commented Dec 13, 2018

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:

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>
@bkintanar
Copy link
Member

@vpratfr I've tried this and it is working with few modifications. Are you willing to create a PR for this or are you ok for me to proceed with this and use your approach?

@vpratfr
Copy link
Author

vpratfr commented Feb 20, 2020

Sure. Go ahead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants