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:
@@ -28,7 +28,7 @@
|
||||
empty-text="Aucune catégorie disponible"
|
||||
:option-label="typeOptionLabel"
|
||||
:option-description="typeOptionDescription"
|
||||
:disabled="loadingTypes || submitting"
|
||||
:disabled="!canEdit || loadingTypes || submitting"
|
||||
/>
|
||||
<p v-if="loadingTypes" class="text-xs text-gray-500 mt-1">
|
||||
Chargement des catégories…
|
||||
@@ -45,7 +45,7 @@
|
||||
v-model="creationForm.name"
|
||||
type="text"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:disabled="submitting || !selectedType"
|
||||
:disabled="!canEdit || submitting || !selectedType"
|
||||
placeholder="Nom affiché dans le catalogue"
|
||||
required
|
||||
>
|
||||
@@ -61,7 +61,7 @@
|
||||
v-model="creationForm.reference"
|
||||
type="text"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:disabled="submitting || !selectedType"
|
||||
:disabled="!canEdit || submitting || !selectedType"
|
||||
placeholder="Référence interne ou fournisseur"
|
||||
>
|
||||
</div>
|
||||
@@ -73,7 +73,7 @@
|
||||
<ConstructeurSelect
|
||||
v-model="creationForm.constructeurIds"
|
||||
class="w-full"
|
||||
:disabled="submitting || !selectedType"
|
||||
:disabled="!canEdit || submitting || !selectedType"
|
||||
placeholder="Rechercher un ou plusieurs fournisseurs..."
|
||||
/>
|
||||
</div>
|
||||
@@ -90,7 +90,7 @@
|
||||
step="0.01"
|
||||
min="0"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:disabled="submitting || !selectedType"
|
||||
:disabled="!canEdit || submitting || !selectedType"
|
||||
placeholder="Valeur indicatrice"
|
||||
>
|
||||
</div>
|
||||
@@ -244,7 +244,7 @@
|
||||
type="text"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:required="field.required"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
<input
|
||||
v-else-if="field.type === 'number'"
|
||||
@@ -253,14 +253,14 @@
|
||||
step="0.01"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:required="field.required"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
<select
|
||||
v-else-if="field.type === 'select'"
|
||||
v-model="field.value"
|
||||
class="select select-bordered select-sm md:select-md"
|
||||
:required="field.required"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
<option value="">Sélectionner...</option>
|
||||
<option
|
||||
@@ -278,7 +278,7 @@
|
||||
class="checkbox checkbox-sm"
|
||||
true-value="true"
|
||||
false-value="false"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
<span class="text-sm">{{ field.value === 'true' ? 'Oui' : 'Non' }}</span>
|
||||
</div>
|
||||
@@ -288,7 +288,7 @@
|
||||
type="date"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:required="field.required"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
@@ -296,7 +296,7 @@
|
||||
type="text"
|
||||
class="input input-bordered input-sm md:input-md"
|
||||
:required="field.required"
|
||||
:disabled="submitting"
|
||||
:disabled="!canEdit || submitting"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -314,7 +314,7 @@
|
||||
{{ selectedDocuments.length }} document{{ selectedDocuments.length > 1 ? 's' : '' }} prêt{{ selectedDocuments.length > 1 ? 's' : '' }} à être ajouté{{ selectedDocuments.length > 1 ? 's' : '' }}
|
||||
</span>
|
||||
</header>
|
||||
<div :class="{ 'pointer-events-none opacity-60': submitting }">
|
||||
<div :class="{ 'pointer-events-none opacity-60': !canEdit || submitting }">
|
||||
<DocumentUpload
|
||||
v-model="selectedDocuments"
|
||||
title="Déposer vos fichiers"
|
||||
@@ -401,6 +401,7 @@ const {
|
||||
const toast = useToast()
|
||||
const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields()
|
||||
const { uploadDocuments } = useDocuments()
|
||||
const { canEdit } = usePermissions()
|
||||
|
||||
const initialTypeId = ref<string>(typeof route.query.typeId === 'string' ? route.query.typeId : '')
|
||||
const selectedTypeId = ref<string>(initialTypeId.value)
|
||||
@@ -755,6 +756,7 @@ const requiredCustomFieldsFilled = computed(() =>
|
||||
)
|
||||
|
||||
const canSubmit = computed(() => Boolean(
|
||||
canEdit.value &&
|
||||
selectedType.value &&
|
||||
creationForm.name &&
|
||||
requiredCustomFieldsFilled.value &&
|
||||
|
||||
Reference in New Issue
Block a user