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

@@ -104,10 +104,11 @@
Commencez par ajouter des sites et des machines.
</p>
<div class="flex gap-2 justify-center">
<button class="btn btn-primary" @click="showAddSiteModal = true">
<button v-if="canEdit" class="btn btn-primary" @click="showAddSiteModal = true">
Ajouter un site
</button>
<button
v-if="canEdit"
class="btn btn-secondary"
@click="showAddMachineModal = true"
>
@@ -239,12 +240,14 @@
<div class="card-actions justify-end mt-3">
<button
v-if="canEdit"
class="btn btn-xs btn-outline"
@click.stop="editMachine(machine)"
>
Modifier
</button>
<button
v-if="canEdit"
class="btn btn-xs btn-error"
@click.stop="confirmDeleteMachine(machine)"
>
@@ -277,6 +280,7 @@
Aucune machine dans ce site
</p>
<button
v-if="canEdit"
class="btn btn-sm btn-primary"
@click="addMachineToSite(site)"
>
@@ -304,11 +308,12 @@
type="text"
placeholder="Ex: Usine de production"
class="input input-bordered"
:disabled="!canEdit"
required
>
</div>
<SiteContactFormFields :form="newSite" />
<SiteContactFormFields :form="newSite" :disabled="!canEdit" />
<div class="modal-action">
<button
@@ -318,7 +323,7 @@
>
Annuler
</button>
<button type="submit" class="btn btn-primary">
<button type="submit" class="btn btn-primary" :disabled="!canEdit">
Créer le site
</button>
</div>
@@ -343,6 +348,7 @@
type="text"
placeholder="Ex: Presse hydraulique #1"
class="input input-bordered"
:disabled="!canEdit"
required
>
</div>
@@ -354,6 +360,7 @@
<select
v-model="newMachine.siteId"
class="select select-bordered"
:disabled="!canEdit"
required
>
<option value="">
@@ -374,6 +381,7 @@
<select
v-model="newMachine.typeMachineId"
class="select select-bordered"
:disabled="!canEdit"
required
>
<option value="">
@@ -398,6 +406,7 @@
type="text"
placeholder="Ex: PRESS-001"
class="input input-bordered"
:disabled="!canEdit"
>
</div>
</div>
@@ -446,7 +455,7 @@
>
Annuler
</button>
<button type="submit" class="btn btn-primary">
<button type="submit" class="btn btn-primary" :disabled="!canEdit">
Créer la machine
</button>
</div>
@@ -474,6 +483,7 @@ import IconLucideTag from '~icons/lucide/tag'
import { formatPhone } from '~/utils/formatters/phone'
import { extractRelationId } from '~/shared/apiRelations'
const { canEdit } = usePermissions()
const { sites, loading, loadSites, createSite } = useSites()
const { machineTypes, loadMachineTypes } = useMachineTypesApi()
const { machines, loadMachines, createMachineFromType, deleteMachine } = useMachines()