feat: update versioning and add activity last updated endpoint
- Bumped application version to 0.9r and updated build date to 2026-04-20. - Added a new endpoint `/activity-last-updated` to retrieve the last activity date for a user, optimizing data retrieval for activity history. - Updated the frontend to utilize the new endpoint, enhancing the ActivitySection with the last activity date display. - Refactored the History component to streamline data loading and improve user experience with activity insights.
This commit is contained in:
parent
5d67a77a12
commit
ba2bd3a4a2
|
|
@ -59,6 +59,15 @@ def _last_activity_date(profile_id: str) -> Optional[str]:
|
|||
return _iso(row["d"])
|
||||
|
||||
|
||||
def get_activity_last_updated_iso(profile_id: str) -> Optional[str]:
|
||||
"""
|
||||
Leichtgewicht: letztes activity_log.date — identisch zu ``last_updated`` im Fitness-Viz-Bundle.
|
||||
|
||||
Für History-Header o. Ä. ohne vollständige Aktivitätsliste (Phase A, Issue-53-Pfad).
|
||||
"""
|
||||
return _last_activity_date(profile_id)
|
||||
|
||||
|
||||
def get_fitness_dashboard_viz_bundle(profile_id: str, days: int) -> Dict[str, Any]:
|
||||
"""
|
||||
Bundle für Fitness-Übersicht: KPI-Kacheln + eingebettete Chart-Payloads (Chart.js-Format).
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ from data_layer.body_metrics import (
|
|||
)
|
||||
from data_layer.body_viz import get_body_history_viz_bundle
|
||||
from data_layer.nutrition_viz import get_nutrition_history_viz_bundle
|
||||
from data_layer.fitness_viz import get_fitness_dashboard_viz_bundle
|
||||
from data_layer.fitness_viz import get_fitness_dashboard_viz_bundle, get_activity_last_updated_iso
|
||||
from data_layer.recovery_viz import get_recovery_dashboard_viz_bundle
|
||||
from data_layer.history_overview_viz import get_history_overview_viz_bundle
|
||||
from data_layer.recovery_chart_payloads import (
|
||||
|
|
@ -319,6 +319,17 @@ def get_fitness_dashboard_viz(
|
|||
return serialize_dates(bundle)
|
||||
|
||||
|
||||
@router.get("/activity-last-updated")
|
||||
def get_activity_last_updated(session: dict = Depends(require_auth)) -> Dict:
|
||||
"""
|
||||
Minimal-Metadatum: letztes Trainingsdatum — gleiche Quelle wie ``last_updated`` im Fitness-Viz-Bundle.
|
||||
|
||||
Vermeidet Massen-Ladevorgänge (z. B. listActivity) nur für Datumsanzeige im Verlauf.
|
||||
"""
|
||||
pid = session["profile_id"]
|
||||
return {"last_activity_date": get_activity_last_updated_iso(pid)}
|
||||
|
||||
|
||||
@router.get("/recovery-dashboard-viz")
|
||||
def get_recovery_dashboard_viz(
|
||||
days: int = Query(
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ Semantic Versioning: MAJOR.MINOR.PATCH
|
|||
- PATCH: Bugfix, kleine Änderung, Refactor
|
||||
"""
|
||||
|
||||
APP_VERSION = "0.9q"
|
||||
BUILD_DATE = "2026-04-11"
|
||||
APP_VERSION = "0.9r"
|
||||
BUILD_DATE = "2026-04-20"
|
||||
DB_SCHEMA_VERSION = "20260409c" # 048/049 vitals_baseline.source csv + SAVEPOINT Import
|
||||
|
||||
MODULE_VERSIONS = {
|
||||
|
|
@ -36,6 +36,14 @@ MODULE_VERSIONS = {
|
|||
}
|
||||
|
||||
CHANGELOG = [
|
||||
{
|
||||
"version": "0.9r",
|
||||
"date": "2026-04-20",
|
||||
"changes": [
|
||||
"History Phase A: GET /api/charts/activity-last-updated (data_layer fitness_viz, gleiche Quelle wie last_updated im Fitness-Bundle)",
|
||||
"History: entfernt toten Initial-Load listWeight/listCaliper/listCirc/listNutrition/listActivity(25k); Profil/Insights/Prompts + Activity-Datum",
|
||||
],
|
||||
},
|
||||
{
|
||||
"version": "0.9q",
|
||||
"date": "2026-04-11",
|
||||
|
|
|
|||
|
|
@ -1196,14 +1196,12 @@ function NutritionSection({ profile, insights, onRequest, loadingSlug, filterAct
|
|||
}
|
||||
|
||||
// ── Activity Section — nur Layer-2b-Bundle (+ KI-Insights), keine parallelen Client-Charts ─
|
||||
function ActivitySection({ activities, insights, onRequest, loadingSlug, filterActiveSlugs, globalQualityLevel }) {
|
||||
function ActivitySection({ activityLastDate, insights, onRequest, loadingSlug, filterActiveSlugs, globalQualityLevel }) {
|
||||
const [period, setPeriod] = useState(30)
|
||||
const actList = activities || []
|
||||
const hasList = actList.length > 0
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SectionHeader title="🏋️ Fitness" to="/activity" toLabel="Alle Einträge" lastUpdated={actList[0]?.date}/>
|
||||
<SectionHeader title="🏋️ Fitness" to="/activity" toLabel="Alle Einträge" lastUpdated={activityLastDate || undefined}/>
|
||||
<PeriodSelector value={period} onChange={setPeriod}/>
|
||||
<p style={{ fontSize: 11, color: 'var(--text3)', lineHeight: 1.45, marginBottom: 10 }}>
|
||||
Fitness und Erholung aus den Data-Layer-Bundles (Issue 53). Zeitraum-Buttons steuern beide Bereiche gleichzeitig.
|
||||
|
|
@ -1215,7 +1213,7 @@ function ActivitySection({ activities, insights, onRequest, loadingSlug, filterA
|
|||
</div>
|
||||
<RecoveryDashboardOverview period={period} onPeriodChange={setPeriod} hidePeriodSelector />
|
||||
|
||||
{hasList && globalQualityLevel && globalQualityLevel !== 'all' && (
|
||||
{activityLastDate && globalQualityLevel && globalQualityLevel !== 'all' && (
|
||||
<div style={{
|
||||
marginTop: 12,
|
||||
marginBottom: 12, padding:'8px 12px', borderRadius:8,
|
||||
|
|
@ -1735,11 +1733,7 @@ export default function History() {
|
|||
const { activeProfile } = useProfile() // Issue #31: Get global quality filter
|
||||
const location = useLocation?.() || {}
|
||||
const [tab, setTab] = useState((location.state?.tab) || 'overview')
|
||||
const [weights, setWeights] = useState([])
|
||||
const [calipers, setCalipers] = useState([])
|
||||
const [circs, setCircs] = useState([])
|
||||
const [nutrition, setNutrition] = useState([])
|
||||
const [activities, setActivities] = useState([])
|
||||
const [activityLastDate, setActivityLastDate] = useState(null)
|
||||
const [insights, setInsights] = useState([])
|
||||
const [prompts, setPrompts] = useState([])
|
||||
const [profile, setProfile] = useState(null)
|
||||
|
|
@ -1747,15 +1741,15 @@ export default function History() {
|
|||
const [loadingSlug,setLoadingSlug]= useState(null)
|
||||
|
||||
const loadAll = () => Promise.all([
|
||||
api.listWeight(365), api.listCaliper(), api.listCirc(),
|
||||
api.listNutrition(90), api.listActivity(25_000),
|
||||
api.latestInsights(), api.getProfile(),
|
||||
api.latestInsights(),
|
||||
api.getProfile(),
|
||||
api.listPrompts(),
|
||||
]).then(([w,ca,ci,n,a,ins,p,pr])=>{
|
||||
setWeights(w); setCalipers(ca); setCircs(ci)
|
||||
setNutrition(n); setActivities(a)
|
||||
setInsights(Array.isArray(ins)?ins:[]); setProfile(p)
|
||||
api.getActivityLastUpdated(),
|
||||
]).then(([ins, p, pr, actMeta]) => {
|
||||
setInsights(Array.isArray(ins) ? ins : [])
|
||||
setProfile(p)
|
||||
setPrompts(Array.isArray(pr) ? pr : [])
|
||||
setActivityLastDate(actMeta?.last_activity_date ?? null)
|
||||
setLoading(false)
|
||||
})
|
||||
|
||||
|
|
@ -1820,7 +1814,7 @@ export default function History() {
|
|||
{tab==='overview' && <HistoryOverviewSection {...sp}/>}
|
||||
{tab==='body' && <BodySection profile={profile} {...sp}/>}
|
||||
{tab==='nutrition' && <NutritionSection profile={profile} {...sp}/>}
|
||||
{tab==='activity' && <ActivitySection activities={activities} globalQualityLevel={activeProfile?.quality_filter_level} {...sp}/>}
|
||||
{tab==='activity' && <ActivitySection activityLastDate={activityLastDate} globalQualityLevel={activeProfile?.quality_filter_level} {...sp}/>}
|
||||
{tab==='photos' && <PhotoGrid/>}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -644,6 +644,8 @@ export const api = {
|
|||
/** Layer 2b: Erholung — KPI, Insights, Charts R1–R5 (recovery_metrics) */
|
||||
getRecoveryDashboardViz: (days=28) => req(`/charts/recovery-dashboard-viz?days=${days}`),
|
||||
getHistoryOverviewViz: (days=30) => req(`/charts/history-overview-viz?days=${days}`),
|
||||
/** Minimal: letztes activity_log.date — wie fitness-dashboard-viz.last_updated */
|
||||
getActivityLastUpdated: () => req('/charts/activity-last-updated'),
|
||||
getWeightEnergyCorrelationChart: (maxLag=14) => req(`/charts/weight-energy-correlation?max_lag=${maxLag}`),
|
||||
getLbmProteinCorrelationChart: (maxLag=14) => req(`/charts/lbm-protein-correlation?max_lag=${maxLag}`),
|
||||
getLoadVitalsCorrelationChart: (maxLag=14) => req(`/charts/load-vitals-correlation?max_lag=${maxLag}`),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user