Add dashboard summary tiles
Shows rider count, activities imported in the last 7 days, 7-day sync success rate, and how many riders currently need attention, right above the rider list where an admin looks first. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import and_, or_, select
|
||||
from sqlalchemy import and_, func, or_, select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.db.models import (
|
||||
Activity,
|
||||
ActivityStatus,
|
||||
HealthState,
|
||||
SchedulerSettings,
|
||||
SyncRun,
|
||||
SyncRunStatus,
|
||||
@@ -19,6 +20,15 @@ from app.db.models import (
|
||||
_SCHEDULER_SETTINGS_ID = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DashboardSummary:
|
||||
rider_total: int
|
||||
rider_enabled: int
|
||||
imported_recent: int
|
||||
success_rate_recent: float | None
|
||||
action_required_count: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserDashboardRow:
|
||||
id: int
|
||||
@@ -78,6 +88,39 @@ class UserRepository:
|
||||
))
|
||||
return rows
|
||||
|
||||
def dashboard_summary(self, *, since: datetime) -> DashboardSummary:
|
||||
rider_total = self.session.scalar(select(func.count()).select_from(SyncUser)) or 0
|
||||
rider_enabled = self.session.scalar(
|
||||
select(func.count()).select_from(SyncUser).where(SyncUser.enabled.is_(True))
|
||||
) or 0
|
||||
action_required_count = self.session.scalar(
|
||||
select(func.count()).select_from(SyncUser).where(SyncUser.health_state == HealthState.ACTION_REQUIRED)
|
||||
) or 0
|
||||
imported_recent = self.session.scalar(
|
||||
select(func.coalesce(func.sum(SyncRun.imported_count), 0)).where(SyncRun.started_at >= since)
|
||||
) or 0
|
||||
|
||||
finished_runs = list(
|
||||
self.session.scalars(
|
||||
select(SyncRun).where(SyncRun.started_at >= since, SyncRun.finished_at.is_not(None))
|
||||
)
|
||||
)
|
||||
if finished_runs:
|
||||
successful = sum(
|
||||
1 for run in finished_runs if run.status in (SyncRunStatus.SUCCESS, SyncRunStatus.PARTIAL)
|
||||
)
|
||||
success_rate_recent = (successful / len(finished_runs)) * 100
|
||||
else:
|
||||
success_rate_recent = None
|
||||
|
||||
return DashboardSummary(
|
||||
rider_total=rider_total,
|
||||
rider_enabled=rider_enabled,
|
||||
imported_recent=imported_recent,
|
||||
success_rate_recent=success_rate_recent,
|
||||
action_required_count=action_required_count,
|
||||
)
|
||||
|
||||
|
||||
class ActivityRepository:
|
||||
def __init__(self, session: Session) -> None:
|
||||
|
||||
Reference in New Issue
Block a user