Navbar-Reihenfolge: Unterpunkte je Gruppe editierbar, Karte unter Profil/Passwort verschoben

- Neuer Settings-Schluessel nav_child_order (JSON dict group_key ->
  geordnete Liste der Kind-Keys), analog zu nav_order fuer die Top-Level-
  Reihenfolge. _ordered_nav_items() liefert die komplette, ungefilterte
  Navbar-Struktur inkl. angewandter Kind-Reihenfolge; inject_nav() filtert
  das anschliessend weiterhin nach Berechtigung wie bisher.
- save_nav_order() verarbeitet zusaetzlich ein Feld
  nav_child_order_<group_key> pro Gruppe mit Kindern.
- account.html: Navbar-Reihenfolge-Karte jetzt UNTER Profil/Passwort
  aendern (vorher darueber), zeigt die komplette Navbar inkl.
  eingerueckter, separat sortierbarer Unterpunkte pro Gruppe
  (verschachtelte <ul>, moveNavItem() bewegt automatisch nur innerhalb
  der eigenen Gruppe dank DOM-Nesting).
- Live per Playwright verifiziert: Zugangsdaten innerhalb Geraete nach
  oben verschoben, gespeichert, Sidebar zeigt danach tatsaechlich die
  neue Reihenfolge (Zugangsdaten vor Clients/Switche).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 10:34:31 +02:00
co-authored by Claude Sonnet 5
parent 9a390e740d
commit 197af26d72
3 changed files with 115 additions and 43 deletions
+51 -7
View File
@@ -343,10 +343,13 @@ def _nav_key_visible(key, user):
return False
@app.context_processor
def inject_nav():
if not current_user.is_authenticated:
return {}
def _ordered_nav_items():
"""Komplette Navbar-Struktur (Top-Level + Unterpunkte je Gruppe) in der
gespeicherten Reihenfolge, OHNE Sichtbarkeitsfilter — Grundlage sowohl
für die Sidebar (dort wird danach noch nach Berechtigung gefiltert) als
auch für den Reihenfolge-Editor auf der Account-Seite (der die
komplette Navbar zeigen soll, unabhängig davon, was der bearbeitende
Admin selbst sehen dürfte — als Admin ohnehin alles)."""
try:
stored_order = json.loads(get_setting("nav_order", "") or "[]")
except (ValueError, TypeError):
@@ -354,14 +357,36 @@ def inject_nav():
ordered_keys = [k for k in stored_order if k in NAV_ITEMS_BY_KEY]
ordered_keys += [k for k in DEFAULT_NAV_ORDER if k not in ordered_keys]
nav_items_ordered = []
try:
stored_child_order = json.loads(get_setting("nav_child_order", "") or "{}")
except (ValueError, TypeError):
stored_child_order = {}
items = []
for k in ordered_keys:
item = NAV_ITEMS_BY_KEY[k]
if item.get("children"):
children_by_key = {c["key"]: c for c in item["children"]}
stored = stored_child_order.get(k, [])
child_keys = [ck for ck in stored if ck in children_by_key]
child_keys += [c["key"] for c in item["children"] if c["key"] not in child_keys]
items.append({**item, "children": [children_by_key[ck] for ck in child_keys]})
else:
items.append(item)
return items
@app.context_processor
def inject_nav():
if not current_user.is_authenticated:
return {}
nav_items_ordered = []
for item in _ordered_nav_items():
if item.get("children"):
visible_children = [c for c in item["children"] if _nav_key_visible(c["key"], current_user)]
if visible_children:
nav_items_ordered.append({**item, "children": visible_children})
elif _nav_key_visible(k, current_user):
elif _nav_key_visible(item["key"], current_user):
nav_items_ordered.append(item)
return {"nav_items_ordered": nav_items_ordered}
@@ -880,7 +905,13 @@ def logout():
@app.route("/account")
@login_required
def account():
return render_template("account.html")
# Volle, ungefilterte Navbar-Struktur für den Reihenfolge-Editor (nur
# für Admins sichtbar/relevant) — anders als das automatisch injizierte
# nav_items_ordered (das nach Berechtigung des jeweils eingeloggten
# Benutzers filtert), damit auch Unterpunkte editierbar sind, die der
# bearbeitende Admin selbst nicht als Nicht-Admin sehen würde.
full_nav_items = _ordered_nav_items() if current_user.is_admin else []
return render_template("account.html", full_nav_items=full_nav_items)
@app.route("/profile", methods=["POST"])
@@ -1692,6 +1723,19 @@ def save_nav_order():
order = [k for k in request.form.getlist("nav_order") if k in NAV_ITEMS_BY_KEY]
order += [k for k in DEFAULT_NAV_ORDER if k not in order]
set_setting("nav_order", json.dumps(order))
# Unterpunkt-Reihenfolge je Gruppe — ein Feld "nav_child_order_<group_key>"
# pro Gruppe mit Kindern, Werte in der gewünschten Reihenfolge.
child_order = {}
for group_key, item in NAV_ITEMS_BY_KEY.items():
if not item.get("children"):
continue
valid_child_keys = {c["key"] for c in item["children"]}
submitted = [k for k in request.form.getlist(f"nav_child_order_{group_key}") if k in valid_child_keys]
submitted += [c["key"] for c in item["children"] if c["key"] not in submitted]
child_order[group_key] = submitted
set_setting("nav_child_order", json.dumps(child_order))
log_action("settings.update", "Navbar-Reihenfolge")
flash("Navbar-Reihenfolge gespeichert.", "success")
return redirect(url_for("account"))