feat(absences) : avancement module absences + suppression du portail client

Deux lots regroupés sur la branche feat/absence-management.

Suppression complète du portail client :
- retire ROLE_CLIENT (security.yaml) ; User::getRoles() ajoute toujours ROLE_USER
- supprime l'entité ClientTicket (+ repo, states, relations), User.client et
  User.allowedProjects, NotificationService, ProjectAllowedExtension, le bloc
  ROLE_CLIENT de MailAccessChecker
- front : pages /portal, layout portal, composants client-ticket/,
  AdminClientTicketTab, services/dto/i18n/docs associés
- fixtures : retire les users client-liot / client-acme
- migration Version20260522110000 (drop client_ticket, user_allowed_projects,
  colonnes liées ; task_document.task_id -> NOT NULL)
- tests : retire les cas obsolètes testant le blocage des clients sur le mail

Module gestion des absences (WIP) :
- entités / migrations (Version20260521160000, Version20260522090000)
- pages absences.vue / team-absences.vue, composants frontend/components/absence/
- services front, AccrueLeaveCommand, PublicHolidayController

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-05-22 11:31:31 +02:00
parent de98924fd3
commit 2a0b202d32
109 changed files with 3918 additions and 3656 deletions

View File

@@ -46,6 +46,12 @@
:class="sidebarIsCollapsed ? 'mt-4' : 'border-t border-secondary-500 pt-6'"
@click="ui.closeMobileSidebar()"
/>
<!-- Section : Gestion de projet -->
<p v-if="!sidebarIsCollapsed" class="px-4 pt-5 pb-1 text-xs font-semibold uppercase tracking-wider text-neutral-400">
Gestion de projet
</p>
<div v-else class="mx-2 my-3 border-t border-secondary-500" />
<SidebarLink
to="/my-tasks"
icon="mdi:clipboard-check-outline"
@@ -53,23 +59,6 @@
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<div v-if="isMailVisible" class="relative">
<SidebarLink
to="/mail"
icon="mdi:email-outline"
:label="$t('mail.sidebar.title')"
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<span
v-if="mailStore.globalUnreadCount > 0"
class="pointer-events-none absolute right-3 top-1/2 flex h-5 min-w-5 -translate-y-1/2 items-center justify-center rounded-full bg-red-500 px-1 text-xs font-bold text-white"
:class="{ 'right-1 top-1 translate-y-0': sidebarIsCollapsed }"
:aria-label="`${mailStore.globalUnreadCount} messages non lus`"
>
{{ mailStore.globalUnreadCount > 99 ? '99+' : mailStore.globalUnreadCount }}
</span>
</div>
<SidebarLink
to="/projects"
icon="mdi:folder-outline"
@@ -103,14 +92,6 @@
sub
@click="ui.closeMobileSidebar()"
/>
<SidebarLink
:to="`/projects/${currentProjectId}/client-tickets`"
icon="mdi:ticket-outline"
label="Tickets client"
:collapsed="sidebarIsCollapsed"
sub
@click="ui.closeMobileSidebar()"
/>
</template>
<SidebarLink
to="/time-tracking"
@@ -119,13 +100,59 @@
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<div v-if="isMailVisible" class="relative">
<SidebarLink
to="/mail"
icon="mdi:email-outline"
:label="$t('mail.sidebar.title')"
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<span
v-if="mailStore.globalUnreadCount > 0"
class="pointer-events-none absolute right-3 top-1/2 flex h-5 min-w-5 -translate-y-1/2 items-center justify-center rounded-full bg-red-500 px-1 text-xs font-bold text-white"
:class="{ 'right-1 top-1 translate-y-0': sidebarIsCollapsed }"
:aria-label="`${mailStore.globalUnreadCount} messages non lus`"
>
{{ mailStore.globalUnreadCount > 99 ? '99+' : mailStore.globalUnreadCount }}
</span>
</div>
<!-- Section : Absences -->
<p v-if="!sidebarIsCollapsed" class="px-4 pt-5 pb-1 text-xs font-semibold uppercase tracking-wider text-neutral-400">
Absences
</p>
<div v-else class="mx-2 my-3 border-t border-secondary-500" />
<SidebarLink
to="/admin"
icon="mdi:cog-outline"
label="Administration"
to="/absences"
icon="mdi:umbrella-beach-outline"
label="Mes absences"
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<SidebarLink
v-if="isAdmin"
to="/team-absences"
icon="mdi:calendar-account-outline"
label="Absences équipe"
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
<!-- Section : Administration (admin only) -->
<template v-if="isAdmin">
<p v-if="!sidebarIsCollapsed" class="px-4 pt-5 pb-1 text-xs font-semibold uppercase tracking-wider text-neutral-400">
Administration
</p>
<div v-else class="mx-2 my-3 border-t border-secondary-500" />
<SidebarLink
to="/admin"
icon="mdi:cog-outline"
label="Administration"
:collapsed="sidebarIsCollapsed"
@click="ui.closeMobileSidebar()"
/>
</template>
</nav>
<div class="px-4 py-3">
@@ -183,12 +210,11 @@ const mailStore = useMailStore()
const {version} = useAppVersion()
const route = useRoute()
const isAdmin = computed(() => (auth.user?.roles ?? []).includes('ROLE_ADMIN'))
const isMailVisible = computed(() => {
const roles: string[] = auth.user?.roles ?? []
const isClientOnly = roles.includes('ROLE_CLIENT')
&& !roles.includes('ROLE_ADMIN')
&& !roles.includes('ROLE_USER')
return !isClientOnly && (roles.includes('ROLE_USER') || roles.includes('ROLE_ADMIN'))
return roles.includes('ROLE_USER') || roles.includes('ROLE_ADMIN')
})
// On mobile, sidebar is always expanded (not collapsed icon mode)