Feat: Grundquellen-Verwaltung und Kundenquellen-Übersicht

- Neuer Tab "Quellen" mit Sub-Tabs "Grundquellen" und "Kundenquellen"
- Grundquellen: CRUD (Erstellen, Bearbeiten, Löschen) - gilt für alle Monitore
- Kundenquellen: Übersicht aller tenant-spezifischen Quellen mit Org-Zuordnung
- Kundenquellen können zu Grundquellen befördert werden
- Suche/Filter in beiden Ansichten
- Sources-Router mit vollständiger API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
claude-dev
2026-03-05 19:46:45 +01:00
Ursprung af6040cbf6
Commit 19fbf152eb
4 geänderte Dateien mit 547 neuen und 1 gelöschten Zeilen

Datei anzeigen

@@ -22,6 +22,7 @@
<button class="nav-tab active" data-section="dashboard">Dashboard</button>
<button class="nav-tab" data-section="orgs">Organisationen</button>
<button class="nav-tab" data-section="licenses">Lizenzen</button>
<button class="nav-tab" data-section="sources">Quellen</button>
</nav>
<!-- Dashboard Section -->
@@ -193,6 +194,72 @@
</div>
</main>
<!-- Sources Section -->
<div class="section" id="sec-sources">
<div class="nav-tabs" id="sourceSubTabs">
<button class="nav-tab active" data-subtab="global-sources">Grundquellen</button>
<button class="nav-tab" data-subtab="tenant-sources">Kundenquellen</button>
</div>
<!-- Grundquellen -->
<div class="section active" id="sub-global-sources">
<div class="action-bar">
<div style="display:flex;align-items:center;gap:12px;">
<input type="text" class="search-input" id="globalSourceSearch" placeholder="Grundquelle suchen...">
<span class="text-secondary" id="globalSourceCount"></span>
</div>
<button class="btn btn-primary" id="newGlobalSourceBtn">+ Neue Grundquelle</button>
</div>
<div class="card">
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Name</th>
<th>URL</th>
<th>Domain</th>
<th>Typ</th>
<th>Kategorie</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody id="globalSourceTable"></tbody>
</table>
</div>
</div>
</div>
<!-- Kundenquellen -->
<div class="section" id="sub-tenant-sources">
<div class="action-bar">
<div style="display:flex;align-items:center;gap:12px;">
<input type="text" class="search-input" id="tenantSourceSearch" placeholder="Kundenquelle suchen...">
<span class="text-secondary" id="tenantSourceCount"></span>
</div>
</div>
<div class="card">
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Name</th>
<th>Domain</th>
<th>Typ</th>
<th>Kategorie</th>
<th>Organisation</th>
<th>Hinzugefuegt von</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody id="tenantSourceTable"></tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Modal: New Organization -->
<div class="modal-overlay" id="modalNewOrg">
<div class="modal">
@@ -286,6 +353,74 @@
</div>
</div>
<!-- Modal: Source (Create/Edit) -->
<div class="modal-overlay" id="modalSource">
<div class="modal">
<div class="modal-header">
<h3 id="sourceModalTitle">Neue Grundquelle</h3>
<button class="modal-close" onclick="closeModal('modalSource')">&times;</button>
</div>
<form id="sourceForm">
<div class="modal-body">
<div class="form-group">
<label for="sourceName">Name</label>
<input type="text" id="sourceName" required>
</div>
<div class="form-group">
<label for="sourceUrl">Feed-URL</label>
<input type="url" id="sourceUrl" placeholder="https://...">
</div>
<div class="form-group">
<label for="sourceDomain">Domain</label>
<input type="text" id="sourceDomain" placeholder="z.B. tagesschau.de">
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;">
<div class="form-group">
<label for="sourceType">Typ</label>
<select id="sourceType">
<option value="rss_feed">RSS-Feed</option>
<option value="web_source">Webquelle</option>
<option value="excluded">Gesperrt</option>
</select>
</div>
<div class="form-group">
<label for="sourceCategory">Kategorie</label>
<select id="sourceCategory">
<option value="nachrichtenagentur">Nachrichtenagentur</option>
<option value="oeffentlich-rechtlich">Oeffentlich-Rechtlich</option>
<option value="qualitaetszeitung">Qualitaetszeitung</option>
<option value="behoerde">Behoerde</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" selected>Sonstige</option>
</select>
</div>
</div>
<div class="form-group">
<label for="sourceStatus">Status</label>
<select id="sourceStatus">
<option value="active">Aktiv</option>
<option value="inactive">Inaktiv</option>
</select>
</div>
<div class="form-group">
<label for="sourceNotes">Notizen</label>
<input type="text" id="sourceNotes" placeholder="Optional">
</div>
<div id="sourceError" class="error-msg" style="display:none"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeModal('modalSource')">Abbrechen</button>
<button type="submit" class="btn btn-primary">Speichern</button>
</div>
</form>
</div>
</div>
<!-- Modal: Confirm -->
<div class="modal-overlay" id="modalConfirm">
<div class="modal" style="max-width: 400px;">
@@ -304,5 +439,6 @@
</div>
<script src="/static/js/app.js"></script>
<script src="/static/js/sources.js"></script>
</body>
</html>