Enhance training framework with phase handling and payload adjustments
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m9s
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m9s
- Updated backend logic to include phases in training unit hydration and insertion processes, improving data integrity. - Modified frontend components to support phases in training framework slots, ensuring consistent data representation. - Refactored payload building functions to accommodate phases, enhancing the save functionality for training plans. - Improved user interface to enable controls for parallel phases, optimizing the user experience during training program edits.
This commit is contained in:
parent
76cc81a385
commit
6e1cc62065
|
|
@ -21,6 +21,7 @@ from routers.training_planning import (
|
|||
_hydrate_training_unit_payload,
|
||||
_optional_positive_int,
|
||||
_insert_sections_from_legacy_exercises,
|
||||
_replace_unit_phases,
|
||||
_replace_unit_sections,
|
||||
_validate_variant_for_exercise,
|
||||
)
|
||||
|
|
@ -132,6 +133,7 @@ def _hydrate_framework(cur, row: Dict[str, Any]) -> Dict[str, Any]:
|
|||
row_b = cur.fetchone()
|
||||
if not row_b:
|
||||
s["blueprint_training_unit_id"] = None
|
||||
s["phases"] = []
|
||||
s["sections"] = []
|
||||
s["exercises"] = []
|
||||
continue
|
||||
|
|
@ -139,6 +141,7 @@ def _hydrate_framework(cur, row: Dict[str, Any]) -> Dict[str, Any]:
|
|||
s["blueprint_training_unit_id"] = uid
|
||||
unit_min: Dict[str, Any] = {"id": uid}
|
||||
_hydrate_training_unit_payload(cur, unit_min)
|
||||
s["phases"] = unit_min.get("phases", [])
|
||||
s["sections"] = unit_min.get("sections", [])
|
||||
s["exercises"] = unit_min.get("exercises", [])
|
||||
row["slots"] = slots
|
||||
|
|
@ -250,6 +253,7 @@ def _insert_slots_and_blueprints(
|
|||
framework_id: int,
|
||||
slots_in: Optional[List[Any]],
|
||||
profile_id: int,
|
||||
role: str,
|
||||
) -> None:
|
||||
if slots_in is None:
|
||||
return
|
||||
|
|
@ -296,10 +300,13 @@ def _insert_slots_and_blueprints(
|
|||
)
|
||||
bid = cur.fetchone()["id"]
|
||||
|
||||
phases_in = slot.get("phases")
|
||||
sections_in = slot.get("sections")
|
||||
exercises_in = slot.get("exercises")
|
||||
|
||||
if sections_in is not None:
|
||||
if phases_in is not None and isinstance(phases_in, list) and len(phases_in) > 0:
|
||||
_replace_unit_phases(cur, bid, phases_in, profile_id, role, profile_id)
|
||||
elif sections_in is not None:
|
||||
if len(sections_in) == 0:
|
||||
_insert_default_blueprint_section(cur, bid)
|
||||
else:
|
||||
|
|
@ -432,7 +439,7 @@ def create_training_framework_program(
|
|||
)
|
||||
fid = cur.fetchone()["id"]
|
||||
_insert_goal_rows(cur, fid, goals_in)
|
||||
_insert_slots_and_blueprints(cur, fid, slots_in, profile_id)
|
||||
_insert_slots_and_blueprints(cur, fid, slots_in, profile_id, role)
|
||||
_replace_training_types(cur, fid, tt_ids)
|
||||
_replace_target_groups(cur, fid, tg_ids)
|
||||
conn.commit()
|
||||
|
|
@ -543,7 +550,9 @@ def update_training_framework_program(
|
|||
"DELETE FROM training_framework_slots WHERE framework_program_id = %s",
|
||||
(framework_id,),
|
||||
)
|
||||
_insert_slots_and_blueprints(cur, framework_id, data.get("slots") or [], profile_id)
|
||||
_insert_slots_and_blueprints(
|
||||
cur, framework_id, data.get("slots") or [], profile_id, role
|
||||
)
|
||||
|
||||
if header_fields or "goals" in data or "slots" in data or "training_type_ids" in data or "target_group_ids" in data:
|
||||
cur.execute(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
defaultSection,
|
||||
normalizeUnitToForm,
|
||||
enrichSectionsWithVariants,
|
||||
buildSectionsPayload,
|
||||
buildPlanPayloadForSave,
|
||||
hydrateExercisePlanningRow,
|
||||
reorderBlockIntoParallelStreamEnd,
|
||||
} from '../utils/trainingUnitSectionsForm'
|
||||
|
|
@ -48,7 +48,11 @@ function emptySlot() {
|
|||
async function enrichFrameworkSlotSections(slots) {
|
||||
const out = []
|
||||
for (const s of slots || []) {
|
||||
const sec = normalizeUnitToForm({ sections: s.sections, exercises: s.exercises })
|
||||
const sec = normalizeUnitToForm({
|
||||
sections: s.sections,
|
||||
exercises: s.exercises,
|
||||
phases: s.phases,
|
||||
})
|
||||
out.push({
|
||||
...s,
|
||||
sections: await enrichSectionsWithVariants(sec),
|
||||
|
|
@ -132,7 +136,11 @@ function serverFrameworkToForm(fw) {
|
|||
slots: (fw.slots || []).map((s) => ({
|
||||
title: s.title || '',
|
||||
notes: s.notes || '',
|
||||
sections: normalizeUnitToForm({ sections: s.sections, exercises: s.exercises }),
|
||||
sections: normalizeUnitToForm({
|
||||
sections: s.sections,
|
||||
exercises: s.exercises,
|
||||
phases: s.phases,
|
||||
}),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
|
@ -151,13 +159,16 @@ function buildApiPayload(form) {
|
|||
|
||||
const slots = (form.slots || []).map((s, si) => {
|
||||
const secList = s.sections && s.sections.length ? s.sections : [defaultSection('Ablauf')]
|
||||
const sectionsPayload = buildSectionsPayload(secList)
|
||||
return {
|
||||
const plan = buildPlanPayloadForSave(secList)
|
||||
const base = {
|
||||
sort_order: si,
|
||||
title: (s.title || '').trim() || null,
|
||||
notes: (s.notes || '').trim() || null,
|
||||
sections: sectionsPayload,
|
||||
}
|
||||
if (plan.phases) {
|
||||
return { ...base, phases: plan.phases }
|
||||
}
|
||||
return { ...base, sections: plan.sections }
|
||||
})
|
||||
|
||||
const focusAreaId =
|
||||
|
|
@ -710,6 +721,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
showExecutionExtras={false}
|
||||
wideExerciseGrid
|
||||
slotIndex={si}
|
||||
enableParallelPhaseControls
|
||||
onMoveSectionsAcrossSlots={moveSectionsAcrossFrameworkSlots}
|
||||
onSectionsChange={(updater) => {
|
||||
setForm((prev) => ({
|
||||
|
|
@ -774,7 +786,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
<strong style={{ color: 'var(--text1)' }}>Rahmenprogramm (Bibliothek):</strong> Wiederverwendbare Vorlage mit
|
||||
Zielen und Session‑Slots. Die <strong>Zuordnung zu Gruppe oder Kalendertermin</strong> erfolgt aus der{' '}
|
||||
<strong>Gruppen‑Planung</strong> („Übernahme“). Pro Slot planst du den Ablauf wie bei einer Trainingsseinheit:{' '}
|
||||
<strong>Abschnitte</strong>, Übungen mit Varianten und Dauer, <strong>Zwischen‑Anmerkungen</strong>.
|
||||
<strong>Abschnitte</strong>, optional <strong>Ganzgruppen- und parallele Phasen (Breakout)</strong>, Übungen mit Varianten und Dauer, <strong>Zwischen‑Anmerkungen</strong>. Abschnitte kannst du per Ziehen auch in eine andere Session legen.
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user