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

@@ -11,6 +11,7 @@ import aiosqlite
from auth import get_current_admin
from database import db_dependency
from audit import log_action, get_client_ip, row_to_dict
from source_meta import get_meta
from config import HEALTH_CHECK_USER_AGENT, HEALTH_CHECK_TIMEOUT_S
from shared.source_rules import (
discover_source,
@@ -28,6 +29,17 @@ router = APIRouter(prefix="/api/sources", tags=["sources"])
SOURCE_UPDATE_COLUMNS = {"name", "url", "domain", "source_type", "category", "status", "notes"}
@router.get("/meta")
async def get_sources_meta(admin: dict = Depends(get_current_admin)):
"""Liefert Kategorien und Typen als Single Source of Truth.
Frontend lädt das beim Init und befüllt damit Filter-Dropdowns + Label-Lookups.
Damit gibt es keine hardcoded Listen mehr im JS/HTML.
"""
return get_meta()
class GlobalSourceCreate(BaseModel):
name: str = Field(min_length=1, max_length=200)
url: Optional[str] = None