lägg till jämna varv-övning + v1.2.0
Ny guidad träningsövning i Open Practice: sätt måltid, tolerans och antal varv, se aktuell serie och dagens bästa live på Training-sidan. Ett missat varv startar en ny serie utan att radera bästa resultatet. Hittade och fixade två buggar under vägen: - syncTrainingLedger byggde om training-state vid varje sparning utan att föra vidare det nya evenLaps-fältet, så sparade konfigurationer försvann direkt - Training-sidan kraschade för alla förare med färre än 3 varv i varje stint (t.ex. de första varven i ett pass) eftersom en dedupe-funktion läste en egenskap på ett null-värde Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
33
src/app.js
33
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, 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, 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";
|
||||
|
||||
@@ -319,10 +319,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 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, 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, 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))) {
|
||||
@@ -632,6 +633,20 @@ const TRANSLATIONS = {
|
||||
"training.session_laps": "Varv i passet",
|
||||
"training.latest_lap": "Senaste varv",
|
||||
"training.live_practice_hint": "Alla kan fortsätta köra i samma Open/Free Practice. Kortet visar bara den valda förarens giltiga varv sedan den aktuella sessionen startades.",
|
||||
"training.evenlaps_eyebrow": "Övning",
|
||||
"training.evenlaps_title": "Jämna varv",
|
||||
"training.evenlaps_hint": "Ställ in en måltid och tolerans nedan för att börja. Varje varv inom toleransen bygger på serien.",
|
||||
"training.evenlaps_streak": "{current}/{target} jämna varv",
|
||||
"training.evenlaps_new_streak": "Ny serie – försök slå din bästa",
|
||||
"training.evenlaps_start_hint": "Kör ditt första varv för att starta en serie.",
|
||||
"training.evenlaps_best_today": "Bästa serie idag: {best}",
|
||||
"training.evenlaps_target": "Måltid",
|
||||
"training.evenlaps_last_lap": "Senaste varv",
|
||||
"training.evenlaps_target_label": "Måltid (sekunder)",
|
||||
"training.evenlaps_tolerance_label": "Tolerans ± (sekunder)",
|
||||
"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.stints": "Stints",
|
||||
"training.best_three": "Bästa 3 sammanhängande",
|
||||
"training.best_five": "Bästa 5 min",
|
||||
@@ -2018,6 +2033,20 @@ const TRANSLATIONS = {
|
||||
"training.session_laps": "Session laps",
|
||||
"training.latest_lap": "Latest lap",
|
||||
"training.live_practice_hint": "Everyone can keep driving in the same Open/Free Practice. This card shows only the selected driver's valid laps since the current session started.",
|
||||
"training.evenlaps_eyebrow": "Exercise",
|
||||
"training.evenlaps_title": "Even laps",
|
||||
"training.evenlaps_hint": "Set a target lap time and tolerance below to get started. Every lap within tolerance extends the streak.",
|
||||
"training.evenlaps_streak": "{current}/{target} even laps",
|
||||
"training.evenlaps_new_streak": "New streak - try to beat your best",
|
||||
"training.evenlaps_start_hint": "Run your first lap to start a streak.",
|
||||
"training.evenlaps_best_today": "Best streak today: {best}",
|
||||
"training.evenlaps_target": "Target",
|
||||
"training.evenlaps_last_lap": "Latest lap",
|
||||
"training.evenlaps_target_label": "Target lap time (seconds)",
|
||||
"training.evenlaps_tolerance_label": "Tolerance ± (seconds)",
|
||||
"training.evenlaps_lapcount_label": "Laps in the streak",
|
||||
"training.evenlaps_save": "Save",
|
||||
"training.evenlaps_suggestion_hint": "Suggested from your best lap: {lap}",
|
||||
"training.stints": "Stints",
|
||||
"training.best_three": "Best 3 consecutive",
|
||||
"training.best_five": "Best 5 min",
|
||||
|
||||
Reference in New Issue
Block a user