AstraOS-Panel/AstraOS/Frontend/HTML/dashboard.html
MrWhiff c9d30cfbdd AstraOS Ver. 1.10.2:
- Benachrichtigung gefixt
2025-12-11 17:04:34 +01:00

254 lines
12 KiB
HTML

{% extends "sidebar.html" %}
{% block title %}AstraOS — Hybrid 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);
}
/* Schriftgröße für Systemstatus-Text im Wartungsmodus noch kleiner und mittig */
#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>
<!-- FLASH MESSAGES -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="toast-container">
{% for category, message in messages %}
<div x-data="{ show: true }" x-init="setTimeout(() => show = false, 5000)" x-show="show"
x-transition:enter="toast transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-x-8"
x-transition:enter-end="opacity-100 translate-x-0"
x-transition:leave="toast transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="max-w-md w-full bg-gray-800 shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden border border-{{ 'red' if category == 'danger' else ('green' if category == 'success' else ('blue' if category == 'info' else 'gray')) }}-500/40">
<div class="p-4">
<div class="flex items-start">
<div class="flex-shrink-0">
{% if category == 'success' %}
<svg class="h-6 w-6 text-green-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
{% elif category == 'danger' %}
<svg class="h-6 w-6 text-red-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
{% else %}
<svg class="h-6 w-6 text-blue-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
{% endif %}
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm font-medium text-gray-100">{{ message }}</p>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<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 %}">
<h3 class="text-2xl font-semibold mb-4">🚀 Willkommen bei AstraOS!</h3>
<p class="text-gray-300">
AstraOS ist da! Wir haben alles von Grund auf neu gebaut, damit du deine Systeme noch intuitiver und effizienter verwalten kannst. Wir hoffen, dir gefallen das neue Design und die vielen praktischen Funktionen.
</p>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Aktive Benutzer -->
<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 Benutzer</h3>
<p class="text-4xl font-bold" id="active-users">{{ stats.active_users.value }}</p>
<p class="text-green-400 text-sm mt-1" id="active-users-percent">
{% set pct = stats.active_users.percent %}
{% if pct is not none %}
{{ '+' if pct>=0 else '' }}{{ pct }}% seit letzter Woche
{% else %}
-
{% endif %}
</p>
</div>
<!-- Server-Auslastung -->
<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>
<!-- Offene Tickets -->
<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 %}">Offene Tickets</h3>
<p class="text-4xl font-bold" id="open-tickets">{{ stats.open_tickets.count }}</p>
<p class="text-gray-400 text-sm mt-1">Keine offenen Anfragen</p>
</div>
<!-- Systemstatus -->
<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>
<!-- Geplante Wartung -->
<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>
<!-- Letzte Benutzererstellung -->
<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">Durch: {{ last.by if last and last.by else 'N/A' }}</p>
</div>
</div>
<script>
gsap.registerPlugin(ScrollTrigger);
// Lade-Timeline
setTimeout(() => {
// Timeline für Header + Cards
const tl = gsap.timeline({ defaults: { duration: 0.4, ease: "power3.out" } });
// Header
tl.to("header", { opacity: 1, y: 0 });
// Cards schnell einblenden
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);
// Hover Glow
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 });
});
});
// Server-Auslastung alle 5 Sekunden aktualisieren
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();
// Systemstatus dynamisch Randfarbe anpassen
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); // initial nach Render
// Optional: falls Systemstatus dynamisch per AJAX kommt, hier regelmäßig prüfen
setInterval(updateSystemStatusCard, 2000);
</script>
{% endblock %}