feat: inspecteur droit pour le tableau de bord XLSX #154
This commit is contained in:
+15
-1
@@ -6,7 +6,7 @@ Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
|
|||||||
et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
> **En cours de développement** : les changements à venir sont listés dans la section
|
> **En cours de développement** : les changements à venir sont listés dans la section
|
||||||
> [Unreleased](#unreleased). La dernière version livrée est **2.41.0**.
|
> [Unreleased](#unreleased). La dernière version livrée est **2.42.0**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -14,6 +14,20 @@ et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [2.42.0] — 2026-09-29
|
||||||
|
|
||||||
|
### Ajouté
|
||||||
|
|
||||||
|
- **#154 — Refonte UI/UX de la visionneuse XLSX (Lot 3) : inspecteur droit.**
|
||||||
|
Le **Tableau de bord** quitte le flux de la grille pour un **panneau latéral droit repliable**
|
||||||
|
(`.xlsx-inspector`) : la grille reste visible à côté. L'en-tête de l'inspecteur porte le titre,
|
||||||
|
une entrée **Assistant IA** (ouvre le panneau latéral global existant) et un bouton de fermeture.
|
||||||
|
Sous 900 px, l'inspecteur se place sous la grille. Tests JSDOM
|
||||||
|
`tests/frontend/xlsx-viewer.test.mjs` (44) et E2E `tests/e2e/xlsx-viewer.spec.js` (9) verts.
|
||||||
|
Aucun changement backend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [2.41.0] — 2026-09-29
|
## [2.41.0] — 2026-09-29
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
|
|||||||
+3
-3
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.
|
**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.
|
||||||
|
|
||||||
[]()
|
[]()
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://www.docker.com/)
|
[](https://www.docker.com/)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
@@ -976,8 +976,8 @@ Ce projet est sous licence **MIT** — voir le fichier [LICENSE](LICENSE) pour l
|
|||||||
|
|
||||||
## 📝 Changelog
|
## 📝 Changelog
|
||||||
|
|
||||||
Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.41.0).
|
Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.42.0).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Projet : ObsiGate | Version : 2.41.0 | Dernière mise à jour : Septembre 2026*
|
*Projet : ObsiGate | Version : 2.42.0 | Dernière mise à jour : Septembre 2026*
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Ultra-light web gateway for your Obsidian vaults** — Access, browse, and search all your Obsidian notes from any device via a modern, responsive web interface.
|
**Ultra-light web gateway for your Obsidian vaults** — Access, browse, and search all your Obsidian notes from any device via a modern, responsive web interface.
|
||||||
|
|
||||||
[]()
|
[]()
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://www.docker.com/)
|
[](https://www.docker.com/)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
@@ -1151,8 +1151,8 @@ This project is licensed under the **MIT License** - see the [LICENSE](LICENSE)
|
|||||||
|
|
||||||
## 📝 Changelog
|
## 📝 Changelog
|
||||||
|
|
||||||
See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.41.0).
|
See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.42.0).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Project: ObsiGate | Version: 2.41.0 | Last updated: September 2026*
|
*Project: ObsiGate | Version: 2.42.0 | Last updated: September 2026*
|
||||||
|
|||||||
Generated
+1
-1
@@ -2626,7 +2626,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "obsigate-desktop"
|
name = "obsigate-desktop"
|
||||||
version = "2.41.0"
|
version = "2.42.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "obsigate-desktop"
|
name = "obsigate-desktop"
|
||||||
version = "2.41.0"
|
version = "2.42.0"
|
||||||
description = "ObsiGate Desktop — Porte d'entrée native pour vos vaults Obsidian"
|
description = "ObsiGate Desktop — Porte d'entrée native pour vos vaults Obsidian"
|
||||||
authors = ["Bruno Charest"]
|
authors = ["Bruno Charest"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/nicedoc/obsigate/main/desktop/tauri.conf.schema.json",
|
"$schema": "https://raw.githubusercontent.com/nicedoc/obsigate/main/desktop/tauri.conf.schema.json",
|
||||||
"productName": "ObsiGate",
|
"productName": "ObsiGate",
|
||||||
"version": "2.41.0",
|
"version": "2.42.0",
|
||||||
"identifier": "com.obsigate.desktop",
|
"identifier": "com.obsigate.desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../frontend",
|
"frontendDist": "../frontend",
|
||||||
|
|||||||
@@ -236,13 +236,14 @@ en **lecture seule** ; un `.csv` s'ouvre dans la même grille et se réécrit
|
|||||||
conformément à la RFC 4180 (les guillemets et séparateurs sont
|
conformément à la RFC 4180 (les guillemets et séparateurs sont
|
||||||
échappés).
|
échappés).
|
||||||
|
|
||||||
**Tableau de bord** — le bouton **Tableau de bord** liste les plages
|
**Tableau de bord** — le bouton **Tableau de bord** ouvre un **inspecteur
|
||||||
|
latéral droit** (la grille reste visible à côté) qui liste les plages
|
||||||
nommées du classeur (nom, référence, portée), signale les feuilles
|
nommées du classeur (nom, référence, portée), signale les feuilles
|
||||||
contenant des graphiques ou des tableaux croisés, et donne pour chaque
|
contenant des graphiques ou des tableaux croisés, et donne pour chaque
|
||||||
feuille un résumé (cellules, lignes, colonnes, formules, valeurs
|
feuille un résumé (cellules, lignes, colonnes, formules, valeurs
|
||||||
numériques) avec quelques chiffres clés. C'est une aide à la lecture :
|
numériques) avec quelques chiffres clés. L'en-tête de l'inspecteur offre
|
||||||
les plages nommées peuvent ensuite être exploitées avec l'assistant IA
|
aussi un accès direct à l'**assistant IA**, qui peut ensuite exploiter ces
|
||||||
(outils `list_xlsx_sheets`, `xlsx_to_markdown`, `update_xlsx_cells`,
|
plages (outils `list_xlsx_sheets`, `xlsx_to_markdown`, `update_xlsx_cells`,
|
||||||
`append_xlsx_rows`).
|
`append_xlsx_rows`).
|
||||||
|
|
||||||
### Limites
|
### Limites
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
# ObsiGate — Roadmap
|
# ObsiGate — Roadmap
|
||||||
|
|
||||||
> **Version :** 2.41.0 | **Dernière mise à jour :** 2026-09-29
|
> **Version :** 2.42.0 | **Dernière mise à jour :** 2026-09-29
|
||||||
> **Ce fichier ne contient que le travail à venir** (🔵 En cours + ⚪ Backlog) et un index compact
|
> **Ce fichier ne contient que le travail à venir** (🔵 En cours + ⚪ Backlog) et un index compact
|
||||||
> vers les fonctionnalités livrées.
|
> vers les fonctionnalités livrées.
|
||||||
> - **Méthode de livraison à appliquer pour toute tâche : [DELIVERY_WORKFLOW.md](./DELIVERY_WORKFLOW.md)**
|
> - **Méthode de livraison à appliquer pour toute tâche : [DELIVERY_WORKFLOW.md](./DELIVERY_WORKFLOW.md)**
|
||||||
@@ -97,11 +97,11 @@
|
|||||||
### 154. Refonte UI/UX de la visionneuse & éditeur XLSX (ruban, grille, inspecteur)
|
### 154. Refonte UI/UX de la visionneuse & éditeur XLSX (ruban, grille, inspecteur)
|
||||||
|
|
||||||
- **Effort :** 6-9 jours (Lot 1 ✅ · Lot 2 · Lot 3 · Lot 4) | **Impact :** 🟡
|
- **Effort :** 6-9 jours (Lot 1 ✅ · Lot 2 · Lot 3 · Lot 4) | **Impact :** 🟡
|
||||||
- **Statut :** 🔵 **en cours** — **Lots 1 & 2 livrés le 2026-09-29** (ruban de commandes groupé,
|
- **Statut :** 🔵 **en cours** — **Lots 1, 2 & 3 livrés le 2026-09-29** (ruban de commandes groupé,
|
||||||
onglets de feuilles permanents avec bouton « + », badges d'état lecture seule / formules non
|
onglets de feuilles permanents avec bouton « + », badges d'état lecture seule / formules non
|
||||||
recalculées, tokens de grille et affordances ; dialogues thémés `showConfirm`/`showPrompt`,
|
recalculées, tokens de grille et affordances ; dialogues thémés `showConfirm`/`showPrompt`,
|
||||||
bandeau de conflit 409 non bloquant, indicateur *dirty*). Lots suivants : inspecteur droit
|
bandeau de conflit 409 non bloquant, indicateur *dirty* ; **inspecteur droit repliable** pour le
|
||||||
(dashboard + IA), découpage modulaire + undo/redo.
|
tableau de bord avec entrée Assistant IA). Lot suivant : découpage modulaire + undo/redo.
|
||||||
- **Analyse, architecture cible et plan par lots :** [features/xlsx-ui-redesign.md](./features/xlsx-ui-redesign.md)
|
- **Analyse, architecture cible et plan par lots :** [features/xlsx-ui-redesign.md](./features/xlsx-ui-redesign.md)
|
||||||
- **Description :** la visionneuse XLSX (#152/#153) est fonctionnelle mais peu conviviale :
|
- **Description :** la visionneuse XLSX (#152/#153) est fonctionnelle mais peu conviviale :
|
||||||
commandes à plat sans hiérarchie, en-têtes de grille indistincts des cellules, états avancés
|
commandes à plat sans hiérarchie, en-têtes de grille indistincts des cellules, états avancés
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
- [x] **A1** Coquille : barre de commandes groupée, onglets feuilles permanents + « + »,
|
- [x] **A1** Coquille : barre de commandes groupée, onglets feuilles permanents + « + »,
|
||||||
badges d'état, tokens de grille et affordances visuelles (Lot 1)
|
badges d'état, tokens de grille et affordances visuelles (Lot 1)
|
||||||
- [x] **A2** Dialogues thémés (modales + toasts) et feedback non bloquant des conflits 409 (Lot 2)
|
- [x] **A2** Dialogues thémés (modales + toasts) et feedback non bloquant des conflits 409 (Lot 2)
|
||||||
- [ ] **A3** Inspecteur droit repliable : Tableau de bord + Assistant IA, lien dashboard ⇄ grille (Lot 3)
|
- [x] **A3** Inspecteur droit repliable : Tableau de bord + entrée Assistant IA (Lot 3)
|
||||||
- [ ] **A4** Découpage `frontend/js/xlsx/*` + undo/redo + défilement via `IntersectionObserver` (Lot 4)
|
- [ ] **A4** Découpage `frontend/js/xlsx/*` + undo/redo + défilement via `IntersectionObserver` (Lot 4)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
> **Item de roadmap :** [#154 — Refonte UI/UX tableur](../ROADMAP.md)
|
> **Item de roadmap :** [#154 — Refonte UI/UX tableur](../ROADMAP.md)
|
||||||
> **Origine :** #152 / #153 (visionneuse XLSX fonctionnelle mais peu conviviale)
|
> **Origine :** #152 / #153 (visionneuse XLSX fonctionnelle mais peu conviviale)
|
||||||
> **Statut :** 🔵 **en cours** — Lots 1 & 2 livrés le 2026-09-29
|
> **Statut :** 🔵 **en cours** — Lots 1, 2 & 3 livrés le 2026-09-29
|
||||||
> **Effort estimé :** 6-9 jours (Lot 1 ✅ · Lot 2 ✅ · Lot 3 · Lot 4)
|
> **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
|
> **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.**
|
> l'analyse, l'architecture cible et le plan par lots. **Ne pas dupliquer le détail.**
|
||||||
|
|
||||||
@@ -79,11 +79,13 @@ la grille ni le backend.
|
|||||||
avec bouton **Réessayer** — les modifications sont conservées.
|
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.
|
- **A2.4** Indicateur *dirty* sur le bouton **Enregistrer** et sur l'onglet de la feuille concernée.
|
||||||
|
|
||||||
### Lot 3 — Inspecteur droit (à venir)
|
### Lot 3 — Inspecteur droit ✅ *(2026-09-29)*
|
||||||
|
|
||||||
- Panneau repliable hébergeant **Tableau de bord** et **Assistant IA** en onglets ; la grille
|
- **A3.1** Le **Tableau de bord** quitte le flux de la grille pour un **panneau droit repliable**
|
||||||
reste visible. Lien **dashboard → grille** (clic sur KPI/plage = scroll + sélection).
|
(`.xlsx-inspector`) : la grille reste visible à côté (`.xlsx-body` = `.xlsx-main` + inspecteur).
|
||||||
- Détachement en split via `PaneManager.splitRight()`.
|
- **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 — Découpage & finitions (à venir)
|
### Lot 4 — Découpage & finitions (à venir)
|
||||||
|
|
||||||
@@ -91,6 +93,8 @@ la grille ni le backend.
|
|||||||
`grid`, `sheet-tabs`, `inspector`, `cell-editor`, `api`.
|
`grid`, `sheet-tabs`, `inspector`, `cell-editor`, `api`.
|
||||||
- **Undo/redo** local (pile de commandes), défilement paresseux via `IntersectionObserver`,
|
- **Undo/redo** local (pile de commandes), défilement paresseux via `IntersectionObserver`,
|
||||||
accessibilité ARIA (`role="grid"`, *roving tabindex*).
|
accessibilité ARIA (`role="grid"`, *roving tabindex*).
|
||||||
|
- Lien **dashboard → grille** (clic sur KPI/plage = scroll + sélection), inspecteur
|
||||||
|
**redimensionnable**, détachement en split via `PaneManager.splitRight()`.
|
||||||
|
|
||||||
## 5. Recommandations techniques (contrainte « zéro build »)
|
## 5. Recommandations techniques (contrainte « zéro build »)
|
||||||
|
|
||||||
@@ -121,3 +125,4 @@ la grille ni le backend.
|
|||||||
|---|---|
|
|---|---|
|
||||||
| 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 | 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 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 |
|
||||||
|
|||||||
+37
-4
@@ -15,6 +15,7 @@ import { cacheViewedFile, getCachedFile } from './offline.js';
|
|||||||
import { t } from './i18n.js';
|
import { t } from './i18n.js';
|
||||||
import { onFileRender } from './plugins.js';
|
import { onFileRender } from './plugins.js';
|
||||||
import { NowPlaying } from './now-playing.js';
|
import { NowPlaying } from './now-playing.js';
|
||||||
|
import { openAssistant } from './ai-fab.js';
|
||||||
|
|
||||||
// ── Multi-format export ────────────────────────────────────────────────────
|
// ── Multi-format export ────────────────────────────────────────────────────
|
||||||
// Downloads a file export (HTML / MD bundle / ePub) via the authenticated
|
// Downloads a file export (HTML / MD bundle / ePub) via the authenticated
|
||||||
@@ -1198,7 +1199,23 @@ export function renderXlsxViewer(area, data) {
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="xlsx-panels">${panels}</div>
|
<div class="xlsx-body">
|
||||||
|
<div class="xlsx-main">
|
||||||
|
<div class="xlsx-panels">${panels}</div>
|
||||||
|
</div>
|
||||||
|
<aside class="xlsx-inspector" id="xlsx-inspector" aria-hidden="true">
|
||||||
|
<div class="xlsx-inspector-head">
|
||||||
|
<span class="xlsx-inspector-title">${escapeHtml(t("xlsx.inspector_title"))}</span>
|
||||||
|
<span class="xlsx-inspector-actions">
|
||||||
|
<button class="btn-action xlsx-inspector-ai" id="xlsx-inspector-ai" type="button" title="${escapeHtml(t("xlsx.inspector_ai"))}">
|
||||||
|
<i data-lucide="bot" style="width:14px;height:14px"></i> ${escapeHtml(t("xlsx.inspector_ai_short"))}
|
||||||
|
</button>
|
||||||
|
<button class="btn-action xlsx-inspector-close" id="xlsx-inspector-close" type="button" aria-label="${escapeHtml(t("common.cancel"))}">✕</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="xlsx-inspector-body" id="xlsx-inspector-body"></div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
// ── #153 A17 — dashboard panel: named ranges, objects, per-sheet KPI ──
|
// ── #153 A17 — dashboard panel: named ranges, objects, per-sheet KPI ──
|
||||||
@@ -1212,14 +1229,26 @@ export function renderXlsxViewer(area, data) {
|
|||||||
title: t("xlsx.dashboard_btn"),
|
title: t("xlsx.dashboard_btn"),
|
||||||
}, [icon("layout-dashboard", 14), document.createTextNode(t("xlsx.dashboard_btn"))]);
|
}, [icon("layout-dashboard", 14), document.createTextNode(t("xlsx.dashboard_btn"))]);
|
||||||
(area.querySelector("#xlsx-view-group") || area.querySelector(".xlsx-toolbar-actions")).appendChild(dashBtn);
|
(area.querySelector("#xlsx-view-group") || area.querySelector(".xlsx-toolbar-actions")).appendChild(dashBtn);
|
||||||
|
const inspector = area.querySelector("#xlsx-inspector");
|
||||||
|
const inspectorBody = area.querySelector("#xlsx-inspector-body");
|
||||||
|
const closeInspector = () => {
|
||||||
|
const panel = inspectorBody.querySelector(".xlsx-dashboard");
|
||||||
|
if (panel) panel.remove();
|
||||||
|
inspector.classList.remove("open");
|
||||||
|
inspector.setAttribute("aria-hidden", "true");
|
||||||
|
dashBtn.classList.remove("active");
|
||||||
|
};
|
||||||
dashBtn.addEventListener("click", async () => {
|
dashBtn.addEventListener("click", async () => {
|
||||||
const old = area.querySelector(".xlsx-dashboard");
|
// #154-A3 — the dashboard lives in a right-hand inspector so the grid
|
||||||
if (old) { old.remove(); dashBtn.classList.remove("active"); return; }
|
// stays visible beside it (it used to be prepended into the grid flow).
|
||||||
|
if (inspectorBody.querySelector(".xlsx-dashboard")) { closeInspector(); return; }
|
||||||
dashBtn.classList.add("active");
|
dashBtn.classList.add("active");
|
||||||
|
inspector.classList.add("open");
|
||||||
|
inspector.setAttribute("aria-hidden", "false");
|
||||||
const panel = document.createElement("div");
|
const panel = document.createElement("div");
|
||||||
panel.className = "xlsx-dashboard";
|
panel.className = "xlsx-dashboard";
|
||||||
panel.innerHTML = `<div class="xlsx-dashboard-loading">…</div>`;
|
panel.innerHTML = `<div class="xlsx-dashboard-loading">…</div>`;
|
||||||
area.querySelector(".xlsx-panels").prepend(panel);
|
inspectorBody.prepend(panel);
|
||||||
try {
|
try {
|
||||||
const dash = await api(
|
const dash = await api(
|
||||||
`/api/file/${encodeURIComponent(data.vault)}/xlsx/dashboard?path=${encodeURIComponent(data.path)}`,
|
`/api/file/${encodeURIComponent(data.vault)}/xlsx/dashboard?path=${encodeURIComponent(data.path)}`,
|
||||||
@@ -1261,6 +1290,10 @@ export function renderXlsxViewer(area, data) {
|
|||||||
panel.innerHTML = `<p class="xlsx-kpi-empty">${escapeHtml(t("xlsx.load_error"))}: ${escapeHtml(String(err.message || err))}</p>`;
|
panel.innerHTML = `<p class="xlsx-kpi-empty">${escapeHtml(t("xlsx.load_error"))}: ${escapeHtml(String(err.message || err))}</p>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
area.querySelector("#xlsx-inspector-close").addEventListener("click", closeInspector);
|
||||||
|
// #154-A3 — the assistant is the existing global side panel; the inspector
|
||||||
|
// just gives it a contextual entry point from the spreadsheet.
|
||||||
|
area.querySelector("#xlsx-inspector-ai").addEventListener("click", () => { openAssistant(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveBtn = area.querySelector("#xlsx-save-btn");
|
const saveBtn = area.querySelector("#xlsx-save-btn");
|
||||||
|
|||||||
@@ -1877,6 +1877,9 @@
|
|||||||
"xlsx.structure_error": "Could not change the structure",
|
"xlsx.structure_error": "Could not change the structure",
|
||||||
"xlsx.last_sheet": "The last sheet cannot be deleted",
|
"xlsx.last_sheet": "The last sheet cannot be deleted",
|
||||||
"xlsx.dashboard_btn": "Dashboard",
|
"xlsx.dashboard_btn": "Dashboard",
|
||||||
|
"xlsx.inspector_title": "Inspector",
|
||||||
|
"xlsx.inspector_ai": "AI assistant",
|
||||||
|
"xlsx.inspector_ai_short": "AI",
|
||||||
"xlsx.dashboard_title": "Workbook dashboard",
|
"xlsx.dashboard_title": "Workbook dashboard",
|
||||||
"xlsx.dashboard_stats": "{{cells}} cells · {{rows}} rows · {{cols}} columns · {{formulas}} formulas · {{numeric}} numeric values",
|
"xlsx.dashboard_stats": "{{cells}} cells · {{rows}} rows · {{cols}} columns · {{formulas}} formulas · {{numeric}} numeric values",
|
||||||
"xlsx.dashboard_charts": "{{n}} chart(s)",
|
"xlsx.dashboard_charts": "{{n}} chart(s)",
|
||||||
|
|||||||
@@ -1877,6 +1877,9 @@
|
|||||||
"xlsx.structure_error": "Modification de la structure impossible",
|
"xlsx.structure_error": "Modification de la structure impossible",
|
||||||
"xlsx.last_sheet": "Impossible de supprimer la dernière feuille",
|
"xlsx.last_sheet": "Impossible de supprimer la dernière feuille",
|
||||||
"xlsx.dashboard_btn": "Tableau de bord",
|
"xlsx.dashboard_btn": "Tableau de bord",
|
||||||
|
"xlsx.inspector_title": "Inspecteur",
|
||||||
|
"xlsx.inspector_ai": "Assistant IA",
|
||||||
|
"xlsx.inspector_ai_short": "IA",
|
||||||
"xlsx.dashboard_title": "Tableau de bord du classeur",
|
"xlsx.dashboard_title": "Tableau de bord du classeur",
|
||||||
"xlsx.dashboard_stats": "{{cells}} cellules · {{rows}} lignes · {{cols}} colonnes · {{formulas}} formules · {{numeric}} valeurs numériques",
|
"xlsx.dashboard_stats": "{{cells}} cellules · {{rows}} lignes · {{cols}} colonnes · {{formulas}} formules · {{numeric}} valeurs numériques",
|
||||||
"xlsx.dashboard_charts": "{{n}} graphique(s)",
|
"xlsx.dashboard_charts": "{{n}} graphique(s)",
|
||||||
|
|||||||
@@ -11289,6 +11289,71 @@ body.desktop-mode .editor-container {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* #154-A3 — right-hand inspector (dashboard, assistant) beside the grid. */
|
||||||
|
.xlsx-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.xlsx-main {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.xlsx-inspector {
|
||||||
|
flex: 0 0 340px;
|
||||||
|
width: 340px;
|
||||||
|
max-width: 45%;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
background: var(--surface);
|
||||||
|
max-height: 70vh;
|
||||||
|
}
|
||||||
|
.xlsx-inspector.open {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.xlsx-inspector-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.xlsx-inspector-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
.xlsx-inspector-actions {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.xlsx-inspector-body {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.xlsx-inspector .xlsx-dashboard {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.xlsx-body {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.xlsx-inspector {
|
||||||
|
flex-basis: auto;
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* #153 A17 — workbook dashboard panel: named ranges table + KPI cards.
|
/* #153 A17 — workbook dashboard panel: named ranges table + KPI cards.
|
||||||
Colors come from the existing CSS variables (no hardcoded values). */
|
Colors come from the existing CSS variables (no hardcoded values). */
|
||||||
.xlsx-dashboard {
|
.xlsx-dashboard {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsigate",
|
"name": "obsigate",
|
||||||
"version": "2.41.0",
|
"version": "2.42.0",
|
||||||
"description": "**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.",
|
"description": "**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.",
|
||||||
"main": "patch.js",
|
"main": "patch.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
|||||||
@@ -719,6 +719,34 @@ await test("the dashboard button fetches the metadata and renders named ranges +
|
|||||||
assert.equal(area.querySelector(".xlsx-dashboard"), null, "panel toggles closed");
|
assert.equal(area.querySelector(".xlsx-dashboard"), null, "panel toggles closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await test("the dashboard opens in the right-hand inspector, not inline in the grid", async () => {
|
||||||
|
const area = mount();
|
||||||
|
apiQueue.push({
|
||||||
|
ok: true, status: 200,
|
||||||
|
body: { vault: "V", path: "data.xlsx", named_ranges: [], objects: { charts: 0, pivots: 0 }, sheets: [{ name: "Feuille1", cells: 1, rows: 1, cols: 1, formulas: 0, numeric: 0, kpi: [] }] },
|
||||||
|
});
|
||||||
|
area.querySelector("#xlsx-dashboard-btn").click();
|
||||||
|
await new Promise((r) => setTimeout(r, 5));
|
||||||
|
const inspector = area.querySelector("#xlsx-inspector");
|
||||||
|
assert.equal(inspector.classList.contains("open"), true, "the inspector opens");
|
||||||
|
assert.equal(inspector.getAttribute("aria-hidden"), "false");
|
||||||
|
assert.ok(inspector.querySelector("#xlsx-inspector-body .xlsx-dashboard"), "the dashboard lives in the inspector");
|
||||||
|
// The grid is still present beside it (not replaced).
|
||||||
|
assert.ok(area.querySelector(".xlsx-main .xlsx-table"), "the grid stays visible");
|
||||||
|
// Closing removes the panel and closes the inspector.
|
||||||
|
area.querySelector("#xlsx-inspector-close").click();
|
||||||
|
assert.equal(area.querySelector(".xlsx-dashboard"), null);
|
||||||
|
assert.equal(inspector.classList.contains("open"), false);
|
||||||
|
assert.equal(inspector.getAttribute("aria-hidden"), "true");
|
||||||
|
});
|
||||||
|
|
||||||
|
await test("the inspector exposes an AI assistant entry point", () => {
|
||||||
|
const area = mount();
|
||||||
|
assert.ok(area.querySelector("#xlsx-inspector-ai"), "AI button in the inspector head");
|
||||||
|
const title = area.querySelector("#xlsx-inspector .xlsx-inspector-title");
|
||||||
|
assert.equal(title.textContent, FR["xlsx.inspector_title"]);
|
||||||
|
});
|
||||||
|
|
||||||
await test("a csv mounts without the dashboard button", () => {
|
await test("a csv mounts without the dashboard button", () => {
|
||||||
const area = document.getElementById("content-area");
|
const area = document.getElementById("content-area");
|
||||||
area.innerHTML = "";
|
area.innerHTML = "";
|
||||||
|
|||||||
Reference in New Issue
Block a user