diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index f10756f97..f710a58ae 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -119,12 +119,6 @@ class ConfigController extends Controller ->order('name'); $this->setupLimitControl(); $this->setupPaginationControl($this->view->modules); - // TODO: Not working - /*$this->setupSortControl(array( - 'name' => $this->translate('Modulename'), - 'path' => $this->translate('Installation Path'), - 'enabled' => $this->translate('State') - ));*/ } public function moduleAction() diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 6c8eaa480..687998d6b 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -253,14 +253,6 @@ class DashboardController extends ActionController $this->dashboard->getConfig()->saveIni(); $this->redirectNow(URL::fromRequest()->remove('remove')); } - $this->view->tabs->add( - 'Add', - array( - 'label' => '+', - 'title' => 'Add a dashlet to an existing or new dashboard', - 'url' => Url::fromPath('dashboard/new-dashlet') - ) - ); $this->view->dashboard = $this->dashboard; } } diff --git a/application/controllers/GroupController.php b/application/controllers/GroupController.php index 949aa8fc6..c5f82e886 100644 --- a/application/controllers/GroupController.php +++ b/application/controllers/GroupController.php @@ -324,7 +324,6 @@ class GroupController extends AuthBackendController array( 'title' => sprintf($this->translate('Show group %s'), $groupName), 'label' => $this->translate('Group'), - 'icon' => 'users', 'url' => Url::fromPath('group/show', array('backend' => $backendName, 'group' => $groupName)) ) ); @@ -355,7 +354,6 @@ class GroupController extends AuthBackendController array( 'title' => $this->translate('List users of authentication backends'), 'label' => $this->translate('Users'), - 'icon' => 'user', 'url' => 'user/list' ) ); @@ -364,7 +362,6 @@ class GroupController extends AuthBackendController array( 'title' => $this->translate('List groups of user group backends'), 'label' => $this->translate('User Groups'), - 'icon' => 'users', 'url' => 'group/list' ) ); diff --git a/application/controllers/RoleController.php b/application/controllers/RoleController.php index 4e865aadb..64e15d89f 100644 --- a/application/controllers/RoleController.php +++ b/application/controllers/RoleController.php @@ -163,7 +163,6 @@ class RoleController extends AuthBackendController array( 'title' => $this->translate('List users of authentication backends'), 'label' => $this->translate('Users'), - 'icon' => 'user', 'url' => 'user/list' ) ); @@ -172,7 +171,6 @@ class RoleController extends AuthBackendController array( 'title' => $this->translate('List groups of user group backends'), 'label' => $this->translate('User Groups'), - 'icon' => 'users', 'url' => 'group/list' ) ); diff --git a/application/controllers/UserController.php b/application/controllers/UserController.php index ae7cf841a..7f2c69667 100644 --- a/application/controllers/UserController.php +++ b/application/controllers/UserController.php @@ -290,7 +290,6 @@ class UserController extends AuthBackendController array( 'title' => sprintf($this->translate('Show user %s'), $userName), 'label' => $this->translate('User'), - 'icon' => 'user', 'url' => Url::fromPath('user/show', array('backend' => $backendName, 'user' => $userName)) ) ); @@ -321,7 +320,6 @@ class UserController extends AuthBackendController array( 'title' => $this->translate('List users of authentication backends'), 'label' => $this->translate('Users'), - 'icon' => 'user', 'url' => 'user/list' ) ); @@ -330,7 +328,6 @@ class UserController extends AuthBackendController array( 'title' => $this->translate('List groups of user group backends'), 'label' => $this->translate('User Groups'), - 'icon' => 'users', 'url' => 'group/list' ) ); diff --git a/application/forms/Control/LimiterControlForm.php b/application/forms/Control/LimiterControlForm.php new file mode 100644 index 000000000..e665ab21a --- /dev/null +++ b/application/forms/Control/LimiterControlForm.php @@ -0,0 +1,113 @@ + '10', + 25 => '25', + 50 => '50', + 100 => '100', + 500 => '500' + ); + + /** + * Default limit for this instance + * + * @var int|null + */ + protected $defaultLimit; + + /** + * {@inheritdoc} + */ + public function init() + { + $this->setAttrib('class', static::CSS_CLASS_LIMITER); + } + + /** + * Get the default limit + * + * @return int + */ + public function getDefaultLimit() + { + return $this->defaultLimit !== null ? $this->defaultLimit : static::DEFAULT_LIMIT; + } + + /** + * Set the default limit + * + * @param int $defaultLimit + * + * @return $this + */ + public function setDefaultLimit($defaultLimit) + { + $this->defaultLimit = (int) $defaultLimit; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getRedirectUrl() + { + return $this->getRequest()->getUrl()->setParam('limit', $this->getElement('limit')->getValue()); + } + + /** + * {@inheritdoc} + */ + public function createElements(array $formData) + { + $this->addElement( + 'select', + 'limit', + array( + 'autosubmit' => true, + 'escape' => false, + 'label' => '#', + 'multiOptions' => static::$limits, + 'value' => $this->getRequest()->getUrl()->getParam('limit', $this->getDefaultLimit()) + ) + ); + } + + /** + * Limiter control is always successful + * + * @return bool + */ + public function onSuccess() + { + return true; + } +} diff --git a/application/forms/Dashboard/DashletForm.php b/application/forms/Dashboard/DashletForm.php index d25001a23..ae8072cda 100644 --- a/application/forms/Dashboard/DashletForm.php +++ b/application/forms/Dashboard/DashletForm.php @@ -96,7 +96,7 @@ class DashletForm extends Form array( 'required' => true, 'label' => $this->translate("New Dashboard Title"), - 'description' => $this->translate('Enter a title for the new pane.') + 'description' => $this->translate('Enter a title for the new dashboard') ) ); } else { @@ -107,7 +107,7 @@ class DashletForm extends Form 'required' => true, 'label' => $this->translate('Dashboard'), 'multiOptions' => $panes, - 'description' => $this->translate('Select a pane you want to add the dashlet.') + 'description' => $this->translate('Select a dashboard you want to add the dashlet to') ) ); } diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php index e9aca1d26..d8ab9f2b1 100644 --- a/application/forms/PreferenceForm.php +++ b/application/forms/PreferenceForm.php @@ -41,7 +41,6 @@ class PreferenceForm extends Form public function init() { $this->setName('form_config_preferences'); - $this->setTitle($this->translate('Preferences')); } /** diff --git a/application/views/scripts/about/index.phtml b/application/views/scripts/about/index.phtml index 47b76a8d2..5e7c918da 100644 --- a/application/views/scripts/about/index.phtml +++ b/application/views/scripts/about/index.phtml @@ -1,7 +1,7 @@
-
+
img( 'img/logo_icinga_big_dark.png', null, @@ -35,7 +35,7 @@ ) ?> -
+
qlink( null, 'https://www.twitter.com/icinga', @@ -54,16 +54,25 @@ 'icon' => 'facebook-squared', 'title' => $this->translate('Icinga on Facebook') ) + ) ?> qlink( + null, + 'https://plus.google.com/+icinga', + null, + array( + 'target' => '_blank', + 'icon' => 'google-plus-squared', + 'title' => $this->translate('Icinga on Google+') + ) ) ?>
-
+ -
qlink( null, 'https://wiki.icinga.org', null, array( 'target' => '_blank', - 'img' => 'img/wiki.png', + 'icon' => 'lightbulb', 'title' => $this->translate('Icinga Wiki') ) ) ?> @@ -95,13 +102,13 @@ null, array( 'target' => '_blank', - 'img' => 'img/docs.png', + 'icon' => 'doc-text', 'title' => $this->translate('Icinga Documentation') ) ) ?>

translate('Loaded modules') ?>

- +
diff --git a/application/views/scripts/config/modules.phtml b/application/views/scripts/config/modules.phtml index 92ced57a2..d2fe2d6b2 100644 --- a/application/views/scripts/config/modules.phtml +++ b/application/views/scripts/config/modules.phtml @@ -1,48 +1,40 @@ compact): ?>
- tabs; ?> -
-
- limiter ?> -
-
- paginator ?> -
-
- sortBox ?> -
-
- filterEditor; ?> + tabs ?> + paginator ?>
-
translate('Name') ?>
+
- + - - + - + echo $this->qlink( + $module->name, + 'config/module/', + array('name' => $module->name), + array( + 'class' => 'rowaction', + 'title' => sprintf($this->translate('Show the overview of the %s module'), $module->name) + ) + ); ?> + + -
translate('Module') ?>translate('Module') ?>
- enabled && $module->loaded) { - echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name)); - } elseif (! $module->enabled) { - echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name)); - } else { // ! $module->loaded - echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name)); - } +
+ enabled && $module->loaded) { + echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name)); + } elseif (! $module->enabled) { + echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name)); + } else { // ! $module->loaded + echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name)); + } - echo $this->qlink( - $module->name, - 'config/module/', - array('name' => $module->name), - array('title' => sprintf($this->translate('Show the overview of the %s module'), $module->name), 'class' => 'rowaction') - ); ?> -
+
diff --git a/application/views/scripts/config/resource.phtml b/application/views/scripts/config/resource.phtml index 6a32cca67..ec9c0c7ea 100644 --- a/application/views/scripts/config/resource.phtml +++ b/application/views/scripts/config/resource.phtml @@ -13,7 +13,7 @@ 'title' => $this->translate('Create a new resource') ) ) ?> - +
diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml index 846184493..0e7800f0e 100644 --- a/application/views/scripts/form/reorder-authbackend.phtml +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -1,5 +1,5 @@ -
translate('Resource') ?>
+
diff --git a/application/views/scripts/group/list.phtml b/application/views/scripts/group/list.phtml index b2bc9b920..a3c597b00 100644 --- a/application/views/scripts/group/list.phtml +++ b/application/views/scripts/group/list.phtml @@ -47,7 +47,7 @@ if (! isset($backend)) { -
translate('Backend') ?>
+
@@ -95,4 +95,4 @@ if (! isset($backend)) {
translate('User Group'); ?>
-
\ No newline at end of file +
diff --git a/application/views/scripts/group/show.phtml b/application/views/scripts/group/show.phtml index fb850a2a5..a460c7ece 100644 --- a/application/views/scripts/group/show.phtml +++ b/application/views/scripts/group/show.phtml @@ -69,7 +69,7 @@ if ($this->hasPermission('config/authentication/groups/edit') && $backend instan
- +
@@ -105,4 +105,4 @@ if ($this->hasPermission('config/authentication/groups/edit') && $backend instan
translate('Username'); ?>
- \ No newline at end of file + diff --git a/application/views/scripts/list/applicationlog.phtml b/application/views/scripts/list/applicationlog.phtml index 15fe9cef1..9d5e15bfa 100644 --- a/application/views/scripts/list/applicationlog.phtml +++ b/application/views/scripts/list/applicationlog.phtml @@ -1,37 +1,29 @@ compact): ?> -
- tabs; ?> -
-
- limiter ?> -
-
- paginator ?> -
-
- sortBox ?> -
+
+ tabs ?> +
+ limiter ?> + paginator ?>
- filterEditor; ?>
- logData !== null): ?> +logData !== null): ?> - - logData as $value): ?> - datetime); ?> - - - - - - + + logData as $value): ?> + datetime) ?> + + + + + +
- escape($datetime->format('d.m. H:i')) ?>
- escape($value->loglevel) ?> -
- escape($value->message), false) ?> -
+ escape($datetime->format('d.m. H:i')) ?>
+ escape($value->loglevel) ?> +
+ escape($value->message), false) ?> +
- +
diff --git a/application/views/scripts/navigation/index.phtml b/application/views/scripts/navigation/index.phtml index e24a3a59f..bf085629b 100644 --- a/application/views/scripts/navigation/index.phtml +++ b/application/views/scripts/navigation/index.phtml @@ -1,16 +1,8 @@ compact): ?> -
+
tabs ?> -
-
- limiter ?> -
-
- paginator ?> -
-
- sortBox ?> -
+
+ sortBox ?>
filterEditor ?>
@@ -31,7 +23,7 @@

translate('You did not create any navigation item yet.') ?>

- +
diff --git a/application/views/scripts/navigation/shared.phtml b/application/views/scripts/navigation/shared.phtml index aae7fa552..c23abc628 100644 --- a/application/views/scripts/navigation/shared.phtml +++ b/application/views/scripts/navigation/shared.phtml @@ -3,27 +3,18 @@ use Icinga\Web\Url; if (! $this->compact): ?> -
+
tabs; ?> -
-
- limiter ?> -
-
- paginator ?> -
-
- sortBox ?> -
+
+ sortBox ?>
- filterEditor; ?>

translate('There are currently no navigation items being shared'); ?>

-
translate('Navigation') ?>
+
@@ -74,4 +65,4 @@ if (! $this->compact): ?>
translate('Shared Navigation'); ?> translate('Type'); ?>
-
\ No newline at end of file +
diff --git a/application/views/scripts/role/list.phtml b/application/views/scripts/role/list.phtml index 00b9c7579..9d047b4d7 100644 --- a/application/views/scripts/role/list.phtml +++ b/application/views/scripts/role/list.phtml @@ -16,7 +16,7 @@ isEmpty()): ?>

translate('No roles found.') ?>

- +
diff --git a/application/views/scripts/user/list.phtml b/application/views/scripts/user/list.phtml index 26114d657..b085881ef 100644 --- a/application/views/scripts/user/list.phtml +++ b/application/views/scripts/user/list.phtml @@ -47,7 +47,7 @@ if (! isset($backend)) { -
translate('Name') ?>
+
@@ -89,4 +89,4 @@ if (! isset($backend)) {
translate('Username') ?>
-
\ No newline at end of file + diff --git a/application/views/scripts/user/show.phtml b/application/views/scripts/user/show.phtml index 2fbdab551..2fc476bed 100644 --- a/application/views/scripts/user/show.phtml +++ b/application/views/scripts/user/show.phtml @@ -72,7 +72,7 @@ if ($this->hasPermission('config/authentication/users/edit') && $backend instanc - +
@@ -108,4 +108,4 @@ if ($this->hasPermission('config/authentication/users/edit') && $backend instanc
translate('Group'); ?>
- \ No newline at end of file + diff --git a/application/views/scripts/usergroupbackend/list.phtml b/application/views/scripts/usergroupbackend/list.phtml index fd688d80d..5ce1df90f 100644 --- a/application/views/scripts/usergroupbackend/list.phtml +++ b/application/views/scripts/usergroupbackend/list.phtml @@ -14,7 +14,7 @@ ) ) ?> - +
diff --git a/doc/installation.md b/doc/installation.md index 156c26af7..c26f5a504 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -53,7 +53,7 @@ add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main' apt-get update ```` -For other Ubuntu versions just replace trusty with your distribution's code name. +For other Ubuntu versions just replace trusty with your distribution\'s code name. **RHEL and CentOS**: ```` @@ -171,10 +171,10 @@ Adopt the package requirements to your needs (e.g. adding ldap for authenticatio Example for RHEL/CentOS/Fedora: -```` -# yum install httpd mysql-server -# yum install php php-gd php-intl php-ZendFramework php-ZendFramework-Db-Adapter-Pdo-Mysql -```` +``` +yum install httpd mysql-server +yum install php php-gd php-intl php-ZendFramework php-ZendFramework-Db-Adapter-Pdo-Mysql +``` The setup wizard will check the pre-requisites later on. @@ -311,13 +311,13 @@ Puppet, Ansible, Chef, etc. modules. Create the database and add a new user as shown below for MySQL: ```` -# sudo mysql -p +sudo mysql -p CREATE DATABASE icingaweb2; GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icingaweb2.* TO 'icingaweb2'@'localhost' IDENTIFIED BY 'icingaweb2'; quit -# mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql +mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql ```` @@ -325,7 +325,7 @@ Then generate a new password hash as described in the [authentication docs](auth and use it to insert a new user called `icingaadmin` into the database. ```` -# mysql -p icingaweb2 +mysql -p icingaweb2 INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$1$EzxLOFDr$giVx3bGhVm4lDUAw6srGX1'); quit diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index c46aa3a27..d19e6cde3 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -348,29 +348,24 @@ abstract class ApplicationBootstrap require $this->libDir . '/Icinga/Application/ClassLoader.php'; $this->loader = new ClassLoader(); - $this->loader->registerNamespace('Icinga', $this->libDir. '/Icinga'); + $this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga'); + $this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga', $this->appDir); $this->loader->register(); return $this; } /** - * Register the Zend Autoloader + * Register the Zend Autoloader - compat only - does nothing * + * @deprecated * @return $this */ public function setupZendAutoloader() { - require_once 'Zend/Loader/Autoloader.php'; - - \Zend_Loader_Autoloader::getInstance(); - - \Zend_Paginator::addScrollingStylePrefixPath( - 'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle' - ); - return $this; } + /** * Setup module manager * diff --git a/library/Icinga/Application/ClassLoader.php b/library/Icinga/Application/ClassLoader.php index 3247d3250..28dd633fe 100644 --- a/library/Icinga/Application/ClassLoader.php +++ b/library/Icinga/Application/ClassLoader.php @@ -3,6 +3,8 @@ namespace Icinga\Application; +use Zend_Loader_Autoloader; + /** * PSR-4 class loader */ @@ -13,6 +15,40 @@ class ClassLoader */ const NAMESPACE_SEPARATOR = '\\'; + /** + * Icinga Web 2 module namespace prefix + */ + const MODULE_PREFIX = 'Icinga\\Module\\'; + + /** + * Icinga Web 2 module namespace prefix length + * + * Helps to make substr/strpos operations even faster + */ + const MODULE_PREFIX_LENGTH = 14; + + /** + * A hardcoded class/subdir map for application ns prefixes + * + * When a module registers with an application directory, those + * namespace prefixes (after the module prefix) will be looked up + * in the corresponding application subdirectories + * + * @var array + */ + protected $applicationPrefixes = array( + 'Clicommands' => 'clicommands', + 'Controllers' => 'controllers', + 'Forms' => 'forms' + ); + + /** + * Whether we already instantiated the ZF autoloader + * + * @var boolean + */ + protected $gotZend = false; + /** * Namespaces * @@ -20,18 +56,33 @@ class ClassLoader */ private $namespaces = array(); + /** + * Application directories + * + * @var array + */ + private $applicationDirectories = array(); + /** * Register a base directory for a namespace prefix * + * Application directory is optional and provides additional lookup + * logic for hardcoded namespaces like "Forms" + * * @param string $namespace * @param string $directory + * @param string $appDirectory * * @return $this */ - public function registerNamespace($namespace, $directory) + public function registerNamespace($namespace, $directory, $appDirectory = null) { $this->namespaces[$namespace] = $directory; + if ($appDirectory !== null) { + $this->applicationDirectories[$namespace] = $appDirectory; + } + return $this; } @@ -56,21 +107,177 @@ class ClassLoader */ public function getSourceFile($class) { + if ($file = $this->getModuleSourceFile($class)) { + return $file; + } + foreach ($this->namespaces as $namespace => $dir) { if ($class === strstr($class, $namespace)) { - $classPath = str_replace( - self::NAMESPACE_SEPARATOR, - DIRECTORY_SEPARATOR, - substr($class, strlen($namespace)) - ) . '.php'; - if (file_exists($file = $dir . $classPath)) { - return $file; - } + return $this->buildClassFilename($class, $namespace); } } + return null; } + /** + * Get the source file of the given module class or interface + * + * @param string $class Module class or interface name + * + * @return string|null + */ + protected function getModuleSourceFile($class) + { + if (! $this->classBelongsToModule($class)) { + return null; + } + + $modules = Icinga::app()->getModuleManager(); + $namespace = $this->extractModuleNamespace($class); + + if ($this->hasNamespace($namespace)) { + + return $this->buildClassFilename($class, $namespace); + + } elseif (! $modules->loadedAllEnabledModules()) { + + $moduleName = $this->extractModuleName($class); + + if ($modules->hasEnabled($moduleName)) { + $modules->loadModule($moduleName); + + return $this->buildClassFilename($class, $namespace); + } + } + + return null; + } + + /** + * Extract the Icinga module namespace from a given namespaced class name + * + * Does no validation, prefix must have been checked before + * + * @return string + */ + protected function extractModuleNamespace($class) + { + return substr( + $class, + 0, + strpos($class, self::NAMESPACE_SEPARATOR, self::MODULE_PREFIX_LENGTH + 1) + ); + } + + /** + * Extract the Icinga module name from a given namespaced class name + * + * Does no validation, prefix must have been checked before + * + * @return string + */ + protected function extractModuleName($class) + { + return lcfirst( + substr( + $class, + self::MODULE_PREFIX_LENGTH, + strpos( + $class, + self::NAMESPACE_SEPARATOR, + self::MODULE_PREFIX_LENGTH + 1 + ) - self::MODULE_PREFIX_LENGTH + ) + ); + } + + /** + * Whether the given class name belongs to a module namespace + * + * @return boolean + */ + protected function classBelongsToModule($class) + { + return substr($class, 0, self::MODULE_PREFIX_LENGTH) === self::MODULE_PREFIX; + } + + /** + * Prepare a filename string for the given class + * + * Expects the given namespace to be registered with a path name + * + * @return string + */ + protected function buildClassFilename($class, $namespace) + { + $relNs = substr($class, strlen($namespace) + 1); + + if ($this->namespaceHasApplictionDirectory($namespace)) { + $prefixSeparator = strpos($relNs, self::NAMESPACE_SEPARATOR); + $prefix = substr($relNs, 0, $prefixSeparator); + + if ($this->isApplicationPrefix($prefix)) { + return $this->applicationDirectories[$namespace] + . DIRECTORY_SEPARATOR + . $this->applicationPrefixes[$prefix] + . $this->classToRelativePhpFilename(substr($relNs, $prefixSeparator)); + } + } + + return $this->namespaces[$namespace] . DIRECTORY_SEPARATOR . $this->classToRelativePhpFilename($relNs); + } + + /** + * Return the relative file name for the given (namespaces) class + * + * @param string $class + * + * @return string + */ + protected function classToRelativePhpFilename($class) + { + return str_replace( + self::NAMESPACE_SEPARATOR, + DIRECTORY_SEPARATOR, + $class + ) . '.php'; + } + + /** + * Whether given prefix (Forms, Controllers...) makes part of "application" + * + * @param string $prefix + * + * @return boolean + */ + protected function isApplicationPrefix($prefix) + { + return array_key_exists($prefix, $this->applicationPrefixes); + } + + /** + * Whether the given namespace registered an application directory + * + * @return boolean + */ + protected function namespaceHasApplictionDirectory($namespace) + { + return array_key_exists($namespace, $this->applicationDirectories); + } + + /** + * Require ZF autoloader + * + * @return Zend_Loader_Autoloader + */ + protected function requireZendAutoloader() + { + require_once 'Zend/Loader/Autoloader.php'; + $this->gotZend = true; + return Zend_Loader_Autoloader::getInstance(); + } + /** * Load the given class or interface * @@ -80,10 +287,22 @@ class ClassLoader */ public function loadClass($class) { - if ($file = $this->getSourceFile($class)) { - require $file; - return true; + // We are aware of the Zend_ prefix and lazyload it's autoloader. + // Return as fast as possible if we already did so. + if (substr($class, 0, 5) === 'Zend_') { + if (! $this->gotZend) { + $this->requireZendAutoloader(); + } + return false; } + + if ($file = $this->getSourceFile($class)) { + if (file_exists($file)) { + require $file; + return true; + } + } + return false; } diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index f3bf4e016..b6947c833 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -73,6 +73,13 @@ class Manager */ private $modulePaths = array(); + /** + * Whether we loaded all enabled modules + * + * @var bool + */ + private $loadedAllEnabledModules = false; + /** * Create a new instance of the module manager * @@ -177,12 +184,28 @@ class Manager */ public function loadEnabledModules() { - foreach ($this->listEnabledModules() as $name) { - $this->loadModule($name); + if (! $this->loadedAllEnabledModules) { + foreach ($this->listEnabledModules() as $name) { + $this->loadModule($name); + } + + $this->loadedAllEnabledModules = true; } + return $this; } + /** + * Whether we loaded all enabled modules + * + * @return bool + */ + public function loadedAllEnabledModules() + { + return $this->loadedAllEnabledModules; + } + + /** * Try to load the module and register it in the application * @@ -245,6 +268,8 @@ class Manager ); } + $this->loadedAllEnabledModules = false; + if (file_exists($link) && is_link($link)) { return $this; } diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 842a581a9..737e5265e 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -51,6 +51,13 @@ class Module */ private $cssdir; + /** + * Base application directory + * + * @var string + */ + private $appdir; + /** * Library directory * @@ -244,6 +251,7 @@ class Module $this->jsdir = $basedir . '/public/js'; $this->libdir = $basedir . '/library'; $this->configdir = $app->getConfigDir('modules/' . $name); + $this->appdir = $basedir . '/application'; $this->localedir = $basedir . '/application/locale'; $this->formdir = $basedir . '/application/forms'; $this->controllerdir = $basedir . '/application/controllers'; @@ -739,6 +747,16 @@ class Module return $this->basedir; } + /** + * Get the module's application directory + * + * @return string + */ + public function getApplicationDir() + { + return $this->appdir; + } + /** * Get the module's library directory * @@ -1043,18 +1061,13 @@ class Module return $this; } - $loader = $this->app->getLoader(); $moduleName = ucfirst($this->getName()); - $moduleLibraryDir = $this->getLibDir(). '/'. $moduleName; - if (is_dir($moduleLibraryDir)) { - $loader->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir); - } - - $moduleFormDir = $this->getFormDir(); - if (is_dir($moduleFormDir)) { - $loader->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir); - } + $this->app->getLoader()->registerNamespace( + 'Icinga\\Module\\' . $moduleName, + $this->getLibDir() . '/'. $moduleName, + $this->getApplicationDir() + ); $this->registeredAutoloader = true; @@ -1118,21 +1131,10 @@ class Module if (! $this->app->isWeb()) { return $this; } - $moduleControllerDir = $this->getControllerDir(); - if (is_dir($moduleControllerDir)) { - $this->app->getfrontController()->addControllerDirectory( - $moduleControllerDir, - $this->getName() - ); - $this->app->getLoader()->registerNamespace( - 'Icinga\\Module\\' . ucfirst($this->getName()) . '\\' . Dispatcher::CONTROLLER_NAMESPACE, - $moduleControllerDir - ); - } - $this + + return $this ->registerLocales() ->registerRoutes(); - return $this; } /** @@ -1143,6 +1145,13 @@ class Module protected function registerRoutes() { $router = $this->app->getFrontController()->getRouter(); + + // TODO: We should not be required to do this. Please check dispatch() + $this->app->getfrontController()->addControllerDirectory( + $this->getControllerDir(), + $this->getName() + ); + /** @var \Zend_Controller_Router_Rewrite $router */ foreach ($this->routes as $name => $route) { $router->addRoute($name, $route); diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index 24b7e641d..ce69dbb0a 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -91,7 +91,6 @@ class Web extends EmbeddedWeb ->setupLogger() ->setupInternationalization() ->setupZendMvc() - ->setupNamespaces() ->setupModuleManager() ->loadSetupModuleIfNecessary() ->loadEnabledModules() @@ -140,19 +139,37 @@ class Web extends EmbeddedWeb return $this->viewRenderer; } - private function hasAccessToSharedNavigationItem(& $config) + private function hasAccessToSharedNavigationItem(& $config, Config $navConfig) { // TODO: Provide a more sophisticated solution if (isset($config['owner']) && $config['owner'] === $this->user->getUsername()) { unset($config['owner']); + unset($config['users']); + unset($config['groups']); return true; } + if (isset($config['parent']) && $navConfig->hasSection($config['parent'])) { + unset($config['owner']); + if (isset($this->accessibleMenuItems[$config['parent']])) { + return $this->accessibleMenuItems[$config['parent']]; + } + + $parentConfig = $navConfig->getSection($config['parent']); + $this->accessibleMenuItems[$config['parent']] = $this->hasAccessToSharedNavigationItem( + $parentConfig, + $navConfig + ); + return $this->accessibleMenuItems[$config['parent']]; + } + if (isset($config['users'])) { $users = array_map('trim', explode(',', strtolower($config['users']))); if (in_array('*', $users, true) || in_array($this->user->getUsername(), $users, true)) { + unset($config['owner']); unset($config['users']); + unset($config['groups']); return true; } } @@ -160,6 +177,8 @@ class Web extends EmbeddedWeb if (isset($config['groups'])) { $groups = array_map('trim', explode(',', strtolower($config['groups']))); if (in_array('*', $groups, true)) { + unset($config['owner']); + unset($config['users']); unset($config['groups']); return true; } @@ -167,6 +186,8 @@ class Web extends EmbeddedWeb $userGroups = array_map('strtolower', $this->user->getGroups()); $matches = array_intersect($userGroups, $groups); if (! empty($matches)) { + unset($config['owner']); + unset($config['users']); unset($config['groups']); return true; } @@ -208,8 +229,17 @@ class Web extends EmbeddedWeb } else { $items = array(); foreach ($config as $name => $typeConfig) { - if ($this->hasAccessToSharedNavigationItem($typeConfig)) { - $items[$name] = $typeConfig; + if (isset($this->accessibleMenuItems[$name])) { + if ($this->accessibleMenuItems[$name]) { + $items[$name] = $typeConfig; + } + } else { + if ($this->hasAccessToSharedNavigationItem($typeConfig, $config)) { + $this->accessibleMenuItems[$name] = true; + $items[$name] = $typeConfig; + } else { + $this->accessibleMenuItems[$name] = false; + } } } @@ -292,22 +322,20 @@ class Web extends EmbeddedWeb 'cssClass' => 'user-nav-item', 'label' => $this->user->getUsername(), 'icon' => 'user', - 'url' => 'preference', 'priority' => 900, - 'renderer' => array( - 'UserNavigationItemRenderer' - ), - ), - 'logout' => array( - 'cssClass' => 'user-nav-item', - 'label' => t('Logout'), - 'icon' => 'starttime', - 'priority' => 990, - 'renderer' => array( - 'LogoutNavigationItemRenderer', - 'target' => '_self' - ), - 'url' => 'authentication/logout' + 'children' => array( + 'preferences' => array( + 'label' => t('Preferences'), + 'priority' => 100, + 'url' => 'preference' + ), + 'logout' => array( + 'label' => t('Logout'), + 'priority' => 200, + 'target' => '_self', + 'url' => 'authentication/logout' + ) + ) ) ); @@ -346,6 +374,7 @@ class Web extends EmbeddedWeb 'layoutPath' => $this->getApplicationDir('/layouts/scripts') ) ); + $this->setupFrontController(); $this->setupViewRenderer(); return $this; @@ -492,24 +521,4 @@ class Web extends EmbeddedWeb } return Translator::DEFAULT_LOCALE; } - - /** - * Setup class loader namespaces for Icinga\Controllers and Icinga\Forms - * - * @return $this - */ - private function setupNamespaces() - { - $this - ->getLoader() - ->registerNamespace( - 'Icinga\\' . Dispatcher::CONTROLLER_NAMESPACE, - $this->getApplicationDir('controllers') - ) - ->registerNamespace( - 'Icinga\\Forms', - $this->getApplicationDir('forms') - ); - return $this; - } } diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index ca087bfcf..c747a0908 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -1171,10 +1171,9 @@ class Form extends Zend_Form $this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl(); } } elseif ($this->getIsApiTarget()) { - $this->getResponse()->sendJson(array( - 'status' => 'fail', - 'data' => array_merge($this->getMessages(), $this->getErrorMessages()) - )); + $this->getResponse()->json()->setFailData( + array_merge($this->getMessages(), $this->getErrorMessages()) + )->sendResponse(); } } elseif ($this->getValidatePartial()) { // The form can't be processed but we may want to show validation errors though diff --git a/library/Icinga/Web/Form/Decorator/FormHints.php b/library/Icinga/Web/Form/Decorator/FormHints.php index f16a07318..c6a63f8dd 100644 --- a/library/Icinga/Web/Form/Decorator/FormHints.php +++ b/library/Icinga/Web/Form/Decorator/FormHints.php @@ -58,7 +58,7 @@ class FormHints extends Zend_Form_Decorator_Abstract $hints = $this->recurseForm($form, $entirelyRequired); if ($entirelyRequired !== null) { $hints[] = $form->getView()->translate(sprintf( - 'Required fields are marked with %s and must be filled in to complete the form.', + '%s Required field', $form->getRequiredCue() )); } diff --git a/library/Icinga/Web/Navigation/Renderer/BadgeNavigationItemRenderer.php b/library/Icinga/Web/Navigation/Renderer/BadgeNavigationItemRenderer.php index 5160d5d66..3ff98bec0 100644 --- a/library/Icinga/Web/Navigation/Renderer/BadgeNavigationItemRenderer.php +++ b/library/Icinga/Web/Navigation/Renderer/BadgeNavigationItemRenderer.php @@ -94,7 +94,22 @@ abstract class BadgeNavigationItemRenderer extends NavigationItemRenderer */ public function render(NavigationItem $item = null) { - return '
' . $this->renderBadge() . parent::render($item) . '
'; + if ($item === null) { + $item = $this->getItem(); + } + $item->setCssClass('badge-nav-item'); + $this->setEscapeLabel(false); + $label = $this->view()->escape($item->getLabel()); + if (($icon = $item->getIcon()) !== null) { + $label = $this->view()->icon($icon) . $label; + $item->setIcon(null); + } + $item->setLabel($this->renderBadge() . $label); + $html = parent::render($item); + if ($icon) { + $item->setIcon(true); + } + return $html; } /** @@ -107,7 +122,7 @@ abstract class BadgeNavigationItemRenderer extends NavigationItemRenderer if ($count = $this->getCount()) { $view = $this->view(); return sprintf( - '%s', + '%s', $view->escape($this->getTitle()), $view->escape($this->getState()), $count diff --git a/library/Icinga/Web/Navigation/Renderer/LogoutNavigationItemRenderer.php b/library/Icinga/Web/Navigation/Renderer/LogoutNavigationItemRenderer.php deleted file mode 100644 index 1dad7c434..000000000 --- a/library/Icinga/Web/Navigation/Renderer/LogoutNavigationItemRenderer.php +++ /dev/null @@ -1,14 +0,0 @@ -navigation->getLayout() === Navigation::LAYOUT_TABS) { @@ -282,6 +284,8 @@ class NavigationRenderer implements RecursiveIterator, NavigationRendererInterfa $cssClass[] = static::CSS_CLASS_NAV_DROPDOWN; } + $cssClass[] = 'nav-level-' . $level; + return ''); + $table = array(''); foreach ($pieChartData as $perfdata) { if ($compact && $perfdata->isVisualizable()) { $results[] = $perfdata->asInlinePie($color)->render(); } else { $data = array(); if ($perfdata->isVisualizable()) { - $data []= $perfdata->asInlinePie($color)->render() . ' '; + $data []= $perfdata->asInlinePie($color)->render(); } elseif (isset($columns[''])) { $data []= ''; } @@ -85,9 +85,10 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract ); } } - $table []= ''; + $table []= ''; } } + $table[] = ''; if ($limit > 0) { $count = $compact ? count($results) : count($table); if ($count > $limit) { @@ -107,8 +108,7 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract return ''; } return sprintf( - '
translate('Backend') ?>' . implode('', $headers) . '
' . implode('', $headers) . '
' . implode('', $data) . '
' . implode('', $data) . '
%s
', - isset($columns['']) ? 'perfdata-piecharts' : '', + '%s
', implode("\n", $table) ); } diff --git a/modules/monitoring/application/views/helpers/PluginOutput.php b/modules/monitoring/application/views/helpers/PluginOutput.php index dec3ca504..da33a5efd 100644 --- a/modules/monitoring/application/views/helpers/PluginOutput.php +++ b/modules/monitoring/application/views/helpers/PluginOutput.php @@ -40,6 +40,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract 'getPurifier()->purify($output) ); + $isHtml = true; } else { // Plaintext $output = preg_replace( @@ -47,11 +48,17 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract self::$txtReplacements, $this->view->escape($output) ); - } - if (! $raw) { - $output = '
' . $output . '
'; + $isHtml = false; } $output = $this->fixLinks($output); + + if (! $raw) { + if ($isHtml) { + $output = '
' . $output . '
'; + } else { + $output = '
' . $output . '
'; + } + } return $output; } diff --git a/modules/monitoring/application/views/scripts/config/index.phtml b/modules/monitoring/application/views/scripts/config/index.phtml index 80882b59f..091aaf70f 100644 --- a/modules/monitoring/application/views/scripts/config/index.phtml +++ b/modules/monitoring/application/views/scripts/config/index.phtml @@ -10,12 +10,12 @@ 'monitoring/config/createbackend', null, array( - 'class' => 'button action-link', + 'class' => 'button-link', 'icon' => 'plus', 'title' => $this->translate('Create a new monitoring backend') ) ) ?> -
+
@@ -35,7 +35,7 @@ 'title' => sprintf($this->translate('Edit monitoring backend %s'), $backendName) ) ) ?> - ((translate('Type: %s'), $this->escape($config->type === 'ido' ? 'IDO' : ucfirst($config->type)) ) ?>) @@ -65,12 +65,12 @@ 'monitoring/config/createtransport', null, array( - 'class' => 'button action-link', + 'class' => 'button-link', 'icon' => 'plus', 'title' => $this->translate('Create a new command transport') ) ) ?> -
translate('Monitoring Backend') ?>
+
@@ -90,7 +90,7 @@ 'title' => sprintf($this->translate('Edit command transport %s'), $transportName) ) ); ?> - ((translate('Type: %s'), $config->host !== null ? $this->translate('Remote') : $this->translate('Local') ) ?>) diff --git a/modules/monitoring/application/views/scripts/host/history.phtml b/modules/monitoring/application/views/scripts/host/history.phtml deleted file mode 100644 index 6b4093b98..000000000 --- a/modules/monitoring/application/views/scripts/host/history.phtml +++ /dev/null @@ -1,166 +0,0 @@ -qlink( - $contact, - 'monitoring/show/contact', - array('contact_name' => $contact), - array('title' => sprintf($view->translate('Show detailed information about %s'), $contact)) - ); - } - return '[' . implode(', ', $links) . ']'; -} - -$self = $this; - -$url = $this->url(); -$limit = (int) $url->getParam('limit', 25); -if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) { - $page = 1; -} - -$history->limit($limit * $page); - -if (! $this->compact): ?> -
- tabs; ?> - render('partials/object/host-header.phtml'); ?> -

translate('This Host\'s Event History'); ?>

- sortBox; ?> - limiter; ?> - - translate('Scroll to the bottom of this page to load additional events'); ?> - - filterEditor; ?> -
- -
-
translate('Transport') ?>
- - peekAhead() as $event): ?> - escape($event->output); - $isService = isset($event->service_description); - switch ($event->type) { - case 'notify': - $icon = 'notification'; - $title = $this->translate('Notification'); - $stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - - $msg = $msg ? preg_replace_callback( - '/^\[([^\]]+)\]/', - function($match) use ($self) { return contactsLink($match, $self); }, - $msg - ) : $this->translate('This notification was not sent out to any contact.'); - break; - case 'comment': - $icon = 'comment'; - $title = $this->translate('Comment'); - break; - case 'comment_deleted': - $icon = 'remove'; - $title = $this->translate('Comment deleted'); - break; - case 'ack': - $icon = 'acknowledgement'; - $title = $this->translate('Acknowledge'); - break; - case 'ack_deleted': - $icon = 'remove'; - $title = $this->translate('Ack removed'); - break; - case 'dt_comment': - $icon = 'in_downtime'; - $title = $this->translate('In Downtime'); - break; - case 'dt_comment_deleted': - $icon = 'remove'; - $title = $this->translate('Downtime removed'); - break; - case 'flapping': - $icon = 'flapping'; - $title = $this->translate('Flapping'); - break; - case 'flapping_deleted': - $icon = 'remove'; - $title = $this->translate('Flapping stopped'); - break; - case 'hard_state': - $stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - $icon = 'attention-alt'; - $title = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - break; - case 'soft_state': - $icon = 'spinner'; - $stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - $title = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - break; - case 'dt_start': - $icon = 'downtime_start'; - $title = $this->translate('Downtime Start'); - break; - case 'dt_end': - $icon = 'downtime_end'; - $title = $this->translate('Downtime End'); - break; - } - ?> - - - - - - -
- getIteratorPosition() % $limit === 0): ?> - - - escape($title); ?> -

timestamp); ?>

-
- - translate('%s on %s', 'Service running on host'), - $this->qlink( - $event->service_display_name, - 'monitoring/service/show', - array( - 'host' => $event->host_name, - 'service' => $event->service_description - ), - array('title' => sprintf( - $this->translate('Show detailed information for service %s on host %s'), - $event->service_display_name, - $event->host_display_name - )) - ), - $event->host_display_name - ) ?> - - escape($event->host_name); ?> - -

- icon($icon, $title); ?> createTicketLinks($msg) ?> -

-
-hasResult()): ?> - translate('No history events found matching the filter'); ?> -hasMore()): ?> - qlink( - $this->translate('Load More'), - $url->setAnchor('page-' . ($page + 1)), - array( - 'page' => $page + 1, - ), - array( - 'id' => 'load-more', - 'class' => 'pull-right action-link' - ) - ); ?> - - diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml index e496ced29..45849a524 100644 --- a/modules/monitoring/application/views/scripts/list/comments.phtml +++ b/modules/monitoring/application/views/scripts/list/comments.phtml @@ -12,7 +12,7 @@
" data-icinga-multiselect-data="comment_id"> diff --git a/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml index ab1695765..688fafc0f 100644 --- a/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml +++ b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml @@ -8,16 +8,16 @@ if (! $stats instanceof stdClass) { } ?>
-qlink( - sprintf($this->translatePlural('%u Host', '%u Hosts', $stats->hosts_total), $stats->hosts_total), - // @TODO(el): Fix that - Url::fromPath('monitoring/list/hosts')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), - null, - array('title' => sprintf( - $this->translatePlural('List %u host', 'List all %u hosts', $stats->hosts_total), - $stats->hosts_total - )) -) ?>: + qlink( + sprintf($this->translatePlural('%u Host', '%u Hosts', $stats->hosts_total), $stats->hosts_total), + // @TODO(el): Fix that + Url::fromPath('monitoring/list/hosts')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), + null, + array('title' => sprintf( + $this->translatePlural('List %u host', 'List all %u hosts', $stats->hosts_total), + $stats->hosts_total + )) + ) ?>: translate('Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to select a range of rows.', 'multiselection'); +$helpMessage = $this->translate( + 'Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to' + .' select a range of rows', + 'Multi-selection help' +); ?> -
- 0 translate('row(s) selected', 'multiselection') ?> +
+ translate('%s row(s) selected', 'Multi-selection count'), + '0' + ) ?>
diff --git a/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml b/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml index b8b61aebe..a56c33c33 100644 --- a/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml +++ b/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml @@ -8,19 +8,19 @@ if (! $stats instanceof stdClass) { } ?>
-qlink( - sprintf($this->translatePlural( - '%u Service', '%u Services', $stats->services_total), - $stats->services_total - ), - // @TODO(el): Fix that - Url::fromPath('monitoring/list/services')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), - null, - array('title' => sprintf( - $this->translatePlural('List %u service', 'List all %u services', $stats->services_total), - $stats->services_total - )) -) ?>: + qlink( + sprintf($this->translatePlural( + '%u Service', '%u Services', $stats->services_total), + $stats->services_total + ), + // @TODO(el): Fix that + Url::fromPath('monitoring/list/services')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), + null, + array('title' => sprintf( + $this->translatePlural('List %u service', 'List all %u services', $stats->services_total), + $stats->services_total + )) + ) ?>: -
+
diff --git a/modules/monitoring/application/views/scripts/list/contacts.phtml b/modules/monitoring/application/views/scripts/list/contacts.phtml index 6ece9e8df..5517f4fc3 100644 --- a/modules/monitoring/application/views/scripts/list/contacts.phtml +++ b/modules/monitoring/application/views/scripts/list/contacts.phtml @@ -11,7 +11,7 @@
hasResult()): ?> -
+
diff --git a/modules/monitoring/application/views/scripts/list/downtimes.phtml b/modules/monitoring/application/views/scripts/list/downtimes.phtml index f6023f421..56be44ffd 100644 --- a/modules/monitoring/application/views/scripts/list/downtimes.phtml +++ b/modules/monitoring/application/views/scripts/list/downtimes.phtml @@ -16,7 +16,7 @@ if (! $this->compact): ?>
translate('Name') ?>
" data-icinga-multiselect-data="downtime_id"> @@ -30,7 +30,6 @@ if (! $this->compact): ?> $this->stateName = Host::getStateText($downtime->host_state); } $this->downtime = $downtime; - $this->displayComment = true; ?> render('partials/downtime/downtime-header.phtml'); ?> diff --git a/modules/monitoring/application/views/scripts/list/eventhistory.phtml b/modules/monitoring/application/views/scripts/list/eventhistory.phtml index cddad22fd..4923f2079 100644 --- a/modules/monitoring/application/views/scripts/list/eventhistory.phtml +++ b/modules/monitoring/application/views/scripts/list/eventhistory.phtml @@ -1,140 +1,17 @@ url(); -$limit = (int) $url->getParam('limit', 25); -if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) { - $page = 1; -} - -$history->limit($limit * $page); if (! $this->compact): ?>
- tabs; ?> -
-
- limiter ?> + tabs ?> +
+ limiter ?> + sortBox ?>
- -
- sortBox ?> -
-
- filterEditor; ?> + filterEditor ?>
-
-
- - peekAhead() as $event): ?> - output; - $title = $event->type; - $stateName = 'invalid'; - $isService = isset($event->service_description); - switch ($event->type) { - case 'notify': - $icon = 'bell'; - $title = $this->translate('Notification'); - $msg = $msg ?: $this->translate('This notification was not sent out to any contact.'); - break; - case 'comment': - $icon = 'comment'; - $title = $this->translate('Comment'); - break; - case 'ack': - $icon = 'ok'; - $title = $this->translate('Acknowledgement'); - break; - case 'dt_comment': - $icon = 'plug'; - $title = $this->translate('In Downtime'); - break; - case 'flapping': - $icon = 'flapping'; - $title = $this->translate('Flapping'); - break; - case 'flapping_deleted': - $icon = 'ok'; - $title = $this->translate('Flapping Stopped'); - break; - case 'hard_state': - $icon = $isService ? 'service' : 'host'; - $stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - $title = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true); - break; - case 'soft_state': - $icon = 'lightbulb'; - $stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); - $title = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true); - break; - case 'dt_start': - $icon = 'starttime'; - $title = $this->translate('Downtime Start'); - break; - case 'dt_end': - $icon = 'endtime'; - $title = $this->translate('Downtime End'); - break; - } - ?> - - - - - - -
- getIteratorPosition() % $limit === 0): ?> - - - escape($title); ?> -

timeAgo($event->timestamp, $this->compact); ?>

-
- icon($icon, $title); ?> - - link()->service( - $event->service_description, $event->service_display_name, $event->host_name, $event->host_display_name, 'rowaction' - ) ?> - - link()->host($event->host_name, $event->host_display_name) ?> - -

- escape($msg) ?> -

-
-hasResult()): ?> - translate('No history events found matching the filter'); ?> -hasMore()): ?> - compact): ?> - qlink( - $this->translate('Show More'), - $url->without(array('view', 'limit')), - null, - array( - 'data-base-target' => '_next', - 'class' => 'pull-right action-link' - ) - ); ?> - - qlink( - $this->translate('Load More'), - $url->setAnchor('page-' . ($page + 1)), - array( - 'page' => $page + 1, - ), - array( - 'id' => 'load-more', - 'class' => 'pull-right action-link' - ) - ); ?> - - -
+partial( + 'partials/event-history.phtml', + array('compact' => $this->compact, 'history' => $history, 'isOverview' => true, 'tableCssClass' => 'table-row-selectable') +) ?> + diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index 4d6d235bc..1eb5e754d 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -18,7 +18,7 @@ if (! $this->compact): ?>

translate('No host groups found matching the filter.') ?>

- +
diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml index 9c955ef66..53b543625 100644 --- a/modules/monitoring/application/views/scripts/list/hosts.phtml +++ b/modules/monitoring/application/views/scripts/list/hosts.phtml @@ -22,7 +22,7 @@ if (! $this->compact): ?>
" data-icinga-multiselect-data="host"> @@ -32,61 +32,63 @@ if (! $this->compact): ?> $hostLink = $this->href('monitoring/host/show', array('host' => $host->host_name)); ?> - addColumns as $col): ?> diff --git a/modules/monitoring/application/views/scripts/list/notifications.phtml b/modules/monitoring/application/views/scripts/list/notifications.phtml index 85255cded..a70eb6932 100644 --- a/modules/monitoring/application/views/scripts/list/notifications.phtml +++ b/modules/monitoring/application/views/scripts/list/notifications.phtml @@ -2,8 +2,6 @@ use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; -$notifications->peekAhead($this->compact); - if (! $this->compact): ?>
@@ -16,22 +14,32 @@ if (! $this->compact): ?>
-
-

- host_state, true) ?> +

host_state, true) ?>
host_state !== 99): ?> -
- timeSince($host->host_last_state_change, $this->compact) ?> - host_state > 0 && (int) $host->host_state_type === 0): ?> -
- Soft host_attempt ?> +
+ timeSince($host->host_last_state_change, $this->compact) ?> + host_state > 0 && (int) $host->host_state_type === 0): ?> +
translate('Soft', 'Soft state') ?> host_attempt ?>
+ +
- -

- iconImage()->host($host) ?> - hostFlags($host)) ?> - qlink( - $host->host_display_name, - $hostLink, - null, - array( - 'title' => sprintf( - $this->translate('Show detailed information for host %s'), - $host->host_display_name - ), - 'class' => 'rowaction' - ) - ) ?> - host_name])): ?> - (qlink( - sprintf( - $this->translatePlural( - '%u unhandled service', '%u unhandled services', $summary[$host->host_name] - ), - $summary[$host->host_name] - ), - 'monitoring/list/services', - array( - 'host' => $host->host_name, - 'service_problem' => 1, - 'service_handled' => 0 - ), - array( - 'title' => sprintf( + +
+ iconImage()->host($host) ?> + qlink( + $host->host_display_name, + $hostLink, + null, + array( + 'title' => sprintf( + $this->translate('Show detailed information for host %s'), + $host->host_display_name + ), + 'class' => 'rowaction' + ) + ) ?> + host_name])): ?> + (qlink( + sprintf( $this->translatePlural( - 'List %s unhandled service problem on host %s', - 'List %s unhandled service problems on host %s', - $summary[$host->host_name] + '%u unhandled service', '%u unhandled services', $summary[$host->host_name] ), - $summary[$host->host_name], - $host->host_name + $summary[$host->host_name] + ), + 'monitoring/list/services', + array( + 'host' => $host->host_name, + 'service_problem' => 1, + 'service_handled' => 0 + ), + array( + 'title' => sprintf( + $this->translatePlural( + 'List %s unhandled service problem on host %s', + 'List %s unhandled service problems on host %s', + $summary[$host->host_name] + ), + $summary[$host->host_name], + $host->host_name + ) ) - ) - ) ?>) - -

pluginOutput($this->ellipsis($host->host_output, 10000), true) ?>

+ ) ?>) + + hostFlags($host)) ?> +
+

+ pluginOutput($this->ellipsis($host->host_output, 10000), true) ?> +

escape($host->$col) ?>
+hasResult()): ?> +

translate('No notifications found matching the filter.') ?>

+ + +
- peekAhead($this->compact) as $notification): if (isset($notification->service_description)) { $isService = true; + $stateLabel = Service::getStateText($notification->notification_state, true); $stateName = Service::getStateText($notification->notification_state); } else { $isService = false; + $stateLabel = Host::getStateText($notification->notification_state, true); $stateName = Host::getStateText($notification->notification_state); } ?> @@ -70,17 +78,17 @@ if (! $this->compact): ?>
- timeAgo($notification->notification_start_time, $this->compact) ?> +
+
+ timeAgo($notification->notification_start_time, $this->compact) ?> +
+
icon('service', $this->translate('Service')); ?> link()->service( @@ -45,24 +53,24 @@ if (! $this->compact): ?> icon('host', $this->translate('Host')); ?> link()->host($notification->host_name, $notification->host_display_name) ?> - contact): ?> - - notification_contact_name): ?> - translate('Sent to %s'), - $this->qlink( - $notification->notification_contact_name, - 'monitoring/show/contact', - array('contact_name' => $notification->notification_contact_name) - ) - ) ?> - - translate('This notification was not sent out to any contact.'); ?> - - +
+ notification_contact_name): ?> + translate('Sent to %s'), + $this->qlink( + $notification->notification_contact_name, + 'monitoring/show/contact', + array('contact_name' => $notification->notification_contact_name) + ) + ) ?> + + translate('Sent out to any contact') ?> + +
-

+

+

pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?>

-hasResult()): ?> - translate('No notifications found matching the filter'); ?> -hasMore()): ?> - qlink( - $this->translate('Show More'), - $this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')), - null, - array( - 'data-base-target' => '_next', - 'class' => 'pull-right action-link' - ) - ); ?> +hasMore()): ?> +
+ qlink( + $this->translate('Show More'), + $this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')), + null, + array( + 'class' => 'action-link', + 'data-base-target' => '_next' + ) + ); ?> +
diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index b51bb3baf..3fdefcbe8 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -3,32 +3,20 @@ use Icinga\Module\Monitoring\Object\Service; use Icinga\Web\Url; if (! $this->compact): ?> -
- tabs; ?> -
-
- limiter ?> -
-
- paginator ?> -
-
- sortBox ?> -
-
- filterEditor; ?> +
+ tabs ?> + sortBox ?> + filterEditor ?>
-translate('No services found matching the filter') . '
'; - return; -} + +

translate('No services found matching the filter.') ?>

+
+ - - +
+ ) ?> $serviceDisplayName): ?> - + $hostDisplayName): ?> - compact && $this->verticalPaginator->getPages()->pageCount > 1): ;?> + compact && $this->verticalPaginator->getPages()->pageCount > 1): ?> - + -
partial( @@ -38,7 +26,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ' 'xAxisPaginator' => $horizontalPaginator, 'yAxisPaginator' => $verticalPaginator ) - ); ?>
qlink( $this->ellipsis($serviceDisplayName, 18), @@ -55,7 +43,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
"> escape($service->service_output) ?> - qlink( - '', - 'monitoring/service/show', - array( - 'host' => $hostName, - 'service' => $serviceDescription - ), - array( - 'aria-describedby' => $ariaDescribedById, - 'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''), - 'title' => $this->escape($service->service_output), - 'aria-label' => sprintf( - $this->translate('Show detailed information for service %s on host %s'), - $service->service_display_name, - $service->host_display_name + qlink( + '', + 'monitoring/service/show', + array( + 'host' => $hostName, + 'service' => $serviceDescription + ), + array( + 'aria-describedby' => $ariaDescribedById, + 'aria-label' => sprintf( + $this->translate('Show detailed information for service %s on host %s'), + $service->service_display_name, + $service->host_display_name + ), + 'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''), + 'title' => $this->escape($service->service_output) ) - ) - ); ?> + ) ?> compact && $this->horizontalPaginator->getPages()->pageCount > 1): ?> @@ -110,16 +98,16 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ' . $this->verticalPaginator->getItemCountPerPage() ), array( - 'data-base-target' => '_self', - 'class' => 'action-link' + 'class' => 'action-link', + 'data-base-target' => '_self' ) ) ?> - +
qlink( @@ -130,13 +118,13 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ' ($this->verticalPaginator->getItemCountPerPage() + 20) ), array( - 'data-base-target' => '_self', - 'class' => 'action-link' + 'class' => 'action-link', + 'data-base-target' => '_self' ) ) ?>
+ diff --git a/modules/monitoring/application/views/scripts/list/servicegroups.phtml b/modules/monitoring/application/views/scripts/list/servicegroups.phtml index 5e9500bea..ca7dfc325 100644 --- a/modules/monitoring/application/views/scripts/list/servicegroups.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegroups.phtml @@ -16,7 +16,7 @@ if (! $this->compact): ?>

translate('No service groups found matching the filter.') ?>

- +
diff --git a/modules/monitoring/application/views/scripts/list/services.phtml b/modules/monitoring/application/views/scripts/list/services.phtml index fc9421795..b0e75c267 100644 --- a/modules/monitoring/application/views/scripts/list/services.phtml +++ b/modules/monitoring/application/views/scripts/list/services.phtml @@ -23,7 +23,7 @@ if (! $this->compact): ?>
translate('Service Group') ?>
@@ -45,51 +45,55 @@ if (! $this->compact): ?> $serviceStateName = Service::getStateText($service->service_state); ?> - addColumns as $col): ?> diff --git a/modules/monitoring/application/views/scripts/object/detail-history.phtml b/modules/monitoring/application/views/scripts/object/detail-history.phtml new file mode 100644 index 000000000..692d3e4ee --- /dev/null +++ b/modules/monitoring/application/views/scripts/object/detail-history.phtml @@ -0,0 +1,13 @@ +compact): ?> +
+ tabs ?> +type === 'service') { + echo $this->render('partials/object/service-header.phtml'); +} else { + echo $this->render('partials/object/host-header.phtml'); +} ?> +
+ +render('partials/event-history.phtml') ?> diff --git a/modules/monitoring/application/views/scripts/partials/comment/comment-description.phtml b/modules/monitoring/application/views/scripts/partials/comment/comment-description.phtml index cfd4421f3..f35680cab 100644 --- a/modules/monitoring/application/views/scripts/partials/comment/comment-description.phtml +++ b/modules/monitoring/application/views/scripts/partials/comment/comment-description.phtml @@ -21,4 +21,4 @@ switch ($comment->type) { $tooltip = $this->translate('Comment was caused by an acknowledgement'); break; } -echo $this->icon($icon, $tooltip, array('class' => 'big-icon')); +echo $this->icon($icon, $tooltip, array('class' => 'large-icon')); diff --git a/modules/monitoring/application/views/scripts/partials/comment/comment-detail.phtml b/modules/monitoring/application/views/scripts/partials/comment/comment-detail.phtml index 695c71901..2d4f32792 100644 --- a/modules/monitoring/application/views/scripts/partials/comment/comment-detail.phtml +++ b/modules/monitoring/application/views/scripts/partials/comment/comment-detail.phtml @@ -1,4 +1,4 @@ - +
objecttype === 'service'): ?> icon('service', $this->translate('Service')) ?> qlink( $comment->host_display_name . ': ' . $comment->service_display_name, @@ -28,27 +28,31 @@ ) ) ?> - translate('by') ?> - escape($comment->author) ?> - timeAgo($comment->timestamp) ?> - - persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?> - expiration ? $this->icon('clock', sprintf( - $this->translate('This comment expires %s.'), - $this->timeUntil($comment->expiration) - )) : '' ?> - populate( - array( - 'comment_id' => $comment->id, - 'comment_is_service' => isset($comment->service_description) - ) - ); - echo $delCommentForm; - } ?> + + translate('by') ?> + escape($comment->author) ?> + timeAgo($comment->timestamp) ?> + + persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?> + expiration ? $this->icon('clock', sprintf( + $this->translate('This comment expires %s.'), + $this->timeUntil($comment->expiration) + )) : '' ?> + setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action'); + $deleteButton->populate( + array( + 'comment_id' => $comment->id, + 'comment_is_service' => isset($comment->service_description) + ) + ); + echo $deleteButton; + } ?> + - +

escape($comment->comment) ?>

diff --git a/modules/monitoring/application/views/scripts/partials/comment/comment-header.phtml b/modules/monitoring/application/views/scripts/partials/comment/comment-header.phtml index 3dcb479cd..44724796a 100644 --- a/modules/monitoring/application/views/scripts/partials/comment/comment-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/comment/comment-header.phtml @@ -1,6 +1,6 @@
-

- service_state, true) ?> - service_state !== 99): ?> -
+

service_state, true) ?>
+ service_state !== 99): ?> +
timeSince($service->service_last_state_change, $this->compact) ?> service_state > 0 && (int) $service->service_state_type === 0): ?> -
- Soft service_attempt ?> +
translate('Soft', 'Soft state') ?> service_attempt ?>
- -

+
+
- iconImage()->service($service) ?> - serviceFlags($service)) ?> - showHost): ?>qlink( - $service->host_display_name - . ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : ''), - $hostLink, - null, - array( - 'title' => sprintf( - $this->translate('Show detailed information for host %s'), - $service->host_display_name + +
+ iconImage()->service($service) ?> + showHost): ?>qlink( + $service->host_display_name + . ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : ''), + $hostLink, + null, + array( + 'title' => sprintf( + $this->translate('Show detailed information for host %s'), + $service->host_display_name + ) ) - ) - ) ?>: - qlink( - $service->service_display_name, - $serviceLink, - null, - array( - 'title' => sprintf( - $this->translate('Show detailed information for service %s on host %s'), - $service->service_display_name, - $service->host_display_name - ), - 'class' => 'rowaction' - ) - ) ?>
-
perfdata($service->service_perfdata, true, 5) ?>
-

- pluginOutput($this->ellipsis($service->service_output, 10000), true) ?> -

+ ) ?>: + qlink( + $service->service_display_name, + $serviceLink, + null, + array( + 'title' => sprintf( + $this->translate('Show detailed information for service %s on host %s'), + $service->service_display_name, + $service->host_display_name + ), + 'class' => 'rowaction' + ) + ) ?> + serviceFlags($service)) ?> +
+
+
+ perfdata($service->service_perfdata, true, 5) ?> +
+

+ pluginOutput($this->ellipsis($service->service_output, 10000), true) ?> +

+
escape($service->$col) ?>
- $comment): - if ($i > 5) { + if ($i === 5) { break; } ?> - diff --git a/modules/monitoring/application/views/scripts/partials/event-history.phtml b/modules/monitoring/application/views/scripts/partials/event-history.phtml new file mode 100644 index 000000000..e7ae0e034 --- /dev/null +++ b/modules/monitoring/application/views/scripts/partials/event-history.phtml @@ -0,0 +1,179 @@ +qlink( + $contact, + 'monitoring/show/contact', + array('contact_name' => $contact), + array('title' => sprintf($view->translate('Show detailed information about %s'), $contact)) + ); + } + return '[' . implode(', ', $links) . ']'; +} + +$self = $this; + +$url = $this->url(); +$limit = (int) $url->getParam('limit', 25); +if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) { + $page = 1; +} + +/** @var \Icinga\Module\Monitoring\DataView\EventHistory $history */ +$history->limit($limit * $page); +?> +
+hasResult()): ?> +

translate('No historical events found matching the filter.') ?>

+
+ +
+ render('partials/comment/comment-description.phtml') ?> diff --git a/modules/monitoring/application/views/scripts/partials/comment/comments-header.phtml b/modules/monitoring/application/views/scripts/partials/comment/comments-header.phtml index 68cc1f958..c4c92daaf 100644 --- a/modules/monitoring/application/views/scripts/partials/comment/comments-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/comment/comments-header.phtml @@ -2,12 +2,12 @@
+ partial('partials/comment/comment-description.phtml', array('comment' => $comment)) ?> diff --git a/modules/monitoring/application/views/scripts/partials/downtime/downtime-header.phtml b/modules/monitoring/application/views/scripts/partials/downtime/downtime-header.phtml index 9c7f7af19..cc5c79d9a 100644 --- a/modules/monitoring/application/views/scripts/partials/downtime/downtime-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/downtime/downtime-header.phtml @@ -1,14 +1,14 @@ start <= time() && ! $downtime->is_in_effect): ?> - translate('Ends'); ?> -

timeUntil($downtime->is_flexible ? $downtime->scheduled_end : $downtime->end, $this->compact) ?>

+
translate('ENDS', 'Downtime status'); ?>
+
timeUntil($downtime->is_flexible ? $downtime->scheduled_end : $downtime->end, $this->compact) ?>
- is_in_effect ? $this->translate('Expires') : $this->translate('Starts'); ?> -

timeUntil($downtime->is_in_effect ? $downtime->end : $downtime->start, $this->compact) ?>

+
is_in_effect ? $this->translate('EXPIRES', 'Downtime status') : $this->translate('STARTS', 'Downtime status'); ?>
+
timeUntil($downtime->is_in_effect ? $downtime->end : $downtime->start, $this->compact) ?>
- +
icon('service', $this->translate('Service')); ?> qlink( $downtime->host_display_name . ': ' . $downtime->service_display_name, @@ -38,11 +38,10 @@ ) ); ?> - - translate('by') ?> - escape($downtime->author_name) ?> - - + + translate('by') ?> + escape($downtime->author_name) ?> + is_flexible): ?> icon('magic', $this->translate('This downtime is flexible')); ?> @@ -52,22 +51,23 @@ - populate( - array( - 'downtime_id' => $downtime->id, - 'downtime_is_service' => isset($downtime->service_description) - ) - ); - echo $delDowntimeForm; - ?> + setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action'); + $deleteButton->populate( + array( + 'downtime_id' => $downtime->id, + 'downtime_is_service' => isset($downtime->service_description) + ) + ); + echo $deleteButton; + ?> + - - -

- escape($downtime->comment) ?> -

- +
+

+ escape($downtime->comment) ?> +

class=""> + + peekAhead() as $event): + $icon = ''; + $iconCssClass = ''; + $isService = isset($event->service_description); + $msg = $event->output; + $stateName = 'no-state'; + switch ($event->type) { + case 'notify': + $icon = 'bell-alt'; + $label = $this->translate('NOTIFICATION'); + $msg = $msg ? preg_replace_callback( + '/^\[([^\]]+)\]/', + function($match) use ($self) { return contactsLink($match, $self); }, + $msg + ) : $this->translate('This notification was not sent out to any contact.'); + $stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); + break; + case 'comment': + $icon = 'comment'; + $label = $this->translate('COMMENT'); + break; + case 'comment_deleted': + $icon = 'cancel'; + $label = $this->translate('COMMENT DELETED'); + break; + case 'ack': + $icon = 'ok'; + $label = $this->translate('ACKNOWLEDGED'); + break; + case 'ack_deleted': + $icon = 'ok'; + $iconCssClass = 'icon-strikethrough'; + $label = $this->translate('ACKNOWLEDGEMENT REMOVED'); + break; + case 'dt_comment': + // TODO(el): Does not appear in history + $icon = 'plug'; + $label = $this->translate('SCHEDULED DOWNTIME'); + break; + case 'dt_comment_deleted': + // TODO(el): Does not appear in history + $icon = 'plug'; + $iconCssClass = 'icon-strikethrough'; + $label = $this->translate('DOWNTIME DELETED'); + break; + case 'flapping': + // TODO(el): Icon + $label = $this->translate('FLAPPING'); + break; + case 'flapping_deleted': + // TODO(el): Icon + $label = $this->translate('FLAPPING STOPPED'); + break; + case 'hard_state': + $label = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true); + $stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); + break; + case 'soft_state': + $label = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true); + $stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state); + break; + case 'dt_start': + $icon = 'plug'; + $label = $this->translate('DOWNTIME START'); + break; + case 'dt_end': + $icon = 'plug'; + $iconCssClass = 'icon-strikethrough'; + $label = $this->translate('DOWNTIME END'); + break; + } ?> + + + + + + +
+ getIteratorPosition() % $limit === 0): ?> + + +
escape($label) ?>
+
timeAgo($event->timestamp, $this->compact) ?>
+
+ isOverview): ?> + qlink( + $event->host_display_name, + 'monitoring/host/show', + array( + 'host' => $event->host_name, + ), + array('title' => sprintf( + $this->translate('Show detailed information for host %s'), + $event->host_display_name + )) + ) ?>: + qlink( + $event->service_display_name, + 'monitoring/service/show', + array( + 'host' => $event->host_name, + 'service' => $event->service_description + ), + array( + 'class' => 'rowaction', + 'title' => sprintf( + $this->translate('Show detailed information for service %s on host %s'), + $event->service_display_name, + $event->host_display_name + ) + ) + ) ?> + + +

+ icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array()); + } ?> + createTicketLinks($this->escape($msg)), false) ?> +

+
+hasMore()): ?> + + + 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 0a3fdbaf6..731ba1cf8 100644 --- a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml @@ -1,48 +1,41 @@ - - 0): ?> - - - - 5) { - continue; - } - ?> - - - - - - - -
- host_state, true); ?> -
-
- iconImage()->host($host) ?> - hostFlags($host)) ?> - escape($host->getName()); ?>
- escape($host->host_output) ?> -
-
- 5): ?> - qlink( - sprintf($this->translate('show all %d hosts'), $i), - $listAllLink, - null, - array( - 'icon' => 'down-open', - 'data-base-target' => '_next' - ) - ); - ?> - -
+if (! ($hostCount = count($objects))): return; endif ?> + + + $host): /** @var Host $host */ + if ($i === 5) { + break; + } ?> + + + + + + +
+ host_state) ?> +
+ timeSince($host->host_last_state_change, $this->compact) ?> +
+
+ link()->host( + $host->host_name, + $host->host_display_name + ) ?> + hostFlags($host)) ?> +
+ 5): ?> + - diff --git a/modules/monitoring/application/views/scripts/partials/object/host-header.phtml b/modules/monitoring/application/views/scripts/partials/object/host-header.phtml index 35f17489a..8bc7b6c64 100644 --- a/modules/monitoring/application/views/scripts/partials/object/host-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/object/host-header.phtml @@ -2,36 +2,34 @@ use Icinga\Module\Monitoring\Object\Host; /** @var Host $object */ ?> - +
-

- host_state, true) ?> -
+

host_state, true) ?>
+
timeSince($object->host_last_state_change) ?> -

+ host_state > 0 && (int) $object->host_state_type === 0): ?> +
translate('Soft', 'Soft state') ?> host_attempt ?>
+ +
-

- iconImage()->host($object) ?> - escape($object->host_display_name) ?> - host_display_name !== $object->host_name): ?> - (escape($object->host_name) ?>) - - host_address6 && $object->host_address6 !== $object->host_name): ?> -
- - escape($object->host_address6) ?> - - - host_address && $object->host_address !== $object->host_name): ?> -
- - escape($object->host_address) ?> - - - render('partials/host/statusicons.phtml') ?> -

+ iconImage()->host($object) ?> + escape($object->host_display_name) ?> + host_display_name !== $object->host_name): ?> + (escape($object->host_name) ?>) + + render('partials/host/statusicons.phtml') ?> + host_address6 && $object->host_address6 !== $object->host_name): ?> +
+ escape($object->host_address6) ?> +
+ + host_address && $object->host_address !== $object->host_name): ?> +
+ escape($object->host_address) ?> +
+
diff --git a/modules/monitoring/application/views/scripts/partials/object/service-header.phtml b/modules/monitoring/application/views/scripts/partials/object/service-header.phtml index 4a34113fe..93eb41f94 100644 --- a/modules/monitoring/application/views/scripts/partials/object/service-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/object/service-header.phtml @@ -3,55 +3,53 @@ use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ ?> - +
-

- host_state, true) ?> -
+

host_state, true) ?>
+
timeSince($object->host_last_state_change) ?> -

+ host_state > 0 && (int) $object->host_state_type === 0): ?> +
translate('Soft', 'Soft state') ?> host_attempt ?>
+ +
-

- iconImage()->service($object) ?> - escape($object->host_display_name) ?> - host_display_name !== $object->host_name): ?> - (escape($object->host_name) ?>) - - host_address6 && $object->host_address6 !== $object->host_name): ?> -
- - escape($object->host_address6) ?> - - - host_address && $object->host_address !== $object->host_name): ?> -
- - escape($object->host_address) ?> - - + iconImage()->host($object) ?> + escape($object->host_display_name) ?> + host_display_name !== $object->host_name): ?> + (escape($object->host_name) ?>) + render('partials/host/statusicons.phtml') ?> -

+ host_address6 && $object->host_address6 !== $object->host_name): ?> +
+ escape($object->host_address6) ?> +
+ + host_address && $object->host_address !== $object->host_name): ?> +
+ escape($object->host_address) ?> +
+
-

- service_state, true) ?> -
+

service_state, true) ?>
+
timeSince($object->service_last_state_change) ?> -

+ service_state > 0 && (int) $object->service_state_type === 0): ?> +
translate('Soft', 'Soft state') ?> service_attempt ?>
+ +
-

- iconImage()->host($object) ?> - translate('Service') ?>: escape($object->service_display_name) ?> + iconImage()->service($object) ?> + translate('Service') ?>: escape($object->service_display_name) ?> service_display_name !== $object->service_description): ?> - (escape($object->service_description) ?>) + (escape($object->service_description) ?>) - render('partials/service/statusicons.phtml') ?> -

+ render('partials/service/statusicons.phtml') ?>
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 d75de6029..7512a3042 100644 --- a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml @@ -1,46 +1,45 @@ - 0): ?> - - - - 5) { - continue; - } - ?> - - - + + + +
- service_state, true); ?>
-
- iconImage()->service($service) ?> +if (! ($serviceCount = count($objects))): return; endif ?> + + + $service): /** @var Service $service */ + if ($i === 5) { + break; + } ?> + + + - - - -
+ service_state) ?> +
+ timeSince($service->service_last_state_change, $this->compact) ?> +
+
+ link()->service( + $service->service_description, + $service->service_display_name, + $service->host_name, + $service->host_display_name + . ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : '') + ) ?> serviceFlags($service)) ?> - - escape($service->getHost()->getName()); ?>: - escape($service->getName()); ?>
-
- escape($service->service_output) ?> -
-
- 5): ?> - qlink( - sprintf($this->translate('List all %d services'), $i), - $listAllLink, - null, - array( - 'icon' => 'down-open', - 'data-base-target' => '_next' - ) - ); - ?> - -
+
+ 5): ?> + diff --git a/modules/monitoring/application/views/scripts/service/history.phtml b/modules/monitoring/application/views/scripts/service/history.phtml deleted file mode 100644 index db4625c0a..000000000 --- a/modules/monitoring/application/views/scripts/service/history.phtml +++ /dev/null @@ -1,150 +0,0 @@ -qlink( - $contact, - 'monitoring/show/contact', - array('contact_name' => $contact), - array('title' => sprintf($view->translate('Show detailed information about %s'), $contact)) - ); - } - return '[' . implode(', ', $links) . ']'; -} - -$self = $this; - -$url = $this->url(); -$limit = (int) $url->getParam('limit', 25); -if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) { - $page = 1; -} - -$history->limit($limit * $page); - -if (! $this->compact): ?> -
- tabs; ?> - render('partials/object/service-header.phtml'); ?> -

translate('This Service\'s Event History'); ?>

- sortBox; ?> - limiter; ?> - - translate('Scroll to the bottom of this page to load additional events'); ?> - - filterEditor; ?> -
- -
- - - peekAhead() as $event): ?> - escape($event->output); - switch ($event->type) { - case 'notify': - $icon = 'notification'; - $title = $this->translate('Notification'); - $stateClass = Service::getStateText($event->state); - - $msg = $msg ? preg_replace_callback( - '/^\[([^\]]+)\]/', - function($match) use ($self) { return contactsLink($match, $self); }, - $msg - ) : $this->translate('This notification was not sent out to any contact.'); - break; - case 'comment': - $icon = 'comment'; - $title = $this->translate('Comment'); - break; - case 'comment_deleted': - $icon = 'remove'; - $title = $this->translate('Comment deleted'); - break; - case 'ack': - $icon = 'acknowledgement'; - $title = $this->translate('Acknowledge'); - break; - case 'ack_deleted': - $icon = 'remove'; - $title = $this->translate('Ack removed'); - break; - case 'dt_comment': - $icon = 'in_downtime'; - $title = $this->translate('In Downtime'); - break; - case 'dt_comment_deleted': - $icon = 'remove'; - $title = $this->translate('Downtime removed'); - break; - case 'flapping': - $icon = 'flapping'; - $title = $this->translate('Flapping'); - break; - case 'flapping_deleted': - $icon = 'remove'; - $title = $this->translate('Flapping stopped'); - break; - case 'hard_state': - $stateClass = Service::getStateText($event->state); - $icon = 'attention-alt'; - $title = Service::getStateText($event->state); - break; - case 'soft_state': - $icon = 'spinner'; - $stateClass = Service::getStateText($event->state); - $title = Service::getStateText($event->state); - break; - case 'dt_start': - $icon = 'downtime_start'; - $title = $this->translate('Downtime Start'); - break; - case 'dt_end': - $icon = 'downtime_end'; - $title = $this->translate('Downtime End'); - break; - } - ?> - - - - - - -
- getIteratorPosition() % $limit === 0): ?> - - - escape($title); ?> -
- timestamp); ?> -
- translate('%s on %s', 'Service running on host'), - $this->escape($event->service_display_name), - $event->host_display_name - ) ?> -
-
- icon($icon, $title); ?> createTicketLinks($msg) ?> -
-
-hasResult()): ?> - translate('No history events found matching the filter'); ?> -hasMore()): ?> - qlink( - $this->translate('Load More'), - $url->setAnchor('page-' . ($page + 1)), - array( - 'page' => $page + 1, - ), - array( - 'id' => 'load-more', - 'class' => 'pull-right action-link' - ) - ); ?> - -
diff --git a/modules/monitoring/application/views/scripts/show/components/acknowledgement.phtml b/modules/monitoring/application/views/scripts/show/components/acknowledgement.phtml index 5582cf084..77d99f69f 100644 --- a/modules/monitoring/application/views/scripts/show/components/acknowledgement.phtml +++ b/modules/monitoring/application/views/scripts/show/components/acknowledgement.phtml @@ -7,86 +7,87 @@ if (in_array((int) $object->state, array(0, 99))) { return; } -if ($object->acknowledged): ?> - acknowledgement; - /** @var \Icinga\Module\Monitoring\Object\Acknowledgement $acknowledgement */ - ?> - - translate('Acknowledged') ?> - -
-
- escape($acknowledgement->getAuthor()) ?> - translate('acknowledged') ?> +if ($object->acknowledged): +$acknowledgement = $object->acknowledgement; +/** @var \Icinga\Module\Monitoring\Object\Acknowledgement $acknowledgement */ +?> + + translate('Acknowledged') ?> + +
+
+ escape($acknowledgement->getAuthor()) ?> + + translate('acknowledged') ?> timeAgo($acknowledgement->getEntryTime()) ?> - getSticky()) { - echo $this->icon('pin', sprintf( - $this->translate( - 'Acknowledgement remains until the %1$s recovers even if the %1$s changes state' - ), - $object->getType(true) - )); - } - if (isset($removeAckForm)) { - $removeAckForm->setAttrib('class', $removeAckForm->getAttrib('class') . ' pull-right'); - // Form is unset if the current user lacks the respective permission - echo $removeAckForm; - } - ?> -
-
- createTicketLinks($acknowledgement->getComment()), false) ?> -
- expires()): ?> -
+ expires()): ?> + translate('Expires %s'), $this->timeUntil($acknowledgement->getExpirationTime()) ) ?> -
- -
- - + + getSticky()): ?> + icon('pin', sprintf( + $this->translate( + 'Acknowledgement remains until the %1$s recovers even if the %1$s changes state' + ), + $object->getType(true) + )) ?> + + + + setAttrib('class', $removeAckForm->getAttrib('class') . ' remove-action'); + echo $removeAckForm; + ?> + + + +
+
+

createTicketLinks($this->escape($acknowledgement->getComment())), false) ?>

+
+
+ + - - translate('Not acknowledged') ?> - - hasPermission('monitoring/command/acknowledge-problem')) { - if ($object->getType() === $object::TYPE_HOST) { - $ackLink = $this->href( - 'monitoring/host/acknowledge-problem', - array('host' => $object->getName()), - null, - array('class' => 'action-link') - ); - } else { - $ackLink = $this->href( - 'monitoring/service/acknowledge-problem', - array('host' => $object->getHost()->getName(), 'service' => $object->getName()), - null, - array('class' => 'action-link') - ); - } - ?> - qlink( - $this->translate('Acknowledge'), - $ackLink, + + translate('Not acknowledged') ?> + + hasPermission('monitoring/command/acknowledge-problem')) { + if ($object->getType() === $object::TYPE_HOST) { + $ackLink = $this->href( + 'monitoring/host/acknowledge-problem', + array('host' => $object->getName()), null, - array( - 'class' => 'action-link', - 'data-base-target' => '_self', - 'icon' => 'ok', - 'title' => $this->translate( - 'Acknowledge this problem, suppress all future notifications for it and tag it as being handled' - ) + array('class' => 'action-link') + ); + } else { + $ackLink = $this->href( + 'monitoring/service/acknowledge-problem', + array('host' => $object->getHost()->getName(), 'service' => $object->getName()), + null, + array('class' => 'action-link') + ); + } + ?> + qlink( + $this->translate('Acknowledge'), + $ackLink, + null, + array( + 'class' => 'action-link', + 'data-base-target' => '_self', + 'icon' => 'ok', + 'title' => $this->translate( + 'Acknowledge this problem, suppress all future notifications for it and tag it as being handled' ) - ); ?> - - - + ) + ); ?> + + + diff --git a/modules/monitoring/application/views/scripts/show/components/checksource.phtml b/modules/monitoring/application/views/scripts/show/components/checksource.phtml index 5405e0d22..5e65e9d33 100644 --- a/modules/monitoring/application/views/scripts/show/components/checksource.phtml +++ b/modules/monitoring/application/views/scripts/show/components/checksource.phtml @@ -4,19 +4,17 @@ translate('Check Source') ?> -

- is_reachable !== null) { - if ((bool) $object->is_reachable) { - echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok')); - } else { - echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical')); - } - } ?> - escape($object->check_source) ?> - is_reachable !== null): ?> - is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?> - -

+ is_reachable !== null) { + if ((bool) $object->is_reachable) { + echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok')); + } else { + echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical')); + } + } ?> + escape($object->check_source) ?> + is_reachable !== null): ?> + is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?> + diff --git a/modules/monitoring/application/views/scripts/show/components/comments.phtml b/modules/monitoring/application/views/scripts/show/components/comments.phtml index a0a88fa72..7d0874366 100644 --- a/modules/monitoring/application/views/scripts/show/components/comments.phtml +++ b/modules/monitoring/application/views/scripts/show/components/comments.phtml @@ -36,40 +36,40 @@ if (empty($object->comments) && ! $addLink) { translate('Comments'); if (! empty($object->comments) && $addLink) { - echo '
' . $addLink; + echo '
' . $addLink; } ?> comments)): echo $addLink; else: ?> -
- comments as $comment): - // Form is unset if the current user lacks the respective permission - if (isset($delCommentForm)) { - $deleteButton = clone($delCommentForm); - /** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm $deleteButton */ - $deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' pull-right'); - $deleteButton->populate( - array( - 'comment_id' => $comment->id, - 'comment_is_service' => isset($comment->service_description) - ) - ); - } else { - $deleteButton = ''; - } - ?> -
+
+ comments as $comment): ?> +
escape($comment->author) ?> - translate('commented') ?> - timeAgo($comment->timestamp) ?> - - - + + translate('commented') ?> + timeAgo($comment->timestamp) ?> + + + setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action'); + $deleteButton->populate( + array( + 'comment_id' => $comment->id, + 'comment_is_service' => isset($comment->service_description) + ) + ); + echo $deleteButton; + ?> + + +
- ', $this->createTicketLinks($comment->comment)) ?> +

createTicketLinks($this->escape($comment->comment)), false) ?>

diff --git a/modules/monitoring/application/views/scripts/show/components/downtime.phtml b/modules/monitoring/application/views/scripts/show/components/downtime.phtml index 489547c6e..184fcc44e 100644 --- a/modules/monitoring/application/views/scripts/show/components/downtime.phtml +++ b/modules/monitoring/application/views/scripts/show/components/downtime.phtml @@ -40,14 +40,14 @@ if (empty($object->comments) && ! $addLink) { translate('Downtimes'); if (! empty($object->downtimes) && $addLink) { - echo '
' . $addLink; + echo '
' . $addLink; } ?> downtimes)): echo $addLink; else: ?> -
+
downtimes as $downtime): if ((bool) $downtime->is_in_effect) { $state = sprintf( @@ -72,30 +72,34 @@ if (empty($object->comments) && ! $addLink) { ); } } - // Form is unset if the current user lacks the respective permission - if (isset($delDowntimeForm)) { - $deleteButton = clone($delDowntimeForm); - $deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' pull-right'); - $deleteButton->populate( - array( - 'downtime_id' => $downtime->id, - 'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE - ) - ); - } else { - $deleteButton = ''; - } - ?> -
- escape($downtime->author_name) ?> - timeAgo($downtime->entry_time) ?> - -
-
- ', $this->createTicketLinks($downtime->comment)) ?> -
-
- + ?> +
+ escape($downtime->author_name) ?> + + translate('created') ?> + timeAgo($downtime->entry_time) ?> + + + + + setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action'); + $deleteButton->populate( + array( + 'downtime_id' => $downtime->id, + 'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE + ) + ); + echo $deleteButton; + ?> + + + +
+
+

createTicketLinks($this->escape($downtime->comment)), false) ?>

diff --git a/modules/monitoring/application/views/scripts/show/components/output.phtml b/modules/monitoring/application/views/scripts/show/components/output.phtml index 82230beae..e4c0fd0a8 100644 --- a/modules/monitoring/application/views/scripts/show/components/output.phtml +++ b/modules/monitoring/application/views/scripts/show/components/output.phtml @@ -1,5 +1,3 @@ -
-

translate('Plugin Output') ?>

- pluginOutput($object->output) ?> - pluginOutput($object->long_output) ?> -
+

translate('Plugin Output') ?>

+pluginOutput($object->output) ?> +pluginOutput($object->long_output) ?> diff --git a/modules/monitoring/application/views/scripts/tactical/components/ok_hosts.phtml b/modules/monitoring/application/views/scripts/tactical/components/ok_hosts.phtml index ab6961ebb..05ffd290d 100644 --- a/modules/monitoring/application/views/scripts/tactical/components/ok_hosts.phtml +++ b/modules/monitoring/application/views/scripts/tactical/components/ok_hosts.phtml @@ -49,7 +49,6 @@ $service_problems = ( statusSummary->hosts_down || $this->statusSummary->hosts_unreachable): ?>
- translate('Services'); ?> partial( 'tactical/components/parts/servicestatesummarybyhoststate.phtml', array( diff --git a/modules/monitoring/application/views/scripts/tactical/components/problem_hosts.phtml b/modules/monitoring/application/views/scripts/tactical/components/problem_hosts.phtml index f06170c7a..6374ff83d 100644 --- a/modules/monitoring/application/views/scripts/tactical/components/problem_hosts.phtml +++ b/modules/monitoring/application/views/scripts/tactical/components/problem_hosts.phtml @@ -47,7 +47,6 @@
- translate('Services'); ?> partial( 'tactical/components/parts/servicestatesummarybyhoststate.phtml', array( diff --git a/modules/monitoring/application/views/scripts/tactical/index.phtml b/modules/monitoring/application/views/scripts/tactical/index.phtml index b23872960..6639b0c1b 100644 --- a/modules/monitoring/application/views/scripts/tactical/index.phtml +++ b/modules/monitoring/application/views/scripts/tactical/index.phtml @@ -11,7 +11,5 @@ statusSummary->hosts_up || $this->statusSummary->hosts_pending): ?> render('tactical/components/ok_hosts.phtml'); ?> - render('tactical/components/monitoringfeatures.phtml'); ?> - render('tactical/components/hostservicechecks.phtml'); ?>
diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index f8101d996..359af6457 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -353,6 +353,5 @@ $dashboard->add( /* * CSS */ -$this->provideCssFile('plugin-output.less'); $this->provideCssFile('service-grid.less'); $this->provideCssFile('tables.less'); diff --git a/modules/monitoring/library/Monitoring/Object/Service.php b/modules/monitoring/library/Monitoring/Object/Service.php index ee75706ea..e2f017186 100644 --- a/modules/monitoring/library/Monitoring/Object/Service.php +++ b/modules/monitoring/library/Monitoring/Object/Service.php @@ -107,6 +107,7 @@ class Service extends MonitoredObject { return $this->backend->select()->from('servicestatus', array( 'instance_name', + 'host_attempt', 'host_icon_image', 'host_icon_image_alt', 'host_acknowledged', @@ -122,6 +123,7 @@ class Service extends MonitoredObject 'host_notifications_enabled', 'host_passive_checks_enabled', 'host_state', + 'host_state_type', 'service_icon_image', 'service_icon_image_alt', 'service_acknowledged', diff --git a/modules/monitoring/library/Monitoring/Plugin/Perfdata.php b/modules/monitoring/library/Monitoring/Plugin/Perfdata.php index 3bcebdbf6..34a6cb30f 100644 --- a/modules/monitoring/library/Monitoring/Plugin/Perfdata.php +++ b/modules/monitoring/library/Monitoring/Plugin/Perfdata.php @@ -400,7 +400,6 @@ class Perfdata $data = $this->calculatePieChartData(); $pieChart = new InlinePie($data, $this); $pieChart->setColors(array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd')); - $pieChart->setSparklineClass('sparkline-perfdata'); if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) { $pieChart->disableNoScript(); diff --git a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php index 9fdaff259..eac9ef293 100644 --- a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php +++ b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php @@ -108,6 +108,7 @@ abstract class MonitoredObjectController extends Controller $this->setupLimitControl(50); $this->setupPaginationControl($this->view->history, 50); $this->view->object = $this->object; + $this->render('object/detail-history', null, true); } /** @@ -180,7 +181,6 @@ abstract class MonitoredObjectController extends Controller $isService ? $object->getHost()->getName() : $object->getName() ), 'label' => $this->translate('Host'), - 'icon' => 'host', 'url' => 'monitoring/host/show', 'urlParams' => $params ) @@ -195,7 +195,6 @@ abstract class MonitoredObjectController extends Controller $isService ? $object->getHost()->getName() : $object->getName() ), 'label' => $this->translate('Service'), - 'icon' => 'service', 'url' => 'monitoring/service/show', 'urlParams' => $params ) @@ -209,7 +208,6 @@ abstract class MonitoredObjectController extends Controller $isService ? $object->getHost()->getName() : $object->getName() ), 'label' => $this->translate('Services'), - 'icon' => 'services', 'url' => 'monitoring/host/services', 'urlParams' => $params ) @@ -227,7 +225,6 @@ abstract class MonitoredObjectController extends Controller : sprintf($this->translate('Show all event records of host %s'), $object->getName()) , 'label' => $this->translate('History'), - 'icon' => 'rewind', 'url' => $isService ? 'monitoring/service/history' : 'monitoring/host/history', 'urlParams' => $params ) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index a0dbb0d8f..154dc1a4e 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -1,10 +1,17 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ +// Show more and load more links in overviews +.action-links { + text-align: right; +} + +// State summary badges .state-badges { display: inline-block; + vertical-align: middle; > ul > li { - padding-right: 5px; + padding-right: @vertical-padding; &:last-child { padding-right: 0; @@ -12,16 +19,47 @@ } } +// Multi-selection info +.selection-info { + float: right; + font-size: @font-size-small; + padding: @vertical-padding / 2 0; + + &:hover { + cursor: help; + } +} + +// Performance data pie charts +.sparkline { + height: 1em; + margin-right: 0.1em; + position: relative; + top: 0.1em; + width: 1em; +} + +// Host and service summaries in detail and list views .hosts-summary, .services-summary { - .v-center(); - margin-top: @horizontal-padding; + margin-bottom: 0.5em; + + > .hosts-link, + > .services-link, + > .state-badges { + vertical-align: middle; + } +} + +// State table in the host and service multi-selection and detail views +.host-detail-state, +.service-detail-state { + margin-bottom: 0.5em; } .grid { .hosts-summary, .services-summary { - margin: 0; .pull-left(); } } @@ -64,8 +102,6 @@ } .boxview div.box.badge { - border-radius: 3px; - margin: 5px; padding: 5px; } @@ -79,26 +115,41 @@ /* Tactical overview element styles */ .tactical > .boxview > div.box { - min-height: 30em; + min-height: 45em; + padding: 0px; } .tactical div.box.header { - min-height: 5em; - border-bottom:1px solid @gray-lighter; + margin: 10px; + min-height: 8em; + color: @text-color-inverted; + font-size: @font-size-dashboard; +} + +.tactical div.box.badge { + border-radius: 0.0em; } div.box.ok_hosts.state_up { - border: 1px solid @gray-lighter; - border-left: 15px solid @color-ok; + background-color: @color-ok; + border: 1px solid white; } div.box.problem_hosts.state_down { - border: 1px solid @gray-lighter; - border-left: 15px solid @color-critical; + background-color: @color-critical; + border: 1px solid white; } div.box.ok_hosts div.box.entry, div.box.problem_hosts div.box.entry { - min-width: 11.1em; + min-width: 8em; + min-height: 4em; +} + +.tactical div.box.contents { + background-color: white; + min-height: 13em; + font-size: @font-size-dashboard-small; + text-align: left; } div.box.monitoringfeatures { @@ -347,23 +398,36 @@ form.instance-features span.description, form.object-features span.description { text-align: left; } -form.object-features .control-label-group { - text-align: left; - width: 150px; +.object-features { + .control-label-group { + text-align: left; + padding: @table-column-padding; + padding-left: 0; + width: @name-value-table-name-width; + + label { + font-size: inherit; + } + } + + input[type="checkbox"] { + margin: @table-column-padding; + } } -form.object-features .control-label { - margin-left: 7px; - line-height: 25px; +div.pluginoutput { + border-left: 5px solid @gray-lighter; + padding: 0.66em 0.33em; } -.custom-variables ul { - list-style-type: none; - margin: 0; - padding: 0; - padding-left: @vertical-padding; -} +.go-ahead > a { + border-bottom: 1px @gray-light dotted; + &:hover { + border-bottom: 1px @gray-light solid; + text-decoration: none; + } +} //p.pluginoutput { // width: 100%; diff --git a/modules/monitoring/public/css/plugin-output.less b/modules/monitoring/public/css/plugin-output.less deleted file mode 100644 index faa5110bf..000000000 --- a/modules/monitoring/public/css/plugin-output.less +++ /dev/null @@ -1,13 +0,0 @@ -/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ - -p.plugin-output { - .text-small(); - font-family: @font-family-fixed; - line-height: @line-height-small; -} - -pre.plugin-output { - .text-small(); - line-height: @line-height-small; - white-space: pre-wrap; -} diff --git a/modules/monitoring/public/css/service-grid.less b/modules/monitoring/public/css/service-grid.less index 54565ab8d..6fee13252 100644 --- a/modules/monitoring/public/css/service-grid.less +++ b/modules/monitoring/public/css/service-grid.less @@ -1,6 +1,6 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ -table.service-grid-table { +.service-grid-table { width: 0; white-space: nowrap; @@ -25,7 +25,7 @@ table.service-grid-table { } } - th.rotate-45 { + .rotate-45 { height: 6em; div { @@ -34,10 +34,14 @@ table.service-grid-table { } } - td.service-grid-table-more { + .service-grid-table-more { text-align: center; a { display: inline; } } } + +.joystick-pagination a { + color: @text-color; +} diff --git a/modules/monitoring/public/css/tables.less b/modules/monitoring/public/css/tables.less index 07413ae02..5efedf50a 100644 --- a/modules/monitoring/public/css/tables.less +++ b/modules/monitoring/public/css/tables.less @@ -2,10 +2,99 @@ @border-left-width: 6px; -.count-col { - width: 60px; +// Check source reachable information in the host and service detail views +.check-source-meta { + font-size: @font-size-small; } +// Type information for backends in the monitoring config +.config-label-meta { + font-size: @font-size-small; +} + +// Column for counts, e.g. host group members +.count-col { + width: 4em; +} + +// Custom variables in the host and service detail view +.custom-variables > ul { + list-style-type: none; + margin: 0; + padding: 0 0 0 @vertical-padding; + + &:first-child { + padding: 0; + } +} + +// Host name and IP addresses in the host and service detail view +.host-meta { + color: @text-color-light; + font-size: @font-size-small; +} + +// Link to unhandled services in the hosts overview +.host-services-incidents { + color: @color-critical; + font-family: @font-family-wide; + font-size: @font-size-small; +} + +// Notification recipient in the notifications overview +.notification-recipient { + color: @text-color-light; + float: right; + font-size: @font-size-small; +} + + +// Container for plugin output and performance data in overviews +.overview-plugin-output-container { + .clearfix(); +} + +// Performance data pies in overviews +.overview-performance-data { + float: right; + font-size: @font-size-small; +} + +// Plugin output in overviews +.overview-plugin-output { + color: @text-color-light; + font-family: @font-family-fixed; + font-size: @font-size-small; + margin: 0; +} + +// Table for performance data in detail views +.performance-data-table { + width: 100%; + + > thead > tr > th { + text-align: left; + } + + > thead > tr > th:first-child, + > tbody > tr > td:first-child { + // Reset base padding + padding-left: 0; + } +} + +// Performance data table column for sparkline pie charts in detail views +.sparkline-col { + width: 2em; +} + +// Service description if in the service detail view +.service-meta { + color: @text-color-light; + font-size: @font-size-small; +} + +// State column for label and duration in overviews .state-col { &.state-ok, &.state-up { @@ -18,71 +107,97 @@ &.state-critical, &.state-down { - .bg-color-critical(); - .fg-color-inverted(); + background-color: @color-critical; + color: @text-color-inverted; &.handled { - .bg-color-default(); - .fg-color-default(); + background-color: inherit; + color: inherit; border-left: @border-left-width solid @color-critical-handled; } } &.state-warning { - .bg-color-warning(); - .fg-color-inverted(); + background-color: @color-warning; + color: @text-color-inverted; &.handled { - .bg-color-default(); - .fg-color-default(); + background-color: inherit; + color: inherit; border-left: @border-left-width solid @color-warning-handled; } } &.state-unknown { - .bg-color-unknown(); - .fg-color-inverted(); + background-color: @color-unknown; + color: @text-color-inverted; &.handled { - .bg-color-default(); - .fg-color-default(); + background-color: inherit; + color: inherit; border-left: @border-left-width solid @color-unknown-handled; } } &.state-unreachable { - .bg-color-unreachable(); - .fg-color-inverted(); + background-color: @color-unreachable; + color: @text-color-inverted; &.handled { - .bg-color-default(); - .fg-color-default(); + background-color: inherit; + color: inherit; border-left: @border-left-width solid @color-unreachable-handled; } } + // State class for history events + &.state-no-state { + border-left: @border-left-width solid @text-color-light; + } + * { color: inherit; } text-align: center; - width: 100px; + width: 8em; } -.comment-col { - padding-top: 0.5em; - vertical-align: top; - width: 3em; +// Wraps links, icons and meta in overviews +.state-header { + .clearfix(); } -.comment-content { - line-height: 1.5em; - padding-top: 0.4em; - padding-bottom: 0.7em; - max-width: 15em; - color: @text-color-light; +// State icons, e.g. acknowledged in overviews +.state-icons { + float: right; } -.comment-header { - line-height: 1.8em; +// State labels in overviews +.state-label { + font-family: @font-family-wide; + font-size: @font-size-small; + letter-spacing: 1px; +} + +// State duration and state type information in overviews +.state-meta { + font-size: @font-size-small; +} + +.state-table { + border-collapse: separate; + border-spacing: 0 1px; + width: 100%; + + tr[href] { + &.active { + background-color: @gray-lighter; + } + + &:hover { + background-color: @gray-lightest; + cursor: pointer; + } + } } diff --git a/public/css/icinga/about.less b/public/css/icinga/about.less new file mode 100644 index 000000000..fd9352884 --- /dev/null +++ b/public/css/icinga/about.less @@ -0,0 +1,28 @@ +/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ + +#about { + .about-social i { + font-size: 1.7em; + color: @text-color; + } + + .about-social i:hover { + color: @icinga-blue; + } + + .about-links { + margin-top: 2.5em; + margin-bottom: 2.5em; + } + + .about-links i { + margin: 0.5em; + padding: 0; + font-size: 5em; + color: @text-color; + } + + .about-links i:hover { + color: @icinga-blue; + } +} diff --git a/public/css/icinga/badges.less b/public/css/icinga/badges.less index a2451198a..46a99969b 100644 --- a/public/css/icinga/badges.less +++ b/public/css/icinga/badges.less @@ -1,15 +1,21 @@ +/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ + +@badge-line-height: 1.2; +@badge-padding: 0.25em; + .badge { - min-width: 25px; - font-family: tahoma, verdana, sans-serif; - font-weight: @font-weight-bold; - font-size: 11px; - text-align: center; - color: @text-color-inverted; - padding-left: 5px; - padding-right: 5px; - padding-top: 2px; - padding-bottom: 2px; + .rounded-corners(); background-color: @gray-light; + color: @text-color-inverted; + display: inline-block; + font-family: @font-family-wide; + font-size: @font-size-small; + line-height: @badge-line-height; + min-width: 2em; + padding: @badge-padding; + text-align: center; + vertical-align: middle; + white-space: nowrap; &.state-ok { .bg-color-ok(); diff --git a/public/css/icinga/base.less b/public/css/icinga/base.less index e00cf3db2..595618022 100644 --- a/public/css/icinga/base.less +++ b/public/css/icinga/base.less @@ -1,5 +1,56 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ +// Gray colors +@gray: #7F7F7F; +@gray-light: #C9C9C9; +@gray-lighter: #EEEEEE; +@gray-lightest: #F7F7F7; + +// Icinga colors +@icinga-blue: #0095BF; +@icinga-blue-dark: #AA95BF; +@color-ok: #44bb77; +@color-warning: #ffaa44; +@color-warning-handled: #ffcc66; +@color-critical: #ff5566; +@color-critical-handled: #ff99aa; +@color-unknown: #aa44ff; +@color-unknown-handled: #cc77ff; +@color-unreachable: #aa44ff; +@color-unreachable-handled: #cc77ff; +@color-pending: #77aaff; + +// Background color for +@body-bg-color: #fff; + +// Text colors +@text-color: #535353; +@text-color-inverted: @body-bg-color; +@text-color-light: @gray; + +// Text color on +@link-color: @text-color; + +// Font families +@font-family: Calibri, Helvetica, sans-serif; +@font-family-fixed: "Liberation Mono", "Lucida Console", Courier, monospace; +@font-family-wide: Tahoma, Verdana, sans-serif; + +// Font sizes +@font-size: 0.750em; // 12px +@font-size-small: 0.917em; // 11px +@font-size-dashboard: 3.5em; // 56px +@font-size-dashboard-small: 1.1em; // 17px +@font-weight-bold: 600; + +// Set line-height w/o unit so that the line-height is dynamically calculated as font-size * line-height +@line-height: 1.5; + +@table-column-padding: 0.333em; // 4px + +@vertical-padding: 0.5em; // 6px +@horizontal-padding: 1em; // 12px + // Make padding not affect the final computed width of an element html { box-sizing: border-box; @@ -13,71 +64,93 @@ html { a { // Reset defaults color: inherit; - font-weight: @font-weight-bold; text-decoration: none; + &:focus { + outline-color: @icinga-blue; + } + &:hover { text-decoration: underline; } } -blockquote { - border-left: 6px solid @gray-light; - color: @text-color-light; - // Reset default margin - margin: 0; - font-family: @font-family-fixed; - padding: @vertical-padding @horizontal-padding; +// Default margin for block text +blockquote, p, pre { + margin: 0 0 1em 0; } -body { - background-color: @body-bg-color; - color: @text-color; - font-family: @font-family; - font-size: @font-size; +blockquote { + border-left: 5px solid @gray-lighter; + padding: 0.667em 0.333em; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: @font-weight-bold; + margin: 0.556em 0 0.333em; } h1 { - border-bottom: 1px solid @gray-lightest; - font-size: 18px; - font-weight: normal; - line-height: 22px; + border-bottom: 1px solid @gray-lighter; + font-size: 1.333em; } h2 { - border-bottom: 1px solid @gray-lightest; - font-size: 16px; - font-weight: normal; - line-height: 19px; + font-size: 1.333em; } -p { - color: @text-color; - font-size: @font-size; - line-height: @line-height; - // Remove default margin - margin: 0; +h3 { + font-size: 1.167em; +} + +h4 { + font-size: 1em; +} + +h5 { + font-size: @font-size-small; +} + +h6 { + font-size: @font-size-small; + font-weight: normal; } pre { background-color: @gray-lightest; - color: @text-color-light; font-family: @font-family-fixed; + font-size: @font-size-small; padding: @vertical-padding @horizontal-padding; + white-space: pre-wrap; } -table { - border-collapse: separate; - border-spacing: 0 1px; - width: 100%; +td, th { + padding: @table-column-padding; } -td { - padding: @vertical-padding / 2 @horizontal-padding / 2; +[class^="icon-"], [class*=" icon-"] { + // Smooth icons; ifont claims to have it, but it does not work in :before + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + &:before { + margin-left: 0; + } +} + +#layout { + background-color: @body-bg-color; + color: @text-color; + font-family: @font-family; +} + +#main > .container, #menu, #header { + font-size: @font-size; + line-height: @line-height; } @media print { .dont-print { - display:none; + display: none; } } diff --git a/public/css/icinga/colors.less b/public/css/icinga/colors.less index f8fe951ec..77908d991 100644 --- a/public/css/icinga/colors.less +++ b/public/css/icinga/colors.less @@ -1,9 +1,5 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ -.bg-color-default() { - background-color: inherit; -} - .bg-color-ok, .bg-color-up { background-color: @color-ok; @@ -87,11 +83,3 @@ .fg-color-pending { color: @color-pending; } - -.fg-color-default { - color: inherit; -} - -.fg-color-inverted() { - color: @text-color-inverted; -} diff --git a/public/css/icinga/compat.less b/public/css/icinga/compat.less index 82792f12a..6225e482d 100644 --- a/public/css/icinga/compat.less +++ b/public/css/icinga/compat.less @@ -24,10 +24,7 @@ @colorPetrol: @icinga-blue; table.action { - .action-table(); - a { - font-weight: normal; - } + .common-table(); } table.avp { diff --git a/public/css/icinga/controls.less b/public/css/icinga/controls.less index 5f1c18aec..aea9b11e5 100644 --- a/public/css/icinga/controls.less +++ b/public/css/icinga/controls.less @@ -1,6 +1,55 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ -div.sort-control { +.limiter-control > .control-group { + padding: 0; + + > .control-label-group { + text-align: left; + padding: 0; + width: 1em; + } + + > select { + width: 4.5em; + } + + > i { + .sr-only(); + } +} + +.pagination-control { + li { + &.active { + > a, + > a:hover { + border-bottom: 2px solid @icinga-blue; + color: @icinga-blue + } + > a:hover { + background: none; + cursor: default; + text-decoration: none; + } + } + + &.disabled { + color: @gray-light; + cursor: no-drop; + } + + > a, + > span { + padding: 0 0.5em 0.25em 0.5em; + } + > a:hover { + background-color: @gray-lighter; + text-decoration: none; + } + } +} + +.sort-control { label { width: auto; margin-right: 0.5em; @@ -17,7 +66,7 @@ div.sort-control { } } -html.no-js div.sort-control form { +html.no-js .sort-control form { display: table; margin-left: auto; margin-top: 0.25em; diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 7a3e64651..53b4636af 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -1,6 +1,8 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ input { + .transition(border 0.3s ease); + border: none; border-bottom: 1px solid @gray-light; color: inherit; @@ -8,18 +10,35 @@ input { padding: @vertical-padding / 2 @horizontal-padding / 2; &:focus { - border-bottom: 1px solid @icinga-blue; + border-color: @icinga-blue; + outline: none; } } input.search { padding-left: 20px; - background: @gray-lightest url('../img/icons/search.png') no-repeat 2px; + background: transparent url('../img/icons/search.png') no-repeat 2px; background-size: 12px 12px; &:focus { background-color: @body-bg-color; } + + &::-webkit-input-placeholder { + color: inherit; + } + + &:-moz-placeholder { + color: inherit; + } + + &::-moz-placeholder { + color: inherit; + } + + &:-ms-input-placeholder { + color: inherit; + } } input, select, textarea { @@ -59,6 +78,7 @@ button:hover .icon-cancel { .control-info { color: @text-color-light; + margin-left: 0.2em; &:hover { .opacity(0.6); @@ -70,7 +90,8 @@ button:hover .icon-cancel { } label { - .text-small(); + color: @text-color-light; + font-size: @font-size-small; } .control-label-group { @@ -95,8 +116,6 @@ label { border: none; padding: 0; - font-weight: @font-weight-bold; - &:hover { text-decoration: underline; } @@ -109,7 +128,7 @@ label { .form-errors, .form-errors ul, form .errors, form .errors ul { // Reset defaults - margin: 0; + margin: 5 0; padding: 0; list-style-type: none; } @@ -120,7 +139,8 @@ form .errors, form .errors ul { } .form-info { - .text-small(); + color: @text-color-light; + font-size: @font-size-small; } .form-notifications { diff --git a/public/css/icinga/layout-structure.less b/public/css/icinga/layout-structure.less index 370b746bc..d9c29e3fa 100644 --- a/public/css/icinga/layout-structure.less +++ b/public/css/icinga/layout-structure.less @@ -172,7 +172,7 @@ html { } .content { - padding: 1em; + padding: 0 1em 1em 1em; } .dashboard .content { @@ -232,11 +232,11 @@ html { /* 72em */ #layout.compact-layout { - font-size: 0.8em; + font-size: 0.875em; } #layout.poor-layout { - font-size: 0.8em; + font-size: 0.875em; .dashboard > div.container { width: 98%; diff --git a/public/css/icinga/limiter.less b/public/css/icinga/limiter.less deleted file mode 100644 index 4637baeff..000000000 --- a/public/css/icinga/limiter.less +++ /dev/null @@ -1,17 +0,0 @@ -/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ - -.limiter-control { - font-size: @font-size-small; - - li { - a { - padding: 2px 4px; - } - - &.active { - a { - color: @text-color-light; - } - } - } -} diff --git a/public/css/icinga/login.less b/public/css/icinga/login.less index 7608884c2..e9d8bd2cf 100644 --- a/public/css/icinga/login.less +++ b/public/css/icinga/login.less @@ -18,7 +18,7 @@ } .image { - padding-top: 3%; + padding-top: 5%; margin-left: auto; margin-right: auto; text-align: center; @@ -40,7 +40,7 @@ .form { position: absolute; font-size: 0.9em; - top: 30%; + top: 35%; left: 0; bottom: 0; right: 0; diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index 27d1523e6..2bad07bee 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -1,39 +1,32 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ +// Width for the name column--th--of name-value-table +@name-value-table-name-width: 14em; + .action-link { color: @icinga-blue; } -.big-icon { - font-size: 28px; -} - -.clearfix { - &:after { - content: ""; - clear: both; - display: table; - } -} - -.comment-text { - .text-small(); - font-family: @font-family-fixed; +.large-icon { + font-size: 200%; } .content-centered { - .text-center(); margin: 0 auto; + text-align: center; } .icon-col { - width: 28px; + width: 1em; } -.primary-nav { - a { - font-weight: normal; - } +.icon-strikethrough { + text-decoration: line-through; +} + +.preformatted { + font-family: @font-family-fixed; + white-space: pre-wrap; } .pull-left { @@ -44,23 +37,10 @@ float: right; } -.text-center { - text-align: center; -} - -.text-left { - text-align: left; -} - .text-right { text-align: right; } -.text-small { - color: @text-color-light; - font-size: @font-size-small; -} - .user-avatar { height: 16px; width: 16px; @@ -72,10 +52,12 @@ } } -a:hover .icon-cancel { +a:hover > .icon-cancel { color: @color-critical; } +// Link styles + .button-link { .action-link(); .button(); @@ -97,48 +79,90 @@ a:hover .icon-cancel { } } -dl.feed-list { - dd { - // Reset default margin - margin: 0; - } +// List styles - dt { +.comment-list { + margin: 0; + + .comment-header { border-bottom: 1px solid @gray-lighter; - margin-top: @vertical-padding; - - .icon-cancel { - display: none; - } &:hover { background-color: @gray-lightest; - .icon-cancel { - display: block; + + > .comment-meta > .meta-icons > .remove-action { + visibility: visible; } } - &:first-child { - margin-top: 0; + > .comment-meta > .meta-icons > .remove-action { + visibility: hidden; } } } -dl.name-value-list { +.comment-header { + .clearfix(); +} + +.comment-meta { + color: @text-color-light; + font-size: @font-size-small; + + > .meta-icons { + float: right; + margin-top: 0.2em; + } +} + +.comment-text { + // Reset margin + margin: 0; +} + +.name-value-list { dd { // Reset default margin margin: 0; } dt { - .text-small(); + color: @text-color-light; + font-size: @font-size-small; } } -table.action-table { +// Table styles + +.common-table { + width: 100%; + + td, th { + padding-bottom: 1em; + padding-top: 1em; + } + + th { + text-align: left; + } + + thead { + border-bottom: 1px solid @gray-light; + } + tbody tr { + border-bottom: 1px solid @gray-lightest; + border-left: 5px solid transparent; + + &:last-child { + border-bottom: none; + } + } + + tr[href] { &.active { background-color: @gray-lighter; + border-left-color: @icinga-blue; } &:hover { @@ -146,42 +170,23 @@ table.action-table { cursor: pointer; } } -} -table.listing-table { - border-collapse: collapse; - - tbody th { - text-align: left; - } - - thead { - color: @text-color-light; - // Reset default font-weight - font-weight: normal; - } - - tr { - border-bottom: 1px solid @gray-lightest; - - &:last-child { - border-bottom: none; - } + caption { + border-top: 1px solid @gray-light; + caption-side: bottom; + text-align: right; + font-style: italic; } } -.name-value-table { - border-spacing: @vertical-padding 0; - line-height: @line-height; - - th { - .text-left(); - .text-small(); - // Reset default font-weight - font-weight: normal; - width: 120px; - vertical-align: top; - } +.name-value-table th { + color: @text-color-light; + // Reset default font-weight + font-weight: normal; + padding-left: 0; + text-align: left; + vertical-align: top; + width: @name-value-table-name-width; } // TODO(el): Fix @@ -200,9 +205,4 @@ table.listing-table { .pull-right(); padding: @vertical-padding / 2 0; } - - .selection-info { - .pull-right(); - padding: @vertical-padding / 2 0; - } } diff --git a/public/css/icinga/menu.less b/public/css/icinga/menu.less index 1bd2aaf9d..f975a5f2e 100644 --- a/public/css/icinga/menu.less +++ b/public/css/icinga/menu.less @@ -1,313 +1,168 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ +@icon-width: 1.2em; // 1em width + 0.2em right margin + #menu { - max-height: 100%; + height: 100%; overflow: auto; } -#menu > nav > ul > li.nav-item.no-icon a { - display: inline-block; - padding-left: 28px; -} - -#layout.hoveredmenu #menu { - overflow: visible; -} - -#menu, #menu ul { - margin: 0; - padding: 0; -} - #menu a { - color: @text-color-default; -} - -#menu .separator { - background-color: #888; -} - -#menu li { - margin-left: 0.0em; -} - -#menu > nav > ul > li > ul { - display: none; - padding-left: 6px; -} - -.no-js #menu > nav > ul > li > ul { - display: block; -} - -#menu > nav > ul > li.active > ul { - display: block; -} - -#menu > nav > ul > li.active { - background-color: white; - padding-left: 0.0em; - margin-left: 0; - margin-right: 0; -} - -#menu > nav > ul > li.active > a { - color: @icinga-blue; -} - -#menu > nav > ul > li.active > div.clearfix > a { - color: @icinga-blue; -} - -#menu > nav > ul > li.active li.active a { - color: @icinga-blue; -} - -#menu > nav > ul > li a:hover { - color: @icinga-blue; -} - -#menu > nav > ul > li.nav-item.hover > ul > li > a:hover { - color: @gray; -} - -#menu > nav > ul > li.nav-item.hover > ul > li div.clearfix > a:hover { - color: @gray; -} - -#menu > nav > ul > li li { - font-size: 0.8em; - padding-left: 1.6em; -} - -#menu .badge { - margin-right: 5px; -} - -#menu nav > ul > li.active > .badge { - margin-top: 15px; - margin-right: 5px; -} - -#menu nav > ul > li > div > .badge{ - margin-top: 8px; -} - -#menu nav > ul > li.active > div > .badge{ - display: none; -} - - -/* Collapsed menu item color */ -#menu > nav > ul > li > a { - color: @text-color-light; - font-weight: 500; -} - -/* Sub item color */ -#menu .active ul li a { - color: @colorTextDefault; -} - -#menu ul { - list-style-type: none; - padding: 0; -} - -#menu ul li a { - display: block; - line-height: 2.8em; - padding-left: 0.7em; - text-decoration: none; - white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; + + &:focus { + color: @icinga-blue; + outline-offset: -0.25em; + } + + &:hover { + color: @icinga-blue; + text-decoration: none; + } +} + +#menu .active > a { + color: @icinga-blue; +} + +#menu .nav-level-1 > .nav-item { + border-left: 5px solid transparent; + line-height: 2.167em; // 26 px + + &.active { + > a > .badge { + display: none; + } + + .nav-level-2 > li { + // Expand menu if active + display: block; + } + + background-color: @body-bg-color; + border-color: @icinga-blue; + } + + &.no-icon > a { + margin-left: @icon-width; + } + + > a { + padding: 0.5em 0.5em; // 6px 6px + } + + > a:active ~ .nav-level-2 > li { + display: block; + } +} + +#menu .nav-level-2 > .nav-item { + // Collapse menu by default + display: none; + line-height: 1.833em; // 22px + margin-left: @icon-width; + + > a { + font-size: @font-size-small; + padding: 0.364em 0.545em; // 4px 6px + } +} + +.no-js #menu .nav-level-2 > .nav-item { + // Expand menu if JavaScript is disabled + display: block; } #menu img.icon { - margin-right: 0.5em; + line-height: 1; + margin: 0 0.2em; width: 1em; - height: 1em; } -#menu ul ul li a { - line-height: 1.5em; - padding-top: 0.4em; - padding-bottom: 0.7em; +#menu .user-nav-item { + background-color: @gray-light; } -#menu ul ul li a { +#menu input.search { + background: transparent url('../img/icons/search.png') no-repeat @horizontal-padding center; + background-size: 1em auto; + border: none; + border-left: 5px solid transparent; + line-height: 2.167em; + padding-left: @icon-width + @horizontal-padding; + width: 100%; + + &.active { + background-color: @body-bg-color; + border-color: @icinga-blue; + } } -#menu > nav > ul > li { - border-left: solid 5px @gray-lighter; +// Badge offset correction + +#menu > nav > .nav-level-1 > .badge-nav-item > a > .badge { + margin-top: 0.2em; } -#menu > nav > ul > li > a { - color: @text-color; +#menu .nav-level-2 > .badge-nav-item > a > .badge { + margin-top: 0.2em; } -#menu > nav > ul > li.active { - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; - border-left: solid 5px @icinga-blue; - -webkit-transition: border 0.5s; - -moz-transition: border 0.5s; - -o-transition: border 0.5s; - transition: border 0.5s; -} +// Hovered menu - -/* BEGIN OF Hoverable menu */ - -#menu li.hover { - width: 27em; - padding-left: 0.0em; - margin-left: 0px; - margin-right: 5; +#menu .nav-level-1 > .nav-item.hover { position: relative; -} -#menu li.hover > ul{ - position: absolute; - display: block; - left: 10.9em; - right: 0; - top: -0.5em; - padding-top: 0.8em; - padding-left: 1em; - padding-bottom: 0.5em; - height: auto; - background-color: @text-color; - font-size:15px; -} + &:before { + border: 0.5em solid rgba(0, 0, 0, 0); + border-right-color: @text-color; + content: ""; + position: absolute; + right: 0; + top: 30%; + } -#menu li.hover > a { - overflow: visible; -} + > .nav-level-2 { + background-color: @text-color; + color: @text-color-inverted; + left: 100%; + padding: @vertical-padding 0; + position: absolute; + top: 0; + width: 14em; -#menu li.hover > ul a { - width: 90%; - display: block; - color: @text-color-inverted; -} + > .nav-item { + display: block; -#menu li.hover > ul a:hover { - text-decoration: underline; -} + > a:hover { + color: @text-color-inverted; + text-decoration: underline; + } + } + } -#menu li.hover > ul a:focus { - text-shadow: none; -} - -#menu li.hover > ul > li.active > a { - font-weight: bold; - color: @text-color-light; -} - -#menu li.hover li { - padding: 0; -} - -#menu li.hover > a:after { - border: 0.5em solid rgba(0, 0, 0, 0); - border-right-color: #333; - content: " "; - margin-top: 0.8em; - pointer-events: none; - position: absolute; - left: 10.8em; - height: 0; - width: 0; + > a > .badge { + display: none; + } } #layout.hoveredmenu { #main { - z-index: 2; + z-index: 2; } + #sidebar { - z-index: 3; + z-index: 3; + } + + #menu { + overflow: visible; } } -/* END of Hoverable menu */ - -#menu form { - width: 100%; -} - -#menu input.search { - font-size: 14px; - margin: 0; - padding: 0 0.5em 0 2.2em; - border: none; - width: 100%; - border-radius: 0; - height: 2.8em; - display: block; - outline: none; - background-color: transparent; - background-image: url('../img/icons/search.png'); - background-repeat: no-repeat; - background-position: 1.0em center; - color: @colorTextDefault; - border-left: solid 5px @gray-lighter; -} - -html.ie8 #menu input.search { - line-height: 2.8em; -} - -#menu input.search:-ms-input-placeholder { - color: @text-color; -} - -#menu input.search::-webkit-input-placeholder { - color: @text-color; -} - -#menu input.search::-moz-placeholder { - color: @text-color; -} - -#menu input.search.active { - background-color: white; - color: #121212; - text-shadow: none; - border-left: solid 5px @icinga-blue; - -webkit-transition: border 0.5s; - -moz-transition: border 0.5s; - -o-transition: border 0.5s; - transition: border 0.5s; -} - -#menu input.search.active::-moz-placeholder { - color: #999; -} - -#menu input.search.active::-webkit-input-placeholder { - color: #999; -} - -#menu input.search.active:-ms-input-placeholder { - color: #999; -} - -input:focus { outline: none; } - -/* Make focus outline properly visible */ -a:focus { - outline: dotted black 1px; -} - -/* Displaying the outline in the navigation is not possible because of the messed up link borders, - color those links instead. */ -#menu a:focus, -#menu > nav > ul > li > a:focus, -#menu .active ul li a:focus { - color: @icinga-blue; - outline: none; -} +// Accessibility skip links .skip-links { position: relative; @@ -318,9 +173,9 @@ a:focus { li { display: block; a, button[type="submit"] { - background-color: #fff; - left: -999em; - padding: 0.8em; + background-color: @body-bg-color; + left: -999px; + padding: @vertical-padding @horizontal-padding; position: absolute; width: 100%; &:focus { @@ -334,46 +189,3 @@ a:focus { } } } - -.user-nav-item { - margin-top: 39px; -} -.user-nav-item ~ .user-nav-item { - margin-top: 0px; -} - -#menu .user-nav-item { - background-color: @gray; - border-left: solid 5px @gray; - - .user-avatar { - border: 1px solid @gray; - float: right; - margin-top: 5px; - margin-right: 5px; - border-radius: 150px; - height: 30px; - width: 30px; - } - - a { - color: @text-color-inverted; - }; - - a:hover { - background-color: white; - color: @gray; - }; -} - -#menu > nav > ul > li.user-nav-item.active > div.clearfix > a { - color: @gray; -} - -#menu > nav > ul > li.user-nav-item.active { - border-left: solid 5px @gray; - -webkit-transition: border 0.5s; - -moz-transition: border 0.5s; - -o-transition: border 0.5s; - transition: border 0.5s; -} diff --git a/public/css/icinga/mixins.less b/public/css/icinga/mixins.less index 512a1b5a3..fe04d7778 100644 --- a/public/css/icinga/mixins.less +++ b/public/css/icinga/mixins.less @@ -26,6 +26,14 @@ } } +.clearfix { + &:after { + content: ""; + clear: both; + display: table; + } +} + .invisible { // Maintain layout but hide visually and from screen readers visibility: hidden; @@ -55,6 +63,13 @@ background-clip: padding-box; } +.transition (@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -o-transition: @transition; + transition: @transition; +} + .visible { visibility: visible; } diff --git a/public/css/icinga/nav.less b/public/css/icinga/nav.less index 002bfe6e1..5ca24c121 100644 --- a/public/css/icinga/nav.less +++ b/public/css/icinga/nav.less @@ -1,23 +1,38 @@ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ -li.nav-item { - a, span { +.badge-nav-item { + > a { + .clearfix(); + + > .badge { + float: right; + } + } +} + +.nav-item { + > a, + > span { // Rollover display: block; } } -ul.nav { +.nav { // Reset defaults + list-style-type: none; margin: 0; padding: 0; - list-style-type: none; } -ul.tab-nav { +.tab-nav { .clearfix(); - li { - .pull-left(); + > .nav-item { + float: left; } } + +.primary-nav a { + font-weight: 500; +} diff --git a/public/css/icinga/pagination.less b/public/css/icinga/pagination.less deleted file mode 100644 index a74265b73..000000000 --- a/public/css/icinga/pagination.less +++ /dev/null @@ -1,44 +0,0 @@ -/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ - -.pagination-control { - font-size: @font-size-small; - - li { - &.active { - > a, - > a:hover { - background-color: @text-color; - border-color: @text-color; - color: @text-color-inverted; - } - > a:hover { - cursor: default; - text-decoration: none; - } - } - - &.disabled { - color: @gray-light; - cursor: no-drop; - } - - &:first-child { - > a, - > a:hover { - margin-left: 0; - } - } - - > a, - > span { - border: 1px solid @gray-lighter; - margin-left: -1px; - padding: 4px 8px; - } - > a:hover { - background-color: @gray-lighter; - border: 1px solid @gray-lighter; - padding: 4px 8px; - } - } -} diff --git a/public/css/icinga/selection-toolbar.less b/public/css/icinga/selection-toolbar.less deleted file mode 100644 index d9c696f4a..000000000 --- a/public/css/icinga/selection-toolbar.less +++ /dev/null @@ -1,10 +0,0 @@ -/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ - -div.selection-toolbar { - float: right; - padding-right: 20px; -} - -div.selection-toolbar a { - color: @icinga-blue; -} diff --git a/public/css/icinga/themes/icinga.less b/public/css/icinga/themes/icinga.less deleted file mode 100644 index c663e757b..000000000 --- a/public/css/icinga/themes/icinga.less +++ /dev/null @@ -1,43 +0,0 @@ -// Gray colors -@gray: #7F7F7F; -@gray-light: #C9C9C9; -@gray-lighter: #EEEEEE; -@gray-lightest: #F7F7F7; - -// Icinga colors -@icinga-blue: #0095BF; -@icinga-blue-dark: #AA95BF; -@color-ok: #44bb77; -@color-warning: #ffaa44; -@color-warning-handled: #ffcc66; -@color-critical: #ff5566; -@color-critical-handled: #ff99aa; -@color-unknown: #aa44ff; -@color-unknown-handled: #cc77ff; -@color-unreachable: #aa44ff; -@color-unreachable-handled: #cc77ff; -@color-pending: #77aaff; - -// Background color for -@body-bg-color: #fff; - -// Text colors -@text-color: #535353; -@text-color-inverted: @body-bg-color; -@text-color-light: @gray; - -// Text color on -@link-color: @text-color; - -// Font and line-height for text -@font-family: Calibri, Helvetica, sans-serif; -@font-family-fixed: Menlo, monospace; -@font-size: 14px; -@font-size-small: 11px; -@font-weight-bold: 600; -@line-height: 17px; -@line-height-small: 14px; - -// Default padding -@vertical-padding: 6px; -@horizontal-padding: 12px; diff --git a/public/css/icinga/widgets.less b/public/css/icinga/widgets.less index 61adf4932..340ddf505 100644 --- a/public/css/icinga/widgets.less +++ b/public/css/icinga/widgets.less @@ -9,7 +9,7 @@ table.historycolorgrid th { height: 1em; margin: 0.5em; font-size: 0.55em; - font-weight: normal; + font-weight: bold; } table.historycolorgrid td { @@ -24,17 +24,18 @@ table.historycolorgrid td:hover { table.historycolorgrid td.weekday { font-size: 0.55em; - font-weight: normal; + font-weight: bold; width: 2.5em; opacity: 1.0; } table.historycolorgrid a, table.historycolorgrid span { + .rounded-corners(0.2em); margin: 0; text-decoration: none; display: block; - width: 1em; - height: 1em; + width: 1.1em; + height: 1.1em; } table.historycolorgrid a:hover { @@ -66,21 +67,12 @@ table.multiselect tr[href] td { } } -ul.datafilter li { - list-style-type: none; - margin: 0; -} - ul.tree select { /* ?? */ margin-bottom: 0.3em; margin-left: 1em; } -ul.datafilter li input, ul.datafilter li select:first-child { - margin-left: 1em; -} ul.tree { - font-size: 0.8em; padding: 0; margin: 0; } @@ -165,7 +157,7 @@ ul.tree > ul > li::before, ul.tree > ul > li::after { ul.tree li a { display: inline-block; -/* TODO -> find something better padding-left: 2.4em; */ + padding-left: 1em; line-height: 2em; text-decoration: none; color: #777; @@ -192,10 +184,6 @@ ul.tree li a.error:hover { opacity: 0.85; } -.pie-data:hover { - opacity: 0.6; -} - /* charts should grow as much as possible but never beyond the current viewport's size */ .svg-container-responsive { padding: 1.5em; @@ -238,42 +226,6 @@ ul.tree li a.error:hover { // color: @colorGray; // text-decoration: none; //} -// -//#menu nav ul .badge { -// margin-right: 0em; -// top: 0.5em; -//} - -//#menu nav > ul > li.active > .badge-container { -// display: none; -//} -// -//#menu nav > ul > li.hover > .badge-container { -// display: none; -//} -// -//#menu nav > ul > li.active > ul > li .badge-container { -// position: relative; -// top: -0.5em; -//} - -#menu nav > ul > li.hover > ul > li > a { - width: 12.5em; -} - -//#menu nav > ul > li.hover > ul > li .badge-container { -// position: relative; -// top: -0.5em; -//} - -#menu nav > ul > li.hover > ul > li { - // prevent floating badges from resizing list items in webkit - //max-height: 2em; -} - -//li li .badge { -// font-size: 0.975em; -//} //.badge-critical { // background-color: @colorCritical; @@ -303,46 +255,14 @@ ul.tree li a.error:hover { // background-color: @colorUnknown; //} -.sparkline-box { - position: relative; - top: -3px; - float: right; -} - -.dashboard .sparkline-box { - top: -3px; -} - -.sparkline { - width: 12px; - height: 12px; - position: relative; - top: 4px; - - margin: 0em 0em 0em 0.1em; -} - .tipsy .tipsy-inner { // overwrite tooltip max width, we need them to grow bigger + font-family: @font-family; + font-size: @font-size-small; 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; -} - .progress-label span { font-size: 1.5em; .animate(blink 1.4s infinite both); diff --git a/public/img/bugreport.png b/public/img/bugreport.png deleted file mode 100644 index 23d913291..000000000 Binary files a/public/img/bugreport.png and /dev/null differ diff --git a/public/img/docs.png b/public/img/docs.png deleted file mode 100644 index 051db6cce..000000000 Binary files a/public/img/docs.png and /dev/null differ diff --git a/public/img/support.png b/public/img/support.png deleted file mode 100644 index 17a0c9233..000000000 Binary files a/public/img/support.png and /dev/null differ diff --git a/public/img/wiki.png b/public/img/wiki.png deleted file mode 100644 index 02df73af6..000000000 Binary files a/public/img/wiki.png and /dev/null differ diff --git a/public/js/icinga/behavior/actiontable.js b/public/js/icinga/behavior/actiontable.js index 8ec3c63f6..6e134d3fd 100644 --- a/public/js/icinga/behavior/actiontable.js +++ b/public/js/icinga/behavior/actiontable.js @@ -330,7 +330,7 @@ this.loading = false; this.on('rendered', this.onRendered, this); - this.on('click', 'table.action tr[href], table.action-table tr[href]', this.onRowClicked, this); + this.on('click', 'table.action tr[href], table.table-row-selectable tr[href]', this.onRowClicked, this); }; ActionTable.prototype = new Icinga.EventListener(); @@ -342,9 +342,9 @@ */ ActionTable.prototype.tables = function(context) { if (context) { - return $(context).find('table.action, table.action-table'); + return $(context).find('table.action, table.table-row-selectable'); } - return $('table.action, table.action-table'); + return $('table.action, table.table-row-selectable'); }; /** @@ -354,7 +354,7 @@ var self = event.data.self; var $target = $(event.target); var $tr = $target.closest('tr'); - var table = new Selection($tr.closest('table.action, table.action-table')[0], self.icinga); + var table = new Selection($tr.closest('table.action, table.table-row-selectable')[0], self.icinga); // some rows may contain form actions that trigger a different action, pass those through if (!$target.hasClass('rowaction') && $target.closest('form').length && @@ -417,7 +417,7 @@ var self = evt.data.self; // initialize all rows with the correct row action - $('table.action tr, table.action-table tr', container).each(function(idx, el) { + $('table.action tr, table.table-row-selectable tr', container).each(function(idx, el) { // decide which row action to use: links declared with the class rowaction take // the highest precedence before hrefs defined in the tr itself and regular links @@ -437,7 +437,7 @@ }); // IE will not ignore user-select unless we cancel selectstart - $('table.action.multiselect tr, table.action-table.multiselect tr', container).each(function(idx, el) { + $('table.action.multiselect tr, table.table-row-selectable.multiselect tr', container).each(function(idx, el) { $(el).on('selectstart', false); }); diff --git a/public/js/icinga/behavior/navigation.js b/public/js/icinga/behavior/navigation.js index e614a95ff..cf91bc392 100644 --- a/public/js/icinga/behavior/navigation.js +++ b/public/js/icinga/behavior/navigation.js @@ -42,30 +42,32 @@ Navigation.prototype = new Icinga.EventListener(); /** - * Apply the menu selection and hovering according to the current state + * Activate menu items if their class is set to active or if the current URL matches their link * - * @param evt {Object} The event context + * @param {Object} e Event */ - Navigation.prototype.onRendered = function(evt) { - var self = evt.data.self; - this.element = evt.target; + Navigation.prototype.onRendered = function(e) { + var _this = e.data.self; - if (! self.active) { + this.element = e.target; + + if (! _this.active) { // There is no stored menu item, therefore it is assumed that this is the first rendering // of the navigation after the page has been opened. // initialise the menu selected by the backend as active. - var $menus = $('#menu li.active', evt.target); - if ($menus.size()) { - $menus.each(function () { - self.setActive($(this)); + var $menus = $('#menu li.active', e.target); + if ($menus.length) { + $menus.each(function() { + _this.setActive($(this)); }); } else { // if no item is marked as active, try to select the menu from the current URL - self.setActiveByUrl($('#col1').data('icingaUrl')); + _this.setActiveByUrl($('#col1').data('icingaUrl')); } } - self.refresh(); + + _this.refresh(); }; /** @@ -205,7 +207,7 @@ // unfold the containing menu var $outerMenu = $selectedMenu.parent().closest('li'); - if ($outerMenu.size()) { + if ($outerMenu.length) { $outerMenu.addClass('active'); } } else if ($input.length) { diff --git a/public/js/icinga/behavior/sparkline.js b/public/js/icinga/behavior/sparkline.js index ee352002a..04c55b3e4 100644 --- a/public/js/icinga/behavior/sparkline.js +++ b/public/js/icinga/behavior/sparkline.js @@ -2,7 +2,7 @@ (function(Icinga, $) { - "use strict"; + 'use strict'; Icinga.Behaviors = Icinga.Behaviors || {}; @@ -10,45 +10,20 @@ Icinga.EventListener.call(this, icinga); this.on('rendered', this.onRendered, this); }; + Sparkline.prototype = new Icinga.EventListener(); - Sparkline.prototype.onRendered = function(evt) { - var el = evt.target; - - $('.sparkline', el).each(function(i, element) { - // read custom options - var $spark = $(element); - var title = $spark.attr('title'); - - if ($spark.attr('labels')) { - $spark.removeAttr('original-title'); - } - - var options; - if ($spark.hasClass('sparkline-perfdata')) { - options = { - enableTagOptions: true, - width: 16, - height: 16, - title: title, - disableTooltips: true, - borderWidth: 1.4, - borderColor: '#FFF' - }; - $spark.sparkline('html', options); - } else if ($spark.hasClass('sparkline-multi')) { - options = { - width: 100, - height: 100, - title: title, - enableTagOptions: true - }; - $spark.sparkline('html', options); - } + Sparkline.prototype.onRendered = function(e) { + var el = e.target; + $(e.target).find('.sparkline').each(function() { + $(this).sparkline('html', { + enableTagOptions: true, + disableTooltips: true + }); }); }; Icinga.Behaviors.Sparkline = Sparkline; -}) (Icinga, jQuery); +})(Icinga, jQuery);