feat: rewrite getVisibleSessions() to honor active view (task-2)
- Add _activeView state variable with default 'all' in App state section - Rewrite getVisibleSessions() to filter by active view: - 'all' view: excludes hidden sessions - 'hidden' view: shows only hidden sessions - user view: filters to view's sessions list using sessionKey - Falls back to 'all' if active view no longer exists - Add _getActiveView() and _setActiveView() test helpers - Export new test helpers in window.MuxplexApp (module.exports) - Add 6 new tests covering all acceptance criteria Tests added: - test_active_view_state_variable_exists - test_get_visible_sessions_all_view_excludes_hidden - test_get_visible_sessions_hidden_view_shows_hidden - test_get_visible_sessions_user_view_filters_by_session_key - test_get_active_view_helper_exported - test_set_active_view_helper_exported All 220 tests pass.
This commit is contained in:
+41
-5
@@ -137,6 +137,7 @@ let _settingsOpen = false;
|
||||
let _serverSettings = null;
|
||||
let _gridViewMode = 'flat';
|
||||
let _activeFilterDevice = 'all';
|
||||
let _activeView = 'all';
|
||||
const DISPLAY_DEFAULTS = {
|
||||
fontSize: 14,
|
||||
hoverPreviewDelay: 1500,
|
||||
@@ -531,18 +532,45 @@ function buildStatusTileHTML(deviceName, statusText, statusClass) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sessions with hidden session names removed.
|
||||
* Hides any session whose name appears in the hidden_sessions list,
|
||||
* regardless of whether it is local or remote (federated).
|
||||
* Consolidates the hidden-session filter used by all render paths.
|
||||
* Returns sessions filtered by the active view.
|
||||
*
|
||||
* - 'all' view: excludes hidden sessions (sessions in hidden_sessions list)
|
||||
* - 'hidden' view: shows only hidden sessions
|
||||
* - user view: shows only sessions whose sessionKey is in that view's sessions list
|
||||
*
|
||||
* Status entries (unreachable, auth_failed, empty) are always excluded —
|
||||
* they are rendered separately as status tiles.
|
||||
*
|
||||
* Falls back to 'all' behaviour if the active view no longer exists.
|
||||
*
|
||||
* @param {object[]} sessions
|
||||
* @returns {object[]}
|
||||
*/
|
||||
function getVisibleSessions(sessions) {
|
||||
var hidden = (_serverSettings && _serverSettings.hidden_sessions) || [];
|
||||
var views = (_serverSettings && _serverSettings.views) || [];
|
||||
var view = _resolveActiveView(_activeView, views);
|
||||
|
||||
return (sessions || []).filter(function(s) {
|
||||
// Skip status entries (unreachable, auth_failed) — rendered separately as status tiles
|
||||
// Skip status entries (unreachable, auth_failed, empty) — rendered separately as status tiles
|
||||
if (s.status) return false;
|
||||
|
||||
if (view === 'hidden') {
|
||||
// 'hidden' view: only show sessions that are in the hidden list
|
||||
return hidden.length > 0 && (hidden.includes(s.sessionKey || s.name) || hidden.includes(s.name));
|
||||
}
|
||||
|
||||
if (view !== 'all') {
|
||||
// User-defined view: show only sessions whose sessionKey is in this view's sessions list
|
||||
var userView = views.find(function(v) { return v.name === view; });
|
||||
if (userView) {
|
||||
var viewSessions = userView.sessions || [];
|
||||
return viewSessions.includes(s.sessionKey || s.name) || viewSessions.includes(s.name);
|
||||
}
|
||||
// View no longer exists — fall through to 'all' behaviour
|
||||
}
|
||||
|
||||
// 'all' view: exclude hidden sessions
|
||||
if (hidden.length > 0 && (hidden.includes(s.sessionKey || s.name) || hidden.includes(s.name))) {
|
||||
return false;
|
||||
}
|
||||
@@ -2499,6 +2527,12 @@ function _setActiveFilterDevice(device) {
|
||||
_activeFilterDevice = device;
|
||||
}
|
||||
|
||||
/** Test-only: get current _activeView value. */
|
||||
function _getActiveView() { return _activeView; }
|
||||
|
||||
/** Test-only: set _activeView directly. */
|
||||
function _setActiveView(view) { _activeView = view; }
|
||||
|
||||
// Recalculate fit layout on window resize
|
||||
window.addEventListener('resize', function() {
|
||||
var ds = getDisplaySettings();
|
||||
@@ -2625,5 +2659,7 @@ if (typeof module !== 'undefined' && module.exports) {
|
||||
_getGridViewMode,
|
||||
_setGridViewMode,
|
||||
_setActiveFilterDevice,
|
||||
_getActiveView,
|
||||
_setActiveView,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3010,3 +3010,86 @@ def test_settings_hidden_sessions_uses_session_key() -> None:
|
||||
"(with s.name fallback) as the checkbox value so remote sessions are "
|
||||
"stored in device_id:name format in hidden_sessions"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Active view state variable and getVisibleSessions (task-2-active-view)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_active_view_state_variable_exists() -> None:
|
||||
"""_activeView state variable must be declared with default 'all'."""
|
||||
assert "let _activeView = 'all'" in _JS, (
|
||||
"let _activeView = 'all' must be declared in the App state section of app.js"
|
||||
)
|
||||
|
||||
|
||||
def test_get_visible_sessions_all_view_excludes_hidden() -> None:
|
||||
"""getVisibleSessions must reference _activeView to honour the active view."""
|
||||
match = re.search(
|
||||
r"function getVisibleSessions\(sessions\)\s*\{(.*?)\n\}",
|
||||
_JS,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "getVisibleSessions function not found"
|
||||
body = match.group(1)
|
||||
assert "_activeView" in body, (
|
||||
"getVisibleSessions must check _activeView to filter sessions by view"
|
||||
)
|
||||
|
||||
|
||||
def test_get_visible_sessions_hidden_view_shows_hidden() -> None:
|
||||
"""getVisibleSessions must handle the 'hidden' view case."""
|
||||
match = re.search(
|
||||
r"function getVisibleSessions\(sessions\)\s*\{(.*?)\n\}",
|
||||
_JS,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "getVisibleSessions function not found"
|
||||
body = match.group(1)
|
||||
assert "'hidden'" in body or '"hidden"' in body, (
|
||||
"getVisibleSessions must explicitly handle the 'hidden' view (show only hidden sessions)"
|
||||
)
|
||||
|
||||
|
||||
def test_get_visible_sessions_user_view_filters_by_session_key() -> None:
|
||||
"""getVisibleSessions must use sessionKey when filtering for a user-defined view."""
|
||||
match = re.search(
|
||||
r"function getVisibleSessions\(sessions\)\s*\{(.*?)\n\}",
|
||||
_JS,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "getVisibleSessions function not found"
|
||||
body = match.group(1)
|
||||
assert "sessionKey" in body, (
|
||||
"getVisibleSessions must use sessionKey to match sessions against the user view's "
|
||||
"sessions list"
|
||||
)
|
||||
|
||||
|
||||
def test_get_active_view_helper_exported() -> None:
|
||||
"""window.MuxplexApp must export _getActiveView test helper."""
|
||||
match = re.search(
|
||||
r"module\.exports\s*=\s*\{(.*?)\};",
|
||||
_JS,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "module.exports block not found"
|
||||
exports = match.group(1)
|
||||
assert "_getActiveView" in exports, (
|
||||
"module.exports must export _getActiveView test helper"
|
||||
)
|
||||
|
||||
|
||||
def test_set_active_view_helper_exported() -> None:
|
||||
"""window.MuxplexApp must export _setActiveView test helper."""
|
||||
match = re.search(
|
||||
r"module\.exports\s*=\s*\{(.*?)\};",
|
||||
_JS,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "module.exports block not found"
|
||||
exports = match.group(1)
|
||||
assert "_setActiveView" in exports, (
|
||||
"module.exports must export _setActiveView test helper"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user