From 3252ff892590391600e7d938715aecd2131dd38d Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 24 Mar 2025 13:02:27 +0100 Subject: [PATCH] Introduce class `LoadMoreObjectList` and `NotificationRenderer` - Remove now obsolete ItemList classes - Fix load-more element's css - LoadMore: Replace `list-item` css class with new `item-layout` class, as this class is now responsible for list items --- .../controllers/NotificationsController.php | 7 +- .../NotificationRenderer.php} | 271 +++++++++--------- .../Widget/ItemList/LoadMoreObjectList.php | 37 +++ .../Widget/ItemList/NotificationList.php | 55 ---- .../Widget/ItemList/NotificationListItem.php | 18 -- .../ItemList/NotificationListItemDetailed.php | 18 -- .../ItemList/NotificationListItemMinimal.php | 27 -- .../Icingadb/Widget/ItemList/ObjectList.php | 5 + public/css/list/item-list.less | 6 +- 9 files changed, 190 insertions(+), 254 deletions(-) rename library/Icingadb/{Widget/ItemList/BaseNotificationListItem.php => View/NotificationRenderer.php} (54%) create mode 100644 library/Icingadb/Widget/ItemList/LoadMoreObjectList.php delete mode 100644 library/Icingadb/Widget/ItemList/NotificationList.php delete mode 100644 library/Icingadb/Widget/ItemList/NotificationListItem.php delete mode 100644 library/Icingadb/Widget/ItemList/NotificationListItemDetailed.php delete mode 100644 library/Icingadb/Widget/ItemList/NotificationListItemMinimal.php diff --git a/application/controllers/NotificationsController.php b/application/controllers/NotificationsController.php index 2d23604c..286bb140 100644 --- a/application/controllers/NotificationsController.php +++ b/application/controllers/NotificationsController.php @@ -8,13 +8,11 @@ use GuzzleHttp\Psr7\ServerRequest; use Icinga\Module\Icingadb\Model\NotificationHistory; use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions; use Icinga\Module\Icingadb\Web\Controller; -use Icinga\Module\Icingadb\Widget\ItemList\NotificationList; +use Icinga\Module\Icingadb\Widget\ItemList\LoadMoreObjectList; use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher; -use ipl\Sql\Sql; use ipl\Stdlib\Filter; use ipl\Web\Control\LimitControl; use ipl\Web\Control\SortControl; -use ipl\Web\Filter\QueryString; use ipl\Web\Url; class NotificationsController extends Controller @@ -94,7 +92,8 @@ class NotificationsController extends Controller ->onlyWith($preserveParams) ->setFilter($filter); - $notificationList = (new NotificationList($notifications->execute())) + $notificationList = (new LoadMoreObjectList($notifications->execute())) + ->setDetailUrl(Url::fromPath('icingadb/event')) ->setPageSize($limitControl->getLimit()) ->setViewMode($viewModeSwitcher->getViewMode()) ->setLoadMoreUrl($url->setParam('before', $before)); diff --git a/library/Icingadb/Widget/ItemList/BaseNotificationListItem.php b/library/Icingadb/View/NotificationRenderer.php similarity index 54% rename from library/Icingadb/Widget/ItemList/BaseNotificationListItem.php rename to library/Icingadb/View/NotificationRenderer.php index b538ac4a..9b88eaaf 100644 --- a/library/Icingadb/Widget/ItemList/BaseNotificationListItem.php +++ b/library/Icingadb/View/NotificationRenderer.php @@ -1,43 +1,168 @@ */ +class NotificationRenderer implements ItemRenderer { + use Translation; use HostLink; - use NoSubjectLink; use ServiceLink; - /** @var NotificationList */ - protected $list; - - protected function init(): void + public function assembleAttributes($item, Attributes $attributes, string $layout): void { - $this->setNoSubjectLink($this->list->getNoSubjectLink()); - $this->list->addDetailFilterAttribute($this, Filter::equal('id', bin2hex($this->item->history->id))); + $attributes->get('class')->addValue('notification'); + } + + public function assembleVisual($item, HtmlDocument $visual, string $layout): void + { + $ballSize = StateBall::SIZE_LARGE; + if ($layout === 'minimal' || $layout === 'header') { + $ballSize = StateBall::SIZE_BIG; + } + + switch ($item->type) { + case 'acknowledgement': + $visual->addHtml(HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::IS_ACKNOWLEDGED) + )); + + break; + case 'custom': + $visual->addHtml(HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::NOTIFICATION) + )); + + break; + case 'downtime_end': + case 'downtime_removed': + case 'downtime_start': + $visual->addHtml(HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::IN_DOWNTIME) + )); + + break; + case 'flapping_end': + case 'flapping_start': + $visual->addHtml(HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::IS_FLAPPING) + )); + + break; + case 'problem': + case 'recovery': + if ($item->object_type === 'host') { + $state = HostStates::text($item->state); + $previousHardState = HostStates::text($item->previous_hard_state); + } else { + $state = ServiceStates::text($item->state); + $previousHardState = ServiceStates::text($item->previous_hard_state); + } + + $visual->addHtml(new StateChange($state, $previousHardState)); + + break; + } + } + + public function assembleTitle($item, HtmlDocument $title, string $layout): void + { + if ($layout === 'header') { + $title->addHtml(HtmlElement::create( + 'span', + ['class' => 'subject'], + sprintf(self::phraseForType($item->type), ucfirst($item->object_type)) + )); + } else { + $title->addHtml(new Link( + sprintf(self::phraseForType($item->type), ucfirst($item->object_type)), + Links::event($item->history), + ['class' => 'subject'] + )); + } + + if ($item->object_type === 'host') { + $link = $this->createHostLink($item->host, true); + } else { + $link = $this->createServiceLink($item->service, $item->host, true); + } + + $title->addHtml(Text::create(' '), $link); + } + + public function assembleCaption($item, HtmlDocument $caption, string $layout): void + { + if (in_array($item->type, ['flapping_end', 'flapping_start', 'problem', 'recovery'])) { + $commandName = $item->object_type === 'host' + ? $item->host->checkcommand_name + : $item->service->checkcommand_name; + if (isset($commandName)) { + if (empty($item->text)) { + $caption->addHtml(new EmptyState($this->translate('Output unavailable.'))); + } else { + $caption->addHtml(new PluginOutputContainer( + (new PluginOutput($item->text)) + ->setCommandName($commandName) + )); + } + } else { + $caption->addHtml(new EmptyState($this->translate('Waiting for Icinga DB to synchronize the config.'))); + } + } else { + $caption->add([ + new Icon(Icons::USER), + $item->author, + ': ', + $item->text + ]); + } + } + + public function assembleExtendedInfo($item, HtmlDocument $info, string $layout): void + { + $info->addHtml(new TimeAgo($item->send_time->getTimestamp())); + } + + public function assembleFooter($item, HtmlDocument $footer, string $layout): void + { + } + + public function assemble($item, string $name, HtmlDocument $element, string $layout): bool + { + return false; // no custom sections } /** @@ -72,118 +197,4 @@ abstract class BaseNotificationListItem extends BaseListItem throw new InvalidArgumentException(sprintf('Type %s is not a valid notification type', $type)); } } - - abstract protected function getStateBallSize(); - - protected function assembleCaption(BaseHtmlElement $caption): void - { - if (in_array($this->item->type, ['flapping_end', 'flapping_start', 'problem', 'recovery'])) { - $commandName = $this->item->object_type === 'host' - ? $this->item->host->checkcommand_name - : $this->item->service->checkcommand_name; - if (isset($commandName)) { - if (empty($this->item->text)) { - $caption->addHtml(new EmptyState(t('Output unavailable.'))); - } else { - $caption->addHtml(new PluginOutputContainer( - (new PluginOutput($this->item->text)) - ->setCommandName($commandName) - )); - } - } else { - $caption->addHtml(new EmptyState(t('Waiting for Icinga DB to synchronize the config.'))); - } - } else { - $caption->add([ - new Icon(Icons::USER), - $this->item->author, - ': ', - $this->item->text - ]); - } - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - switch ($this->item->type) { - case 'acknowledgement': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::IS_ACKNOWLEDGED) - )); - - break; - case 'custom': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::NOTIFICATION) - )); - - break; - case 'downtime_end': - case 'downtime_removed': - case 'downtime_start': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::IN_DOWNTIME) - )); - - break; - case 'flapping_end': - case 'flapping_start': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::IS_FLAPPING) - )); - - break; - case 'problem': - case 'recovery': - if ($this->item->object_type === 'host') { - $state = HostStates::text($this->item->state); - $previousHardState = HostStates::text($this->item->previous_hard_state); - } else { - $state = ServiceStates::text($this->item->state); - $previousHardState = ServiceStates::text($this->item->previous_hard_state); - } - - $visual->addHtml(new StateChange($state, $previousHardState)); - - break; - } - } - - protected function assembleTitle(BaseHtmlElement $title): void - { - if ($this->getNoSubjectLink()) { - $title->addHtml(HtmlElement::create( - 'span', - ['class' => 'subject'], - sprintf(self::phraseForType($this->item->type), ucfirst($this->item->object_type)) - )); - } else { - $title->addHtml(new Link( - sprintf(self::phraseForType($this->item->type), ucfirst($this->item->object_type)), - Links::event($this->item->history), - ['class' => 'subject'] - )); - } - - if ($this->item->object_type === 'host') { - $link = $this->createHostLink($this->item->host, true); - } else { - $link = $this->createServiceLink($this->item->service, $this->item->host, true); - } - - $title->addHtml(Text::create(' '), $link); - } - - protected function createTimestamp(): ?BaseHtmlElement - { - return new TimeAgo($this->item->send_time->getTimestamp()); - } } diff --git a/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php b/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php new file mode 100644 index 00000000..7044c8bb --- /dev/null +++ b/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php @@ -0,0 +1,37 @@ +data = $this->getIterator($data); + } +} diff --git a/library/Icingadb/Widget/ItemList/NotificationList.php b/library/Icingadb/Widget/ItemList/NotificationList.php deleted file mode 100644 index 3a16b0b3..00000000 --- a/library/Icingadb/Widget/ItemList/NotificationList.php +++ /dev/null @@ -1,55 +0,0 @@ - 'notification-list']; - - protected function init(): void - { - /** @var ResultSet $data */ - $data = $this->data; - $this->data = $this->getIterator($data); - $this->initializeDetailActions(); - $this->setDetailUrl(Url::fromPath('icingadb/event')); - } - - protected function getItemClass(): string - { - switch ($this->getViewMode()) { - case 'minimal': - return NotificationListItemMinimal::class; - case 'detailed': - $this->removeAttribute('class', 'default-layout'); - - return NotificationListItemDetailed::class; - default: - return NotificationListItem::class; - } - } - - protected function assemble(): void - { - $this->addAttributes(['class' => $this->getViewMode()]); - - parent::assemble(); - } -} diff --git a/library/Icingadb/Widget/ItemList/NotificationListItem.php b/library/Icingadb/Widget/ItemList/NotificationListItem.php deleted file mode 100644 index 683762f9..00000000 --- a/library/Icingadb/Widget/ItemList/NotificationListItem.php +++ /dev/null @@ -1,18 +0,0 @@ -list->isCaptionDisabled()) { - $this->setCaptionDisabled(); - } - } - - protected function getStateBallSize(): string - { - return StateBall::SIZE_BIG; - } -} diff --git a/library/Icingadb/Widget/ItemList/ObjectList.php b/library/Icingadb/Widget/ItemList/ObjectList.php index 0ce90f89..1f1efa6b 100644 --- a/library/Icingadb/Widget/ItemList/ObjectList.php +++ b/library/Icingadb/Widget/ItemList/ObjectList.php @@ -10,6 +10,7 @@ use Icinga\Module\Icingadb\Model\Comment; use Icinga\Module\Icingadb\Model\DependencyNode; use Icinga\Module\Icingadb\Model\Downtime; use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\NotificationHistory; use Icinga\Module\Icingadb\Model\RedundancyGroup; use Icinga\Module\Icingadb\Model\Service; use Icinga\Module\Icingadb\Model\UnreachableParent; @@ -207,6 +208,10 @@ class ObjectList extends ItemList $this->addDetailFilterAttribute($item, Filter::equal('name', $object->name)); $this->addMultiSelectFilterAttribute($item, Filter::equal('name', $object->name)); + break; + case $object instanceof NotificationHistory: + $this->addDetailFilterAttribute($item, Filter::equal('id', bin2hex($object->history->id))); + break; } diff --git a/public/css/list/item-list.less b/public/css/list/item-list.less index 256ca42f..e19326ec 100644 --- a/public/css/list/item-list.less +++ b/public/css/list/item-list.less @@ -43,8 +43,10 @@ // Layout -.item-list .list-item { - &.load-more a { +.item-list .load-more { + display: flex; + + a { flex: 1; margin: 1.5em 0; padding: .5em 0;