188 lines
4.4 KiB
HTML
188 lines
4.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Node Dashboard</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
<style>
|
|
body{background:#0f172a;color:white}
|
|
.node-card{background:#1e293b;border:1px solid #334155;border-radius:10px;padding:12px}
|
|
.badge{font-size:10px;padding:2px 6px;border-radius:6px;background:#334155}
|
|
.status-dot{width:8px;height:8px;border-radius:50%}
|
|
</style>
|
|
</head>
|
|
|
|
<body class="p-6">
|
|
|
|
<div class="flex justify-between mb-6">
|
|
<h1 class="text-xl font-bold">🖥 Node Cluster</h1>
|
|
<button onclick="openAddNode()" class="bg-blue-600 px-3 py-2 rounded text-sm">+ Node</button>
|
|
</div>
|
|
|
|
<div id="nodes" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{% for node in nodes %}
|
|
|
|
<div class="node-card" onclick="editNode({{node.id}})">
|
|
|
|
<div class="flex justify-between items-center mb-2">
|
|
<div class="font-bold text-sm">{{node.name}}</div>
|
|
|
|
{% if node.status == 'Online' %}
|
|
<div class="status-dot bg-green-500"></div>
|
|
{% else %}
|
|
<div class="status-dot bg-red-500"></div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="text-xs text-slate-400 font-mono mb-2">
|
|
{{node.ip}}
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-1 mb-2">
|
|
|
|
<span class="badge">{{node.os}}</span>
|
|
<span class="badge">{{node.architecture}}</span>
|
|
|
|
{% if node.docker_installed %}
|
|
<span class="badge">🐳 Docker</span>
|
|
{% endif %}
|
|
|
|
<span class="badge">🔐 SSH</span>
|
|
|
|
{% if node.vnc_available %}
|
|
<span class="badge">🖥 VNC</span>
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
<div class="flex justify-between">
|
|
|
|
<button onclick="event.stopPropagation();openTerminal('{{node.ip}}')" class="text-xs bg-slate-700 px-2 py-1 rounded">Terminal</button>
|
|
|
|
<button onclick="event.stopPropagation();refreshNode({{node.id}})" class="text-xs bg-slate-700 px-2 py-1 rounded">Refresh</button>
|
|
|
|
<form action="/remove_node/{{node.id}}" method="post" onclick="event.stopPropagation()">
|
|
<button class="text-xs bg-red-600 px-2 py-1 rounded">Delete</button>
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% endfor %}
|
|
</div>
|
|
|
|
|
|
<!-- ADD NODE MODAL -->
|
|
|
|
<div id="addModal" class="hidden fixed inset-0 bg-black/80 flex items-center justify-center">
|
|
|
|
<div class="bg-slate-800 p-6 rounded w-96">
|
|
<h2 class="mb-4 font-bold">Node hinzufügen</h2>
|
|
|
|
<form action="/add_node" method="post" class="space-y-3">
|
|
|
|
<input name="name" placeholder="Name" class="w-full bg-slate-900 p-2 rounded text-sm" required>
|
|
|
|
<input name="ip" placeholder="IP" class="w-full bg-slate-900 p-2 rounded text-sm" required>
|
|
|
|
<input name="user" placeholder="User" class="w-full bg-slate-900 p-2 rounded text-sm" required>
|
|
|
|
<input name="password" type="password" placeholder="SSH Passwort" class="w-full bg-slate-900 p-2 rounded text-sm" required>
|
|
|
|
<div class="flex justify-end gap-2 pt-2">
|
|
<button type="button" onclick="closeAddNode()">Abbrechen</button>
|
|
<button class="bg-blue-600 px-3 py-1 rounded">Add</button>
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
<!-- EDIT NODE MODAL -->
|
|
|
|
<div id="editModal" class="hidden fixed inset-0 bg-black/80 flex items-center justify-center">
|
|
|
|
<div class="bg-slate-800 p-6 rounded w-96">
|
|
<h2 class="mb-4 font-bold">Node bearbeiten</h2>
|
|
|
|
<form id="editForm" method="post" class="space-y-3">
|
|
|
|
<input id="edit_name" name="name" class="w-full bg-slate-900 p-2 rounded text-sm">
|
|
<input id="edit_ip" name="ip" class="w-full bg-slate-900 p-2 rounded text-sm">
|
|
<input id="edit_user" name="user" class="w-full bg-slate-900 p-2 rounded text-sm">
|
|
|
|
<div class="flex justify-end gap-2">
|
|
<button type="button" onclick="closeEdit()">Cancel</button>
|
|
<button class="bg-blue-600 px-3 py-1 rounded">Save</button>
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
|
function openAddNode(){
|
|
|
|
document.getElementById("addModal").classList.remove("hidden")
|
|
|
|
}
|
|
|
|
function closeAddNode(){
|
|
|
|
document.getElementById("addModal").classList.add("hidden")
|
|
|
|
}
|
|
|
|
|
|
async function refreshNode(id){
|
|
|
|
const r = await fetch(`/refresh_status/${id}`)
|
|
const data = await r.json()
|
|
|
|
location.reload()
|
|
|
|
}
|
|
|
|
|
|
async function editNode(id){
|
|
|
|
const r = await fetch(`/node/${id}`)
|
|
const node = await r.json()
|
|
|
|
document.getElementById("edit_name").value = node.name
|
|
document.getElementById("edit_ip").value = node.ip
|
|
document.getElementById("edit_user").value = node.user
|
|
|
|
document.getElementById("editForm").action = `/update_node/${id}`
|
|
|
|
document.getElementById("editModal").classList.remove("hidden")
|
|
|
|
}
|
|
|
|
function closeEdit(){
|
|
|
|
document.getElementById("editModal").classList.add("hidden")
|
|
|
|
}
|
|
|
|
|
|
function openTerminal(ip){
|
|
|
|
window.open(`/terminal/${ip}`)
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|