Add composable HTTP access roles #62
@@ -6051,9 +6051,18 @@ function initSettingsUI() {
|
||||
}
|
||||
async function refreshUserManagement() {
|
||||
const section = document.getElementById("user-management");
|
||||
if (!section) return;
|
||||
section.style.display = authEnabled && authRole === "admin" ? "block" : "none";
|
||||
if (section.style.display === "none") return;
|
||||
const tab = document.getElementById("settings-users-tab");
|
||||
if (!section || !tab) return;
|
||||
const canManageUsers = authEnabled && authRole === "admin";
|
||||
tab.style.display = canManageUsers ? "" : "none";
|
||||
if (!canManageUsers) {
|
||||
const panel = document.getElementById("subtab-settings-users");
|
||||
if (panel) panel.style.display = "none";
|
||||
if (tab.classList.contains("active")) {
|
||||
document.querySelector('[data-subtab="settings-scheduler"]')?.click();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const list = requiredElement("user-list");
|
||||
try {
|
||||
const users = await listUsers();
|
||||
|
||||
@@ -1461,6 +1461,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
<button class="sub-tab" data-subtab="settings-background-decode">Background Decode</button>
|
||||
<button class="sub-tab" data-subtab="settings-bandplan">Bandplan</button>
|
||||
<button class="sub-tab" data-subtab="settings-history">History</button>
|
||||
<button id="settings-users-tab" class="sub-tab" data-subtab="settings-users" style="display:none;">Users</button>
|
||||
</div>
|
||||
<div id="subtab-settings-scheduler" class="sub-tab-panel">
|
||||
<div id="scheduler-panel" class="sch-panel">
|
||||
@@ -1750,8 +1751,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section id="user-management" style="display:none; margin-top:1rem;">
|
||||
<h2 class="section-heading">User management</h2>
|
||||
<div id="subtab-settings-users" class="sub-tab-panel" style="display:none;">
|
||||
<div id="user-management">
|
||||
<div class="settings-card">
|
||||
<form id="user-create-form" class="sch-row" style="flex-wrap:wrap; gap:.5rem;">
|
||||
<input id="user-create-username" class="auth-input" placeholder="Username" autocomplete="off" required />
|
||||
@@ -1762,7 +1763,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
<div id="user-management-error" class="auth-error" style="display:none;"></div>
|
||||
<div id="user-list" style="margin-top:.75rem;"></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-about" class="tab-panel" style="display:none;">
|
||||
<h2 class="section-heading">About</h2>
|
||||
|
||||
@@ -5055,9 +5055,18 @@ function initSettingsUI() {
|
||||
|
||||
async function refreshUserManagement() {
|
||||
const section = document.getElementById("user-management");
|
||||
if (!section) return;
|
||||
section.style.display = authEnabled && authRole === "admin" ? "block" : "none";
|
||||
if (section.style.display === "none") return;
|
||||
const tab = document.getElementById("settings-users-tab");
|
||||
if (!section || !tab) return;
|
||||
const canManageUsers = authEnabled && authRole === "admin";
|
||||
tab.style.display = canManageUsers ? "" : "none";
|
||||
if (!canManageUsers) {
|
||||
const panel = document.getElementById("subtab-settings-users");
|
||||
if (panel) panel.style.display = "none";
|
||||
if (tab.classList.contains("active")) {
|
||||
document.querySelector<HTMLButtonElement>('[data-subtab="settings-scheduler"]')?.click();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const list = requiredElement("user-list");
|
||||
try {
|
||||
const users = await listUsers();
|
||||
|
||||
@@ -9,6 +9,7 @@ import { readFile } from "node:fs/promises";
|
||||
const indexPath = new URL("../../assets/web/index.html", import.meta.url);
|
||||
const pluginLoaderPath = new URL("../src/plugin-loader.ts", import.meta.url);
|
||||
const mapCorePath = new URL("../src/map-core.ts", import.meta.url);
|
||||
const appPath = new URL("../src/app.ts", import.meta.url);
|
||||
|
||||
test("index loads one first-party application bootstrap", async () => {
|
||||
const html = await readFile(indexPath, "utf8");
|
||||
@@ -30,6 +31,17 @@ test("startup has no remote script or stylesheet dependencies", async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("administrator user management is a dedicated Settings sub-tab", async () => {
|
||||
const [html, app] = await Promise.all([
|
||||
readFile(indexPath, "utf8"),
|
||||
readFile(appPath, "utf8"),
|
||||
]);
|
||||
assert.match(html, /data-subtab="settings-users"/);
|
||||
assert.match(html, /id="subtab-settings-users" class="sub-tab-panel"/);
|
||||
assert.match(app, /authEnabled && authRole === "admin"/);
|
||||
assert.match(app, /settings-users-tab/);
|
||||
});
|
||||
|
||||
test("lazy frontend features use modules and local map symbols", async () => {
|
||||
const [loader, map] = await Promise.all([
|
||||
readFile(pluginLoaderPath, "utf8"),
|
||||
|
||||
Reference in New Issue
Block a user