AstraOS-Panel/AstraOS/Frontend/HTML/dashboard.html
elias 2d9a796ee5
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 11s
AstraOS Ver. 1.50 - Dashboard Schnellzugriff aktive Nutzer fix Tickets entfernt
2026-08-30 16:23:41 +02:00

239 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% 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="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-5">
<div>
<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="text-xs text-slate-500 flex items-center gap-1.5">
<span class="w-1.5 h-1.5 rounded-full bg-green-400 inline-block"></span>
Letztes Deploy: <span class="text-slate-300 font-mono ml-1" id="last-deploy-time">wird geladen…</span>
</div>
</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="grid grid-cols-1 lg:grid-cols-3 gap-8">
<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>
// Last Deploy Zeit laden
fetch('https://git.astra-os.de/api/v1/repos/MrWhiff/AstraOS-Panel/commits?limit=1&token=', {signal: AbortSignal.timeout(4000)})
.then(r => r.json())
.then(data => {
const el = document.getElementById('last-deploy-time');
if (!el) return;
const d = data?.[0]?.created;
if (!d) { el.textContent = 'unbekannt'; return; }
const date = new Date(d);
const diff = Math.round((Date.now() - date.getTime()) / 60000);
if (diff < 60) el.textContent = `vor ${diff} Min.`;
else if (diff < 1440) el.textContent = `vor ${Math.round(diff/60)} Std.`;
else el.textContent = date.toLocaleDateString('de-DE', {day:'2-digit', month:'short', hour:'2-digit', minute:'2-digit'});
})
.catch(() => { const el = document.getElementById('last-deploy-time'); 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 %}