From 20055c3b7433cafdff0838d087b6970e6e532786 Mon Sep 17 00:00:00 2001 From: Erik Thiele Date: Wed, 23 Sep 2026 19:47:35 +0200 Subject: [PATCH] feat: Verlauf im Dashboard seitenweise blaettern Co-Authored-By: Claude Opus 5 --- app.py | 41 ++++++++++++++++++++++++++++------ templates/admin_dashboard.html | 26 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/app.py b/app.py index 1ef2a6d..dc48aff 100755 --- a/app.py +++ b/app.py @@ -50,6 +50,8 @@ MEDIA_DIR = os.path.join(BASE_DIR, "media") # Medien-Dateien je Standort/S CONFIG_FILE = os.path.join(BASE_DIR, "config.json") # Persistente Konfiguration USERS_FILE = os.path.join(BASE_DIR, "users.json") # User-Datenbank HISTORY_FILE = os.path.join(BASE_DIR, "history.json") # Aktivitätsverlauf +HISTORY_MAX = 1000 # so viele Einträge werden aufbewahrt +HISTORY_PER_PAGE = 25 # Einträge je Seite im Dashboard-Verlauf APP_VERSION = "6.2.8" UPLOAD_EXTENSIONS = {".jpg", ".jpeg", ".png", ".mp4"} @@ -183,24 +185,33 @@ def add_history_entry(action, detail, user_email): except (json.JSONDecodeError, OSError): history = [] history.insert(0, entry) # Neueste zuerst - # Maximal 200 Einträge behalten - history = history[:200] + # Maximal HISTORY_MAX Einträge behalten + history = history[:HISTORY_MAX] with open(HISTORY_FILE, "w") as f: json.dump(history, f, indent=2) -def get_history(limit=50): - """Gibt die letzten history-Einträge zurück.""" +def _load_history(): + """Liest den kompletten Verlauf; bei defekter Datei eine leere Liste.""" if not os.path.exists(HISTORY_FILE): return [] try: with open(HISTORY_FILE) as f: - history = json.load(f) - return history[:limit] + return json.load(f) except (json.JSONDecodeError, OSError): return [] +def get_history(limit=50, offset=0): + """Gibt einen Ausschnitt des Verlaufs zurück (neueste zuerst).""" + return _load_history()[offset:offset + limit] + + +def get_history_count(): + """Anzahl aller gespeicherten Verlaufseintraege (fuer die Seitennavigation).""" + return len(_load_history()) + + def get_screen_config(cfg, site, screen): """Holt die Konfiguration für einen bestimmten Screen. Erzeugt automatisch fehlende Dict-Ebenen (sites → site → screens → screen).""" @@ -2080,8 +2091,19 @@ def admin_dashboard(): admin_count = sum(1 for u in users_data.values() if u.get("role") == "admin") superuser_count = sum(1 for u in users_data.values() if u.get("role") == "superuser") + # Kennzahlen und Sparklines bleiben bewusst am jüngsten Ausschnitt haengen, + # damit sie sich beim Blaettern im Verlauf nicht veraendern. history = get_history(30) + gesamt = get_history_count() + seiten = max(1, (gesamt + HISTORY_PER_PAGE - 1) // HISTORY_PER_PAGE) + try: + seite = int(request.args.get("page", 1)) + except ValueError: + seite = 1 + seite = min(max(seite, 1), seiten) + history_page = get_history(HISTORY_PER_PAGE, (seite - 1) * HISTORY_PER_PAGE) + # Sparkline-Daten aus dem Verlauf berechnen def build_sparkline(entries, creates, deletes): seq = list(reversed(entries)) @@ -2130,7 +2152,12 @@ def admin_dashboard(): user_trend=user_trend, admin_trend=admin_trend, superuser_trend=superuser_trend, - history=history, + history=history_page, + history_page=seite, + history_pages=seiten, + history_total=gesamt, + history_from=(seite - 1) * HISTORY_PER_PAGE + 1 if gesamt else 0, + history_to=min(seite * HISTORY_PER_PAGE, gesamt), site_list=get_accessible_sites(cfg, current_user), current_site=current_site_for(cfg, current_user), version=APP_VERSION, diff --git a/templates/admin_dashboard.html b/templates/admin_dashboard.html index bdeaa85..4056d03 100644 --- a/templates/admin_dashboard.html +++ b/templates/admin_dashboard.html @@ -121,6 +121,9 @@

Verlauf

+ {% if history_total %} + {{ history_from }}–{{ history_to }} von {{ history_total }} + {% endif %}
@@ -171,6 +174,29 @@ {% endfor %}
+ {% if history_pages > 1 %} + + {% endif %}