feat: add links to contacts with role (combo box with suggestions)
New contact_links junction table. Contact detail page shows linked links with add form (link picker + role datalist combo) and unlink/edit actions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -71,8 +71,27 @@ async def contact_detail(contact_id: str, request: Request, db: AsyncSession = D
|
||||
item = await repo.get(contact_id)
|
||||
if not item:
|
||||
return RedirectResponse(url="/contacts", status_code=303)
|
||||
|
||||
# Linked links
|
||||
result = await db.execute(text("""
|
||||
SELECT l.*, cl.role, cl.created_at as linked_at
|
||||
FROM links l
|
||||
JOIN contact_links cl ON cl.link_id = l.id
|
||||
WHERE cl.contact_id = :cid AND l.is_deleted = false
|
||||
ORDER BY l.label
|
||||
"""), {"cid": contact_id})
|
||||
links = [dict(r._mapping) for r in result]
|
||||
|
||||
# All links for add dropdown
|
||||
result = await db.execute(text("""
|
||||
SELECT id, label, url FROM links
|
||||
WHERE is_deleted = false ORDER BY label
|
||||
"""))
|
||||
all_links = [dict(r._mapping) for r in result]
|
||||
|
||||
return templates.TemplateResponse("contact_detail.html", {
|
||||
"request": request, "sidebar": sidebar, "item": item,
|
||||
"links": links, "all_links": all_links,
|
||||
"page_title": f"{item['first_name']} {item.get('last_name', '')}".strip(),
|
||||
"active_nav": "contacts",
|
||||
})
|
||||
@@ -126,6 +145,33 @@ async def delete_contact(contact_id: str, db: AsyncSession = Depends(get_db)):
|
||||
return RedirectResponse(url="/contacts", status_code=303)
|
||||
|
||||
|
||||
# ---- Link linking ----
|
||||
|
||||
@router.post("/{contact_id}/links/add")
|
||||
async def add_link(
|
||||
contact_id: str,
|
||||
link_id: str = Form(...),
|
||||
role: Optional[str] = Form(None),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
await db.execute(text("""
|
||||
INSERT INTO contact_links (contact_id, link_id, role)
|
||||
VALUES (:cid, :lid, :role) ON CONFLICT DO NOTHING
|
||||
"""), {"cid": contact_id, "lid": link_id, "role": role if role and role.strip() else None})
|
||||
return RedirectResponse(url=f"/contacts/{contact_id}", status_code=303)
|
||||
|
||||
|
||||
@router.post("/{contact_id}/links/{link_id}/remove")
|
||||
async def remove_link(
|
||||
contact_id: str, link_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
await db.execute(text(
|
||||
"DELETE FROM contact_links WHERE contact_id = :cid AND link_id = :lid"
|
||||
), {"cid": contact_id, "lid": link_id})
|
||||
return RedirectResponse(url=f"/contacts/{contact_id}", status_code=303)
|
||||
|
||||
|
||||
@router.post("/reorder")
|
||||
async def reorder_contact(
|
||||
request: Request,
|
||||
|
||||
Reference in New Issue
Block a user