mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-10 01:05:33 +00:00
Group firmware picker hardware variants
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
]);
|
||||
|
||||
const FILTER_FIELDS = Object.freeze([
|
||||
"hardwareFamily",
|
||||
"hardware",
|
||||
"role",
|
||||
"logging",
|
||||
@@ -308,6 +309,57 @@
|
||||
};
|
||||
}
|
||||
|
||||
function hardwareFamilyFor(hardware, hardwareNames) {
|
||||
const value = String(hardware || "");
|
||||
const lowerValue = value.toLowerCase();
|
||||
const parents = (hardwareNames || []).filter(function (candidate) {
|
||||
const parent = String(candidate || "");
|
||||
if (!parent || parent === value) return false;
|
||||
const lowerParent = parent.toLowerCase();
|
||||
return lowerValue.startsWith(lowerParent + "_") ||
|
||||
lowerValue.startsWith(lowerParent + "-");
|
||||
}).sort(function (a, b) {
|
||||
return a.length - b.length || a.localeCompare(b);
|
||||
});
|
||||
return parents[0] || value;
|
||||
}
|
||||
|
||||
function humanizeHardwareVariant(hardware, family) {
|
||||
const value = String(hardware || "");
|
||||
const parent = String(family || "");
|
||||
if (!parent || value === parent) return "Base / standard";
|
||||
|
||||
const knownLabels = {
|
||||
"heltec_v4_2_v4_3": "V4.2 / V4.3",
|
||||
"heltec_v4_3": "V4.3",
|
||||
"heltec_v4_3_expansionkit_tft": "V4.3 + expansion kit + TFT",
|
||||
"heltec_v4_3_tft": "V4.3 + TFT",
|
||||
"heltec_v4_expansionkit": "Expansion kit",
|
||||
"heltec_v4_expansionkit_tft": "Expansion kit + TFT",
|
||||
"heltec_v4_r8": "R8",
|
||||
"heltec_v4_r8_tft": "R8 + TFT",
|
||||
"heltec_v4_tft": "TFT",
|
||||
"Station_G2_logging": "RX-boosted radio profile",
|
||||
"Station_G3_ESP32_logging": "Alternate radio profile",
|
||||
"wio-e5-mini": "Mini",
|
||||
};
|
||||
if (knownLabels[value]) return knownLabels[value];
|
||||
|
||||
let suffix = value.slice(parent.length).replace(/^[_-]+/, "");
|
||||
const suffixLabels = {
|
||||
logging: "Logging hardware profile",
|
||||
without_display: "Without display",
|
||||
sdcard: "SD card",
|
||||
"096": "0.96-inch display",
|
||||
"096_rotated": "0.96-inch rotated display",
|
||||
Lite_non_shell: "Lite (no shell)",
|
||||
};
|
||||
if (suffixLabels[suffix]) return suffixLabels[suffix];
|
||||
suffix = humanizeHardware(suffix).replace(/\bTft\b/gi, "TFT")
|
||||
.replace(/\bWio\b/gi, "WIO");
|
||||
return suffix || humanizeHardware(value);
|
||||
}
|
||||
|
||||
function canonicalAsset(files, installKind) {
|
||||
return (Array.isArray(files) ? files : []).filter(function (file) {
|
||||
return file.installKind === installKind;
|
||||
@@ -358,6 +410,16 @@
|
||||
});
|
||||
});
|
||||
|
||||
const hardwareNames = Array.from(new Set(profiles.map(function (profile) {
|
||||
return profile.hardware;
|
||||
})));
|
||||
profiles.forEach(function (profile) {
|
||||
profile.hardwareFamily = hardwareFamilyFor(
|
||||
profile.hardware,
|
||||
hardwareNames
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
releaseSet: releaseSet,
|
||||
rows: firmwareRows,
|
||||
@@ -374,8 +436,11 @@
|
||||
}
|
||||
|
||||
function profileMatchesFacets(profile, filters, ignoredField) {
|
||||
const ignoredFields = new Set(
|
||||
Array.isArray(ignoredField) ? ignoredField : [ignoredField]
|
||||
);
|
||||
return FACET_FIELDS.every(function (field) {
|
||||
if (field === ignoredField) return true;
|
||||
if (ignoredFields.has(field)) return true;
|
||||
const value = filters && filters[field];
|
||||
if (!value) return true;
|
||||
if (field === "install") {
|
||||
@@ -385,9 +450,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
function facetValues(profiles, filters, field) {
|
||||
function facetValues(profiles, filters, field, additionallyIgnoredFields) {
|
||||
const ignoredFields = [field].concat(additionallyIgnoredFields || []);
|
||||
const compatible = (profiles || []).filter(function (profile) {
|
||||
return profileMatchesFacets(profile, filters, field);
|
||||
return profileMatchesFacets(profile, filters, ignoredFields);
|
||||
});
|
||||
const values = field === "install"
|
||||
? compatible.flatMap(function (profile) {
|
||||
@@ -428,6 +494,7 @@
|
||||
}
|
||||
|
||||
function labelFor(field, value) {
|
||||
if (field === "hardwareFamily") return humanizeHardware(value);
|
||||
if (field === "hardware") return humanizeHardware(value);
|
||||
if (field === "role") return ROLE_LABELS[value] || value;
|
||||
if (field === "logging") return LOGGING_LABELS[value] || value;
|
||||
@@ -604,7 +671,8 @@
|
||||
function setSelectOptions(select, field, values, selected) {
|
||||
select.replaceChildren();
|
||||
const placeholders = {
|
||||
hardware: "Any hardware",
|
||||
hardwareFamily: "Any hardware",
|
||||
hardware: "Choose a hardware variant",
|
||||
mode: "Any connection / mode",
|
||||
variant: "Any hardware/profile variant",
|
||||
};
|
||||
@@ -614,7 +682,10 @@
|
||||
values.slice().sort(function (a, b) {
|
||||
return optionSort(field, a, b);
|
||||
}).forEach(function (value) {
|
||||
const option = createElement("option", labelFor(field, value));
|
||||
const label = field === "hardware"
|
||||
? humanizeHardwareVariant(value, filters.hardwareFamily)
|
||||
: labelFor(field, value);
|
||||
const option = createElement("option", label);
|
||||
option.value = value;
|
||||
select.appendChild(option);
|
||||
});
|
||||
@@ -658,18 +729,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
function stabilizeSingleChoices() {
|
||||
function valuesForField(field) {
|
||||
return facetValues(
|
||||
catalog.profiles,
|
||||
filters,
|
||||
field,
|
||||
field === "hardwareFamily" ? ["hardware"] : []
|
||||
);
|
||||
}
|
||||
|
||||
function stabilizeFilters() {
|
||||
let changed = true;
|
||||
let passes = 0;
|
||||
while (changed && passes <= FACET_FIELDS.length) {
|
||||
changed = false;
|
||||
passes += 1;
|
||||
FACET_FIELDS.forEach(function (field) {
|
||||
const values = facetValues(catalog.profiles, filters, field);
|
||||
if (field === "hardware" && !filters.hardwareFamily) {
|
||||
if (filters.hardware) {
|
||||
filters.hardware = "";
|
||||
changed = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const values = valuesForField(field);
|
||||
if (filters[field] && !values.includes(filters[field])) {
|
||||
filters[field] = "";
|
||||
changed = true;
|
||||
} else if (!filters[field] && values.length === 1) {
|
||||
} else if (field === "hardware" && filters.hardwareFamily &&
|
||||
!filters[field] && values.length === 1) {
|
||||
filters[field] = values[0];
|
||||
changed = true;
|
||||
}
|
||||
@@ -678,13 +766,16 @@
|
||||
}
|
||||
|
||||
function refreshFacets() {
|
||||
stabilizeSingleChoices();
|
||||
stabilizeFilters();
|
||||
FACET_FIELDS.forEach(function (field) {
|
||||
setControlOptions(
|
||||
field,
|
||||
facetValues(catalog.profiles, filters, field)
|
||||
);
|
||||
setControlOptions(field, valuesForField(field));
|
||||
});
|
||||
const hardwareVariants = valuesForField("hardware");
|
||||
const hardwareVariantControl = root.querySelector(
|
||||
'[data-role="hardware-variant-control"]'
|
||||
);
|
||||
hardwareVariantControl.hidden = !filters.hardwareFamily ||
|
||||
hardwareVariants.length <= 1;
|
||||
render();
|
||||
}
|
||||
|
||||
@@ -778,6 +869,7 @@
|
||||
const target = event.target;
|
||||
const field = target.dataset.choiceField || target.dataset.field;
|
||||
if (!FACET_FIELDS.includes(field)) return;
|
||||
if (field === "hardwareFamily") filters.hardware = "";
|
||||
filters[field] = target.value;
|
||||
refreshFacets();
|
||||
});
|
||||
@@ -851,6 +943,8 @@
|
||||
flattenReleaseAssets: flattenReleaseAssets,
|
||||
parseFirmwareAsset: parseFirmwareAsset,
|
||||
parseTargetProfile: parseTargetProfile,
|
||||
hardwareFamilyFor: hardwareFamilyFor,
|
||||
humanizeHardwareVariant: humanizeHardwareVariant,
|
||||
buildCatalog: buildCatalog,
|
||||
profileMatches: profileMatches,
|
||||
profileMatchesFacets: profileMatchesFacets,
|
||||
|
||||
Reference in New Issue
Block a user