ui batch: admin tab, time filter, count-up, chevron sync, tidy
1. New /admin route with sub-tabs (Protokoll, Benutzer) for admins. Top nav: "Protokoll" dropped, "Admin" added right of Einstellungen. /logs and /einstellungen/benutzer issue 301 redirects to the new paths. Benutzer is no longer part of Einstellungen sub-nav. 2. User_filters.max_age_hours (migration v6) — new dropdown (1–10 h / beliebig) under Einstellungen → Filter; Wohnungen list drops flats older than the cutoff by discovered_at. 3. Header shows "aktualisiert vor X s" instead of a countdown. Template emits data-counter-up-utc with last_alert_heartbeat; app.js ticks up each second. When a scrape runs, the heartbeat updates and the HTMX swap resets the counter naturally. 4. Chevron state synced after HTMX swaps: panes preserved via hx-preserve keep the user's open/closed state, and the sibling button's .open class is re-applied by syncFlatExpandState() on afterSwap — previously a scroll-triggered poll would flip the chevron back to closed while the pane stayed open. 5. "Final absenden" footer removed from the profile page (functionality is unchanged, the switch still sits atop Wohnungen). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
83db8cd902
commit
da180bd7c7
10 changed files with 175 additions and 85 deletions
|
|
@ -1,25 +1,21 @@
|
|||
{% extends "_layout.html" %}
|
||||
{% block content %}
|
||||
<section class="card p-4">
|
||||
<form method="get" action="/logs" class="flex flex-wrap items-end gap-3">
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">von</label>
|
||||
<input class="input" type="date" name="from" value="{{ from_str }}">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">bis</label>
|
||||
<input class="input" type="date" name="to" value="{{ to_str }}">
|
||||
</div>
|
||||
<button class="btn btn-primary text-sm" type="submit">Anwenden</button>
|
||||
<a class="btn btn-ghost text-sm" href="/logs">zurücksetzen</a>
|
||||
<a class="btn btn-ghost text-sm"
|
||||
href="/logs/export.csv?from={{ from_str }}&to={{ to_str }}">
|
||||
CSV herunterladen
|
||||
</a>
|
||||
</form>
|
||||
</section>
|
||||
<form method="get" action="/admin/protokoll" class="flex flex-wrap items-end gap-3 mb-5">
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">von</label>
|
||||
<input class="input" type="date" name="from" value="{{ from_str }}">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">bis</label>
|
||||
<input class="input" type="date" name="to" value="{{ to_str }}">
|
||||
</div>
|
||||
<button class="btn btn-primary text-sm" type="submit">Anwenden</button>
|
||||
<a class="btn btn-ghost text-sm" href="/admin/protokoll">zurücksetzen</a>
|
||||
<a class="btn btn-ghost text-sm"
|
||||
href="/logs/export.csv?from={{ from_str }}&to={{ to_str }}">
|
||||
CSV herunterladen
|
||||
</a>
|
||||
</form>
|
||||
|
||||
<section class="card">
|
||||
<div class="card">
|
||||
<div class="px-4 py-3 border-b border-soft flex items-center justify-between">
|
||||
<h2 class="font-semibold">System-Protokoll</h2>
|
||||
<span class="text-xs text-slate-500">
|
||||
|
|
@ -50,5 +46,4 @@
|
|||
<div class="px-4 py-8 text-center text-slate-500">Keine Einträge im gewählten Zeitraum.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
<nav class="max-w-6xl mx-auto px-6 flex border-b border-soft -mb-px">
|
||||
<a class="tab {% if active_tab=='wohnungen' %}active{% endif %}" href="/">Wohnungen</a>
|
||||
<a class="tab {% if active_tab=='bewerbungen' %}active{% endif %}" href="/bewerbungen">Bewerbungen</a>
|
||||
{% if is_admin %}
|
||||
<a class="tab {% if active_tab=='logs' %}active{% endif %}" href="/logs">Protokoll</a>
|
||||
{% endif %}
|
||||
<a class="tab {% if active_tab=='einstellungen' %}active{% endif %}" href="/einstellungen">Einstellungen</a>
|
||||
{% if is_admin %}
|
||||
<a class="tab {% if active_tab=='admin' %}active{% endif %}" href="/admin">Admin</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</header>
|
||||
<main class="max-w-6xl mx-auto px-6 py-6 space-y-6">
|
||||
|
|
|
|||
|
|
@ -38,6 +38,15 @@
|
|||
<option value="no" {% if filters.wbs_required == 'no' %}selected{% endif %}>nein</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs uppercase tracking-wide text-slate-500 mb-1">max Alter</label>
|
||||
<select class="input" name="max_age_hours">
|
||||
<option value="" {% if not filters.max_age_hours %}selected{% endif %}>beliebig</option>
|
||||
{% for h in range(1, 11) %}
|
||||
<option value="{{ h }}" {% if filters.max_age_hours == h %}selected{% endif %}>≤ {{ h }} h</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-3">
|
||||
<button class="btn btn-primary" type="submit">Filter speichern</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -118,12 +118,3 @@
|
|||
<button class="btn btn-primary" type="submit">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr class="my-6 border-soft">
|
||||
<h3 class="font-semibold mb-2">Final absenden</h3>
|
||||
<p class="text-sm text-slate-600 mb-3">
|
||||
<span class="chip chip-warn">experimentell</span>
|
||||
Solange „Final absenden" aus ist, füllt die Automation das Formular aus, klickt aber
|
||||
nicht auf „Senden". Erst einschalten, wenn du jeden Anbieter einmal durchgetestet hast.
|
||||
Der Schalter liegt auch oben auf der Wohnungen-Seite.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@
|
|||
<h2 class="font-semibold">Passende Wohnungen auf inberlinwohnen.de</h2>
|
||||
<div class="flex items-center gap-3 text-xs text-slate-500">
|
||||
<span>{{ flats|length }} gefunden</span>
|
||||
{% if next_scrape_utc %}
|
||||
{% if last_scrape_utc %}
|
||||
<span class="sep">·</span>
|
||||
<span>nächste Aktualisierung <span class="countdown" data-countdown-utc="{{ next_scrape_utc }}">…</span></span>
|
||||
<span>aktualisiert <span class="countdown" data-counter-up-utc="{{ last_scrape_utc }}">…</span></span>
|
||||
{% endif %}
|
||||
{% if is_admin and (enrichment_counts.pending or enrichment_counts.failed) %}
|
||||
<span class="sep">·</span>
|
||||
|
|
|
|||
22
web/templates/admin.html
Normal file
22
web/templates/admin.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{#
|
||||
Admin-only landing page. Merges the former /logs tab and the former
|
||||
Benutzer sub-section of Einstellungen into one place, with sub-tabs.
|
||||
#}
|
||||
{% extends "_layout.html" %}
|
||||
{% block content %}
|
||||
<section class="card">
|
||||
<nav class="flex flex-wrap border-b border-soft px-4">
|
||||
{% set sections = [('protokoll','Protokoll'), ('benutzer','Benutzer')] %}
|
||||
{% for key, label in sections %}
|
||||
<a href="/admin/{{ key }}"
|
||||
class="tab {% if section == key %}active{% endif %}">{{ label }}</a>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
|
||||
<div class="p-5">
|
||||
{% if section == 'protokoll' %}{% include "_admin_logs.html" %}
|
||||
{% elif section == 'benutzer' %}{% include "_settings_users.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
<section class="card">
|
||||
<nav class="flex flex-wrap border-b border-soft px-4">
|
||||
{% set sections = [('profil','Profil'),('filter','Filter'),('benachrichtigungen','Benachrichtigungen'),('account','Account')] %}
|
||||
{% if is_admin %}{% set sections = sections + [('benutzer','Benutzer')] %}{% endif %}
|
||||
{% for key, label in sections %}
|
||||
<a href="/einstellungen/{{ key }}"
|
||||
class="tab {% if section == key %}active{% endif %}">{{ label }}</a>
|
||||
|
|
@ -15,7 +14,6 @@
|
|||
{% elif section == 'filter' %}{% include "_settings_filter.html" %}
|
||||
{% elif section == 'benachrichtigungen' %}{% include "_settings_notifications.html" %}
|
||||
{% elif section == 'account' %}{% include "_settings_account.html" %}
|
||||
{% elif section == 'benutzer' %}{% include "_settings_users.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue