Improve project/task/sub-task workflows across backend and web

Backend:
- notes.py: add parent_id filter to list_notes()
- routes/notes.py: expose project_id, milestone_id, parent_id, type
  query params on GET /api/notes
- milestones.py: add find_milestone_by_title() (cross-project search)
- tools.py: list_notes project filter + updated_at; list_tasks milestone
  without project; tag_mode default add; fail-fast project resolution

Web frontend:
- TaskEditorView: add sub-tasks section (fetch, toggle, create inline);
  pre-fill projectId/milestoneId/parentId from URL query params on new task
- ProjectView: add + button in Todo kanban column header linking to
  /tasks/new?projectId=X&milestoneId=Y for quick task creation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 22:00:44 -05:00
parent 6580d16942
commit 4fd2c915b6
6 changed files with 266 additions and 4 deletions
+14 -1
View File
@@ -54,8 +54,21 @@ async def list_notes_route():
elif request.args.get("is_task", "").lower() == "true":
is_task = True
project_id = request.args.get("project_id", type=int)
milestone_id = request.args.get("milestone_id", type=int)
parent_id = request.args.get("parent_id", type=int)
# type= shorthand used by web frontend (?type=task or ?type=note)
type_param = request.args.get("type")
if type_param == "task":
is_task = True
elif type_param == "note":
is_task = False
notes, total = await list_notes(
uid, q=q, tags=tag or None, is_task=is_task, sort=sort, order=order, limit=limit, offset=offset
uid, q=q, tags=tag or None, is_task=is_task, sort=sort, order=order,
limit=limit, offset=offset,
project_id=project_id, milestone_id=milestone_id, parent_id=parent_id,
)
return jsonify({"notes": [n.to_dict() for n in notes], "total": total})