feat(admin): complete Slice 2 admin client handlers (#79)

- Added missing role and invite UI client handlers to `public/admin-scripts.js` mapped to `globalThis`.
- Enforced strict backend contract adherence by changing `spiffe_id` to `spiffeId` in `handleSaveApp`.
- Updated unused catch error parameter blocks to adhere to Deno conventions (`_e` or `_err`).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
This commit is contained in:
Tyler Gillispie 2026-09-25 19:08:57 -07:00 committed by GitHub
parent 7b115f4ef1
commit c93be6a27f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -321,7 +321,7 @@ function openEditAppDrawer(appJson) {
let app; let app;
try { try {
app = typeof appJson === "string" ? JSON.parse(appJson) : appJson; app = typeof appJson === "string" ? JSON.parse(appJson) : appJson;
} catch (e) { } catch (_e) {
showNotice("Failed to parse application data.", true); showNotice("Failed to parse application data.", true);
return; return;
} }
@ -379,7 +379,7 @@ async function handleSaveApp(e) {
const payload = { const payload = {
name, name,
spiffe_id: spiffeId, spiffeId,
description, description,
domain, domain,
is_public: isPublic, is_public: isPublic,
@ -413,7 +413,7 @@ async function handleSaveApp(e) {
const data = await res.json(); const data = await res.json();
showNotice(data.error || "Failed to save application", true); showNotice(data.error || "Failed to save application", true);
} }
} catch (err) { } catch (_err) {
showNotice("Network error saving application", true); showNotice("Network error saving application", true);
} }
} }
@ -435,8 +435,146 @@ async function deleteApp(appId, appName) {
const data = await res.json(); const data = await res.json();
showNotice(data.error || "Failed to delete application", true); showNotice(data.error || "Failed to delete application", true);
} }
} catch (err) { } catch (_err) {
showNotice("Network error deleting application", true); showNotice("Network error deleting application", true);
} }
} }
globalThis.deleteApp = deleteApp; globalThis.deleteApp = deleteApp;
// Slice 2: Roles Handlers
function openCreateRoleDrawer() {
const drawer = document.getElementById("roleDrawer");
if (!drawer) return;
const title = document.getElementById("roleDrawerTitle");
if (title) title.textContent = "Create Custom Role";
const editId = document.getElementById("roleEditId");
if (editId) editId.value = "";
const nameInput = document.getElementById("roleNameInput");
if (nameInput) nameInput.value = "";
const appSelect = document.getElementById("roleAppSelect");
if (appSelect) appSelect.value = "";
const descInput = document.getElementById("roleDescInput");
if (descInput) descInput.value = "";
drawer.style.display = "block";
}
globalThis.openCreateRoleDrawer = openCreateRoleDrawer;
function closeRoleDrawer() {
const drawer = document.getElementById("roleDrawer");
if (drawer) drawer.style.display = "none";
}
globalThis.closeRoleDrawer = closeRoleDrawer;
async function handleSaveRole(e) {
e.preventDefault();
const id = document.getElementById("roleEditId")?.value;
const name = document.getElementById("roleNameInput")?.value?.trim();
const app_id = document.getElementById("roleAppSelect")?.value;
const description = document.getElementById("roleDescInput")?.value?.trim();
if (!name) {
showNotice("Role name is required", true);
return;
}
const payload = { id, name, description, app_id: app_id || null };
try {
const res = await fetch("/api/admin/roles", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
if (res.ok) {
showNotice("Role saved successfully!", false);
setTimeout(() => globalThis.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || "Failed to save role", true);
}
} catch (_err) {
showNotice("Network error saving role", true);
}
}
globalThis.handleSaveRole = handleSaveRole;
async function deleteRole(roleId, roleName) {
if (!confirm("Permanently delete role '" + roleName + "'?")) return;
try {
const res = await fetch("/api/admin/roles/" + roleId, { method: "DELETE" });
if (res.ok) {
showNotice("Role deleted successfully", false);
setTimeout(() => globalThis.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || "Failed to delete role", true);
}
} catch (_err) {
showNotice("Network error deleting role", true);
}
}
globalThis.deleteRole = deleteRole;
// Slice 2: Invites Handlers
function toggleCreateInviteForm() {
const drawer = document.getElementById("inviteDrawer");
if (!drawer) return;
drawer.style.display = drawer.style.display === "none" ? "block" : "none";
}
globalThis.toggleCreateInviteForm = toggleCreateInviteForm;
async function handleCreateInvite(e) {
e.preventDefault();
const app_id = document.getElementById("inviteAppSelect")?.value;
const role = document.getElementById("inviteRoleSelect")?.value || "user";
const max_uses = document.getElementById("inviteMaxUsesInput")?.value;
const payload = {
app_id: app_id || null,
role,
max_uses: Number(max_uses) || 1,
expires_in_days: 7,
};
try {
const res = await fetch("/api/admin/invites", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
if (res.ok) {
const data = await res.json();
showNotice("Invite created: " + (data.invite?.code || "Success"), false);
setTimeout(() => globalThis.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || "Failed to create invite", true);
}
} catch (_err) {
showNotice("Network error creating invite", true);
}
}
globalThis.handleCreateInvite = handleCreateInvite;
async function revokeInvite(inviteId) {
if (!confirm("Revoke this invite token?")) return;
try {
const res = await fetch("/api/admin/invites/" + inviteId, {
method: "DELETE",
});
if (res.ok) {
showNotice("Invite revoked successfully", false);
setTimeout(() => globalThis.location.reload(), 600);
} else {
const data = await res.json();
showNotice(data.error || "Failed to revoke invite", true);
}
} catch (_err) {
showNotice("Network error revoking invite", true);
}
}
globalThis.revokeInvite = revokeInvite;