feat: implement multi-tenancy and super admin impersonation with security banner
This commit is contained in:
@@ -13,6 +13,21 @@ const showingNavigationDropdown = ref(false);
|
||||
<template>
|
||||
<div>
|
||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-900">
|
||||
<!-- Impersonation Banner -->
|
||||
<div v-if="$page.props.tenant.is_impersonating" class="bg-amber-500 text-white py-2 px-4 shadow-md">
|
||||
<div class="max-w-7xl mx-auto flex justify-between items-center text-sm font-bold">
|
||||
<div class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
<span>MODE SIMULATION ACTIF : Vous modifiez actuellement le locataire "{{ $page.props.tenant.current ? $page.props.tenant.current.name : 'VUE GLOBALE' }}"</span>
|
||||
</div>
|
||||
<Link :href="route('superadmin.reset')" method="post" as="button" class="bg-white text-amber-600 px-3 py-1 rounded-md hover:bg-amber-50 transition-colors">
|
||||
Arrêter la simulation
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav
|
||||
class="border-b border-gray-100 bg-white dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
@@ -20,13 +35,16 @@ const showingNavigationDropdown = ref(false);
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-16 justify-between">
|
||||
<div class="flex">
|
||||
<!-- Logo -->
|
||||
<div class="flex shrink-0 items-center">
|
||||
<!-- Logo and Structure Name -->
|
||||
<div class="flex shrink-0 items-center space-x-3">
|
||||
<Link :href="route('dashboard')">
|
||||
<ApplicationLogo
|
||||
class="block h-9 w-auto"
|
||||
/>
|
||||
</Link>
|
||||
<span class="text-lg font-bold text-gray-800 dark:text-gray-200">
|
||||
{{ $page.props.tenant.current ? $page.props.tenant.current.name : ($page.props.auth.user.structure ? $page.props.auth.user.structure.name : '') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Links -->
|
||||
@@ -40,40 +58,48 @@ const showingNavigationDropdown = ref(false);
|
||||
Tableau de Bord
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('users.index')"
|
||||
:active="route().current('users.*')"
|
||||
>
|
||||
Utilisateurs
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('roles.index')"
|
||||
:active="route().current('roles.*')"
|
||||
>
|
||||
Rôles
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('permissions.index')"
|
||||
:active="route().current('permissions.*')"
|
||||
>
|
||||
Permissions
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('services.index')"
|
||||
:active="route().current('services.*')"
|
||||
>
|
||||
Services
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('templates.index')"
|
||||
:active="route().current('templates.*')"
|
||||
>
|
||||
Modèles
|
||||
</NavLink>
|
||||
<NavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'SuperAdmin')"
|
||||
:href="route('superadmin.index')"
|
||||
:active="route().current('superadmin.*')"
|
||||
class="text-indigo-600 dark:text-indigo-400 font-bold"
|
||||
>
|
||||
🛠️ SaaS Admin
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,40 +208,48 @@ const showingNavigationDropdown = ref(false);
|
||||
Tableau de Bord
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('users.index')"
|
||||
:active="route().current('users.*')"
|
||||
>
|
||||
Utilisateurs
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('roles.index')"
|
||||
:active="route().current('roles.*')"
|
||||
>
|
||||
Rôles
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('permissions.index')"
|
||||
:active="route().current('permissions.*')"
|
||||
>
|
||||
Permissions
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('services.index')"
|
||||
:active="route().current('services.*')"
|
||||
>
|
||||
Services
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin')"
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'Admin' || r.name === 'SuperAdmin')"
|
||||
:href="route('templates.index')"
|
||||
:active="route().current('templates.*')"
|
||||
>
|
||||
Modèles
|
||||
</ResponsiveNavLink>
|
||||
<ResponsiveNavLink
|
||||
v-if="$page.props.auth.user.roles.some(r => r.name === 'SuperAdmin')"
|
||||
:href="route('superadmin.index')"
|
||||
:active="route().current('superadmin.*')"
|
||||
class="text-indigo-600 dark:text-indigo-400 font-bold"
|
||||
>
|
||||
🛠️ SaaS Admin
|
||||
</ResponsiveNavLink>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Settings Options -->
|
||||
@@ -261,6 +295,18 @@ const showingNavigationDropdown = ref(false);
|
||||
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
<!-- Flash Messages -->
|
||||
<div v-if="$page.props.flash.success" class="max-w-7xl mx-auto mt-4 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative" role="alert">
|
||||
<span class="block sm:inline">{{ $page.props.flash.success }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="$page.props.flash.error" class="max-w-7xl mx-auto mt-4 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
||||
<span class="block sm:inline">{{ $page.props.flash.error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user