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

@@ -2,7 +2,7 @@
<div v-if="visible" class="modal modal-open">
<div class="modal-box max-w-md">
<h3 class="font-bold text-lg mb-4">
Modifier le site
{{ disabled ? 'Détails du site' : 'Modifier le site' }}
<span v-if="siteName" class="block text-sm font-normal text-gray-500">{{ siteName }}</span>
</h3>
<form class="space-y-4" @submit.prevent="emit('submit')">
@@ -15,11 +15,12 @@
type="text"
placeholder="Nom du site"
class="input input-bordered"
:disabled="disabled"
required
>
</div>
<SiteContactFormFields :form="props.form" />
<SiteContactFormFields :form="props.form" :disabled="disabled" />
<div class="border-t border-base-200 pt-4 space-y-4">
<div class="flex items-center justify-between">
@@ -37,6 +38,7 @@
</div>
<DocumentUpload
v-if="!disabled"
v-model="selectedFilesModel"
title="Déposer vos fichiers"
subtitle="Formats courants acceptés : PDF, JPG, PNG, DOCX..."
@@ -90,7 +92,7 @@
<button type="button" class="btn btn-ghost btn-xs" @click="emit('download-document', document)">
Télécharger
</button>
<button type="button" class="btn btn-error btn-xs" @click="emit('remove-document', document.id)">
<button v-if="!disabled" type="button" class="btn btn-error btn-xs" @click="emit('remove-document', document.id)">
Supprimer
</button>
</div>
@@ -103,7 +105,7 @@
<button type="button" class="btn" @click="emit('close')">
Annuler
</button>
<button type="submit" class="btn btn-primary" :disabled="uploadingDocuments">
<button type="submit" class="btn btn-primary" :disabled="disabled || uploadingDocuments">
<span v-if="uploadingDocuments" class="loading loading-spinner loading-xs mr-2" />
Enregistrer
</button>
@@ -155,6 +157,10 @@ const props = defineProps({
formatSize: {
type: Function,
required: true
},
disabled: {
type: Boolean,
default: false
}
})