Add dropdown exercise selection to Doris Barbell logs
This commit is contained in:
@@ -53,6 +53,7 @@ The current scaffold already supports:
|
||||
- exercise template creation/listing
|
||||
- routine creation/listing on top of John's imported base split
|
||||
- structured workout logging with nested exercises and sets
|
||||
- dedicated routine log sheets with dropdown exercise selection plus set-by-set reps and weight entry
|
||||
- history endpoints for weight, measurements, and workouts
|
||||
- exercise progression summaries with max weight and estimated 1RM per exercise
|
||||
- mobile-friendly homepage with HTML forms for:
|
||||
|
||||
@@ -133,6 +133,7 @@ def routine_log_sheet(request: Request, routine_id: str):
|
||||
'title': f"Log {routine['name']}",
|
||||
'routine': routine,
|
||||
'routine_sheet': _build_routine_log_sheet(routine),
|
||||
'exercise_options': _exercise_options_for_routine(request, routine),
|
||||
'routine_action_label': _routine_action_label(routine['name']),
|
||||
'default_performed_at': _default_performed_at_value(),
|
||||
},
|
||||
@@ -285,6 +286,24 @@ def _build_routine_log_sheet(routine: dict) -> list[dict]:
|
||||
return sheet
|
||||
|
||||
|
||||
def _exercise_options_for_routine(request: Request, routine: dict) -> list[str]:
|
||||
routine_names = [exercise['exercise_name'] for exercise in routine.get('exercises', []) if exercise.get('exercise_name')]
|
||||
template_names = [
|
||||
template['name']
|
||||
for template in request.app.state.store.list_exercise_templates()
|
||||
if template.get('name')
|
||||
]
|
||||
ordered = []
|
||||
seen = set()
|
||||
for name in [*routine_names, *template_names]:
|
||||
normalized = name.strip().lower()
|
||||
if normalized in seen:
|
||||
continue
|
||||
ordered.append(name)
|
||||
seen.add(normalized)
|
||||
return ordered
|
||||
|
||||
|
||||
def _default_reps_value(target_reps: str | None) -> str:
|
||||
if target_reps is None:
|
||||
return ''
|
||||
|
||||
@@ -52,13 +52,18 @@
|
||||
|
||||
{% for exercise in routine_sheet %}
|
||||
<section class="evidence-slab">
|
||||
<input type="hidden" name="exercise_{{ exercise.exercise_index }}_name" value="{{ exercise.exercise_name }}">
|
||||
<input type="hidden" name="exercise_{{ exercise.exercise_index }}_set_count" value="{{ exercise.target_sets }}">
|
||||
<div class="case-legend">
|
||||
<span class="section-label">Exercise {{ loop.index }}</span>
|
||||
<span class="pill">{{ exercise.target_sets }} sets</span>
|
||||
</div>
|
||||
<h3>{{ exercise.exercise_name }}</h3>
|
||||
<label>Exercise
|
||||
<select name="exercise_{{ exercise.exercise_index }}_name">
|
||||
{% for option_name in exercise_options %}
|
||||
<option value="{{ option_name }}" {% if option_name == exercise.exercise_name %}selected{% endif %}>{{ option_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<p class="muted">Target reps: {{ exercise.target_reps or 'enter manually' }}</p>
|
||||
<div class="grid cols-2 compact-grid">
|
||||
{% for set in exercise.sets %}
|
||||
|
||||
@@ -388,6 +388,9 @@ def test_seeded_routine_can_render_prefilled_log_sheet(tmp_path: Path) -> None:
|
||||
assert 'Thursday: Shoulders' in body
|
||||
assert 'Shoulder Press' in body
|
||||
assert 'Save shoulder day workout' in body
|
||||
assert 'name="exercise_0_name"' in body
|
||||
assert '<option value="Shoulder Press" selected>' in body
|
||||
assert 'value="Upright Row"' in body
|
||||
assert 'name="exercise_0_set_0_reps"' in body
|
||||
assert 'name="exercise_0_set_0_weight_lbs"' in body
|
||||
assert 'value="10"' in body
|
||||
@@ -417,7 +420,7 @@ def test_seeded_routine_log_submission_creates_structured_workout(tmp_path: Path
|
||||
'exercise_0_set_1_weight_lbs': '80',
|
||||
'exercise_0_set_2_reps': '8',
|
||||
'exercise_0_set_2_weight_lbs': '90',
|
||||
'exercise_1_name': 'Arnold Press',
|
||||
'exercise_1_name': 'Upright Row',
|
||||
'exercise_1_set_count': '3',
|
||||
'exercise_1_set_0_reps': '10',
|
||||
'exercise_1_set_0_weight_lbs': '35',
|
||||
@@ -441,6 +444,7 @@ def test_seeded_routine_log_submission_creates_structured_workout(tmp_path: Path
|
||||
assert payload[0]['total_volume_lbs'] == 3240
|
||||
assert payload[0]['exercises'][0]['exercise_name'] == 'Shoulder Press'
|
||||
assert payload[0]['exercises'][0]['sets'][2] == {'reps': 8, 'weight_lbs': 90.0}
|
||||
assert payload[0]['exercises'][1]['exercise_name'] == 'Upright Row'
|
||||
|
||||
|
||||
def test_existing_state_gets_seeded_routine_backfill(tmp_path: Path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user