fix: renumber sets after delete and use last-logged values for prefill #2

Merged
ptarrant merged 1 commits from feature/auto-populate-suggestions into master 2026-02-24 21:56:32 +00:00
2 changed files with 62 additions and 21 deletions
Showing only changes of commit 2208f0492b - Show all commits

View File

@@ -23,6 +23,30 @@ logger = structlog.get_logger(__name__)
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)
async def log_set(
request: Request,
@@ -80,10 +104,9 @@ async def log_set(
# Return updated logs for this exercise
logs = log_service.list_logs_for_exercise(ws.id, exercise_id)
next_set = len(logs) + 1
# Fetch suggestion for pre-filling the next set form
progression = ProgressionService(session)
suggestion = progression.get_suggestion(active_profile_id, exercise_id)
suggested_reps, suggested_weight = _get_prefill_values(
logs, session, active_profile_id, exercise_id,
)
templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", {
@@ -93,8 +116,8 @@ async def log_set(
"workout_day_id": workout_day_id,
"next_set": next_set,
"session_id": ws.id,
"suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggestion.get("suggested_weight"),
"suggested_reps": suggested_reps,
"suggested_weight": suggested_weight,
})
@@ -131,12 +154,12 @@ async def edit_log(
logs = log_service.list_logs_for_exercise(log.session_id, log.exercise_id)
next_set = len(logs) + 1
# Fetch suggestion for pre-filling the next set form
active_profile_id = get_active_profile_id(request)
suggestion = {}
suggested_reps, suggested_weight = None, None
if active_profile_id:
progression = ProgressionService(session)
suggestion = progression.get_suggestion(active_profile_id, log.exercise_id)
suggested_reps, suggested_weight = _get_prefill_values(
logs, session, active_profile_id, log.exercise_id,
)
templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", {
@@ -146,8 +169,8 @@ async def edit_log(
"workout_day_id": 0,
"next_set": next_set,
"session_id": log.session_id,
"suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggestion.get("suggested_weight"),
"suggested_reps": suggested_reps,
"suggested_weight": suggested_weight,
})
@@ -180,12 +203,12 @@ async def delete_log(
logs = log_service.list_logs_for_exercise(session_id, exercise_id)
next_set = len(logs) + 1
# Fetch suggestion for pre-filling the next set form
active_profile_id = get_active_profile_id(request)
suggestion = {}
suggested_reps, suggested_weight = None, None
if active_profile_id:
progression = ProgressionService(session)
suggestion = progression.get_suggestion(active_profile_id, exercise_id)
suggested_reps, suggested_weight = _get_prefill_values(
logs, session, active_profile_id, exercise_id,
)
templates = request.app.state.templates
return templates.TemplateResponse("partials/log_entry.html", {
@@ -195,8 +218,8 @@ async def delete_log(
"workout_day_id": 0,
"next_set": next_set,
"session_id": session_id,
"suggested_reps": suggestion.get("suggested_reps"),
"suggested_weight": suggestion.get("suggested_weight"),
"suggested_reps": suggested_reps,
"suggested_weight": suggested_weight,
})
return HTMLResponse("")

View File

@@ -149,7 +149,8 @@ class LogService:
def delete_log(self, log_id: int) -> None:
"""Delete a log entry.
Removes the log and cleans up the parent session if no logs remain.
Removes the log, renumbers remaining sets, and cleans up the
parent session if no logs remain.
Args:
log_id: The log entry ID.
@@ -162,15 +163,32 @@ class LogService:
raise ValueError(f"WorkoutLog with id {log_id} not found")
session_id = log.session_id
exercise_id = log.exercise_id
self._session.delete(log)
self._session.commit()
logger.info("log_deleted", log_id=log_id)
# Clean up orphaned session if no logs remain
# Renumber remaining sets so they stay sequential (1, 2, 3...)
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)
).first()
if remaining is None:
if any_remaining is None:
ws = self._session.get(WorkoutSession, session_id)
if ws:
self._session.delete(ws)