From 59dd1e651b2a50c8e7c2646294867ffb3e52d953 Mon Sep 17 00:00:00 2001 From: raviks789 Date: Wed, 20 Mar 2024 12:25:57 +0100 Subject: [PATCH] Implement object hook to get event object information from respective sources --- .../Hook/EventsObjectsInfoHook.php | 119 ++++++++++++++++++ library/Notifications/Model/Objects.php | 11 +- .../Widget/Detail/EventDetail.php | 38 ++---- .../Widget/Detail/IncidentDetail.php | 42 +++---- .../Widget/ItemList/EventList.php | 37 ++++++ .../Widget/ItemList/EventListItem.php | 7 +- public/css/common.less | 16 +++ 7 files changed, 206 insertions(+), 64 deletions(-) create mode 100644 library/Notifications/Hook/EventsObjectsInfoHook.php diff --git a/library/Notifications/Hook/EventsObjectsInfoHook.php b/library/Notifications/Hook/EventsObjectsInfoHook.php new file mode 100644 index 000000000..b87d8e03b --- /dev/null +++ b/library/Notifications/Hook/EventsObjectsInfoHook.php @@ -0,0 +1,119 @@ + */ + protected static $objectNameWidgets = []; + + /** + * Get the object name widgets for the objects using the object ID tags + * + * @param array> $objectIdTags + * + * @return array + */ + abstract public function getObjectNameWidgets(array $objectIdTags): array; + + /** + * Get the source of the objects + * + * @return string + */ + abstract public function getSource(): string; + + /** + * Get the object list item widget for the given object ID tag + * + * @param array $objectIdTag + * + * @return ValidHtml + */ + abstract public function getHtmlForObject(array $objectIdTag): ValidHtml; + + /** + * Register object name widgets for the objects using the object ID tags + * + * @param array>> $objectIdTags + * + * @return void + */ + final public static function registerObjectNameWidgets(array $objectIdTags): void + { + $objectDisplayNames = []; + foreach (Hook::all('Notifications\\EventsObjectsInfo') as $hook) { + /** @var self $hook */ + try { + $objectDisplayNames = array_merge( + $objectDisplayNames, + $hook->getObjectNameWidgets($objectIdTags[$hook->getSource()]) + ); + } catch (Exception $e) { + Logger::error('Failed to load hook %s:', get_class($hook), $e); + } + } + + self::$objectNameWidgets = $objectDisplayNames; + } + + /** + * Get the display name for the given object + * + * @param Objects $obj + * + * @return ValidHtml + */ + final public static function getObjectNameWidget(Objects $obj): ValidHtml + { + /** @var Query|Source $source */ + $source = $obj->source; + if ($source instanceof Query) { + $source = $obj->source->first(); + } + + $objectTags = []; + + foreach ($obj->id_tags as $tag => $value) { + $objectTags[] = sprintf('%s=%s', $tag, $value); + } + + return self::$objectNameWidgets[$source->type][$obj->id] ?? new HtmlString(implode(', ', $objectTags)); + } + + /** + * Get the object list item widget for the object using the object ID tag + * + * @param string $source + * @param array $objectIdTag + * + * @return ?ValidHtml + */ + final public static function getObjectListItemWidget(string $source, array $objectIdTag): ?ValidHtml + { + $objectListItemWidget = null; + foreach (Hook::all('Notifications\\EventsObjectsInfo') as $hook) { + /** @var self $hook */ + try { + if ($source === $hook->getSource()) { + $objectListItemWidget = $hook->getHtmlForObject($objectIdTag); + } + } catch (Exception $e) { + Logger::error('Failed to load hook %s:', get_class($hook), $e); + } + } + + return $objectListItemWidget; + } +} diff --git a/library/Notifications/Model/Objects.php b/library/Notifications/Model/Objects.php index 8a2b08a49..60dadd2ec 100644 --- a/library/Notifications/Model/Objects.php +++ b/library/Notifications/Model/Objects.php @@ -4,8 +4,8 @@ namespace Icinga\Module\Notifications\Model; +use Icinga\Module\Notifications\Hook\EventsObjectsInfoHook; use Icinga\Module\Notifications\Model\Behavior\IdTagAggregator; -use ipl\Html\HtmlString; use ipl\Html\ValidHtml; use ipl\Orm\Behavior\Binary; use ipl\Orm\Behaviors; @@ -91,13 +91,6 @@ public function createRelations(Relations $relations) public function getName(): ValidHtml { - //TODO: Once hooks are available, they should render the tags accordingly - $objectTags = []; - - foreach ($this->id_tags as $tag => $value) { - $objectTags[] = sprintf('%s=%s', $tag, $value); - } - - return new HtmlString(implode(', ', $objectTags)); + return EventsObjectsInfoHook::getObjectNameWidget($this); } } diff --git a/library/Notifications/Widget/Detail/EventDetail.php b/library/Notifications/Widget/Detail/EventDetail.php index 9f16a697e..358f61753 100644 --- a/library/Notifications/Widget/Detail/EventDetail.php +++ b/library/Notifications/Widget/Detail/EventDetail.php @@ -5,15 +5,18 @@ namespace Icinga\Module\Notifications\Widget\Detail; use Icinga\Date\DateFormatter; +use Icinga\Module\Notifications\Hook\EventsObjectsInfoHook; use Icinga\Module\Notifications\Model\Event; use Icinga\Module\Notifications\Model\Incident; use Icinga\Module\Notifications\Model\Objects; +use Icinga\Module\Notifications\Model\Source; use Icinga\Module\Notifications\Widget\EventSourceBadge; use Icinga\Module\Notifications\Widget\ItemList\IncidentList; use InvalidArgumentException; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\ValidHtml; +use ipl\Web\Url; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; @@ -80,37 +83,22 @@ protected function createMessage(): array /** @return ValidHtml[] */ protected function createRelatedObject(): array { - //TODO(sd): This is just placeholder. Add hook implementation instead - $relatedObj = Html::tag('ul', ['class' => ['item-list', 'action-list'], 'data-base-target' => '_next']); - /** @var Objects $obj */ $obj = $this->event->object; - /** @var string $objUrl */ - $objUrl = $obj->url; - $relatedObj->add( - Html::tag( - 'li', - ['class' => 'list-item', 'data-action-item' => true], - [ //TODO(sd): fix stateball - Html::tag('div', ['class' => 'visual'], new StateBall('down', StateBall::SIZE_LARGE)), - Html::tag( - 'div', - ['class' => 'main'], - Html::tag('header') - ->add(Html::tag( - 'div', - ['class' => 'title'], - new Link($obj->getName(), $objUrl, ['class' => 'subject']) - )) - ) - ] - ) - ); + /** @var Source $source */ + $source = $obj->source; + + $objWidget = EventsObjectsInfoHook::getObjectListItemWidget($source->name, $obj->id_tags); + $objUrl = Url::fromPath($obj->url); return [ Html::tag('h2', t('Related Object')), - $relatedObj + $objWidget ?? (new Link( + $obj->getName(), + $objUrl->isExternal() ? $objUrl->getAbsoluteUrl() : $objUrl->getRelativeUrl(), + ['class' => 'subject'] + ))->setBaseTarget('_next') ]; } diff --git a/library/Notifications/Widget/Detail/IncidentDetail.php b/library/Notifications/Widget/Detail/IncidentDetail.php index e3fff80b3..e1a119e5c 100644 --- a/library/Notifications/Widget/Detail/IncidentDetail.php +++ b/library/Notifications/Widget/Detail/IncidentDetail.php @@ -4,8 +4,10 @@ namespace Icinga\Module\Notifications\Widget\Detail; +use Icinga\Module\Notifications\Hook\EventsObjectsInfoHook; use Icinga\Module\Notifications\Model\Incident; use Icinga\Module\Notifications\Model\Objects; +use Icinga\Module\Notifications\Model\Source; use Icinga\Module\Notifications\Widget\EventSourceBadge; use Icinga\Module\Notifications\Widget\ItemList\IncidentContactList; use Icinga\Module\Notifications\Widget\ItemList\IncidentHistoryList; @@ -14,8 +16,8 @@ use ipl\Html\Html; use ipl\Html\HtmlElement; use ipl\Html\Table; +use ipl\Web\Url; use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; class IncidentDetail extends BaseHtmlElement { @@ -52,39 +54,23 @@ protected function createContacts() protected function createRelatedObject() { - //TODO(sd): Add hook implementation - $list = Html::tag('ul', ['class' => ['item-list', 'minimal', 'action-list'], 'data-base-target' => '_next']); - /** @var Objects $obj */ $obj = $this->incident->object; - /** @var string $objUrl */ - $objUrl = $obj->url; - $list->add(Html::tag( - 'li', - ['class' => 'list-item', 'data-action-item' => true], - [ //TODO(sd): fix stateball - Html::tag( - 'div', - ['class' => 'visual'], - new StateBall('down', StateBall::SIZE_LARGE) - ), - Html::tag( - 'div', - ['class' => 'main'], - Html::tag('header') - ->add(Html::tag( - 'div', - ['class' => 'title'], - new Link($obj->getName(), $objUrl, ['class' => 'subject']) - )) - ) - ] - )); + /** @var Source $source */ + $source = $obj->source; + + $objWidget = EventsObjectsInfoHook::getObjectListItemWidget($source->name, $obj->id_tags); + /** @var Url $objUrl */ + $objUrl = Url::fromPath($obj->url); return [ Html::tag('h2', t('Object')), - $list + $objWidget ?? (new Link( + $obj->getName(), + $objUrl->isExternal() ? $objUrl->getAbsoluteUrl() : $objUrl->getRelativeUrl(), + ['class' => 'subject'] + ))->setBaseTarget('_next') ]; } diff --git a/library/Notifications/Widget/ItemList/EventList.php b/library/Notifications/Widget/ItemList/EventList.php index 2ef47006a..fbd6955d1 100644 --- a/library/Notifications/Widget/ItemList/EventList.php +++ b/library/Notifications/Widget/ItemList/EventList.php @@ -6,6 +6,11 @@ use Icinga\Module\Notifications\Common\LoadMore; use Icinga\Module\Notifications\Common\NoSubjectLink; +use Icinga\Module\Notifications\Hook\EventsObjectsInfoHook; +use Icinga\Module\Notifications\Model\Event; +use Icinga\Module\Notifications\Model\Objects; +use Icinga\Module\Notifications\Model\Source; +use ipl\Html\ValidHtml; use ipl\Orm\ResultSet; use ipl\Web\Common\BaseItemList; @@ -19,6 +24,12 @@ class EventList extends BaseItemList /** @var ResultSet */ protected $data; + /** @var array>> Object ID tags for each source */ + public $objectIdTagsCache = []; + + /** @var array Object display names obtained from the corresponding web modules of the sources */ + public $renderedObjectDisplayNames = []; + public function __construct(ResultSet $data) { parent::__construct($data); @@ -27,10 +38,36 @@ public function __construct(ResultSet $data) protected function init(): void { $this->data = $this->getIterator($this->data); + + $this->on(self::ON_ITEM_ADD, function (EventListItem $item, Event $data) { + /** @var Objects $obj */ + $obj = $data->object; + /** @var Source $src */ + $src = $obj->source; + $this->objectIdTagsCache[$src->type][$obj->id] = $obj->id_tags; + }); + + $this->on(self::ON_ASSEMBLED, function () { + EventsObjectsInfoHook::registerObjectNameWidgets( + $this->objectIdTagsCache + ); + }); } protected function getItemClass(): string { return EventListItem::class; } + + /** + * Get the rendered object display name for the given object ID + * + * @param string $objectID + * + * @return ?ValidHtml + */ + public function getRenderedObjectDisplayName(string $objectID): ?ValidHtml + { + return $this->renderedObjectDisplayNames[$objectID] ?? null; + } } diff --git a/library/Notifications/Widget/ItemList/EventListItem.php b/library/Notifications/Widget/ItemList/EventListItem.php index a305f1552..9d519cd74 100644 --- a/library/Notifications/Widget/ItemList/EventListItem.php +++ b/library/Notifications/Widget/ItemList/EventListItem.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Notifications\Widget\ItemList; use Icinga\Module\Notifications\Common\Links; +use Icinga\Module\Notifications\Hook\EventsObjectsInfoHook; use Icinga\Module\Notifications\Model\Event; use Icinga\Module\Notifications\Model\Incident; use Icinga\Module\Notifications\Model\Objects; @@ -13,6 +14,7 @@ use Icinga\Module\Notifications\Widget\SourceIcon; use InvalidArgumentException; use ipl\Html\BaseHtmlElement; +use ipl\Html\DeferredText; use ipl\Html\Html; use ipl\Stdlib\Str; use ipl\Web\Common\BaseListItem; @@ -105,14 +107,15 @@ protected function assembleTitle(BaseHtmlElement $title): void /** @var Objects $obj */ $obj = $this->item->object; - $name = $obj->getName(); + $name = (new DeferredText(function () use ($obj) { + return $obj->getName(); + }))->setEscaped(); if (! $this->list->getNoSubjectLink()) { $content = new Link($name, Links::event($this->item->id), ['class' => 'subject']); } else { $content = Html::tag('span', ['class' => 'subject'], $name); } - $msg = null; if ($this->item->severity === null) { $description = strtolower(trim($this->item->message ?? '')); if (Str::startsWith($description, 'incident reached age')) { diff --git a/public/css/common.less b/public/css/common.less index 9f704c66a..b87d39496 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -27,6 +27,22 @@ } } +.incident-detail, +.event-detail { + .subject { + color: @default-text-color; + } + + a { + font-weight: bold; + + &:hover { + color: @list-item-title-hover-color; + text-decoration: none; + } + } +} + .source-icon { .ball(); .ball-solid(@gray-light);