feat: domain > area > project hierarchy for daily focus with compact padding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,11 @@ async def focus_view(
|
||||
t.project_id, t.due_date, t.estimated_minutes,
|
||||
COALESCE(p.name, lp.name) as project_name,
|
||||
COALESCE(t.project_id, l.project_id) as effective_project_id,
|
||||
d.name as domain_name, d.color as domain_color,
|
||||
COALESCE(d.name, ld.name) as domain_name,
|
||||
COALESCE(d.color, ld.color) as domain_color,
|
||||
COALESCE(d.id, ld.id) as effective_domain_id,
|
||||
COALESCE(a.name, la.name) as area_name,
|
||||
COALESCE(a.id, la.id) as effective_area_id,
|
||||
li.content as list_item_content, li.list_id as list_item_list_id,
|
||||
li.completed as list_item_completed,
|
||||
l.name as list_name
|
||||
@@ -47,24 +51,50 @@ async def focus_view(
|
||||
LEFT JOIN tasks t ON df.task_id = t.id
|
||||
LEFT JOIN projects p ON t.project_id = p.id
|
||||
LEFT JOIN domains d ON t.domain_id = d.id
|
||||
LEFT JOIN areas a ON t.area_id = a.id
|
||||
LEFT JOIN list_items li ON df.list_item_id = li.id
|
||||
LEFT JOIN lists l ON li.list_id = l.id
|
||||
LEFT JOIN projects lp ON l.project_id = lp.id
|
||||
LEFT JOIN domains ld ON l.domain_id = ld.id
|
||||
LEFT JOIN areas la ON l.area_id = la.id
|
||||
WHERE df.focus_date = :target_date AND df.is_deleted = false
|
||||
ORDER BY df.sort_order, df.created_at
|
||||
"""), {"target_date": target_date})
|
||||
items = [dict(r._mapping) for r in result]
|
||||
|
||||
# Group items by project for template rendering
|
||||
# Build Domain > Area > Project hierarchy
|
||||
from collections import OrderedDict
|
||||
_groups = OrderedDict()
|
||||
domain_map = OrderedDict()
|
||||
for item in items:
|
||||
key = item.get("effective_project_id") or "__general__"
|
||||
label = item.get("project_name") or "General"
|
||||
if key not in _groups:
|
||||
_groups[key] = {"label": label, "rows": []}
|
||||
_groups[key]["rows"].append(item)
|
||||
grouped_items = list(_groups.values())
|
||||
dk = item.get("effective_domain_id") or "__none__"
|
||||
dl = item.get("domain_name") or "General"
|
||||
dc = item.get("domain_color") or ""
|
||||
if dk not in domain_map:
|
||||
domain_map[dk] = {"label": dl, "color": dc, "areas": OrderedDict()}
|
||||
|
||||
ak = item.get("effective_area_id") or "__none__"
|
||||
al = item.get("area_name") or ""
|
||||
area_map = domain_map[dk]["areas"]
|
||||
if ak not in area_map:
|
||||
area_map[ak] = {"label": al, "projects": OrderedDict()}
|
||||
|
||||
pk = item.get("effective_project_id") or "__none__"
|
||||
pl = item.get("project_name") or ""
|
||||
proj_map = area_map[ak]["projects"]
|
||||
if pk not in proj_map:
|
||||
proj_map[pk] = {"label": pl, "rows": []}
|
||||
proj_map[pk]["rows"].append(item)
|
||||
|
||||
# Convert to nested lists for Jinja
|
||||
hierarchy = []
|
||||
for dk, dv in domain_map.items():
|
||||
domain_group = {"label": dv["label"], "color": dv["color"], "areas": []}
|
||||
for ak, av in dv["areas"].items():
|
||||
area_group = {"label": av["label"], "projects": []}
|
||||
for pk, pv in av["projects"].items():
|
||||
area_group["projects"].append({"label": pv["label"], "rows": pv["rows"]})
|
||||
domain_group["areas"].append(area_group)
|
||||
hierarchy.append(domain_group)
|
||||
|
||||
# --- Available tasks ---
|
||||
available_tasks = []
|
||||
@@ -152,7 +182,7 @@ async def focus_view(
|
||||
|
||||
return templates.TemplateResponse("focus.html", {
|
||||
"request": request, "sidebar": sidebar,
|
||||
"items": items, "grouped_items": grouped_items,
|
||||
"items": items, "hierarchy": hierarchy,
|
||||
"available_tasks": available_tasks,
|
||||
"available_list_items": available_list_items,
|
||||
"focus_date": target_date,
|
||||
|
||||
Reference in New Issue
Block a user