Live-Log-Fix, Sidebar-Untermenüs für Geräte/Einstellungen, eigenes Konto
- Live-Log-Bug behoben: _latest_log_file() sortierte nach Datei-ctime statt
nach Dateiname — auf manchen Dateisystemen (u.a. unter WSL2 auf einem
gemounteten Windows-Laufwerk) unzuverlässig und lieferte nicht immer das
tatsächlich neueste Logfile. Sortiert jetzt wie der Rest des Codes über
den chronologisch sortierbaren Dateinamen (rpi-YYYYMMDDHHMMSS.log).
- Navbar umstrukturiert in aufklappbare Gruppen mit Unterpunkten:
- "Geräte": Clients (bisherige Devices-Seite), Switche, Zugangsdaten
- "Einstellungen": Benutzer, Gruppen, Systemeinstellungen (Prüfintervall),
Im-/Export
- "Logs": Live, Änderungen (vormals Live-Log/Änderungslog)
Sichtbarkeit gilt jetzt auch pro Unterpunkt: eine Gruppe erscheint nur,
wenn mindestens ein Unterpunkt für den Benutzer sichtbar ist, und zeigt
dann auch nur die sichtbaren Unterpunkte.
- Im-/Export als eigene Unterseite mit Export/Import nebeneinander
(.settings-grid).
- Neue Seite "Mein Konto" (/account, erreichbar über ein Zahnrad-Symbol
neben dem eigenen Namen in der Sidebar) ersetzt das bisherige Profil-Modal:
Profil/Passwort/Profilbild als volle Seite, dazu für Admins die
Navbar-Reihenfolge (aus den Systemeinstellungen hierher verschoben).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
"history": '<path d="M3 12a9 9 0 109-9 9.75 9.75 0 00-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l4 2"/>',
|
||||
"sliders": '<path d="M4 6h9M17 6h3M4 12h3M11 12h9M4 18h13M20 18h0"/><circle cx="15" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="17" cy="18" r="2"/>',
|
||||
"logout": '<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><path d="M16 17l5-5-5-5"/><path d="M21 12H9"/>',
|
||||
"gear": '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06A1.65 1.65 0 004.6 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06A1.65 1.65 0 009 4.6a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/>',
|
||||
"transfer": '<path d="M17 3l4 4-4 4"/><path d="M3 7h18"/><path d="M7 21l-4-4 4-4"/><path d="M21 17H3"/>',
|
||||
} %}
|
||||
|
||||
<div class="app-shell">
|
||||
@@ -65,7 +67,7 @@
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<button type="button" class="user-chip" data-open-modal="profileModal" onclick="resetProfileForms();" style="cursor:pointer; text-align:left; background:none; border:none; width:100%;">
|
||||
<div class="user-chip">
|
||||
{% if current_user.avatar_url %}
|
||||
<img class="user-avatar" src="{{ current_user.avatar_url }}" alt="" style="object-fit:cover;">
|
||||
{% else %}
|
||||
@@ -75,7 +77,10 @@
|
||||
<div class="u-name">{{ current_user.display_name }}</div>
|
||||
<div class="u-role">{{ "Administrator" if current_user.is_admin else current_user.group_names or "Benutzer" }}</div>
|
||||
</div>
|
||||
</button>
|
||||
<a href="{{ url_for('account') }}" class="icon-btn" title="Einstellungen">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">{{ icons['gear']|safe }}</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="footer-actions">
|
||||
<button type="button" class="icon-btn" data-theme-toggle title="Theme wechseln">
|
||||
<span data-theme-icon></span>
|
||||
@@ -86,49 +91,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Modal: Mein Profil (Klick auf eigenen Namen in der Sidebar) -->
|
||||
<div class="modal-overlay" id="profileModal">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h3>Mein Profil</h3>
|
||||
<button type="button" class="modal-close" data-close-modal>×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div style="display:flex; align-items:center; gap:14px; margin-bottom:20px;">
|
||||
{% if current_user.avatar_url %}
|
||||
<img src="{{ current_user.avatar_url }}" alt="" style="width:56px; height:56px; border-radius:50%; object-fit:cover;">
|
||||
{% else %}
|
||||
<div class="user-avatar" style="width:56px; height:56px; font-size:18px;">{{ current_user.username[:2]|upper }}</div>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ url_for('profile') }}" enctype="multipart/form-data" id="avatarForm" style="flex:1;">
|
||||
<input type="file" name="avatar" id="avatarInput" accept="image/png,image/jpeg,image/gif,image/webp" style="display:none;" onchange="document.getElementById('avatarForm').requestSubmit();">
|
||||
<button type="button" class="btn btn-secondary" style="width:100%;" onclick="document.getElementById('avatarInput').click();">Profilbild ändern</button>
|
||||
<input type="hidden" name="upload_avatar" value="1">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ url_for('profile') }}" id="profileForm">
|
||||
<div class="field"><label>Vorname</label><input type="text" name="first_name" value="{{ current_user.first_name or '' }}"></div>
|
||||
<div class="field"><label>Name</label><input type="text" name="last_name" value="{{ current_user.last_name or '' }}"></div>
|
||||
<div class="field"><label>Username</label><input type="text" value="{{ current_user.username }}" disabled></div>
|
||||
<button type="submit" name="update_profile" value="1" class="btn btn-primary btn-block">Speichern</button>
|
||||
</form>
|
||||
|
||||
<div style="border-top:1px solid var(--border); margin:20px 0;"></div>
|
||||
|
||||
<form method="post" action="{{ url_for('profile') }}" id="passwordForm">
|
||||
<h4 style="font-size:13px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-dim); margin-bottom:12px;">Passwort ändern</h4>
|
||||
<div class="field"><label>Aktuelles Passwort</label><input type="password" name="current_password" autocomplete="current-password"></div>
|
||||
<div class="field"><label>Neues Passwort</label><input type="password" name="new_password" autocomplete="new-password"></div>
|
||||
<div class="field"><label>Neues Passwort bestätigen</label><input type="password" name="confirm_password" autocomplete="new-password"></div>
|
||||
<button type="submit" name="change_password" value="1" class="btn btn-secondary btn-block">Passwort ändern</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="main {% if not current_user.is_authenticated %}no-sidebar{% endif %}">
|
||||
@@ -171,12 +133,6 @@
|
||||
{% endwith %}
|
||||
|
||||
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
|
||||
<script>
|
||||
function resetProfileForms() {
|
||||
const pwForm = document.getElementById("passwordForm");
|
||||
if (pwForm) pwForm.reset();
|
||||
}
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user