diff --git a/backend/dashboard_widget_config.py b/backend/dashboard_widget_config.py index 57c6a58..729c1ea 100644 --- a/backend/dashboard_widget_config.py +++ b/backend/dashboard_widget_config.py @@ -18,6 +18,8 @@ WIDGETS_ALLOWING_CONFIG: frozenset[str] = frozenset({ "kpi_board", "quick_capture", "trend_kcal_weight", + "nutrition_detail_charts", + "recovery_charts_panel", }) _QUICK_CAPTURE_KEYS: frozenset[str] = frozenset({ @@ -58,6 +60,10 @@ def validate_widget_entry_config(widget_id: str, raw: Any) -> dict[str, Any]: return _validate_quick_capture_config(raw) if widget_id == "trend_kcal_weight": return _validate_chart_days_only(raw, label="trend_kcal_weight") + if widget_id == "nutrition_detail_charts": + return _validate_chart_days_only(raw, label="nutrition_detail_charts") + if widget_id == "recovery_charts_panel": + return _validate_chart_days_only(raw, label="recovery_charts_panel") raise ValueError(f"Widget {widget_id}: keine Konfiguration unterstützt") diff --git a/backend/tests/test_dashboard_widget_config.py b/backend/tests/test_dashboard_widget_config.py index f2287fc..9f30f19 100644 --- a/backend/tests/test_dashboard_widget_config.py +++ b/backend/tests/test_dashboard_widget_config.py @@ -71,6 +71,20 @@ def test_quick_capture_visibility(): validate_widget_entry_config("quick_capture", {"extra": 1}) +def test_nutrition_detail_charts_days(): + assert validate_widget_entry_config("nutrition_detail_charts", {}) == {} + assert validate_widget_entry_config("nutrition_detail_charts", {"chart_days": 60}) == {"chart_days": 60} + with pytest.raises(ValueError): + validate_widget_entry_config("nutrition_detail_charts", {"chart_days": 3}) + + +def test_recovery_charts_panel_days(): + assert validate_widget_entry_config("recovery_charts_panel", {}) == {} + assert validate_widget_entry_config("recovery_charts_panel", {"chart_days": 28}) == {"chart_days": 28} + with pytest.raises(ValueError): + validate_widget_entry_config("recovery_charts_panel", {"chart_days": 99}) + + def test_trend_kcal_weight_chart_days(): assert validate_widget_entry_config("trend_kcal_weight", {}) == {} assert validate_widget_entry_config("trend_kcal_weight", {"chart_days": 30}) == {"chart_days": 30} diff --git a/backend/version.py b/backend/version.py index e2cb67f..6dca031 100644 --- a/backend/version.py +++ b/backend/version.py @@ -30,7 +30,7 @@ MODULE_VERSIONS = { "importdata": "1.0.0", "membership": "2.1.0", "workflow": "0.6.0", # Phase 4: End Node Template Engine - "app_dashboard": "1.6.2", # quick_capture: Sichtbarkeit show_* konfigurierbar + "app_dashboard": "1.7.0", # nutrition_detail_charts, recovery_charts_panel, progress_photos } CHANGELOG = [ diff --git a/backend/widget_catalog.py b/backend/widget_catalog.py index b0c8f9e..bf7cd33 100644 --- a/backend/widget_catalog.py +++ b/backend/widget_catalog.py @@ -77,6 +77,21 @@ WIDGET_CATALOG: list[WidgetCatalogEntry] = [ "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 7–90, Default 30)", + }, + { + "id": "recovery_charts_panel", + "title": "Erholung — Charts R1–R5", + "description": "RecoveryCharts wie Verlauf (optional chart_days 7–90, Default 28)", + }, + { + "id": "progress_photos", + "title": "Fortschrittsfotos", + "description": "Galerie der hochgeladenen Fotos", + }, { "id": "recovery_sleep_rest", "title": "Erholung", diff --git a/frontend/src/components/dashboard-widgets/NutritionDetailChartsWidget.jsx b/frontend/src/components/dashboard-widgets/NutritionDetailChartsWidget.jsx new file mode 100644 index 0000000..a3958cd --- /dev/null +++ b/frontend/src/components/dashboard-widgets/NutritionDetailChartsWidget.jsx @@ -0,0 +1,32 @@ +import { useNavigate } from 'react-router-dom' +import NutritionCharts from '../NutritionCharts' +import { normalizeBodyChartDays } from '../../widgetSystem/bodyChartDays' + +/** + * Phase-0c-Ernährungscharts (wie „Detaillierte Charts“ im Verlauf). + * @param {{ refreshTick?: number, chartDays?: number }} props + */ +export default function NutritionDetailChartsWidget({ refreshTick = 0, chartDays }) { + const nav = useNavigate() + const days = chartDays != null ? normalizeBodyChartDays(chartDays) : 30 + + return ( +