feat(ui): shared header — Sign in/Sign out and New Chat on every page; hide the Sources nav link from anonymous users
This commit is contained in:
+22
-26
@@ -63,6 +63,8 @@
|
||||
* All DOM ids match frontend/index.html.
|
||||
*/
|
||||
|
||||
import { fetchIsAdmin, initSharedHeader } from "/assets/header.js";
|
||||
|
||||
const messagesEl = document.querySelector("#messages");
|
||||
const emptyState = document.querySelector("#empty-state");
|
||||
const suggestionsEl = document.querySelector("#suggestions");
|
||||
@@ -756,9 +758,19 @@ function rememberBrainTurn(rawText, meta) {
|
||||
* tuning surface at all — the Tuning toggle + panel are removed from the
|
||||
* DOM (the story says "absent", not just hidden), /api/steering is never
|
||||
* fetched, and appendTuneButton injects nothing (new or restored
|
||||
* messages). Admin → Sign out (POST /api/logout + reload) + the full
|
||||
* phase-15 UI. Whoami is awaited BEFORE the phase-14 restore, so restored
|
||||
* brain bubbles never flash a Tune button that should not be there.
|
||||
* messages). Admin → Sign out + the full phase-15 UI. Whoami is awaited
|
||||
* BEFORE the phase-14 restore, so restored brain bubbles never flash a
|
||||
* Tune button that should not be there.
|
||||
*
|
||||
* Phase 19: the whoami fetch, the Sign in / Sign out / Sources-nav
|
||||
* toggling, and the #sign-out-btn click binding (POST /api/logout +
|
||||
* reload) all moved to the shared header module (assets/header.js) —
|
||||
* initSharedHeader() does the header toggling on every page, and
|
||||
* fetchIsAdmin() is the single cached whoami, so this page still makes
|
||||
* exactly one request per load. applyAuthState keeps only the
|
||||
* chat-page-specific work (removing the tuning surface for anonymous
|
||||
* visitors) — idempotent alongside the header module's own link/button
|
||||
* toggling.
|
||||
*/
|
||||
const signInLink = document.querySelector("#sign-in-link");
|
||||
const signOutBtn = document.querySelector("#sign-out-btn");
|
||||
@@ -773,27 +785,6 @@ function applyAuthState() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAuthState() {
|
||||
try {
|
||||
const r = await fetch("/api/whoami");
|
||||
if (r.ok) isAdmin = (await r.json()).authenticated === true;
|
||||
} catch {
|
||||
isAdmin = false; // API unreachable: anonymous-safe defaults
|
||||
}
|
||||
applyAuthState();
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
if (signOutBtn) {
|
||||
signOutBtn.addEventListener("click", async () => {
|
||||
signOutBtn.disabled = true;
|
||||
try {
|
||||
await fetch("/api/logout", { method: "POST" });
|
||||
} catch { /* the reload resets the UI either way */ }
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const newChatBtn = document.querySelector("#new-chat-btn");
|
||||
function startNewChat() {
|
||||
if (uiState === UI_STATE.thinking || uiState === UI_STATE.streaming) return;
|
||||
@@ -983,9 +974,14 @@ composer.addEventListener("submit", handleSend);
|
||||
|
||||
/* Boot: auth state FIRST — it decides whether the restored conversation
|
||||
gets Tune buttons and whether the steering UI exists at all (phase 16).
|
||||
Phase 14: the conversation then comes back exactly as left. */
|
||||
Phase 14: the conversation then comes back exactly as left. Phase 19:
|
||||
the shared header module runs the whoami (cached — exactly one
|
||||
request per page load) and toggles the Sign in/out pair + the Sources
|
||||
nav link; applyAuthState() then applies the chat-page-only gating. */
|
||||
(async () => {
|
||||
await loadAuthState();
|
||||
await initSharedHeader(); // header.js: whoami + Sign in/out + #nav-sources
|
||||
isAdmin = await fetchIsAdmin(); // the same cached promise — one whoami
|
||||
applyAuthState(); // chat page: the admin-only tuning surface
|
||||
restoreConversation();
|
||||
loadSuggestions();
|
||||
loadHealth();
|
||||
|
||||
Reference in New Issue
Block a user