Add multi-decoder split and pit timing support
This commit is contained in:
@@ -132,6 +132,8 @@ function renderLeaderboardModal(session, row, deps) {
|
||||
<p>${t("timing.total_time")}: ${escapeHtml(row.resultDisplay)}</p>
|
||||
<p>${t("table.best_lap")}: ${formatLap(row.bestLapMs)}</p>
|
||||
<p>${t("table.last_lap")}: ${formatLap(row.lastLapMs)}</p>
|
||||
<p>${t("table.split")}: ${formatLap(row.lastSplitMs)}${Number.isFinite(row.lastSplitDeltaMs) ? ` (${row.lastSplitDeltaMs >= 0 ? "+" : ""}${formatLap(Math.abs(row.lastSplitDeltaMs))})` : ""}</p>
|
||||
<p>${t("table.pit")}: ${row.pitActive ? t("timing.pit_active") : `${Number(row.pitStops || 0)} / ${formatLap(row.totalPitMs)}`}</p>
|
||||
<p>${t("table.own_delta")}: ${escapeHtml(row.lapDelta || "-")}</p>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@@ -192,6 +194,8 @@ function renderLeaderboard(rows, deps) {
|
||||
t("table.leader_gap"),
|
||||
t("table.ahead_gap"),
|
||||
t("table.own_delta"),
|
||||
t("table.split"),
|
||||
t("table.pit"),
|
||||
"",
|
||||
],
|
||||
rows.map((row, idx) => {
|
||||
@@ -214,6 +218,8 @@ function renderLeaderboard(rows, deps) {
|
||||
<td>${escapeHtml(row.leaderGap || row.gap || "-")}</td>
|
||||
<td>${escapeHtml(row.gapAhead || "-")}</td>
|
||||
<td>${escapeHtml(row.lapDelta || "-")}</td>
|
||||
<td>${formatLap(row.lastSplitMs)}</td>
|
||||
<td>${row.pitActive ? `<strong>${t("timing.pit_active")}</strong>` : `${Number(row.pitStops || 0)} / ${formatLap(row.totalPitMs)}`}</td>
|
||||
<td><button id="leaderboard-detail-${row.key}" class="btn btn-mini">${t("timing.details")}</button></td>
|
||||
</tr>
|
||||
`;
|
||||
@@ -297,8 +303,16 @@ export function renderTimingView(deps) {
|
||||
<div class="panel-header"><h3>${t("timing.decoder_connection")}</h3></div>
|
||||
<div class="panel-body timing-top-grid">
|
||||
<div class="timing-compact-card">
|
||||
<label class="timing-compact-label" for="timingWsUrl">${t("settings.decoder")}</label>
|
||||
<label class="timing-compact-label" for="timingWsUrl">${t("timing.main_decoder")}</label>
|
||||
<input id="timingWsUrl" value="${escapeHtml(state.settings.wsUrl)}" placeholder="ws://127.0.0.1:9000" />
|
||||
<label class="toggle"><input id="timingSplitEnabled" type="checkbox" ${state.settings.splitDecoderEnabled ? "checked" : ""} /><span>${t("settings.enable_split_decoder")}</span></label>
|
||||
<label for="timingSplitWsUrl"><small>${t("timing.split_decoder")} WebSocket</small></label>
|
||||
<input id="timingSplitWsUrl" value="${escapeHtml(state.settings.splitWsUrl || "")}" placeholder="ws://127.0.0.1:9001" />
|
||||
<label class="toggle"><input id="timingPitEnabled" type="checkbox" ${state.settings.pitDecoderEnabled ? "checked" : ""} /><span>${t("settings.enable_pit_decoders")}</span></label>
|
||||
<label for="timingPitEntryWsUrl"><small>${t("timing.pit_entry_decoder")} WebSocket</small></label>
|
||||
<input id="timingPitEntryWsUrl" value="${escapeHtml(state.settings.pitEntryWsUrl || "")}" placeholder="ws://127.0.0.1:9002" />
|
||||
<label for="timingPitExitWsUrl"><small>${t("timing.pit_exit_decoder")} WebSocket</small></label>
|
||||
<input id="timingPitExitWsUrl" value="${escapeHtml(state.settings.pitExitWsUrl || "")}" placeholder="ws://127.0.0.1:9003" />
|
||||
<div class="actions">
|
||||
<button id="timingConnect" class="btn btn-primary">${t("timing.connect")}</button>
|
||||
<button id="timingDisconnect" class="btn">${t("timing.disconnect")}</button>
|
||||
@@ -307,9 +321,12 @@ export function renderTimingView(deps) {
|
||||
</div>
|
||||
<div class="timing-compact-card">
|
||||
<span class="timing-compact-label">${t("timing.status")}</span>
|
||||
<strong>${state.decoder.connected ? t("timing.connected") : t("timing.disconnected")}</strong>
|
||||
<strong>${t("timing.main_decoder")}: ${state.decoder.connected ? t("timing.connected") : t("timing.disconnected")}</strong>
|
||||
<small>${t("timing.last_message")}: ${state.decoder.lastMessageAt ? new Date(state.decoder.lastMessageAt).toLocaleString() : "-"}</small>
|
||||
${state.settings.splitDecoderEnabled ? `<strong>${t("timing.split_decoder")}: ${state.decoder.splitConnected ? t("timing.connected") : t("timing.disconnected")}</strong><small>${t("timing.last_message")}: ${state.decoder.splitLastMessageAt ? new Date(state.decoder.splitLastMessageAt).toLocaleString() : "-"}</small>` : ""}
|
||||
${state.settings.pitDecoderEnabled ? `<strong>${t("timing.pit_entry_decoder")}: ${state.decoder.pitEntryConnected ? t("timing.connected") : t("timing.disconnected")}</strong><small>${t("timing.last_message")}: ${state.decoder.pitEntryLastMessageAt ? new Date(state.decoder.pitEntryLastMessageAt).toLocaleString() : "-"}</small><strong>${t("timing.pit_exit_decoder")}: ${state.decoder.pitExitConnected ? t("timing.connected") : t("timing.disconnected")}</strong><small>${t("timing.last_message")}: ${state.decoder.pitExitLastMessageAt ? new Date(state.decoder.pitExitLastMessageAt).toLocaleString() : "-"}</small>` : ""}
|
||||
<p class="error">${escapeHtml(state.decoder.lastError || "")}</p>
|
||||
<p class="error">${escapeHtml(state.decoder.splitLastError || state.decoder.pitEntryLastError || state.decoder.pitExitLastError || "")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -406,8 +423,13 @@ export function renderTimingView(deps) {
|
||||
const input = document.getElementById("timingWsUrl");
|
||||
if (input && input.value.trim()) {
|
||||
state.settings.wsUrl = input.value.trim();
|
||||
saveState();
|
||||
}
|
||||
state.settings.splitDecoderEnabled = Boolean(document.getElementById("timingSplitEnabled")?.checked);
|
||||
state.settings.splitWsUrl = String(document.getElementById("timingSplitWsUrl")?.value || "").trim();
|
||||
state.settings.pitDecoderEnabled = Boolean(document.getElementById("timingPitEnabled")?.checked);
|
||||
state.settings.pitEntryWsUrl = String(document.getElementById("timingPitEntryWsUrl")?.value || "").trim();
|
||||
state.settings.pitExitWsUrl = String(document.getElementById("timingPitExitWsUrl")?.value || "").trim();
|
||||
saveState();
|
||||
connectDecoder();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user