Merge branch 'master' into feature/navigation-unhandled-badges-7114
Conflicts: library/Icinga/Web/Menu.php
This commit is contained in:
commit
51d14af154
|
@ -9,6 +9,7 @@ use Icinga\Data\ResourceFactory;
|
|||
use Icinga\Logger\Logger;
|
||||
use Icinga\Logger\Writer\FileWriter;
|
||||
use Icinga\Protocol\File\FileReader;
|
||||
use \Zend_Controller_Action_Exception as ActionError;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
|
@ -38,20 +39,21 @@ class ListController extends Controller
|
|||
*/
|
||||
public function applicationlogAction()
|
||||
{
|
||||
if (! Logger::writesToFile()) {
|
||||
throw new ActionError('Site not found', 404);
|
||||
}
|
||||
|
||||
$this->addTitleTab('application log');
|
||||
$pattern = '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
|
||||
. ' - (?<message>.*)$/'; // message
|
||||
|
||||
$loggerWriter = Logger::getInstance()->getWriter();
|
||||
if ($loggerWriter instanceof FileWriter) {
|
||||
$resource = new FileReader(new Zend_Config(array(
|
||||
'filename' => $loggerWriter->getPath(),
|
||||
'fields' => '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
|
||||
. ' - (?<message>.*)$/' // message
|
||||
)));
|
||||
$this->view->logData = $resource->select()->order('DESC')->paginate();
|
||||
} else {
|
||||
$this->view->logData = null;
|
||||
}
|
||||
$resource = new FileReader(new Zend_Config(array(
|
||||
'filename' => $loggerWriter->getPath(),
|
||||
'fields' => $pattern
|
||||
)));
|
||||
$this->view->logData = $resource->select()->order('DESC')->paginate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class StaticController extends ActionController
|
|||
$cache->send($cacheFile);
|
||||
return;
|
||||
}
|
||||
$img = file_get_contents('http://www.gravatar.com/avatar/' . $filename . '?s=200&d=mm');
|
||||
$img = file_get_contents('http://www.gravatar.com/avatar/' . $filename . '?s=120&d=mm');
|
||||
$cache->store($cacheFile, $img);
|
||||
header('ETag: "' . $cache->etagForCachedFile($cacheFile) . '"');
|
||||
echo $img;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Icinga\Form\Preference;
|
||||
|
||||
use DateTimeZone;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Zend_Config;
|
||||
use Zend_Form_Element_Text;
|
||||
use Zend_Form_Element_Select;
|
||||
|
@ -69,13 +70,22 @@ class GeneralForm extends Form
|
|||
*/
|
||||
private function addTimezoneSelection(Zend_Config $cfg)
|
||||
{
|
||||
$prefs = $this->getUserPreferences();
|
||||
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
|
||||
$detect = new TimezoneDetect();
|
||||
|
||||
$tzList = array();
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
||||
$helptext = 'Use the following timezone for dates and times';
|
||||
$prefs = $this->getUserPreferences();
|
||||
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
|
||||
|
||||
if ($useGlobalTimezone && $detect->success() === true) {
|
||||
$helptext .= '<br />' . t('Currently your time was detected to be')
|
||||
. ': '
|
||||
. '<strong>' . $detect->getTimezoneName() . '</strong>';
|
||||
}
|
||||
|
||||
$selectTimezone = new Zend_Form_Element_Select(
|
||||
array(
|
||||
|
@ -87,6 +97,7 @@ class GeneralForm extends Form
|
|||
'value' => $prefs->get('app.timezone', $cfg->get('timezone', date_default_timezone_get()))
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'default_timezone',
|
||||
|
@ -99,7 +110,9 @@ class GeneralForm extends Form
|
|||
if ($useGlobalTimezone) {
|
||||
$selectTimezone->setAttrib('disabled', 1);
|
||||
}
|
||||
|
||||
$this->addElement($selectTimezone);
|
||||
|
||||
$this->enableAutoSubmit(array('default_timezone'));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,17 +29,17 @@ $iframeClass = $isIframe ? ' iframe' : '';
|
|||
<title><?= $this->title ? $this->escape($this->title) : 'Icinga Web' ?></title>
|
||||
<!-- TODO: viewport and scale settings make no sense for us, fix this -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link rel="stylesheet" href="<?= $this->href($cssfile) ?>" media="screen" type="text/css" />
|
||||
<? if ($isIframe): ?>
|
||||
<? if ($isIframe): ?>
|
||||
<base target="_parent"/>
|
||||
<?php else: ?>
|
||||
<?php else: ?>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var html = document.getElementsByTagName('html')[0];
|
||||
html.className = html.className.replace(/no-js/, 'js');
|
||||
}());
|
||||
</script>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<link rel="stylesheet" href="<?= $this->href($cssfile) ?>" media="screen" type="text/css" />
|
||||
<!-- Respond.js IE8 support of media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="<?= $this->baseUrl('js/vendor/respond.min.js');?>"></script>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use Zend_View_Helper_FormElement;
|
||||
use \Zend_View_Helper_FormElement;
|
||||
|
||||
/**
|
||||
* Helper to generate a "datetime" element
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use Zend_View_Helper_FormElement;
|
||||
use \Zend_View_Helper_FormElement;
|
||||
|
||||
/**
|
||||
* Helper to generate a "datetime" element
|
||||
|
|
|
@ -10,6 +10,7 @@ use Icinga\Authentication\Manager as AuthenticationManager;
|
|||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Response;
|
||||
use Icinga\Web\View;
|
||||
|
@ -273,10 +274,11 @@ class Web extends ApplicationBootstrap
|
|||
*/
|
||||
protected function setupTimezone()
|
||||
{
|
||||
$userTimezone = null;
|
||||
|
||||
if ($this->user !== null && $this->user->getPreferences() !== null) {
|
||||
$userTimezone = $this->user->getPreferences()->get('app.timezone');
|
||||
} else {
|
||||
$userTimezone = null;
|
||||
$detect = new TimezoneDetect();
|
||||
$userTimezone = $this->user->getPreferences()->get('app.timezone', $detect->getTimezoneName());
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -27,6 +27,13 @@ class Logger
|
|||
*/
|
||||
protected $writer;
|
||||
|
||||
/**
|
||||
* The configured type
|
||||
*
|
||||
* @string Type (syslog, file)
|
||||
*/
|
||||
protected $type = 'none';
|
||||
|
||||
/**
|
||||
* The maximum severity to emit
|
||||
*
|
||||
|
@ -83,6 +90,7 @@ class Logger
|
|||
$config->type
|
||||
);
|
||||
}
|
||||
$this->type = $config->type;
|
||||
|
||||
return new $class($config);
|
||||
}
|
||||
|
@ -204,6 +212,16 @@ class Logger
|
|||
return $this->writer;
|
||||
}
|
||||
|
||||
public static function writesToSyslog()
|
||||
{
|
||||
return static::$instance && static::$instance->type === 'syslog';
|
||||
}
|
||||
|
||||
public static function writesToFile()
|
||||
{
|
||||
return static::$instance && static::$instance->type === 'file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this' instance
|
||||
*
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Icinga\Protocol\File;
|
|||
|
||||
use Icinga\Data\Selectable;
|
||||
use Countable;
|
||||
use Icinga\Util\Enumerate;
|
||||
use Zend_Config;
|
||||
|
||||
/**
|
||||
|
@ -52,7 +53,9 @@ class FileReader implements Selectable, Countable
|
|||
*/
|
||||
public function iterate()
|
||||
{
|
||||
return new FileIterator($this->filename, $this->fields);
|
||||
return new Enumerate(
|
||||
new FileIterator($this->filename, $this->fields)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,15 +120,13 @@ class FileReader implements Selectable, Countable
|
|||
$skip = $count - ($skip + $read);
|
||||
}
|
||||
}
|
||||
$index = 0;
|
||||
foreach ($this->iterate() as $line) {
|
||||
foreach ($this->iterate() as $index => $line) {
|
||||
if ($index >= $skip) {
|
||||
if ($index >= $skip + $read) {
|
||||
break;
|
||||
}
|
||||
$lines[] = $line;
|
||||
}
|
||||
++$index;
|
||||
}
|
||||
if ($query->sortDesc()) {
|
||||
$lines = array_reverse($lines);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Util;
|
||||
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Class Enumerate
|
||||
*
|
||||
* @see https://docs.python.org/2/library/functions.html#enumerate
|
||||
*
|
||||
* @package Icinga\Util
|
||||
*/
|
||||
class Enumerate implements Iterator
|
||||
{
|
||||
/**
|
||||
* @var Iterator
|
||||
*/
|
||||
protected $iterator;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* @param Iterator $iterator
|
||||
*/
|
||||
public function __construct(Iterator $iterator)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->iterator->rewind();
|
||||
$this->key = 0;
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
$this->iterator->next();
|
||||
++$this->key;
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return $this->iterator->valid();
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return $this->iterator->current();
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Util;
|
||||
|
||||
use Icinga\Application\Platform;
|
||||
|
||||
/**
|
||||
* Retrieve timezone information from cookie
|
||||
*/
|
||||
class TimezoneDetect
|
||||
{
|
||||
/**
|
||||
* If detection was successful
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $success;
|
||||
|
||||
/**
|
||||
* Timezone offset in minutes
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $offset = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $timezoneName;
|
||||
|
||||
/**
|
||||
* Cookie name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $cookieName = 'icingaweb2-tzo';
|
||||
|
||||
/**
|
||||
* Timezone name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $timezone;
|
||||
|
||||
/**
|
||||
* Create new object and try to identify the timezone
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (self::$success !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform::isCli() === false && array_key_exists(self::$cookieName, $_COOKIE)) {
|
||||
list($offset, $dst) = explode(',', $_COOKIE[self::$cookieName]);
|
||||
$timezoneName = timezone_name_from_abbr('', (int)$offset, (int)$dst);
|
||||
|
||||
self::$success = (bool)$timezoneName;
|
||||
|
||||
if (self::$success === true) {
|
||||
self::$offset = $offset;
|
||||
self::$timezoneName = $timezoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset()
|
||||
{
|
||||
return self::$offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timezone name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTimezoneName()
|
||||
{
|
||||
return self::$timezoneName;
|
||||
}
|
||||
|
||||
/**
|
||||
* True on success
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function success()
|
||||
{
|
||||
return self::$success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset object
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
self::$success = null;
|
||||
self::$timezoneName = null;
|
||||
self::$offset = 0;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ class JavaScript
|
|||
'js/icinga/events.js',
|
||||
'js/icinga/history.js',
|
||||
'js/icinga/module.js',
|
||||
'js/icinga/timezone.js',
|
||||
);
|
||||
|
||||
protected static $vendorFiles = array(
|
||||
|
|
|
@ -9,6 +9,7 @@ use RecursiveIterator;
|
|||
use Zend_Config;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Url;
|
||||
|
@ -67,6 +68,13 @@ class Menu implements RecursiveIterator
|
|||
* @var MenuItemRenderer
|
||||
*/
|
||||
protected $itemRenderer = null;
|
||||
|
||||
/*
|
||||
* Parent menu
|
||||
*
|
||||
* @var Menu
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Create a new menu
|
||||
|
@ -74,9 +82,12 @@ class Menu implements RecursiveIterator
|
|||
* @param int $id The id of this menu
|
||||
* @param Zend_Config $config The configuration for this menu
|
||||
*/
|
||||
public function __construct($id, Zend_Config $config = null)
|
||||
public function __construct($id, Zend_Config $config = null, Menu $parent = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
if ($parent !== null) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
$this->setProperties($config);
|
||||
}
|
||||
|
||||
|
@ -212,10 +223,13 @@ class Menu implements RecursiveIterator
|
|||
'url' => 'config/modules',
|
||||
'priority' => 400
|
||||
));
|
||||
$section->add(t('ApplicationLog'), array(
|
||||
'url' => 'list/applicationlog',
|
||||
'priority' => 500
|
||||
));
|
||||
|
||||
if (Logger::writesToFile()) {
|
||||
$section->add(t('Application Log'), array(
|
||||
'url' => 'list/applicationlog',
|
||||
'priority' => 500
|
||||
));
|
||||
}
|
||||
|
||||
$this->add(t('Logout'), array(
|
||||
'url' => 'authentication/logout',
|
||||
|
@ -247,6 +261,30 @@ class Menu implements RecursiveIterator
|
|||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our ID without invalid characters
|
||||
*
|
||||
* @return string the ID
|
||||
*/
|
||||
protected function getSafeHtmlId()
|
||||
{
|
||||
return preg_replace('/[^a-zA-Z0-9]/', '_', $this->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique menu item id
|
||||
*
|
||||
* @return string the ID
|
||||
*/
|
||||
public function getUniqueId()
|
||||
{
|
||||
if ($this->parent === null) {
|
||||
return 'menuitem-' . $this->getSafeHtmlId();
|
||||
} else {
|
||||
return $this->parent->getUniqueId() . '-' . $this->getSafeHtmlId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of this menu
|
||||
*
|
||||
|
@ -384,7 +422,7 @@ class Menu implements RecursiveIterator
|
|||
public function addSubMenu($id, Zend_Config $menuConfig = null)
|
||||
{
|
||||
if (false === ($pos = strpos($id, '.'))) {
|
||||
$subMenu = new self($id, $menuConfig);
|
||||
$subMenu = new self($id, $menuConfig, $this);
|
||||
$this->subMenus[$id] = $subMenu;
|
||||
} else {
|
||||
list($parentId, $id) = explode('.', $id, 2);
|
||||
|
@ -651,4 +689,12 @@ class Menu implements RecursiveIterator
|
|||
{
|
||||
next($this->subMenus);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 5.3 GC should not leak, but just to be on the safe side...
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->parent = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,9 +118,9 @@ class MenuRenderer extends RecursiveIteratorIterator
|
|||
|
||||
if ($childIsActive || ($passedActiveChild && $this->getDepth() === 0)) {
|
||||
$passedActiveChild &= $this->getDepth() !== 0;
|
||||
$openTag = '<li class="active">';
|
||||
$openTag = '<li class="active" id="' . $child->getUniqueId() . '">';
|
||||
} else {
|
||||
$openTag = '<li>';
|
||||
$openTag = '<li id="' . $child->getUniqueId() . '">';
|
||||
}
|
||||
$content = $this->renderChild($child);
|
||||
$closingTag = '</li>';
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Icinga\Web;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Cli\FakeRequest;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\UrlParams;
|
||||
|
||||
|
@ -98,7 +99,12 @@ class Url
|
|||
*/
|
||||
protected static function getRequest()
|
||||
{
|
||||
return Icinga::app()->getFrontController()->getRequest();
|
||||
$app = Icinga::app();
|
||||
if ($app->isCli()) {
|
||||
return new FakeRequest();
|
||||
} else {
|
||||
return $app->getFrontController()->getRequest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -424,6 +430,24 @@ class Url
|
|||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this url with the given parameter(s)
|
||||
*
|
||||
* The argument can be either a single query parameter name or an array of parameter names to
|
||||
* remove from the query list
|
||||
*
|
||||
* @param string|array $param A single string or an array containing parameter names
|
||||
* @param array $values an optional values array
|
||||
*
|
||||
* @return Url
|
||||
*/
|
||||
public function with($param, $values = null)
|
||||
{
|
||||
$url = clone($this);
|
||||
$url->params->mergeValues($param, $values);
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->params = clone $this->params;
|
||||
|
|
|
@ -181,6 +181,9 @@ class UrlParams
|
|||
$this->set($k, $v);
|
||||
}
|
||||
} else {
|
||||
if (! is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$this->set($param, $value);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ $this->addHelperFunction('url', function ($path = null, $params = null) {
|
|||
$url = Url::fromPath($path);
|
||||
}
|
||||
if ($params !== null) {
|
||||
$url->setParams($params);
|
||||
$url->overwriteParams($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
|
|
@ -88,7 +88,7 @@ class FilterWidget extends AbstractWidget
|
|||
$editorUrl->setParam('modifyFilter', true);
|
||||
if ($this->filter->isEmpty()) {
|
||||
$title = t('Filter this list');
|
||||
$txt = $view->icon('create.png', $title);
|
||||
$txt = $view->icon('create.png');
|
||||
$remove = '';
|
||||
} else {
|
||||
$txt = t('Filtered');
|
||||
|
@ -98,7 +98,7 @@ class FilterWidget extends AbstractWidget
|
|||
. '" title="'
|
||||
. t('Remove this filter')
|
||||
. '">'
|
||||
. $view->icon('remove.png', $title)
|
||||
. $view->icon('remove.png')
|
||||
. '</a>';
|
||||
}
|
||||
$filter = $this->filter->isEmpty() ? '' : ': ' . $this->filter;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Module\Monitoring\Backend;
|
||||
use Icinga\Module\Monitoring\DataView\DataView;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Hook;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
|
@ -236,6 +235,25 @@ class Monitoring_ListController extends Controller
|
|||
// TODO: Workaround, paginate should be able to fetch limit from new params
|
||||
$this->view->services = $query->paginate($this->params->get('limit'));
|
||||
}
|
||||
|
||||
$this->view->stats = $this->backend->select()->from('statusSummary', array(
|
||||
'services_total',
|
||||
'services_ok',
|
||||
'services_problem',
|
||||
'services_problem_handled',
|
||||
'services_problem_unhandled',
|
||||
'services_critical',
|
||||
'services_critical_unhandled',
|
||||
'services_critical_handled',
|
||||
'services_warning',
|
||||
'services_warning_unhandled',
|
||||
'services_warning_handled',
|
||||
'services_unknown',
|
||||
'services_unknown_unhandled',
|
||||
'services_unknown_handled',
|
||||
'services_pending',
|
||||
))->getQuery()->fetchRow();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -500,19 +518,19 @@ class Monitoring_ListController extends Controller
|
|||
{
|
||||
$this->addTitleTab('servicematrix');
|
||||
$this->setAutorefreshInterval(15);
|
||||
$dataview = $this->backend->select()->from('serviceStatus', array(
|
||||
$query = $this->backend->select()->from('serviceStatus', array(
|
||||
'host_name',
|
||||
'service_description',
|
||||
'service_state',
|
||||
'service_output',
|
||||
'service_handled'
|
||||
));
|
||||
$this->applyFilters($dataview);
|
||||
$this->applyFilters($query);
|
||||
$this->setupSortControl(array(
|
||||
'host_name' => 'Hostname',
|
||||
'service_description' => 'Service description'
|
||||
));
|
||||
$pivot = $dataview->pivot('service_description', 'host_name');
|
||||
$pivot = $query->pivot('service_description', 'host_name');
|
||||
$this->view->pivot = $pivot;
|
||||
$this->view->horizontalPaginator = $pivot->paginateXAxis();
|
||||
$this->view->verticalPaginator = $pivot->paginateYAxis();
|
||||
|
@ -572,10 +590,6 @@ class Monitoring_ListController extends Controller
|
|||
|
||||
/**
|
||||
* Apply current user's `monitoring/filter' restrictions on the given data view
|
||||
*
|
||||
* @param DataView $dataView
|
||||
*
|
||||
* @return DataView
|
||||
*/
|
||||
protected function applyRestrictions($query)
|
||||
{
|
||||
|
|
|
@ -70,6 +70,7 @@ class Monitoring_ShowController extends Controller
|
|||
if ($this->grapher) {
|
||||
$this->view->grapherHtml = $this->grapher->getPreviewHtml($o);
|
||||
}
|
||||
$this->fetchHostStats();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +86,7 @@ class Monitoring_ShowController extends Controller
|
|||
if ($this->grapher) {
|
||||
$this->view->grapherHtml = $this->grapher->getPreviewHtml($o);
|
||||
}
|
||||
$this->fetchHostStats();
|
||||
}
|
||||
|
||||
public function historyAction()
|
||||
|
@ -94,6 +96,7 @@ class Monitoring_ShowController extends Controller
|
|||
$this->view->object->fetchEventHistory();
|
||||
$this->view->history = $this->view->object->eventhistory->paginate($this->params->get('limit', 50));
|
||||
$this->handleFormatRequest($this->view->object->eventhistory);
|
||||
$this->fetchHostStats();
|
||||
}
|
||||
|
||||
public function servicesAction()
|
||||
|
@ -106,6 +109,28 @@ class Monitoring_ShowController extends Controller
|
|||
'view' => 'compact',
|
||||
'sort' => 'service_description',
|
||||
));
|
||||
$this->fetchHostStats();
|
||||
}
|
||||
|
||||
protected function fetchHostStats()
|
||||
{
|
||||
$this->view->stats = $this->backend->select()->from('statusSummary', array(
|
||||
'services_total',
|
||||
'services_ok',
|
||||
'services_problem',
|
||||
'services_problem_handled',
|
||||
'services_problem_unhandled',
|
||||
'services_critical',
|
||||
'services_critical_unhandled',
|
||||
'services_critical_handled',
|
||||
'services_warning',
|
||||
'services_warning_unhandled',
|
||||
'services_warning_handled',
|
||||
'services_unknown',
|
||||
'services_unknown_unhandled',
|
||||
'services_unknown_handled',
|
||||
'services_pending',
|
||||
))->where('service_host_name', $this->params->get('host'))->getQuery()->fetchRow();
|
||||
}
|
||||
|
||||
public function contactAction()
|
||||
|
|
|
@ -85,7 +85,7 @@ $helper = $this->getHelper('CommandForm');
|
|||
<br>
|
||||
<?= $comment->expiration ? sprintf(
|
||||
$this->translate('This comment expires on %s at %s.'),
|
||||
date('d.m.y', $comment-expiration),
|
||||
date('d.m.y', $comment->expiration),
|
||||
date('H:i', $comment->expiration)
|
||||
) : $this->translate('This comment does not expire.'); ?>
|
||||
</td>
|
||||
|
@ -111,4 +111,4 @@ $helper = $this->getHelper('CommandForm');
|
|||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\Url;
|
||||
$selfUrl = 'monitoring/list/services';
|
||||
$currentUrl = Url::fromRequest()->getRelativeUrl();
|
||||
|
||||
?><h3 class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : '' ?>>
|
||||
<?= $this->qlink(sprintf($this->translate('%s services:'), $this->stats->services_total), $selfUrl) ?>
|
||||
<span class="state ok<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 0))->getRelativeUrl() ? ' active' : '' ?>"><?= $this->qlink(
|
||||
$this->stats->services_ok,
|
||||
$selfUrl,
|
||||
array('service_state' => 0),
|
||||
array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('ok'))))
|
||||
) ?></span>
|
||||
<?php
|
||||
|
||||
foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $state) {
|
||||
$pre = 'services_' . $state;
|
||||
if ($this->stats->$pre) {
|
||||
$handled = $pre . '_handled';
|
||||
$unhandled = $pre . '_unhandled';
|
||||
$paramsHandled = array('service_state' => $stateId, 'service_handled' => 1);
|
||||
$paramsUnhandled = array('service_state' => $stateId, 'service_handled' => 0);
|
||||
if ($this->stats->$unhandled) {
|
||||
$compareUrl = Url::fromPath($selfUrl, $paramsUnhandled)->getRelativeUrl();
|
||||
} else {
|
||||
$compareUrl = Url::fromPath($selfUrl, $paramsHandled)->getRelativeUrl();
|
||||
}
|
||||
|
||||
if ($compareUrl === $currentUrl) {
|
||||
$active = ' active';
|
||||
} else {
|
||||
$active = '';
|
||||
}
|
||||
|
||||
echo '<span class="state ' . $state . $active . ($this->stats->$unhandled ? '' : ' handled') . '">';
|
||||
if ($this->stats->$unhandled) {
|
||||
|
||||
echo $this->qlink(
|
||||
$this->stats->$unhandled,
|
||||
$selfUrl,
|
||||
$paramsUnhandled,
|
||||
array('title' => sprintf($this->translate('Unandled services with state %s'), strtoupper($this->translate($state))))
|
||||
);
|
||||
}
|
||||
if ($this->stats->$handled) {
|
||||
|
||||
if (Url::fromPath($selfUrl, $paramsHandled)->getRelativeUrl() === $currentUrl) {
|
||||
$active = ' active';
|
||||
} else {
|
||||
$active = '';
|
||||
}
|
||||
if ($this->stats->$unhandled) {
|
||||
echo '<span class="state handled ' . $state . $active . '">';
|
||||
}
|
||||
echo $this->qlink(
|
||||
$this->stats->$handled,
|
||||
$selfUrl,
|
||||
$paramsHandled,
|
||||
array('title' => sprintf($this->translate('Handled services with state %s'), strtoupper($this->translate($state))))
|
||||
);
|
||||
if ($this->stats->$unhandled) {
|
||||
echo "</span>\n";
|
||||
}
|
||||
}
|
||||
echo "</span>\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?php if ($this->stats->services_pending): ?>
|
||||
<span class="state pending<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 99))->getRelativeUrl() ? ' active' : '' ?>"><?= $this->qlink(
|
||||
$this->stats->services_pending,
|
||||
$selfUrl,
|
||||
array('service_state' => 99),
|
||||
array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('pending'))))
|
||||
) ?></span>
|
||||
<?php endif ?>
|
||||
</h3>
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
<?php
|
||||
$helper = $this->getHelper('MonitoringState');
|
||||
|
||||
$selfUrl = 'monitoring/list/services';
|
||||
|
||||
if (!$this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<div style="margin: 1em;" class="dontprint">
|
||||
<?= $this->render('list/components/servicesummary.phtml') ?>
|
||||
<?= $this->translate('Sort by') ?> <?= $this->sortControl ?>
|
||||
<?php if (! $this->filterEditor): ?>
|
||||
<?= $this->filterPreview ?>
|
||||
|
@ -21,6 +24,9 @@ if (!$this->compact): ?>
|
|||
|
||||
<div class="content">
|
||||
<?= $this->filterEditor ?>
|
||||
<?php else: ?>
|
||||
|
||||
<div class="content">
|
||||
<?php endif ?>
|
||||
<table data-base-target="_next"
|
||||
class="action multiselect <?php if ($this->compact): ?> compact<?php endif ?>" style="table-layout: auto;"
|
||||
|
@ -113,6 +119,4 @@ foreach ($services as $service):
|
|||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if (!$this->compact): ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\Url;
|
||||
$selfUrl = Url::fromPath('monitoring/show/services', array('host' => $this->object->host_name));
|
||||
$currentUrl = Url::fromRequest()->without('limit')->getRelativeUrl();
|
||||
|
||||
?>
|
||||
<h3 class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : '' ?>>
|
||||
<?= $this->qlink(sprintf($this->translate('%s service configured:'), $this->stats->services_total), $selfUrl) ?>
|
||||
<?php if ($this->stats->services_ok > 0): ?>
|
||||
<span class="state ok<?= $currentUrl === $selfUrl->with('service_state', 0)->getRelativeUrl() ? ' active' : '' ?>"><?= $this->qlink(
|
||||
$this->stats->services_ok,
|
||||
$selfUrl,
|
||||
array('service_state' => 0),
|
||||
array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('ok'))))
|
||||
) ?></span>
|
||||
<?php endif ?>
|
||||
<?php
|
||||
|
||||
foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $state) {
|
||||
$pre = 'services_' . $state;
|
||||
if ($this->stats->$pre) {
|
||||
$handled = $pre . '_handled';
|
||||
$unhandled = $pre . '_unhandled';
|
||||
$paramsHandled = array('service_state' => $stateId, 'service_handled' => 1);
|
||||
$paramsUnhandled = array('service_state' => $stateId, 'service_handled' => 0);
|
||||
if ($this->stats->$unhandled) {
|
||||
$compareUrl = $selfUrl->with($paramsUnhandled)->getRelativeUrl();
|
||||
} else {
|
||||
$compareUrl = $selfUrl->with($paramsHandled)->getRelativeUrl();
|
||||
}
|
||||
|
||||
if ($compareUrl === $currentUrl) {
|
||||
$active = ' active';
|
||||
} else {
|
||||
$active = '';
|
||||
}
|
||||
|
||||
echo '<span class="state ' . $state . $active . ($this->stats->$unhandled ? '' : ' handled') . '">';
|
||||
if ($this->stats->$unhandled) {
|
||||
|
||||
echo $this->qlink(
|
||||
$this->stats->$unhandled,
|
||||
$selfUrl,
|
||||
$paramsUnhandled,
|
||||
array('title' => sprintf($this->translate('Unandled services with state %s'), strtoupper($this->translate($state))))
|
||||
);
|
||||
}
|
||||
if ($this->stats->$handled) {
|
||||
|
||||
if ($selfUrl->with($paramsHandled)->getRelativeUrl() === $currentUrl) {
|
||||
$active = ' active';
|
||||
} else {
|
||||
$active = '';
|
||||
}
|
||||
if ($this->stats->$unhandled) {
|
||||
echo '<span class="state handled ' . $state . $active . '">';
|
||||
}
|
||||
echo $this->qlink(
|
||||
$this->stats->$handled,
|
||||
$selfUrl,
|
||||
$paramsHandled,
|
||||
array('title' => sprintf($this->translate('Handled services with state %s'), strtoupper($this->translate($state))))
|
||||
);
|
||||
if ($this->stats->$unhandled) {
|
||||
echo "</span>\n";
|
||||
}
|
||||
}
|
||||
echo "</span>\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?php if ($this->stats->services_pending): ?>
|
||||
<span class="state pending<?= $currentUrl === $selfUrl->with('service_state', 99)->getRelativeUrl() ? ' active' : '' ?>"><?= $this->qlink(
|
||||
$this->stats->services_pending,
|
||||
$selfUrl,
|
||||
array('service_state' => 99),
|
||||
array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('pending'))))
|
||||
) ?></span>
|
||||
<?php endif ?>
|
||||
</h3>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?php if ($object->host_name !== false): ?>
|
||||
<div class="controls">
|
||||
<?= $this->render('show/components/header.phtml') ?>
|
||||
<h1><?= $this->translate("This host's current state") ?></h1>
|
||||
<?= $this->render('show/components/hostservicesummary.phtml') ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<?= $this->render('show/components/output.phtml') ?>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<div class="controls">
|
||||
<?= $this->render('show/components/header.phtml') ?>
|
||||
<h1><?= $this->translate('All services configured on this host') ?></h1>
|
||||
<?= $this->render('show/components/hostservicesummary.phtml') ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
<?= preg_replace('~<table data-base-target="_next"~', '<table data-base-target="_self"', $services) /* TODO: find an elegant solution for this */ ?>
|
||||
</div>
|
||||
|
|
|
@ -53,3 +53,80 @@ div.contacts div.contact > img {
|
|||
div.contacts div.notification-periods {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
h3.tinystatesummary {
|
||||
line-height: 2em;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
padding-left: 1em;
|
||||
background-color: #555;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.2em;
|
||||
-moz-border-radius: 0.2em;
|
||||
-webkit-border-radius: 0.2em;
|
||||
}
|
||||
|
||||
h3.tinystatesummary a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
|
||||
h3.tinystatesummary a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* State badges */
|
||||
span.state {
|
||||
font-size: 0.8em;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 1px 2px;
|
||||
margin-right: 5px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
span.state.active {
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
span.state span.state {
|
||||
font-size: 1em;
|
||||
margin: 0 -3px 0 5px;
|
||||
}
|
||||
|
||||
span.state.ok {
|
||||
background: @colorOk;
|
||||
}
|
||||
|
||||
span.state.critical {
|
||||
background: @colorCritical;
|
||||
}
|
||||
|
||||
span.state.handled.critical {
|
||||
background: @colorCriticalHandled;
|
||||
}
|
||||
|
||||
span.state.warning {
|
||||
background: @colorWarning;
|
||||
}
|
||||
|
||||
span.state.handled.warning {
|
||||
background: @colorWarningHandled;
|
||||
}
|
||||
|
||||
span.state.unknown {
|
||||
background: @colorUnknown;
|
||||
}
|
||||
|
||||
span.state.handled.unknown {
|
||||
background: @colorUnknownHandled;
|
||||
}
|
||||
|
||||
span.state.pending {
|
||||
background: @colorPending;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ ul.pagination {
|
|||
font-size: 0.68em;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
|
|
|
@ -82,14 +82,16 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
this.utils = new Icinga.Utils(this);
|
||||
this.logger = new Icinga.Logger(this);
|
||||
this.timer = new Icinga.Timer(this);
|
||||
this.ui = new Icinga.UI(this);
|
||||
this.loader = new Icinga.Loader(this);
|
||||
this.events = new Icinga.Events(this);
|
||||
this.history = new Icinga.History(this);
|
||||
this.timezone = new Icinga.Timezone();
|
||||
this.utils = new Icinga.Utils(this);
|
||||
this.logger = new Icinga.Logger(this);
|
||||
this.timer = new Icinga.Timer(this);
|
||||
this.ui = new Icinga.UI(this);
|
||||
this.loader = new Icinga.Loader(this);
|
||||
this.events = new Icinga.Events(this);
|
||||
this.history = new Icinga.History(this);
|
||||
|
||||
this.timezone.initialize();
|
||||
this.timer.initialize();
|
||||
this.events.initialize();
|
||||
this.history.initialize();
|
||||
|
@ -147,6 +149,7 @@
|
|||
module.destroy();
|
||||
});
|
||||
|
||||
this.timezone.destroy();
|
||||
this.timer.destroy();
|
||||
this.events.destroy();
|
||||
this.loader.destroy();
|
||||
|
|
|
@ -515,7 +515,7 @@
|
|||
var isMenuLink = $a.closest('#menu').length > 0;
|
||||
var formerUrl;
|
||||
var remote = /^(?:[a-z]+:)\/\//;
|
||||
if (href.match(/^javascript:/)) {
|
||||
if (href.match(/^(mailto|javascript):/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
(function(Icinga, $) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Get the maximum timezone offset
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
Date.prototype.getStdTimezoneOffset = function() {
|
||||
if (Date.maxTimezoneOffset !== undefined) {
|
||||
return Date.maxTimezoneOffset;
|
||||
}
|
||||
|
||||
var year = new Date().getYear();
|
||||
var previousOffset;
|
||||
|
||||
for (var i=0; i<12; i++) {
|
||||
var d = new Date(year, i, 1);
|
||||
if (previousOffset !== undefined) {
|
||||
previousOffset = Math.max(previousOffset, d.getTimezoneOffset());
|
||||
} else {
|
||||
previousOffset = d.getTimezoneOffset();
|
||||
}
|
||||
}
|
||||
|
||||
Date.maxTimezoneOffset = previousOffset;
|
||||
|
||||
return Date.maxTimezoneOffset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test for daylight saving time zone
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Date.prototype.isDst = function() {
|
||||
return (this.getStdTimezoneOffset() === this.getTimezoneOffset()) ? false : true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write timezone information into a cookie
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
Icinga.Timezone = function() {
|
||||
this.cookieName = 'icingaweb2-tzo';
|
||||
};
|
||||
|
||||
Icinga.Timezone.prototype = {
|
||||
/**
|
||||
* Initialize interface method
|
||||
*/
|
||||
initialize: function () {
|
||||
this.writeTimezone();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// PASS
|
||||
},
|
||||
|
||||
/**
|
||||
* Write timezone information into cookie
|
||||
*/
|
||||
writeTimezone: function() {
|
||||
var date = new Date();
|
||||
var timezoneOffset = (date.getTimezoneOffset()*60) * -1;
|
||||
var dst = date.isDst();
|
||||
|
||||
if (this.readCookie(this.cookieName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeCookie(this.cookieName, timezoneOffset + ',' + Number(dst), 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Write cookie data
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
* @param {Number} days
|
||||
*/
|
||||
writeCookie: function(name, value, days) {
|
||||
var expires = '';
|
||||
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
var expires = '; expires=' + date.toGMTString();
|
||||
}
|
||||
document.cookie = name + '=' + value + expires + '; path=/';
|
||||
},
|
||||
|
||||
/**
|
||||
* Read cookie data
|
||||
*
|
||||
* @param {String} name
|
||||
* @returns {*}
|
||||
*/
|
||||
readCookie: function(name) {
|
||||
var nameEq = name + '=';
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') {
|
||||
c = c.substring(1,c.length);
|
||||
}
|
||||
if (c.indexOf(nameEq) == 0) {
|
||||
return c.substring(nameEq.length,c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
})(Icinga, jQuery);
|
Loading…
Reference in New Issue