From 2c65e5b4c2f7bec00b6dfe85bbeea53759ca23a4 Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Mon, 13 Apr 2026 12:01:32 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20filter=20status=20entries=20from=20visib?= =?UTF-8?q?le=20sessions=20=E2=80=94=20no=20more=20duplicate=20blank/offli?= =?UTF-8?q?ne=20tiles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unreachable/auth_failed status entries from the federation response were rendered twice: once as a blank session tile (no name) by buildTileHTML, and again as an 'Offline' status tile by the separate status rendering loop. Fix: getVisibleSessions() now filters out entries with a status field. Status tiles are still rendered separately from the full sessions array. --- muxplex/frontend/app.js | 2 ++ muxplex/frontend/tests/test_app.mjs | 31 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/muxplex/frontend/app.js b/muxplex/frontend/app.js index 4d112dd..e4cbbb9 100644 --- a/muxplex/frontend/app.js +++ b/muxplex/frontend/app.js @@ -530,6 +530,8 @@ function buildStatusTileHTML(deviceName, statusText, statusClass) { function getVisibleSessions(sessions) { var hidden = (_serverSettings && _serverSettings.hidden_sessions) || []; return (sessions || []).filter(function(s) { + // Skip status entries (unreachable, auth_failed) — rendered separately as status tiles + if (s.status) return false; if (hidden.length > 0 && hidden.includes(s.name)) { return false; } diff --git a/muxplex/frontend/tests/test_app.mjs b/muxplex/frontend/tests/test_app.mjs index 257fc9e..7a76b8f 100644 --- a/muxplex/frontend/tests/test_app.mjs +++ b/muxplex/frontend/tests/test_app.mjs @@ -1769,6 +1769,37 @@ test('renderSidebar does nothing when view is not fullscreen', () => { globalThis.document.getElementById = origGetById; }); +// --- getVisibleSessions --- + +test('getVisibleSessions filters out entries with unreachable status (no name)', () => { + const sessions = [ + { name: 'real-session', snapshot: '' }, + { status: 'unreachable', remoteId: 0, deviceName: 'alienware-r13' }, + ]; + const result = app.getVisibleSessions(sessions); + assert.strictEqual(result.length, 1, 'should return only the real session'); + assert.strictEqual(result[0].name, 'real-session'); +}); + +test('getVisibleSessions filters out entries with auth_failed status', () => { + const sessions = [ + { name: 'real-session', snapshot: '' }, + { name: 'Workstation', status: 'auth_failed' }, + ]; + const result = app.getVisibleSessions(sessions); + assert.strictEqual(result.length, 1, 'auth_failed entry should be filtered out'); + assert.strictEqual(result[0].name, 'real-session'); +}); + +test('getVisibleSessions passes through sessions with no status field', () => { + const sessions = [ + { name: 'alpha', snapshot: '' }, + { name: 'beta', snapshot: '' }, + ]; + const result = app.getVisibleSessions(sessions); + assert.strictEqual(result.length, 2, 'normal sessions should all pass through'); +}); + // ─── initSidebar ───────────────────────────────────────────────────────────── test('initSidebar defaults to open (removes sidebar--collapsed) on wide screens when no stored value', () => {