+
+
+
+
@@ -217,12 +240,13 @@
- | Name |
+ Name |
URL |
- Domain |
- Typ |
- Kategorie |
- Status |
+ Domain |
+ Typ |
+ Kategorie |
+ Artikel |
+ Status |
Aktionen |
@@ -250,7 +274,7 @@
Typ |
Kategorie |
Organisation |
- Hinzugefuegt von |
+ Hinzugefügt von |
Aktionen |
diff --git a/src/static/js/sources.js b/src/static/js/sources.js
index 6901b14..04b9ac7 100644
--- a/src/static/js/sources.js
+++ b/src/static/js/sources.js
@@ -4,6 +4,8 @@
let globalSourcesCache = [];
let tenantSourcesCache = [];
let editingSourceId = null;
+let globalSortField = "name";
+let globalSortAsc = true;
const CATEGORY_LABELS = {
nachrichtenagentur: "Nachrichtenagentur",
@@ -21,7 +23,7 @@ const CATEGORY_LABELS = {
const TYPE_LABELS = {
rss_feed: "RSS-Feed",
web_source: "Webquelle",
- excluded: "Gesperrt",
+ excluded: "Ausgeschlossen",
};
// --- Init ---
@@ -63,7 +65,7 @@ async function loadGlobalSources() {
function renderGlobalSources(sources) {
const tbody = document.getElementById("globalSourceTable");
if (sources.length === 0) {
- tbody.innerHTML = '| Keine Grundquellen |
';
+ tbody.innerHTML = '| Keine Grundquellen |
';
return;
}
tbody.innerHTML = sources.map((s) => `
@@ -73,31 +75,72 @@ function renderGlobalSources(sources) {
${esc(s.domain || "-")} |
${TYPE_LABELS[s.source_type] || s.source_type} |
${CATEGORY_LABELS[s.category] || s.category} |
+ ${s.article_count || 0} |
${s.status === "active" ? "Aktiv" : "Inaktiv"} |
-
+
|
`).join("");
document.getElementById("globalSourceCount").textContent = `${sources.length} Grundquellen`;
+
+ // Sort-Icons aktualisieren
+ document.querySelectorAll("th.sortable .sort-icon").forEach(el => el.textContent = "");
+ const activeHeader = document.querySelector(`th.sortable[data-sort="${globalSortField}"] .sort-icon`);
+ if (activeHeader) activeHeader.textContent = globalSortAsc ? " ▲" : " ▼";
}
-// Suche
+// Filter + Sortierung
document.addEventListener("DOMContentLoaded", () => {
const el = document.getElementById("globalSourceSearch");
if (el) {
- el.addEventListener("input", () => {
- const q = el.value.toLowerCase();
- const filtered = globalSourcesCache.filter((s) =>
- s.name.toLowerCase().includes(q) || (s.domain || "").toLowerCase().includes(q) || (s.category || "").toLowerCase().includes(q)
- );
- renderGlobalSources(filtered);
- });
+ el.addEventListener("input", () => filterGlobalSources());
}
});
+function filterGlobalSources() {
+ const q = (document.getElementById("globalSourceSearch")?.value || "").toLowerCase();
+ const typeFilter = document.getElementById("globalFilterType")?.value || "";
+ const catFilter = document.getElementById("globalFilterCategory")?.value || "";
+ const statusFilter = document.getElementById("globalFilterStatus")?.value || "";
+
+ let filtered = globalSourcesCache.filter((s) => {
+ if (q && !(s.name.toLowerCase().includes(q) || (s.domain || "").toLowerCase().includes(q) || (s.url || "").toLowerCase().includes(q))) return false;
+ if (typeFilter && s.source_type !== typeFilter) return false;
+ if (catFilter && s.category !== catFilter) return false;
+ if (statusFilter && s.status !== statusFilter) return false;
+ return true;
+ });
+
+ // Sortierung anwenden
+ filtered.sort((a, b) => {
+ let va = a[globalSortField] ?? "";
+ let vb = b[globalSortField] ?? "";
+ if (globalSortField === "article_count") {
+ va = va || 0; vb = vb || 0;
+ return globalSortAsc ? va - vb : vb - va;
+ }
+ va = String(va).toLowerCase();
+ vb = String(vb).toLowerCase();
+ const cmp = va.localeCompare(vb, "de");
+ return globalSortAsc ? cmp : -cmp;
+ });
+
+ renderGlobalSources(filtered);
+}
+
+function sortGlobalSources(field) {
+ if (globalSortField === field) {
+ globalSortAsc = !globalSortAsc;
+ } else {
+ globalSortField = field;
+ globalSortAsc = true;
+ }
+ filterGlobalSources();
+}
+
// --- Grundquelle erstellen/bearbeiten ---
function openNewGlobalSource() {
editingSourceId = null;
@@ -172,7 +215,7 @@ function setupSourceForms() {
function confirmDeleteGlobalSource(id, name) {
showConfirm(
- "Grundquelle loeschen",
+ "Grundquelle löschen",
`Soll die Grundquelle "${name}" endgültig gelöscht werden? Sie wird für alle Monitore entfernt.`,
async () => {
try {
@@ -210,7 +253,7 @@ function renderTenantSources(sources) {
${esc(s.org_name || "-")} |
${esc(s.added_by || "-")} |
-
+
|
`).join("");
@@ -320,7 +363,7 @@ async function addDiscoveredFeeds() {
});
if (selected.length === 0) {
- alert("Keine Feeds ausgewaehlt");
+ alert("Keine Feeds ausgewählt");
return;
}