Großes Cleanup: Bugs fixen, Features fertigstellen, toten Code entfernen

Bugs behoben:
- handleEdit() async keyword hinzugefügt (E-Mail-Checkboxen funktionieren jetzt)
- parseUTC() Funktion definiert (Fortschritts-Timer nutzt Server-Startzeit)
- Status cancelling wird im Frontend korrekt angezeigt

Features fertiggestellt:
- Sidebar: Lagen nach Typ getrennt (adhoc/research) mit Zählern
- Quellen-Bearbeiten: Edit-Button pro Quelle, Formular vorausfüllen
- Lizenz-Info: Org-Name und Lizenzstatus im Header angezeigt

Toter Code entfernt:
- 5 verwaiste Dateien gelöscht (alte rss_parser, style.css, components.js, layout.js, setup_users)
- 6 ungenutzte Pydantic Models entfernt
- Ungenutzte Funktionen/Imports in auth.py, routers, agents, config
- Tote API-Methoden, Legacy-UI-Methoden, verwaiste WS-Handler
- Abgeschlossene DB-Migrationen aufgeräumt

Sonstiges:
- requirements.txt: passlib[bcrypt] durch bcrypt ersetzt
- Umlaute korrigiert (index.html)
- CSS: incident-type-label → incident-type-badge, .login-success hinzugefügt
- Schließen statt Schliessen im Feedback-Modal
Dieser Commit ist enthalten in:
claude-dev
2026-03-04 18:45:38 +01:00
Ursprung 2a155c084d
Commit 71296edb97
23 geänderte Dateien mit 269 neuen und 4768 gelöschten Zeilen

Datei anzeigen

@@ -1,3 +1,16 @@
/**
* Parst einen UTC-Zeitstring vom Server in ein Date-Objekt.
*/
function parseUTC(dateStr) {
if (!dateStr) return null;
try {
const d = new Date(dateStr.endsWith('Z') ? dateStr : dateStr + 'Z');
return isNaN(d.getTime()) ? null : d;
} catch (e) {
return null;
}
}
/**
* UI-Komponenten für das Dashboard.
*/
@@ -149,19 +162,6 @@ const UI = {
return `${explanationHtml}<div class="evidence-chips">${chips}</div>`;
},
/**
* Verifizierungs-Badge.
*/
verificationBadge(status) {
const map = {
verified: { class: 'badge-verified', text: 'Verifiziert' },
unverified: { class: 'badge-unverified', text: 'Offen' },
contradicted: { class: 'badge-contradicted', text: 'Widerlegt' },
};
const badge = map[status] || map.unverified;
return `<span class="badge ${badge.class}">${badge.text}</span>`;
},
/**
* Toast-Benachrichtigung anzeigen.
*/
@@ -228,6 +228,7 @@ const UI = {
deep_researching: { active: 1, label: 'Tiefenrecherche läuft...' },
analyzing: { active: 2, label: 'Analysiert Meldungen...' },
factchecking: { active: 3, label: 'Faktencheck läuft...' },
cancelling: { active: 0, label: 'Wird abgebrochen...' },
};
const step = steps[status] || steps.queued;
@@ -553,6 +554,7 @@ const UI = {
<span class="source-feed-name">${this.escape(feed.name)}</span>
<span class="source-type-badge type-${feed.source_type}">${typeLabel}</span>
<span class="source-feed-url" title="${this.escape(feed.url || '')}">${this.escape(urlDisplay)}</span>
<button class="source-edit-btn" onclick="App.editSource(${feed.id})" title="Bearbeiten" aria-label="Bearbeiten">&#9998;</button>
<button class="source-delete-btn" onclick="App.deleteSingleFeed(${feed.id})" title="Löschen" aria-label="Löschen">&times;</button>
</div>`;
});
@@ -572,6 +574,7 @@ const UI = {
<span class="source-category-badge cat-${feeds[0]?.category || 'sonstige'}">${catLabel}</span>
${feedCountBadge}
<div class="source-group-actions" onclick="event.stopPropagation()">
${!hasMultiple && feeds[0]?.id ? `<button class="source-edit-btn" onclick="App.editSource(${feeds[0].id})" title="Bearbeiten" aria-label="Bearbeiten">&#9998;</button>` : ''}
<button class="btn btn-small btn-secondary" onclick="App.blockDomainDirect('${escapedDomain}')">Sperren</button>
<button class="source-delete-btn" onclick="App.deleteDomain('${escapedDomain}')" title="Löschen" aria-label="Löschen">&times;</button>
</div>
@@ -593,26 +596,6 @@ const UI = {
return url.length > 50 ? url.substring(0, 47) + '...' : url;
}
},
/**
* URLs in Evidence-Text als kompakte Hostname-Chips rendern (Legacy-Fallback).
*/
renderEvidenceChips(text) {
return this.renderEvidence(text);
},
/**
* URLs in Evidence-Text als klickbare Links rendern (Legacy).
*/
linkifyEvidence(text) {
if (!text) return '';
const escaped = this.escape(text);
return escaped.replace(
/(https?:\/\/[^\s,)]+)/g,
'<a href="$1" target="_blank" rel="noopener">$1</a>'
);
},
/**
* HTML escapen.
*/