diff --git a/src/soa_builder/web/app.py b/src/soa_builder/web/app.py index cf79147..109edaf 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,20 @@ 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, + VisitUpdate, + 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,51 +1059,23 @@ 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() # 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 @@ -5755,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/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 diff --git a/src/soa_builder/web/templates/edit.html b/src/soa_builder/web/templates/edit.html index 49e57b8..e06f94e 100644 --- a/src/soa_builder/web/templates/edit.html +++ b/src/soa_builder/web/templates/edit.html @@ -86,7 +86,7 @@