From 35a492ec95350b101482a59e7d482e6c01f1183b Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sat, 1 Aug 2026 11:05:45 +0200 Subject: [PATCH] fix(ui): gate broadcast layout on rig capability --- .../trx-frontend-http/assets/web/app.js | 4 ++ .../trx-frontend-http/assets/web/ui-core.js | 39 ++++++++++++++++--- .../trx-frontend-http/src/api/rig.rs | 2 + 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index 173fa189..7114fd45 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -1305,6 +1305,10 @@ async function refreshRigList() { } }); serverRigs = rigs; + window.trxUi?.setBroadcastLayoutAvailable(rigs.some((rig) => + Array.isArray(rig?.supported_modes) + && rig.supported_modes.map(normalizeMode).includes("WFM") + )); serverActiveRigId = data.active_remote || null; applyRigList(data.active_remote, rigIds, displayNames); window.trx.modules.map?.syncAprsReceiverMarker(); diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/ui-core.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/ui-core.js index 0471b366..fb72d6cd 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/ui-core.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/ui-core.js @@ -127,14 +127,39 @@ const layouts = { compact: { label: "Compact", advanced: false, preferredTab: "main" }, - broadcast: { label: "Broadcast", advanced: false, preferredTab: "main" }, + broadcast: { label: "Broadcast", advanced: false, preferredTab: "main", capability: "broadcast" }, digital: { label: "Digital", advanced: false, preferredTab: "digital-modes" }, full: { label: "Full controls", advanced: true, preferredTab: "main" }, }; + let hasBroadcastRig = false; + + function broadcastLayoutAvailable() { + return hasBroadcastRig; + } + + function refreshLayoutOptions() { + const select = document.getElementById("operator-layout-select"); + if (!select) return; + const previous = select.value || document.body.dataset.operatorLayout || "compact"; + select.replaceChildren(); + Object.entries(layouts).forEach(([value, layout]) => { + if (layout.capability === "broadcast" && !broadcastLayoutAvailable()) return; + select.add(new Option(layout.label, value)); + }); + const available = Array.from(select.options).some(option => option.value === previous); + select.value = available ? previous : "compact"; + if (!available && previous === "broadcast") api.applyLayout("compact"); + } + + api.setBroadcastLayoutAvailable = function setBroadcastLayoutAvailable(available) { + hasBroadcastRig = Boolean(available); + refreshLayoutOptions(); + }; api.applyLayout = function applyLayout(name, options = {}) { - const layout = layouts[name] || layouts.compact; - document.body.dataset.operatorLayout = name in layouts ? name : "compact"; + const permittedName = name === "broadcast" && !broadcastLayoutAvailable() ? "compact" : name; + const layout = layouts[permittedName] || layouts.compact; + document.body.dataset.operatorLayout = permittedName in layouts ? permittedName : "compact"; localStorage.setItem("trxOperatorLayout", document.body.dataset.operatorLayout); const details = document.getElementById("advanced-radio-controls"); if (details) details.open = layout.advanced; @@ -150,10 +175,12 @@ label.className = "operator-layout-picker"; label.innerHTML = 'Operator layout'; const select = label.querySelector("select"); - Object.entries(layouts).forEach(([value, layout]) => select.add(new Option(layout.label, value))); - select.value = localStorage.getItem("trxOperatorLayout") || "compact"; - select.addEventListener("change", () => api.applyLayout(select.value, { navigate: true })); + const savedLayout = localStorage.getItem("trxOperatorLayout") || "compact"; actions.insertBefore(label, actions.firstChild); + select.value = savedLayout; + refreshLayoutOptions(); + if (savedLayout !== "broadcast" && layouts[savedLayout]) select.value = savedLayout; + select.addEventListener("change", () => api.applyLayout(select.value, { navigate: true })); api.applyLayout(select.value); } diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/api/rig.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/api/rig.rs index 4a92eaff..7504926d 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/api/rig.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/api/rig.rs @@ -388,6 +388,7 @@ struct RigListItem { display_name: Option, manufacturer: String, model: String, + supported_modes: Vec, initialized: bool, #[serde(skip_serializing_if = "Option::is_none")] latitude: Option, @@ -422,6 +423,7 @@ fn map_rig_entry(entry: &RemoteRigEntry) -> RigListItem { display_name: entry.display_name.clone(), manufacturer: entry.state.info.manufacturer.clone(), model: entry.state.info.model.clone(), + supported_modes: entry.state.info.capabilities.supported_modes.clone(), initialized: entry.state.initialized, latitude: entry.state.server_latitude, longitude: entry.state.server_longitude,