Files
----/backend/app/routes/dashboard.py
smolkik-code 9b15f8b09c feat: CMDB full-stack app - FastAPI + PostgreSQL + React
- 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)
2026-06-25 13:01:40 +07:00

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,
}