feat: gear registry — manage bikes/shoes per athlete, set per activity

- New /api/gear CRUD endpoints (gear.json per user)
- Gear tab in AthleteView (owner-only): add, edit, retire items
- EditDrawer gear field becomes a dropdown when registry has items
- Strava API sync now resolves gear_id → name, adds to registry automatically
- Strava ZIP import reads Gear column from activities.csv
- POST /api/strava/import-gear for one-time backfill from stored originals
This commit is contained in:
Davide Scaini
2026-05-24 12:33:41 +02:00
parent aca9f79b46
commit e553e08663
9 changed files with 576 additions and 10 deletions
+10
View File
@@ -150,6 +150,15 @@ def fetch_streams(access_token: str, activity_id: int) -> dict:
return result if isinstance(result, dict) else {}
def fetch_gear(access_token: str, gear_id: str) -> dict:
"""Fetch gear details for a single gear item. Returns {} on error."""
try:
result = _api_get(f"{_API_BASE}/gear/{gear_id}", access_token)
return result if isinstance(result, dict) else {}
except StravaError:
return {}
# ── Model conversion ───────────────────────────────────────────────────────────
def strava_meta_to_partial(meta: dict) -> ParsedActivity:
@@ -215,4 +224,5 @@ def strava_to_parsed(meta: dict, streams: dict) -> ParsedActivity:
description=meta.get("description") or None,
strava_id=str(meta["id"]),
privacy="unlisted" if is_private else "public",
gear=meta.get("_gear_name") or None,
)