"""Eisenhower Matrix: read-only 2x2 priority/urgency grid of open tasks.""" from fastapi import APIRouter, Request, Depends from fastapi.templating import Jinja2Templates from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import text from typing import Optional from core.database import get_db from core.base_repository import BaseRepository from core.sidebar import get_sidebar_data router = APIRouter(prefix="/eisenhower", tags=["eisenhower"]) templates = Jinja2Templates(directory="templates") @router.get("/") async def eisenhower_matrix( request: Request, domain_id: Optional[str] = None, project_id: Optional[str] = None, status: Optional[str] = None, context: Optional[str] = None, db: AsyncSession = Depends(get_db), ): sidebar = await get_sidebar_data(db) where_clauses = [ "t.is_deleted = false", "t.status IN ('open', 'in_progress', 'blocked')", ] params = {} if domain_id: where_clauses.append("t.domain_id = :domain_id") params["domain_id"] = domain_id if project_id: where_clauses.append("t.project_id = :project_id") params["project_id"] = project_id if status: where_clauses.append("t.status = :status") params["status"] = status if context: where_clauses.append("t.context = :context") params["context"] = context where_sql = " AND ".join(where_clauses) result = await db.execute(text(f""" SELECT t.id, t.title, t.priority, t.status, t.due_date, t.context, t.estimated_minutes, p.name as project_name, d.name as domain_name, d.color as domain_color FROM tasks t LEFT JOIN projects p ON t.project_id = p.id LEFT JOIN domains d ON t.domain_id = d.id WHERE {where_sql} ORDER BY t.priority, t.due_date NULLS LAST, t.title """), params) tasks = [dict(r._mapping) for r in result] # Classify into quadrants from datetime import date, timedelta today = date.today() urgent_cutoff = today + timedelta(days=7) quadrants = { "do_first": [], "schedule": [], "delegate": [], "eliminate": [], } for t in tasks: important = t["priority"] in (1, 2) urgent = ( t["due_date"] is not None and t["due_date"] <= urgent_cutoff ) if important and urgent: quadrants["do_first"].append(t) elif important and not urgent: quadrants["schedule"].append(t) elif not important and urgent: quadrants["delegate"].append(t) else: quadrants["eliminate"].append(t) counts = {k: len(v) for k, v in quadrants.items()} total = sum(counts.values()) # Filter options domains_repo = BaseRepository("domains", db) domains = await domains_repo.list() projects_repo = BaseRepository("projects", db) projects = await projects_repo.list() result = await db.execute(text( "SELECT value, label FROM context_types WHERE is_deleted = false ORDER BY sort_order" )) context_types = [dict(r._mapping) for r in result] return templates.TemplateResponse("eisenhower.html", { "request": request, "sidebar": sidebar, "quadrants": quadrants, "counts": counts, "total": total, "today": today, "domains": domains, "projects": projects, "context_types": context_types, "current_domain_id": domain_id or "", "current_project_id": project_id or "", "current_status": status or "", "current_context": context or "", "page_title": "Eisenhower Matrix", "active_nav": "eisenhower", })