Phase 3b: Kategorien/Typen aus Backend (/api/sources/meta)

- src/source_meta.py NEU: SOURCE_CATEGORIES + SOURCE_TYPES als
  Single Source of Truth (Liste mit {key, label}). category_label/type_label
  Lookup-Funktionen, get_meta() liefert das gesamte Set.
- src/routers/sources.py: GET /api/sources/meta ergänzt (admin-auth,
  liefert Kategorien + Typen)
- src/static/js/app.js: window.META + loadMeta() + categoryLabel/typeLabel +
  populateSelect Helper. Beim DOMContentLoaded wird Meta geladen, befüllt
  globale CATEGORY_LABELS und TYPE_LABELS.
- src/static/js/sources.js: hardcoded const CATEGORY_LABELS und TYPE_LABELS
  entfernt - werden jetzt aus app.js loadMeta() global gesetzt.
  loadGlobalSources() ruft populateSelect() für die Filter-Dropdowns auf.
- src/static/js/source-health.js: gleiche hardcoded Listen entfernt.
- src/static/dashboard.html: <option>-Listen für globalFilterCategory und
  globalFilterType entfernt (nur noch default Alle). JS befüllt sie dynamisch.

Ergebnis: Bei einer neuen Kategorie nur source_meta.py anpassen,
keine 3-fach-Pflege mehr in HTML+sources.js+source-health.js.
Dieser Commit ist enthalten in:
claude-dev
2026-05-09 03:05:16 +00:00
Ursprung 5a87168416
Commit eda60f9299
5 geänderte Dateien mit 138 neuen und 53 gelöschten Zeilen

Datei anzeigen

@@ -303,32 +303,9 @@
<input type="text" class="search-input" id="globalSourceSearch" placeholder="Grundquelle suchen...">
<select class="filter-select" id="globalFilterType" onchange="filterGlobalSources()">
<option value="">Alle Typen</option>
<option value="rss_feed">RSS-Feed</option>
<option value="web_source">Webquelle</option>
<option value="telegram_channel">Telegram-Kanal</option>
<option value="podcast_feed">Podcast-Feed</option>
</select>
<select class="filter-select" id="globalFilterCategory" onchange="filterGlobalSources()">
<option value="">Alle Kategorien</option>
<option value="nachrichtenagentur">Nachrichtenagentur</option>
<option value="oeffentlich-rechtlich">Öffentlich-Rechtlich</option>
<option value="qualitaetszeitung">Qualitätszeitung</option>
<option value="behoerde">Behörde</option>
<option value="fachmedien">Fachmedien</option>
<option value="think-tank">Think-Tank</option>
<option value="international">International</option>
<option value="regional">Regional</option>
<option value="boulevard">Boulevard</option>
<option value="sonstige">Sonstige</option>
<option value="cybercrime">Cybercrime / Hacktivismus</option>
<option value="cybercrime-leaks">Cybercrime / Leaks</option>
<option value="ukraine-russland-krieg">Ukraine-Russland-Krieg</option>
<option value="irankonflikt">Irankonflikt</option>
<option value="osint-international">OSINT International</option>
<option value="extremismus-deutschland">Extremismus Deutschland</option>
<option value="russische-staatspropaganda">Russische Staatspropaganda</option>
<option value="russische-opposition">Russische Opposition / Exilmedien</option>
<option value="syrien-nahost">Syrien / Nahost</option>
</select>
<select class="filter-select" id="globalFilterStatus" onchange="filterGlobalSources()">
<option value="">Alle Status</option>