diff --git a/application/controllers/EventController.php b/application/controllers/EventController.php index 7108606d..ae325621 100644 --- a/application/controllers/EventController.php +++ b/application/controllers/EventController.php @@ -4,12 +4,10 @@ namespace Icinga\Module\Icingadb\Controllers; -use ArrayObject; use Icinga\Module\Icingadb\Model\History; use Icinga\Module\Icingadb\Web\Controller; use Icinga\Module\Icingadb\Widget\Detail\EventDetail; -use Icinga\Module\Icingadb\Widget\ItemList\HistoryList; -use ipl\Orm\ResultSet; +use Icinga\Module\Icingadb\Widget\Detail\ObjectHeader; use ipl\Stdlib\Filter; class EventController extends Controller @@ -60,12 +58,7 @@ class EventController extends Controller public function indexAction() { - $this->addControl((new HistoryList(new ResultSet(new ArrayObject([$this->event])))) - ->setViewMode('minimal') - ->setPageSize(1) - ->setCaptionDisabled() - ->setNoSubjectLink() - ->setDetailActionsDisabled()); - $this->addContent((new EventDetail($this->event))->setTicketLinkEnabled()); + $this->addControl(new ObjectHeader($this->event)); + $this->addContent(new EventDetail($this->event)); } } diff --git a/application/controllers/HistoryController.php b/application/controllers/HistoryController.php index a1b873b2..1dd938a9 100644 --- a/application/controllers/HistoryController.php +++ b/application/controllers/HistoryController.php @@ -8,8 +8,8 @@ use GuzzleHttp\Psr7\ServerRequest; use Icinga\Module\Icingadb\Model\History; use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions; use Icinga\Module\Icingadb\Web\Controller; -use Icinga\Module\Icingadb\Widget\ItemList\HistoryList; use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher; +use Icinga\Module\Icingadb\Widget\ItemList\LoadMoreObjectList; use ipl\Stdlib\Filter; use ipl\Web\Control\LimitControl; use ipl\Web\Control\SortControl; @@ -98,7 +98,8 @@ class HistoryController extends Controller ->onlyWith($preserveParams) ->setFilter($filter); - $historyList = (new HistoryList($history->execute())) + $historyList = (new LoadMoreObjectList($history->execute())) + ->setDetailUrl(Url::fromPath('icingadb/event')) ->setPageSize($limitControl->getLimit()) ->setViewMode($viewModeSwitcher->getViewMode()) ->setLoadMoreUrl($url->setParam('before', $before)); diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index 31e41c80..fba845e6 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -28,8 +28,8 @@ use Icinga\Module\Icingadb\Widget\Detail\HostInspectionDetail; use Icinga\Module\Icingadb\Widget\Detail\HostMetaInfo; use Icinga\Module\Icingadb\Widget\Detail\ObjectHeader; use Icinga\Module\Icingadb\Widget\Detail\QuickActions; +use Icinga\Module\Icingadb\Widget\ItemList\LoadMoreObjectList; use Icinga\Module\Icingadb\Widget\ItemList\ObjectList; -use Icinga\Module\Icingadb\Widget\ItemList\HistoryList; use ipl\Orm\Query; use ipl\Sql\Expression; use ipl\Sql\Filter\Exists; @@ -167,7 +167,8 @@ class HostController extends Controller $this->addControl($limitControl); $this->addControl($viewModeSwitcher); - $historyList = (new HistoryList($history->execute())) + $historyList = (new LoadMoreObjectList($history->execute())) + ->setDetailUrl(Url::fromPath('icingadb/event')) ->setViewMode($viewModeSwitcher->getViewMode()) ->setPageSize($limitControl->getLimit()) ->setLoadMoreUrl($url->setParam('before', $before)); diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index e68587e0..f00e01fc 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -25,8 +25,8 @@ use Icinga\Module\Icingadb\Widget\Detail\QuickActions; use Icinga\Module\Icingadb\Widget\Detail\ServiceDetail; use Icinga\Module\Icingadb\Widget\Detail\ServiceInspectionDetail; use Icinga\Module\Icingadb\Widget\Detail\ServiceMetaInfo; +use Icinga\Module\Icingadb\Widget\ItemList\LoadMoreObjectList; use Icinga\Module\Icingadb\Widget\ItemList\ObjectList; -use Icinga\Module\Icingadb\Widget\ItemList\HistoryList; use ipl\Orm\Query; use ipl\Sql\Expression; use ipl\Stdlib\Filter; @@ -313,7 +313,8 @@ class ServiceController extends Controller $this->addControl($limitControl); $this->addControl($viewModeSwitcher); - $historyList = (new HistoryList($history->execute())) + $historyList = (new LoadMoreObjectList($history->execute())) + ->setDetailUrl(Url::fromPath('icingadb/event')) ->setViewMode($viewModeSwitcher->getViewMode()) ->setPageSize($limitControl->getLimit()) ->setLoadMoreUrl($url->setParam('before', $before)); diff --git a/library/Icingadb/View/HistoryRenderer.php b/library/Icingadb/View/HistoryRenderer.php new file mode 100644 index 00000000..69846d1d --- /dev/null +++ b/library/Icingadb/View/HistoryRenderer.php @@ -0,0 +1,440 @@ + */ +class HistoryRenderer implements ItemRenderer +{ + use Translation; + use TicketLinks; + use HostLink; + use ServiceLink; + + public function assembleAttributes($item, Attributes $attributes, string $layout): void + { + $attributes->get('class')->addValue('history'); + } + + public function assembleVisual($item, HtmlDocument $visual, string $layout): void + { + $ballSize = StateBall::SIZE_LARGE; + if ($layout === 'minimal' || $layout === 'header') { + $ballSize = StateBall::SIZE_BIG; + } + + switch ($item->event_type) { + case 'comment_add': + $visual->addHtml( + HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::COMMENT) + ) + ); + + break; + case 'comment_remove': + case 'downtime_end': + case 'ack_clear': + $visual->addHtml( + HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::REMOVE) + ) + ); + + break; + case 'downtime_start': + $visual->addHtml( + HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::IN_DOWNTIME) + ) + ); + + break; + case 'ack_set': + $visual->addHtml( + HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::IS_ACKNOWLEDGED) + ) + ); + + 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 'notification': + $visual->addHtml( + HtmlElement::create( + 'div', + ['class' => ['icon-ball', 'ball-size-' . $ballSize]], + new Icon(Icons::NOTIFICATION) + ) + ); + + break; + case 'state_change': + if ($item->state->state_type === 'soft') { + $stateType = 'soft_state'; + $previousStateType = 'previous_soft_state'; + + if ($item->state->previous_soft_state === 0) { + $previousStateType = 'hard_state'; + } + + $visual->addHtml( + new CheckAttempt( + (int) $item->state->check_attempt, + (int) $item->state->max_check_attempts + ) + ); + } else { + $stateType = 'hard_state'; + $previousStateType = 'previous_hard_state'; + + if ($item->state->hard_state === $item->state->previous_hard_state) { + $previousStateType = 'previous_soft_state'; + } + } + + if ($item->object_type === 'host') { + $state = HostStates::text($item->state->$stateType); + $previousState = HostStates::text($item->state->$previousStateType); + } else { + $state = ServiceStates::text($item->state->$stateType); + $previousState = ServiceStates::text($item->state->$previousStateType); + } + + $stateChange = new StateChange($state, $previousState); + if ($stateType === 'soft_state') { + $stateChange->setCurrentStateBallSize(StateBall::SIZE_MEDIUM_LARGE); + } + + if ($previousStateType === 'previous_soft_state') { + $stateChange->setPreviousStateBallSize(StateBall::SIZE_MEDIUM_LARGE); + if ($stateType === 'soft_state') { + $visual->getAttributes()->add('class', 'small-state-change'); + } + } + + $visual->prependHtml($stateChange); + + break; + } + } + + public function assembleTitle($item, HtmlDocument $title, string $layout): void + { + switch ($item->event_type) { + case 'comment_add': + $subjectLabel = $this->translate('Comment added'); + + break; + case 'comment_remove': + if (! empty($item->comment->removed_by)) { + if ($item->comment->removed_by !== $item->comment->author) { + $subjectLabel = sprintf( + $this->translate('Comment removed by %s', '..'), + $item->comment->removed_by + ); + } else { + $subjectLabel = $this->translate('Comment removed by author'); + } + } elseif (isset($item->comment->expire_time)) { + $subjectLabel = $this->translate('Comment expired'); + } else { + $subjectLabel = $this->translate('Comment removed'); + } + + break; + case 'downtime_end': + if (! empty($item->downtime->cancelled_by)) { + if ($item->downtime->cancelled_by !== $item->downtime->author) { + $subjectLabel = sprintf( + $this->translate('Downtime cancelled by %s', '..'), + $item->downtime->cancelled_by + ); + } else { + $subjectLabel = $this->translate('Downtime cancelled by author'); + } + } elseif ($item->downtime->has_been_cancelled === 'y') { + $subjectLabel = $this->translate('Downtime cancelled'); + } else { + $subjectLabel = $this->translate('Downtime ended'); + } + + break; + case 'downtime_start': + $subjectLabel = $this->translate('Downtime started'); + + break; + case 'flapping_start': + $subjectLabel = $this->translate('Flapping started'); + + break; + case 'flapping_end': + $subjectLabel = $this->translate('Flapping stopped'); + + break; + case 'ack_set': + $subjectLabel = $this->translate('Acknowledgement set'); + + break; + case 'ack_clear': + if (! empty($item->acknowledgement->cleared_by)) { + if ($item->acknowledgement->cleared_by !== $item->acknowledgement->author) { + $subjectLabel = sprintf( + $this->translate('Acknowledgement cleared by %s', '..'), + $item->acknowledgement->cleared_by + ); + } else { + $subjectLabel = $this->translate('Acknowledgement cleared by author'); + } + } elseif (isset($item->acknowledgement->expire_time)) { + $subjectLabel = $this->translate('Acknowledgement expired'); + } else { + $subjectLabel = $this->translate('Acknowledgement cleared'); + } + + break; + case 'notification': + $subjectLabel = isset($item->notification->type) ? sprintf( + NotificationRenderer::phraseForType($item->notification->type), + ucfirst($item->object_type) + ) : $item->event_type; + + break; + case 'state_change': + $state = $item->state->state_type === 'hard' + ? $item->state->hard_state + : $item->state->soft_state; + if ($state === 0) { + if ($item->object_type === 'service') { + $subjectLabel = $this->translate('Service recovered'); + } else { + $subjectLabel = $this->translate('Host recovered'); + } + } else { + if ($item->state->state_type === 'hard') { + $subjectLabel = $this->translate('Hard state changed'); + } else { + $subjectLabel = $this->translate('Soft state changed'); + } + } + + break; + default: + $subjectLabel = $item->event_type; + + break; + } + + if ($layout === 'header') { + $title->addHtml(HtmlElement::create('span', ['class' => 'subject'], $subjectLabel)); + } else { + $title->addHtml(new Link($subjectLabel, Links::event($item), ['class' => 'subject'])); + } + + if ($item->object_type === 'host') { + if (isset($item->host->id)) { + $link = $this->createHostLink($item->host, true); + } + } else { + if (isset($item->host->id, $item->service->id)) { + $link = $this->createServiceLink($item->service, $item->host, true); + } + } + + $title->addHtml(Text::create(' ')); + if (isset($link)) { + $title->addHtml($link); + } + } + + public function assembleCaption($item, HtmlDocument $caption, string $layout): void + { + switch ($item->event_type) { + case 'comment_add': + case 'comment_remove': + $markdownLine = new MarkdownLine($this->createTicketLinks($item->comment->comment)); + $caption->getAttributes()->add($markdownLine->getAttributes()); + $caption->add([ + new Icon(Icons::USER), + $item->comment->author, + ': ' + ])->addFrom($markdownLine); + + break; + case 'downtime_end': + case 'downtime_start': + $markdownLine = new MarkdownLine($this->createTicketLinks($item->downtime->comment)); + $caption->getAttributes()->add($markdownLine->getAttributes()); + $caption->add([ + new Icon(Icons::USER), + $item->downtime->author, + ': ' + ])->addFrom($markdownLine); + + break; + case 'flapping_start': + $caption + ->add( + sprintf( + $this->translate('State Change Rate: %.2f%%; Start Threshold: %.2f%%'), + $item->flapping->percent_state_change_start, + $item->flapping->flapping_threshold_high + ) + ) + ->getAttributes() + ->add('class', 'plugin-output'); + + break; + case 'flapping_end': + $caption + ->add( + sprintf( + $this->translate('State Change Rate: %.2f%%; End Threshold: %.2f%%; Flapping for %s'), + $item->flapping->percent_state_change_end, + $item->flapping->flapping_threshold_low, + isset($item->flapping->end_time) + ? DateFormatter::formatDuration( + $item->flapping->end_time->getTimestamp() + - $item->flapping->start_time->getTimestamp() + ) + : $this->translate('n. a.') + ) + ) + ->getAttributes() + ->add('class', 'plugin-output'); + + break; + case 'ack_clear': + case 'ack_set': + if (! isset($item->acknowledgement->comment) && ! isset($item->acknowledgement->author)) { + $caption->addHtml( + new EmptyState( + $this->translate('This acknowledgement was set before Icinga DB history recording') + ) + ); + } else { + $markdownLine = new MarkdownLine($this->createTicketLinks($item->acknowledgement->comment)); + $caption->getAttributes()->add($markdownLine->getAttributes()); + $caption->add([ + new Icon(Icons::USER), + $item->acknowledgement->author, + ': ' + ])->addFrom($markdownLine); + } + + break; + case 'notification': + if (! empty($item->notification->author)) { + $caption->add([ + new Icon(Icons::USER), + $item->notification->author, + ': ', + $item->notification->text + ]); + } else { + $commandName = $item->object_type === 'host' + ? $item->host->checkcommand_name + : $item->service->checkcommand_name; + if (isset($commandName)) { + if (empty($item->notification->text)) { + $caption->addHtml(new EmptyState(t('Output unavailable.'))); + } else { + $caption->addHtml( + new PluginOutputContainer( + (new PluginOutput($item->notification->text)) + ->setCommandName($commandName) + ) + ); + } + } else { + $caption->addHtml( + new EmptyState($this->translate('Waiting for Icinga DB to synchronize the config.')) + ); + } + } + + break; + case 'state_change': + $commandName = $item->object_type === 'host' + ? $item->host->checkcommand_name + : $item->service->checkcommand_name; + if (isset($commandName)) { + if (empty($item->state->output)) { + $caption->addHtml(new EmptyState($this->translate('Output unavailable.'))); + } else { + $caption->addHtml( + new PluginOutputContainer( + (new PluginOutput($item->state->output)) + ->setCommandName($commandName) + ) + ); + } + } else { + $caption->addHtml( + new EmptyState($this->translate('Waiting for Icinga DB to synchronize the config.')) + ); + } + + break; + } + } + + public function assembleExtendedInfo($item, HtmlDocument $info, string $layout): void + { + $info->addHtml(new TimeAgo($item->event_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 + } +} diff --git a/library/Icingadb/Widget/Detail/ObjectHeader.php b/library/Icingadb/Widget/Detail/ObjectHeader.php index e95da021..d425db63 100644 --- a/library/Icingadb/Widget/Detail/ObjectHeader.php +++ b/library/Icingadb/Widget/Detail/ObjectHeader.php @@ -7,6 +7,7 @@ namespace Icinga\Module\Icingadb\Widget\Detail; use Icinga\Exception\NotImplementedError; use Icinga\Module\Icingadb\Model\Comment; use Icinga\Module\Icingadb\Model\Downtime; +use Icinga\Module\Icingadb\Model\History; use Icinga\Module\Icingadb\Model\Host; use Icinga\Module\Icingadb\Model\RedundancyGroup; use Icinga\Module\Icingadb\Model\Service; @@ -14,6 +15,7 @@ use Icinga\Module\Icingadb\Model\User; use Icinga\Module\Icingadb\Model\Usergroup; use Icinga\Module\Icingadb\View\CommentRenderer; use Icinga\Module\Icingadb\View\DowntimeRenderer; +use Icinga\Module\Icingadb\View\HistoryRenderer; use Icinga\Module\Icingadb\View\HostRenderer; use Icinga\Module\Icingadb\View\RedundancyGroupRenderer; use Icinga\Module\Icingadb\View\ServiceRenderer; @@ -65,6 +67,10 @@ class ObjectHeader extends BaseHtmlElement case $this->object instanceof Downtime: $renderer = new DowntimeRenderer(); + break; + case $this->object instanceof History: + $renderer = new HistoryRenderer(); + break; default: throw new NotImplementedError('Not implemented'); diff --git a/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php b/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php deleted file mode 100644 index 61da9fd1..00000000 --- a/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php +++ /dev/null @@ -1,407 +0,0 @@ -setNoSubjectLink($this->list->getNoSubjectLink()); - $this->setTicketLinkEnabled($this->list->getTicketLinkEnabled()); - $this->list->addDetailFilterAttribute($this, Filter::equal('id', bin2hex($this->item->id))); - } - - abstract protected function getStateBallSize(): string; - - protected function assembleCaption(BaseHtmlElement $caption): void - { - switch ($this->item->event_type) { - case 'comment_add': - case 'comment_remove': - $markdownLine = new MarkdownLine($this->createTicketLinks($this->item->comment->comment)); - $caption->getAttributes()->add($markdownLine->getAttributes()); - $caption->add([ - new Icon(Icons::USER), - $this->item->comment->author, - ': ' - ])->addFrom($markdownLine); - - break; - case 'downtime_end': - case 'downtime_start': - $markdownLine = new MarkdownLine($this->createTicketLinks($this->item->downtime->comment)); - $caption->getAttributes()->add($markdownLine->getAttributes()); - $caption->add([ - new Icon(Icons::USER), - $this->item->downtime->author, - ': ' - ])->addFrom($markdownLine); - - break; - case 'flapping_start': - $caption - ->add(sprintf( - t('State Change Rate: %.2f%%; Start Threshold: %.2f%%'), - $this->item->flapping->percent_state_change_start, - $this->item->flapping->flapping_threshold_high - )) - ->getAttributes() - ->add('class', 'plugin-output'); - - break; - case 'flapping_end': - $caption - ->add(sprintf( - t('State Change Rate: %.2f%%; End Threshold: %.2f%%; Flapping for %s'), - $this->item->flapping->percent_state_change_end, - $this->item->flapping->flapping_threshold_low, - isset($this->item->flapping->end_time) - ? DateFormatter::formatDuration( - $this->item->flapping->end_time->getTimestamp() - - $this->item->flapping->start_time->getTimestamp() - ) - : t('n. a.') - )) - ->getAttributes() - ->add('class', 'plugin-output'); - - break; - case 'ack_clear': - case 'ack_set': - if (! isset($this->item->acknowledgement->comment) && ! isset($this->item->acknowledgement->author)) { - $caption->addHtml(new EmptyState( - t('This acknowledgement was set before Icinga DB history recording') - )); - } else { - $markdownLine = new MarkdownLine($this->createTicketLinks($this->item->acknowledgement->comment)); - $caption->getAttributes()->add($markdownLine->getAttributes()); - $caption->add([ - new Icon(Icons::USER), - $this->item->acknowledgement->author, - ': ' - ])->addFrom($markdownLine); - } - - break; - case 'notification': - if (! empty($this->item->notification->author)) { - $caption->add([ - new Icon(Icons::USER), - $this->item->notification->author, - ': ', - $this->item->notification->text - ]); - } else { - $commandName = $this->item->object_type === 'host' - ? $this->item->host->checkcommand_name - : $this->item->service->checkcommand_name; - if (isset($commandName)) { - if (empty($this->item->notification->text)) { - $caption->addHtml(new EmptyState(t('Output unavailable.'))); - } else { - $caption->addHtml(new PluginOutputContainer( - (new PluginOutput($this->item->notification->text)) - ->setCommandName($commandName) - )); - } - } else { - $caption->addHtml(new EmptyState(t('Waiting for Icinga DB to synchronize the config.'))); - } - } - - break; - case 'state_change': - $commandName = $this->item->object_type === 'host' - ? $this->item->host->checkcommand_name - : $this->item->service->checkcommand_name; - if (isset($commandName)) { - if (empty($this->item->state->output)) { - $caption->addHtml(new EmptyState(t('Output unavailable.'))); - } else { - $caption->addHtml(new PluginOutputContainer( - (new PluginOutput($this->item->state->output)) - ->setCommandName($commandName) - )); - } - } else { - $caption->addHtml(new EmptyState(t('Waiting for Icinga DB to synchronize the config.'))); - } - - break; - } - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - switch ($this->item->event_type) { - case 'comment_add': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::COMMENT) - )); - - break; - case 'comment_remove': - case 'downtime_end': - case 'ack_clear': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::REMOVE) - )); - - break; - case 'downtime_start': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::IN_DOWNTIME) - )); - - break; - case 'ack_set': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::IS_ACKNOWLEDGED) - )); - - 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 'notification': - $visual->addHtml(HtmlElement::create( - 'div', - ['class' => ['icon-ball', 'ball-size-' . $this->getStateBallSize()]], - new Icon(Icons::NOTIFICATION) - )); - - break; - case 'state_change': - if ($this->item->state->state_type === 'soft') { - $stateType = 'soft_state'; - $previousStateType = 'previous_soft_state'; - - if ($this->item->state->previous_soft_state === 0) { - $previousStateType = 'hard_state'; - } - - $visual->addHtml(new CheckAttempt( - (int) $this->item->state->check_attempt, - (int) $this->item->state->max_check_attempts - )); - } else { - $stateType = 'hard_state'; - $previousStateType = 'previous_hard_state'; - - if ($this->item->state->hard_state === $this->item->state->previous_hard_state) { - $previousStateType = 'previous_soft_state'; - } - } - - if ($this->item->object_type === 'host') { - $state = HostStates::text($this->item->state->$stateType); - $previousState = HostStates::text($this->item->state->$previousStateType); - } else { - $state = ServiceStates::text($this->item->state->$stateType); - $previousState = ServiceStates::text($this->item->state->$previousStateType); - } - - $stateChange = new StateChange($state, $previousState); - if ($stateType === 'soft_state') { - $stateChange->setCurrentStateBallSize(StateBall::SIZE_MEDIUM_LARGE); - } - - if ($previousStateType === 'previous_soft_state') { - $stateChange->setPreviousStateBallSize(StateBall::SIZE_MEDIUM_LARGE); - if ($stateType === 'soft_state') { - $visual->getAttributes()->add('class', 'small-state-change'); - } - } - - $visual->prependHtml($stateChange); - - break; - } - } - - protected function assembleTitle(BaseHtmlElement $title): void - { - switch ($this->item->event_type) { - case 'comment_add': - $subjectLabel = t('Comment added'); - - break; - case 'comment_remove': - if (! empty($this->item->comment->removed_by)) { - if ($this->item->comment->removed_by !== $this->item->comment->author) { - $subjectLabel = sprintf( - t('Comment removed by %s', '..'), - $this->item->comment->removed_by - ); - } else { - $subjectLabel = t('Comment removed by author'); - } - } elseif (isset($this->item->comment->expire_time)) { - $subjectLabel = t('Comment expired'); - } else { - $subjectLabel = t('Comment removed'); - } - - break; - case 'downtime_end': - if (! empty($this->item->downtime->cancelled_by)) { - if ($this->item->downtime->cancelled_by !== $this->item->downtime->author) { - $subjectLabel = sprintf( - t('Downtime cancelled by %s', '..'), - $this->item->downtime->cancelled_by - ); - } else { - $subjectLabel = t('Downtime cancelled by author'); - } - } elseif ($this->item->downtime->has_been_cancelled === 'y') { - $subjectLabel = t('Downtime cancelled'); - } else { - $subjectLabel = t('Downtime ended'); - } - - break; - case 'downtime_start': - $subjectLabel = t('Downtime started'); - - break; - case 'flapping_start': - $subjectLabel = t('Flapping started'); - - break; - case 'flapping_end': - $subjectLabel = t('Flapping stopped'); - - break; - case 'ack_set': - $subjectLabel = t('Acknowledgement set'); - - break; - case 'ack_clear': - if (! empty($this->item->acknowledgement->cleared_by)) { - if ($this->item->acknowledgement->cleared_by !== $this->item->acknowledgement->author) { - $subjectLabel = sprintf( - t('Acknowledgement cleared by %s', '..'), - $this->item->acknowledgement->cleared_by - ); - } else { - $subjectLabel = t('Acknowledgement cleared by author'); - } - } elseif (isset($this->item->acknowledgement->expire_time)) { - $subjectLabel = t('Acknowledgement expired'); - } else { - $subjectLabel = t('Acknowledgement cleared'); - } - - break; - case 'notification': - $subjectLabel = isset($this->item->notification->type) ? sprintf( - NotificationListItem::phraseForType($this->item->notification->type), - ucfirst($this->item->object_type) - ) : $this->item->event_type; - - break; - case 'state_change': - $state = $this->item->state->state_type === 'hard' - ? $this->item->state->hard_state - : $this->item->state->soft_state; - if ($state === 0) { - if ($this->item->object_type === 'service') { - $subjectLabel = t('Service recovered'); - } else { - $subjectLabel = t('Host recovered'); - } - } else { - if ($this->item->state->state_type === 'hard') { - $subjectLabel = t('Hard state changed'); - } else { - $subjectLabel = t('Soft state changed'); - } - } - - break; - default: - $subjectLabel = $this->item->event_type; - - break; - } - - if ($this->getNoSubjectLink()) { - $title->addHtml(HtmlElement::create('span', ['class' => 'subject'], $subjectLabel)); - } else { - $title->addHtml(new Link($subjectLabel, Links::event($this->item), ['class' => 'subject'])); - } - - if ($this->item->object_type === 'host') { - if (isset($this->item->host->id)) { - $link = $this->createHostLink($this->item->host, true); - } - } else { - if (isset($this->item->host->id, $this->item->service->id)) { - $link = $this->createServiceLink($this->item->service, $this->item->host, true); - } - } - - $title->addHtml(Text::create(' ')); - if (isset($link)) { - $title->addHtml($link); - } - } - - protected function createTimestamp(): ?BaseHtmlElement - { - return new TimeAgo($this->item->event_time->getTimestamp()); - } -} diff --git a/library/Icingadb/Widget/ItemList/HistoryList.php b/library/Icingadb/Widget/ItemList/HistoryList.php deleted file mode 100644 index d3b62328..00000000 --- a/library/Icingadb/Widget/ItemList/HistoryList.php +++ /dev/null @@ -1,57 +0,0 @@ - 'history-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 HistoryListItemMinimal::class; - case 'detailed': - $this->removeAttribute('class', 'default-layout'); - - return HistoryListItemDetailed::class; - default: - return HistoryListItem::class; - } - } - - protected function assemble(): void - { - $this->addAttributes(['class' => $this->getViewMode()]); - - parent::assemble(); - } -} diff --git a/library/Icingadb/Widget/ItemList/HistoryListItem.php b/library/Icingadb/Widget/ItemList/HistoryListItem.php deleted file mode 100644 index c44a8076..00000000 --- a/library/Icingadb/Widget/ItemList/HistoryListItem.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/LoadMoreObjectList.php b/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php index 7044c8bb..81fb2df5 100644 --- a/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php +++ b/library/Icingadb/Widget/ItemList/LoadMoreObjectList.php @@ -6,7 +6,9 @@ namespace Icinga\Module\Icingadb\Widget\ItemList; use Icinga\Exception\NotImplementedError; use Icinga\Module\Icingadb\Common\LoadMore; +use Icinga\Module\Icingadb\Model\History; use Icinga\Module\Icingadb\Model\NotificationHistory; +use Icinga\Module\Icingadb\View\HistoryRenderer; use Icinga\Module\Icingadb\View\NotificationRenderer; use ipl\Orm\Model; use ipl\Web\Widget\ItemList; @@ -27,6 +29,8 @@ class LoadMoreObjectList extends ObjectList ItemList::__construct($data, function (Model $item) { if ($item instanceof NotificationHistory) { return new NotificationRenderer(); + } elseif ($item instanceof History) { + return new HistoryRenderer(); } throw new NotImplementedError('Not implemented'); diff --git a/library/Icingadb/Widget/ItemList/ObjectList.php b/library/Icingadb/Widget/ItemList/ObjectList.php index 1f1efa6b..c541b15d 100644 --- a/library/Icingadb/Widget/ItemList/ObjectList.php +++ b/library/Icingadb/Widget/ItemList/ObjectList.php @@ -9,6 +9,7 @@ use Icinga\Module\Icingadb\Common\DetailActions; use Icinga\Module\Icingadb\Model\Comment; use Icinga\Module\Icingadb\Model\DependencyNode; use Icinga\Module\Icingadb\Model\Downtime; +use Icinga\Module\Icingadb\Model\History; use Icinga\Module\Icingadb\Model\Host; use Icinga\Module\Icingadb\Model\NotificationHistory; use Icinga\Module\Icingadb\Model\RedundancyGroup; @@ -212,6 +213,11 @@ class ObjectList extends ItemList case $object instanceof NotificationHistory: $this->addDetailFilterAttribute($item, Filter::equal('id', bin2hex($object->history->id))); + break; + + case $object instanceof History: + $this->addDetailFilterAttribute($item, Filter::equal('id', bin2hex($object->id))); + break; } diff --git a/public/css/common.less b/public/css/common.less index d314d46e..3fc3e5d4 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -374,9 +374,9 @@ div.show-more { } } -.history-list, .header-item-layout.host, -.header-item-layout.service { +.header-item-layout.service, +.item-layout.history { .visual.small-state-change .state-change { padding-top: .25em; }