diff --git a/modules/pihole/assets/pihole.js b/modules/pihole/assets/pihole.js index 81e863f..ce2bd81 100644 --- a/modules/pihole/assets/pihole.js +++ b/modules/pihole/assets/pihole.js @@ -2,6 +2,13 @@ const page = document.querySelector('[data-pihole-page]'); if (!page) return; + const pageType = page.dataset.piholePage || 'dashboard'; + const configuredRefreshSeconds = Number(page.dataset.refreshSeconds || 0); + const defaultRefreshSeconds = pageType === 'dashboard' ? 1 : 5; + const refreshSeconds = Number.isFinite(configuredRefreshSeconds) && configuredRefreshSeconds >= 0 + ? configuredRefreshSeconds + : defaultRefreshSeconds; + const fmt = new Intl.NumberFormat('de-DE'); const fmtDate = (ts) => { if (!ts) return '–'; @@ -11,7 +18,6 @@ let refreshTimer = null; let loadInFlight = false; - let loadErrorShown = false; const apiCall = async (action, payload = {}) => { const res = await fetch(`/module/pihole/api?action=${encodeURIComponent(action)}`, @@ -265,7 +271,6 @@ 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); - loadErrorShown = false; const existing = page.querySelector('[data-pihole-load-error]'); if (existing) existing.remove(); } catch (err) { @@ -278,19 +283,37 @@ page.appendChild(message); } message.textContent = `Fehler beim Laden der Pi-hole Daten: ${err.message}`; - loadErrorShown = true; } finally { loadInFlight = false; } }; + const stopAutoRefresh = () => { + if (refreshTimer !== null) { + window.clearInterval(refreshTimer); + refreshTimer = null; + } + }; + + const startAutoRefresh = () => { + stopAutoRefresh(); + if (refreshSeconds <= 0 || document.visibilityState !== 'visible') { + return; + } + refreshTimer = window.setInterval(loadDashboard, refreshSeconds * 1000); + }; + bindActionButtons(); bindForms(); loadDashboard(); - refreshTimer = window.setInterval(loadDashboard, 1000); - window.addEventListener('beforeunload', () => { - if (refreshTimer !== null) { - window.clearInterval(refreshTimer); + startAutoRefresh(); + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + loadDashboard(); + startAutoRefresh(); + return; } + stopAutoRefresh(); }); + window.addEventListener('beforeunload', stopAutoRefresh); })(); diff --git a/modules/pihole/module.json b/modules/pihole/module.json index 2b9e437..6d5409b 100644 --- a/modules/pihole/module.json +++ b/modules/pihole/module.json @@ -2,5 +2,29 @@ "title": "Pi-hole", "version": "0.1.0", "description": "Pi-hole Monitoring, Listen und Steuerung fuer mehrere Instanzen.", - "setup": { "fields": [] } + "setup": { + "fields": [ + { + "name": "dashboard_refresh_sec", + "label": "Refresh Dashboard (Sekunden)", + "type": "number", + "help": "Automatische Aktualisierung fuer das Dashboard. Standard: 1 Sekunde. 0 deaktiviert den Auto-Refresh.", + "required": false + }, + { + "name": "lists_refresh_sec", + "label": "Refresh Listen (Sekunden)", + "type": "number", + "help": "Automatische Aktualisierung fuer die Listen-Seite. Standard: 5 Sekunden. 0 deaktiviert den Auto-Refresh.", + "required": false + }, + { + "name": "queries_refresh_sec", + "label": "Refresh Queries (Sekunden)", + "type": "number", + "help": "Automatische Aktualisierung fuer die Queries-Seite. Standard: 5 Sekunden. 0 deaktiviert den Auto-Refresh.", + "required": false + } + ] + } } diff --git a/modules/pihole/pages/api.php b/modules/pihole/pages/api.php index 261b71a..4aa6d03 100644 --- a/modules/pihole/pages/api.php +++ b/modules/pihole/pages/api.php @@ -209,10 +209,18 @@ $detectApi = function (array $instance) use ($v6Auth, $v6RequestAny, $v5Request) $authRes = $v6Auth($instance); if (($authRes['ok'] ?? false) && !empty($authRes['sid'])) { $sid = (string)$authRes['sid']; + + $probe = $v6RequestAny($instance, ['dns/blocking', 'stats/summary', 'summary'], 'GET', [], $sid); + return ['version' => 6, 'sid' => $sid, 'probe' => $probe, 'auth' => $authRes]; + } + + $httpCode = (int)($authRes['http_code'] ?? 0); + if (in_array($httpCode, [401, 403], true)) { + return ['version' => 6, 'sid' => '', 'probe' => $authRes, 'auth' => $authRes]; } } - $probe = $v6RequestAny($instance, ['stats/summary', 'summary'], 'GET', [], $sid); + $probe = $v6RequestAny($instance, ['dns/blocking', 'stats/summary', 'summary'], 'GET', [], $sid); if ($probe['ok'] || in_array((int)($probe['http_code'] ?? 0), [401, 403], true)) { return ['version' => 6, 'sid' => $sid, 'probe' => $probe, 'auth' => $authRes]; } @@ -222,7 +230,7 @@ $detectApi = function (array $instance) use ($v6Auth, $v6RequestAny, $v5Request) return ['version' => 5, 'sid' => '', 'probe' => $legacy]; } - return ['version' => 0, 'sid' => '', 'probe' => $probe, 'legacy' => $legacy]; + return ['version' => 0, 'sid' => '', 'probe' => $probe, 'legacy' => $legacy, 'auth' => $authRes]; }; $debugResult = static function (string $label, string $instanceId, array $instance, array $result) use ($debugPush): void { diff --git a/modules/pihole/pages/index.php b/modules/pihole/pages/index.php index c1084b7..8e6b130 100644 --- a/modules/pihole/pages/index.php +++ b/modules/pihole/pages/index.php @@ -3,14 +3,19 @@ $assets = app()->assets(); $assets->addStyle('/module/pihole/asset?file=pihole.css'); $assets->addScript('/module/pihole/asset?file=pihole.js', 'footer', true); +$settings = modules()->settings('pihole'); $instances = module_fn('pihole', 'instances'); $hasConfig = !empty($instances); +$refreshSeconds = (int)($settings['dashboard_refresh_sec'] ?? 1); +if ($refreshSeconds < 0) { + $refreshSeconds = 1; +} ?> = module_shell_header('pihole', [ 'title' => 'Pi-hole Dashboard', 'description' => 'Status, Blockings, Usage und Steuerung fuer beide Instanzen.', ]) ?> -