Supprime la colonne actions des tables users et roles (la ligne cliquable ouvre deja le drawer). Deplace la suppression d'un role dans le drawer d'edition (bouton danger avec icone, desactive pour les roles systeme). Harmonise les boutons annuler en variant tertiary et ajoute les icones manquantes (plus pour nouveau role, poubelle pour supprimer). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
162 lines
4.4 KiB
Vue
162 lines
4.4 KiB
Vue
<template>
|
|
<div>
|
|
<!-- En-tete -->
|
|
<div class="flex items-center justify-between">
|
|
<h1 class="text-xl font-bold text-primary-500 sm:text-2xl">
|
|
{{ t('admin.roles.title') }}
|
|
</h1>
|
|
<MalioButton
|
|
v-if="can('core.roles.manage')"
|
|
:label="t('admin.roles.newRole')"
|
|
icon-name="mdi:plus"
|
|
icon-position="left"
|
|
@click="openCreateDrawer"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Table des roles -->
|
|
<MalioDataTable
|
|
class="mt-6"
|
|
:columns="columns"
|
|
:items="roleItems"
|
|
:total-items="roles.length"
|
|
:row-clickable="canManage"
|
|
:empty-message="t('admin.roles.noRoles')"
|
|
@row-click="onRowClick"
|
|
>
|
|
<template #cell-code="{ item }">
|
|
<span class="font-mono text-xs">{{ item.code }}</span>
|
|
</template>
|
|
<template #cell-permissions="{ item }">
|
|
{{ item.permissions }}
|
|
</template>
|
|
<template #cell-system="{ item }">
|
|
<span
|
|
v-if="item.isSystem"
|
|
class="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800"
|
|
>
|
|
{{ t('admin.roles.table.system') }}
|
|
</span>
|
|
</template>
|
|
</MalioDataTable>
|
|
|
|
<!-- Drawer creation/edition -->
|
|
<RoleDrawer
|
|
v-model="drawerOpen"
|
|
:role="selectedRole"
|
|
@saved="onRoleSaved"
|
|
@delete="onDeleteRequest"
|
|
/>
|
|
|
|
<!-- Modale de suppression -->
|
|
<RoleDeleteModal
|
|
v-model="deleteModalOpen"
|
|
:role-label="roleToDelete?.label ?? ''"
|
|
:loading="deleting"
|
|
@confirm="handleDelete"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { Role } from '~/shared/types/rbac'
|
|
|
|
const { t } = useI18n()
|
|
const api = useApi()
|
|
const { can } = usePermissions()
|
|
const canManage = computed(() => can('core.roles.manage'))
|
|
|
|
useHead({ title: t('admin.roles.title') })
|
|
|
|
const roles = ref<Role[]>([])
|
|
const loading = ref(false)
|
|
|
|
const columns = [
|
|
{ key: 'label', label: t('admin.roles.table.label') },
|
|
{ key: 'code', label: t('admin.roles.table.code') },
|
|
{ key: 'permissions', label: t('admin.roles.table.permissions') },
|
|
{ key: 'system', label: t('admin.roles.table.system') },
|
|
]
|
|
|
|
// Transformer les roles en items compatibles MalioDataTable
|
|
const roleItems = computed(() =>
|
|
roles.value.map(role => ({
|
|
id: role.id,
|
|
label: role.label,
|
|
code: role.code,
|
|
permissions: role.permissions.length,
|
|
isSystem: role.isSystem,
|
|
system: '', // colonne geree par le slot
|
|
}))
|
|
)
|
|
|
|
function getRoleById(id: number): Role | undefined {
|
|
return roles.value.find(r => r.id === id)
|
|
}
|
|
|
|
function onRowClick(item: Record<string, unknown>) {
|
|
const role = getRoleById(item.id as number)
|
|
if (role) openEditDrawer(role)
|
|
}
|
|
const drawerOpen = ref(false)
|
|
const selectedRole = ref<Role | null>(null)
|
|
const deleteModalOpen = ref(false)
|
|
const roleToDelete = ref<Role | null>(null)
|
|
const deleting = ref(false)
|
|
|
|
// Charger la liste des roles
|
|
async function loadRoles() {
|
|
loading.value = true
|
|
try {
|
|
const data = await api.get<{ member: Role[] }>(
|
|
'/roles',
|
|
{},
|
|
{ toast: false },
|
|
)
|
|
roles.value = data.member
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function openCreateDrawer() {
|
|
selectedRole.value = null
|
|
drawerOpen.value = true
|
|
}
|
|
|
|
function openEditDrawer(role: Role) {
|
|
selectedRole.value = role
|
|
drawerOpen.value = true
|
|
}
|
|
|
|
function onDeleteRequest() {
|
|
if (!selectedRole.value || selectedRole.value.isSystem) return
|
|
roleToDelete.value = selectedRole.value
|
|
deleteModalOpen.value = true
|
|
}
|
|
|
|
async function handleDelete() {
|
|
if (!roleToDelete.value) return
|
|
deleting.value = true
|
|
try {
|
|
await api.delete(`/roles/${roleToDelete.value.id}`, {}, {
|
|
toastSuccessMessage: t('admin.roles.toast.deleted'),
|
|
})
|
|
deleteModalOpen.value = false
|
|
roleToDelete.value = null
|
|
drawerOpen.value = false
|
|
await loadRoles()
|
|
} finally {
|
|
deleting.value = false
|
|
}
|
|
}
|
|
|
|
function onRoleSaved() {
|
|
loadRoles()
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadRoles()
|
|
})
|
|
</script>
|