diff --git a/frontend/css/main.css b/frontend/css/main.css index 6247f1b..3141345 100644 --- a/frontend/css/main.css +++ b/frontend/css/main.css @@ -58,6 +58,11 @@ body { display: block; padding: 8px 10px; color: var(--text-muted); font-size: 12px; font-style: italic; } +/* #19: single-workspace view - name + always-visible manage icons (no dropdown). */ +.workspace-switcher-single { display: flex; align-items: center; gap: 4px; } +.workspace-switcher-single .workspace-switcher-static { flex: 1; min-width: 0; } +.workspace-switcher-single .workspace-switcher-members, +.workspace-switcher-single .workspace-switcher-pencil { visibility: visible; align-self: end; } .workspace-switcher-button .chev { flex-shrink: 0; margin-left: 8px; color: var(--text-muted); transition: transform var(--transition); diff --git a/frontend/js/components/workspace-switcher.js b/frontend/js/components/workspace-switcher.js index 69dd68a..fda759a 100644 --- a/frontend/js/components/workspace-switcher.js +++ b/frontend/js/components/workspace-switcher.js @@ -14,6 +14,51 @@ function formatResourceCount(n, keyBase, zeroKey) { return tn(keyBase, n); } +// Admin affordances shown beside a workspace: manage members + rename. Returns +// '' for non-admins. Shared by the single-workspace view and the multi-workspace +// dropdown items so the two never drift - #19: the single view was missing these, +// locking single-workspace users out of org settings (invite users, perms, slug). +function adminIconsHtml(w) { + if (!w.can_admin) return ''; + return ` + + `; +} + +// Wire the manage-members + rename buttons within `scope`. `list` resolves a +// workspace id to its object (for the rename modal). stopPropagation so a click +// on an icon never triggers the row's switch handler. +function wireAdminIcons(scope, list) { + scope.querySelectorAll('.workspace-switcher-pencil').forEach(btn => { + btn.addEventListener('click', async (e) => { + e.stopPropagation(); + const ws = list.find(w => w.id === btn.dataset.renameId); + if (!ws) return; + scope.classList.remove('open'); + const { openWorkspaceRenameModal } = await import('./workspace-rename-modal.js'); + openWorkspaceRenameModal(ws); + }); + }); + scope.querySelectorAll('.workspace-switcher-members').forEach(btn => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + scope.classList.remove('open'); + window.location.hash = `#/workspace/${btn.dataset.membersId}/members`; + }); + }); +} + // Render the workspace switcher inside #workspaceSwitcher based on the // /api/auth/me response. Three modes: // - 0 accessible workspaces: muted "No workspace" placeholder @@ -33,8 +78,17 @@ export function renderWorkspaceSwitcher(me) { } if (list.length === 1) { + // #19: a single workspace still needs its admin affordances (manage members / + // rename + slug). Render the name as before, plus the inline manage icons + // when the user can administer it - no dropdown for one item. container.classList.remove('open'); - container.innerHTML = `${esc(list[0].name)}`; + const only = list[0]; + container.innerHTML = ` +