feat: port full CRUD API routes and frontend pages from Immich Watcher
Backend API (38 routes): - providers: full CRUD + test connection + list collections + API key masking - trackers: full CRUD + trigger + history + test-periodic/memory - tracking-configs: full CRUD with Pydantic models, provider_type filter - template-configs: full CRUD + preview + preview-raw with two-pass validation - targets: full CRUD + test notification + config masking - telegram-bots: full CRUD + chat discovery + token endpoint - users: full admin CRUD + password reset + self-delete protection - status: dashboard endpoint with providers/trackers/targets/events counts Frontend pages updated: - Dashboard with animated stat cards and event timeline - Providers with proper components, delete confirm, snackbar - Trackers/targets/tracking-configs/template-configs/telegram-bots/users all use PageHeader, Card, Loading, MdiIcon with correct i18n keys Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""Status/dashboard API route."""
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlmodel import func, select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from ..auth.dependencies import get_current_user
|
||||
from ..database.engine import get_session
|
||||
from ..database.models import NotificationTarget, ServiceProvider, Tracker, EventLog, User
|
||||
|
||||
router = APIRouter(prefix="/api/status", tags=["status"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def get_status(
|
||||
user: User = Depends(get_current_user),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Get dashboard status data."""
|
||||
providers_count = (await session.exec(
|
||||
select(func.count()).select_from(ServiceProvider).where(ServiceProvider.user_id == user.id)
|
||||
)).one()
|
||||
|
||||
trackers_result = await session.exec(
|
||||
select(Tracker).where(Tracker.user_id == user.id)
|
||||
)
|
||||
trackers = trackers_result.all()
|
||||
active_count = sum(1 for t in trackers if t.enabled)
|
||||
|
||||
targets_count = (await session.exec(
|
||||
select(func.count()).select_from(NotificationTarget).where(NotificationTarget.user_id == user.id)
|
||||
)).one()
|
||||
|
||||
recent_events = await session.exec(
|
||||
select(EventLog)
|
||||
.join(Tracker, EventLog.tracker_id == Tracker.id)
|
||||
.where(Tracker.user_id == user.id)
|
||||
.order_by(EventLog.created_at.desc())
|
||||
.limit(10)
|
||||
)
|
||||
|
||||
return {
|
||||
"providers": providers_count,
|
||||
"trackers": {"total": len(trackers), "active": active_count},
|
||||
"targets": targets_count,
|
||||
"recent_events": [
|
||||
{
|
||||
"id": e.id,
|
||||
"event_type": e.event_type,
|
||||
"collection_name": e.collection_name,
|
||||
"created_at": e.created_at.isoformat(),
|
||||
}
|
||||
for e in recent_events.all()
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user