Files
Lesstime/docs/superpowers/specs/2026-06-25-malio-sidebar-migration-design.md
T
tristan c766e76624
Auto Tag Develop / tag (push) Successful in 8s
feat(sidebar) : migration vers MalioSidebar — 3 groupes, footer timer+version, logo (LST-71) (#26)
## 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>
2026-06-25 15:30:23 +00:00

201 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.