Files
Live_RC/src/event_manager_view.js

836 lines
45 KiB
JavaScript

export function renderEventManagerMarkup(context) {
const {
event,
t,
escapeHtml,
sessions,
sessionTypeChoices,
sessionTypeHintKey,
raceTeams,
getSessionEntrants,
getSessionTypeLabel,
getStartModeLabel,
getStatusLabel,
normalizeStartMode,
branding,
driverOptions,
carOptions,
manageStatuses,
renderManageStatusBadgeView,
selectedParticipantCount,
raceDrivers,
teamDriverPool,
state,
getDriverDisplayById,
raceFormatAdvanced,
racePresets,
selectedPreset,
isEndurancePreset,
showBasicQualifyingFields = true,
showBasicFinalFields = true,
renderRaceFormatContextCardView,
renderRaceFormatFieldView,
raceSummaryWarnings,
raceSummaryItems,
selectedGridSession,
renderGridEditor,
renderRaceStandingsTableView,
buildPracticeStandings,
buildQualifyingStandings,
buildFinalStandings,
renderTeamRaceStandings,
renderFinalMatrix,
editingTeam,
editingSession,
getModeLabel,
renderTable,
} = context;
return `
<section class="panel" id="manage-session-plan">
<div class="panel-header">
<h3>${t("events.manage_title")}: ${escapeHtml(event.name)}</h3>
</div>
<div class="panel-body">
<form id="sessionForm" class="form-grid cols-5">
<label>
${t("events.session_name")}
<input required name="name" placeholder="${t("events.session_name")}" />
</label>
<label>
${t("events.session_type_label")}
<select name="type">
${sessionTypeChoices.map((s) => `<option value="${s}">${getSessionTypeLabel(s)}</option>`).join("")}
</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")}" />
<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}" />
<small>${t("events.session_followup_hint")}</small>
</label>
<label>
${t("events.session_start_mode_label")}
<select name="startMode">
<option value="mass">${t("events.start_mode_mass")}</option>
<option value="position">${t("events.start_mode_position")}</option>
<option value="staggered">${t("events.start_mode_staggered")}</option>
</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")}" />
<small>${t("events.session_seed_laps_hint")}</small>
</label>
<label>
${t("events.session_seed_method_label")}
<select name="seedMethod">
<option value="best_sum">${t("events.seed_method_best_sum")}</option>
<option value="average">${t("events.seed_method_average")}</option>
<option value="consecutive">${t("events.seed_method_consecutive")}</option>
</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")}" />
<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")}" />
<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>
</div>
</form>
<p class="hint">${t("events.seed_best_laps_hint")}</p>
<p class="hint">${t("events.free_practice_note")}</p>
<p class="hint">${t("events.open_practice_note")}</p>
<div class="mt-16">
${renderTable(
[t("table.session"), t("table.type"), t("table.duration"), t("table.start_mode"), t("table.seeding"), t("table.status"), t(event.mode === "track" ? "events.assignments" : "events.participants"), t("events.actions")],
sessions.map((s) => {
const assignCount =
event.mode === "track"
? (s.assignments || []).length
: s.type === "team_race"
? raceTeams.length
: getSessionEntrants(s).length;
return `
<tr>
<td>${escapeHtml(s.name)}</td>
<td>${escapeHtml(getSessionTypeLabel(s.type))}</td>
<td>${s.durationMin} min</td>
<td>${escapeHtml(getStartModeLabel(s.startMode))}</td>
<td>${s.seedBestLapCount > 0 ? `${s.seedBestLapCount}` : "-"}</td>
<td>${escapeHtml(getStatusLabel(s.status))}</td>
<td>${assignCount || (event.mode === "track" ? t("events.na") : "-")}</td>
<td class="actions-inline">
<button id="session-edit-${s.id}" class="btn">${t("events.edit_session")}</button>
<button id="session-active-${s.id}" class="btn">${t("events.set_active")}</button>
${
event.mode === "race" && normalizeStartMode(s.startMode) === "position"
? `<button id="session-grid-${s.id}" class="btn" type="button">${t("events.open_grid")}</button>`
: ""
}
${
event.mode === "race" && ["qualification", "final"].includes(s.type)
? `
<button id="session-sheet-print-${s.id}" class="btn" type="button">${t("events.print_heat_sheet")}</button>
<button id="session-sheet-export-${s.id}" class="btn" type="button">${t("events.export_heat_sheet")}</button>
<button id="session-sheet-pdf-${s.id}" class="btn" type="button">${t("events.pdf_heat_sheet")}</button>
`
: ""
}
<button id="session-delete-${s.id}" class="btn btn-danger">${t("common.delete")}</button>
</td>
</tr>
`;
})
)}
</div>
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.branding")}</h3></div>
<form id="eventBrandingForm" class="panel-body form-grid cols-3">
<input name="brandName" value="${escapeHtml(branding.brandName)}" placeholder="${t("events.brand_name")}" />
<input name="brandTagline" value="${escapeHtml(branding.brandTagline)}" placeholder="${t("events.brand_tagline")}" />
<input name="pdfFooter" value="${escapeHtml(branding.pdfFooter)}" placeholder="${t("events.brand_footer")}" />
<select name="pdfTheme">
<option value="" ${!branding.pdfTheme ? "selected" : ""}>${t("events.branding_use_global")}</option>
<option value="classic" ${branding.pdfTheme === "classic" ? "selected" : ""}>${t("settings.pdf_theme_classic")}</option>
<option value="minimal" ${branding.pdfTheme === "minimal" ? "selected" : ""}>${t("settings.pdf_theme_minimal")}</option>
<option value="motorsport" ${branding.pdfTheme === "motorsport" ? "selected" : ""}>${t("settings.pdf_theme_motorsport")}</option>
</select>
<button class="btn btn-primary" type="submit">${t("events.branding_save")}</button>
</form>
<div class="panel-body">
<p class="hint">${t("events.branding_note")}</p>
<div class="actions">
<input id="eventLogoUpload" type="file" accept="image/*" />
<button id="eventLogoClear" class="btn" type="button">${t("settings.logo_clear")}</button>
</div>
${branding.logoDataUrl ? `<div class="logo-preview mt-16"><img src="${escapeHtml(branding.logoDataUrl)}" alt="event-logo" /></div>` : ""}
</div>
</section>
${
event.mode === "track"
? `
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.sponsor_tools")}</h3></div>
<div class="panel-body">
<form id="sponsorRoundsForm" class="form-grid cols-5">
<input type="number" min="0" name="qualificationRounds" value="1" placeholder="${t("events.qual_rounds")}" />
<input type="number" min="0" name="heatRounds" value="3" placeholder="${t("events.heat_rounds")}" />
<input type="number" min="0" name="finalRounds" value="3" placeholder="${t("events.final_rounds")}" />
<input type="number" min="1" name="roundDuration" value="5" placeholder="${t("events.round_duration")}" />
<button class="btn btn-primary" type="submit">${t("events.create_rounds")}</button>
</form>
<p class="hint">
${t("events.tp_rule")}
</p>
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.assign_title")}</h3></div>
<div class="panel-body">
<form id="assignForm" class="form-grid cols-4">
<select name="sessionId">${sessions
.map((s) => `<option value="${s.id}">${escapeHtml(s.name)}</option>`)
.join("")}</select>
<select name="driverId">${driverOptions}</select>
<select name="carId">${carOptions}</select>
<button class="btn btn-primary" type="submit">${t("events.assign")}</button>
</form>
<div class="actions mt-16">
<button id="autoAssignSession" class="btn" type="button">${t("events.auto_assign")}</button>
<button id="clearAssignSession" class="btn btn-danger" type="button">${t("events.clear_assign")}</button>
</div>
<div id="assignmentList" class="mt-16"></div>
</div>
</section>
`
: ""
}
${
event.mode === "race"
? `
<section class="panel mt-16">
<div class="panel-body manage-step-grid">
<article class="manage-step-card manage-step-card-${manageStatuses?.setup?.status || "pending"} manage-step-card-link" data-target="manage-session-plan" role="button" tabindex="0">
<div class="manage-step-head"><strong>${t("events.manage_step_setup")}</strong>${renderManageStatusBadgeView(manageStatuses?.setup?.status || "pending")}</div>
<div class="manage-step-meta">${escapeHtml(manageStatuses?.setup?.detail || "")}</div>
<p>${t("events.manage_step_setup_hint")}</p>
</article>
<article class="manage-step-card manage-step-card-${manageStatuses?.format?.status || "pending"} manage-step-card-link" data-target="manage-format" role="button" tabindex="0">
<div class="manage-step-head"><strong>${t("events.manage_step_format")}</strong>${renderManageStatusBadgeView(manageStatuses?.format?.status || "pending")}</div>
<div class="manage-step-meta">${escapeHtml(manageStatuses?.format?.detail || "")}</div>
<p>${t("events.manage_step_format_hint")}</p>
</article>
<article class="manage-step-card manage-step-card-${manageStatuses?.generation?.status || "pending"} manage-step-card-link" data-target="manage-generation" role="button" tabindex="0">
<div class="manage-step-head"><strong>${t("events.manage_step_generate")}</strong>${renderManageStatusBadgeView(manageStatuses?.generation?.status || "pending")}</div>
<div class="manage-step-meta">${escapeHtml(manageStatuses?.generation?.detail || "")}</div>
<p>${t("events.manage_step_generate_hint")}</p>
</article>
<article class="manage-step-card manage-step-card-${manageStatuses?.live?.status || "pending"} manage-step-card-link" data-target="manage-live-results" role="button" tabindex="0">
<div class="manage-step-head"><strong>${t("events.manage_step_live")}</strong>${renderManageStatusBadgeView(manageStatuses?.live?.status || "pending")}</div>
<div class="manage-step-meta">${escapeHtml(manageStatuses?.live?.detail || "")}</div>
<p>${t("events.manage_step_live_hint")}</p>
</article>
</div>
</section>
<div class="race-stage-grid mt-16">
<section class="panel" id="manage-setup-participants">
<div class="panel-header panel-header-with-pill">
<h3>${t("events.select_participants")}</h3>
<span class="pill">${selectedParticipantCount}</span>
</div>
<div class="panel-body">
<div class="actions">
<button id="selectAllParticipants" class="btn" type="button">${t("events.select_all_participants")}</button>
<button id="clearParticipants" class="btn btn-danger" type="button">${t("events.clear_participants")}</button>
</div>
<div class="check-grid mt-16">
${raceDrivers
.map((driver) => {
const checked = event.raceConfig.participantsConfigured
? (event.raceConfig.driverIds || []).includes(driver.id)
: true;
return `
<label class="check-card">
<input type="checkbox" class="race-participant" value="${driver.id}" ${checked ? "checked" : ""} />
<span>${escapeHtml(driver.name)}${driver.transponder ? ` (${escapeHtml(driver.transponder)})` : ""}</span>
</label>
`;
})
.join("")}
</div>
</div>
</section>
<section class="panel" id="manage-setup-teams">
<div class="panel-header panel-header-with-pill">
<h3>${t("events.teams")}</h3>
<span class="pill">${raceTeams.length}</span>
</div>
<div class="panel-body">
<p class="hint">${t("events.team_race_intro")}</p>
<p class="hint">${t("events.team_steps")}</p>
<form id="teamForm" class="form-grid cols-4 team-create-form">
<input name="teamName" required placeholder="${t("events.team_name")}" />
<button class="btn btn-primary" id="teamAddSave" type="button" onclick="window.__liveRcTeamActions?.add?.()">${t("events.add_team")}</button>
</form>
<p class="hint">${t("events.team_hint")}</p>
<div class="panel-row mt-16">
<section class="panel">
<div class="panel-header"><h3>${t("events.team_drivers")}</h3></div>
<div class="panel-body"><p class="hint">${t("events.team_form_drivers")}</p></div>
${teamDriverPool.fallback ? `<div class="panel-body"><p class="hint">${t("events.team_driver_fallback")}</p></div>` : ""}
<div class="panel-body check-grid">
${raceDrivers
.map(
(driver) => `
<label class="check-card">
<input type="checkbox" name="teamDriverIds" form="teamForm" value="${driver.id}" />
<span>${escapeHtml(driver.name)}${driver.transponder ? ` (${escapeHtml(driver.transponder)})` : ""}</span>
</label>
`
)
.join("")}
</div>
</section>
<section class="panel">
<div class="panel-header"><h3>${t("events.team_cars")}</h3></div>
<div class="panel-body"><p class="hint">${t("events.team_form_cars")}</p></div>
<div class="panel-body check-grid">
${state.cars
.map(
(car) => `
<label class="check-card">
<input type="checkbox" name="teamCarIds" form="teamForm" value="${car.id}" />
<span>${escapeHtml(car.name)} (${escapeHtml(car.transponder || "-")})</span>
</label>
`
)
.join("")}
</div>
</section>
</div>
<div class="mt-16">
${
raceTeams.length
? raceTeams
.map(
(team) => `
<article class="team-card">
<div>
<strong>${escapeHtml(team.name)}</strong>
<div class="hint">${t("events.team_drivers")}: ${escapeHtml(
team.driverIds.map((driverId) => getDriverDisplayById(driverId)).join(", ") || "-"
)}</div>
<div class="hint">${t("events.team_cars")}: ${escapeHtml(
team.carIds
.map((carId) => {
const car = state.cars.find((item) => item.id === carId);
return car ? `${car.name} (${car.transponder || "-"})` : "";
})
.filter(Boolean)
.join(", ") || "-"
)}</div>
</div>
<div class="actions-inline">
<button id="team-edit-${team.id}" class="btn" type="button" onclick="window.__liveRcTeamActions?.edit?.('${team.id}')">${t("events.edit_team")}</button>
<button id="team-delete-${team.id}" class="btn btn-danger" type="button" onclick="window.__liveRcTeamActions?.remove?.('${team.id}')">${t("common.delete")}</button>
</div>
</article>
`
)
.join("")
: `<p>${t("events.no_teams")}</p>`
}
</div>
</div>
</section>
</div>
<section class="panel mt-16" id="manage-format">
<div class="panel-header"><h3>${t("events.race_format")}</h3></div>
<div class="panel-body">
<p>${t("events.race_format_intro")}</p>
</div>
<div class="panel-body race-setup-shell">
<div class="race-setup-main">
<div class="race-setup-modebar">
<div>
<strong>${t("events.race_format")}</strong>
<div class="field-hint">${t("events.race_actions_hint")}</div>
</div>
<div class="actions-inline race-setup-toggle">
<button id="raceFormatBasicToggle" class="btn ${!raceFormatAdvanced ? "is-active" : ""}" type="button">${t("events.setup_mode_basic")}</button>
<button id="raceFormatAdvancedToggle" class="btn ${raceFormatAdvanced ? "is-active" : ""}" type="button">${t("events.setup_mode_advanced")}</button>
</div>
</div>
<form id="raceFormatForm" class="race-format-sections">
<section class="race-format-section">
<div class="panel-header"><h3>${t("events.practice_block")}</h3></div>
<div class="panel-body"><p class="hint">${t("events.practice_block_hint")}</p></div>
<div class="panel-body form-grid cols-2 race-format-grid">
${renderRaceFormatContextCardView(isEndurancePreset ? "events.context_endurance_title" : "events.context_standard_title", isEndurancePreset ? "events.context_endurance_hint" : "events.context_standard_hint")}
${renderRaceFormatFieldView(
"events.race_preset",
"events.race_preset_hint",
`<select name="presetId">
${racePresets
.map(
(preset) => `<option value="${preset.id}" ${event.raceConfig.presetId === preset.id ? "selected" : ""}>${escapeHtml(preset.label)}</option>`
)
.join("")}
</select>`
)}
${raceFormatAdvanced
? `
<div class="field-card race-preset-actions-card">
<span class="field-label">${t("events.preset_name")}</span>
<span class="field-hint">${t("events.race_preset_hint")}</span>
<input name="presetName" value="${escapeHtml(selectedPreset?.custom ? selectedPreset.label : "")}" placeholder="${t("events.preset_name")}" />
<div class="actions-inline">
<button class="btn" id="applyRacePreset" type="button">${t("events.apply_preset")}</button>
<button class="btn" id="saveRacePreset" type="button">${t("events.save_preset")}</button>
<button class="btn btn-danger" id="deleteRacePreset" type="button">${t("events.delete_preset")}</button>
</div>
</div>
`
: `
<div class="field-card race-preset-actions-card race-preset-actions-card-compact">
<span class="field-label">${t("events.race_preset")}</span>
<span class="field-hint">${t("events.race_preset_hint")}</span>
<div class="actions-inline">
<button class="btn" id="applyRacePreset" type="button">${t("events.apply_preset")}</button>
</div>
</div>
`}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.qualifying_scoring",
"events.qualifying_scoring_hint",
`<select name="qualifyingScoring">
<option value="points" ${event.raceConfig.qualifyingScoring === "points" ? "selected" : ""}>${t("events.qualifying_scoring_points")}</option>
<option value="best" ${event.raceConfig.qualifyingScoring === "best" ? "selected" : ""}>${t("events.qualifying_scoring_best")}</option>
</select>`
) : ""}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.qualifying_rounds",
"events.qualifying_rounds_hint",
`<input type="number" min="1" name="qualifyingRounds" value="${event.raceConfig.qualifyingRounds}" />`
) : ""}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.cars_per_heat",
"events.cars_per_heat_hint",
`<input type="number" min="2" name="carsPerHeat" value="${event.raceConfig.carsPerHeat}" />`
) : ""}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.qual_duration",
"events.qual_duration_hint",
`<input type="number" min="1" name="qualDurationMin" value="${event.raceConfig.qualDurationMin}" />`
) : ""}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.qual_start_mode",
"events.qual_start_mode_hint",
`<select name="qualStartMode">
<option value="mass" ${event.raceConfig.qualStartMode === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${event.raceConfig.qualStartMode === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${event.raceConfig.qualStartMode === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
</select>`
) : ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.qual_seed_laps",
"events.qual_seed_laps_hint",
`<input type="number" min="0" name="qualSeedLapCount" value="${event.raceConfig.qualSeedLapCount}" />`
)
: ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.qual_seed_method",
"events.qual_seed_method_hint",
`<select name="qualSeedMethod">
<option value="best_sum" ${event.raceConfig.qualSeedMethod === "best_sum" ? "selected" : ""}>${t("events.seed_method_best_sum")}</option>
<option value="average" ${event.raceConfig.qualSeedMethod === "average" ? "selected" : ""}>${t("events.seed_method_average")}</option>
<option value="consecutive" ${event.raceConfig.qualSeedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
</select>`
)
: ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.counted_qual_rounds",
"events.counted_qual_rounds_hint",
`<input type="number" min="1" name="countedQualRounds" value="${event.raceConfig.countedQualRounds}" />`
)
: ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.qual_points_table",
"events.qual_points_table_hint",
`<select name="qualifyingPointsTable">
<option value="rank_low" ${event.raceConfig.qualifyingPointsTable === "rank_low" ? "selected" : ""}>${t("events.qual_points_rank")}</option>
<option value="field_desc" ${event.raceConfig.qualifyingPointsTable === "field_desc" ? "selected" : ""}>${t("events.qual_points_desc")}</option>
<option value="ifmar" ${event.raceConfig.qualifyingPointsTable === "ifmar" ? "selected" : ""}>${t("events.qual_points_ifmar")}</option>
</select>`
)
: ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.qual_tie_break",
"events.qual_tie_break_hint",
`<select name="qualifyingTieBreak">
<option value="rounds" ${event.raceConfig.qualifyingTieBreak === "rounds" ? "selected" : ""}>${t("events.qual_tie_break_rounds")}</option>
<option value="best_lap" ${event.raceConfig.qualifyingTieBreak === "best_lap" ? "selected" : ""}>${t("events.qual_tie_break_best_lap")}</option>
<option value="best_round" ${event.raceConfig.qualifyingTieBreak === "best_round" ? "selected" : ""}>${t("events.qual_tie_break_best_round")}</option>
</select>`
)
: ""}
</div>
</section>
<section class="race-format-section">
<div class="panel-header"><h3>${t("events.finals_block")}</h3></div>
<div class="panel-body"><p class="hint">${t("events.finals_block_hint")}</p></div>
<div class="panel-body form-grid cols-2 race-format-grid">
${renderRaceFormatContextCardView(isEndurancePreset ? "events.context_endurance_title" : "events.context_standard_title", isEndurancePreset ? "events.context_endurance_hint" : "events.context_standard_hint")}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.cars_per_final",
"events.cars_per_final_hint",
`<input type="number" min="2" name="carsPerFinal" value="${event.raceConfig.carsPerFinal}" />`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.final_legs",
"events.final_legs_hint",
`<input type="number" min="1" name="finalLegs" value="${event.raceConfig.finalLegs}" />`
) : ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.counted_final_legs",
"events.counted_final_legs_hint",
`<input type="number" min="1" name="countedFinalLegs" value="${event.raceConfig.countedFinalLegs}" />`
)
: ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.final_duration",
"events.final_duration_hint",
`<input type="number" min="1" name="finalDurationMin" value="${event.raceConfig.finalDurationMin}" />`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.final_start_mode",
"events.final_start_mode_hint",
`<select name="finalStartMode">
<option value="mass" ${event.raceConfig.finalStartMode === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${event.raceConfig.finalStartMode === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${event.raceConfig.finalStartMode === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
</select>`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.bump_count",
"events.bump_count_hint",
`<input type="number" min="0" name="bumpCount" value="${event.raceConfig.bumpCount}" />`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.source_for_finals",
"events.finals_source_hint",
`<select name="finalsSource">
<option value="qualifying" ${event.raceConfig.finalsSource === "qualifying" ? "selected" : ""}>${t("events.finals_from_qualifying")}</option>
<option value="practice" ${event.raceConfig.finalsSource === "practice" ? "selected" : ""}>${t("events.finals_from_practice")}</option>
</select>`
) : ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.reserve_bump_slots",
"events.reserve_bump_slots_hint",
`<label class="toggle"><input type="checkbox" name="reserveBumpSlots" ${event.raceConfig.reserveBumpSlots ? "checked" : ""} /><span>${t("events.reserve_bump_slots")}</span></label>`,
{ checkbox: true }
)
: ""}
</div>
</section>
<section class="race-format-section">
<div class="panel-header"><h3>${t("events.rules_block")}</h3></div>
<div class="panel-body"><p class="hint">${t("events.rules_block_hint")}</p></div>
<div class="panel-body form-grid cols-2 race-format-grid">
${renderRaceFormatContextCardView("events.context_rules_title", "events.context_rules_hint")}
${renderRaceFormatFieldView(
"events.follow_up_sec",
"events.follow_up_sec_hint",
`<input type="number" min="0" step="1" name="followUpSec" value="${event.raceConfig.followUpSec || 0}" />`
)}
${renderRaceFormatFieldView(
"events.min_lap_time",
"events.min_lap_time_hint",
`<input type="number" min="0" step="0.1" name="minLapSec" value="${((event.raceConfig.minLapMs || 0) / 1000).toFixed(1)}" />`
)}
${renderRaceFormatFieldView(
"events.max_lap_time",
"events.max_lap_time_hint",
`<input type="number" min="1" step="0.1" name="maxLapSec" value="${((event.raceConfig.maxLapMs || 60000) / 1000).toFixed(1)}" />`
)}
<div class="field-card race-format-note-card">
<span class="field-label">${t("events.actions")}</span>
<span class="field-hint">${t("events.race_driver_scope")}</span>
<span class="field-hint">${t("events.bump_reserved_note")}</span>
</div>
</div>
</section>
<div class="race-format-save-row">
<button class="btn btn-primary" type="submit">${t("events.save_race_format")}</button>
</div>
</form>
</div>
<aside class="race-summary-card">
<div class="panel-header"><h3>${t("events.race_summary")}</h3></div>
<div class="panel-body">
<p class="hint">${t("events.race_summary_hint")}</p>
${raceSummaryWarnings.length ? `
<div class="race-summary-warnings">
<strong>${t("events.summary_warnings_title")}</strong>
<ul>
${raceSummaryWarnings.map((warning) => `<li><button class="summary-warning-link" type="button" data-target="${escapeHtml(warning.target)}">${escapeHtml(warning.message)}</button></li>`).join("")}
</ul>
</div>
` : ""}
<div class="race-summary-list">
${raceSummaryItems
.map(
(item) => `
<article class="race-summary-item">
<span>${escapeHtml(item.label)}</span>
<strong>${escapeHtml(item.value)}</strong>
</article>
`
)
.join("")}
</div>
</div>
</aside>
</div>
<div class="panel-body race-actions-panel" id="manage-generation">
<div class="panel-header panel-header-inline"><h3>${t("events.race_actions_title")}</h3></div>
<p class="hint">${t("events.race_actions_hint")}</p>
<div class="actions mt-16">
<button id="generateQualifying" class="btn" type="button">${t("events.generate_qualifying")}</button>
<button id="clearGeneratedQualifying" class="btn btn-danger" type="button">${t("events.clear_generated_qualifying")}</button>
<button id="reseedQualifying" class="btn" type="button">${t("events.reseed_qualifying")}</button>
<button id="generateFinals" class="btn btn-primary" type="button">${t("events.generate_finals")}</button>
<button id="clearGeneratedFinals" class="btn btn-danger" type="button">${t("events.clear_generated_finals")}</button>
<button id="applyBumps" class="btn" type="button">${t("events.apply_bumps")}</button>
</div>
<div class="actions mt-16">
<button id="exportRacePackage" class="btn" type="button">${t("events.export_race_package")}</button>
<input id="importRacePackage" type="file" accept="application/json" aria-label="${t("events.import_race_package")}" />
</div>
<p class="hint">${t("events.race_package_hint")}</p>
</div>
</section>
<section class="panel mt-16" id="manage-live-grid">
<div class="panel-header"><h3>${t("events.grid_editor")}</h3></div>
<div class="panel-body">
${renderGridEditor(selectedGridSession)}
</div>
</section>
<section class="panel mt-16" id="manage-live-results">
<div class="panel-header"><h3>${t("events.practice_standings")}</h3></div>
<div class="panel-body">
${renderRaceStandingsTableView(buildPracticeStandings(event), t("events.no_practice_results"))}
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.qualifying_standings")}</h3></div>
<div class="panel-body">
${renderRaceStandingsTableView(buildQualifyingStandings(event), t("events.no_qualifying_results"))}
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.final_standings")}</h3></div>
<div class="panel-body">
${renderRaceStandingsTableView(buildFinalStandings(event), t("events.no_final_results"))}
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.team_standings")}</h3></div>
<div class="panel-body">
<div class="actions">
<button id="printTeamResults" class="btn" type="button">${t("events.print_team_results")}</button>
<button id="pdfTeamResults" class="btn" type="button">${t("events.pdf_team_results")}</button>
</div>
<div class="mt-16">
${renderTeamRaceStandings(event)}
</div>
</div>
</section>
<section class="panel mt-16">
<div class="panel-header"><h3>${t("events.final_matrix")}</h3></div>
<div class="panel-body">
<div class="actions">
<button id="printStartlists" class="btn" type="button">${t("events.print_startlists")}</button>
<button id="printResults" class="btn" type="button">${t("events.print_results")}</button>
<button id="pdfStartlists" class="btn" type="button">${t("events.pdf_startlists")}</button>
<button id="pdfResults" class="btn" type="button">${t("events.pdf_results")}</button>
</div>
<div class="mt-16">
${renderFinalMatrix(event)}
</div>
</div>
</section>
`
: ""
}
${
editingTeam
? `
<div class="modal-overlay" id="teamEditModalOverlay">
<div class="modal-card">
<div class="panel-header">
<h3>${t("events.edit_team")}</h3>
<button class="btn" id="teamEditCancel">${t("common.cancel")}</button>
</div>
<form id="teamEditForm" class="panel-body form-grid cols-2">
<input name="teamName" required value="${escapeHtml(editingTeam.name)}" placeholder="${t("events.team_name")}" />
<p class="form-error" id="teamEditError" hidden></p>
<div>
<h4>${t("events.team_drivers")}</h4>
<div class="check-grid">
${raceDrivers
.map(
(driver) => `
<label class="check-card">
<input type="checkbox" name="teamDriverIds" value="${driver.id}" ${editingTeam.driverIds.includes(driver.id) ? "checked" : ""} />
<span>${escapeHtml(driver.name)}${driver.transponder ? ` (${escapeHtml(driver.transponder)})` : ""}</span>
</label>
`
)
.join("")}
</div>
</div>
<div>
<h4>${t("events.team_cars")}</h4>
<div class="check-grid">
${state.cars
.map(
(car) => `
<label class="check-card">
<input type="checkbox" name="teamCarIds" value="${car.id}" ${editingTeam.carIds.includes(car.id) ? "checked" : ""} />
<span>${escapeHtml(car.name)} (${escapeHtml(car.transponder || "-")})</span>
</label>
`
)
.join("")}
</div>
</div>
<div class="actions-inline">
<button class="btn btn-primary" id="teamEditSave" type="button" onclick="window.__liveRcTeamActions?.saveEdit?.()">${t("common.save")}</button>
<button class="btn" id="teamEditCancelFooter" type="button">${t("common.cancel")}</button>
</div>
</form>
</div>
</div>
`
: ""
}
${
editingSession
? `
<div class="modal-overlay" id="sessionEditModalOverlay">
<div class="modal-card">
<div class="panel-header">
<h3>${t("events.edit_session")}</h3>
<button class="btn" id="sessionEditCancel">${t("common.cancel")}</button>
</div>
<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")}" />
</label>
<label>
${t("events.session_type_label")}
<select name="type">
${sessionTypeChoices.map(
(item) => `<option value="${item}" ${item === editingSession.type ? "selected" : ""}>${getSessionTypeLabel(item)}</option>`
).join("")}
</select>
<small>${t(sessionTypeHintKey)}</small>
</label>
<label>
${t("events.session_duration_label")}
<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}" />
<small>${t("events.session_followup_hint")}</small>
</label>
<label>
${t("events.session_start_mode_label")}
<select name="startMode">
<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="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
</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}" />
<small>${t("events.session_seed_laps_hint")}</small>
</label>
<label>
${t("events.session_seed_method_label")}
<select name="seedMethod">
<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="consecutive" ${editingSession.seedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
</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}" />
<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>
<div class="actions-inline">
<button class="btn btn-primary" type="submit">${t("common.save")}</button>
<button class="btn" id="sessionEditCancelFooter" type="button">${t("common.cancel")}</button>
</div>
</form>
</div>
</div>
`
: ""
}
`;;
}