- FastAPI app at panel/ proxying receiver API server-side (admin creds stay server-side) - Login-protected dashboard: SLA status, rotate flag, restart/rollback/activate/deactivate, SSH creds, command history - Runs as systemd service gemastik-panel.service on :18081 - Published at https://panel.gemastik.imrnes.team via Traefik
64 lines
2.4 KiB
HTML
64 lines
2.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Gemastik A/D Panel — Login</title>
|
|
<style>
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|
body {
|
|
font-family: 'JetBrains Mono','Fira Code',monospace;
|
|
background: radial-gradient(ellipse at top, #0d1b2a 0%, #0a0f1c 60%, #05070d 100%);
|
|
color: #c9d4e3; height:100vh; display:flex; align-items:center; justify-content:center;
|
|
}
|
|
.card {
|
|
background:#0e1526cc; border:1px solid #1e3a5f; border-radius:14px;
|
|
padding:42px 46px; width:360px; box-shadow:0 0 60px #0a3d6b55;
|
|
}
|
|
h1 { font-size:20px; color:#5ad1ff; letter-spacing:1px; margin-bottom:6px; }
|
|
.sub { color:#718096; font-size:12px; margin-bottom:28px; }
|
|
label { display:block; font-size:11px; color:#7d8ba1; margin:14px 0 6px; text-transform:uppercase; letter-spacing:1px; }
|
|
input {
|
|
width:100%; background:#0a101f; border:1px solid #1e3a5f; color:#dbe6f4;
|
|
border-radius:8px; padding:11px 13px; font-size:14px; font-family:inherit; outline:none;
|
|
}
|
|
input:focus { border-color:#3b82f6; box-shadow:0 0 0 3px #3b82f633; }
|
|
button {
|
|
width:100%; margin-top:24px; background:linear-gradient(135deg,#0ea5e9,#2563eb);
|
|
border:none; color:#fff; font-family:inherit; font-weight:700; font-size:14px;
|
|
padding:12px; border-radius:8px; cursor:pointer; letter-spacing:.5px; transition:filter .2s;
|
|
}
|
|
button:hover { filter:brightness(1.15); }
|
|
.err { color:#f87171; font-size:12px; margin-top:14px; min-height:16px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<h1>⚔️ GEMASTIK A/D</h1>
|
|
<div class="sub">Node Control Panel — imrnes</div>
|
|
<form id="f">
|
|
<label>Username</label>
|
|
<input id="u" autocomplete="username" required>
|
|
<label>Password</label>
|
|
<input id="p" type="password" autocomplete="current-password" required>
|
|
<button type="submit">MASUK</button>
|
|
<div class="err" id="err"></div>
|
|
</form>
|
|
</div>
|
|
<script>
|
|
const f = document.getElementById('f');
|
|
f.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const err = document.getElementById('err');
|
|
err.textContent = '';
|
|
const r = await fetch('/api/login', {
|
|
method: 'POST',
|
|
headers: {'Content-Type':'application/json'},
|
|
body: JSON.stringify({user: u.value, pass: p.value})
|
|
});
|
|
if (r.ok) location.href = '/';
|
|
else err.textContent = 'Kredensial salah!';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |