Restaure et termine le lot tableur resté non committé. Il n'existait que dans un `git stash` (24 fichiers suivis) et en fichiers non suivis (menus.js, formula.js, color-picker.js, tests, fiches) : la 2.53.3 livrée ne le contenait donc pas. Le stash, créé avant le commit BUG-108, n'a jamais été restauré. #180 Redimensionnement au curseur (en-tête de bord miroité + classe de repaint), grille thémée sur les 15 thèmes et les modes contraste élevé / sépia, menu Fichier au niveau des onglets, barre épinglée pleine largeur. #181 Modèle de saisie Google Sheets : sélection ≠ édition (caret masqué sans quitter contenteditable, double-clic / F2 / première frappe qui remplace, Entrée contextuelle, Échap qui restaure) + inventaire priorisé des écarts. #182 Désélection fiable (clic simple sans dépendre du focus), contours de plage non empilés (sélecteur de classes sans point), couleurs texte/fond sur une plage, clic droit qui préserve la sélection multiple. #183 Panneau de couleurs façon Google Sheets : palette 8 × 10, STANDARD, PERSONNALISÉ, coche selon la luminance, sortie `#rrggbb` (une valeur HSL était rejetée par normHex). #184 Peinture de format complète (toutes propriétés, source sans format = réinitialisation), sélection multi-lignes/colonnes depuis les marges, grille étendue : colonnes A → Z d'emblée, lignes ajoutées PAR BLOCS DE 100 au défilement jusqu'à 1000 — matérialiser 1000 lignes d'un coup = ~26 000 cellules câblées par feuille, ce qui épuisait le tas de la suite JSDOM ; index de cellules `ref → td`, court-circuits formule/styles, marqueur data-wired. #185 Barre de menus : les 10 menus Google Sheets (161 entrées, 125 câblées, 36 annoncées indisponibles), ruban façon Sheets, grille unie 1 px dérivée du thème. #186 « Créer un fichier » propose .xlsx et construit un vrai classeur OPC (openpyxl) au lieu d'une charge utile texte illisible. Corrections trouvées en restaurant et en exerçant le lot : - fuite mémoire : écouteur `click` anonyme posé sur #content-area à chaque rendu, jamais retiré — sa fermeture retenait la grille précédente en entier ; - sorties Markdown / HTML / Imprimer de la barre de menus inertes (`data-xlsx-export` jamais réparti, seul `data-xlsx-action` l'était) ; - collision de classe `.xlsx-structure-menu` entre la barre de menus et le menu Structure de la barre d'outils (toute requête tombait sur un nœud masqué) ; - curseur col/row-resize absent quand le pointeur est sur la table elle-même ; - l'export emportait les lignes et colonnes vides du quadrillage (CSV, Markdown, HTML, impression) ; - clic extérieur avalé par la grâce de 250 ms du menu contextuel (destinée au seul appui long tactile) ; - une entrée indisponible laissait la barre de menus ouverte. Tests : pytest 1595 passés / 2 ignorés ; ruff et mypy 0 erreur ; bandit 0 ; 33 suites frontend vertes (xlsx-viewer 163/163, xlsx-menus 19/19, xlsx-formula 14/14) ; E2E complet 132 passés / 12 ignorés ; E2E xlsx-viewer 19/19.
119 lines
6.9 KiB
Markdown
119 lines
6.9 KiB
Markdown
# #185 — Tableur : barre de menus Google Sheets, boutons façon Sheets, grille unie
|
||
|
||
> **Statut :** ✅ livré le 2026-10-08 (v2.54.0) — ouvert le 2026-10-05 | **Effort :** 1-2 jours | **Impact :** 🟡
|
||
> **Références :** [Roadmap](../ROADMAP.md) · [Changelog](../../CHANGELOG.md) ·
|
||
> [#154](./xlsx-ui-redesign.md) · [#179](./xlsx-menus-179.md) ·
|
||
> [#180](./xlsx-sheetbar-180.md) · [#183](./xlsx-sheet-input-181.md))
|
||
|
||
## 1. Constat
|
||
|
||
L'éditeur tableur avait un ruban de boutons et trois menus (Structure, Mise en
|
||
forme, Export) mais **aucune barre de menus** : ni Fichier, ni Modifier, ni
|
||
Affichage, ni Insertion, ni Format, ni Données, ni Outils, ni Gemini, ni
|
||
Extensions, ni Aide. Beaucoup de fonctions existentes n'étaient atteignables que
|
||
par un clic droit ou par un bouton à connaître. Le ruban lui-même gardait un
|
||
chromer bordersé qui ne ressemblait à rien, et la grille n'était bordée qu'en
|
||
bas avec une couleur (`--border`) quasi identique au fond des cellules : le
|
||
quadillage se lisait comme une tache, pas comme une grille.
|
||
|
||
## 2. Livré
|
||
|
||
### A1 — Barre de menus (les 10 menus de Google Sheets)
|
||
|
||
`frontend/js/xlsx/menus.js` (nouveau) décrit **les dix menus, dans l'ordre et avec
|
||
les libellés exacts de Google Sheets** (Fichier · Modifier · Affichage ·
|
||
Insertion · Format · Données · Outils · Gemini · Extensions · Aide), puis
|
||
`buildMenuBar()` produit la barre et ses dix menus déroulants. 161 entrées, dont
|
||
**125 wirables** (67 actions distinctes) et **36 honestement déclarées
|
||
indisponibles** (elles s'affichent mais répondent « *« X » n'est pas disponible
|
||
dans ObsiGate* »** — jamais un clic muet). Les sections imbriquées (Nombre,
|
||
Thème, Alignement, Zoom, Nettoyage…) sont des **accordéons** comme dans Sheets :
|
||
une seule ouverte à la fois par niveau.
|
||
|
||
Le menu **Fichier** a quitté la barre d'onglets pour la barre de menus, en
|
||
conservant ses identifiants (`#xlsx-file-btn`, `#xlsx-file-menu`,
|
||
`#xlsx-download-btn`, `#xlsx-csv-btn`, `[data-xlsx-export]`). Seul
|
||
**Enregistrer** reste épinglé à droite de la barre d'onglets.
|
||
|
||
### A2 — Fonctions réellement câblées
|
||
|
||
- **Fichier** : Partager, Télécharger (original · CSV · Markdown · HTML),
|
||
Imprimer, **Renommer** (`PATCH /api/file/{vault}`), **Corbeille**
|
||
(`DELETE /api/file/{vault}`), **Historique des versions** (visionneuse de
|
||
sauvegardes), Détails (vault, chemin, feuilles, cellules, révision, ·
|
||
modifications en attente via `/api/health` pour le numéro de version).
|
||
- **Modifier** : Annuler, Rétablir, Couper, Copier, Coller, **Collage spécial →
|
||
valeurs uniquement** (les formules sont évaluées puis collées comme texte),
|
||
**Supprimer → lignes / colonnes / contenu**, Tout sélectionner,
|
||
**Rechercher et remplacer** (toutes les feuilles).
|
||
- **Affichage** : Figer (ici / ligne / colonne / libérer), **Afficher → barre de
|
||
formule · grille · en-têtes · tableau de bord**, Grouper (déclaré), Feuilles
|
||
masquées (déclaré), **Zoom** (50 → 200 %, même état que le ruban), **Plein
|
||
écran**.
|
||
- **Insertion** : Lignes (au-dessus / en dessous), Colonnes (à gauche / à
|
||
droite), Cellules, Lien, Commentaire, **Fonction** (insère l'appel et place le
|
||
curseur entre les parenthèses).
|
||
- **Format** : Nombre (6 formats), **Thème** (liste des 15 thèmes construite à la
|
||
demande), Gras / Italique / Souligné / Barré, Taille de police, Alignement
|
||
(horizontal + vertical), Retour à la ligne, Rotation, **Couleurs alternées**
|
||
(une écriture par ligne, lots de 50 — plafond du backend), Effacer la mise en
|
||
forme.
|
||
- **Données** : Trier la plage (croissant / décroissant / réinitialiser),
|
||
**Créer un filtre** (sur la valeur de la cellule active), **Plages nommées**
|
||
(panneau du tableau de bord), **Nettoyage → supprimer les doublons ·trimmer**,
|
||
**Diviser le texte en colonnes**.
|
||
- **Outils** : **Saisie semi-automatique** (bascule la liste de fonctions de la
|
||
barre de formule), **Accessibilité** (cellules plus grandes, grille plus
|
||
contrastée).
|
||
- **Gemini** : les six entrées ouvrent le panneau de l'assistant IA.
|
||
- **Aide** : aide intégrée, **Mises à jour** (version), **Raccourcis clavier**
|
||
(liste), **Signaler un problème** (diagnostic copié dans le presse-papiers).
|
||
|
||
### A3 — Ruban façon Google Sheets
|
||
|
||
Boutons **plats** : 30 × 30, sans bordure ni fond au repos, survol discret, état
|
||
actif teinté, groupes séparés par des filets verticaux. Les sélecteurs (zoom,
|
||
format de nombre, taille de police) suivent le même traitement. **Enregistrer**
|
||
reste le seul pilier plein. Nouveau bouton **grille** (`#xs-grid`), piloté par le
|
||
menu Affichage et inversement.
|
||
|
||
### A4 — Grille unie et visible
|
||
|
||
- Chaque cellule est encadrée sur **les quatre côtés** par **la même** ligne
|
||
1 px (les en-têtes compris : ils se distinguent par leur fond, plus par une
|
||
bordure plus lourde).
|
||
- `--grid-border` n'est plus `--border` (1-2 % d'écart avec le fond sur la plupart
|
||
des thèmes) mais un `color-mix` **du texte vers la surface** calculé par
|
||
`themes.js` : une seule valeur pour toute la grille, lisible en sombre comme
|
||
en clair et dans les modes générés (contraste élevé, sépia).
|
||
- Les valeurs de repli des 4 blocs `:root` ont été remontées en contraste.
|
||
|
||
## 3. Tests
|
||
|
||
- `tests/frontend/xlsx-menus.test.mjs` : i18n amorcé, barre de menus (10 libellés,
|
||
un déroulant par bouton, accordéon), ** exhaustivité des actions déclarées**,
|
||
disparition des entrées d'édition en lecture seule, absence de HTML dans les
|
||
libellés, ids historiques du menu Fichier ; ruban (save, « + », grille).
|
||
- `tests/frontend/xlsx-viewer.test.mjs` : barre présente au-dessus du ruban,
|
||
entrée indisponible qui répond (et n'envoie rien), bascules Affichage, Zoom,
|
||
écriture de structure (Insertion), écriture de style (Format ▸ Nombre),
|
||
**Couleurs alternées** (3 lignes → 3 ops), Accessibilité, Raccourcis clavier,
|
||
classeur en lecture seule, jeton `--grid-border`.
|
||
- `tests/e2e/xlsx-viewer.spec.js` : les 10 menus dans le bon ordre et **au-dessus**
|
||
du ruban, accordéon Format ▸ Nombre, option indisponible, **grille 1 px sur
|
||
les 4 côtés** puis masquée à 0 px.
|
||
|
||
## 4. Limites assumées
|
||
|
||
- Les 36 options Google Sheets qu'ObsiGate n'implémente pas (macros, Apps
|
||
Script, TCD, graphiques, formulaires,/modules, AppSheet, Looker Studio,
|
||
training…) sont **listées pour rester fidèle** à la demande, et **annoncées**
|
||
comme indisponibles au clic. Elles ne sont pas masquées : la parité visuelle
|
||
prime, l'honnêteté prime sur le silence.
|
||
- **Déplacer** lignes/colonnes est déclaré indisponible : leivinguer
|
||
(supprimer + insérer + réécrire) sur un classeur avec fusions, styles et
|
||
formules n'est pas sûr en un seul geste.
|
||
- Le menu **Thème** est construit à la demande (import dynamique de
|
||
`themes.js`) : 15 entrées, pas de coût au rendu.
|
||
- Les couleurs de la grille sont dérivées via `color-mix` : un moteur qui ne le
|
||
supporte pas retombe sur `--grid-border` (feuille de style). |