Files
ObsiGate/docs/features/xlsx-ui-redesign.md
T

11 KiB
Raw Permalink Blame History

#154 — Refonte UI/UX de la visionneuse & éditeur XLSX (ruban, grille, inspecteur)

Item de roadmap : #154 — Refonte UI/UX tableur Origine : #152 / #153 (visionneuse XLSX fonctionnelle mais peu conviviale) Statut : ✅ terminé — Lots 1 → 5 livrés le 2026-09-29 (A1-A5) Effort estimé : 6-9 jours (Lot 1 ✅ · Lot 2 ✅ · Lot 3 ✅ · Lot 4 ✅ · Lot 5 ✅) 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). 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 ✅ (2026-09-29)

  • A2.1 Helpers génériques showConfirm() / showPrompt() (frontend/js/ui.js), promise-based, réutilisant les classes .obsigate-modal-* (fini window.confirm() / window.prompt()).
  • A2.2 La visionneuse XLSX utilise ces dialogues pour les actions de structure (ajouter / renommer / dupliquer / supprimer feuille, insérer / supprimer ligne et colonne) et pour la confirmation de perte (409 xlsx_lossy_content).
  • A2.3 Conflit de sauvegarde (409 conflict) : bandeau non bloquant .xlsx-banner-conflict avec bouton Réessayer — les modifications sont conservées.
  • A2.4 Indicateur dirty sur le bouton Enregistrer et sur l'onglet de la feuille concernée.

Lot 3 — Inspecteur droit ✅ (2026-09-29)

  • A3.1 Le Tableau de bord quitte le flux de la grille pour un panneau droit repliable (.xlsx-inspector) : la grille reste visible à côté (.xlsx-body = .xlsx-main + inspecteur).
  • A3.2 En-tête d'inspecteur : titre, bouton Assistant IA (ouvre le panneau latéral global existant) et bouton de fermeture.
  • A3.3 Responsive : sous 900 px, l'inspecteur passe sous la grille.

Lot 4 — Interactions : undo/redo, défilement, accessibilité ✅ (2026-09-29)

  • A4.1 Undo/redo local (pile de commandes) pour les éditions de cellules : boutons Annuler / Rétablir dans le ruban + raccourcis Ctrl+Z, Ctrl+Maj+Z, Ctrl+Y.
  • A4.2 Chargement des fenêtres via IntersectionObserver (repli sur l'écouteur de défilement pour les environnements sans IO).
  • A4.3 Sémantique ARIA : role="grid" / row / gridcell / columnheader / rowheader.

Lot 5 — Découpage modulaire & finitions ✅ (2026-09-29)

  • A5.1 Extraction des parties pures/sans état du monolithe renderXlsxViewer dans frontend/js/xlsx/ : refs.js (parseRef, columnName, findTd, sheetOfRef, firstCellOfRange), command-bar.js (buildCommandBar : onglets + ruban + pastilles), dashboard.js (renderDashboardLoading, renderDashboardHtml). Le noyau avec état (orchestration DOM, édition, écouteurs) reste dans viewer.js : l'extraction est volontairement limitée aux unités sans état, à comportement constant et sous couvert des tests.
  • A5.2 Lien dashboard → grille : cliquer une plage nommée sélectionne et révèle sa première cellule (change d'onglet si la plage est sur une autre feuille).
  • A5.3 Inspecteur redimensionnable (poignée gauche, largeur 260–640 px, restaurée par session via localStorage).
  • A5.4 SW_VERSION incrémenté (v28) et nouveaux modules ajoutés au pré-cache du service worker.

Hors périmètre (documenté) : le détachement de l'inspecteur en split view (PaneManager.splitRight()) n'est pas retenu — l'inspecteur est intrinsèquement lié à la visionneuse d'un document ; un split générique ouvrirait un second contexte sans le classeur. À réévaluer si un usage concret apparaît.

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)
2026-09-29 Lot 2 livré : dialogues thémés (showConfirm/showPrompt) pour la structure et la confirmation de perte, bandeau de conflit 409 non bloquant avec réessai, indicateur dirty (bouton + onglet)
2026-09-29 Lot 3 livré : le Tableau de bord passe dans un inspecteur droit repliable (grille toujours visible), en-tête d'inspecteur avec entrée Assistant IA et fermeture, responsive < 900 px
2026-09-29 Lot 4 livré : undo/redo (boutons + Ctrl+Z/Ctrl+Maj+Z/Ctrl+Y), chargement par IntersectionObserver, ARIA role="grid" ; le découpage modulaire est reporté en A5
2026-09-29 Lot 5 livré (clôture #154) : extraction des unités sans état dans frontend/js/xlsx/* (refs.js, command-bar.js, dashboard.js), lien dashboard → grille, inspecteur redimensionnable, SW_VERSION v28 + pré-cache. Split view écarté (documenté)