adsd
This commit is contained in:
@@ -205,6 +205,79 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderDashboardData = (data) => {
|
||||||
|
const summary = data.aggregate?.summary || {};
|
||||||
|
setText(document.querySelector('[data-summary-dns]'), fmt.format(Number(summary.dns_queries_today || 0)));
|
||||||
|
setText(document.querySelector('[data-summary-blocked]'), fmt.format(Number(summary.ads_blocked_today || 0)));
|
||||||
|
setText(document.querySelector('[data-summary-percent]'), `${Number(summary.ads_percentage_today || 0).toFixed(2)}%`);
|
||||||
|
setText(document.querySelector('[data-summary-clients]'), fmt.format(Number(summary.unique_clients || 0)));
|
||||||
|
setStatusBadge(document.querySelector('[data-summary-status]'), summary.status || 'unknown');
|
||||||
|
setText(document.querySelector('[data-summary-last-refresh]'), `Letztes Update: ${fmtDate(data.ts)}`);
|
||||||
|
|
||||||
|
renderInstances(data.instances || {});
|
||||||
|
renderList(document.querySelector('[data-query-types]'), data.aggregate?.query_types, 'Keine Daten');
|
||||||
|
renderList(document.querySelector('[data-forward-destinations]'), data.aggregate?.forward_destinations, 'Keine Daten');
|
||||||
|
renderList(document.querySelector('[data-top-ads]'), data.aggregate?.top_ads, 'Keine Daten');
|
||||||
|
renderList(document.querySelector('[data-top-queries]'), data.aggregate?.top_queries, 'Keine Daten');
|
||||||
|
renderList(document.querySelector('[data-top-clients]'), data.aggregate?.query_sources, 'Keine Daten');
|
||||||
|
renderBlocked(document.querySelector('[data-recent-blocked]'), data.aggregate?.recent_blocked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dashboardFingerprint = (data) => {
|
||||||
|
const aggregate = data?.aggregate?.summary || {};
|
||||||
|
const instanceSummary = Object.values(data?.instances || {}).map((entry) => ({
|
||||||
|
id: entry?.meta?.id || '',
|
||||||
|
blocked_domains: Number(entry?.summary?.blocked_domains || 0),
|
||||||
|
ads_blocked_today: Number(entry?.summary?.ads_blocked_today || 0),
|
||||||
|
unique_domains: Number(entry?.summary?.unique_domains || 0),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return JSON.stringify({
|
||||||
|
blocked_domains: Number(aggregate.blocked_domains || 0),
|
||||||
|
ads_blocked_today: Number(aggregate.ads_blocked_today || 0),
|
||||||
|
unique_domains: Number(aggregate.unique_domains || 0),
|
||||||
|
instances: instanceSummary,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const delay = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
const monitorGravityProgress = async (baselineData, instanceLabel) => {
|
||||||
|
const baselineFingerprint = dashboardFingerprint(baselineData || {});
|
||||||
|
const maxPolls = 24;
|
||||||
|
const pollDelayMs = 5000;
|
||||||
|
|
||||||
|
appendActionLog(`Pi-hole meldet keinen Live-Fortschritt. Pruefe jetzt zyklisch auf erkennbare Aenderungen fuer ${instanceLabel}.`, 'info');
|
||||||
|
|
||||||
|
for (let attempt = 1; attempt <= maxPolls; attempt += 1) {
|
||||||
|
await delay(pollDelayMs);
|
||||||
|
appendActionLog(`Pruefung ${attempt}/${maxPolls}: aktuelle Statusdaten werden geladen ...`, 'info');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await apiCall('dashboard');
|
||||||
|
if (!data.ok) {
|
||||||
|
throw new Error(data.error || 'API error');
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDashboardData(data);
|
||||||
|
const nextFingerprint = dashboardFingerprint(data);
|
||||||
|
if (nextFingerprint !== baselineFingerprint) {
|
||||||
|
appendActionLog(`Erkennbare Aenderung gefunden. Listen-Update fuer ${instanceLabel} scheint abgeschlossen zu sein.`, 'success');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt % 3 === 0) {
|
||||||
|
appendActionLog('Noch keine erkennbare Aenderung in den Pi-hole Statusdaten.', 'info');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
appendActionLog(`Statuspruefung fehlgeschlagen: ${err.message}`, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendActionLog(`Innerhalb des Beobachtungsfensters wurde keine erkennbare Aenderung gefunden. Das Update fuer ${instanceLabel} kann trotzdem weiterlaufen oder bereits ohne sichtbare Statistikaenderung beendet worden sein.`, 'error');
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const renderInstances = (instances) => {
|
const renderInstances = (instances) => {
|
||||||
const holder = document.querySelector('[data-instance-cards]');
|
const holder = document.querySelector('[data-instance-cards]');
|
||||||
const tpl = document.querySelector('#pihole-instance-template');
|
const tpl = document.querySelector('#pihole-instance-template');
|
||||||
@@ -275,6 +348,7 @@
|
|||||||
const scope = btn.closest('.pihole-instance') || document;
|
const scope = btn.closest('.pihole-instance') || document;
|
||||||
const customInput = scope.querySelector(`[data-custom-minutes="${instance}"]`);
|
const customInput = scope.querySelector(`[data-custom-minutes="${instance}"]`);
|
||||||
let payload = { instance };
|
let payload = { instance };
|
||||||
|
let baselineData = null;
|
||||||
|
|
||||||
if (action === 'disable') {
|
if (action === 'disable') {
|
||||||
payload.minutes = Number(minutes || 0);
|
payload.minutes = Number(minutes || 0);
|
||||||
@@ -299,6 +373,8 @@
|
|||||||
appendActionLog(actionLabel, 'info');
|
appendActionLog(actionLabel, 'info');
|
||||||
setActionLock(true, actionLabel);
|
setActionLock(true, actionLabel);
|
||||||
|
|
||||||
|
baselineData = action === 'gravity' ? await apiCall('dashboard').catch(() => null) : null;
|
||||||
|
|
||||||
if (action === 'enable') {
|
if (action === 'enable') {
|
||||||
appendActionLog(`Aktiviere ${instance === 'all' ? 'alle Instanzen' : `Instanz ${instance}`}.`, 'info');
|
appendActionLog(`Aktiviere ${instance === 'all' ? 'alle Instanzen' : `Instanz ${instance}`}.`, 'info');
|
||||||
await apiCall('enable', payload);
|
await apiCall('enable', payload);
|
||||||
@@ -319,10 +395,18 @@
|
|||||||
await apiCall('update', payload);
|
await apiCall('update', payload);
|
||||||
}
|
}
|
||||||
appendActionLog('Aktion abgeschlossen. Dashboard wird aktualisiert.', 'success');
|
appendActionLog('Aktion abgeschlossen. Dashboard wird aktualisiert.', 'success');
|
||||||
await loadDashboard();
|
if (action === 'gravity') {
|
||||||
appendActionLog('Anzeige erfolgreich aktualisiert.', 'success');
|
await monitorGravityProgress(baselineData, instance === 'all' ? 'alle Instanzen' : `Instanz ${instance}`);
|
||||||
|
} else {
|
||||||
|
await loadDashboard();
|
||||||
|
appendActionLog('Anzeige erfolgreich aktualisiert.', 'success');
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
appendActionLog(`Aktion fehlgeschlagen: ${err.message}`, 'error');
|
appendActionLog(`Aktion fehlgeschlagen: ${err.message}`, 'error');
|
||||||
|
if (action === 'gravity' && /timed out/i.test(err.message)) {
|
||||||
|
appendActionLog('Der Request ist in Nexus abgelaufen. Pi-hole kann intern trotzdem weiterarbeiten. Starte weiterfuehrende Statuspruefung.', 'info');
|
||||||
|
await monitorGravityProgress(baselineData, instance === 'all' ? 'alle Instanzen' : `Instanz ${instance}`);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setActionLock(false);
|
setActionLock(false);
|
||||||
}
|
}
|
||||||
@@ -374,22 +458,7 @@
|
|||||||
try {
|
try {
|
||||||
const data = await apiCall('dashboard');
|
const data = await apiCall('dashboard');
|
||||||
if (!data.ok) throw new Error(data.error || 'API error');
|
if (!data.ok) throw new Error(data.error || 'API error');
|
||||||
|
renderDashboardData(data);
|
||||||
const summary = data.aggregate?.summary || {};
|
|
||||||
setText(document.querySelector('[data-summary-dns]'), fmt.format(Number(summary.dns_queries_today || 0)));
|
|
||||||
setText(document.querySelector('[data-summary-blocked]'), fmt.format(Number(summary.ads_blocked_today || 0)));
|
|
||||||
setText(document.querySelector('[data-summary-percent]'), `${Number(summary.ads_percentage_today || 0).toFixed(2)}%`);
|
|
||||||
setText(document.querySelector('[data-summary-clients]'), fmt.format(Number(summary.unique_clients || 0)));
|
|
||||||
setStatusBadge(document.querySelector('[data-summary-status]'), summary.status || 'unknown');
|
|
||||||
setText(document.querySelector('[data-summary-last-refresh]'), `Letztes Update: ${fmtDate(data.ts)}`);
|
|
||||||
|
|
||||||
renderInstances(data.instances || {});
|
|
||||||
renderList(document.querySelector('[data-query-types]'), data.aggregate?.query_types, 'Keine Daten');
|
|
||||||
renderList(document.querySelector('[data-forward-destinations]'), data.aggregate?.forward_destinations, 'Keine Daten');
|
|
||||||
renderList(document.querySelector('[data-top-ads]'), data.aggregate?.top_ads, 'Keine Daten');
|
|
||||||
renderList(document.querySelector('[data-top-queries]'), data.aggregate?.top_queries, 'Keine Daten');
|
|
||||||
renderList(document.querySelector('[data-top-clients]'), data.aggregate?.query_sources, 'Keine Daten');
|
|
||||||
renderBlocked(document.querySelector('[data-recent-blocked]'), data.aggregate?.recent_blocked);
|
|
||||||
const existing = page.querySelector('[data-pihole-load-error]');
|
const existing = page.querySelector('[data-pihole-load-error]');
|
||||||
if (existing) existing.remove();
|
if (existing) existing.remove();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ if ($action === 'dashboard') {
|
|||||||
'ads_blocked_today' => 0,
|
'ads_blocked_today' => 0,
|
||||||
'unique_clients' => 0,
|
'unique_clients' => 0,
|
||||||
'unique_domains' => 0,
|
'unique_domains' => 0,
|
||||||
|
'blocked_domains' => 0,
|
||||||
'queries_forwarded' => 0,
|
'queries_forwarded' => 0,
|
||||||
'queries_cached' => 0,
|
'queries_cached' => 0,
|
||||||
'status' => 'unknown',
|
'status' => 'unknown',
|
||||||
@@ -611,6 +612,13 @@ if ($action === 'dashboard') {
|
|||||||
'ads_blocked_today' => (int)($queriesBlock['blocked'] ?? 0),
|
'ads_blocked_today' => (int)($queriesBlock['blocked'] ?? 0),
|
||||||
'unique_clients' => (int)($clientsBlock['active'] ?? $clientsBlock['total'] ?? 0),
|
'unique_clients' => (int)($clientsBlock['active'] ?? $clientsBlock['total'] ?? 0),
|
||||||
'unique_domains' => (int)($queriesBlock['unique_domains'] ?? 0),
|
'unique_domains' => (int)($queriesBlock['unique_domains'] ?? 0),
|
||||||
|
'blocked_domains' => (int)(
|
||||||
|
$sum['domains_being_blocked']
|
||||||
|
?? $sum['gravity']['domains_being_blocked']
|
||||||
|
?? $sum['gravity']['domains']
|
||||||
|
?? $sum['gravity']['blocked']
|
||||||
|
?? 0
|
||||||
|
),
|
||||||
'queries_forwarded' => (int)($queriesBlock['forwarded'] ?? 0),
|
'queries_forwarded' => (int)($queriesBlock['forwarded'] ?? 0),
|
||||||
'queries_cached' => (int)($queriesBlock['cached'] ?? 0),
|
'queries_cached' => (int)($queriesBlock['cached'] ?? 0),
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
@@ -768,6 +776,7 @@ if ($action === 'dashboard') {
|
|||||||
$aggregate['summary']['ads_blocked_today'] += (int)($summaryData['ads_blocked_today'] ?? 0);
|
$aggregate['summary']['ads_blocked_today'] += (int)($summaryData['ads_blocked_today'] ?? 0);
|
||||||
$aggregate['summary']['unique_clients'] += (int)($summaryData['unique_clients'] ?? 0);
|
$aggregate['summary']['unique_clients'] += (int)($summaryData['unique_clients'] ?? 0);
|
||||||
$aggregate['summary']['unique_domains'] += (int)($summaryData['unique_domains'] ?? 0);
|
$aggregate['summary']['unique_domains'] += (int)($summaryData['unique_domains'] ?? 0);
|
||||||
|
$aggregate['summary']['blocked_domains'] += (int)($summaryData['blocked_domains'] ?? 0);
|
||||||
$aggregate['summary']['queries_forwarded'] += (int)($summaryData['queries_forwarded'] ?? 0);
|
$aggregate['summary']['queries_forwarded'] += (int)($summaryData['queries_forwarded'] ?? 0);
|
||||||
$aggregate['summary']['queries_cached'] += (int)($summaryData['queries_cached'] ?? 0);
|
$aggregate['summary']['queries_cached'] += (int)($summaryData['queries_cached'] ?? 0);
|
||||||
$status = (string)($summaryData['status'] ?? 'unknown');
|
$status = (string)($summaryData['status'] ?? 'unknown');
|
||||||
|
|||||||
Reference in New Issue
Block a user