feat: Edit, Unlink, Delete actions on all project detail tabs
Every tab (tasks, notes, links, files, lists, decisions, meetings, focus, contacts) now has consistent row actions: Edit, Unlink from project, and Delete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -419,25 +419,108 @@ async def remove_contact(
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=contacts", status_code=303)
|
||||
|
||||
|
||||
# ---- Link unlinking ----
|
||||
# ---- Entity unlink / delete from project tabs ----
|
||||
|
||||
# Tasks (FK: tasks.project_id)
|
||||
@router.post("/{project_id}/tasks/{task_id}/unlink")
|
||||
async def unlink_task(project_id: str, task_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"UPDATE tasks SET project_id = NULL, updated_at = now() WHERE id = :tid AND project_id = :pid"
|
||||
), {"tid": task_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=tasks", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/tasks/{task_id}/delete")
|
||||
async def delete_project_task(project_id: str, task_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("tasks", db).soft_delete(task_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=tasks", status_code=303)
|
||||
|
||||
# Notes (FK: notes.project_id)
|
||||
@router.post("/{project_id}/notes/{note_id}/unlink")
|
||||
async def unlink_note(project_id: str, note_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"UPDATE notes SET project_id = NULL, updated_at = now() WHERE id = :nid AND project_id = :pid"
|
||||
), {"nid": note_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=notes", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/notes/{note_id}/delete")
|
||||
async def delete_project_note(project_id: str, note_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("notes", db).soft_delete(note_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=notes", status_code=303)
|
||||
|
||||
# Links (FK: links.project_id)
|
||||
@router.post("/{project_id}/links/{link_id}/unlink")
|
||||
async def unlink_link(
|
||||
project_id: str, link_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
async def unlink_link(project_id: str, link_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"UPDATE links SET project_id = NULL, updated_at = now() WHERE id = :lid AND project_id = :pid"
|
||||
), {"lid": link_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=links", status_code=303)
|
||||
|
||||
|
||||
@router.post("/{project_id}/links/{link_id}/delete")
|
||||
async def delete_project_link(
|
||||
project_id: str, link_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
repo = BaseRepository("links", db)
|
||||
await repo.soft_delete(link_id)
|
||||
async def delete_project_link(project_id: str, link_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("links", db).soft_delete(link_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=links", status_code=303)
|
||||
|
||||
# Files (junction: file_mappings)
|
||||
@router.post("/{project_id}/files/{file_id}/unlink")
|
||||
async def unlink_file(project_id: str, file_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"DELETE FROM file_mappings WHERE file_id = :fid AND context_type = 'project' AND context_id = :pid::uuid"
|
||||
), {"fid": file_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=files", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/files/{file_id}/delete")
|
||||
async def delete_project_file(project_id: str, file_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("files", db).soft_delete(file_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=files", status_code=303)
|
||||
|
||||
# Lists (FK: lists.project_id)
|
||||
@router.post("/{project_id}/lists/{list_id}/unlink")
|
||||
async def unlink_list(project_id: str, list_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"UPDATE lists SET project_id = NULL, updated_at = now() WHERE id = :lid AND project_id = :pid"
|
||||
), {"lid": list_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=lists", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/lists/{list_id}/delete")
|
||||
async def delete_project_list(project_id: str, list_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("lists", db).soft_delete(list_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=lists", status_code=303)
|
||||
|
||||
# Decisions (junction: decision_projects)
|
||||
@router.post("/{project_id}/decisions/{decision_id}/unlink")
|
||||
async def unlink_decision(project_id: str, decision_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"DELETE FROM decision_projects WHERE decision_id = :did AND project_id = :pid"
|
||||
), {"did": decision_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=decisions", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/decisions/{decision_id}/delete")
|
||||
async def delete_project_decision(project_id: str, decision_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("decisions", db).soft_delete(decision_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=decisions", status_code=303)
|
||||
|
||||
# Meetings (junction: project_meetings) — remove already exists, add delete
|
||||
@router.post("/{project_id}/meetings/{meeting_id}/delete")
|
||||
async def delete_project_meeting(project_id: str, meeting_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("meetings", db).soft_delete(meeting_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=meetings", status_code=303)
|
||||
|
||||
# Focus (FK: daily_focus.project_id)
|
||||
@router.post("/{project_id}/focus/{focus_id}/unlink")
|
||||
async def unlink_focus(project_id: str, focus_id: str, db=Depends(get_db)):
|
||||
await db.execute(text(
|
||||
"UPDATE daily_focus SET project_id = NULL, updated_at = now() WHERE id = :fid AND project_id = :pid"
|
||||
), {"fid": focus_id, "pid": project_id})
|
||||
await db.commit()
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=focus", status_code=303)
|
||||
|
||||
@router.post("/{project_id}/focus/{focus_id}/delete")
|
||||
async def delete_project_focus(project_id: str, focus_id: str, db=Depends(get_db)):
|
||||
await BaseRepository("daily_focus", db).soft_delete(focus_id)
|
||||
return RedirectResponse(url=f"/projects/{project_id}?tab=focus", status_code=303)
|
||||
|
||||
Reference in New Issue
Block a user