feat(permissions) : add role-based UI guards and readonly mode for viewers

- Add usePermissions composable (isAdmin, canEdit, canView)
- Password-protected profile login with modal on profiles page
- Disable all form fields for ROLE_VIEWER across edit/create pages
- Show navigation buttons (Modifier/Consulter) for all roles, hide delete for viewers
- Add readonly prop to ModelTypeForm for category pages
- Disable modal fields (sites, constructeurs) for viewers
- Guard /admin routes in middleware

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-02-26 13:36:42 +01:00
parent 6bed715b7f
commit cc70fe2b29
46 changed files with 946 additions and 423 deletions

View File

@@ -186,9 +186,9 @@
Connecté en tant que<br />
<span class="font-semibold text-base-content">{{ activeProfileLabel }}</span>
</li>
<li>
<NuxtLink to="/profiles/manage" class="justify-between">
Gestion des profils
<li v-if="isAdmin">
<NuxtLink to="/admin" class="justify-between">
Administration
<IconLucideChevronRight class="w-4 h-4" aria-hidden="true" />
</NuxtLink>
</li>
@@ -214,6 +214,7 @@
import { computed } from 'vue'
import { useRoute } from '#imports'
import { useNavDropdown } from '~/composables/useNavDropdown'
import { usePermissions } from '~/composables/usePermissions'
import { useProfileSession } from '~/composables/useProfileSession'
import IconLucideMenu from '~icons/lucide/menu'
import IconLucideSettings from '~icons/lucide/settings'
@@ -288,6 +289,7 @@ const navGroups: NavGroup[] = [
const route = useRoute()
const { openDropdown, setDropdown, scheduleDropdownClose, toggleDropdown } = useNavDropdown()
const { activeProfile } = useProfileSession()
const { isAdmin } = usePermissions()
const isActive = (path: string) => {
if (path === '/') {