fix event
This commit is contained in:
121
src/app.js
121
src/app.js
@@ -13,6 +13,10 @@ const NAV_ITEMS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const SESSION_TYPES = ["open_practice", "free_practice", "practice", "qualification", "heat", "final", "team_race"];
|
const SESSION_TYPES = ["open_practice", "free_practice", "practice", "qualification", "heat", "final", "team_race"];
|
||||||
|
|
||||||
|
function getSessionTypeChoices(mode) {
|
||||||
|
return mode === "track" ? SESSION_TYPES.filter((type) => type !== "team_race") : SESSION_TYPES;
|
||||||
|
}
|
||||||
const STORAGE_KEY = "rc_timing_control_v1";
|
const STORAGE_KEY = "rc_timing_control_v1";
|
||||||
const DEFAULT_LANGUAGE = "sv";
|
const DEFAULT_LANGUAGE = "sv";
|
||||||
const DEFAULT_THEME = "dark";
|
const DEFAULT_THEME = "dark";
|
||||||
@@ -385,6 +389,24 @@ const TRANSLATIONS = {
|
|||||||
"events.print_team_results": "Skriv ut lagrapport",
|
"events.print_team_results": "Skriv ut lagrapport",
|
||||||
"events.pdf_team_results": "PDF lagrapport",
|
"events.pdf_team_results": "PDF lagrapport",
|
||||||
"events.add_session": "Lägg till session",
|
"events.add_session": "Lägg till session",
|
||||||
|
"events.session_type_label": "Sessionstyp",
|
||||||
|
"events.session_type_hint_track": "Välj vilken del av sponsor-eventet du skapar: träning, kval, heat eller final. Eventet i sig är redan ett sponsor-event.",
|
||||||
|
"events.session_type_hint_race": "Välj vilken session i racet du skapar: träning, kval, heat, final eller lagrace.",
|
||||||
|
"events.session_duration_label": "Längd (min)",
|
||||||
|
"events.session_duration_hint": "Ordinarie körtid för sessionen i minuter.",
|
||||||
|
"events.session_followup_label": "Follow-up (sek)",
|
||||||
|
"events.session_followup_hint": "Extra tid efter ordinarie sluttid så sista bilarna kan fullfölja.",
|
||||||
|
"events.session_start_mode_label": "Starttyp",
|
||||||
|
"events.session_start_mode_hint": "Mass-start, positionsstart eller individuell staggered start.",
|
||||||
|
"events.session_seed_laps_label": "Seedning bästa varv",
|
||||||
|
"events.session_seed_laps_hint": "0 = av. Använd 2 eller 3 för practice/kval-seedning.",
|
||||||
|
"events.session_seed_method_label": "Seedmetod",
|
||||||
|
"events.session_seed_method_hint": "Hur de bästa varven ska räknas: summa, snitt eller följdvarv.",
|
||||||
|
"events.session_stagger_gap_label": "Stagger-gap (sek)",
|
||||||
|
"events.session_stagger_gap_hint": "Används bara för staggered start. 0 = ingen extra lucka.",
|
||||||
|
"events.session_max_cars_label": "Max bilar (valfritt)",
|
||||||
|
"events.session_max_cars_hint": "Sätt gräns om just den sessionen bara ska ha ett visst antal bilar.",
|
||||||
|
"events.edit_session_help": "Ändra sessionens namn, typ, tid och seed-/startinställningar här.",
|
||||||
"events.set_active": "Sätt aktiv",
|
"events.set_active": "Sätt aktiv",
|
||||||
"events.assignments": "Tilldelningar",
|
"events.assignments": "Tilldelningar",
|
||||||
"events.na": "ej relevant",
|
"events.na": "ej relevant",
|
||||||
@@ -1174,6 +1196,24 @@ const TRANSLATIONS = {
|
|||||||
"events.print_team_results": "Print team report",
|
"events.print_team_results": "Print team report",
|
||||||
"events.pdf_team_results": "PDF team report",
|
"events.pdf_team_results": "PDF team report",
|
||||||
"events.add_session": "Add Session",
|
"events.add_session": "Add Session",
|
||||||
|
"events.session_type_label": "Session type",
|
||||||
|
"events.session_type_hint_track": "Choose which part of the sponsor event you are creating: practice, qualifying, heat or final. The event itself is already a sponsor event.",
|
||||||
|
"events.session_type_hint_race": "Choose which race session you are creating: practice, qualifying, heat, final or team race.",
|
||||||
|
"events.session_duration_label": "Duration (min)",
|
||||||
|
"events.session_duration_hint": "Main running time for the session in minutes.",
|
||||||
|
"events.session_followup_label": "Follow-up (sec)",
|
||||||
|
"events.session_followup_hint": "Extra time after the main timer so the last cars can finish.",
|
||||||
|
"events.session_start_mode_label": "Start mode",
|
||||||
|
"events.session_start_mode_hint": "Mass start, position start or individual staggered start.",
|
||||||
|
"events.session_seed_laps_label": "Seed best laps",
|
||||||
|
"events.session_seed_laps_hint": "0 = off. Use 2 or 3 for practice/qualifying seeding.",
|
||||||
|
"events.session_seed_method_label": "Seed method",
|
||||||
|
"events.session_seed_method_hint": "How to count the best laps: sum, average or consecutive laps.",
|
||||||
|
"events.session_stagger_gap_label": "Stagger gap (sec)",
|
||||||
|
"events.session_stagger_gap_hint": "Only used for staggered starts. 0 = no extra gap.",
|
||||||
|
"events.session_max_cars_label": "Max cars (optional)",
|
||||||
|
"events.session_max_cars_hint": "Set a limit if this session should only allow a certain number of cars.",
|
||||||
|
"events.edit_session_help": "Edit the session name, type, timing and seed/start settings here.",
|
||||||
"events.set_active": "Set Active",
|
"events.set_active": "Set Active",
|
||||||
"events.assignments": "Assignments",
|
"events.assignments": "Assignments",
|
||||||
"events.na": "n/a",
|
"events.na": "n/a",
|
||||||
@@ -4300,6 +4340,8 @@ function renderEventManager(eventId) {
|
|||||||
.join("");
|
.join("");
|
||||||
const branding = normalizeBrandingConfig(event.branding);
|
const branding = normalizeBrandingConfig(event.branding);
|
||||||
const editingSession = sessions.find((session) => session.id === selectedSessionEditId) || null;
|
const editingSession = sessions.find((session) => session.id === selectedSessionEditId) || null;
|
||||||
|
const sessionTypeChoices = getSessionTypeChoices(event.mode);
|
||||||
|
const sessionTypeHintKey = event.mode === "track" ? "events.session_type_hint_track" : "events.session_type_hint_race";
|
||||||
const racePresets = getRaceFormatPresets();
|
const racePresets = getRaceFormatPresets();
|
||||||
const selectedPreset = racePresets.find((preset) => preset.id === event.raceConfig.presetId) || racePresets[0];
|
const selectedPreset = racePresets.find((preset) => preset.id === event.raceConfig.presetId) || racePresets[0];
|
||||||
const isEndurancePreset = event.mode === "race" && selectedPreset?.id === "endurance";
|
const isEndurancePreset = event.mode === "race" && selectedPreset?.id === "endurance";
|
||||||
@@ -4326,26 +4368,63 @@ function renderEventManager(eventId) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form id="sessionForm" class="form-grid cols-5">
|
<form id="sessionForm" class="form-grid cols-5">
|
||||||
|
<label>
|
||||||
|
${t("events.session_name")}
|
||||||
<input required name="name" placeholder="${t("events.session_name")}" />
|
<input required name="name" placeholder="${t("events.session_name")}" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_type_label")}
|
||||||
<select name="type">
|
<select name="type">
|
||||||
${SESSION_TYPES.map((s) => `<option value="${s}">${getSessionTypeLabel(s)}</option>`).join("")}
|
${sessionTypeChoices.map((s) => `<option value="${s}">${getSessionTypeLabel(s)}</option>`).join("")}
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t(sessionTypeHintKey)}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_duration_label")}
|
||||||
<input required type="number" min="1" name="durationMin" placeholder="${t("events.duration_placeholder")}" />
|
<input required type="number" min="1" name="durationMin" placeholder="${t("events.duration_placeholder")}" />
|
||||||
|
<small>${t("events.session_duration_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_followup_label")}
|
||||||
<input type="number" min="0" step="1" name="followUpSec" placeholder="${t("events.follow_up_sec")}" value="${event.mode === "race" ? event.raceConfig.followUpSec || 0 : 0}" />
|
<input type="number" min="0" step="1" name="followUpSec" placeholder="${t("events.follow_up_sec")}" value="${event.mode === "race" ? event.raceConfig.followUpSec || 0 : 0}" />
|
||||||
|
<small>${t("events.session_followup_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_start_mode_label")}
|
||||||
<select name="startMode">
|
<select name="startMode">
|
||||||
<option value="mass">${t("events.start_mode_mass")}</option>
|
<option value="mass">${t("events.start_mode_mass")}</option>
|
||||||
<option value="position">${t("events.start_mode_position")}</option>
|
<option value="position">${t("events.start_mode_position")}</option>
|
||||||
<option value="staggered">${t("events.start_mode_staggered")}</option>
|
<option value="staggered">${t("events.start_mode_staggered")}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t("events.session_start_mode_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_seed_laps_label")}
|
||||||
<input type="number" min="0" name="seedBestLapCount" placeholder="${t("events.seed_best_laps")}" />
|
<input type="number" min="0" name="seedBestLapCount" placeholder="${t("events.seed_best_laps")}" />
|
||||||
|
<small>${t("events.session_seed_laps_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_seed_method_label")}
|
||||||
<select name="seedMethod">
|
<select name="seedMethod">
|
||||||
<option value="best_sum">${t("events.seed_method_best_sum")}</option>
|
<option value="best_sum">${t("events.seed_method_best_sum")}</option>
|
||||||
<option value="average">${t("events.seed_method_average")}</option>
|
<option value="average">${t("events.seed_method_average")}</option>
|
||||||
<option value="consecutive">${t("events.seed_method_consecutive")}</option>
|
<option value="consecutive">${t("events.seed_method_consecutive")}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t("events.session_seed_method_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_stagger_gap_label")}
|
||||||
<input type="number" min="0" step="1" name="staggerGapSec" placeholder="${t("events.stagger_gap_sec")}" />
|
<input type="number" min="0" step="1" name="staggerGapSec" placeholder="${t("events.stagger_gap_sec")}" />
|
||||||
|
<small>${t("events.session_stagger_gap_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_max_cars_label")}
|
||||||
<input type="number" min="1" name="maxCars" placeholder="${t("events.max_cars_placeholder")}" />
|
<input type="number" min="1" name="maxCars" placeholder="${t("events.max_cars_placeholder")}" />
|
||||||
|
<small>${t("events.session_max_cars_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<div class="actions-inline align-end">
|
||||||
<button class="btn btn-primary" type="submit">${t("events.add_session")}</button>
|
<button class="btn btn-primary" type="submit">${t("events.add_session")}</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<p class="hint">${t("events.seed_best_laps_hint")}</p>
|
<p class="hint">${t("events.seed_best_laps_hint")}</p>
|
||||||
<p class="hint">${t("events.free_practice_note")}</p>
|
<p class="hint">${t("events.free_practice_note")}</p>
|
||||||
@@ -5000,26 +5079,63 @@ function renderEventManager(eventId) {
|
|||||||
<button class="btn" id="sessionEditCancel">${t("common.cancel")}</button>
|
<button class="btn" id="sessionEditCancel">${t("common.cancel")}</button>
|
||||||
</div>
|
</div>
|
||||||
<form id="sessionEditForm" class="panel-body form-grid cols-5">
|
<form id="sessionEditForm" class="panel-body form-grid cols-5">
|
||||||
|
<div class="span-5"><p class="hint">${t("events.edit_session_help")}</p></div>
|
||||||
|
<label>
|
||||||
|
${t("events.session_name")}
|
||||||
<input name="name" required value="${escapeHtml(editingSession.name)}" placeholder="${t("events.session_name")}" />
|
<input name="name" required value="${escapeHtml(editingSession.name)}" placeholder="${t("events.session_name")}" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_type_label")}
|
||||||
<select name="type">
|
<select name="type">
|
||||||
${SESSION_TYPES.map(
|
${sessionTypeChoices.map(
|
||||||
(item) => `<option value="${item}" ${item === editingSession.type ? "selected" : ""}>${getSessionTypeLabel(item)}</option>`
|
(item) => `<option value="${item}" ${item === editingSession.type ? "selected" : ""}>${getSessionTypeLabel(item)}</option>`
|
||||||
).join("")}
|
).join("")}
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t(sessionTypeHintKey)}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_duration_label")}
|
||||||
<input name="durationMin" required type="number" min="1" value="${editingSession.durationMin || 5}" />
|
<input name="durationMin" required type="number" min="1" value="${editingSession.durationMin || 5}" />
|
||||||
|
<small>${t("events.session_duration_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_followup_label")}
|
||||||
<input name="followUpSec" type="number" min="0" step="1" value="${editingSession.followUpSec || 0}" />
|
<input name="followUpSec" type="number" min="0" step="1" value="${editingSession.followUpSec || 0}" />
|
||||||
|
<small>${t("events.session_followup_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_start_mode_label")}
|
||||||
<select name="startMode">
|
<select name="startMode">
|
||||||
<option value="mass" ${normalizeStartMode(editingSession.startMode) === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
|
<option value="mass" ${normalizeStartMode(editingSession.startMode) === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
|
||||||
<option value="position" ${normalizeStartMode(editingSession.startMode) === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
|
<option value="position" ${normalizeStartMode(editingSession.startMode) === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
|
||||||
<option value="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
|
<option value="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t("events.session_start_mode_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_seed_laps_label")}
|
||||||
<input name="seedBestLapCount" type="number" min="0" step="1" value="${editingSession.seedBestLapCount || 0}" />
|
<input name="seedBestLapCount" type="number" min="0" step="1" value="${editingSession.seedBestLapCount || 0}" />
|
||||||
|
<small>${t("events.session_seed_laps_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_seed_method_label")}
|
||||||
<select name="seedMethod">
|
<select name="seedMethod">
|
||||||
<option value="best_sum" ${editingSession.seedMethod === "best_sum" ? "selected" : ""}>${t("events.seed_method_best_sum")}</option>
|
<option value="best_sum" ${editingSession.seedMethod === "best_sum" ? "selected" : ""}>${t("events.seed_method_best_sum")}</option>
|
||||||
<option value="average" ${editingSession.seedMethod === "average" ? "selected" : ""}>${t("events.seed_method_average")}</option>
|
<option value="average" ${editingSession.seedMethod === "average" ? "selected" : ""}>${t("events.seed_method_average")}</option>
|
||||||
<option value="consecutive" ${editingSession.seedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
|
<option value="consecutive" ${editingSession.seedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<small>${t("events.session_seed_method_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_stagger_gap_label")}
|
||||||
<input name="staggerGapSec" type="number" min="0" step="1" value="${editingSession.staggerGapSec || 0}" />
|
<input name="staggerGapSec" type="number" min="0" step="1" value="${editingSession.staggerGapSec || 0}" />
|
||||||
|
<small>${t("events.session_stagger_gap_hint")}</small>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
${t("events.session_max_cars_label")}
|
||||||
|
<input name="maxCars" type="number" min="1" value="${editingSession.maxCars || ""}" />
|
||||||
|
<small>${t("events.session_max_cars_hint")}</small>
|
||||||
|
</label>
|
||||||
<p class="form-error" id="sessionEditError" hidden></p>
|
<p class="form-error" id="sessionEditError" hidden></p>
|
||||||
<div class="actions-inline">
|
<div class="actions-inline">
|
||||||
<button class="btn btn-primary" type="submit">${t("common.save")}</button>
|
<button class="btn btn-primary" type="submit">${t("common.save")}</button>
|
||||||
@@ -5215,6 +5331,7 @@ function renderEventManager(eventId) {
|
|||||||
? String(form.get("seedMethod")).toLowerCase()
|
? String(form.get("seedMethod")).toLowerCase()
|
||||||
: "best_sum";
|
: "best_sum";
|
||||||
editingSession.staggerGapSec = Math.max(0, Number(form.get("staggerGapSec") || 0) || 0);
|
editingSession.staggerGapSec = Math.max(0, Number(form.get("staggerGapSec") || 0) || 0);
|
||||||
|
editingSession.maxCars = Number(form.get("maxCars") || 0) || null;
|
||||||
selectedSessionEditId = null;
|
selectedSessionEditId = null;
|
||||||
saveState();
|
saveState();
|
||||||
renderEventManager(eventId);
|
renderEventManager(eventId);
|
||||||
|
|||||||
@@ -379,6 +379,22 @@ body {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-grid > label {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid > label > small {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-5 {
|
||||||
|
grid-column: span 5;
|
||||||
|
}
|
||||||
|
|
||||||
.field-card {
|
.field-card {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|||||||
Reference in New Issue
Block a user