diff --git a/routers/contacts.py b/routers/contacts.py index db43d9f..eceb179 100644 --- a/routers/contacts.py +++ b/routers/contacts.py @@ -138,7 +138,7 @@ async def contact_detail(contact_id: str, request: Request, db: AsyncSession = D @router.get("/{contact_id}/edit") -async def edit_form(contact_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(contact_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("contacts", db) sidebar = await get_sidebar_data(db) item = await repo.get(contact_id) @@ -159,6 +159,7 @@ async def edit_form(contact_id: str, request: Request, db: AsyncSession = Depend "request": request, "sidebar": sidebar, "page_title": "Edit Contact", "active_nav": "contacts", "item": item, "all_links": all_links, "linked_links": linked_links, + "from_project": from_project or "", }) @@ -174,6 +175,7 @@ async def update_contact( phone: Optional[str] = Form(None), notes: Optional[str] = Form(None), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("contacts", db) @@ -224,6 +226,8 @@ async def update_contact( await db.commit() + if from_project and from_project.strip(): + return RedirectResponse(url=f"/projects/{from_project}?tab=contacts", status_code=303) return RedirectResponse(url=f"/contacts/{contact_id}", status_code=303) diff --git a/routers/decisions.py b/routers/decisions.py index 1506180..ac4a6c9 100644 --- a/routers/decisions.py +++ b/routers/decisions.py @@ -57,6 +57,7 @@ async def create_form( request: Request, meeting_id: Optional[str] = None, task_id: Optional[str] = None, + project_id: Optional[str] = None, db: AsyncSession = Depends(get_db), ): sidebar = await get_sidebar_data(db) @@ -74,6 +75,7 @@ async def create_form( "item": None, "prefill_meeting_id": meeting_id or "", "prefill_task_id": task_id or "", + "prefill_project_id": project_id or "", }) @@ -87,6 +89,7 @@ async def create_decision( decided_at: Optional[str] = Form(None), meeting_id: Optional[str] = Form(None), task_id: Optional[str] = Form(None), + project_id: Optional[str] = Form(None), tags: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): @@ -105,8 +108,18 @@ async def create_decision( data["tags"] = [t.strip() for t in tags.split(",") if t.strip()] decision = await repo.create(data) + + # Link to project if created from project context + if project_id and project_id.strip(): + await db.execute(text(""" + INSERT INTO decision_projects (decision_id, project_id) + VALUES (:did, :pid) ON CONFLICT DO NOTHING + """), {"did": decision["id"], "pid": project_id}) + if task_id and task_id.strip(): return RedirectResponse(url=f"/tasks/{task_id}?tab=decisions", status_code=303) + if project_id and project_id.strip(): + return RedirectResponse(url=f"/projects/{project_id}?tab=decisions", status_code=303) return RedirectResponse(url=f"/decisions/{decision['id']}", status_code=303) @@ -152,7 +165,7 @@ async def decision_detail(decision_id: str, request: Request, db: AsyncSession = @router.get("/{decision_id}/edit") -async def edit_form(decision_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(decision_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("decisions", db) sidebar = await get_sidebar_data(db) item = await repo.get(decision_id) @@ -178,6 +191,7 @@ async def edit_form(decision_id: str, request: Request, db: AsyncSession = Depen "page_title": "Edit Decision", "active_nav": "decisions", "item": item, "prefill_meeting_id": "", + "from_project": from_project or "", }) @@ -192,6 +206,7 @@ async def update_decision( meeting_id: Optional[str] = Form(None), superseded_by_id: Optional[str] = Form(None), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("decisions", db) @@ -208,6 +223,9 @@ async def update_decision( data["tags"] = None await repo.update(decision_id, data) + + if from_project and from_project.strip(): + return RedirectResponse(url=f"/projects/{from_project}?tab=decisions", status_code=303) return RedirectResponse(url=f"/decisions/{decision_id}", status_code=303) diff --git a/routers/files.py b/routers/files.py index f8775af..4a066d9 100644 --- a/routers/files.py +++ b/routers/files.py @@ -379,6 +379,12 @@ async def upload_file( # Redirect back to context or file list if context_type and context_id: + if context_type == "project": + return RedirectResponse(url=f"/projects/{context_id}?tab=files", status_code=303) + if context_type == "task": + return RedirectResponse(url=f"/tasks/{context_id}?tab=files", status_code=303) + if context_type == "meeting": + return RedirectResponse(url=f"/meetings/{context_id}?tab=files", status_code=303) return RedirectResponse( url=f"/files?context_type={context_type}&context_id={context_id}", status_code=303, diff --git a/routers/focus.py b/routers/focus.py index 755e3db..36730a8 100644 --- a/routers/focus.py +++ b/routers/focus.py @@ -416,7 +416,7 @@ async def reorder_focus_list_items( @router.get("/{focus_id}/edit") -async def edit_focus_item(focus_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_focus_item(focus_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("daily_focus", db) item = await repo.get(focus_id) if not item or item.get("task_id") or item.get("list_item_id"): @@ -429,6 +429,7 @@ async def edit_focus_item(focus_id: str, request: Request, db: AsyncSession = De "request": request, "sidebar": sidebar, "item": item, "domains": domains, "projects": projects, "lists": lists, "page_title": "Edit Focus Item", "active_nav": "focus", + "from_project": from_project or "", }) @@ -438,14 +439,21 @@ async def update_focus_item( title: str = Form(...), domain_id: Optional[str] = Form(None), project_id: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("daily_focus", db) + new_project = project_id if project_id and project_id.strip() else None await repo.update(focus_id, { "title": title.strip(), "domain_id": domain_id or None, - "project_id": project_id or None, + "project_id": new_project, }) + + if from_project and from_project.strip(): + if new_project and new_project != from_project: + return RedirectResponse(url=f"/projects/{new_project}?tab=focus", status_code=303) + return RedirectResponse(url=f"/projects/{from_project}?tab=focus", status_code=303) return RedirectResponse(url=f"/focus/{focus_id}", status_code=303) diff --git a/routers/links.py b/routers/links.py index fdda3cf..32b334e 100644 --- a/routers/links.py +++ b/routers/links.py @@ -122,7 +122,7 @@ async def create_link( @router.get("/{link_id}/edit") -async def edit_form(link_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(link_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("links", db) sidebar = await get_sidebar_data(db) item = await repo.get(link_id) @@ -138,6 +138,7 @@ async def edit_form(link_id: str, request: Request, db: AsyncSession = Depends(g "item": item, "prefill_domain_id": "", "prefill_project_id": "", "prefill_task_id": "", "prefill_meeting_id": "", + "from_project": from_project or "", }) @@ -146,6 +147,7 @@ async def update_link( link_id: str, label: str = Form(...), url: str = Form(...), domain_id: Optional[str] = Form(None), project_id: Optional[str] = Form(None), description: Optional[str] = Form(None), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("links", db) @@ -160,6 +162,12 @@ async def update_link( else: data["tags"] = None await repo.update(link_id, data) + + new_project = data.get("project_id") + if from_project and from_project.strip(): + if new_project and new_project != from_project: + return RedirectResponse(url=f"/projects/{new_project}?tab=links", status_code=303) + return RedirectResponse(url=f"/projects/{from_project}?tab=links", status_code=303) return RedirectResponse(url="/links", status_code=303) diff --git a/routers/lists.py b/routers/lists.py index aa75349..7db9aa1 100644 --- a/routers/lists.py +++ b/routers/lists.py @@ -141,6 +141,8 @@ async def create_list( return RedirectResponse(url=f"/meetings/{meeting_id}?tab=lists", status_code=303) if focus_id and focus_id.strip(): return RedirectResponse(url=f"/focus/{focus_id}?tab=lists", status_code=303) + if project_id and project_id.strip(): + return RedirectResponse(url=f"/projects/{project_id}?tab=lists", status_code=303) return RedirectResponse(url=f"/lists/{new_list['id']}", status_code=303) @@ -216,7 +218,7 @@ async def list_detail(list_id: str, request: Request, db: AsyncSession = Depends @router.get("/{list_id}/edit") -async def edit_form(list_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(list_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("lists", db) sidebar = await get_sidebar_data(db) item = await repo.get(list_id) @@ -236,6 +238,7 @@ async def edit_form(list_id: str, request: Request, db: AsyncSession = Depends(g "page_title": "Edit List", "active_nav": "lists", "item": item, "prefill_domain_id": "", "prefill_project_id": "", + "from_project": from_project or "", }) @@ -249,6 +252,7 @@ async def update_list( list_type: str = Form("checklist"), description: Optional[str] = Form(None), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("lists", db) @@ -264,6 +268,12 @@ async def update_list( data["tags"] = None await repo.update(list_id, data) + + new_project = data.get("project_id") + if from_project and from_project.strip(): + if new_project and new_project != from_project: + return RedirectResponse(url=f"/projects/{new_project}?tab=lists", status_code=303) + return RedirectResponse(url=f"/projects/{from_project}?tab=lists", status_code=303) return RedirectResponse(url=f"/lists/{list_id}", status_code=303) diff --git a/routers/meetings.py b/routers/meetings.py index 0768590..3be101a 100644 --- a/routers/meetings.py +++ b/routers/meetings.py @@ -51,7 +51,7 @@ async def list_meetings( @router.get("/create") -async def create_form(request: Request, db: AsyncSession = Depends(get_db)): +async def create_form(request: Request, project_id: Optional[str] = None, db: AsyncSession = Depends(get_db)): sidebar = await get_sidebar_data(db) # Get contacts for attendee selection contacts_repo = BaseRepository("contacts", db) @@ -68,6 +68,7 @@ async def create_form(request: Request, db: AsyncSession = Depends(get_db)): "contacts": contacts, "parent_meetings": parent_meetings, "page_title": "New Meeting", "active_nav": "meetings", "item": None, + "prefill_project_id": project_id or "", }) @@ -84,6 +85,7 @@ async def create_meeting( parent_id: Optional[str] = Form(None), agenda: Optional[str] = Form(None), tags: Optional[str] = Form(None), + project_id: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("meetings", db) @@ -103,6 +105,14 @@ async def create_meeting( data["tags"] = [t.strip() for t in tags.split(",") if t.strip()] meeting = await repo.create(data) + + # Link to project if created from project context + if project_id and project_id.strip(): + await db.execute(text(""" + INSERT INTO project_meetings (project_id, meeting_id) + VALUES (:pid, :mid) ON CONFLICT DO NOTHING + """), {"pid": project_id, "mid": meeting["id"]}) + return RedirectResponse(url=f"/projects/{project_id}?tab=meetings", status_code=303) return RedirectResponse(url=f"/meetings/{meeting['id']}", status_code=303) @@ -253,7 +263,7 @@ async def meeting_detail( @router.get("/{meeting_id}/edit") -async def edit_form(meeting_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(meeting_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("meetings", db) sidebar = await get_sidebar_data(db) item = await repo.get(meeting_id) @@ -273,6 +283,7 @@ async def edit_form(meeting_id: str, request: Request, db: AsyncSession = Depend "contacts": contacts, "parent_meetings": parent_meetings, "page_title": "Edit Meeting", "active_nav": "meetings", "item": item, + "from_project": from_project or "", }) @@ -291,6 +302,7 @@ async def update_meeting( transcript: Optional[str] = Form(None), notes_body: Optional[str] = Form(None), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("meetings", db) @@ -315,6 +327,9 @@ async def update_meeting( data["tags"] = None await repo.update(meeting_id, data) + + if from_project and from_project.strip(): + return RedirectResponse(url=f"/projects/{from_project}?tab=meetings", status_code=303) return RedirectResponse(url=f"/meetings/{meeting_id}", status_code=303) diff --git a/routers/notes.py b/routers/notes.py index c2a7c1d..8042b65 100644 --- a/routers/notes.py +++ b/routers/notes.py @@ -122,6 +122,8 @@ async def create_note( return RedirectResponse(url=f"/meetings/{meeting_id}?tab=notes", status_code=303) if focus_id and focus_id.strip(): return RedirectResponse(url=f"/focus/{focus_id}?tab=notes", status_code=303) + if project_id and project_id.strip(): + return RedirectResponse(url=f"/projects/{project_id}?tab=notes", status_code=303) return RedirectResponse(url=f"/notes/{note['id']}", status_code=303) @@ -153,7 +155,7 @@ async def note_detail(note_id: str, request: Request, db: AsyncSession = Depends @router.get("/{note_id}/edit") -async def edit_form(note_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(note_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("notes", db) sidebar = await get_sidebar_data(db) item = await repo.get(note_id) @@ -168,6 +170,7 @@ async def edit_form(note_id: str, request: Request, db: AsyncSession = Depends(g "domains": domains, "projects": projects, "page_title": f"Edit Note", "active_nav": "notes", "item": item, "prefill_domain_id": "", "prefill_project_id": "", + "from_project": from_project or "", }) @@ -180,6 +183,7 @@ async def update_note( body: Optional[str] = Form(None), content_format: str = Form("rich"), tags: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("notes", db) @@ -193,6 +197,12 @@ async def update_note( else: data["tags"] = None await repo.update(note_id, data) + + new_project = data.get("project_id") + if from_project and from_project.strip(): + if new_project and new_project != from_project: + return RedirectResponse(url=f"/projects/{new_project}?tab=notes", status_code=303) + return RedirectResponse(url=f"/projects/{from_project}?tab=notes", status_code=303) return RedirectResponse(url=f"/notes/{note_id}", status_code=303) diff --git a/routers/tasks.py b/routers/tasks.py index 3d156b7..c995d54 100644 --- a/routers/tasks.py +++ b/routers/tasks.py @@ -322,7 +322,7 @@ async def task_detail( @router.get("/{task_id}/edit") -async def edit_form(task_id: str, request: Request, db: AsyncSession = Depends(get_db)): +async def edit_form(task_id: str, request: Request, from_project: Optional[str] = None, db: AsyncSession = Depends(get_db)): repo = BaseRepository("tasks", db) sidebar = await get_sidebar_data(db) item = await repo.get(task_id) @@ -344,6 +344,7 @@ async def edit_form(task_id: str, request: Request, db: AsyncSession = Depends(g "page_title": f"Edit Task", "active_nav": "tasks", "item": item, "prefill_domain_id": "", "prefill_project_id": "", "prefill_parent_id": "", + "from_project": from_project or "", }) @@ -363,6 +364,7 @@ async def update_task( tags: Optional[str] = Form(None), estimated_minutes: Optional[str] = Form(None), energy_required: Optional[str] = Form(None), + from_project: Optional[str] = Form(None), db: AsyncSession = Depends(get_db), ): repo = BaseRepository("tasks", db) @@ -392,6 +394,13 @@ async def update_task( data["completed_at"] = None await repo.update(task_id, data) + + # Redirect back to project context if applicable + new_project = data.get("project_id") + if from_project and from_project.strip(): + if new_project and new_project != from_project: + return RedirectResponse(url=f"/projects/{new_project}?tab=tasks", status_code=303) + return RedirectResponse(url=f"/projects/{from_project}?tab=tasks", status_code=303) return RedirectResponse(url=f"/tasks/{task_id}", status_code=303) diff --git a/templates/contact_form.html b/templates/contact_form.html index 551e0f7..f4b1565 100644 --- a/templates/contact_form.html +++ b/templates/contact_form.html @@ -46,7 +46,8 @@ -
Cancel
+ {% if from_project is defined and from_project %}{% endif %} +
Cancel
diff --git a/templates/decision_form.html b/templates/decision_form.html index 6a7c2a3..a34c340 100644 --- a/templates/decision_form.html +++ b/templates/decision_form.html @@ -78,9 +78,11 @@ {% if prefill_task_id is defined and prefill_task_id %}{% endif %} + {% if prefill_project_id is defined and prefill_project_id %}{% endif %} + {% if from_project is defined and from_project %}{% endif %}
- Cancel + Cancel
diff --git a/templates/focus_edit.html b/templates/focus_edit.html index f61ec00..6b5a6e6 100644 --- a/templates/focus_edit.html +++ b/templates/focus_edit.html @@ -45,9 +45,10 @@ + {% if from_project is defined and from_project %}{% endif %}
- Cancel + Cancel
diff --git a/templates/link_form.html b/templates/link_form.html index 2f70699..dd42226 100644 --- a/templates/link_form.html +++ b/templates/link_form.html @@ -16,7 +16,8 @@ {% if prefill_task_id is defined and prefill_task_id %}{% endif %} {% if prefill_meeting_id is defined and prefill_meeting_id %}{% endif %} {% if prefill_contact_id is defined and prefill_contact_id %}{% endif %} -
Cancel
+ {% if from_project is defined and from_project %}{% endif %} +
Cancel
{% endblock %} diff --git a/templates/list_form.html b/templates/list_form.html index 595767e..683c606 100644 --- a/templates/list_form.html +++ b/templates/list_form.html @@ -76,9 +76,10 @@ {% if prefill_task_id is defined and prefill_task_id %}{% endif %} {% if prefill_meeting_id is defined and prefill_meeting_id %}{% endif %} {% if prefill_focus_id is defined and prefill_focus_id %}{% endif %} + {% if from_project is defined and from_project %}{% endif %}
- Cancel + Cancel
diff --git a/templates/meeting_form.html b/templates/meeting_form.html index 183b7ec..b7484ce 100644 --- a/templates/meeting_form.html +++ b/templates/meeting_form.html @@ -93,9 +93,11 @@ + {% if prefill_project_id is defined and prefill_project_id %}{% endif %} + {% if from_project is defined and from_project %}{% endif %}
- Cancel + Cancel
diff --git a/templates/note_form.html b/templates/note_form.html index 027c62d..a20f4ed 100644 --- a/templates/note_form.html +++ b/templates/note_form.html @@ -16,7 +16,8 @@ {% if prefill_task_id is defined and prefill_task_id %}{% endif %} {% if prefill_meeting_id is defined and prefill_meeting_id %}{% endif %} {% if prefill_focus_id is defined and prefill_focus_id %}{% endif %} -
Cancel
+ {% if from_project is defined and from_project %}{% endif %} +
Cancel
{% endblock %} diff --git a/templates/project_detail.html b/templates/project_detail.html index 0713630..797aa98 100644 --- a/templates/project_detail.html +++ b/templates/project_detail.html @@ -67,7 +67,7 @@ {% if t.due_date %}{{ t.due_date }}{% endif %} {{ t.status|replace('_', ' ') }}
- Edit + Edit
@@ -87,7 +87,7 @@ {{ n.title }} {{ n.updated_at.strftime('%Y-%m-%d') if n.updated_at else '' }}
- Edit + Edit
@@ -107,7 +107,7 @@ {{ l.label }} {{ l.url[:50] }}{% if l.url|length > 50 %}...{% endif %}
- Edit + Edit
@@ -146,7 +146,7 @@ {{ l.name }} {{ l.item_count }} items
- Edit + Edit
@@ -166,7 +166,7 @@ {{ d.title }} {{ d.status }}
- Edit + Edit
@@ -180,7 +180,7 @@ {% endfor %} {% elif tab == 'meetings' %} -+ New Meeting ++ New Meeting
@@ -201,7 +201,7 @@ {{ m.meeting_date }} {{ m.status }}
- Edit + Edit @@ -221,7 +221,7 @@ {% if f.domain_name %}{{ f.domain_name }}{% endif %} {{ f.created_at.strftime('%Y-%m-%d') if f.created_at else '' }}
- Edit + Edit
@@ -262,7 +262,7 @@ {% if c.role %}{{ c.role }}{% endif %} {{ c.linked_at.strftime('%Y-%m-%d') if c.linked_at else '' }}
- Edit + Edit
diff --git a/templates/task_form.html b/templates/task_form.html index 255e468..f5c0da9 100644 --- a/templates/task_form.html +++ b/templates/task_form.html @@ -108,10 +108,11 @@ {% if prefill_parent_id %} {% endif %} + {% if from_project is defined and from_project %}{% endif %}
- Cancel + Cancel