mitai-jinkendo/backend/widget_catalog.py
Lars d22e0ba0a7
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
feat: add fitness_history_viz widget and enhance configuration handling
- Introduced the `fitness_history_viz` widget to the dashboard, enabling users to visualize fitness history data.
- Updated widget configuration to include `fitness_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `fitness_history_viz` entry.
- Implemented default values and validation logic for the widget's configuration, ensuring proper handling of user inputs.
- Added tests to ensure proper validation of the `fitness_history_viz` widget configuration.
- Bumped application version to reflect the addition of the new widget.
2026-04-22 10:13:21 +02:00

172 lines
6.0 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, NotRequired, TypedDict
class WidgetCatalogEntry(TypedDict):
"""requires_feature: optional features.id; fehlt oder leer → Widget immer sichtbar (nur Auth)."""
id: str
title: str
description: str
requires_feature: NotRequired[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); Feature weight_entries",
"requires_feature": "weight_entries",
},
{
"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); Feature weight_entries",
"requires_feature": "weight_entries",
},
{
"id": "body_history_viz",
"title": "Körper (Verlauf-Bundle)",
"description": "Layer-2b body-history-viz: schlanker Standard (KPI kompakt + Gewicht); optional Blöcke/Charts per config (show_* , kpi_detail); chart_days 790; Feature weight_entries",
"requires_feature": "weight_entries",
},
{
"id": "activity_overview",
"title": "Aktivität",
"description": "Trainingstyp-Verteilung (Kuchen) + Konsistenz — Zeitraum über config chart_days 790; Feature activity_entries",
"requires_feature": "activity_entries",
},
{
"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); Feature weight_entries",
"requires_feature": "weight_entries",
},
{
"id": "body_stat_strip",
"title": "Kennzahlen-Kacheln",
"description": "Gewicht, KF, Magermasse, Ø-kcal — Oberreihe; u. a. nutrition_entries (Ø-kcal)",
"requires_feature": "nutrition_entries",
},
{
"id": "status_pills",
"title": "Indikatoren (Pills)",
"description": "WHR, WHtR, Protein, KF; Feature nutrition_entries",
"requires_feature": "nutrition_entries",
},
{
"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); Feature nutrition_entries",
"requires_feature": "nutrition_entries",
},
{
"id": "nutrition_activity_summary",
"title": "Ernährung & Aktivität Kurz",
"description": "Ø 7T Kacheln; Feature nutrition_entries",
"requires_feature": "nutrition_entries",
},
{
"id": "nutrition_detail_charts",
"title": "Ernährung — Detaillierte Charts",
"description": "Phase-0c NutritionCharts (optional chart_days 790, Default 30); Feature nutrition_entries",
"requires_feature": "nutrition_entries",
},
{
"id": "nutrition_history_viz",
"title": "Ernährung (Verlauf-Bundle)",
"description": "Layer-2b nutrition-history-viz: schlanker Standard; Blöcke per show_* / kpi_detail; chart_days 790; Feature nutrition_entries",
"requires_feature": "nutrition_entries",
},
{
"id": "fitness_history_viz",
"title": "Fitness (Verlauf-Bundle)",
"description": "Layer-2b fitness-dashboard-viz: schlanker Standard; Blöcke per show_* / kpi_detail; chart_days 790; Feature activity_entries",
"requires_feature": "activity_entries",
},
{
"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; Feature photos",
"requires_feature": "photos",
},
{
"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; Feature ai_pipeline",
"requires_feature": "ai_pipeline",
},
]
DEFAULT_LAB_WIDGET_IDS: frozenset[str] = frozenset(
{
"welcome",
"quick_capture",
"kpi_board",
"body_overview",
"activity_overview",
}
)
# Produkt-Übersicht (/): Default wenn Nutzer kein dashboard_layout in der DB hat (Physisch: nur Profil-JSON).
DEFAULT_PRODUCT_DASHBOARD_WIDGET_IDS: frozenset[str] = frozenset(
{
"dashboard_greeting",
"quick_weight_today",
"body_stat_strip",
"status_pills",
"trend_kcal_weight",
"nutrition_activity_summary",
"activity_overview",
"recovery_sleep_rest",
"goals_focus_teaser",
"profile_goals_progress",
"ai_pipeline_insight",
}
)
ALLOWED_WIDGET_IDS: frozenset[str] = frozenset(e["id"] for e in WIDGET_CATALOG)