mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2025-12-27 17:49:35 -05:00
Redesign state badges for acknowledged nodes
Add and group state badges for acknowkedeged nodes based on state.
This commit is contained in:
parent
711677f903
commit
f0aae66544
8 changed files with 240 additions and 95 deletions
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
47
library/Businessprocess/Widget/StateBadge.php
Normal file
47
library/Businessprocess/Widget/StateBadge.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Widget;
|
||||
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
|
||||
class StateBadge extends BaseHtmlElement
|
||||
{
|
||||
protected $defaultAttributes = ['class' => '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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
60
public/css/state-badge.less
Normal file
60
public/css/state-badge.less
Normal file
|
|
@ -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%);
|
||||
}
|
||||
}
|
||||
27
public/css/state-badges.less
Normal file
27
public/css/state-badges.less
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue