[ 'label' => 'Dashboard', 'title' => 'Pi-hole Dashboard', 'description' => 'Status, Blockings, Usage und direkte Steuerung fuer alle angebundenen Instanzen.', 'nav_description' => 'Live-Status, Sperren und aggregierte DNS-Zahlen.', ], 'lists' => [ 'label' => 'Listen', 'title' => 'Listen & Domains', 'description' => 'Gravity-Updates, Top-Domains und neue Listen-/Domain-Eintraege.', 'nav_description' => 'Blocklisten, Whitelist und Adlist-Pflege.', ], 'queries' => [ 'label' => 'Queries', 'title' => 'Zugriffe & Blockings', 'description' => 'Aktuelle Blockings und Top-Clients ueber alle Instanzen.', 'nav_description' => 'Abfragen, blockierte Domains und Client-Nutzung.', ], 'instances' => [ 'label' => 'Instanzen', 'title' => 'Pi-hole Instanzen', 'description' => 'Hosts, Zugangsdaten und Primaer-Instanz administrieren.', 'nav_description' => 'Instanzen anlegen, testen, bearbeiten und loeschen.', ], 'setup' => [ 'label' => 'Setup', 'title' => 'Setup', 'description' => 'Timeouts, API-Pfad und globale Pi-hole-Moduloptionen verwalten.', 'nav_description' => 'Standard-Timeouts, TLS und Refresh-Regeln.', ], ]; $assetVersion = static function (string $relativePath): string { $fullPath = dirname(__DIR__) . '/' . ltrim($relativePath, '/'); $mtime = is_file($fullPath) ? filemtime($fullPath) : false; return $mtime === false ? '0' : (string) $mtime; }; $renderSetup = static function (): void { $moduleName = 'pihole'; $manifestPath = dirname(__DIR__) . '/module.json'; $manifestRaw = is_file($manifestPath) ? file_get_contents($manifestPath) : false; $manifest = is_string($manifestRaw) && trim($manifestRaw) !== '' ? json_decode($manifestRaw, true) : []; $fields = is_array($manifest['setup']['fields'] ?? null) ? $manifest['setup']['fields'] : []; $settings = modules()->settings($moduleName); $notice = null; $error = null; $getValue = static function (array $source, string $path): mixed { $value = $source; foreach (explode('.', $path) as $segment) { if (!is_array($value) || !array_key_exists($segment, $value)) { return null; } $value = $value[$segment]; } return $value; }; $setValue = static function (array &$target, string $path, mixed $value): void { $segments = explode('.', $path); $cursor = &$target; foreach ($segments as $index => $segment) { if ($index === count($segments) - 1) { $cursor[$segment] = $value; return; } if (!isset($cursor[$segment]) || !is_array($cursor[$segment])) { $cursor[$segment] = []; } $cursor = &$cursor[$segment]; } }; if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string) ($_POST['action'] ?? '') === 'save_setup') { try { $nextSettings = $settings; foreach ($fields as $field) { if (!is_array($field)) { continue; } $name = trim((string) ($field['name'] ?? '')); $type = trim((string) ($field['type'] ?? 'text')); if ($name === '') { continue; } $raw = $_POST['settings'][$name] ?? null; $value = match ($type) { 'checkbox' => $raw !== null, 'number' => ($raw === null || $raw === '') ? null : (is_numeric((string) $raw) ? 0 + $raw : null), default => is_string($raw) ? trim($raw) : '', }; $setValue($nextSettings, $name, $value); } modules()->saveSettings($moduleName, $nextSettings); $settings = modules()->settings($moduleName); $notice = 'Setup gespeichert.'; } catch (\Throwable $e) { $error = $e->getMessage(); } } ?>

Modul-Setup

Bestehende Nexus-Einstellungen werden uebernommen. Aenderungen werden lokal als Override gespeichert.

'/apps/pihole/index.php?view=dashboard', 'lists' => '/apps/pihole/index.php?view=lists', 'queries' => '/apps/pihole/index.php?view=queries', 'instances' => '/apps/pihole/index.php?view=instances', 'setup' => '/apps/pihole/index.php?view=setup', ]; ob_start(); if ($view === 'setup') { $renderSetup(); } else { require dirname(__DIR__) . '/partials/' . $view . '.php'; } $innerContent = (string) ob_get_clean(); ?>

Pi-hole

Desktop-App Netzwerk-Tools View:
Pi-hole