From f0aae665448c003cde00951fa913aacdd76f121a Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Mon, 13 Sep 2021 16:11:51 +0200 Subject: [PATCH] Redesign state badges for acknowledged nodes Add and group state badges for acknowkedeged nodes based on state. --- configuration.php | 3 + library/Businessprocess/BpNode.php | 36 ++++++--- library/Businessprocess/Renderer/Renderer.php | 77 +++++++++++++------ .../Renderer/TileRenderer/NodeTile.php | 19 +---- library/Businessprocess/Widget/StateBadge.php | 47 +++++++++++ public/css/module.less | 66 +++++----------- public/css/state-badge.less | 60 +++++++++++++++ public/css/state-badges.less | 27 +++++++ 8 files changed, 240 insertions(+), 95 deletions(-) create mode 100644 library/Businessprocess/Widget/StateBadge.php create mode 100644 public/css/state-badge.less create mode 100644 public/css/state-badges.less diff --git a/configuration.php b/configuration.php index 4615bd4..b1b0a9f 100644 --- a/configuration.php +++ b/configuration.php @@ -59,3 +59,6 @@ $this->provideRestriction( $this->provideJsFile('vendor/Sortable.js'); $this->provideJsFile('behavior/sortable.js'); $this->provideJsFile('vendor/jquery.fn.sortable.js'); + +$this->provideCssFile('state-badge.less'); +$this->provideCssFile('state-badges.less'); diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 6944f09..ba42cb7 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -30,15 +30,15 @@ class BpNode extends Node protected $stateOverrides = []; protected static $emptyStateSummary = array( - 'OK' => 0, - 'WARNING' => 0, - 'CRITICAL' => 0, - 'UNKNOWN' => 0, - 'PENDING' => 0, - 'UP' => 0, - 'DOWN' => 0, - 'UNREACHABLE' => 0, - 'MISSING' => 0, + 'CRITICAL' => 0, + 'CRITICAL-HANDLED' => 0, + 'WARNING' => 0, + 'WARNING-HANDLED' => 0, + 'UNKNOWN' => 0, + 'UNKNOWN-HANDLED' => 0, + 'OK' => 0, + 'PENDING' => 0, + 'MISSING' => 0, ); protected static $sortStateInversionMap = array( @@ -74,7 +74,23 @@ class BpNode extends Node $this->counters['MISSING']++; } else { $state = $child->getStateName($this->getChildState($child)); - $this->counters[$state]++; + if ($child->isHandled()) { + $state = $state . '-HANDLED'; + } + + if ($state === 'DOWN') { + $this->counters['CRITICAL']++; + } elseif ($state === 'DOWN-HANDLED') { + $this->counters['CRITICAL-HANDLED']++; + } elseif ($state === 'UNREACHABLE') { + $this->counters['UNKNOWN']++; + } elseif ($state === 'UNREACHABLE-HANDLED') { + $this->counters['UNKNOWN-HANDLED']++; + } elseif ($state === 'UP') { + $this->counters['OK']++; + } else { + $this->counters[$state]++; + } } } } diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 35e3225..a659fe6 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -9,6 +9,7 @@ use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Url; +use Icinga\Module\Businessprocess\Widget\StateBadge; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\HtmlDocument; @@ -135,34 +136,39 @@ abstract class Renderer extends HtmlDocument * @param $summary * @return BaseHtmlElement */ - public function renderStateBadges($summary) + public function renderStateBadges($summary, $totalChildren) { $elements = []; - foreach ($summary as $state => $cnt) { - if ($cnt === 0 - || $state === 'OK' - || $state === 'UP' - ) { - continue; - } - - $elements[] = Html::tag( - 'span', - [ - 'class' => [ - 'badge', - 'badge-' . strtolower($state) - ], - // TODO: We should translate this in this module - 'title' => mt('monitoring', $state) + $itemCount = Html::tag( + 'span', + [ + 'class' => [ + 'item-count', ], - $cnt - ); - } + 'title' => sprintf('%u %s', $totalChildren, mtp( + 'businessprocess', + 'Child', + 'Children', + $totalChildren, + 'businessprocess.nodes' + )) + ], + $totalChildren + ); + + $elements[] = array_filter([ + $this->createBadgeGroup($summary, 'CRITICAL'), + $this->createBadgeGroup($summary, 'UNKNOWN'), + $this->createBadgeGroup($summary, 'WARNING'), + $this->createBadge($summary, 'OK'), + $this->createBadge($summary, 'MISSING'), + $this->createBadge($summary, 'PENDING') + ]); if (!empty($elements)) { - $container = Html::tag('div', ['class' => 'badges']); + $container = Html::tag('ul', ['class' => 'state-badges']); + $container->add($itemCount); foreach ($elements as $element) { $container->add($element); } @@ -172,6 +178,33 @@ abstract class Renderer extends HtmlDocument return null; } + protected function createBadge($summary, $state) + { + if ($summary[$state] !== 0) { + return Html::tag('li', new StateBadge($summary[$state], $state)); + } + + return null; + } + + protected function createBadgeGroup($summary, $state) + { + $content = []; + if ($summary[$state] !== 0) { + $content[] = Html::tag('li', new StateBadge($summary[$state], $state)); + } + + if ($summary[$state . '-HANDLED'] !== 0) { + $content[] = Html::tag('li', new StateBadge($summary[$state . '-HANDLED'], $state, true)); + } + + if (empty($content)) { + return null; + } + + return Html::tag('li', Html::tag('ul', $content)); + } + public function getNodeClasses(Node $node) { if ($node->isMissing()) { diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 261b6cd..67bb4a6 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -129,24 +129,7 @@ class NodeTile extends BaseHtmlElement } if ($node instanceof BpNode && !$renderer->isBreadcrumb()) { - $this->add(Html::tag( - 'p', - ['class' => 'children-count'], - $node->hasChildren() - ? Html::tag( - 'span', - null, - sprintf('%u %s', $node->countChildren(), mtp( - 'businessprocess', - 'Child', - 'Children', - $node->countChildren(), - 'businessprocess.nodes' - )) - ) - : null - )); - $this->add($renderer->renderStateBadges($node->getStateSummary())); + $this->add($renderer->renderStateBadges($node->getStateSummary(), $node->countChildren())); } return parent::render(); diff --git a/library/Businessprocess/Widget/StateBadge.php b/library/Businessprocess/Widget/StateBadge.php new file mode 100644 index 0000000..783940a --- /dev/null +++ b/library/Businessprocess/Widget/StateBadge.php @@ -0,0 +1,47 @@ + 'state-badge']; + + /** @var mixed Badge content */ + protected $content; + + /** @var bool Whether the state is handled */ + protected $isHandled; + + /** @var string Textual representation of a state */ + protected $state; + + /** + * Create a new state badge + * + * @param mixed $content Content of the badge + * @param string $state Textual representation of a state + * @param bool $isHandled True if state is handled + */ + public function __construct($content, $state, $isHandled = false, $group = false) + { + $this->content = $content; + $this->isHandled = $isHandled; + $this->state = strtolower($state); + } + + protected function assemble() + { + $this->setTag('span'); + + $class = "state-{$this->state}"; + if ($this->isHandled) { + $class .= ' handled'; + } + + $this->addAttributes(['class' => $class]); + + $this->add($this->content); + } +} diff --git a/public/css/module.less b/public/css/module.less index 78617c5..0089bef 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -330,19 +330,6 @@ ul.bp { } } } - - .badge { - margin-top: 0.25em; - text-decoration: none; - - &:last-child { - margin-right: 0; - } - - &:hover { - box-shadow: 0px 0px 5px @gray-light; - } - } } .dashboard-tile, @@ -376,35 +363,31 @@ ul.bp { } /** END Dashboard **/ -/** BEGIN Badges **/ -.badges { - background-color: fade(@body-bg-color, 50%); - border-radius: 0.45em; - display: block; - padding: 0.3em 0.4em; - - .badge { - border: 1px solid @body-bg-color; - margin: 0; - } +// State summary badges +.state-badges { + .state-badges(); } -div.bp .badges { +// Node children count +.item-count { + font-size: 1em; + text-align: center; + color: @text-color-inverted; +} + +div.bp .state-badges { display: inline-block; padding-top: 0; } - - -td > a > .badges { +td > a > .state-badges { background-color: transparent; } -.badge-critical, .badge-down { background: @color-critical; } -.badge-unknown, .badge-unreachable { background: @color-unknown; } -.badge-warning { background: @color-warning } -.badge-pending { background: @color-pending } -.badge-missing { background: @gray-semilight; color: @text-color-on-icinga-blue; } +.state-badge.state-missing { + background: @gray-semilight; + color: @text-color-on-icinga-blue; +} /** END Badges **/ /** BEGIN Tiles **/ @@ -431,7 +414,11 @@ td > a > .badges { cursor: pointer; position: relative; - .badges { + .item-count { + margin-right: .5em; + } + + .state-badges { position: absolute; bottom: 0; right: 0; @@ -457,17 +444,6 @@ td > a > .badges { padding: 1em 1em 0; font-weight: bold; word-wrap: break-word; - - & + p.children-count { - margin: 0; - font-size: .5em; - text-align: center; - - span { - font-size: .8em; - font-weight: bold; - } - } } &:hover { diff --git a/public/css/state-badge.less b/public/css/state-badge.less new file mode 100644 index 0000000..9768cb8 --- /dev/null +++ b/public/css/state-badge.less @@ -0,0 +1,60 @@ +.state-badge { + .rounded-corners(); + color: @text-color-on-icinga-blue; + display: inline-block; + font-size: .8em; + min-width: 2em; + padding: .25em; + text-align: center; + border: 1px solid black; + + &.state-critical { + background-color: @color-critical + } + + &.state-critical.handled { + background-color: @color-critical-handled + } + + &.state-down { + background-color: @color-down + } + + &.state-down.handled { + background-color: @color-down-handled + } + + &.state-ok { + background-color: @color-ok + } + + &.state-pending { + background-color: @color-pending + } + + &.state-unknown { + background-color: @color-unknown + } + + &.state-unknown.handled { + background-color: @color-unknown-handled + } + + &.state-up { + background-color: @color-up + } + + &.state-warning { + background-color: @color-warning + } + + &.state-warning.handled { + background-color: @color-warning-handled + } +} + +a .state-badge { + &:hover { + filter: brightness(80%); + } +} diff --git a/public/css/state-badges.less b/public/css/state-badges.less new file mode 100644 index 0000000..570af1f --- /dev/null +++ b/public/css/state-badges.less @@ -0,0 +1,27 @@ +.state-badges() { + &.state-badges { + padding: 0; + + ul { + padding: 0; + } + + li { + display: inline-block; + } + + li > ul > li:first-child:not(:last-child) .state-badge { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + + li > ul > li:last-child:not(:first-child) .state-badge { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + } + + > li:not(:last-child) { + margin-right: .25em; + } + } +}