Add brand filtering for drivers and cars

This commit is contained in:
larssand
2026-03-16 20:07:29 +01:00
parent baebb6ac9d
commit 61008eac0a
3 changed files with 52 additions and 8 deletions

View File

@@ -87,12 +87,14 @@ const TRANSLATIONS = {
"drivers.create": "Skapa förare",
"drivers.name_placeholder": "Förarnamn",
"drivers.brand_placeholder": "Team / märke (valfritt)",
"drivers.brand_filter_placeholder": "Filtrera på team / märke",
"drivers.transponder_placeholder": "Personlig transponder (valfritt)",
"drivers.add": "Lägg till förare",
"drivers.title": "Förare",
"cars.create": "Skapa bil",
"cars.name_placeholder": "Bilnamn eller nummer",
"cars.brand_placeholder": "Märke / modell (valfritt)",
"cars.brand_filter_placeholder": "Filtrera på märke / modell",
"cars.transponder_placeholder": "Bilens transponder",
"cars.add": "Lägg till bil",
"cars.title": "Bilar",
@@ -539,14 +541,14 @@ const TRANSLATIONS = {
"guide.title": "Guide och dokumentation",
"guide.intro": "Här finns steg-för-steg för sponsor-event (10 personer, 4 bilar), vanligt race, samt AMMC-installation på Windows/Linux. Guiden beskriver också var AMMC faktiskt körs i Managed AMMC-läget.",
"guide.sponsor_title": "Skapa Sponsor Event: 10 personer, 4 bilar",
"guide.sponsor_1": "1. Lägg upp 4 bilar i sidan Bilar med unikt transponder-ID.",
"guide.sponsor_2": "2. Lägg upp 10 förare i sidan Förare.",
"guide.sponsor_1": "1. Lägg upp 4 bilar i sidan Bilar med unikt transponder-ID. Lägg gärna också in märke/modell i brandfältet.",
"guide.sponsor_2": "2. Lägg upp 10 förare i sidan Förare. Du kan också spara team/märke i brandfältet och filtrera listan på det senare.",
"guide.sponsor_3": "3. Skapa event med läge Sponsor Event.",
"guide.sponsor_4": "4. Klicka Hantera på eventet och skapa rundor (kval/heat/final).",
"guide.sponsor_5": "5. Tilldela 4 förare till 4 bilar i Heat 1, byt förare till Heat 2/3 osv.",
"guide.sponsor_6": "6. I Tidtagning: välj session, Sätt aktiv, Starta, Stoppa.",
"guide.race_title": "Skapa vanligt race (förare har egna transpondrar)",
"guide.race_1": "1. Lägg in förare med personlig transponder.",
"guide.race_1": "1. Lägg in förare med personlig transponder. Brandfältet kan användas för team, sponsor eller bilmärke.",
"guide.race_2": "2. Skapa event med läge Race.",
"guide.race_3": "3. Klicka Hantera på racet och markera exakt vilka förare som ska få vara med i just detta race.",
"guide.race_4": "4. Gå igenom Raceformat och välj antal kvalrundor, förare per heat, tider, starttyp och hur finaler ska seedas.",
@@ -727,12 +729,14 @@ const TRANSLATIONS = {
"drivers.create": "Create Driver",
"drivers.name_placeholder": "Driver name",
"drivers.brand_placeholder": "Team / brand (optional)",
"drivers.brand_filter_placeholder": "Filter by team / brand",
"drivers.transponder_placeholder": "Personal transponder (optional)",
"drivers.add": "Add Driver",
"drivers.title": "Drivers",
"cars.create": "Create Track Car",
"cars.name_placeholder": "Car name or number",
"cars.brand_placeholder": "Brand / model (optional)",
"cars.brand_filter_placeholder": "Filter by brand / model",
"cars.transponder_placeholder": "Car transponder",
"cars.add": "Add Car",
"cars.title": "Cars",
@@ -1179,14 +1183,14 @@ const TRANSLATIONS = {
"guide.title": "Guide and Documentation",
"guide.intro": "Step-by-step setup for sponsor events (10 drivers, 4 cars), normal race mode, and AMMC on Windows/Linux. The guide also explains where Managed AMMC actually runs.",
"guide.sponsor_title": "Create Sponsor Event: 10 drivers, 4 cars",
"guide.sponsor_1": "1. Add 4 cars in Cars with unique transponder IDs.",
"guide.sponsor_2": "2. Add 10 drivers in Drivers.",
"guide.sponsor_1": "1. Add 4 cars in Cars with unique transponder IDs. You can also store brand/model in the brand field.",
"guide.sponsor_2": "2. Add 10 drivers in Drivers. You can also store team/brand in the brand field and filter by it later.",
"guide.sponsor_3": "3. Create event in Track Event mode.",
"guide.sponsor_4": "4. Click Manage and create rounds (qualification/heat/final).",
"guide.sponsor_5": "5. Assign 4 drivers to 4 cars in Heat 1, rotate drivers for Heat 2/3, then finals.",
"guide.sponsor_6": "6. In Timing: select session, Set Active, Start, Stop.",
"guide.race_title": "Create regular race (driver transponders)",
"guide.race_1": "1. Add drivers with personal transponder IDs.",
"guide.race_1": "1. Add drivers with personal transponder IDs. The brand field can be used for team, sponsor or car brand.",
"guide.race_2": "2. Create event in Race mode.",
"guide.race_3": "3. Click Manage on the race and select exactly which drivers should be valid for this race.",
"guide.race_4": "4. Go through Race Format and choose qualifying rounds, drivers per heat, times, start mode and how finals should be seeded.",
@@ -1323,6 +1327,8 @@ let selectedJudgeKey = null;
let judgingCompetitorFilter = "all";
let judgingLogFilter = "all";
let quickAddDraft = null;
let driverBrandFilter = "";
let carBrandFilter = "";
let overlaySyncTimer = null;
let overlayRotationTimer = null;
let overlayLiveRefreshTimer = null;
@@ -2835,6 +2841,11 @@ function renderDrivers() {
const classOptions = state.classes
.map((c) => `<option value="${c.id}">${escapeHtml(c.name)}</option>`)
.join("");
const filteredDrivers = state.drivers.filter((driver) =>
String(driver.brand || "")
.toLowerCase()
.includes(driverBrandFilter.trim().toLowerCase())
);
const editingDriver = state.drivers.find((driver) => driver.id === selectedDriverEditId) || null;
dom.view.innerHTML = `
@@ -2851,10 +2862,13 @@ function renderDrivers() {
<section class="panel">
<div class="panel-header"><h3>${t("drivers.title")}</h3></div>
<div class="panel-body">
<input id="driverBrandFilter" value="${escapeHtml(driverBrandFilter)}" placeholder="${t("drivers.brand_filter_placeholder")}" />
</div>
<div class="panel-body">
${renderTable(
[t("table.name"), t("table.class"), t("table.brand"), t("table.transponder"), t("events.actions")],
state.drivers.map(
filteredDrivers.map(
(d) => `
<tr>
<td>${escapeHtml(d.name)}</td>
@@ -2922,6 +2936,15 @@ function renderDrivers() {
renderView();
});
document.getElementById("driverBrandFilter")?.addEventListener("input", (event) => {
const input = event.currentTarget;
if (!(input instanceof HTMLInputElement)) {
return;
}
driverBrandFilter = input.value;
renderDrivers();
});
state.drivers.forEach((d) => {
document.getElementById(`driver-edit-${d.id}`)?.addEventListener("click", () => {
selectedDriverEditId = d.id;
@@ -2990,6 +3013,11 @@ function renderDrivers() {
}
function renderCars() {
const filteredCars = state.cars.filter((car) =>
String(car.brand || "")
.toLowerCase()
.includes(carBrandFilter.trim().toLowerCase())
);
const editingCar = state.cars.find((car) => car.id === selectedCarEditId) || null;
dom.view.innerHTML = `
<section class="panel">
@@ -3004,10 +3032,13 @@ function renderCars() {
<section class="panel">
<div class="panel-header"><h3>${t("cars.title")}</h3></div>
<div class="panel-body">
<input id="carBrandFilter" value="${escapeHtml(carBrandFilter)}" placeholder="${t("cars.brand_filter_placeholder")}" />
</div>
<div class="panel-body">
${renderTable(
[t("table.car"), t("table.brand"), t("table.transponder"), t("events.actions")],
state.cars.map(
filteredCars.map(
(c) => `
<tr>
<td>${escapeHtml(c.name)}</td>
@@ -3070,6 +3101,15 @@ function renderCars() {
renderView();
});
document.getElementById("carBrandFilter")?.addEventListener("input", (event) => {
const input = event.currentTarget;
if (!(input instanceof HTMLInputElement)) {
return;
}
carBrandFilter = input.value;
renderCars();
});
state.cars.forEach((c) => {
document.getElementById(`car-edit-${c.id}`)?.addEventListener("click", () => {
selectedCarEditId = c.id;