feat: focus priority, focus links, task list assignment, lists drag-and-drop, URL display fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 22:19:15 +00:00
parent 931abf2abd
commit 2e919d458b
12 changed files with 291 additions and 19 deletions

View File

@@ -63,7 +63,7 @@ async def focus_view(
WHERE df.is_deleted = false
AND (t.id IS NULL OR t.is_deleted = false)
AND (li.id IS NULL OR li.is_deleted = false)
ORDER BY df.sort_order, df.created_at
ORDER BY df.focus_priority ASC NULLS LAST, df.sort_order, df.created_at
"""))
items = [dict(r._mapping) for r in result]
@@ -344,10 +344,23 @@ async def focus_detail(
"""), {"lid": list_id})
list_items = [dict(r._mapping) for r in result]
# Load linked links
result = await db.execute(text("""
SELECT l.*, fl.role
FROM links l JOIN focus_links fl ON fl.link_id = l.id
WHERE fl.focus_id = :fid AND l.is_deleted = false
ORDER BY fl.created_at
"""), {"fid": focus_id})
linked_links = [dict(r._mapping) for r in result]
# All links for the "add existing" dropdown
all_links = await BaseRepository("links", db).list()
return templates.TemplateResponse("focus_detail.html", {
"request": request, "sidebar": sidebar, "item": item,
"domain": domain, "project": project, "all_lists": all_lists,
"note": note, "list_id": list_id, "list_items": list_items,
"linked_links": linked_links, "all_links": all_links,
"page_title": item.get("title", "Focus Item"), "active_nav": "focus",
})
@@ -392,6 +405,17 @@ async def toggle_focus_list_item(
return RedirectResponse(url=f"/focus/{focus_id}", status_code=303)
@router.post("/{focus_id}/list-item/{item_id}/edit")
async def edit_focus_list_item(
focus_id: str, item_id: str, request: Request,
content: str = Form(...),
db: AsyncSession = Depends(get_db),
):
li_repo = BaseRepository("list_items", db)
await li_repo.update(item_id, {"content": content.strip()})
return RedirectResponse(url=f"/focus/{focus_id}", status_code=303)
@router.post("/{focus_id}/list-item/{item_id}/delete")
async def delete_focus_list_item(
focus_id: str, item_id: str, request: Request,
@@ -600,6 +624,44 @@ async def toggle_focus(focus_id: str, request: Request, db: AsyncSession = Depen
return RedirectResponse(url=referer, status_code=303)
@router.post("/{focus_id}/set-priority")
async def set_focus_priority(focus_id: str, request: Request, focus_priority: Optional[str] = Form(None), db: AsyncSession = Depends(get_db)):
repo = BaseRepository("daily_focus", db)
val = None
if focus_priority and focus_priority.strip():
try:
val = int(focus_priority.strip())
except ValueError:
pass
await repo.update(focus_id, {"focus_priority": val})
return RedirectResponse(url="/focus", status_code=303)
@router.post("/{focus_id}/links/add")
async def add_focus_link(
focus_id: str,
link_id: str = Form(...),
role: Optional[str] = Form(None),
db: AsyncSession = Depends(get_db),
):
await db.execute(text("""
INSERT INTO focus_links (focus_id, link_id, role)
VALUES (:fid, :lid, :role) ON CONFLICT DO NOTHING
"""), {"fid": focus_id, "lid": link_id, "role": role if role and role.strip() else None})
return RedirectResponse(url=f"/focus/{focus_id}", status_code=303)
@router.post("/{focus_id}/links/{link_id}/remove")
async def remove_focus_link(
focus_id: str, link_id: str,
db: AsyncSession = Depends(get_db),
):
await db.execute(text(
"DELETE FROM focus_links WHERE focus_id = :fid AND link_id = :lid"
), {"fid": focus_id, "lid": link_id})
return RedirectResponse(url=f"/focus/{focus_id}", status_code=303)
@router.post("/{focus_id}/toggle-critical")
async def toggle_critical(focus_id: str, request: Request, db: AsyncSession = Depends(get_db)):
repo = BaseRepository("daily_focus", db)