fix: workspace updates on profile switch; remove redundant topbar workspace chip

Two changes:

1. Workspace updates correctly on profile switch
   switchToProfile() now applies data.default_workspace from the switch
   response to the current session via /api/session/update, updates
   S.session.workspace in-memory, and stores S._profileDefaultWorkspace
   so the next new session also inherits the profile's workspace.
   newSession() in sessions.js picks up S._profileDefaultWorkspace when
   creating a new session after a profile switch.

2. Workspace chip removed from topbar
   The workspace was shown in two places: the topbar chip (wsChip) AND
   the sidebar bottom display (sidebarWsDisplay with name + full path).
   The topbar chip was redundant, cluttered the topbar, and pushed other
   chips (profile, model, clear, settings) off screen.
   Removed wsChip from the topbar entirely. The sidebar display is now
   the sole workspace UI, consistent and unambiguous.
   Moved wsDropdown to live inside the sidebar position:relative wrapper
   so it opens downward from sidebarWsDisplay. Updated the click-outside
   listener to close on clicks outside sidebarWsDisplay/wsDropdown.
   Removed stale wsChip update code from syncTopbar() in ui.js.

Tests: 426 passed, 0 failed.
This commit is contained in:
Nathan Esquenazi
2026-04-03 19:38:33 +00:00
parent c778c1eb0c
commit d4ab01c152
5 changed files with 33 additions and 20 deletions

View File

@@ -145,6 +145,7 @@
<option value="meta-llama/llama-4-scout">Llama 4 Scout</option>
</optgroup>
</select>
<div style="position:relative">
<div id="sidebarWsDisplay" style="display:flex;align-items:center;gap:7px;padding:0 0 8px;cursor:pointer;border-radius:8px;transition:background .15s" onclick="toggleWsDropdown()" title="Switch workspace">
<span style="font-size:14px;opacity:.7">&#128193;</span>
<div style="min-width:0;flex:1">
@@ -153,6 +154,8 @@
</div>
<span style="font-size:10px;color:var(--muted);flex-shrink:0">&#9662;</span>
</div>
<div class="ws-dropdown" id="wsDropdown"></div>
</div>
<div class="sidebar-actions">
<button class="sm-btn" id="btnDownload" title="Download as Markdown">&#8595; Transcript</button>
<button class="sm-btn" id="btnExportJSON" title="Export full session as JSON">&#10092;/&#10093; JSON</button>
@@ -174,10 +177,7 @@
<div class="profile-dropdown" id="profileDropdown"></div>
</div>
<div class="chip model" id="modelChip">GPT-5.4 Mini</div>
<div id="wsChipWrap" style="position:relative">
<div class="chip ws-chip" id="wsChip" onclick="toggleWsDropdown()" title="Switch workspace" style="cursor:pointer">&#128193; test-workspace &#9662;</div>
<div class="ws-dropdown" id="wsDropdown"></div>
</div>
<button class="chip clear-btn" id="btnClearConv" onclick="clearConversation()" title="Clear all messages in this conversation" style="display:none">&#128465; Clear</button>
<button class="chip gear-btn" id="btnSettings" onclick="toggleSettings()" title="Settings">&#9881;</button>
<button class="chip mobile-files-btn" id="btnMobileFiles" onclick="toggleMobileFiles()" title="Files">&#128193;</button>

View File

@@ -490,7 +490,7 @@ function closeWsDropdown(){
if(dd)dd.classList.remove('open');
}
document.addEventListener('click',e=>{
if(!e.target.closest('#wsChipWrap'))closeWsDropdown();
if(!e.target.closest('#sidebarWsDisplay') && !e.target.closest('#wsDropdown'))closeWsDropdown();
});
async function loadWorkspacesPanel(){
@@ -683,6 +683,24 @@ async function switchToProfile(name) {
// Refresh workspace list (now profile-local)
_workspaceList = null;
await loadWorkspaceList();
// Apply the profile's default workspace to the current session
if (data.default_workspace) {
if (S.session) {
// Update existing session's workspace to the profile default
try {
await api('/api/session/update', { method: 'POST', body: JSON.stringify({
session_id: S.session.session_id,
workspace: data.default_workspace,
model: S.session.model,
})});
S.session.workspace = data.default_workspace;
} catch (_) {}
}
// Store as the profile default so the next new session picks it up
S._profileDefaultWorkspace = data.default_workspace;
}
// Reset profile filter and refresh session list
_showAllProfiles = false;
await renderSessionList();

View File

@@ -13,7 +13,9 @@ async function newSession(flash){
MSG_QUEUE.length=0;updateQueueBadge();
S.toolCalls=[];
clearLiveToolCards();
const inheritWs=S.session?S.session.workspace:null;
// Use profile default workspace for new sessions after a profile switch,
// otherwise inherit from the current session (or let server pick the default)
const inheritWs=S._profileDefaultWorkspace||( S.session?S.session.workspace:null);
const data=await api('/api/session/new',{method:'POST',body:JSON.stringify({model:$('modelSelect').value,workspace:inheritWs})});
S.session=data.session;S.messages=data.session.messages||[];
if(flash)S.session._flash=true;

View File

@@ -345,7 +345,7 @@
/* ── Workspace dropdown (topbar) ── */
.ws-chip{user-select:none;}
.ws-dropdown{display:none;position:absolute;top:calc(100% + 6px);right:0;min-width:240px;background:#1a2535;border:1px solid var(--border2);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:200;overflow:hidden;max-height:320px;overflow-y:auto;}
.ws-dropdown{display:none;position:absolute;top:calc(100% + 4px);left:0;right:0;min-width:200px;background:#1a2535;border:1px solid var(--border2);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.4);z-index:200;overflow:hidden;max-height:320px;overflow-y:auto;}
.ws-dropdown.open{display:block;}
.ws-opt{padding:9px 14px;cursor:pointer;transition:background .12s;}
.ws-opt:hover{background:rgba(255,255,255,.07);}

View File

@@ -336,13 +336,6 @@ function syncTopbar(){
const displayModel=$('modelSelect').value||m;
$('modelChip').textContent=getModelLabel(displayModel);
const ws=S.session.workspace||'';
$('wsChip').textContent=ws.split('/').slice(-2).join('/')||ws;
// Update workspace chip in topbar with friendly name from workspace list
const wsChipEl=$('wsChip');
if(wsChipEl){
const wsFriendly=getWorkspaceFriendlyName(ws);
wsChipEl.textContent='\u{1F4C1} '+wsFriendly+' \u25BE';
}
// Update sidebar workspace display
const sidebarName=$('sidebarWsName');
const sidebarPath=$('sidebarWsPath');