feat: visionneuse XLSX - ruban groupe, onglets permanents et badges d'etat #154
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# #154 — Refonte UI/UX de la visionneuse & éditeur XLSX (ruban, grille, inspecteur)
|
||||
|
||||
> **Item de roadmap :** [#154 — Refonte UI/UX tableur](../ROADMAP.md)
|
||||
> **Origine :** #152 / #153 (visionneuse XLSX fonctionnelle mais peu conviviale)
|
||||
> **Statut :** 🔵 **en cours** — Lot 1 livré le 2026-09-29
|
||||
> **Effort estimé :** 6-9 jours (Lot 1 ✅ · Lot 2 · Lot 3 · Lot 4)
|
||||
> **Règle de maintenance :** la Roadmap porte les cases à cocher (suivi), cette fiche porte
|
||||
> l'analyse, l'architecture cible et le plan par lots. **Ne pas dupliquer le détail.**
|
||||
|
||||
---
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Rendre la vue tableur d'ObsiGate **intuitive, moderne et hautement utilisable** en s'inspirant
|
||||
des standards du marché (Excel, Google Sheets, Airtable), **sans renier les contraintes du
|
||||
dépôt** : thème sombre, `vanilla JS`, **zéro framework, zéro build npm**
|
||||
([`AGENTS.md`](../../AGENTS.md)). La refonte est **organique** : on améliore la coquille
|
||||
existante (`frontend/js/viewer.js::renderXlsxViewer`, `frontend/style.css`), on ne réécrit pas
|
||||
la grille ni le backend.
|
||||
|
||||
## 2. Audit UX — les 3 problèmes majeurs
|
||||
|
||||
| # | Problème | Constat | Résolution |
|
||||
|---|---|---|---|
|
||||
| **P1** | **Aucune hiérarchie ni regroupement des commandes** | Rangée plate de boutons de poids identique (`viewer.js` toolbar historique) ; « Tableau de bord » *prependé* au runtime ; barre de formule réduite à un `input`. | **Barre de commandes groupée** (Formules · Insertion · Vue · Fichier), bouton **Enregistrer primaire**, état *dirty*. |
|
||||
| **P2** | **Grille sans affordances : en-têtes = cellules** | Contraste faible entre `th` et `td`, pas de zébrage, pas de survol lisible, cellule active peu marquée. | **Tokens de grille** + en-têtes plus clairs/interactifs, zébrage, survol, cellule active en bordure accent. |
|
||||
| **P3** | **États avancés traités comme du contenu** | Dashboard *inline* qui pousse la grille, troncature/lecture seule/formules non recalculées sans emplacement dédié, `confirm()`/`prompt()` natifs. | **Couche UI dédiée** : bandeaux d'état + **inspecteur droit** (Lot 3) + dialogues thémés (Lot 2). |
|
||||
|
||||
## 3. Architecture cible de l'écran
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ BARRE APP (globale, existante) │
|
||||
├─────────────┬────────────────────────────────────────────────────────────┤
|
||||
│ │ A. RUBAN — groupes Formules · Insertion · Vue · Fichier │
|
||||
│ EXPLORATEUR│ B. BARRE DE FORMULE — [ A1 ] fx [ … ] │
|
||||
│ DE FICHIERS│ C. BANDEAUX D'ÉTAT — lecture seule · formules non recalculées│
|
||||
│ (sidebar) ├──────────────────────────────────────────────┬─────────────┤
|
||||
│ │ D. GRILLE (en-têtes clairs, zébrage, survol) │ E. INSPECTEUR│
|
||||
│ │ │ (dashboard + │
|
||||
│ │ │ IA, repliable)│
|
||||
│ ├───────────────────────────────────────────────┤ │
|
||||
│ │ F. ONGLETS FEUILLES + « + » · 500/522 │ │
|
||||
└─────────────┴───────────────────────────────────────────────┴─────────────┘
|
||||
```
|
||||
|
||||
- **A. Ruban** : groupes d'actions avec séparateurs ; actions de style désactivées (styles lus,
|
||||
pas écrits). Bouton **Enregistrer** en accent, désactivé si rien de *dirty*.
|
||||
- **B. Barre de formule** : zone nom + champ + badge de session `f(x)`.
|
||||
- **C. Bandeaux d'état** : empilables, non bloquants ; portent lecture seule et
|
||||
« formules non recalculées ».
|
||||
- **D. Grille** : rendue côté serveur (`backend/xlsx_reader.py`), habillée et câblée par le front.
|
||||
- **E. Inspecteur** : **à venir (Lot 3)** — Tableau de bord + Assistant IA dans un panneau droit
|
||||
repliable (réutilise `PaneManager` pour le détachement), au lieu du dashboard *inline* actuel.
|
||||
- **F. Onglets feuilles** : permanents (même à une seule feuille) + bouton « + ».
|
||||
|
||||
## 4. Plan par lots (incréments livrables)
|
||||
|
||||
### Lot 1 — Coquille : ruban groupé, onglets permanents, badges d'état ✅ *(2026-09-29)*
|
||||
|
||||
- **A1.1** Barre de commandes groupée (`.xlsx-cmdbar`, `.xlsx-cmd-group`, `.xlsx-cmd-sep`,
|
||||
`.xlsx-save-primary`), IDs existants conservés (compatibilité tests JSDOM/E2E).
|
||||
- **A1.2** Onglets de feuilles **toujours rendus** (non-CSV) + bouton **`+`** `.xlsx-tab-add`
|
||||
→ `sheet_add` (même pipeline `putStructure`).
|
||||
- **A1.3** Badges d'état : `.xlsx-status-pill` **lecture seule** (`.xls`/`.ods`) et
|
||||
**formules non recalculées** (non-CSV).
|
||||
- **A1.4** Tokens de grille (`--grid-bg`, `--grid-header-bg`, `--grid-header-text`,
|
||||
`--grid-border`, `--grid-zebra`) déclinés dark/light + affordances (en-têtes clairs,
|
||||
zébrage, survol, cellule active solide, cellule *dirty* prioritaire au survol).
|
||||
|
||||
### Lot 2 — Dialogues thémés & feedback (à venir)
|
||||
|
||||
- Remplacer `confirm()`/`prompt()` par des **modales thémées** (`.obsigate-modal-*`) et des
|
||||
**toasts** : structure (feuille/ligne/colonne), perte (409 `xlsx_lossy_content`), conflit
|
||||
(409 `conflict`) en bandeau non bloquant.
|
||||
- Indicateur *dirty* sur l'onglet de feuille et la barre.
|
||||
|
||||
### Lot 3 — Inspecteur droit (à venir)
|
||||
|
||||
- Panneau repliable hébergeant **Tableau de bord** et **Assistant IA** en onglets ; la grille
|
||||
reste visible. Lien **dashboard → grille** (clic sur KPI/plage = scroll + sélection).
|
||||
- Détachement en split via `PaneManager.splitRight()`.
|
||||
|
||||
### Lot 4 — Découpage & finitions (à venir)
|
||||
|
||||
- Extraction de `renderXlsxViewer` en modules (`frontend/js/xlsx/*.js`) : `toolbar`, `formula-bar`,
|
||||
`grid`, `sheet-tabs`, `inspector`, `cell-editor`, `api`.
|
||||
- **Undo/redo** local (pile de commandes), défilement paresseux via `IntersectionObserver`,
|
||||
accessibilité ARIA (`role="grid"`, *roving tabindex*).
|
||||
|
||||
## 5. Recommandations techniques (contrainte « zéro build »)
|
||||
|
||||
| Option Data Grid | Build | Licence | Verdict |
|
||||
|---|---|---|---|
|
||||
| AG Grid Community | npm + bundler | MIT | ❌ viole « zéro build », réécrit le DOM, casse les tests |
|
||||
| Handsontable | npm + bundler | **commerciale** | ❌ licence non libre |
|
||||
| TanStack Table | headless (importable esm.sh) | MIT | ⚠ possible sans build, mais *headless* → gain limité |
|
||||
| **Grille maison sur `<table>`** | aucun | — | ✅ **recommandé** (conserve DOM, CSP, i18n, tests) |
|
||||
|
||||
- **Performance** : ne pas ré-écrire tout le DOM ; réutiliser le pipeline `appendWindow` ;
|
||||
`content-visibility:auto; contain:strict` sur les lignes ; garder la pagination serveur
|
||||
(500 × 40 = 20 000 cellules/feuille) plutôt qu'une virtualisation client complexe.
|
||||
- **CSP** : `main.py` autorise déjà `esm.sh` — une lib *headless* reste possible en Lot 4 si
|
||||
un vrai besoin de modèle de colonnes apparaît.
|
||||
|
||||
## 6. Critères d'acceptation (par lot)
|
||||
|
||||
- **Lot 1** : une feuille unique affiche son onglet + « + » ; « + » ajoute une feuille via
|
||||
`PUT …/xlsx/structure` et re-rend ; `.xls`/`.ods` montrent le badge « lecture seule » (pas de
|
||||
« + », pas de structure, pas de dashboard) ; un `.xlsx` montre le badge « formules non
|
||||
recalculées », un `.csv` non ; les tests JSDOM/E2E existants restent verts + nouveaux tests.
|
||||
- Lots suivants : définis à leur ouverture.
|
||||
|
||||
## 7. Historique
|
||||
|
||||
| Date | Événement |
|
||||
|---|---|
|
||||
| 2026-09-29 | Audit UX (3 problèmes) + architecture cible + plan par lots ; **Lot 1** livré (ruban groupé, onglets permanents + « + », badges d'état, tokens de grille) |
|
||||
Reference in New Issue
Block a user