From 33e962e73d3660f69c644f81d8c7c16943ccad67 Mon Sep 17 00:00:00 2001 From: serversdown Date: Fri, 27 Mar 2026 20:54:04 +0000 Subject: [PATCH] feat: add edit session times functionality with modal for monitoring sessions --- backend/routers/projects.py | 61 +++++++++++++- .../partials/projects/unified_files.html | 79 +++++++++++++++++++ 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/backend/routers/projects.py b/backend/routers/projects.py index ee58eb5..79b5b61 100644 --- a/backend/routers/projects.py +++ b/backend/routers/projects.py @@ -20,7 +20,7 @@ import json import logging import io -from backend.utils.timezone import utc_to_local, format_local_datetime +from backend.utils.timezone import utc_to_local, format_local_datetime, local_to_utc from backend.database import get_db from fastapi import UploadFile, File @@ -1800,6 +1800,23 @@ async def delete_session( VALID_PERIOD_TYPES = {"weekday_day", "weekday_night", "weekend_day", "weekend_night"} + +def _derive_period_type(dt: datetime) -> str: + is_weekend = dt.weekday() >= 5 + is_night = dt.hour >= 22 or dt.hour < 7 + if is_weekend: + return "weekend_night" if is_night else "weekend_day" + return "weekday_night" if is_night else "weekday_day" + + +def _build_session_label(dt: datetime, location_name: str, period_type: str) -> str: + day_abbr = dt.strftime("%a") + date_str = f"{dt.month}/{dt.day}" + period_str = {"weekday_day": "Day", "weekday_night": "Night", "weekend_day": "Day", "weekend_night": "Night"}.get(period_type, "") + parts = [p for p in [location_name, f"{day_abbr} {date_str}", period_str] if p] + return " — ".join(parts) + + @router.patch("/{project_id}/sessions/{session_id}") async def patch_session( project_id: str, @@ -1807,13 +1824,53 @@ async def patch_session( data: dict, db: Session = Depends(get_db), ): - """Update session_label and/or period_type on a monitoring session.""" + """Update session fields: started_at, stopped_at, session_label, period_type.""" session = db.query(MonitoringSession).filter_by(id=session_id).first() if not session: raise HTTPException(status_code=404, detail="Session not found") if session.project_id != project_id: raise HTTPException(status_code=403, detail="Session does not belong to this project") + times_changed = False + + if "started_at" in data and data["started_at"]: + try: + local_dt = datetime.fromisoformat(data["started_at"]) + session.started_at = local_to_utc(local_dt) + times_changed = True + except ValueError: + raise HTTPException(status_code=400, detail="Invalid started_at datetime format") + + if "stopped_at" in data: + if data["stopped_at"]: + try: + local_dt = datetime.fromisoformat(data["stopped_at"]) + session.stopped_at = local_to_utc(local_dt) + times_changed = True + except ValueError: + raise HTTPException(status_code=400, detail="Invalid stopped_at datetime format") + else: + session.stopped_at = None + times_changed = True + + if times_changed and session.started_at and session.stopped_at: + delta = session.stopped_at - session.started_at + session.duration_seconds = max(0, int(delta.total_seconds())) + elif times_changed and not session.stopped_at: + session.duration_seconds = None + + # Re-derive period_type and session_label from new started_at unless explicitly provided + if times_changed and session.started_at and "period_type" not in data: + local_start = utc_to_local(session.started_at) + session.period_type = _derive_period_type(local_start) + + if times_changed and session.started_at and "session_label" not in data: + from backend.models import MonitoringLocation + location = db.query(MonitoringLocation).filter_by(id=session.location_id).first() + location_name = location.name if location else "" + local_start = utc_to_local(session.started_at) + session.session_label = _build_session_label(local_start, location_name, session.period_type or "") + if "session_label" in data: session.session_label = str(data["session_label"]).strip() or None if "period_type" in data: diff --git a/templates/partials/projects/unified_files.html b/templates/partials/projects/unified_files.html index 118c217..a3bf0d1 100644 --- a/templates/partials/projects/unified_files.html +++ b/templates/partials/projects/unified_files.html @@ -56,6 +56,15 @@ {% else %}bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300{% endif %}"> {{ session.status or 'unknown' }} + + + + + +