mitai-jinkendo/backend/widget_catalog.py
Lars bc91396885
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s
feat: Add new widgets and enhance configuration validation
- Introduced "nutrition_detail_charts", "recovery_charts_panel", and "progress_photos" widgets to the dashboard.
- Updated widget configuration validation to support new widgets, including chart days for nutrition and recovery charts.
- Enhanced the widget catalog and dashboard layout to include the new features.
- Bumped app_dashboard version to 1.7.0 to reflect these additions and improvements.
2026-04-07 20:58:44 +02:00

131 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Öffentlicher Widget-Katalog (Dashboard-Lab / später Produkt-Dashboard).
Single Source für: erlaubte IDs, Standard-Reihenfolge, Anzeige-Metadaten für API/GUI.
Frontend-Komponenten registrieren dieselben IDs lokal (siehe widgetSystem/registerPilotLabWidgets).
"""
from __future__ import annotations
from typing import Any, TypedDict
class WidgetCatalogEntry(TypedDict):
id: str
title: str
description: str
# Reihenfolge = Default-Layout-Reihenfolge. Aktiv-Flags: DEFAULT_LAB_WIDGET_IDS (Rest zunächst aus).
WIDGET_CATALOG: list[WidgetCatalogEntry] = [
{
"id": "welcome",
"title": "Willkommen",
"description": "Begrüßung und Kurzkontext",
},
{
"id": "quick_capture",
"title": "Schnelleingabe",
"description": "Gewicht + Baseline-Vitals; optional show_weight / show_resting_hr / show_hrv / show_vo2_max (false = aus)",
},
{
"id": "kpi_board",
"title": "KPI-Kacheln",
"description": "Referenzwerte, KF%, Ø-Kalorien — optional Kacheln & Reihenfolge (config.tiles, max. 9)",
},
{
"id": "body_overview",
"title": "Körper (Chart)",
"description": "Gewicht & Kennzahlen (optional: config chart_days 790)",
},
{
"id": "activity_overview",
"title": "Aktivität",
"description": "Trainingstyp-Verteilung (Kuchen) + Konsistenz — Zeitraum über config chart_days 790",
},
{
"id": "dashboard_greeting",
"title": "Begrüßung (Produkt)",
"description": "Hallo, Datum & letztes Gewicht-Update",
},
{
"id": "quick_weight_today",
"title": "Gewicht heute",
"description": "Tagesgewicht erfassen (wie Produkt-Dashboard)",
},
{
"id": "body_stat_strip",
"title": "Kennzahlen-Kacheln",
"description": "Gewicht, KF, Magermasse, Ø-kcal — Oberreihe",
},
{
"id": "status_pills",
"title": "Indikatoren (Pills)",
"description": "WHR, WHtR, Protein, KF",
},
{
"id": "profile_goals_progress",
"title": "Profil-Ziele",
"description": "Fortschritt Gewicht/Körperfett aus Profilfeldern",
},
{
"id": "trend_kcal_weight",
"title": "Trend Kalorien + Gewicht",
"description": "Linienchart (optional config chart_days 790, Default 30)",
},
{
"id": "nutrition_activity_summary",
"title": "Ernährung & Aktivität Kurz",
"description": "Ø 7T Kacheln",
},
{
"id": "nutrition_detail_charts",
"title": "Ernährung — Detaillierte Charts",
"description": "Phase-0c NutritionCharts (optional chart_days 790, Default 30)",
},
{
"id": "recovery_charts_panel",
"title": "Erholung — Charts R1R5",
"description": "RecoveryCharts wie Verlauf (optional chart_days 790, Default 28)",
},
{
"id": "progress_photos",
"title": "Fortschrittsfotos",
"description": "Galerie der hochgeladenen Fotos",
},
{
"id": "recovery_sleep_rest",
"title": "Erholung",
"description": "Schlaf-Widget & Ruhetage",
},
{
"id": "goals_focus_teaser",
"title": "Ziele Teaser",
"description": "Kurzlink zur Ziele-Seite",
},
{
"id": "ai_pipeline_insight",
"title": "KI Pipeline & letzte Analyse",
"description": "Pipeline starten + Gesamt-Insight",
},
]
DEFAULT_LAB_WIDGET_IDS: frozenset[str] = frozenset(
{
"welcome",
"quick_capture",
"kpi_board",
"body_overview",
"activity_overview",
}
)
ALLOWED_WIDGET_IDS: frozenset[str] = frozenset(e["id"] for e in WIDGET_CATALOG)
def catalog_response() -> dict[str, Any]:
"""Payload für GET /api/app/widgets/catalog."""
return {
"catalog_version": 1,
"widgets": list(WIDGET_CATALOG),
}