feat: remove deprecated demo route and enhance dashboard widget registration
All checks were successful
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Successful in 5s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s

- Removed outdated visualization demo route and fixed demo layout in the frontend.
- Updated widget registration logic in `frontend/src/widgetSystem/registerDashboardWidgets.js` to ensure proper integration of core widgets.
- Adjusted documentation in `.claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` and comments in `backend/widget_catalog.py` to reflect changes.
- Added new dashboard widgets for activity and body overview, enhancing user experience and data visualization capabilities.
- Bumped application version to reflect these changes.
This commit is contained in:
Lars 2026-04-23 15:24:13 +02:00
parent 725e7ffe4b
commit ddc87ba5ae
18 changed files with 70 additions and 138 deletions

View File

@ -42,7 +42,7 @@ Kontext: **Dashboard-Lab** unter geschützten Endpoints `GET/PUT /api/app/...` (
1. **`backend/widget_catalog.py`** `WIDGET_CATALOG`: erlaubte Widget-IDs, Reihenfolge, Titel/Beschreibung für API und Default-Layout.
2. **`backend/dashboard_layout_schema.py`** `DashboardLayoutPayload`: jede Zeile hat `id`, `enabled`, optional `config`. IDs müssen in `ALLOWED_WIDGET_IDS` sein (aus dem Katalog abgeleitet).
3. **`backend/dashboard_widget_config.py`** `validate_widget_entry_config`: **nur** Widgets in `WIDGETS_ALLOWING_CONFIG` dürfen **nicht-leere** `config` haben; Keys werden streng validiert (unbekannte Keys → Fehler).
4. **Frontend** `ensurePilotLabWidgetsRegistered()` in `frontend/src/widgetSystem/registerPilotLabWidgets.js`: verbindet jede Katalog-ID mit einer React-Komponente und mappt `ctx.layoutEntry.config` auf Props.
4. **Frontend** `ensureDashboardWidgetsRegistered()` in `frontend/src/widgetSystem/registerDashboardWidgets.js`: verbindet jede Katalog-ID mit einer React-Komponente und mappt `ctx.layoutEntry.config` auf Props.
5. **Dashboard-Lab-UI** `frontend/src/pages/DashboardLabPage.jsx`: Umsortieren, Ein/Aus, Speichern; **zusätzliche** UI nur nötig, wenn das Widget konfigurierbare Felder braucht.
---
@ -53,8 +53,8 @@ Kontext: **Dashboard-Lab** unter geschützten Endpoints `GET/PUT /api/app/...` (
|--------|--------|--------|
| A | `backend/widget_catalog.py` | Neuen Eintrag `{ "id", "title", "description" }` in `WIDGET_CATALOG` einfügen (Reihenfolge = Default-Reihenfolge im Layout). Optional `"requires_feature": "<features.id>"` für Tarif-Gating (`dashboard_widget_entitlements`). |
| B | `backend/widget_catalog.py` | Optional: ID zu `DEFAULT_LAB_WIDGET_IDS` hinzufügen, wenn es im Standard-Lab **aktiv** sein soll. |
| C | `frontend/src/components/dashboard-widgets/MyWidget.jsx` (oder Pilot-Komponente) | React-Komponente implementieren; typischerweise `refreshTick` aus `mapProps` nutzen, um Daten neu zu laden. |
| D | `frontend/src/widgetSystem/registerPilotLabWidgets.js` | `import` + `registerDashboardWidget({ id, Component, mapProps })` `id` **exakt** wie im Katalog. |
| C | `frontend/src/components/dashboard-widgets/MyWidget.jsx` (oder Legacy-Widget unter `dashboard-widgets-legacy/`) | React-Komponente implementieren; typischerweise `refreshTick` aus `mapProps` nutzen, um Daten neu zu laden. |
| D | `frontend/src/widgetSystem/registerDashboardWidgets.js` | `import` + `registerDashboardWidget({ id, Component, mapProps })` `id` **exakt** wie im Katalog. |
| E | `backend/tests/test_widget_catalog.py` | Läuft implizit mit; bei Strukturänderungen Katalog-Tests beachten. |
| F | `backend/version.py` | `MODULE_VERSIONS["app_dashboard"]` MINOR erhöhen und kurz kommentieren. |
| G | Build/Tests | `pytest` (z.B. `tests/test_dashboard_layout_schema.py`, `test_widget_catalog.py`); `npm run build` im `frontend`. |
@ -159,5 +159,5 @@ Nach Speichern ruft die Seite `api.putAppDashboardLayout(layout)` auf; das Backe
| Layout-Pydantic | `backend/dashboard_layout_schema.py` |
| HTTP | `backend/routers/app_dashboard.py` |
| Registry + Render | `frontend/src/widgetSystem/dashboardWidgetRegistry.jsx` |
| Pilot/Lab-Registrierung | `frontend/src/widgetSystem/registerPilotLabWidgets.js` |
| Dashboard-Widget-Registrierung | `frontend/src/widgetSystem/registerDashboardWidgets.js` |
| Lab-UI | `frontend/src/pages/DashboardLabPage.jsx` |

View File

@ -100,6 +100,11 @@ frontend/src/
**Branch:** develop
**Nächster Schritt:** Frontend Chart Integration → Testing → Prod Deploy v0.9i
### Updates (23.04.2026 - Dashboard: veraltete Demo-Route entfernt, klare Produkt-Registry)
- **Frontend:** Veraltete Visualisierungs-Demo-Route und festes Demo-Layout entfernt; Widget-Registrierung in `frontend/src/widgetSystem/registerDashboardWidgets.js` (`ensureDashboardWidgetsRegistered`). Kern-Widgets unter `frontend/src/components/dashboard-widgets-legacy/`. Chart-Hilfen in `frontend/src/widgetSystem/dashboardChartUtils.js`.
- **Doku:** `.claude/docs/technical/DASHBOARD_WIDGETS_AGENT_GUIDE.md` und Kommentar in `backend/widget_catalog.py` angepasst.
### Updates (09.04.2026 - Universal CSV Import, Prod-Migration abgeschlossen)
- **Agent-Leitfaden:** `.claude/docs/technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` (Checkliste für neue Import-Module, Executor, Vorlagen, `source=csv`, SAVEPOINT-/Cursor-Regeln)

View File

@ -2,7 +2,7 @@
Ö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).
Frontend-Komponenten registrieren dieselben IDs lokal (siehe widgetSystem/registerDashboardWidgets.js, Funktion ensureDashboardWidgetsRegistered).
"""
from __future__ import annotations

View File

@ -25,7 +25,6 @@ import Analysis from './pages/Analysis'
import SettingsPage from './pages/SettingsPage'
import SettingsShell from './layouts/SettingsShell'
import ProfileReferenceValuesPage from './pages/ProfileReferenceValuesPage'
import PilotVizPage from './pages/PilotVizPage'
import DashboardLabPage from './pages/DashboardLabPage'
import DashboardConfigurePage from './pages/DashboardConfigurePage'
import GuidePage from './pages/GuidePage'
@ -271,7 +270,6 @@ function AppShell() {
</Route>
<Route path="/workflow-editor/:id" element={<WorkflowEditorPage/>}/>
<Route path="/subscription" element={<SubscriptionPage/>}/>
<Route path="/pilot/viz" element={<PilotVizPage />} />
<Route path="/app/dashboard-lab" element={<DashboardLabPage />} />
</Routes>
</main>

View File

@ -8,9 +8,9 @@ import {
BODY_CHART_DAYS_DEFAULT,
normalizeBodyChartDays,
} from '../../widgetSystem/bodyChartDays'
import PilotRuleCard from './PilotRuleCard'
import DashboardRuleCard from './DashboardRuleCard'
export default function PilotActivitySection({ refreshTick = 0, chartDays = BODY_CHART_DAYS_DEFAULT }) {
export default function ActivityOverviewWidget({ refreshTick = 0, chartDays = BODY_CHART_DAYS_DEFAULT }) {
const periodDays = normalizeBodyChartDays(chartDays)
const { activeProfile } = useProfile()
const globalQualityLevel = activeProfile?.quality_filter_level
@ -124,7 +124,7 @@ export default function PilotActivitySection({ refreshTick = 0, chartDays = BODY
</Link>
</p>
) : (
actRules.map((item, i) => <PilotRuleCard key={i} item={item} />)
actRules.map((item, i) => <DashboardRuleCard key={i} item={item} />)
)}
</div>
</div>

View File

@ -15,14 +15,14 @@ import dayjs from 'dayjs'
import { api } from '../../utils/api'
import { useProfile } from '../../context/ProfileContext'
import { getInterpretation } from '../../utils/interpret'
import { rollingAvg, fmtDate } from '../../pilot/pilotChartUtils'
import { rollingAvg, fmtDate } from '../../widgetSystem/dashboardChartUtils'
import {
BODY_CHART_DAYS_DEFAULT,
normalizeBodyChartDays,
} from '../../widgetSystem/bodyChartDays'
import PilotRuleCard from './PilotRuleCard'
import DashboardRuleCard from './DashboardRuleCard'
export default function PilotBodySection({ refreshTick = 0, chartDays = BODY_CHART_DAYS_DEFAULT }) {
export default function BodyOverviewWidget({ refreshTick = 0, chartDays = BODY_CHART_DAYS_DEFAULT }) {
const windowDays = normalizeBodyChartDays(chartDays)
const { activeProfile } = useProfile()
const [weights, setWeights] = useState([])
@ -221,7 +221,7 @@ export default function PilotBodySection({ refreshTick = 0, chartDays = BODY_CHA
Körperfett, Magermasse (FFMI), BMI gleiche Logik wie auf der Verlauf-Seite (Körper).
</p>
{rules.map((item, i) => (
<PilotRuleCard key={i} item={item} />
<DashboardRuleCard key={i} item={item} />
))}
</div>
)}

View File

@ -2,7 +2,7 @@ import { useState } from 'react'
import { ChevronDown, ChevronUp } from 'lucide-react'
import { getStatusColor, getStatusBg } from '../../utils/interpret'
export default function PilotRuleCard({ item }) {
export default function DashboardRuleCard({ item }) {
const [open, setOpen] = useState(false)
const color = getStatusColor(item.status)
return (

View File

@ -38,7 +38,7 @@ function buildAutoTileIds(refTiles, hasBf, hasKcal) {
* @param {{ refreshTick?: number, kpiConfig?: Record<string, unknown> }} props
* kpiConfig.tiles: geordnete Kachel-ids; fehlend = automatische Belegung (wie bisher).
*/
export default function PilotKpiBoard({ refreshTick = 0, kpiConfig }) {
export default function KpiBoardWidget({ refreshTick = 0, kpiConfig }) {
const manualOrder = useMemo(() => kpiTileOrderFromConfig(kpiConfig), [kpiConfig])
const { activeProfile } = useProfile()

View File

@ -9,7 +9,7 @@ import { api } from '../../utils/api'
* @param {{ onSaved?: () => void, captureConfig?: Record<string, unknown> }} props
* captureConfig: show_weight, show_resting_hr, show_hrv, show_vo2_max (false = ausblenden; fehlend = true)
*/
export default function PilotQuickCapture({ onSaved, captureConfig }) {
export default function QuickCaptureWidget({ onSaved, captureConfig }) {
const cfgRaw = captureConfig && typeof captureConfig === 'object' ? captureConfig : {}
const showWeight = cfgRaw.show_weight !== false
const showRestingHr = cfgRaw.show_resting_hr !== false
@ -200,7 +200,7 @@ export default function PilotQuickCapture({ onSaved, captureConfig }) {
{showRestingHr && (
<div>
<label
htmlFor="pqc-resting-hr"
htmlFor="qcw-resting-hr"
className="form-label"
style={{ display: 'block', marginBottom: 4, fontSize: 11, fontWeight: 600, color: 'var(--text2)' }}
>
@ -208,7 +208,7 @@ export default function PilotQuickCapture({ onSaved, captureConfig }) {
<span style={{ fontWeight: 400, color: 'var(--text3)' }}> (bpm)</span>
</label>
<input
id="pqc-resting-hr"
id="qcw-resting-hr"
type="number"
className="form-input"
style={{ width: '100%' }}
@ -221,7 +221,7 @@ export default function PilotQuickCapture({ onSaved, captureConfig }) {
{showHrv && (
<div>
<label
htmlFor="pqc-hrv"
htmlFor="qcw-hrv"
className="form-label"
style={{ display: 'block', marginBottom: 4, fontSize: 11, fontWeight: 600, color: 'var(--text2)' }}
>
@ -229,7 +229,7 @@ export default function PilotQuickCapture({ onSaved, captureConfig }) {
<span style={{ fontWeight: 400, color: 'var(--text3)' }}> (ms)</span>
</label>
<input
id="pqc-hrv"
id="qcw-hrv"
type="number"
className="form-input"
style={{ width: '100%' }}
@ -242,14 +242,14 @@ export default function PilotQuickCapture({ onSaved, captureConfig }) {
{showVo2 && (
<div>
<label
htmlFor="pqc-vo2"
htmlFor="qcw-vo2"
className="form-label"
style={{ display: 'block', marginBottom: 4, fontSize: 11, fontWeight: 600, color: 'var(--text2)' }}
>
VO₂max
</label>
<input
id="pqc-vo2"
id="qcw-vo2"
type="number"
className="form-input"
style={{ width: '100%' }}

View File

@ -4,7 +4,7 @@ import { useProfile } from '../../context/ProfileContext'
dayjs.locale('de')
export default function PilotWelcome() {
export default function WelcomeWidget() {
const { activeProfile } = useProfile()
return (
<div className="card section-gap" style={{ marginBottom: 16 }}>
@ -12,7 +12,7 @@ export default function PilotWelcome() {
Hallo, {activeProfile?.name || 'Nutzer'} 👋
</h2>
<p style={{ fontSize: 12, color: 'var(--text3)', margin: '6px 0 0' }}>
{dayjs().format('dddd, DD. MMMM YYYY')} · Pilot-Übersicht
{dayjs().format('dddd, DD. MMMM YYYY')} · Übersicht
</p>
</div>
)

View File

@ -5,7 +5,7 @@ import { api } from '../utils/api'
import { useProfile } from '../context/ProfileContext'
import TrialBanner from '../components/TrialBanner'
import EmailVerificationBanner from '../components/EmailVerificationBanner'
import { ensurePilotLabWidgetsRegistered } from '../widgetSystem/registerPilotLabWidgets'
import { ensureDashboardWidgetsRegistered } from '../widgetSystem/registerDashboardWidgets'
import { WidgetRenderer } from '../widgetSystem/dashboardWidgetRegistry'
function catalogMetaById(catalog) {
@ -27,7 +27,7 @@ export default function Dashboard() {
const requestRefresh = () => setRefreshTick((t) => t + 1)
useEffect(() => {
ensurePilotLabWidgetsRegistered()
ensureDashboardWidgetsRegistered()
}, [])
useEffect(() => {

View File

@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Link } from 'react-router-dom'
import { ChevronDown, ChevronUp, GripVertical, LayoutDashboard, Plus, Search, X } from 'lucide-react'
import { api, formatFastApiDetail } from '../utils/api'
import { ensurePilotLabWidgetsRegistered } from '../widgetSystem/registerPilotLabWidgets'
import { ensureDashboardWidgetsRegistered } from '../widgetSystem/registerDashboardWidgets'
import {
BODY_CHART_DAYS_DEFAULT,
BODY_CHART_DAYS_MAX,
@ -46,7 +46,7 @@ function catalogMetaById(catalog) {
* @param {{ adminMode?: boolean }} [props]
*/
export default function DashboardConfigurePage({ adminMode = false } = {}) {
ensurePilotLabWidgetsRegistered()
ensureDashboardWidgetsRegistered()
const [bundle, setBundle] = useState(null)
const [adminFromDatabase, setAdminFromDatabase] = useState(null)

View File

@ -3,7 +3,7 @@ import { ChevronDown, ChevronUp, LayoutGrid } from 'lucide-react'
import { Link } from 'react-router-dom'
import { api, formatFastApiDetail } from '../utils/api'
import { WidgetRenderer } from '../widgetSystem/dashboardWidgetRegistry'
import { ensurePilotLabWidgetsRegistered } from '../widgetSystem/registerPilotLabWidgets'
import { ensureDashboardWidgetsRegistered } from '../widgetSystem/registerDashboardWidgets'
import {
BODY_CHART_DAYS_DEFAULT,
BODY_CHART_DAYS_MAX,
@ -38,7 +38,7 @@ function catalogMetaById(catalog) {
}
export default function DashboardLabPage() {
ensurePilotLabWidgetsRegistered()
ensureDashboardWidgetsRegistered()
const [refreshTick, setRefreshTick] = useState(0)
const requestRefresh = () => setRefreshTick((t) => t + 1)
@ -198,13 +198,11 @@ export default function DashboardLabPage() {
<p style={{ fontSize: 13, color: 'var(--text2)', lineHeight: 1.6, marginTop: 8 }}>
Widget-System: Katalog, Registry, Renderer; optional pro Widget <code>config</code> (z.B.{' '}
<strong>Körper</strong> / <strong>Aktivität</strong>: Zeitraum 790 Tage; <strong>KPI</strong>: Kacheln
wählen &amp; sortieren). Layout pro Profil in der DB
getrennt vom Produktiv-Dashboard.
Vergleich:{' '}
<Link to="/pilot/viz" style={{ color: 'var(--accent)' }}>
Pilot-Übersicht (festes Standard-Layout)
wählen &amp; sortieren). Layout pro Profil in der DB dieselben Widgets wie auf der{' '}
<Link to="/" style={{ color: 'var(--accent)' }}>
Produkt-Übersicht
</Link>
.
, hier mit Editor und API-Fokus.
</p>
</div>

View File

@ -1,45 +0,0 @@
import { useState } from 'react'
import { FlaskConical } from 'lucide-react'
import { Link } from 'react-router-dom'
import { WidgetRenderer } from '../widgetSystem/dashboardWidgetRegistry'
import { ensurePilotLabWidgetsRegistered } from '../widgetSystem/registerPilotLabWidgets'
import { DEFAULT_LAB_LAYOUT } from '../widgetSystem/defaultLabLayout'
/**
* Pilot-Übersicht nach Product-Spec (festes Standard-Layout).
* Nutzt dasselbe Widget-Rendering wie /app/dashboard-lab.
*/
export default function PilotVizPage() {
ensurePilotLabWidgetsRegistered()
const [refreshTick, setRefreshTick] = useState(0)
const requestRefresh = () => setRefreshTick((t) => t + 1)
return (
<div style={{ paddingBottom: 96, textAlign: 'left', maxWidth: 920, margin: '0 auto' }}>
<div style={{ marginBottom: 20 }}>
<Link
to="/settings"
className="btn btn-secondary"
style={{ display: 'inline-flex', marginBottom: 12, textDecoration: 'none' }}
>
Einstellungen
</Link>
<h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<FlaskConical size={26} color="var(--accent)" />
Pilot: Übersicht
</h1>
<p style={{ fontSize: 13, color: 'var(--text2)', lineHeight: 1.6, marginTop: 8 }}>
Konfigurierbare Ziel-Übersicht (Test). Produktives Dashboard und Verlauf unverändert. Nach Speichern von
Gewicht oder Vitalwerten werden KPIs und Körperbereich neu geladen.
</p>
</div>
<WidgetRenderer
layout={DEFAULT_LAB_LAYOUT}
refreshTick={refreshTick}
requestRefresh={requestRefresh}
/>
</div>
)
}

View File

@ -463,20 +463,12 @@ export default function SettingsPage() {
style={{ borderStyle: 'dashed', borderColor: 'var(--border2)', background: 'var(--surface2)' }}
>
<div className="card-title" style={{ fontSize: 14 }}>
Pilot: Visualisierungs-Module
Entwickler: Dashboard-Layout (API)
</div>
<p style={{ fontSize: 12, color: 'var(--text2)', marginBottom: 12, lineHeight: 1.5 }}>
Ziel-Übersicht-Pilot: Schnelleingabe, KPIs, Körper-Chart, Aktivität. Die reguläre Übersicht konfigurierst du
unter <strong>Übersicht anpassen</strong> oben.
Experimentelles Layout-Lab mit Katalog und API (getrennt von der regulären Übersicht). Die produktive Kachelansicht
steuerst du über <strong>Übersicht anpassen</strong> oben.
</p>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<Link
to="/pilot/viz"
className="btn btn-secondary btn-full"
style={{ textAlign: 'center', textDecoration: 'none', boxSizing: 'border-box' }}
>
Pilot öffnen
</Link>
<Link
to="/app/dashboard-lab"
className="btn btn-secondary btn-full"
@ -491,10 +483,9 @@ export default function SettingsPage() {
}}
>
<LayoutGrid size={18} />
Dashboard-Lab (Layout API)
Dashboard-Lab öffnen
</Link>
</div>
</div>
{/* Auth actions */}
<div className="card section-gap">

View File

@ -1,15 +0,0 @@
/**
* Standard-Layout v1 (nur Pilot `/pilot/viz` ohne API).
* API-Nutzer: default_layout aus Backend (alle Katalog-IDs; aktiv = DEFAULT_LAB_WIDGET_IDS).
* Diese Datei: kompakte feste 5 Widgets für den Pilot nicht automatisch alle P1-Widgets.
*/
export const DEFAULT_LAB_LAYOUT = {
version: 1,
widgets: [
{ id: 'welcome', enabled: true },
{ id: 'quick_capture', enabled: true },
{ id: 'kpi_board', enabled: true },
{ id: 'body_overview', enabled: true },
{ id: 'activity_overview', enabled: true },
],
}

View File

@ -1,11 +1,11 @@
/**
* Pilot/Lab-Widgets registrieren. IDs müssen zu backend/widget_catalog.WIDGET_CATALOG passen.
* Dashboard-Widget-Registry: Katalog-IDs aus backend/widget_catalog.WIDGET_CATALOG React-Komponenten.
*/
import PilotWelcome from '../components/pilot/PilotWelcome'
import PilotQuickCapture from '../components/pilot/PilotQuickCapture'
import PilotKpiBoard from '../components/pilot/PilotKpiBoard'
import PilotBodySection from '../components/pilot/PilotBodySection'
import PilotActivitySection from '../components/pilot/PilotActivitySection'
import WelcomeWidget from '../components/dashboard-widgets-legacy/WelcomeWidget'
import QuickCaptureWidget from '../components/dashboard-widgets-legacy/QuickCaptureWidget'
import KpiBoardWidget from '../components/dashboard-widgets-legacy/KpiBoardWidget'
import BodyOverviewWidget from '../components/dashboard-widgets-legacy/BodyOverviewWidget'
import ActivityOverviewWidget from '../components/dashboard-widgets-legacy/ActivityOverviewWidget'
import DashboardGreetingWidget from '../components/dashboard-widgets/DashboardGreetingWidget'
import QuickWeightTodayWidget from '../components/dashboard-widgets/QuickWeightTodayWidget'
import BodyStatStripWidget from '../components/dashboard-widgets/BodyStatStripWidget'
@ -34,18 +34,18 @@ import { registerDashboardWidget } from './dashboardWidgetRegistry'
let _registered = false
export function ensurePilotLabWidgetsRegistered() {
export function ensureDashboardWidgetsRegistered() {
if (_registered) return
_registered = true
registerDashboardWidget({
id: 'welcome',
Component: PilotWelcome,
Component: WelcomeWidget,
mapProps: () => ({}),
})
registerDashboardWidget({
id: 'quick_capture',
Component: PilotQuickCapture,
Component: QuickCaptureWidget,
mapProps: (ctx) => ({
onSaved: ctx.requestRefresh,
captureConfig: ctx.layoutEntry?.config || {},
@ -53,7 +53,7 @@ export function ensurePilotLabWidgetsRegistered() {
})
registerDashboardWidget({
id: 'kpi_board',
Component: PilotKpiBoard,
Component: KpiBoardWidget,
mapProps: (ctx) => ({
refreshTick: ctx.refreshTick,
kpiConfig: ctx.layoutEntry?.config || {},
@ -61,7 +61,7 @@ export function ensurePilotLabWidgetsRegistered() {
})
registerDashboardWidget({
id: 'body_overview',
Component: PilotBodySection,
Component: BodyOverviewWidget,
mapProps: (ctx) => ({
refreshTick: ctx.refreshTick,
chartDays: normalizeBodyChartDays(ctx.layoutEntry?.config?.chart_days),
@ -77,7 +77,7 @@ export function ensurePilotLabWidgetsRegistered() {
})
registerDashboardWidget({
id: 'activity_overview',
Component: PilotActivitySection,
Component: ActivityOverviewWidget,
mapProps: (ctx) => ({
refreshTick: ctx.refreshTick,
chartDays: normalizeBodyChartDays(ctx.layoutEntry?.config?.chart_days),
@ -193,6 +193,6 @@ export function ensurePilotLabWidgetsRegistered() {
}
/** @internal Nur für Tests */
export function __resetPilotLabRegistrationForTests() {
export function __resetDashboardWidgetRegistrationForTests() {
_registered = false
}