252 lines
15 KiB
HTML
252 lines
15 KiB
HTML
{% extends "sidebar.html" %}
|
||
|
||
{% block title %}AstraOS — Dashboard{% endblock %}
|
||
|
||
{% block head %}
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
|
||
<style>
|
||
.glow-card {
|
||
transition: 0.2s ease;
|
||
}
|
||
.glow-card:hover {
|
||
box-shadow: 0 0 20px rgba(192,132,252,0.3);
|
||
transform: translateY(-4px);
|
||
}
|
||
#system-status-text.small {
|
||
font-size: 2rem;
|
||
text-align: center;
|
||
margin: 0 auto;
|
||
display: block;
|
||
}
|
||
#system-status-desc .wartung-desc {
|
||
font-size: 0.75rem;
|
||
display: block;
|
||
text-align: center;
|
||
margin: 0 auto;
|
||
font-weight: 500;
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<header class="flex justify-between items-center mb-6 opacity-0">
|
||
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Dashboard</h2>
|
||
</header>
|
||
|
||
<div class="grid grid-cols-1 gap-8">
|
||
<div class="glow-card opacity-0 translate-y-8 lg:col-span-2 bg-black/40 p-6 rounded-xl backdrop-blur
|
||
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||
<div class="mb-5">
|
||
<h3 class="text-base font-semibold text-slate-300 uppercase tracking-wider">Schnellzugriff</h3>
|
||
<p class="text-xs text-slate-500 mt-0.5">Zuletzt verwendete Bereiche</p>
|
||
</div>
|
||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3" id="quick-access-grid">
|
||
<a href="/user_management" class="group flex flex-col items-center justify-center gap-2 bg-slate-900/60 hover:bg-purple-950/40 border border-slate-800 hover:border-purple-500/40 rounded-xl p-4 transition-all duration-200">
|
||
<svg class="w-6 h-6 text-slate-400 group-hover:text-purple-400 transition" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/></svg>
|
||
<span class="text-xs font-medium text-slate-400 group-hover:text-slate-200 transition">Benutzerverwaltung</span>
|
||
</a>
|
||
<a href="/logs" class="group flex flex-col items-center justify-center gap-2 bg-slate-900/60 hover:bg-purple-950/40 border border-slate-800 hover:border-purple-500/40 rounded-xl p-4 transition-all duration-200">
|
||
<svg class="w-6 h-6 text-slate-400 group-hover:text-purple-400 transition" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z"/></svg>
|
||
<span class="text-xs font-medium text-slate-400 group-hover:text-slate-200 transition">Logs</span>
|
||
</a>
|
||
<a href="/tracker" class="group flex flex-col items-center justify-center gap-2 bg-slate-900/60 hover:bg-purple-950/40 border border-slate-800 hover:border-purple-500/40 rounded-xl p-4 transition-all duration-200">
|
||
<svg class="w-6 h-6 text-slate-400 group-hover:text-purple-400 transition" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z"/></svg>
|
||
<span class="text-xs font-medium text-slate-400 group-hover:text-slate-200 transition">Tracker</span>
|
||
</a>
|
||
<a href="/notifications" class="group flex flex-col items-center justify-center gap-2 bg-slate-900/60 hover:bg-purple-950/40 border border-slate-800 hover:border-purple-500/40 rounded-xl p-4 transition-all duration-200">
|
||
<svg class="w-6 h-6 text-slate-400 group-hover:text-purple-400 transition" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"/></svg>
|
||
<span class="text-xs font-medium text-slate-400 group-hover:text-slate-200 transition">Benachrichtigungen</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
|
||
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Letzte Änderung</h3>
|
||
<p class="text-base font-bold text-slate-100 truncate" id="last-commit-msg">wird geladen…</p>
|
||
<p class="text-xs text-slate-500 mt-0.5" id="last-commit-author">–</p>
|
||
<p class="text-xs text-purple-400 mt-1 font-mono" id="last-commit-time">–</p>
|
||
</div>
|
||
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
|
||
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Aktive Nutzer</h3>
|
||
<p class="text-4xl font-bold" id="active-users">{{ stats.active_users.value }}</p>
|
||
<p class="text-xs text-slate-500 mt-0.5">von {{ stats.active_users.total }} gesamt</p>
|
||
<p class="text-sm mt-1 {% if stats.active_users.percent >= 0 %}text-green-400{% else %}text-red-400{% endif %}" id="active-users-percent">
|
||
{% set pct = stats.active_users.percent %}
|
||
{% if pct is not none %}
|
||
{{ '+' if pct >= 0 else '' }}{{ pct }}% letzte 7 Tage
|
||
{% else %}
|
||
–
|
||
{% endif %}
|
||
</p>
|
||
</div>
|
||
|
||
<div id="server-load-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-red-500/40 rounded-xl p-6 backdrop-blur">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Server-Auslastung</h3>
|
||
<p class="text-4xl font-bold" id="server-load">{{ stats.server_load.percent }}%</p>
|
||
<p class="text-red-400 text-sm mt-1" id="server-load-status">{{ stats.server_load.status }}</p>
|
||
</div>
|
||
|
||
|
||
<div id="system-status-card" class="glow-card opacity-0 translate-y-8 bg-black/40 border border-green-500/40 rounded-xl p-6 backdrop-blur">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Systemstatus</h3>
|
||
{% set status = stats.system_status.status %}
|
||
<p id="system-status-text"
|
||
class="text-4xl font-bold
|
||
{% if 'online' in status.lower() %}text-green-400
|
||
{% elif 'wartung' in status.lower() or 'systeme im wartungsmodus' in status.lower() %}text-yellow-400 small
|
||
{% else %}text-red-400{% endif %}">
|
||
{{ status }}
|
||
</p>
|
||
<p class="text-gray-400 text-sm mt-1" id="system-status-desc">
|
||
{% if 'wartung' in status.lower() or 'systeme im wartungsmodus' in status.lower() %}
|
||
<span class="wartung-desc">Systeme im Wartungsmodus</span>
|
||
{% elif 'online' in status.lower() %}
|
||
Alle Systeme funktionsfähig
|
||
{% else %}
|
||
Teilweise oder komplett offline
|
||
{% endif %}
|
||
</p>
|
||
</div>
|
||
|
||
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
|
||
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Geplante Wartung</h3>
|
||
{% set maint = stats.scheduled_maintenance %}
|
||
{% if maint and maint.enabled %}
|
||
<p class="text-2xl font-bold text-yellow-400">Aktiv</p>
|
||
<p class="text-yellow-400 text-sm mt-1">{{ maint.status if maint.status else 'Wartungsarbeiten laufen' }}</p>
|
||
{% elif maint and maint.time_str %}
|
||
<p class="text-2xl font-bold">{{ maint.time_str }}</p>
|
||
<p class="text-yellow-400 text-sm mt-1">{{ maint.status if maint and maint.status else 'Geplant' }} {% if maint and maint.duration_minutes %}— Dauer: {{ maint.duration_minutes }} Min.{% endif %}</p>
|
||
{% else %}
|
||
<p class="text-2xl font-bold">Keine geplant</p>
|
||
<p class="text-gray-400 text-sm mt-1">Alle Systeme sind betriebsbereit.</p>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="glow-card opacity-0 translate-y-8 bg-black/40 rounded-xl p-6 backdrop-blur
|
||
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||
<h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Letzte Benutzererstellung</h3>
|
||
{% set last = stats.last_user_created %}
|
||
<p class="text-2xl font-bold" id="last-user-time">{{ last.time_str if last and last.time_str else 'Keine Daten' }}</p>
|
||
<p class="text-gray-400 text-sm mt-1" id="last-user-by">Erstellter Benutzer: {{ last.by if last and last.by else 'N/A' }}</p>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
// Letzte Änderung (Commit) laden
|
||
fetch('https://git.astra-os.de/api/v1/repos/MrWhiff/AstraOS-Panel/commits?limit=1', {signal: AbortSignal.timeout(4000)})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
const commit = data?.[0];
|
||
const msgEl = document.getElementById('last-commit-msg');
|
||
const authEl = document.getElementById('last-commit-author');
|
||
const timeEl = document.getElementById('last-commit-time');
|
||
if (!commit || !msgEl) return;
|
||
// Commit-Message (erste Zeile)
|
||
msgEl.textContent = (commit.commit?.message || '–').split('\n')[0];
|
||
// Autor
|
||
const author = commit.commit?.author?.name || commit.author?.login || '–';
|
||
authEl.textContent = `von ${author}`;
|
||
// Relative Zeit
|
||
const d = commit.created || commit.commit?.author?.date;
|
||
if (d) {
|
||
const diff = Math.round((Date.now() - new Date(d).getTime()) / 60000);
|
||
if (diff < 60) timeEl.textContent = `vor ${diff} Min.`;
|
||
else if (diff < 1440) timeEl.textContent = `vor ${Math.round(diff/60)} Std.`;
|
||
else timeEl.textContent = new Date(d).toLocaleDateString('de-DE', {day:'2-digit', month:'short', hour:'2-digit', minute:'2-digit'});
|
||
}
|
||
})
|
||
.catch(() => {
|
||
const el = document.getElementById('last-commit-msg');
|
||
if (el) el.textContent = 'nicht verfügbar';
|
||
});
|
||
|
||
|
||
gsap.registerPlugin(ScrollTrigger);
|
||
|
||
setTimeout(() => {
|
||
const tl = gsap.timeline({ defaults: { duration: 0.4, ease: "power3.out" } });
|
||
|
||
tl.to("header", { opacity: 1, y: 0 });
|
||
|
||
tl.to(".glow-card", { opacity: 1, y: 0, stagger: 0.08 });
|
||
|
||
// Header Parallax
|
||
gsap.to("header", {
|
||
y: 8,
|
||
ease: "none",
|
||
scrollTrigger: {
|
||
trigger: "header",
|
||
start: "top top",
|
||
scrub: true
|
||
}
|
||
});
|
||
}, 800);
|
||
|
||
document.querySelectorAll(".glow-card").forEach(card => {
|
||
card.addEventListener("mouseenter", () => {
|
||
gsap.to(card, { boxShadow: "0 0 30px rgba(192,132,252,0.4)", duration: 0.2 });
|
||
});
|
||
card.addEventListener("mouseleave", () => {
|
||
gsap.to(card, { boxShadow: "0 0 0 rgba(0,0,0,0)", duration: 0.2 });
|
||
});
|
||
});
|
||
|
||
function updateServerLoad() {
|
||
fetch('/api/server_load')
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
const loadCard = document.getElementById('server-load-card');
|
||
const loadStatus = document.getElementById('server-load-status');
|
||
|
||
document.getElementById('server-load').textContent = data.percent + '%';
|
||
loadStatus.textContent = data.status;
|
||
|
||
// Klassen für Farben entfernen
|
||
loadCard.classList.remove('border-red-500/40', 'border-green-500/40', 'border-yellow-500/40');
|
||
loadStatus.classList.remove('text-red-400', 'text-green-400', 'text-yellow-400');
|
||
|
||
if (data.status === 'Online') {
|
||
if (data.percent > 75) {
|
||
// Gelb bei hoher Auslastung
|
||
loadCard.classList.add('border-yellow-500/40');
|
||
loadStatus.classList.add('text-yellow-400');
|
||
} else {
|
||
// Grün bei normaler Auslastung
|
||
loadCard.classList.add('border-green-500/40');
|
||
loadStatus.classList.add('text-green-400');
|
||
}
|
||
} else {
|
||
// Rot bei Fehler/Offline
|
||
loadCard.classList.add('border-red-500/40');
|
||
loadStatus.classList.add('text-red-400');
|
||
}
|
||
});
|
||
}
|
||
setInterval(updateServerLoad, 5000);
|
||
updateServerLoad();
|
||
|
||
function updateSystemStatusCard() {
|
||
const card = document.getElementById('system-status-card');
|
||
const statusText = document.getElementById('system-status-text');
|
||
if (!card || !statusText) return;
|
||
card.classList.remove('border-green-500/40', 'border-yellow-500/40', 'border-red-500/40');
|
||
statusText.classList.remove('small');
|
||
const status = statusText.textContent.toLowerCase();
|
||
if (status.includes('wartung') || status.includes('systeme im wartungsmodus')) {
|
||
card.classList.add('border-yellow-500/40');
|
||
statusText.classList.add('small');
|
||
} else if (status.includes('online')) {
|
||
card.classList.add('border-green-500/40');
|
||
} else {
|
||
card.classList.add('border-red-500/40');
|
||
}
|
||
}
|
||
setTimeout(updateSystemStatusCard, 100);
|
||
setInterval(updateSystemStatusCard, 2000);
|
||
</script>
|
||
{% endblock %}
|