feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
{% from "v2/components/icon.html" import icon %}
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="de" data-theme="auto">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>{% block title %}GWÖ-Antragsprüfer{% endblock %}</title>
|
|
|
|
|
<link rel="alternate" type="application/atom+xml" title="GWÖ-Antragsprüfer — Neue Bewertungen" href="/api/feed.xml">
|
|
|
|
|
|
|
|
|
|
{# Design-System: Tokens zuerst, dann Fonts, dann Base-Styles #}
|
2026-04-28 00:33:18 +02:00
|
|
|
<link rel="stylesheet" href="/static/v2/tokens.css?v={{ app_version|default('1') }}">
|
|
|
|
|
<link rel="stylesheet" href="/static/v2/fonts.css?v={{ app_version|default('1') }}">
|
|
|
|
|
<link rel="stylesheet" href="/static/v2/v2.css?v={{ app_version|default('1') }}">
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
|
|
|
|
|
{% block head_extra %}{% endblock %}
|
|
|
|
|
</head>
|
|
|
|
|
<body class="v2">
|
|
|
|
|
|
|
|
|
|
{% block body %}
|
|
|
|
|
{# AppShell inline, damit {% block main %} aus Screen-Templates rendert.
|
|
|
|
|
include propagiert Blocks nicht (Jinja2-Limitierung), darum direkt hier. #}
|
|
|
|
|
|
|
|
|
|
<div id="v2-overlay" class="v2-overlay"></div>
|
|
|
|
|
|
|
|
|
|
<div class="v2-shell">
|
|
|
|
|
|
|
|
|
|
<aside id="v2-sidebar" class="v2-sidebar">
|
|
|
|
|
<div class="v2-brand">
|
|
|
|
|
GWÖ-<span class="grn">ANTRAGS</span><span class="blu">PRÜFER</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="v2-brand-sub">Matrix 2.0 · Gemeinden</div>
|
|
|
|
|
|
|
|
|
|
<nav aria-label="Hauptnavigation">
|
|
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Lesen</div>
|
|
|
|
|
<a href="/" class="v2-nav-item {% if v2_active_nav == 'durchsuchen' %}active{% endif %}"
|
|
|
|
|
aria-current="{% if v2_active_nav == 'durchsuchen' %}page{% endif %}">
|
|
|
|
|
{{ icon("magnifying-glass", 14) }} Durchsuchen
|
|
|
|
|
{% if assessment_count is defined and assessment_count %}
|
|
|
|
|
<span class="v2-nav-count">{{ assessment_count }}</span>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</a>
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_authenticated %}<a href="/v2/merkliste" class="v2-nav-item {% if v2_active_nav == 'merkliste' %}active{% endif %}">{{ icon("bookmark-simple", 14) }} Merkliste</a>{% endif %}
|
|
|
|
|
<a href="/v2/tags" class="v2-nav-item {% if v2_active_nav == 'tags' %}active{% endif %}">{{ icon("tag", 14) }} Tags</a>
|
|
|
|
|
{% if is_admin %}<a href="/v2/cluster" class="v2-nav-item {% if v2_active_nav == 'cluster' %}active{% endif %}">{{ icon("graph", 14) }} Cluster</a>{% endif %}
|
|
|
|
|
{% if is_authenticated %}<a href="/v2/landtag-suche" class="v2-nav-item {% if v2_active_nav == 'landtag_suche' %}active{% endif %}">{{ icon("magnifying-glass-plus", 14) }} Landtag-Suche</a>{% endif %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
</div>
|
|
|
|
|
|
2026-04-25 22:18:58 +02:00
|
|
|
{% if is_authenticated %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Prüfen</div>
|
2026-04-25 22:18:58 +02:00
|
|
|
<a href="/v2/neu" class="v2-nav-item {% if v2_active_nav == 'neu' %}active{% endif %}">{{ icon("file-plus", 14) }} Neuer Antrag</a>
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_admin %}<a href="/v2/batch" class="v2-nav-item {% if v2_active_nav == 'batch' %}active{% endif %}">{{ icon("stack", 14) }} Batch-Analyse</a>{% endif %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Daten</div>
|
2026-04-25 22:18:58 +02:00
|
|
|
<a href="/auswertungen" class="v2-nav-item {% if v2_active_nav == 'auswertungen' %}active{% endif %}">{{ icon("chart-bar", 14) }} Auswertungen</a>
|
2026-05-06 17:32:38 +02:00
|
|
|
<a href="/stimmverhalten" class="v2-nav-item {% if v2_active_nav == 'stimmverhalten' %}active{% endif %}">{{ icon("circle-half", 14) }} Stimmverhalten</a>
|
feat(#170): Aktuelle-Themen-Dashboard — News × Anträge × Pressemitteilungen
Vollständiges 4-Phasen-Feature:
**Phase 1 — News-Aggregator** (`app/news_aggregator.py`)
- Tagesschau-API (`/api2u/news?ressort=...`) für inland/ausland/wirtschaft/wissen
- Bundestag-RSS für aktuellethemen / pressemitteilungen / hib
- DB-Tabelle `news_articles` (URL-PK, idempotent)
- Embeddings via existierender qwen-v4-Pipeline
- Cron-Script `scripts/auto-fetch-news.sh`
- Bewusst NICHT: RND.de (robots.txt bannt explizit ClaudeBot, GPTBot,
CCBot, ChatGPT-User, Google-Extended). Nur AI-erlaubende, öffentlich-
rechtliche/parlamentarische Quellen
- Volltexte werden NICHT persistiert (nur Titel + erster Satz)
**Phase 2 — Themen × Anträge Matching** (`app/themen_matching.py`)
- News-Embedding × Assessment-summary_embedding via Cosine-Similarity
- `find_anträge_for_news`: pro News die Top-K passenden Anträge
- `find_news_for_antrag`: pro Antrag Top-K News mit Datums-Fenster (90d)
- `aggregate_top_themen`: primärer Dashboard-Endpoint
- `aggregate_themen_zeitreihe`: News-Volumen pro Tag × Source
**Phase 3 — Dashboard-View** (`/aktuelle-themen`)
- Neuer linker Nav-Eintrag „Aktuelle Themen"
- Stacked-Area-Chart News-Volumen pro Quelle (30d)
- Pro News-Card: Titel + Summary + Tags + Top-3-Antrags-Match-Liste
mit GWÖ-Score-Pill, Drucksache-Link, PM-Vorschlag-Button
- Filter: Zeitfenster, Top-N, min_similarity
- Auth-protected (require_auth)
**Phase 4 — Pressemitteilungs-Generator** (`app/presse_generator.py`)
- LLM-Prompt-Template (200-250 Worte, GWÖ-Sicht, JSON-Output)
- Reuse von `QwenBewerter` aus app/adapters/qwen_bewerter.py
- DB-Tabelle `presse_drafts` (Persistenz)
- POST `/api/aktuelle-themen/generate-presse` rate-limited 5/min,
auth-only (LLM-Kosten)
- GET `/api/aktuelle-themen/drafts` + `/drafts/{id}` für Liste/Detail
- Manueller Trigger via UI-Button, kein Auto-Versand
- Modal-Anzeige des generierten Texts
**Compliance:**
- robots.txt-respektierend (ClaudeBot-Bann von RND vermieden, AI-
erlaubende Quellen verwendet)
- UI zeigt nur Titel+URL+Datum+erster Satz, keine Volltext-Reproduktion
- Pressemitteilungen sind explizit Drafts, nicht Auto-Versand
- LLM-Calls rate-limited, auth-only
**Tests:** 43 neue Tests (19 news_aggregator + 16 themen_matching +
8 presse_generator). Suite jetzt 1048 grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:39:36 +02:00
|
|
|
<a href="/aktuelle-themen" class="v2-nav-item {% if v2_active_nav == 'aktuelle-themen' %}active{% endif %}">{{ icon("book-open", 14) }} Aktuelle Themen</a>
|
2026-04-25 22:18:58 +02:00
|
|
|
<a href="/api/auswertungen/export.csv" class="v2-nav-item">{{ icon("file-csv", 14) }} Export · API</a>
|
2026-04-25 22:34:55 +02:00
|
|
|
<a href="/v2/feed" class="v2-nav-item {% if v2_active_nav == 'feed' %}active{% endif %}">{{ icon("rss", 14) }} Atom-Feed</a>
|
|
|
|
|
<a href="/v2/abos" class="v2-nav-item {% if v2_active_nav == 'abos' %}active{% endif %}">{{ icon("envelope-simple", 14) }} Meine Abos</a>
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
</div>
|
2026-04-25 22:18:58 +02:00
|
|
|
{% endif %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{% if is_admin %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
<div class="v2-nav-group">
|
|
|
|
|
<div class="v2-nav-label">— Administration</div>
|
feat: Stand-Dashboard, Score-Histogram, PM-Markdown, Live-Polling, Cluster-Indicator
Sechs zusammengehoerige UX/Performance-Erweiterungen:
**1. /v2/admin/stand — System-Stand-Dashboard**
KPI-Kacheln (Bewertungen, Plenum-Votes, Match, Vote-Orphans, News, PM-
Drafts, Bookmarks) + GWÖ-Score-Histogram + Per-BL-Tabelle + News-Source-
Tabelle. Auto-Refresh 30 s. Endpoint /api/admin/stand liefert alles in
einem Roundtrip. Nav-Eintrag "Stand" in der Admin-Sektion.
**2. /auswertungen Score-Histogram-Tab**
4. Tab "Score-Verteilung" mit Bar-Chart 0–10. Endpoint
/api/auswertungen/score-histogram liefert Buckets, optional gefiltert
nach Bundesland + Wahlperiode. Reagiert auf den globalen BL-Filter.
**3. PM-Body Markdown-Rendering**
Mini-Renderer im Modal: **bold** / __bold__ / *italic* / _italic_ /
- list-bullets / Doppel-Newline-Paragraphen. Kein externer Markdown-
Parser, keine neue Dependency. Body wird HTML-escaped, Patterns dann
zu Tags umgesetzt.
**4. Performance-Cache fuer themen_matching**
TTL-Cache (60 s) fuer aggregate_top_themen und aggregate_news_cluster.
Cache-Key inkl. aller Filter-Parameter. Automatische Invalidation in
news_aggregator.run_aggregator nach erfolgreichem Insert/Embed.
4 neue Tests fuer cache_get/set/clear-Verhalten.
**5. Stimmverhalten Banner Live-Update**
Statt setTimeout(800) jetzt pollQueueUntilDrained: alle 4 s
GET /api/queue/status, Banner zeigt pending + elapsed live. Bei
pending=0 zwei Polls in Folge: Banner + Stimmverhalten-Charts neu
laden. Max 5 Min Polling-Timeout. Bricht ab wenn Tab gewechselt wird.
**6. Antrag-Detail Cluster-Indicator**
News-Match-Box im Antrag-Detail laedt parallel /aktuelle-themen/cluster
und mappt URL → Cluster. Pro News-Card ein "🔗 Cluster (N News)"-Badge
mit Hover-Tooltip der anderen Cluster-Members. Macht thematische
Bündel sichtbar, ohne Pop-Out auf den Cluster-Tab.
Suite: 1088 → 1092 grün (4 Cache-Tests).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 02:49:06 +02:00
|
|
|
<a href="/v2/admin/stand" class="v2-nav-item {% if v2_active_nav == 'admin_stand' %}active{% endif %}">{{ icon("info", 14) }} Stand</a>
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
<a href="/v2/admin/freischaltungen" class="v2-nav-item">{{ icon("user-check", 14) }} Freischaltungen</a>
|
|
|
|
|
<a href="/v2/admin/queue" class="v2-nav-item">{{ icon("list-checks", 14) }} Queue</a>
|
|
|
|
|
<a href="/v2/admin/abos" class="v2-nav-item">{{ icon("envelope-simple", 14) }} Abos</a>
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</nav>
|
|
|
|
|
</aside>
|
|
|
|
|
|
|
|
|
|
<header class="v2-topbar">
|
|
|
|
|
<button id="v2-menu-toggle" class="v2-menu-toggle" aria-label="Navigation öffnen">☰</button>
|
|
|
|
|
<span class="v2-topbar-spacer"></span>
|
|
|
|
|
<a href="/methodik">{{ icon("info", 13) }} Methodik</a>
|
|
|
|
|
<a href="/quellen">{{ icon("book-open", 13) }} Quellen</a>
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# ── Globaler Bundesland-Selector ─────────────────────────────────── #}
|
|
|
|
|
<select id="v2-global-bl"
|
|
|
|
|
onchange="v2SetGlobalBl(this.value)"
|
|
|
|
|
aria-label="Bundesland wählen"
|
|
|
|
|
style="font-family:var(--font-mono);font-size:11px;padding:3px 6px;border:1px solid var(--ecg-light, var(--ecg-border));background:var(--ecg-card-bg);color:var(--ecg-dark);text-transform:uppercase;border-radius:3px;cursor:pointer;">
|
|
|
|
|
<option value="ALL">Bundesweit</option>
|
|
|
|
|
{% for bl in v2_bundeslaender %}<option value="{{ bl.code }}">{{ bl.code }}</option>{% endfor %}
|
|
|
|
|
</select>
|
|
|
|
|
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
{# ── Auth-Control — wird per JS nach /api/auth/me-Aufruf umgeschaltet ── #}
|
|
|
|
|
<div id="v2-auth-control" style="display:inline-flex;align-items:center;">
|
|
|
|
|
{# Platzhalter, bis initV2Auth() den Zustand kennt — unsichtbar #}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button id="v2-theme-toggle"
|
|
|
|
|
onclick="window.__v2CycleTheme && window.__v2CycleTheme()"
|
|
|
|
|
aria-label="Farbschema wechseln"
|
|
|
|
|
style="background:none;border:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);letter-spacing:0.06em;text-transform:uppercase;opacity:0.75;padding:0;display:inline-flex;align-items:center;gap:4px;">
|
|
|
|
|
<span id="v2-theme-icon">{{ icon("circle-half", 14) }}</span><span id="v2-theme-label">Auto</span>
|
|
|
|
|
</button>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<main class="v2-main" id="v2-main">
|
|
|
|
|
{% block main %}{% endblock %}
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
<footer class="v2-footer">
|
|
|
|
|
<span>GWÖ-Antragsprüfer · Matrix 2.0 · CC BY 4.0</span>
|
|
|
|
|
<a href="/methodik">Methodik</a>
|
|
|
|
|
<a href="/quellen">Quellen</a>
|
|
|
|
|
<a href="/impressum">Impressum</a>
|
|
|
|
|
<a href="/datenschutz">Datenschutz</a>
|
|
|
|
|
<a href="https://repo.toppyr.de/tobias/gwoe-antragspruefer">Quellcode</a>
|
|
|
|
|
<span class="v2-topbar-spacer"></span>
|
|
|
|
|
<a href="/classic" style="color:var(--ecg-green);opacity:1;">Zurück zur klassischen Ansicht</a>
|
|
|
|
|
</footer>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
/* ── Dark-Mode Toggle ────────────────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
const STORAGE_KEY = 'gwoe.theme';
|
|
|
|
|
const PREF_KEY = 'gwoe.ui';
|
|
|
|
|
const root = document.documentElement;
|
|
|
|
|
|
|
|
|
|
function applyTheme(theme) {
|
|
|
|
|
root.setAttribute('data-theme', theme);
|
|
|
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cycleTheme() {
|
|
|
|
|
const current = localStorage.getItem(STORAGE_KEY) || 'auto';
|
|
|
|
|
const next = { auto: 'light', light: 'dark', dark: 'auto' }[current] || 'auto';
|
|
|
|
|
applyTheme(next);
|
|
|
|
|
updateToggleLabel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateToggleLabel() {
|
|
|
|
|
const labelEl = document.getElementById('v2-theme-label');
|
|
|
|
|
const iconEl = document.getElementById('v2-theme-icon');
|
|
|
|
|
if (!labelEl) return;
|
|
|
|
|
const current = localStorage.getItem(STORAGE_KEY) || 'auto';
|
|
|
|
|
const labels = { auto: 'Auto', light: 'Hell', dark: 'Dunkel' };
|
|
|
|
|
const icons = {
|
|
|
|
|
auto: 'circle-half',
|
|
|
|
|
light: 'sun',
|
|
|
|
|
dark: 'moon'
|
|
|
|
|
};
|
|
|
|
|
labelEl.textContent = labels[current] || 'Auto';
|
|
|
|
|
if (iconEl) {
|
|
|
|
|
const iconName = icons[current] || 'circle-half';
|
|
|
|
|
iconEl.dataset.icon = iconName;
|
|
|
|
|
// Replace icon SVG dynamically via fetch (icons are static files)
|
|
|
|
|
fetch('/static/v2/icons/phosphor/' + iconName + '.svg')
|
|
|
|
|
.then(r => r.text())
|
|
|
|
|
.then(svg => { iconEl.innerHTML = svg; })
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore stored theme
|
|
|
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
|
|
|
if (stored) applyTheme(stored);
|
|
|
|
|
|
|
|
|
|
window.__v2CycleTheme = cycleTheme;
|
|
|
|
|
document.addEventListener('DOMContentLoaded', updateToggleLabel);
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
/* ── UI Preference (v2 = Default) ───────────────────────────────── */
|
|
|
|
|
/* AUTO-REDIRECT DEAKTIVIERT — er verursacht Loop mit aggressivem classic-localStorage-Set.
|
|
|
|
|
Umschalter via Topbar-Link „Klassische Ansicht" reicht als Opt-Out. */
|
|
|
|
|
(function () {
|
|
|
|
|
// Alte Preference-Spuren löschen, damit niemand festklebt
|
|
|
|
|
localStorage.removeItem('gwoe.ui');
|
|
|
|
|
return;
|
|
|
|
|
// dead code weiter unten, bewusst belassen für Nachvollziehbarkeit
|
|
|
|
|
// Wenn Nutzer:in zuvor explizit "classic" gewählt hat, zu /classic weiterleiten.
|
|
|
|
|
// gwoe.ui='classic' wird von index.html gesetzt, wenn man /classic besucht.
|
|
|
|
|
// Nach Rückkehr via "Zum neuen Design"-Link überschreibt v2 das localStorage,
|
|
|
|
|
// damit die Präferenz für den nächsten Tab-Start korrekt ist.
|
|
|
|
|
var pref = localStorage.getItem('gwoe.ui');
|
|
|
|
|
if (pref === 'classic') {
|
|
|
|
|
// Einmal weiterleiten; danach bleibt Nutzer:in auf v2 (kein Loop)
|
|
|
|
|
localStorage.removeItem('gwoe.ui');
|
|
|
|
|
window.location.replace('/classic');
|
|
|
|
|
} else {
|
|
|
|
|
localStorage.setItem('gwoe.ui', 'v2');
|
|
|
|
|
}
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
/* ── Mobile Sidebar Toggle ───────────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
const toggle = document.getElementById('v2-menu-toggle');
|
|
|
|
|
const sidebar = document.getElementById('v2-sidebar');
|
|
|
|
|
const overlay = document.getElementById('v2-overlay');
|
|
|
|
|
|
|
|
|
|
if (!toggle || !sidebar || !overlay) return;
|
|
|
|
|
|
|
|
|
|
toggle.addEventListener('click', function () {
|
|
|
|
|
sidebar.classList.toggle('open');
|
|
|
|
|
overlay.classList.toggle('open');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
overlay.addEventListener('click', function () {
|
|
|
|
|
sidebar.classList.remove('open');
|
|
|
|
|
overlay.classList.remove('open');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
{% block body_scripts %}{% endblock %}
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# ── Globaler BL-Selector — Persistenz + Event ───────────────────────────── #}
|
|
|
|
|
<script>
|
|
|
|
|
(function () {
|
|
|
|
|
var BL_KEY = 'gwoe.bl';
|
|
|
|
|
|
|
|
|
|
window.v2SetGlobalBl = function (code) {
|
|
|
|
|
try { localStorage.setItem(BL_KEY, code); } catch (_) {}
|
|
|
|
|
window.dispatchEvent(new CustomEvent('v2-bl-changed', { detail: { bl: code } }));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.v2GetGlobalBl = function () {
|
|
|
|
|
try { return localStorage.getItem(BL_KEY) || 'ALL'; } catch (_) { return 'ALL'; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
var sel = document.getElementById('v2-global-bl');
|
|
|
|
|
if (sel) sel.value = window.v2GetGlobalBl();
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
|
|
|
|
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
{# ── Auth Modal (global, einmal pro Seite) ────────────────────────────── #}
|
|
|
|
|
{% include "v2/components/auth_modal.html" %}
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
/* ── v2 Auth-State — Topbar-Control ─────────────────────────────────── */
|
|
|
|
|
(function () {
|
|
|
|
|
|
|
|
|
|
var TOPBAR_CONTROL_ID = 'v2-auth-control';
|
|
|
|
|
|
|
|
|
|
var BTN_BASE = [
|
|
|
|
|
'background:none',
|
|
|
|
|
'border:none',
|
|
|
|
|
'cursor:pointer',
|
|
|
|
|
'font-family:var(--font-sans)',
|
|
|
|
|
'font-size:11px',
|
|
|
|
|
'color:var(--ecg-dark)',
|
|
|
|
|
'letter-spacing:0.06em',
|
|
|
|
|
'text-transform:uppercase',
|
|
|
|
|
'opacity:0.75',
|
|
|
|
|
'padding:0',
|
|
|
|
|
'display:inline-flex',
|
|
|
|
|
'align-items:center',
|
|
|
|
|
'gap:4px'
|
|
|
|
|
].join(';');
|
|
|
|
|
|
|
|
|
|
function renderUnauthenticated(container) {
|
|
|
|
|
container.innerHTML =
|
|
|
|
|
'<button style="' + BTN_BASE + '" onclick="v2AuthModalOpen()" aria-label="Anmelden">' +
|
|
|
|
|
'{{ icon("key", 13) | replace("\"", "\'") }} Anmelden' +
|
|
|
|
|
'</button>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderAuthenticated(container, user) {
|
|
|
|
|
var name = user.preferred_username || user.name || user.sub || 'Konto';
|
2026-05-03 21:35:01 +02:00
|
|
|
var roles = Array.isArray(user.roles) ? user.roles : [];
|
|
|
|
|
var isAdmin = roles.indexOf('admin') !== -1 || roles.indexOf('gwoe-admin') !== -1;
|
|
|
|
|
var rolesTitle = roles.length ? 'Rollen: ' + roles.join(', ') : 'Keine speziellen Rollen';
|
|
|
|
|
var adminBadge = isAdmin
|
|
|
|
|
? '<span style="display:inline-block;margin-left:4px;padding:1px 6px;background:rgba(0,157,165,0.2);color:var(--ecg-teal);border-radius:9px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;">admin</span>'
|
|
|
|
|
: '';
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
container.innerHTML =
|
2026-05-03 21:35:01 +02:00
|
|
|
'<span style="' + BTN_BASE + ';cursor:default;gap:4px;" title="' + rolesTitle + '">' +
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
'{{ icon("user", 13) | replace("\"", "\'") }} ' +
|
2026-05-03 21:35:01 +02:00
|
|
|
'<span style="max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + name + '</span>' +
|
|
|
|
|
adminBadge +
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
'</span>' +
|
|
|
|
|
' ' +
|
|
|
|
|
'<button style="' + BTN_BASE + '" onclick="v2AuthLogout()" aria-label="Abmelden">' +
|
|
|
|
|
'{{ icon("sign-out", 13) | replace("\"", "\'") }} Abmelden' +
|
|
|
|
|
'</button>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function initV2Auth() {
|
|
|
|
|
var container = document.getElementById(TOPBAR_CONTROL_ID);
|
|
|
|
|
if (!container) return;
|
|
|
|
|
try {
|
|
|
|
|
var resp = await fetch('/api/auth/me');
|
|
|
|
|
var data = await resp.json();
|
|
|
|
|
if (data && data.authenticated) {
|
|
|
|
|
renderAuthenticated(container, data);
|
|
|
|
|
} else {
|
|
|
|
|
renderUnauthenticated(container);
|
|
|
|
|
}
|
|
|
|
|
} catch (_) {
|
|
|
|
|
renderUnauthenticated(container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function logout() {
|
|
|
|
|
// Server-seitig Cookies löschen (HttpOnly → client-side nicht möglich)
|
|
|
|
|
try {
|
|
|
|
|
await fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' });
|
|
|
|
|
} catch (e) { /* ignore, reload trotzdem */ }
|
|
|
|
|
location.reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.v2AuthLogout = logout;
|
|
|
|
|
document.addEventListener('DOMContentLoaded', initV2Auth);
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
2026-04-25 21:50:36 +02:00
|
|
|
|
feat(v2): Feedback-Widget mit Audit-Trail + Screenshot + direkter Gitea-Anbindung
- Component v2/components/feedback_widget.html: Button unten links oberhalb der
Queue, Klick oeffnet Modal mit vorausgefuellten Kontext-Feldern (URL,
Drucksache, Viewport, User-Agent, letzte 15 Klicks, letzte 10 Console-Errors,
letzte 5 Page-Loads). Eingaben: Titel, Beschreibung, optional Screenshot
- Audit-Trail-Sammler in localStorage (Ringbuffer 30 Klicks, 10 Errors)
- Screenshot via self-hosted html2canvas 1.4.1 (194 KB unter app/static/v2/lib/)
- Backend POST /api/feedback (rate-limit 5/h):
- validiert + html-strippt Inputs
- erstellt Gitea-Issue per API mit Label 'feedback' (Label wird idempotent angelegt)
- laedt Screenshot als Issue-Asset hoch (Gitea Issue-Attachment-API)
- 4 neue Settings: gitea_token, gitea_api_url, gitea_repo_owner, gitea_repo_name
- Server .env um GITEA_TOKEN ergaenzt
- 10 neue Unit-Tests (mit gemocktem httpx)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 01:00:44 +02:00
|
|
|
{# Feedback/Bug-Report-Widget — öffnet Gitea-Issues direkt aus dem Browser #}
|
|
|
|
|
{% include "v2/components/feedback_widget.html" %}
|
|
|
|
|
|
2026-04-25 21:50:36 +02:00
|
|
|
{# Queue-Statusbar mit Hover-Tooltip — analog zu classic-UI (#149) #}
|
|
|
|
|
{% include "v2/components/queue_widget.html" %}
|
feat(#139,#129,#138,#141): v2-Frontend (ECOnGOOD-CD), Login-Modal, Auto-DL, OG-Cards
v2-Frontend (#139, ECOnGOOD CD Manual Juni 2024):
- app/static/v2/: tokens.css, fonts.css, v2.css, Nunito-Sans woff2, Phosphor-Icons (21 SVGs)
- app/templates/v2/: base.html + 11 Screens + 8 Component-Macros
- AppShell mit Sidebar (Lesen/Pruefen/Daten/Admin), v2-Detail mit allen Features
(ScoreHero, MatrixMini, QuoteCard, Redline, Fraktions-Scores)
- v2 ist jetzt Default unter / — classic unter /classic
- Login-Modal in v2-Topbar mit Tabs Anmelden/Registrieren (#129)
- Phosphor-Icons in Sidebar + Topbar mit dynamischem Theme-Toggle
- Keyboard-Shortcuts (j/k/Enter/Esc/?/path), Landtag-Suche, Antrag-Historie,
Sort-Dropdown, Matrix-Feld-Info-Modal, Bookmarks/Comments/Voting/Share/Re-Analyze
Backend-Erweiterungen:
- main.py: ~30 neue Routes (/v2/*, /antrag/{ds}, /api/auth/{login,refresh,logout},
/api/me/merkliste/*, /api/admin/*, /v2/admin/*, OG-Cards, etc.)
- og_card.py + og_template: Open-Graph-Bilder via Playwright (#141)
- wahlprogramm_fetch.py + wahlprogramm-links.yaml: SHA-Gate Auto-DL (#138)
- auswertungen.py: BL-Filter + get_wahlperioden Helper (#137)
- auth.py: Direct-Access-Grant + Refresh-Token-Cookie
Classic-Updates:
- Header-DRY via _header.html, Auswertungen redirected, Batch-Inline raus
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00
|
|
|
</body>
|
|
|
|
|
</html>
|