diff --git a/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php b/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php index 8d2bc256..113da5d7 100644 --- a/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php +++ b/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php @@ -14,8 +14,11 @@ use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\MonitoredObject; use Icinga\Module\Monitoring\Object\Service; use ipl\Html\Attributes; +use ipl\Html\Html; +use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; +use ipl\Html\ValidHtml; class CustomVarRenderer extends CustomVarRendererHook { @@ -25,6 +28,18 @@ class CustomVarRenderer extends CustomVarRendererHook /** @var array Related datalists and their keys and values */ protected $datalistMaps = []; + /** @var array Related dictionary names */ + protected $dictionaryNames = []; + + /** @var int The nesting level for dictionary */ + protected $dictionaryLevel = 0; + + /** @var HtmlElement Table for dictionary fields */ + private $dictionaryTable; + + /** @var HtmlElement Table body for dictionary fields */ + private $dictionaryBody; + /** * Get a database connection to the director database * @@ -88,6 +103,8 @@ class CustomVarRenderer extends CustomVarRendererHook if ($field->get('datatype') === 'Icinga\Module\Director\DataType\DataTypeDatalist') { $fieldsWithDataLists[$field->get('id')] = $field; + } elseif ($field->get('datatype') === 'Icinga\Module\Director\DataType\DataTypeDictionary') { + $this->dictionaryNames[] = $field->get('varname'); } } @@ -139,8 +156,12 @@ class CustomVarRenderer extends CustomVarRendererHook Attributes::create(['title' => $this->datalistMaps[$key][$value] . " [$value]"]), Text::create($this->datalistMaps[$key][$value]) ); + } elseif ($value !== null && in_array($key, $this->dictionaryNames)) { + return $this->renderDictionaryVal($key, (array) $value); } } + + return null; } public function identifyCustomVarGroup($key) @@ -149,4 +170,153 @@ class CustomVarRenderer extends CustomVarRendererHook return $this->fieldConfig[$key]['group']; } } + + /** + * Render the dictionary value + * + * @param string $key + * @param array $value + * + * @return ?ValidHtml + */ + protected function renderDictionaryVal(string $key, array $value): ?ValidHtml + { + if ($this->dictionaryLevel > 0) { + $numItems = count($value); + $label = $this->renderCustomVarKey($key) ?? $key; + + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml($label)), + new HtmlElement( + 'td', + null, + Text::create(sprintf(tp('%d item', '%d items', $numItems), $numItems)) + ) + ) + ); + } else { + $this->dictionaryTable = new HtmlElement( + 'table', + Attributes::create(['class' => ['custom-var-table', 'name-value-table']]) + ); + + $this->dictionaryBody = new HtmlElement('tbody'); + } + + $this->dictionaryLevel++; + + foreach ($value as $key => $val) { + if ($key !== null && is_array($val) || is_object($val)) { + $val = (array) $val; + $numChildItems = count($val); + + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml($key)), + new HtmlElement( + 'td', + null, + Text::create(sprintf(tp('%d item', '%d items', $numChildItems), $numChildItems)) + ) + ) + ); + + $this->dictionaryLevel++; + foreach ($val as $childKey => $childVal) { + $childVal = $this->renderCustomVarValue($childKey, $childVal) ?? $childVal; + if (! in_array($childKey, $this->dictionaryNames)) { + $label = $this->renderCustomVarKey($childKey) ?? $childKey; + + if (is_array($childVal)) { + $this->renderArrayVal($label, $childVal); + } else { + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml( + $label + )), + new HtmlElement('td', null, Html::wantHtml($childVal)) + ) + ); + } + } + } + + $this->dictionaryLevel--; + } elseif (is_array($val)) { + $this->renderArrayVal(Html::wantHtml($key), $val); + } else { + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml($key)), + new HtmlElement('td', null, Html::wantHtml($val)) + ) + ); + } + } + + $this->dictionaryLevel--; + + if ($this->dictionaryLevel === 0) { + return $this->dictionaryTable->addHtml($this->dictionaryBody); + } + + return null; + } + + /** + * Render an array + * + * @param HtmlElement|string $name + * @param array $array + * + * @return void + */ + protected function renderArrayVal($name, array $array) + { + $numItems = count($array); + + if ($name instanceof HtmlElement) { + $name->addHtml(Text::create(' (Array)')); + } else { + $name = (new HtmlDocument())->addHtml( + Html::wantHtml($name), + Text::create(' (Array)') + ); + } + + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml($name)), + new HtmlElement('td', null, Html::wantHtml(sprintf(tp('%d item', '%d items', $numItems), $numItems))) + ) + ); + + ++$this->dictionaryLevel; + + ksort($array); + foreach ($array as $key => $value) { + $this->dictionaryBody->addHtml( + new HtmlElement( + 'tr', + Attributes::create(['class' => "level-{$this->dictionaryLevel}"]), + new HtmlElement('th', null, Html::wantHtml("[$key]")), + new HtmlElement('td', null, Html::wantHtml($value)) + ) + ); + } + + --$this->dictionaryLevel; + } }