var WS_LIST = [ { id: 'ws_default', slug: 'default', name: 'Default workspace', role: 'Owner', letter: 'D', color: '#0d9488' } ]; var workspaceLoadPromise = null; var workspaceLoadFailed = false; var lastWorkspaceId = null; function tKey(key) { return typeof t === 'function' ? t(key) : key; } function tfKey(key, vars) { return typeof tf === 'function' ? tf(key, vars) : key; } function buildIconSvg(href, width, height) { var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', String(width)); svg.setAttribute('height', String(height)); var use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); use.setAttribute('href', href); svg.appendChild(use); return svg; } function workspaceColor(index) { return ['#0d9488', '#7c3aed', '#0891b2', '#f59e0b', '#2563eb'][index % 5]; } function mapWorkspace(record, index) { var workspace = record && record.workspace ? record.workspace : record; var displayName = workspace.display_name || workspace.slug || workspace.id; var settings = workspace.settings || {}; var role = record && record.role ? String(record.role).replace(/^\w/, function(char) { return char.toUpperCase(); }) : tKey('workspace_setup.role.owner'); return { id: workspace.id, slug: workspace.slug, name: displayName, role: role, letter: displayName.charAt(0).toUpperCase(), color: settings.color || workspaceColor(index), status: workspace.status, settings: settings, }; } function cachedWorkspaceId() { try { return localStorage.getItem('crank_workspace_id'); } catch (_error) { return null; } } function cachedWorkspaceSlug() { try { return localStorage.getItem('crank_workspace_slug'); } catch (_error) { return null; } } function sessionWorkspaceId() { if (!window.CrankAuth || typeof window.CrankAuth.getCachedSession !== 'function') { return null; } var session = window.CrankAuth.getCachedSession(); return session && session.current_workspace_id ? session.current_workspace_id : null; } function cacheCurrentWorkspace(workspace) { if (!workspace) return; try { localStorage.setItem('crank_workspace_id', workspace.id); localStorage.setItem('crank_workspace_slug', workspace.slug); } catch (_error) {} } function resolveCurrentWorkspace() { var workspaceId = sessionWorkspaceId() || cachedWorkspaceId(); var workspaceSlug = cachedWorkspaceSlug(); return WS_LIST.find(function(item) { return item.id === workspaceId; }) || WS_LIST.find(function(item) { return item.slug === workspaceSlug; }) || WS_LIST[0] || null; } function emitWorkspaceChange(workspace) { if (!workspace) { return; } lastWorkspaceId = workspace.id; window.dispatchEvent(new CustomEvent('crank:workspacechange', { detail: workspace })); } function getCurrentWs() { var workspace = resolveCurrentWorkspace(); if (workspace) { cacheCurrentWorkspace(workspace); } return workspace; } function updateWorkspaceHeader(workspace) { var nameEl = document.getElementById('ws-current-name'); var dotEl = document.getElementById('ws-dot'); if (nameEl) nameEl.textContent = workspace ? workspace.name : 'No workspace'; if (dotEl && workspace) { dotEl.textContent = workspace.letter; dotEl.style.background = workspace.color; } } function renderWorkspaceList() { var current = getCurrentWs(); updateWorkspaceHeader(current); var list = document.getElementById('ws-dropdown-list'); if (!list) return; window.CrankDom.clear(list); WS_LIST.forEach(function(workspace) { var active = current && workspace.id === current.id; var item = document.createElement('div'); item.className = 'ws-dropdown-item' + (active ? ' active' : ''); item.addEventListener('click', function() { switchWorkspace(workspace.id); }); var dot = document.createElement('div'); dot.className = 'ws-item-dot'; dot.style.background = workspace.color; dot.textContent = workspace.letter; item.appendChild(dot); var info = document.createElement('div'); info.className = 'ws-item-info'; var name = document.createElement('div'); name.className = 'ws-item-name'; name.textContent = workspace.name; var role = document.createElement('div'); role.className = 'ws-item-role'; role.textContent = workspace.role; info.appendChild(name); info.appendChild(role); item.appendChild(info); if (active) { var check = buildIconSvg( (window.APP_BASE || '') + 'icons/general/check.svg#icon', 12, 12 ); item.appendChild(check); } list.appendChild(item); }); var divider = document.createElement('div'); divider.className = 'ws-dropdown-divider'; list.appendChild(divider); var manageLink = document.createElement('a'); manageLink.className = 'ws-dropdown-mgmt-link'; manageLink.href = (window.CrankRoutes && window.CrankRoutes.workspaceSetup) || '/workspace-setup'; manageLink.addEventListener('click', function() { var dd = document.getElementById('ws-dropdown'); if (dd) dd.style.display = 'none'; }); manageLink.appendChild( buildIconSvg( (window.APP_BASE || '') + 'icons/general/settings.svg#icon', 14, 14 ) ); manageLink.appendChild(document.createTextNode(tKey('settings.ws.title'))); list.appendChild(manageLink); } async function loadWorkspaces() { if (workspaceLoadPromise) return workspaceLoadPromise; workspaceLoadPromise = (async function() { if (!window.CrankApi) { renderWorkspaceList(); return WS_LIST; } try { var response = await window.CrankApi.listWorkspaces(); var items = (response && response.items ? response.items : []).map(mapWorkspace); if (items.length > 0) { WS_LIST = items; } workspaceLoadFailed = false; } catch (_error) { workspaceLoadFailed = true; } renderWorkspaceList(); return WS_LIST; }()); return workspaceLoadPromise; } async function refreshWorkspaces() { workspaceLoadPromise = null; return loadWorkspaces(); } function initWorkspaceSwitcher() { renderWorkspaceList(); loadWorkspaces(); } function toggleWsSwitcher(e) { e.stopPropagation(); var dd = document.getElementById('ws-dropdown'); if (dd) dd.style.display = dd.style.display === 'none' ? '' : 'none'; } function switchWorkspace(workspaceId) { var workspace = WS_LIST.find(function(item) { return item.id === workspaceId; }); if (!workspace) return; var dd = document.getElementById('ws-dropdown'); if (dd) dd.style.display = 'none'; if (!window.CrankApi || !window.CrankAuth || typeof window.CrankAuth.replaceSession !== 'function') { cacheCurrentWorkspace(workspace); renderWorkspaceList(); emitWorkspaceChange(workspace); return; } return window.CrankApi .setCurrentWorkspace(workspace.id) .then(function(session) { window.CrankAuth.replaceSession(session); cacheCurrentWorkspace(workspace); renderWorkspaceList(); emitWorkspaceChange(workspace); return workspace; }) .catch(function(error) { if (window.CrankUi) { window.CrankUi.error(error.message || tKey('workspace.switch_error'), tKey('workspace.switch_error_title')); } throw error; }); } function setCurrentWorkspace(workspace) { if (!workspace) { return Promise.resolve(null); } return Promise.resolve(switchWorkspace(workspace.id)); } window.getCurrentWorkspace = getCurrentWs; window.whenWorkspacesReady = loadWorkspaces; window.refreshWorkspaces = refreshWorkspaces; window.setCurrentWorkspace = setCurrentWorkspace; window.hasWorkspaceApiFailure = function() { return workspaceLoadFailed; }; document.addEventListener('DOMContentLoaded', initWorkspaceSwitcher); window.addEventListener('crank:sessionchange', function() { var workspace = getCurrentWs(); renderWorkspaceList(); if (workspace && workspace.id !== lastWorkspaceId) { emitWorkspaceChange(workspace); } }); document.addEventListener('click', function(e) { if (!e.target.closest('#ws-switcher')) { var dd = document.getElementById('ws-dropdown'); if (dd) dd.style.display = 'none'; } });