diff --git a/backend/routers/project_locations.py b/backend/routers/project_locations.py index 8c89793..83bd19b 100644 --- a/backend/routers/project_locations.py +++ b/backend/routers/project_locations.py @@ -154,6 +154,24 @@ async def get_project_locations( # Order by operator-set sort_order, then name as a stable tie-breaker. locations = query.order_by(MonitoringLocation.sort_order, MonitoringLocation.name).all() + # For vibration locations, fan out event counts via SFM concurrently + # so the card layout can show "{N} events" instead of "Sessions: 0" + # (sessions don't really exist for the watcher-forward pipeline). + # Sound locations skip this and keep showing session counts. + event_counts: dict[str, int] = {} + vibration_locations = [l for l in locations if l.location_type == "vibration"] + if vibration_locations: + import asyncio + from backend.services.sfm_events import events_for_location + results = await asyncio.gather( + *(events_for_location(db, l.id, limit=1) for l in vibration_locations), + return_exceptions=True, + ) + for loc, res in zip(vibration_locations, results): + if isinstance(res, Exception): + continue # leave event_counts[loc.id] unset → template falls back + event_counts[loc.id] = (res.get("stats") or {}).get("event_count", 0) or 0 + # Enrich with assignment info, splitting active vs removed. active_data: list = [] removed_data: list = [] @@ -184,6 +202,8 @@ async def get_project_locations( "assigned_unit": assigned_unit, "session_count": session_count, } + if location.id in event_counts: + item["event_count"] = event_counts[location.id] if location.removed_at is None: active_data.append(item) else: