- PostgreSQL schema: 14 tables, JSONB attributes, audit triggers, soft delete - FastAPI backend: CRUD, search/filter, relationship graph, bulk import, JWT RBAC - React frontend: CI table, detail card, force-graph, dashboard - Seed data: homelab scenario (Proxmox, Mikrotik, VMs, services) - Docker Compose + Kubernetes manifests - 20 backend tests (pytest + httpx)
52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
from fastapi import APIRouter, Depends
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, func
|
|
from app.database import get_db
|
|
from app.models.models import ConfigurationItem, CIRelationship, Location, User, CIClass, CIType
|
|
from app.middleware.auth import get_current_user
|
|
|
|
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
|
|
|
|
|
|
@router.get("/stats")
|
|
async def get_stats(db: AsyncSession = Depends(get_db), _user: User = Depends(get_current_user)):
|
|
total = (await db.execute(
|
|
select(func.count()).select_from(ConfigurationItem.__table__).where(
|
|
ConfigurationItem.deleted_at.is_(None)
|
|
)
|
|
)).scalar()
|
|
|
|
by_status = (await db.execute(
|
|
select(ConfigurationItem.status, func.count())
|
|
.where(ConfigurationItem.deleted_at.is_(None))
|
|
.group_by(ConfigurationItem.status)
|
|
)).all()
|
|
|
|
by_class = (await db.execute(
|
|
select(CIClass.name, func.count(ConfigurationItem.id))
|
|
.join(CIType, CIType.class_id == CIClass.id)
|
|
.join(ConfigurationItem, ConfigurationItem.ci_type_id == CIType.id)
|
|
.where(ConfigurationItem.deleted_at.is_(None))
|
|
.group_by(CIClass.name)
|
|
)).all()
|
|
|
|
total_relationships = (await db.execute(
|
|
select(func.count()).select_from(CIRelationship.__table__).where(
|
|
CIRelationship.deleted_at.is_(None)
|
|
)
|
|
)).scalar()
|
|
|
|
total_locations = (await db.execute(
|
|
select(func.count()).select_from(Location.__table__).where(
|
|
Location.deleted_at.is_(None)
|
|
)
|
|
)).scalar()
|
|
|
|
return {
|
|
"total_cis": total,
|
|
"by_status": {s: c for s, c in by_status},
|
|
"by_class": {n: c for n, c in by_class},
|
|
"total_relationships": total_relationships,
|
|
"total_locations": total_locations,
|
|
}
|