AstraOS Ver. 1.50 - Dashboard Schnellzugriff aktive Nutzer fix Tickets entfernt
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 11s

This commit is contained in:
elias 2026-08-30 16:23:41 +02:00
parent b5ce3f41b3
commit 2d9a796ee5
2 changed files with 75 additions and 20 deletions

View file

@ -36,24 +36,49 @@
<div class="grid grid-cols-1 gap-8"> <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 <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 %}"> {% 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> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-5">
<p class="text-gray-300"> <div>
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. <h3 class="text-base font-semibold text-slate-300 uppercase tracking-wider">Schnellzugriff</h3>
</p> <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> </div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> <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 <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 %}"> {% 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> <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-4xl font-bold" id="active-users">{{ stats.active_users.value }}</p>
<p class="text-green-400 text-sm mt-1" id="active-users-percent"> <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 %} {% set pct = stats.active_users.percent %}
{% if pct is not none %} {% if pct is not none %}
{{ '+' if pct>=0 else '' }}{{ pct }}% seit letzter Woche {{ '+' if pct >= 0 else '' }}{{ pct }}% letzte 7 Tage
{% else %} {% else %}
- –
{% endif %} {% endif %}
</p> </p>
</div> </div>
@ -64,12 +89,6 @@
<p class="text-red-400 text-sm mt-1" id="server-load-status">{{ stats.server_load.status }}</p> <p class="text-red-400 text-sm mt-1" id="server-load-status">{{ stats.server_load.status }}</p>
</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 %}">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>
<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"> <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> <h3 class="text-xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Systemstatus</h3>
@ -117,6 +136,22 @@
</div> </div>
</div> </div>
<script> <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); gsap.registerPlugin(ScrollTrigger);
setTimeout(() => { setTimeout(() => {

View file

@ -699,7 +699,11 @@ def login():
session['username'] = user['username'] session['username'] = user['username']
session['permissions'] = get_user_permissions(str(user['_id'])) session['permissions'] = get_user_permissions(str(user['_id']))
add_log("Benutzer-Login") add_log("Benutzer-Login")
# Letzten Login-Zeitpunkt speichern
accounts_collection.update_one(
{'_id': user['_id']},
{'$set': {'last_login': datetime.utcnow()}}
)
if not user.get('discord_id') and not user.get('discord_override', False): if not user.get('discord_id') and not user.get('discord_override', False):
flash("Bitte verknüpfe deinen Discord-Account, um fortzufahren.", "info") flash("Bitte verknüpfe deinen Discord-Account, um fortzufahren.", "info")
return redirect(url_for('link_discord')) return redirect(url_for('link_discord'))
@ -784,10 +788,23 @@ def status_page():
@app.route('/dashboard') @app.route('/dashboard')
@login_required @login_required
def dashboard(): def dashboard():
user_count = accounts_collection.count_documents({}) if accounts_collection is not None else 1 user_count = accounts_collection.count_documents({}) if accounts_collection is not None else 0
last_user = accounts_collection.find_one(sort=[("creation_date", -1)]) if accounts_collection is not None else None # Aktive Nutzer: letzten 7 Tage
last_user_time = last_user["creation_date"] if last_user and "creation_date" in last_user else None now = datetime.utcnow()
last_user_by = last_user["username"] if last_user and "username" in last_user else None week_ago = now - timedelta(days=7)
two_weeks_ago = now - timedelta(days=14)
if accounts_collection is not None:
active_now = accounts_collection.count_documents({'last_login': {'$gte': week_ago}})
active_prev = accounts_collection.count_documents({'last_login': {'$gte': two_weeks_ago, '$lt': week_ago}})
if active_prev > 0:
active_pct = round((active_now - active_prev) / active_prev * 100, 1)
elif active_now > 0:
active_pct = 100.0
else:
active_pct = 0.0
else:
active_now = 0
active_pct = 0.0
open_tickets = 0 open_tickets = 0
if tickets_collection is not None: if tickets_collection is not None:
open_tickets = tickets_collection.count_documents({"status": "open"}) open_tickets = tickets_collection.count_documents({"status": "open"})
@ -819,8 +836,11 @@ def dashboard():
return str(v) return str(v)
maint = scheduled_maintenance or {"time": None, "status": "Keine", "duration_minutes": None} maint = scheduled_maintenance or {"time": None, "status": "Keine", "duration_minutes": None}
maint["time_str"] = _dt_to_str(maint.get("time")) maint["time_str"] = _dt_to_str(maint.get("time"))
last_user = accounts_collection.find_one(sort=[("creation_date", -1)]) if accounts_collection is not None else None
last_user_time = last_user["creation_date"] if last_user and "creation_date" in last_user else None
last_user_by = last_user["username"] if last_user and "username" in last_user else None
stats = { stats = {
"active_users": {"value": user_count, "percent": 0}, "active_users": {"value": active_now, "percent": active_pct, "total": user_count},
"server_load": server_load, "server_load": server_load,
"open_tickets": {"count": open_tickets}, "open_tickets": {"count": open_tickets},
"system_status": system_status, "system_status": system_status,