lägg till stegträning-övning + v1.3.0
Andra guidade träningsövningen i Open Practice: konfigurera en stegserie (antal varv + lugnt/kontrollerat/snabbt per steg), förvalt till klassiska pyramiden. Training-sidan visar aktuellt steg, kvarvarande varv och en progress-pill per steg. När sekvensen är klar jämförs de två kontrollerade stegens snitt neutralt (t.ex. "+0.90s"), utan att kalla en försämring för trötthet. syncTrainingLedger sprider nu resten av det normaliserade training-objektet istället för att lista fält manuellt, så samma klass av bugg som drabbade Jämna varv inte kan upprepas för framtida fält. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
29
src/app.js
29
src/app.js
@@ -24,7 +24,7 @@ import { renderEventManagerMarkup } from "./event_manager_view.js";
|
||||
import { renderEventManagerView } from "./event_manager_controller.js";
|
||||
import { createDefaultAmmcConfigHelper, getManagedWsUrlHelper, loadAmmcConfigFromBackendHelper, saveAmmcConfigToBackendHelper, refreshAmmcStatusHelper, startManagedAmmcHelper, stopManagedAmmcHelper, applyPersistedStateHelper, hydrateFromBackendHelper, scheduleBackendSyncHelper, syncStateToBackendHelper, pingBackendHelper, checkAppVersionHelper, startAppVersionPollingHelper, startOverlaySyncHelper, startOverlayRotationHelper, startOverlayLiveRefreshHelper, ensureAudioContextHelper, playPassingBeepHelper, playFinishSirenHelper, playLeaderCueHelper, playStartCueHelper, playBestLapCueHelper, pushOverlayEventHelper, getSpeechVoicesHelper, speakTextHelper, announcePassingHelper, announceRaceStartedHelper, announceRaceFinishedHelper, handleSessionTimerTickHelper, tickClockHelper } from "./runtime_services.js";
|
||||
import { connectDecoderHelper, disconnectDecoderHelper, processDecoderMessageHelper } from "./decoder_runtime.js";
|
||||
import { normalizeTrainingState as normalizeTrainingStateLogic, syncTrainingLedger as syncTrainingLedgerLogic, buildDriverTrainingStats as buildDriverTrainingStatsLogic, buildDriverTimingChannelStats as buildDriverTimingChannelStatsLogic, buildDriverActivePracticeStats as buildDriverActivePracticeStatsLogic, buildEvenLapsProgress as buildEvenLapsProgressLogic, buildTrainingRecommendation as buildTrainingRecommendationLogic, getTrainingGoalProgress as getTrainingGoalProgressLogic, getNextTrainingMilestone as getNextTrainingMilestoneLogic, buildTrainingMissions as buildTrainingMissionsLogic, buildTrainingHighlights as buildTrainingHighlightsLogic, getClubTrainingGoalProgress as getClubTrainingGoalProgressLogic, buildTrainingPaceBuckets as buildTrainingPaceBucketsLogic, buildTrainingWeekdayStats as buildTrainingWeekdayStatsLogic, buildTrainingStintAnalysis as buildTrainingStintAnalysisLogic, buildTrainingMarkerComparisons as buildTrainingMarkerComparisonsLogic } from "./training_logic.js";
|
||||
import { normalizeTrainingState as normalizeTrainingStateLogic, syncTrainingLedger as syncTrainingLedgerLogic, buildDriverTrainingStats as buildDriverTrainingStatsLogic, buildDriverTimingChannelStats as buildDriverTimingChannelStatsLogic, buildDriverActivePracticeStats as buildDriverActivePracticeStatsLogic, buildEvenLapsProgress as buildEvenLapsProgressLogic, buildStepTrainingProgress as buildStepTrainingProgressLogic, buildTrainingRecommendation as buildTrainingRecommendationLogic, getTrainingGoalProgress as getTrainingGoalProgressLogic, getNextTrainingMilestone as getNextTrainingMilestoneLogic, buildTrainingMissions as buildTrainingMissionsLogic, buildTrainingHighlights as buildTrainingHighlightsLogic, getClubTrainingGoalProgress as getClubTrainingGoalProgressLogic, buildTrainingPaceBuckets as buildTrainingPaceBucketsLogic, buildTrainingWeekdayStats as buildTrainingWeekdayStatsLogic, buildTrainingStintAnalysis as buildTrainingStintAnalysisLogic, buildTrainingMarkerComparisons as buildTrainingMarkerComparisonsLogic } from "./training_logic.js";
|
||||
import { renderTrainingView } from "./training_views.js";
|
||||
import { importDriversCsv, importCarsCsv } from "./csv_import.js";
|
||||
|
||||
@@ -320,10 +320,11 @@ const syncTrainingLedger = () => {
|
||||
const buildDriverTrainingStats = (trainingState, driverId, classId = "") => buildDriverTrainingStatsLogic(trainingState, driverId, classId);
|
||||
const buildDriverActivePracticeStats = (trainingState, driverId, nowTs = Date.now(), classId = "") => buildDriverActivePracticeStatsLogic(trainingState, driverId, nowTs, classId);
|
||||
const buildEvenLapsProgress = (trainingState, driverId, classId, config, nowTs = Date.now()) => buildEvenLapsProgressLogic(trainingState, driverId, classId, config, nowTs);
|
||||
const buildStepTrainingProgress = (trainingState, driverId, classId, config, nowTs = Date.now()) => buildStepTrainingProgressLogic(trainingState, driverId, classId, config, nowTs);
|
||||
const buildTrainingRecommendation = (stats) => buildTrainingRecommendationLogic(stats);
|
||||
const getTrainingGoalProgress = (goal, stats) => getTrainingGoalProgressLogic(goal, stats);
|
||||
const getNextTrainingMilestone = (stats) => getNextTrainingMilestoneLogic(stats);
|
||||
const renderTraining = () => renderTrainingView({ state, dom, t, escapeHtml, formatLap, formatRaceClock, uid, saveState, syncStateToBackend, renderView, normalizeTrainingState, syncTrainingLedger, buildDriverTrainingStats, buildDriverTimingChannelStats: buildDriverTimingChannelStatsLogic, buildDriverActivePracticeStats, buildEvenLapsProgress, buildTrainingRecommendation, getTrainingGoalProgress, getNextTrainingMilestone, buildTrainingMissions: buildTrainingMissionsLogic, buildTrainingHighlights: buildTrainingHighlightsLogic, getClubTrainingGoalProgress: getClubTrainingGoalProgressLogic, buildTrainingPaceBuckets: buildTrainingPaceBucketsLogic, buildTrainingWeekdayStats: buildTrainingWeekdayStatsLogic, buildTrainingStintAnalysis: buildTrainingStintAnalysisLogic, buildTrainingMarkerComparisons: buildTrainingMarkerComparisonsLogic, getSelectedDriverId: () => selectedTrainingDriverId, setSelectedDriverId: (value) => { selectedTrainingDriverId = value; updateViewUrl("training", value, selectedTrainingClassId); }, getSelectedClassId: () => selectedTrainingClassId, setSelectedClassId: (value) => { selectedTrainingClassId = value; updateViewUrl("training", selectedTrainingDriverId, value); } });
|
||||
const renderTraining = () => renderTrainingView({ state, dom, t, escapeHtml, formatLap, formatRaceClock, uid, saveState, syncStateToBackend, renderView, normalizeTrainingState, syncTrainingLedger, buildDriverTrainingStats, buildDriverTimingChannelStats: buildDriverTimingChannelStatsLogic, buildDriverActivePracticeStats, buildEvenLapsProgress, buildStepTrainingProgress, buildTrainingRecommendation, getTrainingGoalProgress, getNextTrainingMilestone, buildTrainingMissions: buildTrainingMissionsLogic, buildTrainingHighlights: buildTrainingHighlightsLogic, getClubTrainingGoalProgress: getClubTrainingGoalProgressLogic, buildTrainingPaceBuckets: buildTrainingPaceBucketsLogic, buildTrainingWeekdayStats: buildTrainingWeekdayStatsLogic, buildTrainingStintAnalysis: buildTrainingStintAnalysisLogic, buildTrainingMarkerComparisons: buildTrainingMarkerComparisonsLogic, getSelectedDriverId: () => selectedTrainingDriverId, setSelectedDriverId: (value) => { selectedTrainingDriverId = value; updateViewUrl("training", value, selectedTrainingClassId); }, getSelectedClassId: () => selectedTrainingClassId, setSelectedClassId: (value) => { selectedTrainingClassId = value; updateViewUrl("training", selectedTrainingDriverId, value); } });
|
||||
const applyCompetitorCorrection = (session, row, options = {}) => {
|
||||
const result = applyCompetitorCorrectionLogic(session, row, options, { ensureSessionResult, uid, t, formatLap, saveState });
|
||||
if (!options.reset && ((Number(options.timeMsDelta || 0) > 0) || (Number(options.lapDelta || 0) < 0))) {
|
||||
@@ -647,6 +648,18 @@ const TRANSLATIONS = {
|
||||
"training.evenlaps_lapcount_label": "Antal varv i serien",
|
||||
"training.evenlaps_save": "Spara",
|
||||
"training.evenlaps_suggestion_hint": "Förslag baserat på ditt bästa varv: {lap}",
|
||||
"training.steptraining_eyebrow": "Övning",
|
||||
"training.steptraining_title": "Stegträning",
|
||||
"training.steptraining_hint": "Bygg din stegserie nedan för att börja. Standard är den klassiska pyramiden: lugnt, kontrollerat, snabbt, kontrollerat, lugnt.",
|
||||
"training.steptraining_complete": "Serien klar – bra jobbat!",
|
||||
"training.steptraining_current": "Steg {step}/{total}: {effort}",
|
||||
"training.steptraining_remaining": "{laps} varv kvar",
|
||||
"training.steptraining_controlled_compare": "Kontrollerat steg 1: {first} · Kontrollerat steg 2: {last} ({diff})",
|
||||
"training.steptraining_config_hint": "Ange 0 varv för att hoppa över ett steg. Lugnt/kontrollerat/snabbt är en känsla, inte en exakt tid – systemet kan inte mäta hur hårt du kör.",
|
||||
"training.steptraining_save": "Spara",
|
||||
"training.steptraining_effort_calm": "Lugnt",
|
||||
"training.steptraining_effort_controlled": "Kontrollerat",
|
||||
"training.steptraining_effort_fast": "Snabbt",
|
||||
"training.stints": "Stints",
|
||||
"training.best_three": "Bästa 3 sammanhängande",
|
||||
"training.best_five": "Bästa 5 min",
|
||||
@@ -2047,6 +2060,18 @@ const TRANSLATIONS = {
|
||||
"training.evenlaps_lapcount_label": "Laps in the streak",
|
||||
"training.evenlaps_save": "Save",
|
||||
"training.evenlaps_suggestion_hint": "Suggested from your best lap: {lap}",
|
||||
"training.steptraining_eyebrow": "Exercise",
|
||||
"training.steptraining_title": "Step training",
|
||||
"training.steptraining_hint": "Build your step sequence below to get started. The default is the classic pyramid: calm, controlled, fast, controlled, calm.",
|
||||
"training.steptraining_complete": "Sequence complete - nice work!",
|
||||
"training.steptraining_current": "Step {step}/{total}: {effort}",
|
||||
"training.steptraining_remaining": "{laps} laps remaining",
|
||||
"training.steptraining_controlled_compare": "Controlled step 1: {first} · Controlled step 2: {last} ({diff})",
|
||||
"training.steptraining_config_hint": "Set 0 laps to skip a step. Calm/controlled/fast is a feel, not an exact time - the system can't measure how hard you're pushing.",
|
||||
"training.steptraining_save": "Save",
|
||||
"training.steptraining_effort_calm": "Calm",
|
||||
"training.steptraining_effort_controlled": "Controlled",
|
||||
"training.steptraining_effort_fast": "Fast",
|
||||
"training.stints": "Stints",
|
||||
"training.best_three": "Best 3 consecutive",
|
||||
"training.best_five": "Best 5 min",
|
||||
|
||||
Reference in New Issue
Block a user