From b33ccb16c53b34e92312c8ace8ad5143dfef51bd Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Sun, 7 Jun 2026 18:03:12 -0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20rail/footer=20cleanup=20=E2=80=94=20?= =?UTF-8?q?drop=20admin=20btn,=20real=20username,=20logout=20menu,=20colla?= =?UTF-8?q?pse=20Manage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mock-review batch (4 items): - Footer: drop the redundant Admin button — Manage already surfaces every admin tab, so only the theme toggle relocates from the retired header. - Footer: the user chip now shows the real logged-in user. whoami returns user_id but _storePermissions only persisted permissions, so the chip was stuck on the "account" placeholder; it is now stored as ts.username and the chip repaints once whoami lands (Tier-1 render hook). - Footer: Log out moves into a click-menu on the user chip (reuses the .tab-menu popup chrome; the item clicks the hidden #logout-btn so auth.js stays the single owner of logout and its in-flight-refresh race guards). - Manage: groups start collapsed instead of auto-expanding the first one — the rail is a discovery map, not a wall of open links. Verified end-to-end in the real console shell (headless): chip is a button showing the user, no admin button in the footer, the menu opens with Log out which invokes logout, outside-click/Escape close it, no JS errors. --- turnstone/shared_static/auth.js | 9 +++ turnstone/shared_static/rail.js | 8 +- turnstone/shared_static/shell.css | 14 +++- turnstone/shared_static/shell.js | 118 +++++++++++++++++++++++++++--- 4 files changed, 133 insertions(+), 16 deletions(-) diff --git a/turnstone/shared_static/auth.js b/turnstone/shared_static/auth.js index 4657e31a..a10afcac 100644 --- a/turnstone/shared_static/auth.js +++ b/turnstone/shared_static/auth.js @@ -713,6 +713,15 @@ function _storePermissions(data) { } else { sessionStorage.removeItem("turnstone_permissions"); } + // Surface the authenticated identity for the rail footer's user chip. + // whoami returns user_id (the username); the shell reads it via ts.username + // and repaints once it lands. Cleared in lockstep with permissions so the + // chip never shows a stale user after logout / revocation. + if (data && data.user_id) { + sessionStorage.setItem("ts.username", data.user_id); + } else { + sessionStorage.removeItem("ts.username"); + } } function _setBusy(busy, label) { diff --git a/turnstone/shared_static/rail.js b/turnstone/shared_static/rail.js index 9b72d153..da0bcdd6 100644 --- a/turnstone/shared_static/rail.js +++ b/turnstone/shared_static/rail.js @@ -331,21 +331,21 @@ export function mountManage(root, paneManager) { root.replaceChildren(); // If the Admin pane is already open (e.g. restored by PaneManager.rehydrate), - // seed the rail to its current tab + expand the owning group; otherwise the - // first group expands (mock) and nothing is marked until the user clicks. + // seed the rail to its current tab + expand the owning group; otherwise every + // group starts collapsed and nothing is marked until the user clicks. const adminOpen = paneManager && paneManager.hasPane && paneManager.hasPane("admin"); const activeTab = adminOpen && TS.getActiveTab ? TS.getActiveTab() : null; const rowByTab = new Map(); // tab -> its row