[verified] redesign trash with deadline groups
ci / gitleaks (push) Successful in 11s
ci / docker (push) Successful in 8m0s

This commit is contained in:
2026-09-21 09:00:07 +08:00
parent c7bb9742f1
commit 740eae8a59
11 changed files with 234 additions and 55 deletions
+22 -16
View File
@@ -1091,22 +1091,22 @@ async def list_tasks(
return TaskPage(items=await _task_details(db, items), next_cursor=next_cursor, total=total, page=1, page_size=limit)
async def _task_details(db: AsyncSession, tasks: list[Task]) -> list[TaskDetailOut]:
async def _task_details(
db: AsyncSession,
tasks: list[Task],
*,
include_deleted_subtasks: bool = False,
) -> list[TaskDetailOut]:
if not tasks:
return []
allowed_scopes = {(task.id, task.user_id, task.list_id) for task in tasks}
subtasks = list(
(
await db.scalars(
select(Task)
.where(
tuple_(Task.parent_id, Task.user_id, Task.list_id).in_(allowed_scopes),
Task.deleted_at.is_(None),
)
.order_by(*_task_ordering())
)
).all()
subtask_query = select(Task).where(
tuple_(Task.parent_id, Task.user_id, Task.list_id).in_(allowed_scopes)
)
subtask_query = subtask_query.where(
Task.deleted_at.is_not(None) if include_deleted_subtasks else Task.deleted_at.is_(None)
)
subtasks = list((await db.scalars(subtask_query.order_by(*_task_ordering()))).all())
subtasks_by_task: dict[UUID, list[Task]] = defaultdict(list)
for subtask in subtasks:
if (subtask.parent_id, subtask.user_id, subtask.list_id) in allowed_scopes:
@@ -1257,11 +1257,17 @@ async def list_trash(
Task.user_id == user.id, Task.deleted_at.is_not(None), Task.parent_id.is_(None)
)
total = await db.scalar(select(func.count()).select_from(query.order_by(None).subquery())) or 0
ordering = (Task.created_at, Task.id)
grouping_rank = case(
(Task.due_at < utcnow(), 0),
(Task.due_at.is_not(None), 1),
else_=2,
)
if page is not None:
size = page_size or limit
items = list((await db.scalars(query.order_by(*ordering).offset((page - 1) * size).limit(size))).all())
return TaskPage(items=await _task_details(db, items), total=total, page=page, page_size=size)
page_ordering = (grouping_rank, Task.due_at, Task.created_at, Task.id)
items = list((await db.scalars(query.order_by(*page_ordering).offset((page - 1) * size).limit(size))).all())
return TaskPage(items=await _task_details(db, items, include_deleted_subtasks=True), total=total, page=page, page_size=size)
ordering = (Task.created_at, Task.id)
if cursor:
created_at, task_id = _decode_trash_cursor(cursor)
query = query.where(
@@ -1271,7 +1277,7 @@ async def list_trash(
has_more = len(rows) > limit
items = rows[:limit]
next_cursor = _encode_trash_cursor(items[-1].created_at, items[-1].id) if has_more else None
return TaskPage(items=await _task_details(db, items), next_cursor=next_cursor, total=total, page=1, page_size=limit)
return TaskPage(items=await _task_details(db, items, include_deleted_subtasks=True), next_cursor=next_cursor, total=total, page=1, page_size=limit)
@app.post("/api/v1/tasks/{task_id}/restore", response_model=TaskDetailOut)