site->settings(); $snapshot = $this->site->statisticsSnapshot(); $settingsUrl = admin_url('options-general.php?page='.SettingsPage::MENU_SLUG); $now = time(); require __DIR__.'/views/dashboard-widget.php'; } /** Ton für Punkt und Text: wie die Farben der Hinweise im Backend. */ public static function healthTone(string $health, bool $paused): string { if ($paused) { return 'muted'; } return match ($health) { 'healthy' => 'ok', 'warning' => 'warning', 'critical' => 'critical', default => 'muted', }; } public static function healthLabel(string $health, bool $paused): string { if ($paused) { return __('Paused', 'domainwarn'); } return match ($health) { 'healthy' => __('Healthy', 'domainwarn'), 'warning' => __('Warning', 'domainwarn'), 'critical' => __('Critical', 'domainwarn'), default => __('Unknown', 'domainwarn'), }; } /** Ton eines Ablauftermins: abgelaufen oder in einer Woche rot, im nächsten Monat gelb. */ public static function expiryTone(int $days): string { return match (true) { $days <= self::EXPIRY_CRITICAL_DAYS => 'critical', $days <= self::EXPIRY_WARNING_DAYS => 'warning', default => '', }; } /** * Erreichbarkeit als Prozent mit zwei Nachkommastellen in der Schreibweise der Website (99,98 / 99.98); volle * 100 ohne Nachkommastellen, damit „100,00“ nicht genauer aussieht, als es ist. */ public static function percent(float $ratio): string { $value = round($ratio * 100, 2); return number_format_i18n($value, $value === floor($value) ? 0 : 2); } /** * Die Antwortzeiten als Linie, Werte von links (vor sieben Tagen) nach rechts (jetzt). Eine Stunde ohne Messung * unterbricht die Linie, statt sie auf null fallen zu lassen. Die Höhe ist auf das Maximum skaliert – es geht * um den Verlauf, nicht um die Zahl, die steht daneben. * * @param list $series * @return list Punktfolgen für , je zusammenhängendem Abschnitt eine */ public static function sparkline(array $series, int $width, int $height): array { $values = array_values(array_filter($series, static fn ($value) => is_int($value))); if (count($values) < 2) { return []; } $max = max(1, max($values)); $step = count($series) > 1 ? $width / (count($series) - 1) : 0; $segments = []; $current = []; foreach ($series as $i => $value) { if (! is_int($value)) { if (count($current) > 1) { $segments[] = implode(' ', $current); } $current = []; continue; } // ein Pixel Rand oben und unten, damit die Linie nicht am Rahmen klebt $y = $height - 1 - ($value / $max) * ($height - 2); $current[] = round($i * $step, 1).','.round($y, 1); } if (count($current) > 1) { $segments[] = implode(' ', $current); } return $segments; } /** Farben aus der Palette des Backends: Admin-Blau, Grün, Gelb und Rot der Hinweise, Grau für alles Neutrale. */ private static function css(): string { return <<<'CSS' #domainwarn_status .domainwarn-domain { padding: 10px 0; border-top: 1px solid #f0f0f1; } #domainwarn_status .domainwarn-domain:first-of-type { border-top: 0; padding-top: 0; } #domainwarn_status .domainwarn-head { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; } #domainwarn_status .domainwarn-name { font-weight: 600; color: #1d2327; overflow-wrap: anywhere; } #domainwarn_status .domainwarn-health { margin-left: auto; color: #50575e; white-space: nowrap; } #domainwarn_status .domainwarn-dot { flex: none; width: 10px; height: 10px; border-radius: 50%; background: #8c8f94; } #domainwarn_status .domainwarn-dot.is-ok { background: #00a32a; } #domainwarn_status .domainwarn-dot.is-warning { background: #dba617; } #domainwarn_status .domainwarn-dot.is-critical { background: #d63638; } #domainwarn_status .domainwarn-facts { margin: 0; padding: 0; list-style: none; color: #1d2327; } #domainwarn_status .domainwarn-facts li { margin: 2px 0; } #domainwarn_status .domainwarn-facts .is-warning { color: #996800; } #domainwarn_status .domainwarn-facts .is-critical { color: #d63638; font-weight: 600; } #domainwarn_status .domainwarn-latency { display: flex; align-items: center; gap: 10px; margin: 6px 0; color: #50575e; } #domainwarn_status .domainwarn-sparkline { flex: 1 1 auto; min-width: 0; height: 32px; } #domainwarn_status .domainwarn-sparkline polyline { fill: none; stroke: #2271b1; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; } #domainwarn_status .domainwarn-asof { margin: 10px 0 0; color: #646970; } CSS; } }