Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions internal/api/web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ function showSignedOut(message) {
document.getElementById("console").classList.add("hidden");
document.getElementById("stats").classList.add("hidden");
document.getElementById("account").classList.add("hidden");
setSettingsOpen(false);
document.getElementById("admins-panel").classList.add("hidden");
document.getElementById("security-panel").classList.add("hidden");
document.getElementById("token-banner").classList.add("hidden");
Expand Down Expand Up @@ -813,12 +814,42 @@ document.getElementById("query-select").addEventListener("change", () => {
refresh().catch(showConsoleError);
});
document.getElementById("rules-btn").addEventListener("click", runRules);

function setSettingsOpen(open) {
const menu = document.getElementById("settings-menu");
const button = document.getElementById("settings-btn");
menu.classList.toggle("hidden", !open);
button.setAttribute("aria-expanded", open ? "true" : "false");
}

function closeSettingsMenu() {
const button = document.getElementById("settings-btn");
if (button.getAttribute("aria-expanded") !== "true") return;
setSettingsOpen(false);
button.focus();
}

document.getElementById("settings-btn").addEventListener("click", () => {
const open = document.getElementById("settings-btn").getAttribute("aria-expanded") === "true";
setSettingsOpen(!open);
});
document.addEventListener("click", (event) => {
if (event.target.closest(".settings")) return;
if (document.getElementById("settings-btn").getAttribute("aria-expanded") !== "true") return;
setSettingsOpen(false);
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape") return;
closeSettingsMenu();
});

document.getElementById("token-btn").addEventListener("click", async () => {
const button = document.getElementById("token-btn");
const has = Boolean(currentAdmin && currentAdmin.has_api_token);
if (has && !window.confirm("Replace the current API token? Scripts using it will stop working.")) {
return;
}
closeSettingsMenu();
button.disabled = true;
try {
const created = await fetchJSON(has ? "/v1/admins/token/rotate" : "/v1/admins/token", { method: "POST" });
Expand All @@ -838,6 +869,7 @@ document.getElementById("token-dismiss").addEventListener("click", () => {
document.getElementById("token-banner").classList.add("hidden");
});
document.getElementById("logout-btn").addEventListener("click", async () => {
closeSettingsMenu();
await fetch("/v1/auth/logout", { method: "POST" });
window.location.href = "/login";
});
Expand Down Expand Up @@ -920,6 +952,7 @@ async function renderSecurity() {
}

document.getElementById("security-btn").addEventListener("click", () => {
closeSettingsMenu();
const panel = document.getElementById("security-panel");
if (!panel.classList.contains("hidden")) {
panel.classList.add("hidden");
Expand All @@ -928,6 +961,7 @@ document.getElementById("security-btn").addEventListener("click", () => {
renderSecurity().catch(showConsoleError);
});
document.getElementById("admins-btn").addEventListener("click", () => {
closeSettingsMenu();
const panel = document.getElementById("admins-panel");
if (!panel.classList.contains("hidden")) {
panel.classList.add("hidden");
Expand Down
17 changes: 13 additions & 4 deletions internal/api/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ <h1>OpenSourceOM</h1>
</div>
<div id="account" class="account hidden">
<span id="account-label"></span>
<button id="token-btn" type="button">Create API token</button>
<button id="security-btn" type="button">Security</button>
<button id="admins-btn" type="button">Admins</button>
<button id="logout-btn" type="button">Log out</button>
<div class="settings">
<button id="settings-btn" type="button" aria-expanded="false" aria-controls="settings-menu" aria-haspopup="true">
Settings
<span class="chevron" aria-hidden="true"></span>
</button>
<div id="settings-menu" class="settings-menu hidden">
<button id="token-btn" type="button">Create API token</button>
<button id="security-btn" type="button">Security</button>
<button id="admins-btn" type="button">Admins</button>
<div class="settings-sep" role="separator"></div>
<button id="logout-btn" type="button">Log out</button>
</div>
</div>
</div>
</header>

Expand Down
72 changes: 69 additions & 3 deletions internal/api/web/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,78 @@ header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
gap: 0.75rem 1.5rem;
padding: 1.25rem 1.5rem;
border-bottom: 1px solid var(--border);
position: relative;
z-index: 2;
}
header h1 { margin: 0; font-size: 1.4rem; }
.tagline { margin: 0.25rem 0 0; color: var(--muted); }
.account { display: flex; align-items: center; gap: 0.6rem; color: var(--muted); }
.account {
display: flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 0.5rem 0.75rem;
margin-left: auto;
max-width: 100%;
color: var(--muted);
}
#account-label {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.settings { position: relative; }
#settings-btn {
display: inline-flex;
align-items: center;
gap: 0.45rem;
}
#settings-btn .chevron {
width: 0.4rem;
height: 0.4rem;
border-right: 1.5px solid currentColor;
border-bottom: 1.5px solid currentColor;
transform: translateY(-1px) rotate(45deg);
}
#settings-btn[aria-expanded="true"] { border-color: var(--accent); }
#settings-btn[aria-expanded="true"] .chevron { transform: translateY(2px) rotate(225deg); }
.settings-menu {
position: absolute;
top: calc(100% + 0.45rem);
right: 0;
z-index: 3;
min-width: 13rem;
display: flex;
flex-direction: column;
gap: 0.1rem;
padding: 0.35rem;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 10px;
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
}
.account .settings-menu button {
display: block;
width: 100%;
text-align: left;
background: transparent;
border: 0;
border-radius: 6px;
padding: 0.5rem 0.7rem;
white-space: nowrap;
}
.account .settings-menu button:hover,
.account .settings-menu button:focus-visible { background: #1a2440; }
.settings-sep {
height: 1px;
margin: 0.25rem 0.45rem;
background: var(--border);
}
.hidden { display: none; }

.gate {
Expand Down Expand Up @@ -232,6 +297,7 @@ h2 { margin: 0 0 0.75rem; font-size: 1rem; }
#account.hidden,
#admins-panel.hidden,
#security-panel.hidden,
#token-banner.hidden {
#token-banner.hidden,
#settings-menu.hidden {
display: none;
}
Loading