feat(sessions): optional per-active-workspace sidebar filter#2951
feat(sessions): optional per-active-workspace sidebar filter#2951Sanjays2402 wants to merge 2 commits into
Conversation
Issue nesquena#2549 Slice A. Adds a Settings > Preferences toggle 'Show sessions from all workspaces' (default on) that, when turned off, hides sidebar rows whose stored workspace path does not match the active workspace. The filter runs after the existing project filter inside renderSessionListFromCache and reads window._showAllWorkspaces, mirroring how show_cli_sessions / _showAllProfiles already scope the list along other axes. Re-renders on workspace switch and on toggle change. Closes nesquena#2549
SummaryThanks @Sanjays2402 — this lands the Slice A shape the maintainer scoped in the issue thread, including the Code-quality is good and the test file is appropriately scoped (file-level assertions that catch regressions without coupling to internals). I want to flag three behavioral concerns before merge plus one improvement on the spec. Code referenceThe filter at const _showAllWs=(typeof window!=='undefined')?window._showAllWorkspaces!==false:true;
const _activeWsPath=(typeof S!=='undefined'&&S.session&&S.session.workspace)
||(typeof _currentWorkspaceDetail!=='undefined'&&_currentWorkspaceDetail?_currentWorkspaceDetail.path:null);
const workspaceFiltered=(_showAllWs||!_activeWsPath)
?projectFiltered
:projectFiltered.filter(s=>!s.workspace||s.workspace===_activeWsPath);And the active-workspace update in S.session.workspace=path;
// Trigger a sidebar re-render when the per-workspace filter is active (#2549).
if(typeof renderSessionListFromCache==='function') renderSessionListFromCache();Diagnosis1. Pinned sessions from other workspaces silently disappear (most important)The filter drops every row whose Two options:
2. No empty-state messaging when the filter yields zero rowsThe existing project-filter empty state at if(_activeProject&&sessions.length===0){
const empty=document.createElement('div');
empty.style.cssText='padding:20px 14px;color:var(--muted);font-size:12px;text-align:center;opacity:.7;';
empty.textContent=_activeProject===NO_PROJECT_FILTER?'No unassigned sessions.':'No sessions in this project yet.';
list.appendChild(empty);
}A user who toggles the filter on, then switches to a brand-new workspace, sees a blank sidebar with no explanation. Adding a sibling branch for the workspace filter — something like: if(!_showAllWs&&_activeWsPath&&!_activeProject&&sessions.length===0){
const empty=document.createElement('div');
empty.style.cssText='padding:20px 14px;color:var(--muted);font-size:12px;text-align:center;opacity:.7;';
empty.textContent='No sessions in this workspace yet.';
list.appendChild(empty);
}Even better with a small "Show all workspaces" link that flips the toggle, but the text-only version is the minimum bar. 3. Case-insensitive paths (the maintainer's "Slice C" sharp edge)The maintainer flagged this on the issue: A defensive option for now: use a normalized comparison that does cheap casefold without committing to a storage policy: const norm=p=>typeof p==='string'?p.replace(/\/+$/,'').toLowerCase():p;
:projectFiltered.filter(s=>!s.workspace||norm(s.workspace)===norm(_activeWsPath))That's lossless (doesn't change stored values, just comparison), and means Slice C only needs to decide what to do about the stored value, not what to do about the filter. But out of scope is also fine — your call. 4. Minor:
|
… rejects all (review feedback from @nesquena-hermes)
|
Both real, fixed in 8bd6f42: pinned rows now bypass the workspace filter the same way |
Slice A from the maintainer's plan in #2549: a Preferences toggle that scopes the sidebar to the active workspace, defaulting to today's behaviour (show all).
What this does
show_all_workspacesin_SETTINGS_DEFAULTS(defaultTrue), added to_SETTINGS_BOOL_KEYSso the existing validator covers it.data-i18nkeys (settings_label_all_workspaces,settings_desc_all_workspaces) added to every locale block.renderSessionListFromCacheruns a workspace filter right after the existing project filter and before the archived filter. It readswindow._showAllWorkspacesand compares each row's storeds.workspaceagainst the active workspace path (preferringS.session.workspaceand falling back to_currentWorkspaceDetail.pathfrom panels.js).boot.jshydrateswindow._showAllWorkspacesfrom settings on load and clears it on logout.switchToWorkspacecallsrenderSessionListFromCacheafter the workspace update so the sidebar reflects the new scope immediately.Default
Truekeeps existing users on the current behaviour. Rows missing a workspace value are kept (defensive; matches how cron/CLI rows without resolved workspaces behave today).Verification
pytest tests/test_issue2549_workspace_filter.py— 7 passed (new file covering default, filter ordering, settings wiring, i18n).pytest tests/test_chinese_locale.py tests/test_japanese_locale.py tests/test_korean_locale.py tests/test_russian_locale.py tests/test_spanish_locale.py tests/test_turkish_locale.py— 33 passed (locale parity still holds with the two new keys).node --checkonboot.js,i18n.js,panels.js,sessions.js.python3 -m py_compile api/config.py.Closes #2549
Deviation from spec (worth flagging)
The maintainer's plan said use
_currentWorkspaceDetail.pathas the active workspace. This PR prefersS.session.workspaceand falls back to_currentWorkspaceDetail.pathonly when the former is missing._currentWorkspaceDetailis only set after the user opens Settings → Workspaces (defaultnullatstatic/panels.js:27), so the spec as written would silently no-op for any user who never opens that panel. PreferringS.session.workspacemakes the filter work on first launch.Review-feedback fixes (8bd6f42)
!s.workspacerows do) so the★ Pinnedgroup stays visible across workspace switches.