feat(stats): optimize dashboard data loading with internal ui endpoints

This commit is contained in:
Alexander Kalinovsky
2026-04-01 19:05:57 +03:00
parent 19d659df6b
commit 9b9c7b5575
11 changed files with 552 additions and 140 deletions

View File

@@ -2,79 +2,23 @@ from __future__ import annotations
from pathlib import Path
from fastapi import APIRouter, Depends, Request
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from app.api.tasks import get_task_repository
from app.storage import JsonFileTaskRepository, StoredTask
router = APIRouter(tags=["stats"])
templates = Jinja2Templates(directory=str(Path(__file__).resolve().parents[2] / "templates"))
def get_task_status(task: StoredTask) -> str:
if task.done_at is not None:
return "done"
if task.started_at is not None:
return "in_progress"
return "backlog"
def format_dt(value: object) -> str:
if value is None:
return ""
return str(value)
def format_duration(task: StoredTask) -> str:
if task.started_at is None or task.done_at is None:
return ""
delta = task.done_at - task.started_at
total_seconds = int(delta.total_seconds())
hours, remainder = divmod(total_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{hours}h {minutes}m {seconds}s"
def serialize_task(task: StoredTask) -> dict[str, str]:
return {
"id": str(task.id),
"title": task.title,
"status": get_task_status(task),
"created_at": task.created_at.isoformat(),
"started_at": task.started_at.isoformat() if task.started_at is not None else "",
"done_at": task.done_at.isoformat() if task.done_at is not None else "",
"cycle_time": format_duration(task),
}
@router.get("/stats", response_class=HTMLResponse)
def stats_page(
request: Request,
repo: JsonFileTaskRepository = Depends(get_task_repository),
) -> HTMLResponse:
tasks = repo.list_tasks()
backlog_tasks = [serialize_task(task) for task in tasks if get_task_status(task) == "backlog"]
in_progress_tasks = [serialize_task(task) for task in tasks if get_task_status(task) == "in_progress"]
done_tasks = [serialize_task(task) for task in tasks if get_task_status(task) == "done"]
selected_task = None
if tasks:
selected_task = serialize_task(tasks[0])
return templates.TemplateResponse(
request=request,
name="stats.html",
context={
"selected_task": selected_task,
"backlog_tasks": backlog_tasks,
"in_progress_tasks": in_progress_tasks,
"done_tasks": done_tasks,
"selected_task": None,
},
)