c766e76624
Auto Tag Develop / tag (push) Successful in 8s
## Objectif Remplacer la sidebar maison par le composant `MalioSidebar` de `@malio/layer-ui` (alignement avec Starseed). ## Changements - **Backend** : `config/sidebar.php` re-catégorisé en **3 groupes** (Général / Outils / Administration). Tous les gates permission/rôle/module **préservés côté serveur** (rien déplacé côté client). - **Frontend** : `app/layouts/default.vue` migré vers `<MalioSidebar>`. Un computed `mergedSections` mappe les sections backend et y fusionne les items contextuels (Kanban/Groupes/Archives sous « Projets », Mes absences, Messagerie avec compteur `(N)`, Documents). - **Footer** : timer (`SidebarTimer`) + version de l'app (masquée en mode replié). - **Logo** : logos Malio repris de Starseed (`LOGO_MALIO.png` / `LOGO_MALIO_COLLAPSED.png`). - **Mobile** : `MalioSidebar` étant toujours visible (pas de tiroir off-canvas), le hamburger pilote désormais le repli ; suppression du code de tiroir mobile mort (`sidebarOpen`/`openMobileSidebar`/`closeMobileSidebar`). - **Nettoyage** : suppression de `SidebarLink.vue` et `LOGO_CARRE.png` (obsolètes). `malio.png` conservé (utilisé par la page login). - **i18n** : nouvelles clés `sidebar.tools.section`, `sidebar.general.myAbsences`, `sidebar.project.kanban|groups|archives` ; `sidebar.general.section` → « Général ». ## Compromis (limites du composant, lib non modifiée) - Pas d'icône par item (uniquement icône de section) — design malioUI, comme Starseed. - Badge mail → suffixe `(N)` dans le libellé. ## Vérifications - Build Nuxt OK (`✨ Build complete!`, exit 0). - Revue par task + revue finale whole-branch : aucun Critical/Important. - Sécurité : filtrage des permissions inchangé (côté serveur). Specs/plan : `docs/superpowers/specs/2026-06-25-malio-sidebar-migration-design.md`, `docs/superpowers/plans/2026-06-25-malio-sidebar-migration.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #26 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
201 lines
8.8 KiB
Markdown
201 lines
8.8 KiB
Markdown
# Migration de la sidebar vers `MalioSidebar` (@malio/layer-ui)
|
||
|
||
**Date** : 2026-06-25
|
||
**Statut** : Design validé
|
||
**Scope** : Frontend (layout) + backend (config sidebar) + assets
|
||
|
||
## Contexte
|
||
|
||
La sidebar actuelle de Lesstime est un `<aside>` fait main dans
|
||
`frontend/app/layouts/default.vue`, qui itère sur les sections renvoyées par
|
||
`/api/sidebar` et rend chaque item via le composant maison `SidebarLink`. Le
|
||
timer et la version sont empilés en bas du `<aside>`, le toggle collapse et
|
||
l'overlay mobile sont gérés manuellement.
|
||
|
||
La librairie `@malio/layer-ui` (mise à jour) fournit désormais un composant
|
||
`MalioSidebar`. Le projet **Starseed** a déjà effectué cette migration sur une
|
||
architecture identique (`config/sidebar.php` → `SidebarProvider` → composable
|
||
`useSidebar` → layout). Cette spec applique la même migration à Lesstime, avec
|
||
trois spécificités Lesstime : footer (timer + version), re-catégorisation des
|
||
onglets, et plusieurs items contextuels rendus côté client.
|
||
|
||
On **ne modifie pas** la lib `@malio/layer-ui` (règle CLAUDE.md).
|
||
|
||
## Objectifs
|
||
|
||
1. Remplacer le `<aside>` maison par `<MalioSidebar>`.
|
||
2. Préserver le filtrage des permissions/rôles/modules **côté serveur**.
|
||
3. Re-catégoriser la navigation en 3 groupes : **Général / Outils / Administration**.
|
||
4. Mettre le timer et la version dans le **footer** du composant.
|
||
5. Reprendre le **logo Malio** de Starseed.
|
||
|
||
## Décisions validées
|
||
|
||
- **Catégorisation** : 3 groupes (option B).
|
||
- **Badge mail** : le compteur de non-lus devient un **suffixe sur le label**
|
||
(`Messagerie (3)`), faute de slot badge/icône par item dans `MalioSidebar`.
|
||
|
||
## Contraintes du composant `MalioSidebar`
|
||
|
||
Source : `frontend/node_modules/@malio/layer-ui/app/components/malio/sidebar/Sidebar.vue`.
|
||
|
||
- **Props** : `sections` (requis), `modelValue` (v-model collapse, bool),
|
||
`id`, `sidebarClass`, `toggleClass`.
|
||
- **Types** :
|
||
- `SidebarItem = { label: string; to: string; exact?: boolean }`
|
||
- `SidebarSection = { label?: string; icon?: string; items: SidebarItem[] }`
|
||
- **Slots** : `#logo`, `#logo-collapsed`, `#footer`, `#footer-collapsed`.
|
||
- **Events** : `update:modelValue(boolean)`.
|
||
- **Item** : pas d'icône par item ni de badge — uniquement l'icône de section.
|
||
Route active = match exact ou par préfixe (`exact: true` pour exact strict).
|
||
- Largeurs fixes : 232px (déplié) / 72px (replié). Toggle interne.
|
||
|
||
### Conséquences (compromis assumés)
|
||
|
||
- Perte de l'**icône par item** (design malioUI = texte + icône de section).
|
||
Starseed fonctionne ainsi.
|
||
- Le **badge mail** ne peut pas être une pastille → suffixe `(N)` dans le label.
|
||
|
||
## Architecture cible
|
||
|
||
Modèle **backend-driven** conservé (sécurité serveur intacte). Le frontend
|
||
mappe les sections renvoyées par `/api/sidebar` vers le format `MalioSidebar`
|
||
et **fusionne** les items contextuels (qui dépendent d'un état runtime non
|
||
connu du backend).
|
||
|
||
### 1. Backend — `config/sidebar.php`
|
||
|
||
Re-catégorisation en 3 sections (gates inchangés, juste réorganisés) :
|
||
|
||
```
|
||
GÉNÉRAL (sidebar.general.section, icon mdi:view-dashboard-outline)
|
||
Tableau de bord / —
|
||
Mes tâches /my-tasks module project-management, perm tasks.view
|
||
Projets /projects module project-management, perm projects.view
|
||
Suivi de temps /time-tracking module time-tracking, perm entries.view
|
||
|
||
OUTILS (sidebar.tools.section, icon mdi:tools)
|
||
Messagerie /mail module mail
|
||
(filtré du rendu backend côté front, ré-injecté avec badge)
|
||
|
||
ADMINISTRATION (sidebar.admin.section, icon mdi:cog-outline, roles [ROLE_ADMIN])
|
||
Absences équipe /team-absences module absence
|
||
Répertoire /directory module directory
|
||
Rapports /reporting module reporting, perm reporting.view
|
||
Administration /admin perm core.users.view
|
||
```
|
||
|
||
> `/mail` reste déclaré pour le gating module (`disabledRoutes`), mais est
|
||
> filtré des sections rendues et ré-injecté côté client avec son badge, comme
|
||
> aujourd'hui.
|
||
|
||
### 2. i18n — `frontend/i18n/locales/fr.json`
|
||
|
||
- Renommer `sidebar.general.section` : « Gestion de projet » → « Général ».
|
||
- Ajouter `sidebar.tools.section` : « Outils ».
|
||
- Conserver les clés d'items existantes. Items client : réutiliser les clés
|
||
existantes quand elles existent (`sharedFiles.sidebar.title` pour Documents,
|
||
`mail.sidebar.title`/`sidebar.general.mail` pour Messagerie) ; ajouter une
|
||
clé pour « Mes absences » (aujourd'hui en dur) et pour les contextuels
|
||
(Kanban/Groupes/Archives, aujourd'hui en dur) si on souhaite les traduire,
|
||
sinon conserver les libellés en dur actuels.
|
||
|
||
### 3. Frontend — `frontend/app/layouts/default.vue`
|
||
|
||
Réécriture du template autour de `<MalioSidebar>` :
|
||
|
||
```vue
|
||
<MalioSidebar v-model="ui.sidebarCollapsed" :sections="mergedSections"
|
||
:sidebar-class="ui.sidebarCollapsed ? '' : 'w-[232px]'">
|
||
<template #logo> <img src="/LOGO_MALIO.png" alt="Malio"/></template>
|
||
<template #logo-collapsed> <img src="/LOGO_MALIO_COLLAPSED.png" alt="Malio"/></template>
|
||
<template #footer>
|
||
<SidebarTimer :collapsed="false" />
|
||
<p class="font-bold">v {{ version }}</p>
|
||
</template>
|
||
<template #footer-collapsed>
|
||
<SidebarTimer :collapsed="true" />
|
||
</template>
|
||
</MalioSidebar>
|
||
```
|
||
|
||
**Computed `mergedSections`** : construit les sections finales dans l'ordre
|
||
canonique `[général, outils, administration]`.
|
||
|
||
Logique de fusion :
|
||
1. Partir des sections backend (déjà filtrées), mappées en
|
||
`{ label: t(label), icon, items: items.filter(to !== '/mail').map({label: t, to}) }`.
|
||
2. Définir une table `clientItems` indexée par clé de section :
|
||
- `sidebar.general.section` → (si `currentProjectId`) Kanban (`exact`),
|
||
Groupes, Archives ; puis (si `isEmployee`) Mes absences.
|
||
- `sidebar.tools.section` → (si `isMailVisible`) Messagerie avec label
|
||
`Messagerie` + suffixe `(N)` quand `mailStore.globalUnreadCount > 0`
|
||
(`99+` au-delà) ; puis (si `shareEnabled`) Documents.
|
||
3. Pour chaque section backend, **append** ses items client.
|
||
4. Si une clé de `clientItems` produit des items mais que la section
|
||
correspondante n'est **pas** présente dans la réponse backend (ex. module
|
||
mail off mais partage on → pas de section « Outils » côté backend), **créer**
|
||
la section côté front (label + icône depuis une table locale).
|
||
5. **Supprimer** les sections finales sans items.
|
||
6. Trier selon l'ordre canonique des clés.
|
||
|
||
Le reste du `<script>` (timer title watchers, `refData`/`TimeEntryDrawer`,
|
||
polling mail, `ensureShareStatus`, `currentProjectId`, `isEmployee`,
|
||
`isMailVisible`, `shareEnabled`) est **conservé tel quel**.
|
||
|
||
### 4. Mobile
|
||
|
||
Starseed a **supprimé l'overlay mobile custom** et ne garde que
|
||
`watch(route) → ui.closeMobileSidebar()`. On s'aligne : suppression du markup
|
||
overlay (`ui.sidebarOpen`, `.sidebar-overlay`) si `MalioSidebar` gère le
|
||
responsive. **À vérifier à l'implémentation** : comportement mobile réel du
|
||
composant ; si l'ouverture mobile n'est pas couverte, adapter a minima sans
|
||
modifier la lib.
|
||
|
||
### 5. Assets — logo
|
||
|
||
Copier depuis Starseed vers `frontend/public/` :
|
||
- `LOGO_MALIO.png` (128×44)
|
||
- `LOGO_MALIO_COLLAPSED.png` (34×40)
|
||
|
||
Les anciens `/malio.png` et `/LOGO_CARRE.png` ne sont plus référencés par le
|
||
layout (les laisser ou les retirer si plus aucun usage — à vérifier).
|
||
|
||
## Composants / éléments réutilisés
|
||
|
||
- `SidebarTimer` (`components/ui/SidebarTimer.vue`) : inchangé, déjà piloté par
|
||
`:collapsed`.
|
||
- `useAppVersion()` : inchangé.
|
||
- `useSidebar()` : inchangé.
|
||
- `usePermissions()` : inchangé (le filtrage permission reste backend ; les
|
||
flags client `isEmployee`/`isMailVisible`/`shareEnabled` restent locaux).
|
||
|
||
## Éléments supprimés
|
||
|
||
- Le `<aside>` manuel et son markup (logo, nav, toggle, overlay) dans
|
||
`default.vue`.
|
||
- L'usage de `SidebarLink` dans le layout (le composant peut rester s'il est
|
||
utilisé ailleurs — à vérifier ; sinon suppression possible).
|
||
|
||
## Critères d'acceptation
|
||
|
||
1. La sidebar est rendue par `<MalioSidebar>`.
|
||
2. 3 groupes : Général, Outils, Administration (Administration visible
|
||
uniquement pour `ROLE_ADMIN` / permissions, comme avant).
|
||
3. Toutes les permissions/rôles/modules sont respectés à l'identique (aucune
|
||
régression de visibilité pour user/admin).
|
||
4. Items contextuels présents : Kanban/Groupes/Archives (dans un projet),
|
||
Documents (partage activé), Mes absences (employé).
|
||
5. Messagerie affiche `(N)` quand il y a des non-lus.
|
||
6. Footer : timer fonctionnel + version (version masquée en replié).
|
||
7. Logo Malio de Starseed affiché (déplié + replié).
|
||
8. Collapse/expand et route active fonctionnent.
|
||
9. Pas de doublon `/mail`. Pas de section vide affichée.
|
||
10. Build Nuxt OK, pas d'erreur TS.
|
||
|
||
## Hors scope
|
||
|
||
- Refonte du `SiteSelector` (n'existe pas dans Lesstime).
|
||
- Modification de la lib `@malio/layer-ui`.
|
||
- Changement du modèle de permissions backend.
|