"""Dashboard routes — list available widgets from active plugins (Task 5.25).""" from __future__ import annotations import uuid from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.core.db import get_db from app.core.visibility import apply_visibility_filter from app.deps import require_permission from app.models.contact import Contact from app.plugins.registry import get_registry router = APIRouter(prefix="/api/v1/dashboard", tags=["dashboard"]) @router.get("/widgets") async def list_dashboard_widgets( db: AsyncSession = Depends(get_db), current_user: dict = Depends(require_permission("dashboard:read")), ): """List all available dashboard widgets from active plugins. Returns a flat list of widget definitions contributed by active plugins, sorted by their order field. Each widget includes the contributing plugin name. """ registry = get_registry() manifests = await registry.get_active_manifests(db) widgets: list[dict] = [] for manifest in manifests: for widget in manifest.get("dashboard_widgets", []): widget_copy = dict(widget) widget_copy["plugin_name"] = manifest["name"] widgets.append(widget_copy) # Sort by order field widgets.sort(key=lambda w: w.get("order", 100)) return {"items": widgets, "total": len(widgets)} @router.get("/counts") async def get_dashboard_counts( db: AsyncSession = Depends(get_db), current_user: dict = Depends(require_permission("dashboard:read")), ): """Get dashboard count statistics filtered by user visibility. Returns counts for contacts and companies that the current user is allowed to see based on ownership and sharing permissions. """ tenant_id = uuid.UUID(current_user["tenant_id"]) user_id = uuid.UUID(current_user["user_id"]) is_system_admin = current_user.get("is_system_admin", False) # Contact count with visibility filter contact_query = select(func.count(Contact.id)).where( Contact.tenant_id == tenant_id, Contact.deleted_at.is_(None), ) contact_query = await apply_visibility_filter( db, contact_query, "contact", Contact, user_id, tenant_id, is_system_admin ) contact_result = await db.execute(contact_query) contact_count = contact_result.scalar() or 0 # Company count (Contact.type == 'company') with visibility filter company_query = select(func.count(Contact.id)).where( Contact.tenant_id == tenant_id, Contact.deleted_at.is_(None), Contact.type == "company", ) company_query = await apply_visibility_filter( db, company_query, "contact", Contact, user_id, tenant_id, is_system_admin ) company_result = await db.execute(company_query) company_count = company_result.scalar() or 0 # Person count (Contact.type == 'person') with visibility filter person_query = select(func.count(Contact.id)).where( Contact.tenant_id == tenant_id, Contact.deleted_at.is_(None), Contact.type == "person", ) person_query = await apply_visibility_filter( db, person_query, "contact", Contact, user_id, tenant_id, is_system_admin ) person_result = await db.execute(person_query) person_count = person_result.scalar() or 0 return { "contacts": contact_count, "companies": company_count, "persons": person_count, "total": contact_count, }