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:
@@ -9,7 +9,7 @@
|
||||
Gérez les fournisseurs et leurs coordonnées.
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn btn-primary" @click="openCreateModal">
|
||||
<button v-if="canEdit" class="btn btn-primary" @click="openCreateModal">
|
||||
<IconLucidePlus class="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
Nouveau fournisseur
|
||||
</button>
|
||||
@@ -73,9 +73,9 @@
|
||||
<td class="text-right">
|
||||
<div class="flex justify-end gap-2">
|
||||
<button class="btn btn-ghost btn-xs" @click="openEditModal(constructeur)">
|
||||
Modifier
|
||||
{{ canEdit ? 'Modifier' : 'Consulter' }}
|
||||
</button>
|
||||
<button class="btn btn-error btn-xs" @click="confirmDelete(constructeur)">
|
||||
<button v-if="canEdit" class="btn btn-error btn-xs" @click="confirmDelete(constructeur)">
|
||||
Supprimer
|
||||
</button>
|
||||
</div>
|
||||
@@ -90,22 +90,22 @@
|
||||
<dialog class="modal" :class="{ 'modal-open': modalOpen }">
|
||||
<div class="modal-box">
|
||||
<h3 class="font-bold text-lg mb-4">
|
||||
{{ editingConstructeur ? 'Modifier' : 'Nouveau' }} fournisseur
|
||||
{{ editingConstructeur ? (canEdit ? 'Modifier' : 'Détails du') : 'Nouveau' }} fournisseur
|
||||
</h3>
|
||||
<form class="space-y-4" @submit.prevent="saveConstructeur">
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text">Nom</span></label>
|
||||
<input v-model="form.name" type="text" class="input input-bordered" required>
|
||||
<input v-model="form.name" type="text" class="input input-bordered" :disabled="!canEdit" required>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FieldEmail v-model="form.email" label="Email" />
|
||||
<FieldPhone v-model="form.phone" label="Téléphone" />
|
||||
<FieldEmail v-model="form.email" label="Email" :disabled="!canEdit" />
|
||||
<FieldPhone v-model="form.phone" label="Téléphone" :disabled="!canEdit" />
|
||||
</div>
|
||||
<div class="modal-action">
|
||||
<button type="button" class="btn" @click="closeModal">
|
||||
Annuler
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="saving">
|
||||
<button type="submit" class="btn btn-primary" :disabled="!canEdit || saving">
|
||||
<span v-if="saving" class="loading loading-spinner loading-xs mr-2" />
|
||||
{{ editingConstructeur ? 'Enregistrer' : 'Créer' }}
|
||||
</button>
|
||||
@@ -117,7 +117,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import FieldEmail from '~/components/form/FieldEmail.vue'
|
||||
import FieldPhone from '~/components/form/FieldPhone.vue'
|
||||
import { useConstructeurs } from '~/composables/useConstructeurs'
|
||||
@@ -126,6 +126,7 @@ import { usePersistedValue } from '~/composables/usePersistedValue'
|
||||
import { formatPhone } from '~/utils/formatters/phone'
|
||||
import IconLucidePlus from '~icons/lucide/plus'
|
||||
|
||||
const { canEdit } = usePermissions()
|
||||
const { constructeurs, loading, searchConstructeurs, createConstructeur, updateConstructeur, deleteConstructeur, loadConstructeurs } = useConstructeurs()
|
||||
const { showError } = useToast()
|
||||
|
||||
@@ -221,7 +222,7 @@ const confirmDelete = async (constructeur) => {
|
||||
}
|
||||
}
|
||||
|
||||
loadConstructeurs()
|
||||
onMounted(() => loadConstructeurs())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user