Improve decoder setup UI and add configurable training timers

This commit is contained in:
larssand
2026-08-27 17:29:44 +02:00
parent 32acc0e9c7
commit a87c64a47c
8 changed files with 493 additions and 57 deletions

View File

@@ -308,13 +308,16 @@ const TRANSLATIONS = {
"training.plan_baseline_title": "Bygg en baslinje",
"training.plan_baseline_body": "Kör lugnt och jämnt tills minst 10 rena varv är registrerade. Fokusera på samma linje och bromspunkt varje varv.",
"training.plan_consistency_title": "Höj din lägstanivå",
"training.plan_consistency_body": "Spridningen är hög. Kör först 10 minuter nära max, sedan 10 minuter på 80-90 procent där rena, repeterbara varv är viktigare än ett enstaka snabbt varv.",
"training.plan_consistency_body": "Spridningen är hög. Kör första blocket nära max, sedan ett kontrollerat block på 80-90 procent där rena, repeterbara varv är viktigare än ett enstaka snabbt varv.",
"training.plan_progression_title": "Balansera fart och kontroll",
"training.plan_progression_body": "Du har en stabil grund. Kör 10 minuter med maxfokus och avsluta med 10 minuter kontrollerad körning där målet är en obruten serie jämna varv.",
"training.plan_progression_body": "Du har en stabil grund. Kör ett block med maxfokus och avsluta med ett kontrollerat block där målet är en obruten serie jämna varv.",
"training.plan_target": "Kontrollmål omkring {lap}",
"training.plan_no_target": "Registrera fler varv för tidsmål",
"training.block_push": "Maxfokus: hitta gränsen",
"training.block_control": "80-90%: höj lägstanivån",
"training.flexible_duration": "Valbar tid",
"training.block_one": "Block 1",
"training.block_two": "Block 2",
"training.new_goal": "Nytt delmål",
"training.manage_goals_sharing": "Mål och mobilprofil",
"training.manage_goals_sharing_hint": "Skapa belöningsmål eller hantera förarens delningslänk.",
@@ -361,7 +364,7 @@ const TRANSLATIONS = {
"training.public_profile": "Mobilprofil för förare",
"training.public_profile_active": "Aktiv",
"training.public_profile_off": "Avstängd",
"training.public_profile_help": "Skapa en skrivskyddad mobilvy med den här förarens träningsstatistik, mål, belöningar och 20-minuterstimer.",
"training.public_profile_help": "Skapa en skrivskyddad mobilvy med den här förarens träningsstatistik, mål, belöningar och valbara träningstimer.",
"training.public_profile_private": "Länken innehåller en unik hemlig nyckel. Den visar inte transponder-ID, övriga förare eller adminfunktioner.",
"training.public_profile_link": "Personlig delningslänk",
"training.copy_link": "Kopiera länk",
@@ -800,6 +803,7 @@ const TRANSLATIONS = {
"timing.last_message": "Senaste meddelande",
"timing.main_decoder": "Main start/mål",
"timing.split_decoder": "Mellantid",
"timing.pit_decoders": "Depå in/ut",
"timing.pit_entry_decoder": "Depå in",
"timing.pit_exit_decoder": "Depå ut",
"timing.pit_active": "I DEPÅ",
@@ -907,6 +911,20 @@ const TRANSLATIONS = {
"settings.split_ws_url": "Mellantid WebSocket-url",
"settings.enable_pit_decoders": "Aktivera depådecoders",
"settings.decoder_roles_hint": "Klientens WebSocket-url ska använda backend-datorns IP, inte den fysiska decoderns IP. Main räknar varv; mellantid och depå gör det aldrig.",
"settings.decoder_setup_title": "Välj decoderinstallation",
"settings.decoder_setup_hint": "Välj ett snabbval så bockas rätt extrakanaler i. Main används alltid. Kontrollera URL:erna och klicka sedan Spara.",
"settings.decoder_layout_main": "1 decoder: Main",
"settings.decoder_layout_split": "2 decoders: Main + mellantid",
"settings.decoder_layout_pit": "3 decoders: Main + depå",
"settings.decoder_layout_full": "4 decoders: Komplett",
"settings.role_required": "Obligatorisk",
"settings.role_enabled": "Aktiverad",
"settings.role_disabled": "Avstängd",
"settings.main_role_hint": "Start/mål. Den enda kanalen som räknar varv.",
"settings.split_role_hint": "En extra fysisk decoder för mellantid. Räknar aldrig varv.",
"settings.pit_role_hint": "Kräver två extra fysiska decoders: en vid depå in och en vid depå ut.",
"settings.connection_title": "Backend och anslutning",
"settings.backend_url_hint": "Webb/API på datorn som kör npm start, normalt port 8081.",
"settings.managed_channels_hint": "Fälten Decoder IP / host nedan är de fysiska decodrarnas adresser. Backend startar en AMMC-process per roll på unika portar: main 9000, mellantid 9001, depå in 9002 och depå ut 9003.",
"settings.pit_entry_ws_url": "Depå in WebSocket-url",
"settings.pit_exit_ws_url": "Depå ut WebSocket-url",
@@ -1183,10 +1201,10 @@ const TRANSLATIONS = {
"guide.training_5": "5. När målet nåtts kan belöningen markeras som utdelad. Direktlänken `/?view=training&driver=<id>` kan bokmärkas på förarens mobil.",
"guide.training_6": "6. Träningsloggen uppdateras av domarkorrigeringar medan sessionen finns, men behålls när sessionen senare raderas. Full dataexport i Inställningar inkluderar både logg och mål.",
"guide.training_7": "7. Öppna Mål och mobilprofil och klicka Aktivera mobilprofil. Kopiera den personliga länken och öppna den på förarens eller förälderns mobil.",
"guide.training_8": "8. Mobilprofilen är skrivskyddad och visar bara vald förares statistik. Den lokala 20-minuterstimern växlar från 10 minuter maxfokus till 10 minuter kontrollerad körning och visar förarens varv, bästa varv och snitt under det egna passet.",
"guide.training_8": "8. Mobilprofilen är skrivskyddad och visar bara vald förares statistik. Föraren väljer själv minuter för blocken Maxfokus och Kontrollerad körning; timern visar förarens varv, bästa varv och snitt under det egna passet.",
"guide.training_9": "9. Klicka Skapa ny länk eller Stäng av profil om länken spridits fel. Publicera bara `/public-training/*`, `/src/public_training.js` och `/src/public_training.css` externt, aldrig hela admin-sidan eller `/api/state`.",
"guide.training_10": "10. När Open Practice, Free Practice eller Practice pågår visar Träning ett livekort för vald förare med varv, bästa varv, snitt och senaste varv. Alla förare kör fortfarande i samma gemensamma session.",
"guide.training_11": "11. Knappen högst upp skapar eller öppnar den valda förarens personliga mobillänk. Föraren startar sin egen 20-minuterstimer i mobilen utan att starta om eller påverka den gemensamma practice-sessionen.",
"guide.training_11": "11. Knappen högst upp skapar eller öppnar den valda förarens personliga mobillänk. Föraren ställer in och startar sin egen timer i mobilen utan att starta om eller påverka den gemensamma practice-sessionen. Tiden sparas separat per förare och klass.",
"guide.training_12": "12. Ett glapp över 2 minuter mellan passeringar startar automatiskt en ny stint. Ett långt pausvarv används som gräns men räknas inte som prestationsvarv i stintstatistiken.",
"guide.training_13": "13. Bästa 5 min använder 300 sekunder. Ett slutvarv räknas om det startade före 5:00 även om målgången sker efter tiden, exempelvis 17/05:14.12:123. Avg pace visas för varven i just det resultatet.",
"guide.training_14": "14. En personlig profil och mobillänk kan innehålla flera klasser, men 2WD/4WD-statistik, stints, varvtider och rekommendationer visas alltid separat per vald klass.",
@@ -1344,13 +1362,16 @@ const TRANSLATIONS = {
"training.plan_baseline_title": "Build a baseline",
"training.plan_baseline_body": "Drive calmly and consistently until at least 10 clean laps are recorded. Repeat the same line and braking point every lap.",
"training.plan_consistency_title": "Raise your minimum level",
"training.plan_consistency_body": "Lap spread is high. Run 10 minutes near maximum pace, then 10 minutes at 80-90 percent where clean, repeatable laps matter more than one fast lap.",
"training.plan_consistency_body": "Lap spread is high. Run the first block near maximum pace, then a controlled block at 80-90 percent where clean, repeatable laps matter more than one fast lap.",
"training.plan_progression_title": "Balance pace and control",
"training.plan_progression_body": "You have a stable baseline. Run 10 minutes at maximum focus and finish with 10 controlled minutes aiming for an unbroken sequence of consistent laps.",
"training.plan_progression_body": "You have a stable baseline. Run one block at maximum focus and finish with a controlled block aiming for an unbroken sequence of consistent laps.",
"training.plan_target": "Control target around {lap}",
"training.plan_no_target": "Record more laps to calculate a target",
"training.block_push": "Maximum focus: find the limit",
"training.block_control": "80-90%: raise the floor",
"training.flexible_duration": "Custom time",
"training.block_one": "Block 1",
"training.block_two": "Block 2",
"training.new_goal": "New milestone",
"training.manage_goals_sharing": "Goals and mobile profile",
"training.manage_goals_sharing_hint": "Create reward goals or manage the driver's share link.",
@@ -1397,7 +1418,7 @@ const TRANSLATIONS = {
"training.public_profile": "Driver mobile profile",
"training.public_profile_active": "Active",
"training.public_profile_off": "Disabled",
"training.public_profile_help": "Create a read-only mobile view with this driver's practice statistics, goals, rewards and 20-minute timer.",
"training.public_profile_help": "Create a read-only mobile view with this driver's practice statistics, goals, rewards and configurable practice timer.",
"training.public_profile_private": "The link contains a unique secret key. It does not show transponder IDs, other drivers or admin controls.",
"training.public_profile_link": "Personal share link",
"training.copy_link": "Copy link",
@@ -1836,6 +1857,7 @@ const TRANSLATIONS = {
"timing.last_message": "Last message",
"timing.main_decoder": "Main start/finish",
"timing.split_decoder": "Split timing",
"timing.pit_decoders": "Pit entry/exit",
"timing.pit_entry_decoder": "Pit entry",
"timing.pit_exit_decoder": "Pit exit",
"timing.pit_active": "IN PIT",
@@ -1943,6 +1965,20 @@ const TRANSLATIONS = {
"settings.split_ws_url": "Split WebSocket URL",
"settings.enable_pit_decoders": "Enable pit decoders",
"settings.decoder_roles_hint": "Client WebSocket URLs must use the backend host IP, not a physical decoder IP. Main counts laps; split and pit channels never do.",
"settings.decoder_setup_title": "Choose decoder setup",
"settings.decoder_setup_hint": "Choose a preset to enable the correct extra channels. Main is always used. Check the URLs, then click Save.",
"settings.decoder_layout_main": "1 decoder: Main",
"settings.decoder_layout_split": "2 decoders: Main + split",
"settings.decoder_layout_pit": "3 decoders: Main + pit",
"settings.decoder_layout_full": "4 decoders: Full system",
"settings.role_required": "Required",
"settings.role_enabled": "Enabled",
"settings.role_disabled": "Disabled",
"settings.main_role_hint": "Start/finish. The only channel that counts laps.",
"settings.split_role_hint": "One additional physical decoder for split timing. It never counts laps.",
"settings.pit_role_hint": "Requires two additional physical decoders: one at pit entry and one at pit exit.",
"settings.connection_title": "Backend and connection",
"settings.backend_url_hint": "Web/API on the computer running npm start, normally port 8081.",
"settings.managed_channels_hint": "Decoder IP / host fields below are physical decoder addresses. The backend starts one AMMC process per role on unique ports: main 9000, split 9001, pit entry 9002, and pit exit 9003.",
"settings.pit_entry_ws_url": "Pit entry WebSocket URL",
"settings.pit_exit_ws_url": "Pit exit WebSocket URL",
@@ -2219,10 +2255,10 @@ const TRANSLATIONS = {
"guide.training_5": "5. When a target is reached, mark its reward as delivered. Bookmark `/?view=training&driver=<id>` on the driver's phone for direct access.",
"guide.training_6": "6. The training ledger follows judging corrections while the source session exists, but remains when that session is later deleted. Full data export in Settings includes both ledger and goals.",
"guide.training_7": "7. Open Goals and mobile profile, then click Enable mobile profile. Copy the personal link and open it on the driver's or parent's phone.",
"guide.training_8": "8. The mobile profile is read-only and only shows the selected driver's statistics. Its local 20-minute timer changes from 10 minutes maximum focus to 10 minutes controlled driving and shows the driver's laps, best lap and average during that personal session.",
"guide.training_8": "8. The mobile profile is read-only and only shows the selected driver's statistics. The driver chooses minutes for Maximum focus and Controlled driving; the timer shows that driver's laps, best lap and average during the personal session.",
"guide.training_9": "9. Click Create new link or Disable profile if the link is shared incorrectly. Expose only `/public-training/*`, `/src/public_training.js` and `/src/public_training.css` externally, never the full admin site or `/api/state`.",
"guide.training_10": "10. While Open Practice, Free Practice, or Practice is running, Training shows a live card for the selected driver with laps, best lap, average, and latest lap. Every driver still uses the same shared session.",
"guide.training_11": "11. The top action creates or opens the selected driver's personal mobile link. The driver starts an individual 20-minute timer on the phone without restarting or changing the shared practice session.",
"guide.training_11": "11. The top action creates or opens the selected driver's personal mobile link. The driver configures and starts an individual timer on the phone without restarting or changing the shared practice session. Time is stored separately per driver and class.",
"guide.training_12": "12. A gap longer than 2 minutes between passings automatically starts a new stint. A long return lap defines the boundary but is excluded from stint performance metrics.",
"guide.training_13": "13. Best 5 min uses 300 seconds. A final lap counts when it started before 5:00 even if it finishes later, for example 17/05:14.12:123. Average pace is calculated from the laps in that exact result.",
"guide.training_14": "14. One personal profile and mobile link can contain several classes, but 2WD/4WD statistics, stints, lap times, and recommendations are always shown separately for the selected class.",