Compare commits

..

1 Commits

Author SHA1 Message Date
60acdbefdb Merge pull request 'feature/auto-populate-suggestions' (#1) from feature/auto-populate-suggestions into master
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 11s
Reviewed-on: #1
2026-02-24 21:49:05 +00:00
2 changed files with 21 additions and 62 deletions

View File

@@ -23,30 +23,6 @@ logger = structlog.get_logger(__name__)
router = APIRouter(prefix="/log", tags=["logging"]) router = APIRouter(prefix="/log", tags=["logging"])
def _get_prefill_values(
logs: list,
session: Session,
profile_id: int,
exercise_id: int,
) -> tuple:
"""Get pre-fill values for the next set form.
If sets have already been logged this session, use the last logged
set's values (users typically repeat the same reps/weight across sets).
Otherwise, use the progression engine's suggestion.
Returns:
(suggested_reps, suggested_weight) tuple.
"""
if logs:
last = logs[-1]
return last.reps_completed, last.weight_used
progression = ProgressionService(session)
suggestion = progression.get_suggestion(profile_id, exercise_id)
return suggestion.get("suggested_reps"), suggestion.get("suggested_weight")
@router.post("", response_class=HTMLResponse) @router.post("", response_class=HTMLResponse)
async def log_set( async def log_set(
request: Request, request: Request,
@@ -104,9 +80,10 @@ async def log_set(
# Return updated logs for this exercise # Return updated logs for this exercise
logs = log_service.list_logs_for_exercise(ws.id, exercise_id) logs = log_service.list_logs_for_exercise(ws.id, exercise_id)
next_set = len(logs) + 1 next_set = len(logs) + 1
suggested_reps, suggested_weight = _get_prefill_values(
logs, session, active_profile_id, exercise_id, # Fetch suggestion for pre-filling the next set form
) progression = ProgressionService(session)
suggestion = progression.get_suggestion(active_profile_id, exercise_id)
templates = request.app.state.templates templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", { return templates.TemplateResponse("partials/log_entry.html", {
@@ -116,8 +93,8 @@ async def log_set(
"workout_day_id": workout_day_id, "workout_day_id": workout_day_id,
"next_set": next_set, "next_set": next_set,
"session_id": ws.id, "session_id": ws.id,
"suggested_reps": suggested_reps, "suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggested_weight, "suggested_weight": suggestion.get("suggested_weight"),
}) })
@@ -154,12 +131,12 @@ async def edit_log(
logs = log_service.list_logs_for_exercise(log.session_id, log.exercise_id) logs = log_service.list_logs_for_exercise(log.session_id, log.exercise_id)
next_set = len(logs) + 1 next_set = len(logs) + 1
# Fetch suggestion for pre-filling the next set form
active_profile_id = get_active_profile_id(request) active_profile_id = get_active_profile_id(request)
suggested_reps, suggested_weight = None, None suggestion = {}
if active_profile_id: if active_profile_id:
suggested_reps, suggested_weight = _get_prefill_values( progression = ProgressionService(session)
logs, session, active_profile_id, log.exercise_id, suggestion = progression.get_suggestion(active_profile_id, log.exercise_id)
)
templates = request.app.state.templates templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", { return templates.TemplateResponse("partials/log_entry.html", {
@@ -169,8 +146,8 @@ async def edit_log(
"workout_day_id": 0, "workout_day_id": 0,
"next_set": next_set, "next_set": next_set,
"session_id": log.session_id, "session_id": log.session_id,
"suggested_reps": suggested_reps, "suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggested_weight, "suggested_weight": suggestion.get("suggested_weight"),
}) })
@@ -203,12 +180,12 @@ async def delete_log(
logs = log_service.list_logs_for_exercise(session_id, exercise_id) logs = log_service.list_logs_for_exercise(session_id, exercise_id)
next_set = len(logs) + 1 next_set = len(logs) + 1
# Fetch suggestion for pre-filling the next set form
active_profile_id = get_active_profile_id(request) active_profile_id = get_active_profile_id(request)
suggested_reps, suggested_weight = None, None suggestion = {}
if active_profile_id: if active_profile_id:
suggested_reps, suggested_weight = _get_prefill_values( progression = ProgressionService(session)
logs, session, active_profile_id, exercise_id, suggestion = progression.get_suggestion(active_profile_id, exercise_id)
)
templates = request.app.state.templates templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", { return templates.TemplateResponse("partials/log_entry.html", {
@@ -218,8 +195,8 @@ async def delete_log(
"workout_day_id": 0, "workout_day_id": 0,
"next_set": next_set, "next_set": next_set,
"session_id": session_id, "session_id": session_id,
"suggested_reps": suggested_reps, "suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggested_weight, "suggested_weight": suggestion.get("suggested_weight"),
}) })
return HTMLResponse("") return HTMLResponse("")

View File

@@ -149,8 +149,7 @@ class LogService:
def delete_log(self, log_id: int) -> None: def delete_log(self, log_id: int) -> None:
"""Delete a log entry. """Delete a log entry.
Removes the log, renumbers remaining sets, and cleans up the Removes the log and cleans up the parent session if no logs remain.
parent session if no logs remain.
Args: Args:
log_id: The log entry ID. log_id: The log entry ID.
@@ -163,32 +162,15 @@ class LogService:
raise ValueError(f"WorkoutLog with id {log_id} not found") raise ValueError(f"WorkoutLog with id {log_id} not found")
session_id = log.session_id session_id = log.session_id
exercise_id = log.exercise_id
self._session.delete(log) self._session.delete(log)
self._session.commit() self._session.commit()
logger.info("log_deleted", log_id=log_id) logger.info("log_deleted", log_id=log_id)
# Renumber remaining sets so they stay sequential (1, 2, 3...) # Clean up orphaned session if no logs remain
remaining = self._session.exec( remaining = self._session.exec(
select(WorkoutLog)
.where(
WorkoutLog.session_id == session_id,
WorkoutLog.exercise_id == exercise_id,
)
.order_by(WorkoutLog.set_number)
).all()
for i, remaining_log in enumerate(remaining, start=1):
if remaining_log.set_number != i:
remaining_log.set_number = i
self._session.add(remaining_log)
if remaining:
self._session.commit()
# Clean up orphaned session if no logs remain for ANY exercise
any_remaining = self._session.exec(
select(WorkoutLog).where(WorkoutLog.session_id == session_id) select(WorkoutLog).where(WorkoutLog.session_id == session_id)
).first() ).first()
if any_remaining is None: if remaining is None:
ws = self._session.get(WorkoutSession, session_id) ws = self._session.get(WorkoutSession, session_id)
if ws: if ws:
self._session.delete(ws) self._session.delete(ws)