From 8c1e0648365de01b055189f88fe46108fdec77c6 Mon Sep 17 00:00:00 2001 From: Darren <3921919+pendingintent@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:02:33 -0500 Subject: [PATCH 1/3] Moved models to schemas.py from app.py --- src/soa_builder/web/app.py | 50 +++++++++------------------------- src/soa_builder/web/schemas.py | 31 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/soa_builder/web/app.py b/src/soa_builder/web/app.py index cf79147..f36c71a 100644 --- a/src/soa_builder/web/app.py +++ b/src/soa_builder/web/app.py @@ -35,7 +35,6 @@ from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -from pydantic import BaseModel from ..normalization import normalize_soa from .initialize_database import _connect, _init_db @@ -78,7 +77,19 @@ from .routers.arms import delete_arm # Avoid binding visit helpers directly to allow fresh reloads in tests -from .schemas import ArmCreate, SOACreate, SOAMetadataUpdate, VisitCreate +from .schemas import ( + ArmCreate, + SOACreate, + SOAMetadataUpdate, + VisitCreate, + ConceptsUpdate, + # FreezeCreate, + CellCreate, + # BulkActivities, + # MatrixVisit, + # MatrixActivity, + MatrixImport, +) from .utils import ( get_next_code_uid as _get_next_code_uid, get_next_concept_uid as _get_next_concept_uid, @@ -1047,41 +1058,6 @@ def _rollback_preview(soa_id: int, freeze_id: int) -> dict: } -# ------ Schemas -----# -class ConceptsUpdate(BaseModel): - concept_codes: List[str] - - -class FreezeCreate(BaseModel): - version_label: Optional[str] = None - - -class CellCreate(BaseModel): - visit_id: int - activity_id: int - status: str - - -class BulkActivities(BaseModel): - names: List[str] - - -class MatrixVisit(BaseModel): - name: str - label: Optional[str] = None - - -class MatrixActivity(BaseModel): - name: str - statuses: List[str] - - -class MatrixImport(BaseModel): - visits: List[MatrixVisit] - activities: List[MatrixActivity] - reset: bool = True - - def _fetch_matrix(soa_id: int): conn = _connect() cur = conn.cursor() diff --git a/src/soa_builder/web/schemas.py b/src/soa_builder/web/schemas.py index 88779a0..6c48726 100644 --- a/src/soa_builder/web/schemas.py +++ b/src/soa_builder/web/schemas.py @@ -140,3 +140,34 @@ class SOAMetadataUpdate(BaseModel): study_id: Optional[str] = None study_label: Optional[str] = None study_description: Optional[str] = None + + +# moved from app.py +class ConceptsUpdate(BaseModel): + concept_codes: List[str] + + +class FreezeCreate(BaseModel): + version_label: Optional[str] = None + + +class CellCreate(BaseModel): + visit_id: int + activity_id: int + status: str + + +class MatrixVisit(BaseModel): + name: str + label: Optional[str] = None + + +class MatrixActivity(BaseModel): + name: str + statuses: List[str] + + +class MatrixImport(BaseModel): + visits: List[MatrixVisit] + activities: List[MatrixActivity] + reset: bool = True From 386a436551b377bee4d1fb56d19e20e5b754300f Mon Sep 17 00:00:00 2001 From: Darren <3921919+pendingintent@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:39:21 -0500 Subject: [PATCH 2/3] Update to support updating of Visits on edit.html --- src/soa_builder/web/app.py | 38 +++++++++++++++++++++++-- src/soa_builder/web/templates/edit.html | 26 +++++++++++------ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/soa_builder/web/app.py b/src/soa_builder/web/app.py index f36c71a..109edaf 100644 --- a/src/soa_builder/web/app.py +++ b/src/soa_builder/web/app.py @@ -82,6 +82,7 @@ SOACreate, SOAMetadataUpdate, VisitCreate, + VisitUpdate, ConceptsUpdate, # FreezeCreate, CellCreate, @@ -1063,11 +1064,18 @@ def _fetch_matrix(soa_id: int): cur = conn.cursor() # Epochs not part of matrix axes currently; retrieved separately where needed. cur.execute( - "SELECT id,name,label,order_index,epoch_id FROM visit WHERE soa_id=? ORDER BY order_index", + "SELECT id,name,label,order_index,epoch_id,description FROM visit WHERE soa_id=? ORDER BY order_index", (soa_id,), ) visits = [ - dict(id=r[0], name=r[1], label=r[2], order_index=r[3], epoch_id=r[4]) + dict( + id=r[0], + name=r[1], + label=r[2], + order_index=r[3], + epoch_id=r[4], + description=r[5], + ) for r in cur.fetchall() ] # Activities: include optional label/description if schema supports them @@ -5731,6 +5739,32 @@ def ui_set_visit_epoch( ) +@app.post("/ui/soa/{soa_id}/update_visit", response_class=HTMLResponse) +def ui_update_visit( + request: Request, + soa_id: int, + visit_id: int = Form(...), + name: Optional[str] = Form(None), + label: Optional[str] = Form(None), + description: Optional[str] = Form(None), +): + """Form handler to update a Visit's mutable fields (name/label/description).""" + # Build payload with provided fields; blanks should clear values + payload = VisitUpdate( + name=name, + label=label, + description=description, + ) + try: + visits_router.update_visit(soa_id, visit_id, payload) + except Exception: + # Let redirect proceed; detailed errors will appear in API logs + pass + return HTMLResponse( + f"" + ) + + @app.post("/ui/soa/{soa_id}/delete_activity", response_class=HTMLResponse) def ui_delete_activity(request: Request, soa_id: int, activity_id: int = Form(...)): """Form handler to delete an Activity""" diff --git a/src/soa_builder/web/templates/edit.html b/src/soa_builder/web/templates/edit.html index 49e57b8..84a4c72 100644 --- a/src/soa_builder/web/templates/edit.html +++ b/src/soa_builder/web/templates/edit.html @@ -86,7 +86,7 @@