rss-news/backend/templates/admin_dashboard.html

294 lines
11 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{ title }}</title>
<link rel="stylesheet" href="/admin/static/admin.css" />
</head>
<body>
<header class="topbar">
<div>
<h1>rss-news Admin Dashboard</h1>
<p>Angemeldet als <strong>{{ user }}</strong></p>
</div>
<div class="row">
<a class="linkbtn" href="/admin/connectivity">Connectivity Check</a>
<form method="post" action="/admin/logout">
<button type="submit" class="secondary">Logout</button>
</form>
</div>
</header>
<main class="container">
{% if flash_msg %}
<section class="card flash {{ 'flash-error' if flash_type == 'error' else 'flash-success' }}">
{{ flash_msg }}
</section>
{% endif %}
<section class="stats">
<article class="stat">
<div class="label">Quellen</div>
<div class="value">{{ sources|length }}</div>
</article>
<article class="stat">
<div class="label">Feeds</div>
<div class="value">{{ feeds|length }}</div>
</article>
<article class="stat">
<div class="label">Artikel</div>
<div class="value">{{ articles|length }}</div>
</article>
<article class="stat">
<div class="label">Runs</div>
<div class="value">{{ runs|length }}</div>
</article>
</section>
<section class="grid two">
<article class="card">
<h2>Quelle anlegen</h2>
<form method="post" action="/admin/sources/create" class="stack">
<input name="name" placeholder="Name" required />
<input name="base_url" placeholder="Base URL" />
<input name="terms_url" placeholder="Terms URL" />
<input name="license_name" placeholder="Lizenzname" />
<select name="risk_level">
<option value="green">green</option>
<option value="yellow" selected>yellow</option>
<option value="red">red</option>
</select>
<input name="last_reviewed_at" placeholder="last_reviewed_at (ISO)" />
<button type="submit">Quelle speichern</button>
</form>
</article>
<article class="card">
<h2>Feed anlegen</h2>
<form method="post" action="/admin/feeds/create" class="stack">
<input name="name" placeholder="Feed Name" required />
<input name="url" placeholder="https://..." required />
<label>Quelle</label>
<select name="source_id">
<option value="">-- keine --</option>
{% for s in sources %}
<option value="{{ s.id }}">{{ s.name }} (#{{ s.id }})</option>
{% endfor %}
</select>
<button type="submit">Feed speichern</button>
</form>
</article>
</section>
<section class="card">
<h2>Ingestion starten</h2>
<form method="post" action="/admin/ingestion/run" class="row">
<select name="feed_id">
<option value="">Alle aktivierten Feeds</option>
{% for f in feeds %}
<option value="{{ f.id }}">{{ f.name }} (#{{ f.id }})</option>
{% endfor %}
</select>
<button type="submit">Ingestion starten</button>
</form>
</section>
<section class="card">
<h2>Publisher ausführen</h2>
<form method="post" action="/admin/publisher/run" class="row">
<input name="max_jobs" value="10" />
<button type="submit">Publisher Run starten</button>
</form>
</section>
<section class="card">
<h2>Quellen + Policy</h2>
<table>
<thead>
<tr><th>ID</th><th>Name</th><th>Risk</th><th>Lizenz</th><th>Terms</th><th>Policy</th></tr>
</thead>
<tbody>
{% for s in sources %}
<tr>
<td>{{ s.id }}</td>
<td>{{ s.name }}</td>
<td>{{ s.risk_level }}</td>
<td>{{ s.license_name or "-" }}</td>
<td>{{ s.terms_url or "-" }}</td>
<td>
{% if source_policy[s.id] %}
<span class="badge bad">BLOCKED ({{ source_policy[s.id]|length }})</span>
<div class="subtle">{{ source_policy[s.id]|join(", ") }}</div>
{% else %}
<span class="badge ok">OK</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<section class="card">
<h2>Artikel (Review)</h2>
<form method="get" action="/admin/dashboard" class="row filter-row">
<label>Status-Filter</label>
<select name="status_filter">
<option value="" {% if not status_filter %}selected{% endif %}>alle</option>
{% for s in status_options %}
<option value="{{ s }}" {% if status_filter == s %}selected{% endif %}>{{ s }}</option>
{% endfor %}
</select>
<button type="submit" class="secondary">Filtern</button>
<a href="/admin/dashboard" class="linkbtn">Reset</a>
<a href="/api/articles/export?format=json{% if status_filter %}&status_filter={{ status_filter }}{% endif %}" class="linkbtn">Export JSON</a>
<a href="/api/articles/export?format=csv{% if status_filter %}&status_filter={{ status_filter }}{% endif %}" class="linkbtn">Export CSV</a>
</form>
<table>
<thead>
<tr><th>ID</th><th>Artikel</th><th>Status</th><th>Details</th><th>Rewrite</th><th>Transition</th></tr>
</thead>
<tbody>
{% for a in articles %}
<tr>
<td>{{ a.id }}</td>
<td>
<strong>{{ a.title }}</strong><br />
<span class="subtle">Autor: {{ a.author or "-" }}</span><br />
<span class="subtle">Datum: {{ a.published_at or "-" }} | Alter: {{ a.days_old if a.days_old is not none else "-" }} Tage | Relevanz: {{ a.relevance }}</span><br />
<a href="{{ a.source_url }}" target="_blank" rel="noopener">Original öffnen</a>
<br /><a href="/admin/articles/{{ a.id }}">Details anzeigen</a>
{% if a.canonical_url and a.canonical_url != a.source_url %}
<br /><a href="{{ a.canonical_url }}" target="_blank" rel="noopener">Canonical öffnen</a>
{% endif %}
</td>
<td><span class="badge">{{ a.status_ui }}</span></td>
<td>
<div class="subtle">Legal: {{ "OK" if a.legal_checked else "offen" }}</div>
<div class="subtle">Publish: {{ "bereit" if a.publish_ready else "blockiert" }}</div>
{% if not a.publish_ready and a.publish_blockers %}
<div class="subtle">{{ a.publish_blockers|join(", ") }}</div>
{% endif %}
{% if a.selected_image_url %}
<div class="subtle">Hauptbild gesetzt</div>
<a href="{{ a.selected_image_url }}" target="_blank" rel="noopener"><img src="{{ a.selected_image_proxy_url }}" data-fallback-src="{{ a.selected_image_url }}" alt="Hauptbild" class="thumb" loading="lazy" onerror="if(!this.dataset.fallbackUsed){this.dataset.fallbackUsed='1';this.src=this.dataset.fallbackSrc;}else{this.classList.add('img-failed');}" /></a>
{% endif %}
{% if a.summary %}
<div><strong>Summary:</strong> {{ a.summary }}</div>
{% endif %}
{% if a.content_raw %}
<details>
<summary>Volltext anzeigen</summary>
<div class="pre">{{ a.content_raw }}</div>
</details>
{% endif %}
<div class="subtle">Bilder: {{ a.extracted_images|length }}</div>
{% if a.extracted_images %}
<details>
<summary>Bild-URLs</summary>
<ul>
{% for img in a.extracted_images %}
<li><a href="{{ img }}" target="_blank" rel="noopener">{{ img }}</a></li>
{% endfor %}
</ul>
</details>
{% endif %}
{% if a.press_contact %}
<details>
<summary>Pressekontakt</summary>
<div class="pre">{{ a.press_contact }}</div>
</details>
{% endif %}
{% if a.extraction_error %}
<div class="subtle">Extraktionsfehler: {{ a.extraction_error }}</div>
{% endif %}
</td>
<td>
{% if a.status_ui in ["new", "rewrite"] %}
<form method="post" action="/admin/articles/{{ a.id }}/rewrite-run" class="inline">
<button type="submit">Rewrite ausführen</button>
</form>
{% else %}
-
{% endif %}
</td>
<td>
<form method="post" action="/admin/articles/{{ a.id }}/transition" class="inline">
<select name="target_status">
{% for s in allowed_transitions.get(a.status_ui, []) %}
<option value="{{ s }}">{{ s }}</option>
{% endfor %}
</select>
{% if allowed_transitions.get(a.status_ui, []) %}
<button type="submit" class="secondary">Setzen</button>
{% else %}
<span class="subtle">keine Aktion</span>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<section class="card">
<h2>Runs</h2>
<table>
<thead>
<tr><th>ID</th><th>Typ</th><th>Status</th><th>Start</th><th>Ende</th></tr>
</thead>
<tbody>
{% for r in runs %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.run_type }}</td>
<td>{{ r.status }}</td>
<td>{{ r.started_at }}</td>
<td>{{ r.finished_at or "-" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<section class="card">
<h2>Publish Jobs</h2>
<table>
<thead>
<tr><th>ID</th><th>Artikel</th><th>Status</th><th>Attempts</th><th>WP Post</th><th>Fehler</th><th>Hinweis</th></tr>
</thead>
<tbody>
{% for j in publish_jobs %}
<tr>
<td>{{ j.id }}</td>
<td>#{{ j.article_id }} {{ j.article_title or "-" }}</td>
<td>{{ j.status }}</td>
<td>{{ j.attempts }}/{{ j.max_attempts }}</td>
<td>
{% if j.wp_post_url %}
<a href="{{ j.wp_post_url }}" target="_blank" rel="noopener">#{{ j.wp_post_id }}</a>
{% elif j.wp_post_id %}
#{{ j.wp_post_id }}
{% else %}
-
{% endif %}
</td>
<td>
{% if j.error_message %}
<span class="badge errcat errcat-{{ j.error_category }}">{{ j.error_category }}</span>
<div>{{ j.error_message }}</div>
{% else %}
-
{% endif %}
</td>
<td>{{ j.error_hint or "-" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
</main>
</body>
</html>