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:
parent
7b115f4ef1
commit
c93be6a27f
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user