Files
TK-Wiki-Newsletter/app/templates/dashboard.html
smueller 654276f6b5 Enhance newsletter generation and dashboard functionality
- Introduce a new period selection feature in the dashboard for generating newsletters, allowing users to choose between "last month" and "last X days."
- Refactor newsletter generation logic to support filtering by article type (new, edited, or all) and improve the handling of filters in the dashboard.
- Update the dashboard template to include new input fields for period and article type, enhancing user experience.
- Improve CSS styles for send notifications and sections in the dashboard, providing clearer feedback on newsletter sending status.
2026-07-07 14:20:21 +02:00

340 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<div class="page-header">
<h2>Wiki Newsletter</h2>
<p class="page-lead">Wiki-Änderungen filtern, Newsletter generieren und für Outlook aufbereiten.</p>
</div>
<div class="stats-row">
<div class="stat-card accent-new">
<div class="stat-value">{{ articles_new|length }}</div>
<div class="stat-label">Neue Artikel</div>
</div>
<div class="stat-card accent-edit">
<div class="stat-value">{{ articles_edited|length }}</div>
<div class="stat-label">Bearbeitete Artikel</div>
</div>
<div class="stat-card accent-total">
<div class="stat-value">{{ articles_new|length + articles_edited|length }}</div>
<div class="stat-label">Gesamt</div>
</div>
</div>
<div class="layout-2col">
<div class="main-col">
<section class="card card-accent-orange">
<div class="card-header">
<div>
<h3>Newsletter erstellen</h3>
<p class="card-desc">Zeitraum und Filter wählen, dann generieren.</p>
</div>
</div>
<form method="post" action="/dashboard" class="form-grid">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="form-row">
<label>Zeitraum
<select name="period">
<option value="days" {% if filters.period != 'last_month' %}selected{% endif %}>Letzte X Tage</option>
<option value="last_month" {% if filters.period == 'last_month' %}selected{% endif %}>Letzter Monat (voller Kalendermonat)</option>
</select>
</label>
<label>Tage (nur bei „Letzte X Tage“)
<input type="number" name="days" min="1" max="90" value="{{ filters.days }}">
</label>
</div>
<div class="form-row">
<label>Kategorie (optional)
<input type="text" name="category" value="{{ filters.category }}" placeholder="z. B. Linux">
</label>
</div>
<label>Artikel-Auswahl
<select name="article_type">
<option value="all" {% if filters.article_type == 'all' %}selected{% endif %}>Alle (neue &amp; bearbeitete)</option>
<option value="new" {% if filters.article_type == 'new' %}selected{% endif %}>Nur neue Artikel</option>
<option value="edited" {% if filters.article_type == 'edited' %}selected{% endif %}>Nur bearbeitete Artikel (keine neu erstellten)</option>
</select>
</label>
<fieldset class="display-options">
<legend>Anzeige im Newsletter</legend>
<label class="checkbox">
<input type="checkbox" name="show_date" value="true" {% if filters.display.show_date %}checked{% endif %}>
Datum anzeigen
</label>
<label class="checkbox">
<input type="checkbox" name="show_user" value="true" {% if filters.display.show_user %}checked{% endif %}>
Benutzer anzeigen
</label>
<label class="checkbox">
<input type="checkbox" name="show_category" value="true" {% if filters.display.show_category %}checked{% endif %}>
Kategorie anzeigen
</label>
</fieldset>
<label>Top-Highlights (optional)
<textarea name="highlights" rows="3" placeholder="Ein Artikeltitel pro Zeile muss exakt einem gefundenen Artikel entsprechen (max. 3)">{{ filters.highlights }}</textarea>
</label>
<p class="hint">Hervorgehobene Artikel erscheinen als „Top Highlights“-Box oben im Newsletter.</p>
<label>Redaktionsnotiz (optional)
<textarea name="editor_tip" rows="3" placeholder="Optionaler Hinweis der Redaktion für diese Ausgabe…">{{ filters.editor_tip }}</textarea>
</label>
<p class="hint">Wird nur angezeigt, wenn Text hinterlegt ist erscheint als eigene Box im Newsletter.</p>
{% if wiki_error %}
<p class="error">{{ wiki_error }}</p>
{% endif %}
{% if user.role in ["admin", "editor"] %}
<button type="submit" class="btn-primary">Newsletter generieren</button>
{% else %}
<p class="hint">Sie haben Leserechte. Bitte einen Editor oder Admin bitten, den Newsletter zu generieren.</p>
{% endif %}
</form>
</section>
<section class="card card-accent-orange">
<div class="card-header">
<div>
<h3>Vorschau &amp; Export</h3>
<p class="card-desc">Formatierten Newsletter ansehen und für Outlook kopieren.</p>
</div>
</div>
<p class="hint">Die Vorschau unten zeigt <strong>exakt</strong>, wie der Newsletter aussieht. „Vorschau kopieren“ übernimmt dieses Layout 1:1 in die Zwischenablage.</p>
<div class="copy-actions">
<button type="button" id="copy-outlook-btn" class="btn-primary">Vorschau kopieren</button>
<button type="button" id="open-outlook-btn" class="btn-secondary">Im Browser öffnen</button>
<button type="button" id="download-html-btn" class="btn-secondary">HTML herunterladen</button>
<button type="button" id="copy-html-source-btn" class="btn-outline">HTML-Quelltext</button>
<span id="copy-status" class="copy-status" aria-live="polite"></span>
</div>
<div class="preview-banner">Live-Vorschau so wird der Newsletter dargestellt</div>
<iframe id="newsletter-preview-frame" class="newsletter-preview-frame" title="Newsletter Vorschau"></iframe>
<textarea id="newsletter-html-source" class="hidden-source" hidden readonly>{{ raw_html }}</textarea>
<textarea id="newsletter-outlook-source" class="hidden-source" hidden readonly>{{ outlook_html }}</textarea>
<textarea id="newsletter-plain-source" class="hidden-source" hidden readonly>{{ plain_text }}</textarea>
{% if send_result %}
<div class="send-banner send-banner-{{ send_result.status }}">{{ send_result.message }}</div>
{% endif %}
{% if raw_html and (articles_new or articles_edited) %}
<div class="send-section">
<h4 style="margin:0 0 0.35rem;">Per E-Mail versenden</h4>
<p class="hint" style="margin:0 0 0.75rem;">Bitte oben die Vorschau prüfen. Beim Versenden wird genau dieser Newsletter (aktuelle Filter) an die Verteilerliste geschickt.</p>
<p class="hint" style="margin:0 0 0.75rem;">
<strong>Betreff:</strong> {{ subject }}<br>
<strong>Empfänger:</strong> {{ smtp.recipients if smtp.recipients else "— keine konfiguriert —" }}
{% if smtp.enabled != "true" %}<br><strong style="color:var(--tk-orange-dark);">SMTP ist deaktiviert</strong> bitte zuerst in „SMTP-Konfiguration“ aktivieren.{% endif %}
</p>
{% if user.role in ["admin", "editor"] %}
<form method="post" action="/newsletter/send-now" onsubmit="return confirm('Diesen Newsletter jetzt per E-Mail an die Verteilerliste senden?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="period" value="{{ filters.period }}">
<input type="hidden" name="days" value="{{ filters.days }}">
<input type="hidden" name="category" value="{{ filters.category }}">
<input type="hidden" name="article_type" value="{{ filters.article_type }}">
<input type="hidden" name="show_date" value="{{ 'true' if filters.display.show_date else 'false' }}">
<input type="hidden" name="show_user" value="{{ 'true' if filters.display.show_user else 'false' }}">
<input type="hidden" name="show_category" value="{{ 'true' if filters.display.show_category else 'false' }}">
<input type="hidden" name="highlights" value="{{ filters.highlights }}">
<input type="hidden" name="editor_tip" value="{{ filters.editor_tip }}">
<button type="submit" class="btn-primary">Newsletter jetzt senden</button>
</form>
{% else %}
<p class="hint">Sie haben Leserechte Versand nur für Editor/Admin.</p>
{% endif %}
</div>
{% endif %}
</section>
{% if filters.article_type != 'edited' %}
<section class="card card-accent-gray">
<div class="card-header">
<h3>Neue Artikel <span class="count-badge orange">{{ articles_new|length }}</span></h3>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Titel</th>
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
</tr>
</thead>
<tbody>
{% for item in articles_new %}
<tr>
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
</tr>
{% else %}
<tr class="empty-row"><td colspan="4">Keine neuen Artikel im gewählten Zeitraum.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
{% endif %}
{% if filters.article_type != 'new' %}
<section class="card card-accent-gray">
<div class="card-header">
<h3>Bearbeitete Artikel <span class="count-badge">{{ articles_edited|length }}</span></h3>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Titel</th>
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
</tr>
</thead>
<tbody>
{% for item in articles_edited %}
<tr>
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
</tr>
{% else %}
<tr class="empty-row"><td colspan="4">Keine bearbeiteten Artikel im gewählten Zeitraum.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
{% endif %}
<details class="card-details">
<summary>Weitere Ausgabeformate</summary>
<div class="details-body">
<h4 style="margin:1rem 0 0.5rem;font-size:0.95rem;">Nur-Text (Fallback)</h4>
<p class="hint">URLs als Klartext für klickbare Links die Vorschau nutzen.</p>
<textarea class="readonly-output" rows="10" readonly>{{ plain_text }}</textarea>
<h4 style="margin:1.25rem 0 0.5rem;font-size:0.95rem;">HTML-Quelltext</h4>
<p class="hint">Öffnet ein Fenster mit markiertem Text dort <strong>Strg+C</strong> drücken.</p>
<div class="textarea-actions">
<button type="button" id="copy-html-source-btn-2" class="btn-secondary">HTML-Quelltext kopieren</button>
<button type="button" id="download-html-source-btn" class="btn-outline">Herunterladen</button>
</div>
<textarea id="newsletter-html-display" class="readonly-output" rows="8" readonly>{{ raw_html }}</textarea>
</div>
</details>
{% if user.role == "admin" %}
<details class="card-details">
<summary>SMTP-Konfiguration</summary>
<div class="details-body">
<form method="post" action="/admin/smtp" class="form-grid">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<label class="checkbox">
<input type="checkbox" name="enabled" value="true" {% if smtp.enabled == "true" %}checked{% endif %}>
SMTP-Versand aktivieren
</label>
<div class="form-row">
<label>SMTP-Host
<input type="text" name="host" value="{{ smtp.host }}" placeholder="mail.example.com">
</label>
<label>SMTP-Port
<input type="number" name="port" value="{{ smtp.port }}">
</label>
</div>
<div class="form-row">
<label>Benutzername
<input type="text" name="username" value="{{ smtp.username }}">
</label>
<label>Passwort
<input type="password" name="password" value="{{ smtp.password }}">
</label>
</div>
<label>Absender E-Mail
<input type="email" name="from_email" value="{{ smtp.from_email }}">
</label>
<label class="checkbox">
<input type="checkbox" name="use_tls" value="true" {% if smtp.use_tls == "true" %}checked{% endif %}>
STARTTLS verwenden
</label>
<label>Verteilerliste (kommagetrennt)
<textarea rows="3" name="recipients" placeholder="kollege@firma.de, team@firma.de">{{ smtp.recipients }}</textarea>
</label>
<label>Geplanter täglicher Versand (HH:MM)
<input type="time" name="schedule_time" value="{{ smtp.schedule_time }}">
</label>
<button type="submit">Einstellungen speichern</button>
</form>
</div>
</details>
{% endif %}
<section class="card">
<div class="card-header">
<h3>Versandprotokoll</h3>
<span class="hint" style="margin:0;">Letzte 20 Einträge</span>
</div>
<div class="table-wrap">
<table>
<thead>
<tr><th>Zeit</th><th>Status</th><th>Betreff</th><th>Empfänger</th><th>Details</th></tr>
</thead>
<tbody>
{% for log in send_logs %}
<tr>
<td>{{ log.created_at }}</td>
<td><span class="badge badge-{{ log.status }}">{{ log.status }}</span></td>
<td>{{ log.subject }}</td>
<td>{{ log.recipients }}</td>
<td>{{ log.detail }}</td>
</tr>
{% else %}
<tr class="empty-row"><td colspan="5">Noch keine Versände protokolliert.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
</div>
<aside class="sidebar-col">
<div class="sidebar-card">
<h4>Workflow</h4>
<ol style="margin:0;padding-left:1.1rem;color:var(--tk-gray);">
<li>Filter setzen</li>
<li>Newsletter generieren</li>
<li>Vorschau prüfen</li>
<li>Für Outlook exportieren</li>
</ol>
</div>
<div class="sidebar-card">
<h4>Outlook-Tipp</h4>
<ul>
<li><strong>Vorschau kopieren</strong> übernimmt die Live-Vorschau</li>
<li>In Outlook: <strong>Strg+V</strong></li>
<li>Rechtsklick → <strong>Format beibehalten</strong></li>
<li>Bei Dunkelmodus: Outlook-Design auf „Weiß“ stellen</li>
</ul>
</div>
{% if user.role == "admin" %}
<div class="sidebar-card">
<h4>Administration</h4>
<ul>
<li><a href="/admin/users">Benutzerverwaltung</a></li>
<li>SMTP unter „SMTP-Konfiguration“</li>
</ul>
</div>
{% endif %}
</aside>
</div>
{% endblock %}
{% block scripts %}
<script src="/static/js/newsletter.js?v=8"></script>
{% endblock %}