Phase 15: language + bias als Spalten, Filter, Edit-Form
Bisher waren die DB-Felder sources.language und sources.bias zwar gepflegt (254/275 Quellen mit bias, 254 mit language), aber in der Verwaltung nicht sichtbar. Der Admin konnte nicht filtern oder editieren. Backend (routers/sources.py) - GlobalSourceCreate + GlobalSourceUpdate Pydantic-Modelle: language + bias als Optional[str] erweitert (max 100 / 500 Zeichen). - SOURCE_UPDATE_COLUMNS: language + bias hinzu. - INSERT in create_global_source: schreibt language + bias mit. - Neuer Endpoint GET /api/sources/global/languages: distinct language-Werte fuer Frontend-Filter-Dropdown. Frontend HTML (dashboard.html) - Grundquellen-Filter-Bar: Sprachen-Dropdown ergaenzt. - Grundquellen-Tabellenkopf: 2 neue Spalten Sprache (sortable) + Bias. - modalSource: 2 neue Felder language (mit datalist Vorschlaegen) + bias. - Kundenquellen-Filter-Bar: Sprachen-Dropdown. - Kundenquellen-Tabellenkopf: Sprache (sortable) + Bias. Frontend JS (sources.js) - loadGlobalSources lädt /languages parallel zu /global + /global/stats, populiert beide Sprache-Dropdowns + datalist im Edit-Modal. - renderGlobalSources: cols 11 -> 13, language+bias-Zellen (Bias mit Tooltip fuer Lang-Texte). - filterGlobalSources: Sprache-Filter, Bias in Suche. - editGlobalSource: language + bias laden. - Form-Submit: language + bias mitgesendet. - renderTenantSources: cols 8 -> 10, language+bias-Zellen. - tenantFilters um language erweitert, applyTenantFilterAndSort prueft. Cache-Buster ?v=20260509 (heute) bleibt - Tag wechselt erst morgen.
Dieser Commit ist enthalten in:
@@ -313,6 +313,9 @@
|
||||
<option value="active">Aktiv</option>
|
||||
<option value="inactive">Inaktiv</option>
|
||||
</select>
|
||||
<select class="filter-select" id="globalFilterLanguage" onchange="filterGlobalSources()">
|
||||
<option value="">Alle Sprachen</option>
|
||||
</select>
|
||||
<span class="text-secondary" id="globalSourceCount"></span>
|
||||
</div>
|
||||
<button class="btn btn-secondary" id="discoverSourceBtn">Erkennen</button>
|
||||
@@ -330,6 +333,8 @@
|
||||
<th class="sortable" data-sort="article_count" onclick="sortGlobalSources('article_count')">Artikel <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="articles_30d" onclick="sortGlobalSources('articles_30d')">Aktivität <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="tenant_excluded_count" onclick="sortGlobalSources('tenant_excluded_count')">Sperren <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="language" onclick="sortGlobalSources('language')">Sprache <span class="sort-icon"></span></th>
|
||||
<th>Bias</th>
|
||||
<th class="sortable" data-sort="last_seen_at" onclick="sortGlobalSources('last_seen_at')">Letzter Treffer <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="health_status" onclick="sortGlobalSources('health_status')">Health <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="status" onclick="sortGlobalSources('status')">Status <span class="sort-icon"></span></th>
|
||||
@@ -356,6 +361,9 @@
|
||||
<select class="filter-select" id="tenantFilterOrg" onchange="filterTenantSources()">
|
||||
<option value="">Alle Organisationen</option>
|
||||
</select>
|
||||
<select class="filter-select" id="tenantFilterLanguage" onchange="filterTenantSources()">
|
||||
<option value="">Alle Sprachen</option>
|
||||
</select>
|
||||
<span class="text-secondary" id="tenantSourceCount"></span>
|
||||
</div>
|
||||
<button class="btn btn-primary" id="tenantBulkPromoteBtn" disabled onclick="bulkPromoteSelected()">
|
||||
@@ -373,6 +381,8 @@
|
||||
<th class="sortable" data-sort="source_type" onclick="sortTenantSources('source_type')">Typ <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="category" onclick="sortTenantSources('category')">Kategorie <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="org_name" onclick="sortTenantSources('org_name')">Organisation <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="language" onclick="sortTenantSources('language')">Sprache <span class="sort-icon"></span></th>
|
||||
<th>Bias</th>
|
||||
<th>Hinzugefügt von</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
@@ -597,12 +607,23 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;">
|
||||
<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="sourceLanguage">Sprache</label>
|
||||
<input type="text" id="sourceLanguage" list="languageSuggestions" placeholder="z.B. Deutsch, Englisch, Russisch">
|
||||
<datalist id="languageSuggestions"></datalist>
|
||||
</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>
|
||||
<label for="sourceBias">Bias / Einordnung</label>
|
||||
<input type="text" id="sourceBias" placeholder="z.B. Nachrichtenagentur, faktenbasiert-neutral" maxlength="500">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sourceNotes">Notizen</label>
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren