summaryrefslogtreecommitdiffstats
path: root/library/Icingadb/Web/Navigation
diff options
context:
space:
mode:
Diffstat (limited to 'library/Icingadb/Web/Navigation')
-rw-r--r--library/Icingadb/Web/Navigation/Action.php134
-rw-r--r--library/Icingadb/Web/Navigation/IcingadbHostAction.php9
-rw-r--r--library/Icingadb/Web/Navigation/IcingadbServiceAction.php9
-rw-r--r--library/Icingadb/Web/Navigation/Renderer/HostProblemsBadge.php35
-rw-r--r--library/Icingadb/Web/Navigation/Renderer/ProblemsBadge.php173
-rw-r--r--library/Icingadb/Web/Navigation/Renderer/ServiceProblemsBadge.php36
-rw-r--r--library/Icingadb/Web/Navigation/Renderer/TotalProblemsBadge.php66
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;
+ }
+}