async function api(path, body) { const res = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const json = await res.json().catch(() => ({})); if (!res.ok) { throw new Error(json.detail || res.statusText); } return json; } async function gql(query, variables) { const headers = { "Content-Type": "application/json" }; const token = localStorage.getItem("access_token"); if (token) { headers.Authorization = `Bearer ${token}`; } const res = await fetch("/graphql", { method: "POST", headers, body: JSON.stringify({ query, variables }), }); const json = await res.json(); if (json.errors && json.errors.length) { throw new Error(json.errors[0].message); } return json.data; } const CLIENTS_QUERY = ` query { clients { id clientId name isConfidential redirectUris createdAt } } `; document.addEventListener("DOMContentLoaded", () => { const loginForm = document.getElementById("login-form"); const panel = document.getElementById("panel"); const statusEl = document.getElementById("status"); const clientsBody = document.getElementById("clients-body"); const createBtn = document.getElementById("create-client"); const logoutBtn = document.getElementById("logout"); function setStatus(message, ok = false) { statusEl.textContent = message || ""; statusEl.classList.toggle("ok", ok); } function setLoggedIn(isLoggedIn) { loginForm.classList.toggle("hidden", isLoggedIn); panel.classList.toggle("hidden", !isLoggedIn); } function renderClients(clients) { clientsBody.textContent = ""; for (const client of clients) { const row = document.createElement("tr"); const cells = [ client.id, client.clientId, client.name, client.isConfidential ? "yes" : "no", (client.redirectUris || []).join(", "), client.createdAt, ]; for (const value of cells) { const td = document.createElement("td"); td.textContent = value; row.appendChild(td); } clientsBody.appendChild(row); } } async function loadClients() { try { const data = await gql(CLIENTS_QUERY); renderClients(data.clients); setStatus(""); } catch (err) { renderClients([]); setStatus(err.message); } } async function handleLogin(event) { event.preventDefault(); setStatus(""); const email = document.getElementById("email").value; const password = document.getElementById("password").value; try { const { access_token } = await api("/auth/login", { email, password }); localStorage.setItem("access_token", access_token); setLoggedIn(true); await loadClients(); } catch (err) { setStatus(err.message); } } async function handleCreateClient() { const name = prompt("Название клиента"); if (!name) { return; } try { await gql( "mutation ($name: String!) { createClient(name: $name) { id clientId name } }", { name } ); setStatus(""); await loadClients(); } catch (err) { setStatus(err.message); } } function handleLogout() { localStorage.removeItem("access_token"); setLoggedIn(false); setStatus(""); loginForm.reset(); } loginForm.addEventListener("submit", handleLogin); createBtn.addEventListener("click", handleCreateClient); logoutBtn.addEventListener("click", handleLogout); if (localStorage.getItem("access_token")) { setLoggedIn(true); loadClients(); } });