Promote develop -> main (Quellen-Health Schritt 1: Sub-Section + Pagination + Backend-Slim + UX) #1
@@ -578,10 +578,9 @@ async def get_health(
|
||||
|
||||
cursor = await db.execute("""
|
||||
SELECT
|
||||
h.id, h.source_id, s.name, s.domain, s.url, s.source_type,
|
||||
s.tenant_id, s.category, s.language, s.bias,
|
||||
h.source_id, s.name, s.domain, s.tenant_id, s.language,
|
||||
o.name AS org_name,
|
||||
h.check_type, h.status, h.message, h.details, h.checked_at
|
||||
h.check_type, h.status, h.message
|
||||
FROM source_health_checks h
|
||||
JOIN sources s ON s.id = h.source_id
|
||||
LEFT JOIN organizations o ON o.id = s.tenant_id
|
||||
|
||||
@@ -708,7 +708,7 @@
|
||||
|
||||
<script src="/static/js/app.js?v=20260509d"></script>
|
||||
<script src="/static/js/sources.js?v=20260509d"></script>
|
||||
<script src="/static/js/source-health.js?v=20260509d"></script>
|
||||
<script src="/static/js/source-health.js?v=20260509e"></script>
|
||||
<script src="/static/js/audit.js?v=20260509d"></script>
|
||||
<div id="toastContainer" class="toast-container" aria-live="polite" aria-atomic="true"></div>
|
||||
</body>
|
||||
|
||||
@@ -6,6 +6,11 @@ let suggestionsCache = [];
|
||||
let healthFilters = { status: "", check_type: "", org: "all" };
|
||||
let healthHistoryCache = [];
|
||||
|
||||
// 60-Sekunden-Cache, damit Tab-Wechsel nicht jedes Mal die volle Antwort neu lädt.
|
||||
// Bei Mutationen (Vorschlag annehmen/ablehnen, run-stream, search-fix) wird mit force=true neu geladen.
|
||||
let healthDataCache = { health: null, suggestions: null, history: null, ts: 0 };
|
||||
const HEALTH_CACHE_TTL_MS = 60000;
|
||||
|
||||
|
||||
const CHECK_TYPE_LABELS = {
|
||||
reachability: "Erreichbarkeit",
|
||||
@@ -38,7 +43,15 @@ function setupHealthTab() {
|
||||
document.addEventListener("DOMContentLoaded", setupHealthTab);
|
||||
|
||||
// --- Health-Daten laden ---
|
||||
async function loadHealthData() {
|
||||
async function loadHealthData(force = false) {
|
||||
const now = Date.now();
|
||||
if (!force && healthDataCache.health && (now - healthDataCache.ts) < HEALTH_CACHE_TTL_MS) {
|
||||
healthData = healthDataCache.health;
|
||||
suggestionsCache = healthDataCache.suggestions;
|
||||
healthHistoryCache = healthDataCache.history;
|
||||
renderHealthDashboard();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const [health, suggestions, history] = await Promise.all([
|
||||
API.get("/api/sources/health"),
|
||||
@@ -48,6 +61,7 @@ async function loadHealthData() {
|
||||
healthData = health;
|
||||
suggestionsCache = suggestions;
|
||||
healthHistoryCache = history || [];
|
||||
healthDataCache = { health, suggestions, history: history || [], ts: Date.now() };
|
||||
renderHealthDashboard();
|
||||
} catch (err) {
|
||||
console.error("Health-Daten laden fehlgeschlagen:", err);
|
||||
@@ -289,7 +303,7 @@ async function handleSuggestion(id, accept) {
|
||||
if (result.action) {
|
||||
showToast("Ergebnis: " + result.action, "success");
|
||||
}
|
||||
loadHealthData();
|
||||
loadHealthData(true);
|
||||
// Grundquellen-Liste auch aktualisieren
|
||||
if (typeof loadGlobalSources === "function") loadGlobalSources();
|
||||
} catch (err) {
|
||||
@@ -371,7 +385,7 @@ async function runHealthCheck() {
|
||||
}
|
||||
}
|
||||
|
||||
loadHealthData();
|
||||
loadHealthData(true);
|
||||
} catch (err) {
|
||||
progressEl.innerHTML = '<span class="text-danger">Fehler: ' + esc(err.message) + '</span>';
|
||||
} finally {
|
||||
@@ -419,7 +433,7 @@ async function searchFix(btn) {
|
||||
msg += `\n\nKosten: $${result.cost_usd.toFixed(2)}`;
|
||||
}
|
||||
showToast(msg, "info");
|
||||
loadHealthData();
|
||||
loadHealthData(true);
|
||||
} catch (err) {
|
||||
showToast("Fehler: " + err.message, "error");
|
||||
} finally {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren