mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-05-28 04:36:06 -04:00
Introduce HistoryRenderer
- Remove now obsolete ItemList classes
This commit is contained in:
parent
3252ff8925
commit
183d5ee7ba
14 changed files with 470 additions and 545 deletions
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
440
library/Icingadb/View/HistoryRenderer.php
Normal file
440
library/Icingadb/View/HistoryRenderer.php
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2025 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\View;
|
||||
|
||||
use Icinga\Date\DateFormatter;
|
||||
use Icinga\Module\Icingadb\Common\HostLink;
|
||||
use Icinga\Module\Icingadb\Common\HostStates;
|
||||
use Icinga\Module\Icingadb\Common\Icons;
|
||||
use Icinga\Module\Icingadb\Common\Links;
|
||||
use Icinga\Module\Icingadb\Common\ServiceLink;
|
||||
use Icinga\Module\Icingadb\Common\ServiceStates;
|
||||
use Icinga\Module\Icingadb\Common\TicketLinks;
|
||||
use Icinga\Module\Icingadb\Model\History;
|
||||
use Icinga\Module\Icingadb\Util\PluginOutput;
|
||||
use Icinga\Module\Icingadb\Widget\CheckAttempt;
|
||||
use Icinga\Module\Icingadb\Widget\MarkdownLine;
|
||||
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
|
||||
use Icinga\Module\Icingadb\Widget\StateChange;
|
||||
use ipl\Html\Attributes;
|
||||
use ipl\Html\HtmlDocument;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\Text;
|
||||
use ipl\I18n\Translation;
|
||||
use ipl\Web\Common\ItemRenderer;
|
||||
use ipl\Web\Widget\EmptyState;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use ipl\Web\Widget\Link;
|
||||
use ipl\Web\Widget\StateBall;
|
||||
use ipl\Web\Widget\TimeAgo;
|
||||
|
||||
/** @implements ItemRenderer<History> */
|
||||
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', '..<username>'),
|
||||
$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', '..<username>'),
|
||||
$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', '..<username>'),
|
||||
$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
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -1,407 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Date\DateFormatter;
|
||||
use Icinga\Module\Icingadb\Common\HostLink;
|
||||
use Icinga\Module\Icingadb\Common\HostStates;
|
||||
use Icinga\Module\Icingadb\Common\Icons;
|
||||
use Icinga\Module\Icingadb\Common\Links;
|
||||
use Icinga\Module\Icingadb\Common\NoSubjectLink;
|
||||
use Icinga\Module\Icingadb\Common\TicketLinks;
|
||||
use Icinga\Module\Icingadb\Widget\MarkdownLine;
|
||||
use Icinga\Module\Icingadb\Common\ServiceLink;
|
||||
use Icinga\Module\Icingadb\Common\ServiceStates;
|
||||
use Icinga\Module\Icingadb\Model\History;
|
||||
use Icinga\Module\Icingadb\Util\PluginOutput;
|
||||
use Icinga\Module\Icingadb\Widget\CheckAttempt;
|
||||
use Icinga\Module\Icingadb\Widget\PluginOutputContainer;
|
||||
use Icinga\Module\Icingadb\Widget\StateChange;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Web\Common\BaseListItem;
|
||||
use ipl\Web\Widget\EmptyState;
|
||||
use ipl\Web\Widget\StateBall;
|
||||
use ipl\Web\Widget\TimeAgo;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\Text;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
abstract class BaseHistoryListItem extends BaseListItem
|
||||
{
|
||||
use HostLink;
|
||||
use NoSubjectLink;
|
||||
use ServiceLink;
|
||||
use TicketLinks;
|
||||
|
||||
/** @var History */
|
||||
protected $item;
|
||||
|
||||
/** @var HistoryList */
|
||||
protected $list;
|
||||
|
||||
protected function init(): void
|
||||
{
|
||||
$this->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', '..<username>'),
|
||||
$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', '..<username>'),
|
||||
$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', '..<username>'),
|
||||
$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());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\CaptionDisabled;
|
||||
use Icinga\Module\Icingadb\Common\DetailActions;
|
||||
use Icinga\Module\Icingadb\Common\LoadMore;
|
||||
use Icinga\Module\Icingadb\Common\NoSubjectLink;
|
||||
use Icinga\Module\Icingadb\Common\TicketLinks;
|
||||
use Icinga\Module\Icingadb\Common\ViewMode;
|
||||
use ipl\Orm\ResultSet;
|
||||
use ipl\Web\Common\BaseItemList;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class HistoryList extends BaseItemList
|
||||
{
|
||||
use CaptionDisabled;
|
||||
use NoSubjectLink;
|
||||
use ViewMode;
|
||||
use LoadMore;
|
||||
use TicketLinks;
|
||||
use DetailActions;
|
||||
|
||||
protected $defaultAttributes = ['class' => '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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\ListItemCommonLayout;
|
||||
use ipl\Web\Widget\StateBall;
|
||||
|
||||
class HistoryListItem extends BaseHistoryListItem
|
||||
{
|
||||
use ListItemCommonLayout;
|
||||
|
||||
protected function getStateBallSize(): string
|
||||
{
|
||||
return StateBall::SIZE_LARGE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\ListItemDetailedLayout;
|
||||
use ipl\Web\Widget\StateBall;
|
||||
|
||||
class HistoryListItemDetailed extends BaseHistoryListItem
|
||||
{
|
||||
use ListItemDetailedLayout;
|
||||
|
||||
protected function getStateBallSize(): string
|
||||
{
|
||||
return StateBall::SIZE_LARGE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\ListItemMinimalLayout;
|
||||
use ipl\Web\Widget\StateBall;
|
||||
|
||||
class HistoryListItemMinimal extends BaseHistoryListItem
|
||||
{
|
||||
use ListItemMinimalLayout;
|
||||
|
||||
protected function init(): void
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if ($this->list->isCaptionDisabled()) {
|
||||
$this->setCaptionDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getStateBallSize(): string
|
||||
{
|
||||
return StateBall::SIZE_BIG;
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue