feat: tableau de bord classeur - plages nommees, TCD/graphiques et KPI par feuille #153

A17 — nouveau endpoint GET /api/file/{vault}/xlsx/dashboard (read_workbook_
dashboard : plages nommees avec portee depuis defined_names read_only,
comptage graphiques/TCD par parts OPC, stats par feuille bornées 500x40 :
cellules/lignes/colonnes/formules/numerique + 8 premieres valeurs en cartes
KPI) et panneau frontend toggled depuis la toolbar (table des plages,
cartes KPI par feuille, hint actions IA). Bouton absent pour .csv et
formats en lecture seule ; le menu structure est saute quand le bouton
n'existe pas. i18n FR/EN (xlsx.dashboard_*), 8 tests backend + 2 tests
JSDOM + contre-preuve (5 echecs sur neutralisation), ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
This commit is contained in:
2026-09-28 16:40:09 -04:00
parent ca6407e0c0
commit c4b8e66206
18 changed files with 562 additions and 15 deletions
+37
View File
@@ -318,6 +318,43 @@ class FileContentResponse(BaseModel):
image_mime: str | None = Field(default=None, description="MIME type for image files")
class XlsxDashboardNamedRange(BaseModel):
"""One named range of a workbook (#153 A17)."""
name: str = Field(description="Range name as declared in the workbook")
scope: str = Field(description="Sheet name when sheet-scoped, empty when workbook-wide")
ref: str = Field(description="Formula-style reference, e.g. Data!$A$1:$B$5")
class XlsxDashboardSheetKpi(BaseModel):
"""One KPI card of a sheet dashboard (#153 A17)."""
label: str = Field(description="A1 reference of the numeric cell")
value: float = Field(description="Numeric value of the cell")
class XlsxDashboardSheet(BaseModel):
"""Per-sheet KPI stats of a workbook dashboard (#153 A17)."""
name: str = Field(description="Sheet name")
cells: int = Field(description="Non-empty cells inside the 500x40 caps")
rows: int = Field(description="Rows carrying at least one non-empty cell")
cols: int = Field(description="Columns carrying at least one non-empty cell")
formulas: int = Field(description="Cells whose value is a formula")
numeric: int = Field(description="Cells carrying a numeric value")
kpi: list[XlsxDashboardSheetKpi] = Field(description="First numeric cells as KPI cards")
class XlsxDashboardResponse(BaseModel):
"""Dashboard metadata of an .xlsx workbook (#153 A17)."""
vault: str = Field(description="Vault name")
path: str = Field(description="Relative file path within the vault")
named_ranges: list[XlsxDashboardNamedRange] = Field(description="Named ranges, sorted by name")
objects: dict[str, int] = Field(description="Object counts: {charts, pivots}")
sheets: list[XlsxDashboardSheet] = Field(description="Per-sheet KPI stats")
class XlsxSheetWindowResponse(BaseModel):
"""One window of rows of a single .xlsx sheet (lazy loading, #153 A9).