summaryrefslogtreecommitdiffstats
path: root/modules/monitoring/library/Monitoring/Web/Widget
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:46:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:46:43 +0000
commit3e02d5aff85babc3ffbfcf52313f2108e313aa23 (patch)
treeb01f3923360c20a6a504aff42d45670c58af3ec5 /modules/monitoring/library/Monitoring/Web/Widget
parentInitial commit. (diff)
downloadicingaweb2-3e02d5aff85babc3ffbfcf52313f2108e313aa23.tar.xz
icingaweb2-3e02d5aff85babc3ffbfcf52313f2108e313aa23.zip
Adding upstream version 2.12.1.upstream/2.12.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/monitoring/library/Monitoring/Web/Widget')
-rw-r--r--modules/monitoring/library/Monitoring/Web/Widget/CustomVarTable.php272
-rw-r--r--modules/monitoring/library/Monitoring/Web/Widget/SelectBox.php120
-rw-r--r--modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php341
3 files changed, 733 insertions, 0 deletions
diff --git a/modules/monitoring/library/Monitoring/Web/Widget/CustomVarTable.php b/modules/monitoring/library/Monitoring/Web/Widget/CustomVarTable.php
new file mode 100644
index 0000000..b4273b5
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Web/Widget/CustomVarTable.php
@@ -0,0 +1,272 @@
+<?php
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Web\Widget;
+
+use Icinga\Module\Monitoring\Hook\CustomVarRendererHook;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use ipl\Html\Attributes;
+use ipl\Html\BaseHtmlElement;
+use ipl\Html\Html;
+use ipl\Html\HtmlDocument;
+use ipl\Html\HtmlElement;
+use ipl\Html\Text;
+use ipl\Web\Widget\Icon;
+use Closure;
+
+class CustomVarTable extends BaseHtmlElement
+{
+ /** @var iterable The variables */
+ protected $data;
+
+ /** @var ?MonitoredObject The object the variables are bound to */
+ protected $object;
+
+ /** @var Closure Callback to apply hooks */
+ protected $hookApplier;
+
+ /** @var array The groups as identified by hooks */
+ protected $groups = [];
+
+ /** @var string Header title */
+ protected $headerTitle;
+
+ /** @var int The nesting level */
+ protected $level = 0;
+
+ protected $tag = 'table';
+
+ /** @var HtmlElement The table body */
+ protected $body;
+
+ protected $defaultAttributes = [
+ 'class' => ['custom-var-table', 'name-value-table']
+ ];
+
+ /**
+ * Create a new CustomVarTable
+ *
+ * @param iterable $data
+ * @param ?MonitoredObject $object
+ */
+ public function __construct($data, MonitoredObject $object = null)
+ {
+ $this->data = $data;
+ $this->object = $object;
+ $this->body = new HtmlElement('tbody');
+ }
+
+ /**
+ * Set the header to show
+ *
+ * @param string $title
+ *
+ * @return $this
+ */
+ protected function setHeader($title)
+ {
+ $this->headerTitle = (string) $title;
+
+ return $this;
+ }
+
+ /**
+ * Add a new row to the body
+ *
+ * @param mixed $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ protected function addRow($name, $value)
+ {
+ $this->body->addHtml(new HtmlElement(
+ 'tr',
+ Attributes::create(['class' => "level-{$this->level}"]),
+ new HtmlElement('th', null, Html::wantHtml($name)),
+ new HtmlElement('td', null, Html::wantHtml($value))
+ ));
+ }
+
+ /**
+ * Render a variable
+ *
+ * @param mixed $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ protected function renderVar($name, $value)
+ {
+ if ($this->object !== null && $this->level === 0) {
+ list($name, $value, $group) = call_user_func($this->hookApplier, $name, $value);
+ if ($group !== null) {
+ $this->groups[$group][] = [$name, $value];
+ return;
+ }
+ }
+
+ $isArray = is_array($value);
+ if (! $isArray && $value instanceof \stdClass) {
+ $value = (array) $value;
+ $isArray = true;
+ }
+
+ switch (true) {
+ case $isArray && is_int(key($value)):
+ $this->renderArray($name, $value);
+ break;
+ case $isArray:
+ $this->renderObject($name, $value);
+ break;
+ default:
+ $this->renderScalar($name, $value);
+ }
+ }
+
+ /**
+ * Render an array
+ *
+ * @param mixed $name
+ * @param array $array
+ *
+ * @return void
+ */
+ protected function renderArray($name, array $array)
+ {
+ $numItems = count($array);
+ $name = (new HtmlDocument())->addHtml(
+ Html::wantHtml($name),
+ Text::create(' (Array)')
+ );
+
+ $this->addRow($name, sprintf(tp('%d item', '%d items', $numItems), $numItems));
+
+ ++$this->level;
+
+ ksort($array);
+ foreach ($array as $key => $value) {
+ $this->renderVar("[$key]", $value);
+ }
+
+ --$this->level;
+ }
+
+ /**
+ * Render an object (associative array)
+ *
+ * @param mixed $name
+ * @param array $object
+ *
+ * @return void
+ */
+ protected function renderObject($name, array $object)
+ {
+ $numItems = count($object);
+ $this->addRow($name, sprintf(tp('%d item', '%d items', $numItems), $numItems));
+
+ ++$this->level;
+
+ ksort($object);
+ foreach ($object as $key => $value) {
+ $this->renderVar($key, $value);
+ }
+
+ --$this->level;
+ }
+
+ /**
+ * Render a scalar
+ *
+ * @param mixed $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ protected function renderScalar($name, $value)
+ {
+ if ($value === '') {
+ $value = new HtmlElement('span', Attributes::create(['class' => 'empty']), Text::create(t('empty string')));
+ }
+
+ $this->addRow($name, $value);
+ }
+
+ /**
+ * Render a group
+ *
+ * @param string $name
+ * @param iterable $entries
+ *
+ * @return void
+ */
+ protected function renderGroup($name, $entries)
+ {
+ $table = new self($entries);
+
+ /** @var HtmlDocument $wrapper */
+ $wrapper = $this->getWrapper();
+ if ($wrapper === null) {
+ $wrapper = new HtmlDocument();
+ $wrapper->addHtml($this);
+ $this->prependWrapper($wrapper);
+ }
+
+ $wrapper->addHtml($table->setHeader($name));
+ }
+
+ protected function assemble()
+ {
+ if ($this->object !== null) {
+ $this->hookApplier = CustomVarRendererHook::prepareForObject($this->object);
+ }
+
+ if ($this->headerTitle !== null) {
+ $this->getAttributes()
+ ->add('class', 'collapsible')
+ ->add('data-visible-height', 100)
+ ->add('data-toggle-element', 'thead')
+ ->add(
+ 'id',
+ preg_replace('/\s+/', '-', strtolower($this->headerTitle)) . '-customvars'
+ );
+
+ $this->addHtml(new HtmlElement('thead', null, new HtmlElement(
+ 'tr',
+ null,
+ new HtmlElement(
+ 'th',
+ Attributes::create(['colspan' => 2]),
+ new HtmlElement(
+ 'span',
+ null,
+ new Icon('angle-right'),
+ new Icon('angle-down')
+ ),
+ Text::create($this->headerTitle)
+ )
+ )));
+ }
+
+ if (is_array($this->data)) {
+ ksort($this->data);
+ }
+
+ foreach ($this->data as $name => $value) {
+ $this->renderVar($name, $value);
+ }
+
+ $this->addHtml($this->body);
+
+ // Hooks can return objects as replacement for keys, hence a generator is needed for group entries
+ $genGenerator = function ($entries) {
+ foreach ($entries as list($key, $value)) {
+ yield $key => $value;
+ }
+ };
+
+ foreach ($this->groups as $group => $entries) {
+ $this->renderGroup($group, $genGenerator($entries));
+ }
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Web/Widget/SelectBox.php b/modules/monitoring/library/Monitoring/Web/Widget/SelectBox.php
new file mode 100644
index 0000000..48b98ac
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Web/Widget/SelectBox.php
@@ -0,0 +1,120 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Web\Widget;
+
+use Icinga\Web\Form;
+use Icinga\Web\Request;
+use Icinga\Web\Widget\AbstractWidget;
+
+class SelectBox extends AbstractWidget
+{
+ /**
+ * The name of the form that will be created
+ *
+ * @var string
+ */
+ private $name;
+
+ /**
+ * An array containing all intervals with their associated labels
+ *
+ * @var array
+ */
+ private $values;
+
+ /**
+ * The label displayed next to the select box
+ *
+ * @var string
+ */
+ private $label;
+
+ /**
+ * The name of the url parameter to set
+ *
+ * @var string
+ */
+ private $parameter;
+
+ /**
+ * A request object used for initial form population
+ *
+ * @var Request
+ */
+ private $request;
+
+ /**
+ * Create a TimelineIntervalBox
+ *
+ * @param string $name The name of the form that will be created
+ * @param array $values An array containing all intervals with their associated labels
+ * @param string $label The label displayed next to the select box
+ * @param string $param The request parameter name to set
+ */
+ public function __construct($name, array $values, $label = 'Select', $param = 'selection')
+ {
+ $this->name = $name;
+ $this->values = $values;
+ $this->label = $label;
+ $this->parameter = $param;
+ }
+
+ /**
+ * Apply the parameters from the given request on this widget
+ *
+ * @param Request $request The request to use for populating the form
+ */
+ public function applyRequest(Request $request)
+ {
+ $this->request = $request;
+ }
+
+ /**
+ * Return the chosen interval value or null
+ *
+ * @param Request $request The request to fetch the value from
+ *
+ * @return string|null
+ */
+ public function getInterval(Request $request = null)
+ {
+ if ($request === null && $this->request) {
+ $request = $this->request;
+ }
+
+ if ($request) {
+ return $request->getParam('interval');
+ }
+ }
+
+ /**
+ * Renders this widget and returns the HTML as a string
+ *
+ * @return string
+ */
+ public function render()
+ {
+ $form = new Form();
+ $form->setAttrib('class', Form::DEFAULT_CLASSES . ' inline');
+ $form->setMethod('GET');
+ $form->setUidDisabled();
+ $form->setTokenDisabled();
+ $form->setName($this->name);
+ $form->addElement(
+ 'select',
+ $this->parameter,
+ array(
+ 'label' => $this->label,
+ 'multiOptions' => $this->values,
+ 'autosubmit' => true
+ )
+ );
+
+ if ($this->request) {
+ $form->populate($this->request->getParams());
+ }
+
+ return $form;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php b/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php
new file mode 100644
index 0000000..fdaac51
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Web/Widget/StateBadges.php
@@ -0,0 +1,341 @@
+<?php
+/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Web\Widget;
+
+use Icinga\Web\Form;
+use Icinga\Web\Navigation\Navigation;
+use Icinga\Web\Navigation\NavigationItem;
+use Icinga\Web\Url;
+use Icinga\Web\Widget\AbstractWidget;
+use Icinga\Data\Filter\Filter;
+
+class StateBadges extends AbstractWidget
+{
+ /**
+ * CSS class for the widget
+ *
+ * @var string
+ */
+ const CSS_CLASS = 'state-badges';
+
+ /**
+ * State critical
+ *
+ * @var string
+ */
+ const STATE_CRITICAL = 'state-critical';
+
+ /**
+ * State critical handled
+ *
+ * @var string
+ */
+ const STATE_CRITICAL_HANDLED = 'state-critical handled';
+
+ /**
+ * State down
+ *
+ * @var string
+ */
+ const STATE_DOWN = 'state-down';
+
+ /**
+ * State down handled
+ *
+ * @var string
+ */
+ const STATE_DOWN_HANDLED = 'state-down handled';
+
+ /**
+ * State ok
+ *
+ * @var string
+ */
+ const STATE_OK = 'state-ok';
+
+ /**
+ * State pending
+ *
+ * @var string
+ */
+ const STATE_PENDING = 'state-pending';
+
+ /**
+ * State unknown
+ *
+ * @var string
+ */
+ const STATE_UNKNOWN = 'state-unknown';
+
+ /**
+ * State unknown handled
+ *
+ * @var string
+ */
+ const STATE_UNKNOWN_HANDLED = 'state-unknown handled';
+
+ /**
+ * State unreachable
+ *
+ * @var string
+ */
+ const STATE_UNREACHABLE = 'state-unreachable';
+
+ /**
+ * State unreachable handled
+ *
+ * @var string
+ */
+ const STATE_UNREACHABLE_HANDLED = 'state-unreachable handled';
+
+ /**
+ * State up
+ *
+ * @var string
+ */
+ const STATE_UP = 'state-up';
+
+ /**
+ * State warning
+ *
+ * @var string
+ */
+ const STATE_WARNING = 'state-warning';
+
+ /**
+ * State warning handled
+ *
+ * @var string
+ */
+ const STATE_WARNING_HANDLED = 'state-warning handled';
+
+ /**
+ * State badges
+ *
+ * @var object[]
+ */
+ protected $badges = array();
+
+ /**
+ * Internal counter for badge priorities
+ *
+ * @var int
+ */
+ protected $priority = 1;
+
+ /**
+ * The base filter applied to any badge link
+ *
+ * @var Filter
+ */
+ protected $baseFilter;
+
+ /**
+ * Base URL
+ *
+ * @var Url
+ */
+ protected $url;
+
+ /**
+ * Get the base URL
+ *
+ * @return Url
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Set the base URL
+ *
+ * @param Url|string $url
+ *
+ * @return $this
+ */
+ public function setUrl($url)
+ {
+ if (! $url instanceof $url) {
+ $url = Url::fromPath($url);
+ }
+ $this->url = $url;
+ return $this;
+ }
+
+ /**
+ * Get the base filter
+ *
+ * @return Filter
+ */
+ public function getBaseFilter()
+ {
+ return $this->baseFilter;
+ }
+
+ /**
+ * Set the base filter
+ *
+ * @param Filter $baseFilter
+ *
+ * @return $this
+ */
+ public function setBaseFilter($baseFilter)
+ {
+ $this->baseFilter = $baseFilter;
+ return $this;
+ }
+
+ /**
+ * Add a state badge
+ *
+ * @param string $state
+ * @param int $count
+ * @param array $filter
+ * @param string $translateSingular
+ * @param string $translatePlural
+ * @param array $translateArgs
+ *
+ * @return $this
+ */
+ public function add(
+ $state,
+ $count,
+ array $filter,
+ $translateSingular,
+ $translatePlural,
+ array $translateArgs = array()
+ ) {
+ $this->badges[$state] = (object) array(
+ 'count' => (int) $count,
+ 'filter' => $filter,
+ 'translateArgs' => $translateArgs,
+ 'translatePlural' => $translatePlural,
+ 'translateSingular' => $translateSingular
+ );
+ return $this;
+ }
+
+ /**
+ * Create a badge
+ *
+ * @param string $state
+ * @param Navigation $badges
+ *
+ * @return $this
+ */
+ public function createBadge($state, Navigation $badges)
+ {
+ if ($this->has($state)) {
+ $badge = $this->get($state);
+ $url = clone $this->url->setParams($badge->filter);
+ if (isset($this->baseFilter)) {
+ $url->addFilter($this->baseFilter);
+ }
+ $badges->addItem(new NavigationItem($state, array(
+ 'attributes' => array('class' => 'badge ' . $state),
+ 'label' => $badge->count,
+ 'priority' => $this->priority++,
+ 'title' => vsprintf(
+ mtp('monitoring', $badge->translateSingular, $badge->translatePlural, $badge->count),
+ $badge->translateArgs
+ ),
+ 'url' => $url
+ )));
+ }
+ return $this;
+ }
+
+ /**
+ * Create a badge group
+ *
+ * @param array $states
+ * @param Navigation $badges
+ *
+ * @return $this
+ */
+ public function createBadgeGroup(array $states, Navigation $badges)
+ {
+ $group = array_intersect_key($this->badges, array_flip($states));
+ if (! empty($group)) {
+ $groupItem = new NavigationItem(
+ uniqid(),
+ array(
+ 'cssClass' => 'state-badge-group',
+ 'label' => '',
+ 'priority' => $this->priority++
+ )
+ );
+ $groupBadges = new Navigation();
+ $groupBadges->setLayout(Navigation::LAYOUT_TABS);
+ foreach (array_keys($group) as $state) {
+ $this->createBadge($state, $groupBadges);
+ }
+ $groupItem->setChildren($groupBadges);
+ $badges->addItem($groupItem);
+ }
+ return $this;
+ }
+
+ /**
+ * Get whether a badge for the given state has been added
+ *
+ * @param string $state
+ *
+ * @return bool
+ */
+ public function has($state)
+ {
+ return isset($this->badges[$state]) && $this->badges[$state]->count;
+ }
+
+ /**
+ * Get the badge for the given state
+ *
+ * @param string $state
+ *
+ * @return object
+ */
+ public function get($state)
+ {
+ return $this->badges[$state];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render()
+ {
+ $badges = new Navigation();
+ $badges->setLayout(Navigation::LAYOUT_TABS);
+ $this
+ ->createBadgeGroup(
+ array(static::STATE_CRITICAL, static::STATE_CRITICAL_HANDLED),
+ $badges
+ )
+ ->createBadgeGroup(
+ array(static::STATE_DOWN, static::STATE_DOWN_HANDLED),
+ $badges
+ )
+ ->createBadgeGroup(
+ array(static::STATE_WARNING, static::STATE_WARNING_HANDLED),
+ $badges
+ )
+ ->createBadgeGroup(
+ array(static::STATE_UNREACHABLE, static::STATE_UNREACHABLE_HANDLED),
+ $badges
+ )
+ ->createBadgeGroup(
+ array(static::STATE_UNKNOWN, static::STATE_UNKNOWN_HANDLED),
+ $badges
+ )
+ ->createBadge(static::STATE_OK, $badges)
+ ->createBadge(static::STATE_UP, $badges)
+ ->createBadge(static::STATE_PENDING, $badges);
+ return $badges
+ ->getRenderer()
+ ->setCssClass(static::CSS_CLASS)
+ ->render();
+ }
+}