L'écran Heures / Heures Conducteurs envoyait au bulk-upsert une entrée pour
tous les employés visibles non verrouillés, à partir de l'état en mémoire.
Le backend traitant une entrée vide comme une suppression, un admin avec une
grille périmée pouvait supprimer une ligne saisie entre-temps par un autre
utilisateur (ex. ROLE_SELF non encore validé, donc non verrouillé).
handleSave capture désormais un instantané des lignes chargées (loadedRows,
dans hydrateRows) et ne transmet que les lignes dont l'état courant en diffère.
Une ligne intouchée n'est jamais envoyée → jamais supprimée.
Symétrique dans useHoursPage.ts et useDriverHoursPage.ts.
Doc : doc/hours-save-dirty-tracking.md + note CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Fonctionnel
- Calendrier MalioDate en vue Jour (écrans Heures ET Heures Conducteurs) : les jours entièrement validés par un admin sont peints en vert.
- Endpoint `GET /work-hours/validation-status?from=&to=[&driver=1]` (scope conducteur inversé via `driver=1`), périmètre complet (ignore le filtre sites).
- Chargement à la volée par mois (event `@month-change`), refresh après validation / saisie / absence.
## Harmonisation @malio/layer-ui 1.7.11
- `reserveMessageSpace=false` sur tous les champs (alignement).
- Tous les drawers migrés sur `MalioDrawer` (titre via slot `#header`, `AppDrawer` custom supprimé).
- Boutons d'action en `MalioButton` ; deux boutons côte à côte partagent l'espace.
- Inputs date en `MalioDate`, sélecteur semaine en `MalioDateWeek`.
- Boutons d'ajout uniformisés sur « Ajouter » + icône.
## Divers
- `.env` : `EXCLUDED_PUBLIC_HOLIDAYS="null"`.
- Doc : `doc/hours-validated-days.md`, `documentation-content.ts`, `CLAUDE.md`.
- Tests : provider `WorkHourValidationStatus` (suite complète 236/236 OK via pre-commit hook).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: #30
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>