111 lines
4.2 KiB
HTML
111 lines
4.2 KiB
HTML
{{define "base"}}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{.Title}} — CrowdSec Dashy</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;600&display=swap">
|
|
<link rel="stylesheet" href="/static/css/app.css">
|
|
</head>
|
|
<body>
|
|
<div style="display:flex;height:100vh;overflow:hidden">
|
|
|
|
<aside class="sidebar" id="sidebar">
|
|
<div class="sidebar-logo">
|
|
<div class="logo-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#00d4ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
|
</div>
|
|
<div>
|
|
<span class="logo-name">CrowdSec</span>
|
|
<span class="logo-sub">Dashy</span>
|
|
</div>
|
|
</div>
|
|
<nav class="sidebar-nav">
|
|
{{range .Nav}}
|
|
{{if .Divider}}<div class="nav-divider"></div>{{end}}
|
|
<a href="{{.Path}}" class="nav-item{{if eq $.CurrentPath .Path}} nav-item--active{{end}}">
|
|
<span class="nav-icon">{{safeHTML .Icon}}</span>
|
|
{{.Label}}
|
|
</a>
|
|
{{end}}
|
|
</nav>
|
|
<div class="sidebar-footer">
|
|
{{if .CLIAvailable}}
|
|
<div class="cli-badge cli-badge--ok">cscli: available</div>
|
|
{{else}}
|
|
<div class="cli-badge cli-badge--warn">cscli: unavailable</div>
|
|
{{end}}
|
|
<form method="POST" action="/logout" style="margin-top:10px">
|
|
<input type="hidden" name="_csrf" value="{{.CSRFToken}}">
|
|
<button type="submit" class="btn-ghost-sm" style="width:100%;text-align:center;padding:6px 0">Sign out</button>
|
|
</form>
|
|
</div>
|
|
</aside>
|
|
|
|
<div class="sidebar-overlay" id="sidebar-overlay"></div>
|
|
|
|
<div style="display:flex;flex-direction:column;flex:1;overflow:hidden">
|
|
<header class="topbar">
|
|
<button class="topbar-menu-btn" id="menu-btn" aria-label="Toggle sidebar">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
|
</button>
|
|
<div class="topbar-breadcrumb">
|
|
<span class="topbar-page">{{.Title}}</span>
|
|
</div>
|
|
<div id="health-badge" class="status-pill status-pill--loading">
|
|
<span class="status-dot"></span>checking
|
|
</div>
|
|
</header>
|
|
|
|
{{if .Flash.Message}}
|
|
<div class="flash flash--{{.Flash.Type}}" id="flash-msg">
|
|
<span class="flash-text">{{.Flash.Message}}</span>
|
|
<button class="flash-close" onclick="document.getElementById('flash-msg').remove()">dismiss</button>
|
|
</div>
|
|
{{end}}
|
|
|
|
<main style="flex:1;overflow-y:auto;padding:20px">
|
|
{{template "content" .}}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/static/js/modal.js"></script>
|
|
<script>
|
|
(function() {
|
|
document.body.classList.add('ready');
|
|
var btn = document.getElementById('menu-btn');
|
|
var sb = document.getElementById('sidebar');
|
|
var ov = document.getElementById('sidebar-overlay');
|
|
if (btn) {
|
|
btn.addEventListener('click', function() { sb.classList.toggle('open'); ov.classList.toggle('open'); });
|
|
ov.addEventListener('click', function() { sb.classList.remove('open'); ov.classList.remove('open'); });
|
|
}
|
|
function checkHealth() {
|
|
var badge = document.getElementById('health-badge');
|
|
if (!badge) return;
|
|
fetch('/api/v1/health').then(function(r) { return r.json(); }).then(function(d) {
|
|
if (d.healthy) {
|
|
badge.className = 'status-pill status-pill--healthy';
|
|
badge.innerHTML = '<span class="status-dot"></span>healthy';
|
|
} else {
|
|
badge.className = 'status-pill status-pill--unhealthy';
|
|
badge.innerHTML = '<span class="status-dot"></span>unhealthy';
|
|
}
|
|
}).catch(function() {
|
|
badge.className = 'status-pill status-pill--unhealthy';
|
|
badge.innerHTML = '<span class="status-dot"></span>offline';
|
|
});
|
|
}
|
|
checkHealth();
|
|
setInterval(checkHealth, 30000);
|
|
})();
|
|
</script>
|
|
{{block "scripts" .}}{{end}}
|
|
</body>
|
|
</html>
|
|
{{end}}
|