diff options
Diffstat (limited to 'library/Icingadb/Web/Navigation')
7 files changed, 462 insertions, 0 deletions
diff --git a/library/Icingadb/Web/Navigation/Action.php b/library/Icingadb/Web/Navigation/Action.php new file mode 100644 index 0000000..d02f933 --- /dev/null +++ b/library/Icingadb/Web/Navigation/Action.php @@ -0,0 +1,134 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation; + +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Common\Macros; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Web\Navigation\NavigationItem; +use ipl\Web\Url; + +class Action extends NavigationItem +{ + use Auth; + use Macros; + + /** + * Whether this action's macros were already resolved + * + * @var bool + */ + protected $resolved = false; + + /** + * This action's object + * + * @var Host|Service + */ + protected $object; + + /** + * The filter to use when being asked whether to render this action + * + * @var string + */ + protected $filter; + + /** + * This action's raw url attribute + * + * @var string + */ + protected $rawUrl; + + /** + * Set this action's object + * + * @param Host|Service $object + * + * @return $this + */ + public function setObject($object): self + { + $this->object = $object; + + return $this; + } + + /** + * Get this action's object + * + * @return Host|Service + */ + protected function getObject() + { + return $this->object; + } + + /** + * Set the filter to use when being asked whether to render this action + * + * @param string $filter + * + * @return $this + */ + public function setFilter(string $filter): self + { + $this->filter = $filter; + + return $this; + } + + /** + * Get the filter to use when being asked whether to render this action + * + * @return ?string + */ + public function getFilter(): ?string + { + return $this->filter; + } + + /** + * Set this item's url + * + * @param \Icinga\Web\Url|string $url + * + * @return $this + */ + public function setUrl($url): self + { + if (is_string($url)) { + $this->rawUrl = $url; + } else { + parent::setUrl($url); + } + + return $this; + } + + public function getUrl(): ?\Icinga\Web\Url + { + $url = parent::getUrl(); + if (! $this->resolved && $url === null && $this->rawUrl !== null) { + $this->setUrl(Url::fromPath($this->expandMacros($this->rawUrl, $this->getObject()))); + $this->resolved = true; + return parent::getUrl(); + } else { + return $url; + } + } + + public function getRender(): bool + { + if ($this->render === null) { + $filter = $this->getFilter(); + $this->render = ! $filter || $this->isMatchedOn($filter, $this->getObject()); + } + + return $this->render; + } +} diff --git a/library/Icingadb/Web/Navigation/IcingadbHostAction.php b/library/Icingadb/Web/Navigation/IcingadbHostAction.php new file mode 100644 index 0000000..a5fc256 --- /dev/null +++ b/library/Icingadb/Web/Navigation/IcingadbHostAction.php @@ -0,0 +1,9 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation; + +class IcingadbHostAction extends Action +{ +} diff --git a/library/Icingadb/Web/Navigation/IcingadbServiceAction.php b/library/Icingadb/Web/Navigation/IcingadbServiceAction.php new file mode 100644 index 0000000..d623951 --- /dev/null +++ b/library/Icingadb/Web/Navigation/IcingadbServiceAction.php @@ -0,0 +1,9 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation; + +class IcingadbServiceAction extends Action +{ +} diff --git a/library/Icingadb/Web/Navigation/Renderer/HostProblemsBadge.php b/library/Icingadb/Web/Navigation/Renderer/HostProblemsBadge.php new file mode 100644 index 0000000..fc64c7d --- /dev/null +++ b/library/Icingadb/Web/Navigation/Renderer/HostProblemsBadge.php @@ -0,0 +1,35 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation\Renderer; + +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Common\Links; +use Icinga\Module\Icingadb\Model\HoststateSummary; +use ipl\Web\Url; + +class HostProblemsBadge extends ProblemsBadge +{ + use Auth; + + protected function fetchProblemsCount() + { + $summary = HoststateSummary::on($this->getDb()); + $this->applyRestrictions($summary); + $count = (int) $summary->first()->hosts_down_unhandled; + if ($count) { + $this->setTitle(sprintf( + tp('One unhandled host down', '%d unhandled hosts down', $count), + $count + )); + } + + return $count; + } + + protected function getUrl(): Url + { + return Links::hosts()->setParams(['host.state.is_problem' => 'y', 'sort' => 'host.state.severity desc']); + } +} diff --git a/library/Icingadb/Web/Navigation/Renderer/ProblemsBadge.php b/library/Icingadb/Web/Navigation/Renderer/ProblemsBadge.php new file mode 100644 index 0000000..bebc6be --- /dev/null +++ b/library/Icingadb/Web/Navigation/Renderer/ProblemsBadge.php @@ -0,0 +1,173 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation\Renderer; + +use Exception; +use Icinga\Application\Logger; +use Icinga\Module\Icingadb\Common\Database; +use Icinga\Module\Icingadb\Widget\StateBadge; +use Icinga\Web\Navigation\NavigationItem; +use Icinga\Web\Navigation\Renderer\NavigationItemRenderer; +use ipl\Html\HtmlDocument; +use ipl\Html\HtmlString; +use ipl\Web\Widget\Link; + +abstract class ProblemsBadge extends NavigationItemRenderer +{ + use Database; + + const STATE_CRITICAL = 'critical'; + const STATE_UNKNOWN = 'unknown'; + + /** @var int Count cache */ + protected $count; + + /** @var string State text */ + protected $state; + + /** @var string Title */ + protected $title; + + protected $linkDisabled; + + abstract protected function fetchProblemsCount(); + + abstract protected function getUrl(); + + public function getProblemsCount() + { + if ($this->count === null) { + try { + $count = $this->fetchProblemsCount(); + } catch (Exception $e) { + Logger::debug($e); + + $this->count = 1; + + $this->setState(static::STATE_UNKNOWN); + $this->setTitle($e->getMessage()); + + return $this->count; + } + + $this->count = $this->round($count); + + $this->setState(static::STATE_CRITICAL); + } + + return $this->count; + } + + /** + * Set the state text + * + * @param string $state + * + * @return $this + */ + public function setState(string $state): self + { + $this->state = $state; + + return $this; + } + + /** + * Get the state text + * + * @return string + */ + public function getState(): string + { + if ($this->state === null) { + throw new \LogicException( + 'You are accessing an unset property. Please make sure to set it beforehand.' + ); + } + + return $this->state; + } + + /** + * Set the title + * + * @param string $title + * + * @return $this + */ + public function setTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + /** + * Get the title + * + * @return ?string + */ + public function getTitle() + { + return $this->title; + } + + public function render(NavigationItem $item = null): string + { + if ($item === null) { + $item = $this->getItem(); + } + + $item->setCssClass('badge-nav-item icinga-module module-icingadb'); + + $html = new HtmlDocument(); + + $badge = $this->createBadge(); + if ($badge !== null) { + if ($this->linkDisabled) { + $badge->addAttributes(['class' => 'disabled']); + $this->setEscapeLabel(false); + $label = $this->view()->escape($item->getLabel()); + $item->setLabel($badge . $label); + } else { + $html->add(new Link($badge, $this->getUrl(), ['title' => $this->getTitle()])); + } + } + + return $html + ->prepend(new HtmlString(parent::render($item))) + ->render(); + } + + protected function createBadge() + { + $count = $this->getProblemsCount(); + + if ($count) { + return (new StateBadge($count, $this->getState())) + ->addAttributes(['class' => 'badge', 'title' => $this->getTitle()]); + } + + return null; + } + + protected function round($count) + { + if ($count > 1000000) { + $count = round($count, -6) / 1000000 . 'M'; + } elseif ($count > 1000) { + $count = round($count, -3) / 1000 . 'k'; + } + + return $count; + } + + public function disableLink() + { + $this->linkDisabled = true; + + return $this; + } +} diff --git a/library/Icingadb/Web/Navigation/Renderer/ServiceProblemsBadge.php b/library/Icingadb/Web/Navigation/Renderer/ServiceProblemsBadge.php new file mode 100644 index 0000000..b2f2cae --- /dev/null +++ b/library/Icingadb/Web/Navigation/Renderer/ServiceProblemsBadge.php @@ -0,0 +1,36 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation\Renderer; + +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Common\Links; +use Icinga\Module\Icingadb\Model\ServicestateSummary; +use ipl\Web\Url; + +class ServiceProblemsBadge extends ProblemsBadge +{ + use Auth; + + protected function fetchProblemsCount() + { + $summary = ServicestateSummary::on($this->getDb()); + $this->applyRestrictions($summary); + $count = (int) $summary->first()->services_critical_unhandled; + if ($count) { + $this->setTitle(sprintf( + tp('One unhandled service critical', '%d unhandled services critical', $count), + $count + )); + } + + return $count; + } + + protected function getUrl(): Url + { + return Links::services() + ->setParams(['service.state.is_problem' => 'y', 'sort' => 'service.state.severity desc']); + } +} diff --git a/library/Icingadb/Web/Navigation/Renderer/TotalProblemsBadge.php b/library/Icingadb/Web/Navigation/Renderer/TotalProblemsBadge.php new file mode 100644 index 0000000..703db65 --- /dev/null +++ b/library/Icingadb/Web/Navigation/Renderer/TotalProblemsBadge.php @@ -0,0 +1,66 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Web\Navigation\Renderer; + +use Icinga\Web\Navigation\Renderer\BadgeNavigationItemRenderer; + +class TotalProblemsBadge extends BadgeNavigationItemRenderer +{ + /** + * Cached count + * + * @var int + */ + protected $count; + + /** + * State to severity map + * + * @var array + */ + protected static $stateSeverityMap = [ + self::STATE_OK => 0, + self::STATE_PENDING => 1, + self::STATE_UNKNOWN => 2, + self::STATE_WARNING => 3, + self::STATE_CRITICAL => 4, + ]; + + /** + * Severity to state map + * + * @var array + */ + protected static $severityStateMap = [ + self::STATE_OK, + self::STATE_PENDING, + self::STATE_UNKNOWN, + self::STATE_WARNING, + self::STATE_CRITICAL + ]; + + public function getCount() + { + if ($this->count === null) { + $countMap = array_fill(0, 5, 0); + $maxSeverity = 0; + foreach ($this->getItem()->getChildren() as $child) { + $renderer = $child->getRenderer(); + if ($renderer instanceof ProblemsBadge) { + $count = $renderer->getProblemsCount(); + if ($count) { + $severity = static::$stateSeverityMap[$renderer->getState()]; + $countMap[$severity] += $count; + $maxSeverity = max($maxSeverity, $severity); + } + } + } + $this->count = $countMap[$maxSeverity]; + $this->state = static::$severityStateMap[$maxSeverity]; + } + + return $this->count; + } +} |