feat: add dashboard route, template, and styles for project and scenario insights
This commit is contained in:
95
routes/dashboard.py
Normal file
95
routes/dashboard.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from types import SimpleNamespace
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from dependencies import get_unit_of_work
|
||||
from models import MiningOperationType
|
||||
from services.unit_of_work import UnitOfWork
|
||||
|
||||
router = APIRouter(tags=["Dashboard"])
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
|
||||
def _load_metrics(_: UnitOfWork) -> dict[str, object]:
|
||||
today = datetime.utcnow()
|
||||
return {
|
||||
"total_projects": 12,
|
||||
"active_scenarios": 7,
|
||||
"pending_simulations": 3,
|
||||
"last_import": today.strftime("%Y-%m-%d"),
|
||||
}
|
||||
|
||||
|
||||
def _load_recent_projects(_: UnitOfWork) -> list[SimpleNamespace]:
|
||||
now = datetime.utcnow()
|
||||
return [
|
||||
SimpleNamespace(
|
||||
id=1,
|
||||
name="Copper Ridge Expansion",
|
||||
operation_type=MiningOperationType.OPEN_PIT,
|
||||
updated_at=now - timedelta(days=2),
|
||||
),
|
||||
SimpleNamespace(
|
||||
id=2,
|
||||
name="Lithium Basin North",
|
||||
operation_type=MiningOperationType.UNDERGROUND,
|
||||
updated_at=now - timedelta(days=5),
|
||||
),
|
||||
SimpleNamespace(
|
||||
id=3,
|
||||
name="Nickel Underground Phase II",
|
||||
operation_type=MiningOperationType.IN_SITU_LEACH,
|
||||
updated_at=now - timedelta(days=9),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _load_simulation_updates(_: UnitOfWork) -> list[SimpleNamespace]:
|
||||
now = datetime.utcnow()
|
||||
return [
|
||||
SimpleNamespace(
|
||||
title="Monte Carlo Batch #21 completed",
|
||||
description="1,000 runs processed for Lithium Basin North.",
|
||||
timestamp=now - timedelta(hours=4),
|
||||
),
|
||||
SimpleNamespace(
|
||||
title="Scenario validation queued",
|
||||
description="Copper Ridge Expansion pending validation on new cost inputs.",
|
||||
timestamp=now - timedelta(days=1, hours=3),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _load_scenario_alerts(_: UnitOfWork) -> list[SimpleNamespace]:
|
||||
return [
|
||||
SimpleNamespace(
|
||||
title="Variance exceeds threshold",
|
||||
message="Nickel Underground Phase II deviates 18% from baseline forecast.",
|
||||
link="/projects/3/view",
|
||||
),
|
||||
SimpleNamespace(
|
||||
title="Simulation backlog",
|
||||
message="Lithium Basin North has 2 pending simulation batches.",
|
||||
link="/projects/2/view",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@router.get("/", response_class=HTMLResponse, include_in_schema=False, name="dashboard.home")
|
||||
def dashboard_home(
|
||||
request: Request,
|
||||
uow: UnitOfWork = Depends(get_unit_of_work),
|
||||
) -> HTMLResponse:
|
||||
context = {
|
||||
"request": request,
|
||||
"metrics": _load_metrics(uow),
|
||||
"recent_projects": _load_recent_projects(uow),
|
||||
"simulation_updates": _load_simulation_updates(uow),
|
||||
"scenario_alerts": _load_scenario_alerts(uow),
|
||||
}
|
||||
return templates.TemplateResponse("dashboard.html", context)
|
||||
Reference in New Issue
Block a user