*/ class EventRenderer implements ItemRenderer { use Translation; use TicketLinks; use HostLink; use ServiceLink; /** @var NotificationRenderer To render NotificationHistory event */ protected $notificationRenderer; public function __construct() { $this->notificationRenderer = new NotificationRenderer(); } 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'; } if ($layout !== 'minimal' && $layout !== 'header') { $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 { if ($item->event_type === 'notification' && isset($item->notification->id)) { $item->notification->history = $item; $item->notification->host = $item->host; $item->notification->service = $item->service; $this->notificationRenderer->assembleTitle($item->notification, $title, $layout); return; } 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 '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' && isset($item->host->id)) { $link = $this->createHostLink($item->host, true); } elseif (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 { if ($item->event_type === 'notification') { $item->notification->host = $item->host; $item->notification->service = $item->service; $this->notificationRenderer->assembleCaption($item->notification, $caption, $layout); return; } 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 '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 } }