Dashboard: Verbindungen insgesamt getrennt von eindeutigen Geräten, Geräte-Übersicht ergänzt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8BG6rcfV94au1CrMNQq9E
main
Samuel Zielke 3 weeks ago
parent 357ec010d4
commit 4f9f357f9c

@ -42,30 +42,39 @@
</div> </div>
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-6 col-md-3"> <div class="col-6 col-md-6">
<div class="stat-card text-center">
<div class="stat-value">{{ total_connections }}</div>
<div class="stat-label">Verbindungen insgesamt <small class="text-muted">(alle Pings)</small></div>
</div>
</div>
<div class="col-6 col-md-6">
<div class="stat-card text-center">
<div class="stat-value">{{ unique_devices_total }}</div>
<div class="stat-label">Geräte insgesamt <small class="text-muted">(eindeutig)</small></div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-6 col-md-4">
<div class="stat-card text-center"> <div class="stat-card text-center">
<div class="stat-value">{{ devices_today }}</div> <div class="stat-value">{{ devices_today }}</div>
<div class="stat-label">Geräte heute</div> <div class="stat-label">Geräte heute</div>
</div> </div>
</div> </div>
<div class="col-6 col-md-3"> <div class="col-6 col-md-4">
<div class="stat-card text-center"> <div class="stat-card text-center">
<div class="stat-value">{{ devices_7d }}</div> <div class="stat-value">{{ devices_7d }}</div>
<div class="stat-label">Geräte (7 Tage)</div> <div class="stat-label">Geräte (7 Tage)</div>
</div> </div>
</div> </div>
<div class="col-6 col-md-3"> <div class="col-6 col-md-4">
<div class="stat-card text-center"> <div class="stat-card text-center">
<div class="stat-value">{{ devices_30d }}</div> <div class="stat-value">{{ devices_30d }}</div>
<div class="stat-label">Geräte (30 Tage)</div> <div class="stat-label">Geräte (30 Tage)</div>
</div> </div>
</div> </div>
<div class="col-6 col-md-3">
<div class="stat-card text-center">
<div class="stat-value">{{ unique_devices_total }}</div>
<div class="stat-label">Geräte insgesamt</div>
</div>
</div>
</div> </div>
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
@ -107,8 +116,38 @@
</p> </p>
</div> </div>
<div class="stat-card mb-3">
<h5 class="mb-2">Geräte-Übersicht <small class="text-muted">(ein Eintrag pro Gerät, nicht pro Ping)</small></h5>
<div style="overflow-x: auto;">
<table class="table table-sm table-striped mb-0">
<thead>
<tr>
<th>Gerät</th>
<th>Pings</th>
<th>Erster Kontakt</th>
<th>Letzter Kontakt</th>
<th>Standalone</th>
</tr>
</thead>
<tbody>
{% for device in device_summary %}
<tr>
<td><code>{{ device.device_id|slice:":8" }}…</code></td>
<td>{{ device.ping_count }}</td>
<td>{{ device.first_seen|date:"d.m.Y H:i" }}</td>
<td>{{ device.last_seen|date:"d.m.Y H:i" }}</td>
<td>{{ device.standalone_any|yesno:"Ja,Nein" }}</td>
</tr>
{% empty %}
<tr><td colspan="5" class="text-muted">Noch keine Daten</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="stat-card"> <div class="stat-card">
<h5 class="mb-2">Letzte Signale</h5> <h5 class="mb-2">Letzte Signale <small class="text-muted">(roher Ping-Log, ein Gerät kann hier mehrfach auftauchen)</small></h5>
<div style="overflow-x: auto;"> <div style="overflow-x: auto;">
<table class="table table-sm table-striped mb-0"> <table class="table table-sm table-striped mb-0">
<thead> <thead>

@ -1,7 +1,7 @@
import json import json
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.db.models import Count from django.db.models import Count, Max, Min
from django.http import JsonResponse from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, redirect from django.shortcuts import render, HttpResponse, redirect
from django.utils import timezone from django.utils import timezone
@ -102,6 +102,7 @@ def usage_dashboard(request):
events = UsageEvent.objects.all() events = UsageEvent.objects.all()
context = { context = {
"total_connections": events.count(),
"unique_devices_total": events.values("device_id").distinct().count(), "unique_devices_total": events.values("device_id").distinct().count(),
"devices_today": events.filter(created_at__gte=today_start).values("device_id").distinct().count(), "devices_today": events.filter(created_at__gte=today_start).values("device_id").distinct().count(),
"devices_7d": events.filter(created_at__gte=now - timedelta(days=7)).values("device_id").distinct().count(), "devices_7d": events.filter(created_at__gte=now - timedelta(days=7)).values("device_id").distinct().count(),
@ -109,6 +110,16 @@ def usage_dashboard(request):
"standalone_count": events.filter(is_standalone=True).values("device_id").distinct().count(), "standalone_count": events.filter(is_standalone=True).values("device_id").distinct().count(),
"by_platform": events.values("platform").annotate(count=Count("device_id", distinct=True)).order_by("-count"), "by_platform": events.values("platform").annotate(count=Count("device_id", distinct=True)).order_by("-count"),
"by_browser": events.values("browser").annotate(count=Count("device_id", distinct=True)).order_by("-count"), "by_browser": events.values("browser").annotate(count=Count("device_id", distinct=True)).order_by("-count"),
"device_summary": (
events.values("device_id")
.annotate(
ping_count=Count("id"),
first_seen=Min("created_at"),
last_seen=Max("created_at"),
standalone_any=Max("is_standalone"),
)
.order_by("-last_seen")
),
"recent_events": events[:30], "recent_events": events[:30],
} }
return render(request, "app/dashboard.html", context) return render(request, "app/dashboard.html", context)

Loading…
Cancel
Save

Powered by TurnKey Linux.