[feat](trx-frontend-http): rename Decoders tab to Digital modes and filter by active rig
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -3490,7 +3490,8 @@ async function switchRigFromSelect(selectEl) {
|
|||||||
if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId);
|
if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId);
|
||||||
if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId);
|
if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId);
|
||||||
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
|
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
|
||||||
// Decode SSE and history are rig-independent — no reconnect needed.
|
// Reconnect decode stream so history + live messages filter to the new rig.
|
||||||
|
connectDecode();
|
||||||
// Switch this session's rig and reconnect SSE to the new rig's
|
// Switch this session's rig and reconnect SSE to the new rig's
|
||||||
// state channel.
|
// state channel.
|
||||||
try {
|
try {
|
||||||
@@ -4018,11 +4019,11 @@ if (spectrumBwSweetBtn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Tab navigation ---
|
// --- Tab navigation ---
|
||||||
const TAB_ORDER = ["main", "bookmarks", "decoders", "map", "settings", "about"];
|
const TAB_ORDER = ["main", "bookmarks", "digital-modes", "map", "settings", "about"];
|
||||||
const TAB_PATHS = {
|
const TAB_PATHS = {
|
||||||
main: "/",
|
main: "/",
|
||||||
bookmarks: "/bookmarks",
|
bookmarks: "/bookmarks",
|
||||||
decoders: "/decoders",
|
"digital-modes": "/digital-modes",
|
||||||
map: "/map",
|
map: "/map",
|
||||||
settings: "/settings",
|
settings: "/settings",
|
||||||
about: "/about",
|
about: "/about",
|
||||||
@@ -8196,6 +8197,7 @@ function updateDecodeStatus(text) {
|
|||||||
if (ft2 && ft2.textContent !== "Receiving") ft2.textContent = text;
|
if (ft2 && ft2.textContent !== "Receiving") ft2.textContent = text;
|
||||||
}
|
}
|
||||||
function dispatchDecodeMessage(msg) {
|
function dispatchDecodeMessage(msg) {
|
||||||
|
if (lastActiveRigId && msg.rig_id && msg.rig_id !== lastActiveRigId) return;
|
||||||
if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg);
|
if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg);
|
||||||
if (msg.type === "vdes" && window.onServerVdes) window.onServerVdes(msg);
|
if (msg.type === "vdes" && window.onServerVdes) window.onServerVdes(msg);
|
||||||
if (msg.type === "aprs" && window.onServerAprs) window.onServerAprs(msg);
|
if (msg.type === "aprs" && window.onServerAprs) window.onServerAprs(msg);
|
||||||
@@ -8209,6 +8211,10 @@ function dispatchDecodeMessage(msg) {
|
|||||||
|
|
||||||
function dispatchDecodeBatch(batch) {
|
function dispatchDecodeBatch(batch) {
|
||||||
if (!Array.isArray(batch) || batch.length === 0) return;
|
if (!Array.isArray(batch) || batch.length === 0) return;
|
||||||
|
if (lastActiveRigId) {
|
||||||
|
batch = batch.filter((m) => !m.rig_id || m.rig_id === lastActiveRigId);
|
||||||
|
if (batch.length === 0) return;
|
||||||
|
}
|
||||||
const type = String(batch[0]?.type || "");
|
const type = String(batch[0]?.type || "");
|
||||||
const uniformType = batch.every((msg) => String(msg?.type || "") === type);
|
const uniformType = batch.every((msg) => String(msg?.type || "") === type);
|
||||||
if (uniformType) {
|
if (uniformType) {
|
||||||
@@ -8270,6 +8276,7 @@ function scheduleDecodeHistoryDrainStep(callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function decodeHistoryUrl() {
|
function decodeHistoryUrl() {
|
||||||
|
if (lastActiveRigId) return "/decode/history?remote=" + encodeURIComponent(lastActiveRigId);
|
||||||
return "/decode/history";
|
return "/decode/history";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,9 @@
|
|||||||
<svg class="tab-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 2h8v12l-4-2.5L4 14V2z"/></svg>
|
<svg class="tab-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 2h8v12l-4-2.5L4 14V2z"/></svg>
|
||||||
<span class="tab-label">Bookmarks</span>
|
<span class="tab-label">Bookmarks</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" data-tab="decoders">
|
<button class="tab" data-tab="digital-modes">
|
||||||
<svg class="tab-icon" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="1" y="11" width="2.5" height="4" rx="0.5"/><rect x="4.75" y="8" width="2.5" height="7" rx="0.5"/><rect x="8.5" y="5" width="2.5" height="10" rx="0.5"/><rect x="12.25" y="2" width="2.5" height="13" rx="0.5"/></svg>
|
<svg class="tab-icon" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="1" y="11" width="2.5" height="4" rx="0.5"/><rect x="4.75" y="8" width="2.5" height="7" rx="0.5"/><rect x="8.5" y="5" width="2.5" height="10" rx="0.5"/><rect x="12.25" y="2" width="2.5" height="13" rx="0.5"/></svg>
|
||||||
<span class="tab-label">Decoders</span>
|
<span class="tab-label">Digital modes</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" data-tab="map">
|
<button class="tab" data-tab="map">
|
||||||
<svg class="tab-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2a4 4 0 0 1 4 4c0 3-4 8-4 8S4 9 4 6a4 4 0 0 1 4-4z"/><circle cx="8" cy="6" r="1.2" fill="currentColor" stroke="none"/></svg>
|
<svg class="tab-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2a4 4 0 0 1 4 4c0 3-4 8-4 8S4 9 4 6a4 4 0 0 1 4-4z"/><circle cx="8" cy="6" r="1.2" fill="currentColor" stroke="none"/></svg>
|
||||||
@@ -419,7 +419,7 @@
|
|||||||
<label class="bm-label">Locator
|
<label class="bm-label">Locator
|
||||||
<input type="text" id="bm-locator" class="status-input" maxlength="6" placeholder="e.g. JO93" />
|
<input type="text" id="bm-locator" class="status-input" maxlength="6" placeholder="e.g. JO93" />
|
||||||
</label>
|
</label>
|
||||||
<div class="bm-label">Decoders
|
<div class="bm-label">Digital modes
|
||||||
<div class="bm-decoder-checks">
|
<div class="bm-decoder-checks">
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-aprs" value="aprs" /> APRS</label>
|
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-aprs" value="aprs" /> APRS</label>
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ais" value="ais" /> AIS</label>
|
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ais" value="ais" /> AIS</label>
|
||||||
@@ -451,7 +451,7 @@
|
|||||||
<th>BW</th>
|
<th>BW</th>
|
||||||
<th>Locator</th>
|
<th>Locator</th>
|
||||||
<th>Category</th>
|
<th>Category</th>
|
||||||
<th>Decoders</th>
|
<th>Digital modes</th>
|
||||||
<th>Comment</th>
|
<th>Comment</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -469,7 +469,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tab-decoders" class="tab-panel" style="display:none;">
|
<div id="tab-digital-modes" class="tab-panel" style="display:none;">
|
||||||
<div class="sub-tab-bar">
|
<div class="sub-tab-bar">
|
||||||
<button class="sub-tab active" data-subtab="overview">Overview</button>
|
<button class="sub-tab active" data-subtab="overview">Overview</button>
|
||||||
<button class="sub-tab" data-subtab="ais">AIS</button>
|
<button class="sub-tab" data-subtab="ais">AIS</button>
|
||||||
|
|||||||
@@ -2617,7 +2617,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
.tab-icon { display: block; }
|
.tab-icon { display: block; }
|
||||||
/* Shorten long tab labels to keep bottom nav compact */
|
/* Shorten long tab labels to keep bottom nav compact */
|
||||||
.tab[data-tab="bookmarks"] .tab-label { font-size: 0.6rem; }
|
.tab[data-tab="bookmarks"] .tab-label { font-size: 0.6rem; }
|
||||||
.tab[data-tab="decoders"] .tab-label { font-size: 0.6rem; }
|
.tab[data-tab="digital-modes"] .tab-label { font-size: 0.6rem; }
|
||||||
.top-bar-actions {
|
.top-bar-actions {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@@ -2639,7 +2639,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
#tab-main,
|
#tab-main,
|
||||||
#tab-decoders,
|
#tab-digital-modes,
|
||||||
#tab-map,
|
#tab-map,
|
||||||
#tab-about {
|
#tab-about {
|
||||||
scroll-margin-top: 0.75rem;
|
scroll-margin-top: 0.75rem;
|
||||||
@@ -2917,7 +2917,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
.bm-col-bw::before { content: "Bandwidth"; }
|
.bm-col-bw::before { content: "Bandwidth"; }
|
||||||
.bm-col-loc::before { content: "Locator"; }
|
.bm-col-loc::before { content: "Locator"; }
|
||||||
.bm-col-cat::before { content: "Category"; }
|
.bm-col-cat::before { content: "Category"; }
|
||||||
.bm-col-dec::before { content: "Decoders"; }
|
.bm-col-dec::before { content: "Digital modes"; }
|
||||||
.bm-col-cmt { grid-column: 1 / -1; }
|
.bm-col-cmt { grid-column: 1 / -1; }
|
||||||
.bm-col-cmt::before { content: "Comment"; }
|
.bm-col-cmt::before { content: "Comment"; }
|
||||||
.bm-col-act { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.4rem; padding-top: 0.25rem; }
|
.bm-col-act { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.4rem; padding-top: 0.25rem; }
|
||||||
|
|||||||
@@ -1945,7 +1945,7 @@ pub async fn set_vchan_mode(
|
|||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(index)
|
cfg.service(index)
|
||||||
.service(map_index)
|
.service(map_index)
|
||||||
.service(decoders_index)
|
.service(digital_modes_index)
|
||||||
.service(settings_index)
|
.service(settings_index)
|
||||||
.service(about_index)
|
.service(about_index)
|
||||||
.service(status_api)
|
.service(status_api)
|
||||||
@@ -2057,8 +2057,8 @@ async fn map_index() -> impl Responder {
|
|||||||
no_cache_response("text/html; charset=utf-8", status::index_html())
|
no_cache_response("text/html; charset=utf-8", status::index_html())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/decoders")]
|
#[get("/digital-modes")]
|
||||||
async fn decoders_index() -> impl Responder {
|
async fn digital_modes_index() -> impl Responder {
|
||||||
no_cache_response("text/html; charset=utf-8", status::index_html())
|
no_cache_response("text/html; charset=utf-8", status::index_html())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ impl RouteAccess {
|
|||||||
if path == "/"
|
if path == "/"
|
||||||
|| path == "/index.html"
|
|| path == "/index.html"
|
||||||
|| path == "/map"
|
|| path == "/map"
|
||||||
|| path == "/decoders"
|
|| path == "/digital-modes"
|
||||||
|| path == "/settings"
|
|| path == "/settings"
|
||||||
|| path == "/about"
|
|| path == "/about"
|
||||||
|| path.starts_with("/auth/")
|
|| path.starts_with("/auth/")
|
||||||
@@ -666,7 +666,10 @@ mod tests {
|
|||||||
fn test_route_access_public_paths() {
|
fn test_route_access_public_paths() {
|
||||||
assert_eq!(RouteAccess::from_path("/"), RouteAccess::Public);
|
assert_eq!(RouteAccess::from_path("/"), RouteAccess::Public);
|
||||||
assert_eq!(RouteAccess::from_path("/map"), RouteAccess::Public);
|
assert_eq!(RouteAccess::from_path("/map"), RouteAccess::Public);
|
||||||
assert_eq!(RouteAccess::from_path("/decoders"), RouteAccess::Public);
|
assert_eq!(
|
||||||
|
RouteAccess::from_path("/digital-modes"),
|
||||||
|
RouteAccess::Public
|
||||||
|
);
|
||||||
assert_eq!(RouteAccess::from_path("/settings"), RouteAccess::Public);
|
assert_eq!(RouteAccess::from_path("/settings"), RouteAccess::Public);
|
||||||
assert_eq!(RouteAccess::from_path("/about"), RouteAccess::Public);
|
assert_eq!(RouteAccess::from_path("/about"), RouteAccess::Public);
|
||||||
assert_eq!(RouteAccess::from_path("/auth/login"), RouteAccess::Public);
|
assert_eq!(RouteAccess::from_path("/auth/login"), RouteAccess::Public);
|
||||||
|
|||||||
Reference in New Issue
Block a user