From fe39916ca0d637a7bcfc8ed8ef564be06bb88416 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 24 Feb 2022 17:28:18 +0100 Subject: [PATCH] Finally show previous states and current states properly --- .../Widget/ItemList/BaseHistoryListItem.php | 23 +++++++- .../Widget/ItemList/HostDetailHeader.php | 57 ++++++++++++------ .../Widget/ItemList/ServiceDetailHeader.php | 57 ++++++++++++------ .../Widget/ItemList/StateListItem.php | 30 +++++----- library/Icingadb/Widget/StateChange.php | 59 +++++++++++++++++-- public/css/common.less | 7 +++ public/css/widget/state-change.less | 24 +++++++- 7 files changed, 194 insertions(+), 63 deletions(-) diff --git a/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php b/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php index df11941f..51628169 100644 --- a/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php +++ b/library/Icingadb/Widget/ItemList/BaseHistoryListItem.php @@ -196,6 +196,11 @@ abstract class BaseHistoryListItem extends BaseListItem 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->attempt, @@ -203,21 +208,33 @@ abstract class BaseHistoryListItem extends BaseListItem )); } 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); - $previousSoftState = HostStates::text($this->item->state->previous_soft_state); + $previousState = HostStates::text($this->item->state->$previousStateType); } else { $state = ServiceStates::text($this->item->state->$stateType); - $previousSoftState = ServiceStates::text($this->item->state->previous_soft_state); + $previousState = ServiceStates::text($this->item->state->$previousStateType); } - $stateChange = new StateChange($state, $previousSoftState); + $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; diff --git a/library/Icingadb/Widget/ItemList/HostDetailHeader.php b/library/Icingadb/Widget/ItemList/HostDetailHeader.php index cc9552a5..0c90fea4 100644 --- a/library/Icingadb/Widget/ItemList/HostDetailHeader.php +++ b/library/Icingadb/Widget/ItemList/HostDetailHeader.php @@ -5,40 +5,59 @@ namespace Icinga\Module\Icingadb\Widget\ItemList; use Icinga\Module\Icingadb\Common\HostStates; -use ipl\Html\Attributes; +use Icinga\Module\Icingadb\Widget\CheckAttempt; +use Icinga\Module\Icingadb\Widget\StateChange; use ipl\Html\BaseHtmlElement; -use ipl\Html\HtmlElement; +use ipl\Web\Widget\Icon; use ipl\Web\Widget\StateBall; class HostDetailHeader extends HostListItemMinimal { protected function getStateBallSize(): string { - if ($this->state->state_type === 'soft') { - return StateBall::SIZE_MEDIUM_LARGE; - } - - return StateBall::SIZE_BIG; + return ''; } protected function assembleVisual(BaseHtmlElement $visual) { - parent::assembleVisual($visual); - - $isSoftState = false; if ($this->state->state_type === 'soft') { - $isSoftState = true; + $stateType = 'soft_state'; + $previousStateType = 'previous_soft_state'; + + if ($this->state->previous_soft_state === 0) { + $previousStateType = 'hard_state'; + } + } else { + $stateType = 'hard_state'; + $previousStateType = 'previous_hard_state'; + + if ($this->state->hard_state === $this->state->previous_hard_state) { + $previousStateType = 'previous_soft_state'; + } } - // When the current state type is a soft state change, then use the actual hard_state and not the prev. ones - $previousState = $isSoftState ? $this->state->hard_state : $this->state->previous_hard_state; - $previousHardState = HostStates::text($previousState); + $state = HostStates::text($this->state->$stateType); + $previousState = HostStates::text($this->state->$previousStateType); - $visual->getFirst('span')->addWrapper(new HtmlElement( - 'div', - Attributes::create(['class' => 'state-change']), - new StateBall($previousHardState, StateBall::SIZE_BIG) - )); + $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'); + } + } + + if ($this->state->is_handled) { + $currentStateBall = $stateChange->ensureAssembled()->getContent()[1]; + $currentStateBall->addHtml(new Icon($this->getHandledIcon())); + $currentStateBall->getAttributes()->add('class', 'handled'); + } + + $visual->addHtml($stateChange); } protected function assemble() diff --git a/library/Icingadb/Widget/ItemList/ServiceDetailHeader.php b/library/Icingadb/Widget/ItemList/ServiceDetailHeader.php index 1c477199..6036929b 100644 --- a/library/Icingadb/Widget/ItemList/ServiceDetailHeader.php +++ b/library/Icingadb/Widget/ItemList/ServiceDetailHeader.php @@ -5,40 +5,59 @@ namespace Icinga\Module\Icingadb\Widget\ItemList; use Icinga\Module\Icingadb\Common\ServiceStates; -use ipl\Html\Attributes; +use Icinga\Module\Icingadb\Widget\CheckAttempt; +use Icinga\Module\Icingadb\Widget\StateChange; use ipl\Html\BaseHtmlElement; -use ipl\Html\HtmlElement; +use ipl\Web\Widget\Icon; use ipl\Web\Widget\StateBall; class ServiceDetailHeader extends ServiceListItemMinimal { protected function getStateBallSize(): string { - if ($this->state->state_type === 'soft') { - return StateBall::SIZE_MEDIUM_LARGE; - } - - return StateBall::SIZE_BIG; + return ''; } protected function assembleVisual(BaseHtmlElement $visual) { - parent::assembleVisual($visual); - - $isSoftState = false; if ($this->state->state_type === 'soft') { - $isSoftState = true; + $stateType = 'soft_state'; + $previousStateType = 'previous_soft_state'; + + if ($this->state->previous_soft_state === 0) { + $previousStateType = 'hard_state'; + } + } else { + $stateType = 'hard_state'; + $previousStateType = 'previous_hard_state'; + + if ($this->state->hard_state === $this->state->previous_hard_state) { + $previousStateType = 'previous_soft_state'; + } } - // When the current state type is a soft state change, then use the actual hard_state and not the prev. ones - $previousState = $isSoftState ? $this->state->hard_state : $this->state->previous_hard_state; - $previousHardState = ServiceStates::text($previousState); + $state = ServiceStates::text($this->state->$stateType); + $previousState = ServiceStates::text($this->state->$previousStateType); - $visual->getFirst('span')->addWrapper(new HtmlElement( - 'div', - Attributes::create(['class' => 'state-change']), - new StateBall($previousHardState, StateBall::SIZE_BIG) - )); + $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'); + } + } + + if ($this->state->is_handled) { + $currentStateBall = $stateChange->ensureAssembled()->getContent()[1]; + $currentStateBall->addHtml(new Icon($this->getHandledIcon())); + $currentStateBall->getAttributes()->add('class', 'handled'); + } + + $visual->addHtml($stateChange); } protected function assemble() diff --git a/library/Icingadb/Widget/ItemList/StateListItem.php b/library/Icingadb/Widget/ItemList/StateListItem.php index 50c7395c..66289605 100644 --- a/library/Icingadb/Widget/ItemList/StateListItem.php +++ b/library/Icingadb/Widget/ItemList/StateListItem.php @@ -106,21 +106,7 @@ abstract class StateListItem extends BaseListItem $stateBall = new StateBall($this->state->getStateText(), $this->getStateBallSize()); if ($this->state->is_handled) { - switch (true) { - case $this->state->in_downtime: - $icon = Icons::IN_DOWNTIME; - break; - case $this->state->is_acknowledged: - $icon = Icons::IS_ACKNOWLEDGED; - break; - case $this->state->is_flapping: - $icon = Icons::IS_FLAPPING; - break; - default: - $icon = Icons::HOST_DOWN; - } - - $stateBall->addHtml(new Icon($icon)); + $stateBall->addHtml(new Icon($this->getHandledIcon())); $stateBall->getAttributes()->add('class', 'handled'); } @@ -142,6 +128,20 @@ abstract class StateListItem extends BaseListItem } } + protected function getHandledIcon(): string + { + switch (true) { + case $this->state->in_downtime: + return Icons::IN_DOWNTIME; + case $this->state->is_acknowledged: + return Icons::IS_ACKNOWLEDGED; + case $this->state->is_flapping: + return Icons::IS_FLAPPING; + default: + return Icons::HOST_DOWN; + } + } + protected function assemble() { if ($this->state->is_overdue) { diff --git a/library/Icingadb/Widget/StateChange.php b/library/Icingadb/Widget/StateChange.php index b4f83b3e..0bf4fa30 100644 --- a/library/Icingadb/Widget/StateChange.php +++ b/library/Icingadb/Widget/StateChange.php @@ -13,6 +13,8 @@ class StateChange extends BaseHtmlElement protected $state; + protected $previousStateBallSize = StateBall::SIZE_BIG; + protected $currentStateBallSize = StateBall::SIZE_BIG; protected $defaultAttributes = ['class' => 'state-change']; @@ -25,12 +27,18 @@ class StateChange extends BaseHtmlElement $this->state = $state; } - protected function assemble() + /** + * Set the state ball size for the previous state + * + * @param string $size + * + * @return $this + */ + public function setPreviousStateBallSize(string $size): self { - $this->add([ - new StateBall($this->previousState, StateBall::SIZE_BIG), - new StateBall($this->state, $this->currentStateBallSize) - ]); + $this->previousStateBallSize = $size; + + return $this; } /** @@ -46,4 +54,45 @@ class StateChange extends BaseHtmlElement return $this; } + + protected function assemble() + { + if ($this->isRightBiggerThanLeft()) { + $this->getAttributes()->add('class', 'reversed-state-balls'); + + $this->addHtml( + new StateBall($this->state, $this->currentStateBallSize), + new StateBall($this->previousState, $this->previousStateBallSize) + ); + } else { + $this->addHtml( + new StateBall($this->previousState, $this->previousStateBallSize), + new StateBall($this->state, $this->currentStateBallSize) + ); + } + } + + protected function isRightBiggerThanLeft(): bool + { + $left = $this->previousStateBallSize; + $right = $this->currentStateBallSize; + + if ($left === $right) { + return false; + } elseif ($left === StateBall::SIZE_LARGE) { + return false; + } + + $map = [ + StateBall::SIZE_BIG => [false, [StateBall::SIZE_LARGE]], + StateBall::SIZE_MEDIUM_LARGE => [false, [StateBall::SIZE_BIG, StateBall::SIZE_LARGE]], + StateBall::SIZE_MEDIUM => [true, [StateBall::SIZE_TINY, StateBall::SIZE_SMALL]], + StateBall::SIZE_SMALL => [true, [StateBall::SIZE_TINY]] + ]; + + list($negate, $sizes) = $map[$left]; + $found = in_array($right, $sizes, true); + + return ($negate && ! $found) || (! $negate && $found); + } } diff --git a/public/css/common.less b/public/css/common.less index 3dd29b06..2af00f0d 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -329,6 +329,13 @@ div.show-more { padding-right: .25em; } +.history-list, +.objectHeader { + .visual.small-state-change .state-change { + padding-top: .25em; + } +} + .comment-popup { .comment-list .main { border: none; diff --git a/public/css/widget/state-change.less b/public/css/widget/state-change.less index e1db8805..4cd5a1cc 100644 --- a/public/css/widget/state-change.less +++ b/public/css/widget/state-change.less @@ -1,10 +1,16 @@ .state-change { display: inline-flex; + &.reversed-state-balls { + // This is needed, because with ~ we can address only subsequent nodes + flex-direction: row-reverse; + } + .state-ball { .box-shadow(0, 0, 0, 1px, @body-bg-color); } + // Same on same .state-ball ~ .state-ball { &.ball-size-xs { margin-left: -.05em; @@ -18,20 +24,34 @@ margin-left: -.275em; } + &.ball-size-ml { + margin-left: -.375em; + } + &.ball-size-l, &.ball-size-xl { margin-left: -.875em; } } - .ball-size-l ~ .ball-size-ml { + // big left, smaller right + &:not(.reversed-state-balls) .ball-size-l ~ .state-ball { &.ball-size-ml { margin-top: .25em; - margin-left: -.375em; + margin-left: -.5em; margin-right: .25em; } } + // smaller left, big right + &.reversed-state-balls .ball-size-l ~ .state-ball { + &.ball-size-ml { + z-index: -1; + margin-top: .25em; + margin-right: -.5em; + } + } + .state-ball.state-ok, .state-ball.state-up { &.ball-size-l,