diff --git a/README.md b/README.md
index 984f004..584d794 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
-
+
Why Site Gateway · diff --git a/ROADMAP.md b/ROADMAP.md index bd9498b..2a52b64 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -152,3 +152,5 @@ Roughly in priority order: `v0.16.12` fixes the Backup & Restore tab's "Backup history" section getting stuck on "Loading backup history…" indefinitely. Root cause: `renderBackupHistory()` is only invoked from the periodic `refresh()` cycle, and it bailed out before fetching whenever the Backups tab wasn't the currently active admin tab at that moment — but switching admin tabs only toggles CSS visibility, it never re-triggers a fetch. So if a refresh cycle landed while you were on a different tab, the placeholder text was left in place with no later refresh ever replacing it. Same bug class as v0.16.3's System-tab fix; resolved the same way, by always populating the section's content regardless of the panel's current visibility. `v0.16.13` fixes three Administration/Logs layout inconsistencies found in live use. First, the Groups tab was missing the stat-count bar ("N Administrators · N Standard Users · ...") that every other listing tab (Users) shows, making it look unfinished by comparison — added a matching Enabled/Disabled group count bar. Second, "Create group" lived in its own row inside the Groups panel instead of the shared top-right header button used by "Create user," "New hosted site," and every other creation action — moved it into that same header slot so it behaves and aligns like all the others. Third, the Logs page's "Refresh logs" button (and Performance's and Certificates') sat directly against the first box below it with no gap, because those three pages are the only ones with no status-summary bar to provide the usual spacing under the page header — added a matching top margin so they're consistent with every other page. + +`v0.16.14` fixes the Create button (Create user / Create group) disappearing or showing the wrong label after switching Administration tabs. Root cause: a leftover click handler on the admin tabs bar, written before Groups had a Create button at all, still hard-coded "hide the shared Create button unless the tab is Users" and manually poked tab-active/panel-visibility classes directly -- completely independent of and out of sync with the real logic added in v0.16.13's `render()`. Since that same handler also fires when the app restores your last-viewed tab on page load/refresh, it would immediately stomp the button back to the wrong state. Replaced both old handlers with one that simply updates state and calls the real `render()`, so there's a single source of truth for tab switching instead of two handlers disagreeing with each other. diff --git a/package.json b/package.json index cecb431..19f3c14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "site-gateway", - "version": "0.16.13", + "version": "0.16.14", "private": true, "description": "Site Gateway: simple self-hosted website publishing, reverse proxying, and automatic HTTPS.", "type": "module", diff --git a/src/public/features.js b/src/public/features.js index 864ca9d..32a21eb 100644 --- a/src/public/features.js +++ b/src/public/features.js @@ -211,8 +211,10 @@ document.querySelector("#access-list").addEventListener("click", event => { if ( // --- Administration: tab switching between admin panel sections ---------------- -document.querySelector(".admin-tabs").addEventListener("click", event => { const button = event.target.closest("[data-admin-tab]"); if (!button) return; document.querySelectorAll("[data-admin-tab]").forEach(item => item.classList.toggle("tab-active", item === button)); document.querySelectorAll("[data-admin-panel]").forEach(panel => panel.classList.toggle("hidden", panel.dataset.adminPanel !== button.dataset.adminTab)); document.querySelector("#open-create").classList.toggle("hidden", button.dataset.adminTab !== "users"); }); -document.querySelector(".admin-tabs").addEventListener("click", event => { const button = event.target.closest("[data-admin-tab]"); if (!button) return; state.adminTab = button.dataset.adminTab; history.replaceState(null, "", `${location.pathname}${location.search}#administration/${state.adminTab}`); }); +// A single handler updates state and defers to the real render() for tab-active classes, panel +// visibility, and the shared Create button's visibility/text -- render() is the one place that +// logic lives, so this never drifts out of sync with it the way two separate DOM-poking handlers did. +document.querySelector(".admin-tabs").addEventListener("click", event => { const button = event.target.closest("[data-admin-tab]"); if (!button) return; state.adminTab = button.dataset.adminTab; render(); }); if (state.adminTab && state.view === "administration") document.querySelector(`[data-admin-tab="${state.adminTab}"]`)?.click(); diff --git a/src/public/index.html b/src/public/index.html index 623cae1..b8f09cc 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -8,7 +8,7 @@