feat: group daily focus items by project with "General" fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 15:06:58 +00:00
parent 0be6566045
commit 50200c23cc
2 changed files with 54 additions and 37 deletions

View File

@@ -37,7 +37,8 @@ async def focus_view(
SELECT df.*, SELECT df.*,
t.title as title, t.priority, t.status as task_status, t.title as title, t.priority, t.status as task_status,
t.project_id, t.due_date, t.estimated_minutes, 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, 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.content as list_item_content, li.list_id as list_item_list_id,
li.completed as list_item_completed, 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 domains d ON t.domain_id = d.id
LEFT JOIN list_items li ON df.list_item_id = li.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 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 WHERE df.focus_date = :target_date AND df.is_deleted = false
ORDER BY df.sort_order, df.created_at ORDER BY df.sort_order, df.created_at
"""), {"target_date": target_date}) """), {"target_date": target_date})
items = [dict(r._mapping) for r in result] 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 ---
available_tasks = [] available_tasks = []
if source_type == "tasks": if source_type == "tasks":
@@ -139,7 +152,7 @@ async def focus_view(
return templates.TemplateResponse("focus.html", { return templates.TemplateResponse("focus.html", {
"request": request, "sidebar": sidebar, "request": request, "sidebar": sidebar,
"items": items, "items": items, "grouped_items": grouped_items,
"available_tasks": available_tasks, "available_tasks": available_tasks,
"available_list_items": available_list_items, "available_list_items": available_list_items,
"focus_date": target_date, "focus_date": target_date,

View File

@@ -12,45 +12,49 @@
<span class="text-sm" style="font-weight:600">{{ focus_date }}</span> <span class="text-sm" style="font-weight:600">{{ focus_date }}</span>
</div> </div>
<!-- Focus items --> <!-- Focus items grouped by project -->
{% if items %} {% if items %}
<div class="card"> {% for group in grouped_items %}
{% for item in items %} <div class="card mb-3">
<div class="focus-item {{ 'completed' if item.completed }}"> <div class="card-header" style="padding:6px 12px;">
{% with reorder_url="/focus/reorder", item_id=item.id, extra_fields={"focus_date": focus_date|string} %} <h3 class="card-title" style="font-size:0.85rem;margin:0;">{{ group.label }}</h3>
{% include 'partials/reorder_arrows.html' %} </div>
{% endwith %} {% for item in group.rows %}
<form action="/focus/{{ item.id }}/toggle" method="post" style="display:inline"> <div class="focus-item {{ 'completed' if item.completed }}">
<div class="row-check"> {% with reorder_url="/focus/reorder", item_id=item.id, extra_fields={"focus_date": focus_date|string} %}
<input type="checkbox" id="f-{{ item.id }}" {{ 'checked' if item.completed }} onchange="this.form.submit()"> {% include 'partials/reorder_arrows.html' %}
<label for="f-{{ item.id }}"></label> {% endwith %}
</div> <form action="/focus/{{ item.id }}/toggle" method="post" style="display:inline">
</form> <div class="row-check">
{% if item.task_id %} <input type="checkbox" id="f-{{ item.id }}" {{ 'checked' if item.completed }} onchange="this.form.submit()">
<span class="priority-dot priority-{{ item.priority }}"></span> <label for="f-{{ item.id }}"></label>
{% if item.title %} </div>
<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.title }}</a> </form>
{% else %} {% if item.task_id %}
<span class="focus-title" style="color:var(--muted)">[Deleted]</span> <span class="priority-dot priority-{{ item.priority }}"></span>
{% if item.title %}
<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.title }}</a>
{% else %}
<span class="focus-title" style="color:var(--muted)">[Deleted]</span>
{% endif %}
{% if item.estimated_minutes %}<span class="focus-meta">~{{ item.estimated_minutes }}min</span>{% endif %}
{% if item.due_date %}<span class="focus-meta">{{ item.due_date }}</span>{% endif %}
{% elif item.list_item_id %}
<span style="color:var(--muted);font-size:0.85rem;margin-right:4px">&#9776;</span>
{% if item.list_item_content %}
<a href="/lists/{{ item.list_item_list_id }}" class="focus-title">{{ item.list_item_content }}</a>
{% else %}
<span class="focus-title" style="color:var(--muted)">[Deleted]</span>
{% endif %}
{% if item.list_name %}<span class="row-tag" style="background:var(--purple);color:#fff">{{ item.list_name }}</span>{% endif %}
{% endif %} {% endif %}
{% if item.project_name %}<span class="row-tag">{{ item.project_name }}</span>{% endif %} <form action="/focus/{{ item.id }}/remove" method="post" style="display:inline">
{% if item.estimated_minutes %}<span class="focus-meta">~{{ item.estimated_minutes }}min</span>{% endif %} <button class="btn btn-ghost btn-xs" style="color:var(--red)" title="Remove from focus">&times;</button>
{% if item.due_date %}<span class="focus-meta">{{ item.due_date }}</span>{% endif %} </form>
{% elif item.list_item_id %} </div>
<span style="color:var(--muted);font-size:0.85rem;margin-right:4px">&#9776;</span> {% endfor %}
{% if item.list_item_content %}
<a href="/lists/{{ item.list_item_list_id }}" class="focus-title">{{ item.list_item_content }}</a>
{% else %}
<span class="focus-title" style="color:var(--muted)">[Deleted]</span>
{% endif %}
{% if item.list_name %}<span class="row-tag" style="background:var(--purple);color:#fff">{{ item.list_name }}</span>{% endif %}
{% endif %}
<form action="/focus/{{ item.id }}/remove" method="post" style="display:inline">
<button class="btn btn-ghost btn-xs" style="color:var(--red)" title="Remove from focus">&times;</button>
</form>
</div> </div>
{% endfor %} {% endfor %}
</div>
{% else %} {% else %}
<div class="empty-state mb-4"><div class="empty-state-text">No focus items for this day</div></div> <div class="empty-state mb-4"><div class="empty-state-text">No focus items for this day</div></div>
{% endif %} {% endif %}