diff --git a/modules/monitoring/application/controllers/HostsController.php b/modules/monitoring/application/controllers/HostsController.php index 5dc72eeb05..1586ad723d 100644 --- a/modules/monitoring/application/controllers/HostsController.php +++ b/modules/monitoring/application/controllers/HostsController.php @@ -77,7 +77,8 @@ public function showAction() count($this->hostList) ), 'label' => $this->translate('Hosts'), - 'url' => Url::fromRequest() + 'url' => Url::fromRequest(), + 'icon' => 'host' ) )->activate('show'); $this->setAutorefreshInterval(15); diff --git a/modules/monitoring/application/controllers/ServicesController.php b/modules/monitoring/application/controllers/ServicesController.php index 1e907aab9a..ceabd643e5 100644 --- a/modules/monitoring/application/controllers/ServicesController.php +++ b/modules/monitoring/application/controllers/ServicesController.php @@ -10,6 +10,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\ServiceList; @@ -28,6 +29,19 @@ public function init() $serviceList = new ServiceList($this->backend); $serviceList->setFilter(Filter::fromQueryString((string) $this->params->without('service_problem', 'service_handled'))); $this->serviceList = $serviceList; + $this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/services'); + $this->getTabs()->add( + 'show', + array( + 'title' => sprintf( + $this->translate('Show summarized information for %u services'), + count($this->serviceList) + ), + 'label' => $this->translate('Services'), + 'url' => Url::fromRequest(), + 'icon' => 'services' + ) + )->activate('show'); } protected function handleCommandForm(ObjectsCommandForm $form) @@ -40,7 +54,11 @@ protected function handleCommandForm(ObjectsCommandForm $form) 'service_problem', 'service_handled', 'service_acknowledged', - 'service_in_downtime' + 'service_in_downtime', + 'service_is_flapping', + 'service_notifications_enabled', + 'service_output', + 'service_last_ack' )); $form @@ -90,17 +108,6 @@ protected function handleCommandForm(ObjectsCommandForm $form) public function showAction() { - $this->getTabs()->add( - 'show', - array( - 'title' => sprintf( - $this->translate('Show summarized information for %u services'), - count($this->serviceList) - ), - 'label' => $this->translate('Services'), - 'url' => Url::fromRequest() - ) - )->activate('show'); $this->setAutorefreshInterval(15); $checkNowForm = new CheckNowCommandForm(); $checkNowForm @@ -109,15 +116,21 @@ public function showAction() $this->view->checkNowForm = $checkNowForm; $this->serviceList->setColumns(array( 'host_name', + 'host_output', 'host_state', + 'service_output', 'service_description', 'service_state', 'service_problem', 'service_handled', 'service_acknowledged', - 'service_in_downtime'/*, - 'service_passive_checks_enabled', + 'service_in_downtime', + 'service_is_flapping', 'service_notifications_enabled', + 'service_last_comment', + 'service_last_ack' + /*, + 'service_passive_checks_enabled', 'service_event_handler_enabled', 'service_flap_detection_enabled', 'service_active_checks_enabled', @@ -129,22 +142,34 @@ public function showAction() $objectsInDowntime = array(); $downtimeFilterExpressions = array(); $serviceStates = array( - Service::getStateText(Service::STATE_OK) => 0, - Service::getStateText(Service::STATE_WARNING) => 0, - Service::getStateText(Service::STATE_CRITICAL) => 0, - Service::getStateText(Service::STATE_UNKNOWN) => 0, - Service::getStateText(Service::STATE_PENDING) => 0 + 'services_' . Service::getStateText(Service::STATE_OK) => 0, + 'services_' . Service::getStateText(Service::STATE_OK) . '_unhandled' => 0, + 'services_' . Service::getStateText(Service::STATE_WARNING) => 0, + 'services_' . Service::getStateText(Service::STATE_WARNING) . '_unhandled' => 0, + 'services_' . Service::getStateText(Service::STATE_CRITICAL) => 0, + 'services_' . Service::getStateText(Service::STATE_CRITICAL) . '_unhandled' => 0, + 'services_' . Service::getStateText(Service::STATE_UNKNOWN) => 0, + 'services_' . Service::getStateText(Service::STATE_UNKNOWN) . '_unhandled' => 0, + 'services_' . Service::getStateText(Service::STATE_PENDING) => 0, + 'services_' . Service::getStateText(Service::STATE_PENDING) . '_unhandled' => 0 ); $knownHostStates = array(); $hostStates = array( - Host::getStateText(Host::STATE_UP) => 0, - Host::getStateText(Host::STATE_DOWN) => 0, - Host::getStateText(Host::STATE_UNREACHABLE) => 0, - Host::getStateText(Host::STATE_PENDING) => 0, + 'hosts_' . Host::getStateText(Host::STATE_UP) => 0, + 'hosts_' . Host::getStateText(Host::STATE_UP) . '_unhandled' => 0, + 'hosts_' . Host::getStateText(Host::STATE_DOWN) => 0, + 'hosts_' . Host::getStateText(Host::STATE_DOWN) . '_unhandled' => 0, + 'hosts_' . Host::getStateText(Host::STATE_UNREACHABLE) => 0, + 'hosts_' . Host::getStateText(Host::STATE_UNREACHABLE) . '_unhandled' => 0, + 'hosts_' . Host::getStateText(Host::STATE_PENDING) => 0, + 'hosts_' . Host::getStateText(Host::STATE_PENDING) . '_unhandled' => 0 ); foreach ($this->serviceList as $service) { + $unhandled = false; + /** @var Service $service */ if ((bool) $service->problem === true && (bool) $service->handled === false) { + $unhandled = true; $unhandledObjects[] = $service; $unhandledFilterExpressions[] = Filter::matchAll( Filter::where('host', $service->getHost()->getName()), @@ -161,10 +186,11 @@ public function showAction() Filter::where('downtime_service', $service->getName()) ); } - ++$serviceStates[$service::getStateText($service->state)]; + + ++$serviceStates['services_' . $service::getStateText($service->state) . ($unhandled ? '_unhandled' : '')]; if (! isset($knownHostStates[$service->getHost()->getName()])) { $knownHostStates[$service->getHost()->getName()] = true; - ++$hostStates[$service->getHost()->getStateText($service->host_state)]; + ++$hostStates['hosts_' . $service->getHost()->getStateText($service->host_state)]; } } if (! empty($acknowledgedObjects)) { @@ -174,15 +200,20 @@ public function showAction() ->handleRequest(); $this->view->removeAckForm = $removeAckForm; } + if (! empty($objectsInDowntime)) { + $removeDowntimeForm = new DeleteDowntimeCommandForm(); + $removeDowntimeForm->setObjects($objectsInDowntime) + ->handleRequest(); + $this->view->removeDowntimeForm = $removeDowntimeForm; + } $this->setAutorefreshInterval(15); - $this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/services'); $this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/services/reschedule-check'); $this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/services/schedule-downtime'); $this->view->processCheckResultAllLink = Url::fromRequest()->setPath( 'monitoring/services/process-check-result' ); - $this->view->hostStates = $hostStates; - $this->view->serviceStates = $serviceStates; + $this->view->hostStates = (object)$hostStates; + $this->view->serviceStates = (object)$serviceStates; $this->view->objects = $this->serviceList; $this->view->unhandledObjects = $unhandledObjects; $unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString(); @@ -196,6 +227,7 @@ public function showAction() ->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString()); $this->view->commentsLink = Url::fromRequest() ->setPath('monitoring/list/comments'); + /* $this->view->serviceStatesPieChart = $this->createPieChart( $serviceStates, $this->translate('Service State'), @@ -206,6 +238,7 @@ public function showAction() $this->translate('Host State'), array('#44bb77', '#FF5566', '#E066FF', '#77AAFF') ); + */ } protected function createPieChart(array $states, $title, array $colors) diff --git a/modules/monitoring/application/views/scripts/partials/command/objects-command-form.phtml b/modules/monitoring/application/views/scripts/partials/command/objects-command-form.phtml index d387202c27..ece0aea34c 100644 --- a/modules/monitoring/application/views/scripts/partials/command/objects-command-form.phtml +++ b/modules/monitoring/application/views/scripts/partials/command/objects-command-form.phtml @@ -1,31 +1,19 @@
+ + compact): ?> + + + +

translate('%d Services Selected'), count($objects)) ?>

render('partials/service/objects-header.phtml'); ?> +

translate('%d Hosts Selected'), count($objects)) ?>

render('partials/host/objects-header.phtml'); ?>
+
- - - - - - - - - getObjects() as $object): /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ ?> - - getType() === $object::TYPE_HOST): ?> - - - - - - - - -
icon('host'); ?> translate('Host'); ?>icon('conf'); ?> translate('Service'); ?>
escape($object->getName()); ?>escape($object->getHost()->getName()); ?>escape($object->getName()); ?>

diff --git a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml index f892df6f49..448be4c02c 100644 --- a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml @@ -1,6 +1,7 @@ compact): ?> + 0): ?>

@@ -15,4 +16,4 @@ translate(strtoupper($text)), $count); ?>

- \ No newline at end of file + diff --git a/modules/monitoring/application/views/scripts/partials/host/servicesummary.phtml b/modules/monitoring/application/views/scripts/partials/host/servicesummary.phtml index c0acdead4a..bdd4d9af7b 100644 --- a/modules/monitoring/application/views/scripts/partials/host/servicesummary.phtml +++ b/modules/monitoring/application/views/scripts/partials/host/servicesummary.phtml @@ -31,6 +31,7 @@ $currentUrl = Url::fromRequest()->without('limit')->getRelativeUrl(); translate('No services configured on this host'); ?> + stats->services_ok): ?> diff --git a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml index 6389d992fd..113e7c0a06 100644 --- a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml @@ -1,34 +1,85 @@ -compact): ?> - - + + + 0): ?> -
-
-

- translatePlural('Service (%u)', 'Services (%u)', $serviceCount), $serviceCount); ?> -

-
-
-   -
-
- $count): ?> - translate(strtoupper($text)), $count); ?>
- -
-
-
-
- - translatePlural('Host (%u)', 'Hosts (%u)', $hostCount), $hostCount); ?> -
-
-   -
-
- $count): ?> - translate(strtoupper($text)), $count); ?>
- -
-
- \ No newline at end of file +

+ + + + + + + + + + + + + + 5) { + $desc = $service->getHost()->getName() . ' on ' . $service->getName(); + $hidden[] = $desc; + $hiddenRich[] = sprintf("
%s", $service->getStateText($service->service_state) ,$desc); + continue; + } + ?> + + + + + + + + + + + + + + + + + +
icon('service'); ?> translate('Service'); ?>icon('host'); ?> translate('Host'); ?>translate('Output'); ?>
service_state, true); ?>
+ service_handled && $service->service_state > 0): ?> + icon('attention-alt', $this->translate('Unhandled')) ?> + + + service_acknowledged && !$service->service_in_downtime): ?> + icon('ok', $this->translate('Acknowledged') . ( + $service->service_last_ack ? ': ' . $service->service_last_ack : '' + )) ?> + + + service_is_flapping): ?> + icon('flapping', $this->translate('Flapping')) ?> + + + service_notifications_enabled): ?> + icon('bell-off-empty', $this->translate('Notifications Disabled')) ?> + + + service_in_downtime): ?> + icon('plug', $this->translate('In Downtime')) ?> + + + service_last_comment) && $service->service_last_comment !== null): ?> + icon('comment', $this->translate('Last Comment: ') . $service->service_last_comment) ?> + + escape($service->getName()); ?>escape($service->getHost()->getName()); ?>

escape($service->service_output) ?>

+
+ +
+
+

+ diff --git a/modules/monitoring/application/views/scripts/partials/service/objects-tinysummary.phtml b/modules/monitoring/application/views/scripts/partials/service/objects-tinysummary.phtml new file mode 100644 index 0000000000..7707651d2b --- /dev/null +++ b/modules/monitoring/application/views/scripts/partials/service/objects-tinysummary.phtml @@ -0,0 +1,42 @@ + + +

+ qlink( + sprintf($this->translate('%d Services Selected:'), count($objects)), + $listAllLink + ); ?> + + + services_ok): ?> + + + services_ok ?> + + + + 'critical', + 3 => 'unknown', + 1 => 'warning', + 4 => 'pending' + ) as $stateId => $state) { + + $stateName = 'services_' . $state; + $unhandledStateName = $stateName . '_unhandled'; + if ($serviceStates->$unhandledStateName) { + echo '' . $serviceStates->$unhandledStateName . ''; + } + if ($serviceStates->$stateName) { + echo '' . $serviceStates->$stateName . ''; + } + if ($serviceStates->$unhandledStateName) { + echo ''; + } + $stateName .= '_unhandled'; + }?> + +

\ No newline at end of file diff --git a/modules/monitoring/application/views/scripts/services/show.phtml b/modules/monitoring/application/views/scripts/services/show.phtml index 015fecb958..9dc8650100 100644 --- a/modules/monitoring/application/views/scripts/services/show.phtml +++ b/modules/monitoring/application/views/scripts/services/show.phtml @@ -1,47 +1,66 @@ + +
+ + compact): ?> + + + + render('partials/service/objects-tinysummary.phtml') ?> render('partials/service/objects-header.phtml'); ?> +
- translate('No services matching the filter'); ?> + translate('No services matching the filter'); ?> -

translatePlural('%u Service', '%u Services', $serviceCount), $serviceCount); ?>

-
qlink( - sprintf($this->translate('List all %u services'), $serviceCount), - $listAllLink - ); ?>
+ + +

qlink( - sprintf($this->translate('Reschedule the next check for all %u services'), $serviceCount), - $rescheduleAllLink, - null, - array('icon' => 'reschedule') - ); ?>
+ $this->translate('Reschedule the next check'), + $rescheduleAllLink, + null, + array('icon' => 'reschedule') + ); ?>
qlink( - sprintf($this->translate('Schedule a downtime for all %u services'), $serviceCount), - $downtimeAllLink, - null, - array('icon' => 'plug') - ); ?>
+ $this->translate('Schedule a downtime'), + $downtimeAllLink, + null, + array('icon' => 'plug') + ); ?>
qlink( - sprintf($this->translate('Submit a passive check result for all %u services'), $serviceCount), - $processCheckResultAllLink, - null, - array('icon' => 'reply') - ); ?>
- 0): ?> -
-

translatePlural( - '%u Unhandled Service Problem', - '%u Unhandled Service Problems', - $unhandledCount - ), - $unhandledCount - ); ?>

-
qlink( + $this->translate('Submit a passive check result'), + $processCheckResultAllLink, + null, + array('icon' => 'reply') + ); ?>
+

+ + 0): ?> +
+

+ icon('attention-alt') ?> + translatePlural( + 'Unhandled Problem', + 'Unhandled Problems', + $unhandledCount + ) ?> +

+ +

' . $unhandledCount . '') ?> + + +

+ qlink( sprintf( $this->translatePlural( 'Schedule a downtime for %u unhandled service problem', @@ -53,7 +72,9 @@ $downtimeUnhandledLink, null, array('icon' => 'plug') - ); ?>
+ ); ?> +
+
qlink( sprintf( $this->translatePlural( @@ -67,50 +88,101 @@ null, array('icon' => 'ok') ); ?>
-
- - 0): ?> -
-

translatePlural( - '%u Acknowledged Service Problem', - '%u Acknowledged Service Problems', - $acknowledgedCount - ), +

+ + +

+ + + 0): ?> + +

icon('ok', $this->translate('Acknowledgements')) ?> translate('Acknowledgements') ?>

+

+ translatePlural( + '%u Acknowledged Service Problem', + '%u Acknowledged Service Problems', $acknowledgedCount - ); ?> - - - - 0): ?> -

qlink( - sprintf( - $this->translatePlural( - 'List %u service currently in downtime', - 'List %u services currently in downtime', - $inDowntimeCount - ), - $inDowntimeCount ), + $acknowledgedCount + ); ?> +

+ + + + 0): ?> + +

icon('plug', $this->translate('Downtimes')) ?> translate('Downtimes') ?>

+

translatePlural( + '%u service currently in downtime', + '%u services currently in downtime', + $inDowntimeCount + ), $inDowntimeCount) ?> + +

+ qlink( + $this->translate('List all'), $inDowntimeLink, null, array('icon' => 'plug') - ); ?> - - getComments())) > 0): ?> -

qlink( - sprintf( - $this->translatePlural( - 'List %u service comment', - 'List %u service comments', - $commentCount - ), + );?> +

+ +
+ Delete All +
+

+ + + +getComments()) ?> + 0): ?> +

icon('comment') ?>

+

translatePlural( + 'There are no comments.', + 'There are %d comments', $commentCount - ), - $commentsLink, - null, - array('icon' => 'comment') - ); ?> - + ), $commentCount); + ?> + qlink( + $this->translate('List all'), + $commentsLink, + null, + array('icon' => 'comment') + ); ?>

+ + + + fetchComments(); ?> + + comments as $comment): ?> + + + + + + + +
+ populate( + array('comment_id' => $comment->id, 'redirect' => html_entity_decode($this->url)) + ); + $delCommentForm->setAction( + $this->url( + 'monitoring/service/delete-comment', + array('host' => $service->getHost()->getName(), 'service' => $service->getName()) + ) + ); + echo $delCommentForm; + ?> + (type) ?>): + + comment) ?> +
+ + \ No newline at end of file diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 6c205cd045..eb598bb5d5 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -91,15 +91,16 @@ div.contacts div.notification-periods { margin-top: 0.5em; } -div.tinystatesummary { +.tinystatesummary { .page-header(); font-size: 1em; .badges { display: inline-block; margin-bottom: 4px; margin-left: 1em; + height: auto; } - .state > a { + .state > * { color: white; font-size: 0.8em; padding: 2px 5px; @@ -196,7 +197,7 @@ div.selection-info { .optionbox label { max-width: 6.5em; text-align: left; - vertical-align: middle; + vertgical-align: middle; margin-right: 0em; } diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index 5c19bfe35b..62d5a68cdb 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -922,3 +922,50 @@ table.groupview { } /* End of monitoring groupsummary styles */ + +/* compact table */ +table.statesummary { + text-align: left; + width: auto; + border-collapse: separate; + + tbody { + white-space: nowrap; + } + + td { + padding: 0em 0.4em 0em 0.4em; + line-height: 1.2em; + } + + tr.state td.state { + width: auto; + font-weight: bold; + } + + td .pluginoutput { + font-size: 0.8em; + line-height: 1.2em; + padding-left: 0; + margin: 0; + } + + td.state { + min-width: 70px; + font-size: 0.7em; + text-align: center; + } + + td a { + color: inherit; + text-decoration: none; + } +} + +/* Up to 576px for 1em=16px, should fit 320px devices */ +@media screen and (max-width: 97em) { + + table.statesummary .collapse { + display: none; + } +} diff --git a/public/css/icinga/widgets.less b/public/css/icinga/widgets.less index 45701a6975..de33d6685d 100644 --- a/public/css/icinga/widgets.less +++ b/public/css/icinga/widgets.less @@ -203,23 +203,13 @@ li li .badge-container { margin-right: 0.75em; } -/* -#layout.hoveredmenu .active > .badge-container { - display: none; -} - -#layout.hoveredmenu .hover > .badge-container { - //margin-right: 14.15em; - display: none; -} -*/ - .badge { position: relative; - top: 0.3em; + top: -0.15em; display: inline-block; min-width: 1em; padding: 3px 7px; + margin: 0 0.2em 0 0.2em; font-size: 0.8em; font-weight: 700; line-height: 1.1em; @@ -230,6 +220,11 @@ li li .badge-container { background-color: @colorInvalid; } +#menu nav ul .badge { + margin-right: 0em; + top: 0.3em; +} + #menu nav > ul > li.active > .badge-container { display: none; } @@ -277,7 +272,7 @@ li li .badge { background-color: @colorPending; } -.badge-pending { +.badge-unknown { background-color: @colorUnknown; } @@ -303,3 +298,24 @@ li li .badge { margin: 0em 0em 0em 0.1em; } + +.tipsy .tipsy-inner { + // overwrite tooltip max width, we need them to grow bigger + max-width: 300px; + text-align: left; +} + +.color-box { + position: relative; + top: 2px; + margin: 0px 3px 0px 3px; + display: inline-block; + width: 12px; + height: 12px; +} + +.oneline { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} diff --git a/public/js/icinga/behavior/tooltip.js b/public/js/icinga/behavior/tooltip.js index c9a64257f9..c0abcbd458 100644 --- a/public/js/icinga/behavior/tooltip.js +++ b/public/js/icinga/behavior/tooltip.js @@ -30,7 +30,7 @@ $('svg .chart-data', el).tipsy({ gravity: 'se', html: true }); $('.historycolorgrid a[title]', el).tipsy({ gravity: 's', offset: 2 }); $('img.icon[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, offset: 2 }); - $('[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, delayIn: 500 }); + $('[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, delayIn: 500, html: true }); // migrate or remove all orphaned tooltips $('.tipsy').each(function () {