feat: eisenhower matrix view

This commit is contained in:
2026-03-01 22:22:19 +00:00
parent d792f89fe6
commit 8499c99721
5 changed files with 358 additions and 0 deletions

76
routers/eisenhower.py Normal file
View File

@@ -0,0 +1,76 @@
"""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 core.database import get_db
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,
db: AsyncSession = Depends(get_db),
):
sidebar = await get_sidebar_data(db)
result = await db.execute(text("""
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 t.is_deleted = false
AND t.status IN ('open', 'in_progress', 'blocked')
ORDER BY t.priority, t.due_date NULLS LAST, t.title
"""))
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": [], # Urgent + Important
"schedule": [], # Not Urgent + Important
"delegate": [], # Urgent + Not Important
"eliminate": [], # Not Urgent + Not Important
}
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())
return templates.TemplateResponse("eisenhower.html", {
"request": request,
"sidebar": sidebar,
"quadrants": quadrants,
"counts": counts,
"total": total,
"today": today,
"page_title": "Eisenhower Matrix",
"active_nav": "eisenhower",
})