From 50200c23ccaac0a3fe68660094992642a71b32d2 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 3 Mar 2026 15:06:58 +0000 Subject: [PATCH] feat: group daily focus items by project with "General" fallback Co-Authored-By: Claude Opus 4.6 --- routers/focus.py | 17 ++++++++-- templates/focus.html | 74 +++++++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/routers/focus.py b/routers/focus.py index 3d5f0e4..56545d0 100644 --- a/routers/focus.py +++ b/routers/focus.py @@ -37,7 +37,8 @@ async def focus_view( SELECT df.*, t.title as title, t.priority, t.status as task_status, t.project_id, t.due_date, t.estimated_minutes, - p.name as project_name, + 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, li.content as list_item_content, li.list_id as list_item_list_id, li.completed as list_item_completed, @@ -48,11 +49,23 @@ async def focus_view( LEFT JOIN domains d ON t.domain_id = d.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 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 + from collections import OrderedDict + _groups = 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()) + # --- Available tasks --- available_tasks = [] if source_type == "tasks": @@ -139,7 +152,7 @@ async def focus_view( return templates.TemplateResponse("focus.html", { "request": request, "sidebar": sidebar, - "items": items, + "items": items, "grouped_items": grouped_items, "available_tasks": available_tasks, "available_list_items": available_list_items, "focus_date": target_date, diff --git a/templates/focus.html b/templates/focus.html index 587ea27..e14b69c 100644 --- a/templates/focus.html +++ b/templates/focus.html @@ -12,45 +12,49 @@ {{ focus_date }} - + {% if items %} -
-{% for item in items %} -
- {% with reorder_url="/focus/reorder", item_id=item.id, extra_fields={"focus_date": focus_date|string} %} - {% include 'partials/reorder_arrows.html' %} - {% endwith %} -
-
- - -
-
- {% if item.task_id %} - - {% if item.title %} - {{ item.title }} - {% else %} - [Deleted] +{% for group in grouped_items %} +
+
+

{{ group.label }}

+
+ {% for item in group.rows %} +
+ {% with reorder_url="/focus/reorder", item_id=item.id, extra_fields={"focus_date": focus_date|string} %} + {% include 'partials/reorder_arrows.html' %} + {% endwith %} +
+
+ + +
+
+ {% if item.task_id %} + + {% if item.title %} + {{ item.title }} + {% else %} + [Deleted] + {% endif %} + {% if item.estimated_minutes %}~{{ item.estimated_minutes }}min{% endif %} + {% if item.due_date %}{{ item.due_date }}{% endif %} + {% elif item.list_item_id %} + + {% if item.list_item_content %} + {{ item.list_item_content }} + {% else %} + [Deleted] + {% endif %} + {% if item.list_name %}{{ item.list_name }}{% endif %} {% endif %} - {% if item.project_name %}{{ item.project_name }}{% endif %} - {% if item.estimated_minutes %}~{{ item.estimated_minutes }}min{% endif %} - {% if item.due_date %}{{ item.due_date }}{% endif %} - {% elif item.list_item_id %} - - {% if item.list_item_content %} - {{ item.list_item_content }} - {% else %} - [Deleted] - {% endif %} - {% if item.list_name %}{{ item.list_name }}{% endif %} - {% endif %} -
- -
+
+ +
+
+ {% endfor %}
{% endfor %} -
{% else %}
No focus items for this day
{% endif %}