shinkan-jinkendo/backend/routers/dashboard.py
Lars b06d026dd0
All checks were successful
Deploy Development / deploy (push) Successful in 38s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 57s
chore(version): update version and changelog for release 0.8.118
- Bumped APP_VERSION to 0.8.118 and updated DB_SCHEMA_VERSION to 20260514062.
- Enhanced the dashboard API with a new endpoint that consolidates training home data, allowing for a single request to retrieve upcoming training sessions, planned sessions with notes, and review pending items.
- Updated the frontend Dashboard component to utilize the new API structure, improving data loading efficiency and user experience.
- Added migration details and changelog entries to reflect the latest changes and improvements.
2026-05-14 08:53:09 +02:00

104 lines
3.0 KiB
Python

"""
Dashboard: zusammengefasste Kennzahlen (ein Roundtrip statt mehrerer Listen).
"""
from __future__ import annotations
from datetime import date
from typing import Any, Dict, List
from fastapi import APIRouter, Depends
from tenant_context import TenantContext, get_tenant_context
from routers.exercises import list_exercises_like_get
from routers.training_planning import list_training_units
router = APIRouter(prefix="/api", tags=["dashboard"])
def _slice_training_home_notes(planned_pool: List[Dict[str, Any]], max_notes: int = 5) -> List[Dict[str, Any]]:
out = []
for u in planned_pool:
tn = (u.get("trainer_notes") or "").strip()
n = (u.get("notes") or "").strip()
if tn or n:
out.append(u)
if len(out) >= max_notes:
break
return out
@router.get("/dashboard/kpis")
def get_dashboard_kpis(tenant: TenantContext = Depends(get_tenant_context)):
"""
Kurzüberblick: Übungs-KPIs + YTD-Einheiten + Trainings-Home (nächste Termine, Vermerke, offene Rückschau)
in einem Roundtrip — gleiche Filter wie zuvor im Dashboard (mehrere Client-Calls).
"""
year = date.today().year
year_start = f"{year}-01-01"
year_end = f"{year}-12-31"
today = date.today().isoformat()
draft_list = list_exercises_like_get(
tenant, created_by_me=True, status="draft", limit=100
)
mine_list = list_exercises_like_get(
tenant, created_by_me=True, status=None, limit=100
)
ytd_completed = list_training_units(
group_id=None,
club_id=None,
start_date=year_start,
end_date=year_end,
status="completed",
assigned_to_me=True,
debrief_pending=False,
sort="desc",
limit=250,
tenant=tenant,
)
planned_pool = list_training_units(
group_id=None,
club_id=None,
start_date=today,
end_date=None,
status="planned",
assigned_to_me=True,
debrief_pending=False,
sort="asc",
limit=40,
tenant=tenant,
)
review_pending = list_training_units(
group_id=None,
club_id=None,
start_date=None,
end_date=None,
status=None,
assigned_to_me=True,
debrief_pending=True,
sort="desc",
limit=8,
tenant=tenant,
)
draft_preview = [
{"id": int(ex["id"]), "title": ex.get("title") or f"Übung #{ex['id']}"}
for ex in draft_list[:8]
]
return {
"year": year,
"draft_count": len(draft_list),
"draft_capped": len(draft_list) >= 100,
"draft_preview": draft_preview,
"mine_count": len(mine_list),
"mine_capped": len(mine_list) >= 100,
"ytd_completed_count": len(ytd_completed),
"ytd_capped": len(ytd_completed) >= 250,
"training_home": {
"upcoming": planned_pool[:8],
"planned_with_notes": _slice_training_home_notes(planned_pool),
"review_pending": review_pending,
},
}