diff --git a/web/app.py b/web/app.py index 97f0160..64f4f88 100644 --- a/web/app.py +++ b/web/app.py @@ -403,9 +403,16 @@ def _wohnungen_context(user) -> dict: }, filters): continue last = db.last_application_for_flat(uid, f["id"]) - flats_view.append({"row": f, "last": last}) + enrichment_data = None + if f["enrichment_json"]: + try: + enrichment_data = json.loads(f["enrichment_json"]) + except Exception: + enrichment_data = None + flats_view.append({"row": f, "last": last, "enrichment": enrichment_data}) rejected_view = db.rejected_flats(uid) + enrichment_counts = db.enrichment_counts() allowed, reason = _manual_apply_allowed() alert_label, alert_chip = _alert_status(notif_row) @@ -441,6 +448,7 @@ def _wohnungen_context(user) -> dict: return { "flats": flats_view, "rejected_flats": rejected_view, + "enrichment_counts": enrichment_counts, "map_points": map_points, "has_filters": _has_filters(filters_row), "alert_label": alert_label, diff --git a/web/db.py b/web/db.py index 065f8f6..7e4471a 100644 --- a/web/db.py +++ b/web/db.py @@ -479,6 +479,23 @@ def flats_needing_enrichment(limit: int = 100) -> list[sqlite3.Row]: ).fetchall()) +def enrichment_counts() -> dict: + row = _conn.execute( + """SELECT + COUNT(*) AS total, + SUM(CASE WHEN enrichment_status = 'ok' THEN 1 ELSE 0 END) AS ok, + SUM(CASE WHEN enrichment_status = 'pending' THEN 1 ELSE 0 END) AS pending, + SUM(CASE WHEN enrichment_status = 'failed' THEN 1 ELSE 0 END) AS failed + FROM flats""" + ).fetchone() + return { + "total": int(row["total"] or 0), + "ok": int(row["ok"] or 0), + "pending": int(row["pending"] or 0), + "failed": int(row["failed"] or 0), + } + + # --------------------------------------------------------------------------- # Applications # --------------------------------------------------------------------------- diff --git a/web/templates/_wohnungen_body.html b/web/templates/_wohnungen_body.html index 6c26aaa..46c2f15 100644 --- a/web/templates/_wohnungen_body.html +++ b/web/templates/_wohnungen_body.html @@ -81,7 +81,19 @@
{{ flats|length }} gefunden {% if next_scrape_utc %} - · nächste Aktualisierung + · + nächste Aktualisierung + {% endif %} + {% if is_admin and (enrichment_counts.pending or enrichment_counts.failed) %} + · +
+ + +
{% endif %}
- {% if f.rooms %}{{ "%.1f"|format(f.rooms) }} Z{% endif %} - {% if f.size %} · {{ "%.0f"|format(f.size) }} m²{% endif %} - {% if f.total_rent %} · {{ "%.0f"|format(f.total_rent) }} €{% endif %} - {% if f.wbs %} · WBS: {{ f.wbs }}{% endif %} - · + {% if f.enrichment_status == 'pending' %} + Infos werden abgerufen… + · + {% elif f.enrichment_status == 'failed' %} + Fehler beim Abrufen der Infos + · + {% else %} + {% set e = item.enrichment or {} %} + {% set parts = [] %} + {% if e.rooms %}{% set _ = parts.append('%g Z'|format(e.rooms)) %}{% endif %} + {% if e.size_sqm %}{% set _ = parts.append('%.0f m²'|format(e.size_sqm)) %}{% endif %} + {% set rent = e.rent_total or e.rent_cold %} + {% if rent %}{% set _ = parts.append('%.0f €'|format(rent)) %}{% endif %} + {% if e.wbs_required is true %} + {% set _ = parts.append('WBS: ' ~ (e.wbs_type or 'erforderlich')) %} + {% elif e.wbs_required is false %} + {% set _ = parts.append('ohne WBS') %} + {% endif %} + {{ parts|join(' · ') }}{% if parts %} · {% endif %} + {% endif %}
@@ -176,18 +203,6 @@
-{% if is_admin %} -
-
- - -
-
-{% endif %} {% if rejected_flats %}
diff --git a/web/templates/base.html b/web/templates/base.html index 963821d..8f9bda7 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -48,6 +48,12 @@ transition: border-color .15s, box-shadow .15s; } .input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(47,138,224,.18); } .chip { padding: .2rem .7rem; border-radius: 999px; font-size: .75rem; font-weight: 500; display: inline-block; } + /* Countdown — tabular digits + fixed width so the text doesn't wobble + while the seconds tick down (3 → 10 → 59 → 1 min). */ + .countdown { font-variant-numeric: tabular-nums; display: inline-block; + min-width: 4.2em; text-align: left; } + /* Neutral separator in flex rows so the '·' has equal gap on both sides. */ + .sep { color: var(--muted); user-select: none; } .chip-ok { background: #e4f6ec; color: #1f8a4a; border: 1px solid #b7e4c7; } .chip-warn { background: #fff4dd; color: #a36a1f; border: 1px solid #f5d48b; } .chip-bad { background: #fde6e9; color: #b8404e; border: 1px solid #f5b5bf; }