Merge branch 'master' into bugfix/significant-whitespaces-8777

Conflicts:
	library/Icinga/Web/Widget/FilterEditor.php
This commit is contained in:
Eric Lippmann 2015-05-18 13:35:28 +02:00
commit 82ee1d6e60
189 changed files with 4014 additions and 1470 deletions

View File

@ -1 +1 @@
v2.0.0-beta2 v2.0.0-beta3

View File

@ -11,14 +11,14 @@ use Icinga\Forms\Config\GeneralConfigForm;
use Icinga\Forms\Config\ResourceConfigForm; use Icinga\Forms\Config\ResourceConfigForm;
use Icinga\Forms\ConfirmRemovalForm; use Icinga\Forms\ConfirmRemovalForm;
use Icinga\Security\SecurityException; use Icinga\Security\SecurityException;
use Icinga\Web\Controller\ActionController; use Icinga\Web\Controller;
use Icinga\Web\Notification; use Icinga\Web\Notification;
use Icinga\Web\Widget; use Icinga\Web\Widget;
/** /**
* Application and module configuration * Application and module configuration
*/ */
class ConfigController extends ActionController class ConfigController extends Controller
{ {
/** /**
* The first allowed config action according to the user's permissions * The first allowed config action according to the user's permissions
@ -128,8 +128,15 @@ class ConfigController extends ActionController
$this->view->modules = Icinga::app()->getModuleManager()->select() $this->view->modules = Icinga::app()->getModuleManager()->select()
->from('modules') ->from('modules')
->order('enabled', 'desc') ->order('enabled', 'desc')
->order('name') ->order('name');
->paginate(); $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() public function moduleAction()

View File

@ -34,7 +34,11 @@ class ErrorController extends ActionController
$path = preg_split('~/~', $path); $path = preg_split('~/~', $path);
$path = array_shift($path); $path = array_shift($path);
$this->getResponse()->setHttpResponseCode(404); $this->getResponse()->setHttpResponseCode(404);
$this->view->message = $this->translate('Page not found.'); $title = preg_replace('/\r?\n.*$/s', '', $exception->getMessage());
$this->view->title = 'Server error: ' . $title;
if ($this->getInvokeArg('displayExceptions')) {
$this->view->stackTrace = $exception->getTraceAsString();
}
if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) { if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
$this->view->message .= ' ' . sprintf( $this->view->message .= ' ' . sprintf(
$this->translate('Enabling the "%s" module might help!'), $this->translate('Enabling the "%s" module might help!'),

View File

@ -3,6 +3,8 @@
use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Controller;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Widget\Tabextension\OutputFormat;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Application\Logger; use Icinga\Application\Logger;
use Icinga\Data\ConfigObject; use Icinga\Data\ConfigObject;
@ -29,7 +31,7 @@ class ListController extends Controller
'list/' 'list/'
. str_replace(' ', '', $action) . str_replace(' ', '', $action)
) )
))->activate($action); ))->extend(new OutputFormat())->extend(new DashboardAction())->activate($action);
} }
/** /**
@ -42,15 +44,16 @@ class ListController extends Controller
} }
$this->addTitleTab('application log'); $this->addTitleTab('application log');
$pattern = '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
. ' - (?<message>.*)$/';
$resource = new FileReader(new ConfigObject(array( $resource = new FileReader(new ConfigObject(array(
'filename' => Config::app()->get('logging', 'file'), 'filename' => Config::app()->get('logging', 'file'),
'fields' => $pattern 'fields' => '/(?<!.)(?<datetime>[0-9]{4}(?:-[0-9]{2}){2}' // date
. 'T[0-9]{2}(?::[0-9]{2}){2}(?:[\+\-][0-9]{2}:[0-9]{2})?)' // time
. ' - (?<loglevel>[A-Za-z]+) - (?<message>.*)(?!.)/msS' // loglevel, message
))); )));
$this->view->logData = $resource->select()->order('DESC')->paginate(); $this->view->logData = $resource->select()->order('DESC');
$this->setupLimitControl();
$this->setupPaginationControl($this->view->logData);
} }
} }

View File

@ -51,7 +51,7 @@ class AuthenticationBackendReorderForm extends ConfigForm
try { try {
if ($configForm->move($backendName, $position)->save()) { if ($configForm->move($backendName, $position)->save()) {
Notification::success($this->translate('Authentication order updated!')); Notification::success($this->translate('Authentication order updated'));
} else { } else {
return false; return false;
} }

View File

@ -199,8 +199,8 @@ msgid "Authentication backend name missing"
msgstr "Nome del Backend di autenticazione non specificato" msgstr "Nome del Backend di autenticazione non specificato"
#: /usr/share/icingaweb2/application/forms/Config/AuthenticationBackendReorderForm.php:54 #: /usr/share/icingaweb2/application/forms/Config/AuthenticationBackendReorderForm.php:54
msgid "Authentication order updated!" msgid "Authentication order updated"
msgstr "Ordine di autenticazione aggiornato!" msgstr "Ordine di autenticazione aggiornato"
#: /usr/share/icingaweb2/application/forms/AutoRefreshForm.php:44 #: /usr/share/icingaweb2/application/forms/AutoRefreshForm.php:44
msgid "Auto refresh successfully disabled" msgid "Auto refresh successfully disabled"

View File

@ -130,8 +130,8 @@ msgid "Authentication backend name missing"
msgstr "Falta o nome do backend de autenticação" msgstr "Falta o nome do backend de autenticação"
#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendReorderForm.php:55 #: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendReorderForm.php:55
msgid "Authentication order updated!" msgid "Authentication order updated"
msgstr "Ordem da autenticação atualizada!" msgstr "Ordem da autenticação atualizada"
#: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:307 #: /usr/local/icingaweb/application/forms/Config/AuthenticationBackendConfigForm.php:307
msgid "Autologin" msgid "Autologin"

View File

@ -1,8 +1,12 @@
<?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<?= $this->paginationControl($modules) ?> <?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?>
<div class="content"> <div class="content">
<table class="action" data-base-target="_next"> <table class="action" data-base-target="_next">
<tbody> <tbody>

View File

@ -1,9 +1,12 @@
<?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs->render($this) ?> <?= $this->tabs; ?>
<div style="margin-top: 1em"></div> <?= $this->sortBox; ?>
<?= $this->logData ?> <?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?>
<div class="content"> <div class="content">
<?php if ($this->logData !== null): ?> <?php if ($this->logData !== null): ?>
<table class="action"> <table class="action">
@ -16,7 +19,7 @@
<?= $this->escape($value->loglevel) ?> <?= $this->escape($value->loglevel) ?>
</td> </td>
<td> <td>
<?= $this->escape($value->message) ?> <?= nl2br($this->escape($value->message), false) ?>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>

View File

@ -107,7 +107,7 @@ Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a passwor
command: command:
```` ````
openssl passwd -1 "password" openssl passwd -1 password
```` ````
> Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm. > Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm.

View File

@ -3,21 +3,133 @@
The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating
system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source. system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source.
## <a id="installation-requirements"></a> Installing Requirements ## <a id="installing-requirements"></a> Installing Requirements
* A web server, e.g. Apache or nginx * A web server, e.g. Apache or nginx
* PHP >= 5.3.0 w/ gettext and OpenSSL support * PHP >= 5.3.0 w/ gettext, intl and OpenSSL support
* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database * MySQL or PostgreSQL PHP libraries when using a database for authentication or for storing preferences into a database
* LDAP PHP library when using Active Directory or LDAP for authentication * LDAP PHP library when using Active Directory or LDAP for authentication
* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled * Icinga 1.x w/ Livestatus or IDO; Icinga 2.x w/ Livestatus or IDO feature enabled
* MySQL or PostgreSQL PHP libraries when using IDO
## <a id="installation-from-package"></a> Installing Icinga Web 2 from Package ## <a id="installing-from-package"></a> Installing Icinga Web 2 from Package
A guide on how to install Icinga Web 2 from package will follow shortly. Below is a list of official package repositories for installing Icinga Web 2 for various operating systems.
## <a id="installation-from-source"></a> Installing Icinga Web 2 from Source Distribution | Repository
------------------------|---------------------------
Debian | [debmon](http://debmon.org/packages/debmon-wheezy/icingaweb2), [Icinga Repository](http://packages.icinga.org/debian/)
Ubuntu | [Icinga Repository](http://packages.icinga.org/ubuntu/)
RHEL/CentOS | [Icinga Repository](http://packages.icinga.org/epel/)
openSUSE | [Icinga Repository](http://packages.icinga.org/openSUSE/)
SLES | [Icinga Repository](http://packages.icinga.org/SUSE/)
Gentoo | -
FreeBSD | -
ArchLinux | [Upstream](https://aur.archlinux.org/packages/icingaweb2)
**Step 1: Getting the Source** Packages for distributions other than the ones listed above may also be available.
Please contact your distribution packagers.
### <a id="package-repositories"></a> Setting up Package Repositories
You need to add the Icinga repository to your package management configuration for installing Icinga Web 2.
Below is a list with examples for various distributions.
Debian (debmon):
````
wget -O - http://debmon.org/debmon/repo.key 2>/dev/null | apt-key add -
echo 'deb http://debmon.org/debmon debmon-wheezy main' >/etc/apt/sources.list.d/debmon.list
apt-get update
````
Ubuntu Trusty:
````
wget -O - http://packages.icinga.org/icinga.key | apt-key add -
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.
RHEL and CentOS:
````
rpm --import http://packages.icinga.org/icinga.key
curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/epel/ICINGA-release.repo
yum makecache
````
Fedora:
````
rpm --import http://packages.icinga.org/icinga.key
curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/fedora/ICINGA-release.repo
yum makecache
````
SLES 11:
````
zypper ar http://packages.icinga.org/SUSE/ICINGA-release-11.repo
zypper ref
````
SLES 12:
````
zypper ar http://packages.icinga.org/SUSE/ICINGA-release.repo
zypper ref
````
openSUSE:
````
zypper ar http://packages.icinga.org/openSUSE/ICINGA-release.repo
zypper ref
````
The packages for RHEL/CentOS depend on other packages which are distributed as part of the
[EPEL repository](http://fedoraproject.org/wiki/EPEL). Please make sure to enable this repository by following
[these instructions](http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F).
### <a id="installing-from-package-example"></a> Installing Icinga Web 2
You can install Icinga Web 2 by using your distribution's package manager to install the `icingaweb2` package.
Below is a list with examples for various distributions.
Debian and Ubuntu:
````
apt-get install icingaweb2
````
RHEL, CentOS and Fedora:
````
yum install icingaweb2
````
SLES and openSUSE:
````
zypper install icingaweb2
````
### <a id="preparing-web-setup-from-package"></a> Preparing Web Setup
You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time
you visit Icinga Web 2 in your browser. When using the web setup you are required to authenticate using a token.
In order to generate a token use the `icingacli`:
````
icingacli setup token create
````
In case you do not remember the token you can show it using the `icingacli`:
````
icingacli setup token show
````
Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation:
`/icingaweb2/setup`.
## <a id="installing-from-source"></a> Installing Icinga Web 2 from Source
Although the preferred way of installing Icinga Web 2 is to use packages, it is also possible to install Icinga Web 2
directly from source.
### <a id="getting-the-source"></a> Getting the Source
First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this
repository either via git or http protocol using the following URLs: repository either via git or http protocol using the following URLs:
@ -33,7 +145,7 @@ This version also offers snapshots for easy download which you can use if you do
git clone git://git.icinga.org/icingaweb2.git git clone git://git.icinga.org/icingaweb2.git
```` ````
**Step 2: Install the Source** ### <a id="installing-from-source-example"></a> Installing Icinga Web 2
Choose a target directory and move Icinga Web 2 there. Choose a target directory and move Icinga Web 2 there.
@ -41,7 +153,7 @@ Choose a target directory and move Icinga Web 2 there.
mv icingaweb2 /usr/share/icingaweb2 mv icingaweb2 /usr/share/icingaweb2
```` ````
**Step 3: Configuring the Web Server** ### <a id="configuring-web-server"></a> Configuring the Web Server
Use `icingacli` to generate web server configuration for either Apache or nginx. Use `icingacli` to generate web server configuration for either Apache or nginx.
@ -57,13 +169,15 @@ nginx:
Save the output as new file in your webserver's configuration directory. Save the output as new file in your webserver's configuration directory.
Example for Apache on RHEL/CentOS: Example for Apache on RHEL or CentOS:
```` ````
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf
```` ````
### <a id="preparing-web-setup-from-source"></a> Preparing Web Setup
**Step 4: Preparing Web Setup** You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time
you visit Icinga Web 2 in your browser. Please follow the steps listed below for preparing the web setup.
Because both web and CLI must have access to configuration and logs, permissions will be managed using a special Because both web and CLI must have access to configuration and logs, permissions will be managed using a special
system group. The web server user and CLI user have to be added to this system group. system group. The web server user and CLI user have to be added to this system group.
@ -102,6 +216,7 @@ Use `icingacli` to create the configuration directory which defaults to **/etc/i
./bin/icingacli setup config directory ./bin/icingacli setup config directory
```` ````
When using the web setup you are required to authenticate using a token. In order to generate a token use the When using the web setup you are required to authenticate using a token. In order to generate a token use the
`icingacli`: `icingacli`:
```` ````
@ -113,11 +228,10 @@ In case you do not remember the token you can show it using the `icingacli`:
./bin/icingacli setup token show ./bin/icingacli setup token show
```` ````
**Step 5: Web Setup** Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation:
`/icingaweb2/setup`.
Visit Icinga Web 2 in your browser and complete installation using the web setup: /icingaweb2/setup ## <a id="upgrading-to-beta2"></a> Upgrading to Icinga Web 2 Beta 2
## Upgrading to Icinga Web 2 Beta 2
Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2, Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2,
you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following
@ -134,7 +248,7 @@ If you delegated authentication to your web server using the `autologin` backend
authentication backend to be able to log in again. The new name better reflects whats going on. A similar change authentication backend to be able to log in again. The new name better reflects whats going on. A similar change
affects environments that opted for not storing preferences, your new backend is `none`. affects environments that opted for not storing preferences, your new backend is `none`.
## Upgrading to Icinga Web 2 Beta 3 ## <a id="upgrading-to-beta3"></a> Upgrading to Icinga Web 2 Beta 3
Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your
configuration files after upgrading to Icinga Web 2 Beta 3. configuration files after upgrading to Icinga Web 2 Beta 3.

View File

@ -506,12 +506,21 @@ abstract class ApplicationBootstrap
protected function setupLogger() protected function setupLogger()
{ {
if ($this->config->hasSection('logging')) { if ($this->config->hasSection('logging')) {
$loggingConfig = $this->config->getSection('logging');
try { try {
Logger::create($this->config->getSection('logging')); Logger::create($loggingConfig);
} catch (ConfigurationError $e) { } catch (ConfigurationError $e) {
Logger::error($e); Logger::getInstance()->registerConfigError($e->getMessage());
try {
Logger::getInstance()->setLevel($loggingConfig->get('level', Logger::ERROR));
} catch (ConfigurationError $e) {
Logger::getInstance()->registerConfigError($e->getMessage());
} }
} }
}
return $this; return $this;
} }

View File

@ -67,6 +67,13 @@ class Logger
*/ */
protected $level; protected $level;
/**
* Error messages to be displayed prior to any other log message
*
* @var array
*/
protected $configErrors = array();
/** /**
* Create a new logger object * Create a new logger object
* *
@ -81,37 +88,69 @@ class Logger
throw new ConfigurationError('Required logging configuration directive \'log\' missing'); throw new ConfigurationError('Required logging configuration directive \'log\' missing');
} }
if (($level = $config->level) !== null) { $this->setLevel($config->get('level', static::ERROR));
if (strtolower($config->get('log', 'syslog')) !== 'none') {
$this->writer = $this->createWriter($config);
}
}
/**
* Set the logging level to use
*
* @param mixed $level
*
* @return $this
*
* @throws ConfigurationError In case the given level is invalid
*/
public function setLevel($level)
{
if (is_numeric($level)) { if (is_numeric($level)) {
$level = (int) $level; $level = (int) $level;
if (! isset(static::$levels[$level])) { if (! isset(static::$levels[$level])) {
throw new ConfigurationError( throw new ConfigurationError(
'Can\'t set logging level %d. Logging level is not defined. Use one of %s or one of the' 'Can\'t set logging level %d. Logging level is invalid. Use one of %s or one of the'
. ' Logger\'s constants.', . ' Logger\'s constants.',
$level, $level,
implode(', ', array_keys(static::$levels)) implode(', ', array_keys(static::$levels))
); );
} }
$this->level = $level; $this->level = $level;
} else { } else {
$level = strtoupper($level); $level = strtoupper($level);
$levels = array_flip(static::$levels); $levels = array_flip(static::$levels);
if (! isset($levels[$level])) { if (! isset($levels[$level])) {
throw new ConfigurationError( throw new ConfigurationError(
'Can\'t set logging level "%s". Logging level is not defined. Use one of %s.', 'Can\'t set logging level "%s". Logging level is invalid. Use one of %s.',
$level, $level,
implode(', ', array_keys($levels)) implode(', ', array_keys($levels))
); );
} }
$this->level = $levels[$level]; $this->level = $levels[$level];
} }
} else {
$this->level = static::ERROR; return $this;
} }
if (strtolower($config->get('log', 'syslog')) !== 'none') { /**
$this->writer = $this->createWriter($config); * Register the given message as config error
*
* Config errors are logged every time a log message is being logged.
*
* @param mixed $arg,... A string, exception or format-string + substitutions
*
* @return $this
*/
public function registerConfigError()
{
if (func_num_args() > 0) {
$this->configErrors[] = static::formatMessage(func_get_args());
} }
return $this;
} }
/** /**
@ -156,6 +195,10 @@ class Logger
public function log($level, $message) public function log($level, $message)
{ {
if ($this->writer !== null && $this->level <= $level) { if ($this->writer !== null && $this->level <= $level) {
foreach ($this->configErrors as $error_message) {
$this->writer->log(static::ERROR, $error_message);
}
$this->writer->log($level, $message); $this->writer->log($level, $message);
} }
} }

View File

@ -67,6 +67,6 @@ class SyslogWriter extends LogWriter
public function log($level, $message) public function log($level, $message)
{ {
openlog($this->ident, LOG_PID, $this->facility); openlog($this->ident, LOG_PID, $this->facility);
syslog(static::$severityMap[$level], $message); syslog(static::$severityMap[$level], str_replace("\n", ' ', $message));
} }
} }

View File

@ -12,7 +12,6 @@ use Icinga\Exception\ConfigurationError;
use Icinga\Exception\SystemPermissionException; use Icinga\Exception\SystemPermissionException;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;
use Icinga\Exception\NotFoundError;
/** /**
* Module manager that handles detecting, enabling and disabling of modules * Module manager that handles detecting, enabling and disabling of modules
@ -102,6 +101,16 @@ class Manager
*/ */
private function detectEnabledModules() private function detectEnabledModules()
{ {
if (! file_exists($parent = dirname($this->enableDir))) {
return;
}
if (! is_readable($parent)) {
throw new NotReadableError(
'Cannot read enabled modules. Module directory\'s parent directory "%s" is not readable',
$parent
);
}
if (! file_exists($this->enableDir)) { if (! file_exists($this->enableDir)) {
return; return;
} }
@ -199,7 +208,6 @@ class Manager
* *
* @return $this * @return $this
* @throws ConfigurationError When trying to enable a module that is not installed * @throws ConfigurationError When trying to enable a module that is not installed
* @throws NotFoundError In case the "enabledModules" directory does not exist
* @throws SystemPermissionException When insufficient permissions for the application exist * @throws SystemPermissionException When insufficient permissions for the application exist
*/ */
public function enableModule($name) public function enableModule($name)
@ -218,14 +226,15 @@ class Manager
if (! is_dir($this->enableDir) && !@mkdir($this->enableDir, 02770, true)) { if (! is_dir($this->enableDir) && !@mkdir($this->enableDir, 02770, true)) {
$error = error_get_last(); $error = error_get_last();
throw new SystemPermissionException( throw new SystemPermissionException(
'Failed to create enabledModule directory "%s" (%s)', 'Failed to create enabledModules directory "%s" (%s)',
$this->enableDir, $this->enableDir,
$error['message'] $error['message']
); );
} elseif (! is_writable($this->enableDir)) { } elseif (! is_writable($this->enableDir)) {
throw new SystemPermissionException( throw new SystemPermissionException(
'Cannot enable module "%s". Insufficient system permissions for enabling modules.', 'Cannot enable module "%s". Check the permissions for the enabledModules directory: %s',
$name $name,
$this->enableDir
); );
} }
@ -237,10 +246,11 @@ class Manager
$error = error_get_last(); $error = error_get_last();
if (strstr($error["message"], "File exists") === false) { if (strstr($error["message"], "File exists") === false) {
throw new SystemPermissionException( throw new SystemPermissionException(
'Could not enable module "%s" due to file system errors. ' 'Cannot enable module "%s" at %s due to file system errors. '
. 'Please check path and mounting points because this is not a permission error. ' . 'Please check path and mounting points because this is not a permission error. '
. 'Primary error was: %s', . 'Primary error was: %s',
$name, $name,
$this->enableDir,
$error['message'] $error['message']
); );
} }
@ -259,32 +269,37 @@ class Manager
* @return $this * @return $this
* *
* @throws ConfigurationError When the module is not installed or it's not a symlink * @throws ConfigurationError When the module is not installed or it's not a symlink
* @throws SystemPermissionException When the module can't be disabled * @throws SystemPermissionException When insufficient permissions for the application exist
*/ */
public function disableModule($name) public function disableModule($name)
{ {
if (! $this->hasEnabled($name)) { if (! $this->hasEnabled($name)) {
return $this; return $this;
} }
if (! is_writable($this->enableDir)) { if (! is_writable($this->enableDir)) {
throw new SystemPermissionException( throw new SystemPermissionException(
'Could not disable module. Module path is not writable.' 'Cannot disable module "%s". Check the permissions for the enabledModules directory: %s',
$name,
$this->enableDir
); );
} }
$link = $this->enableDir . DIRECTORY_SEPARATOR . $name; $link = $this->enableDir . DIRECTORY_SEPARATOR . $name;
if (! file_exists($link)) { if (! file_exists($link)) {
throw new ConfigurationError( throw new ConfigurationError(
'Could not disable module. The module %s was not found.', 'Cannot disable module "%s". Module is not installed.',
$name $name
); );
} }
if (! is_link($link)) { if (! is_link($link)) {
throw new ConfigurationError( throw new ConfigurationError(
'Could not disable module. The module "%s" is not a symlink. ' 'Cannot disable module %s at %s. '
. 'It looks like you have installed this module manually and moved it to your module folder. ' . 'It looks like you have installed this module manually and moved it to your module folder. '
. 'In order to dynamically enable and disable modules, you have to create a symlink to ' . 'In order to dynamically enable and disable modules, you have to create a symlink to '
. 'the enabled_modules folder.', . 'the enabledModules folder.',
$name $name,
$this->enableDir
); );
} }
@ -292,10 +307,11 @@ class Manager
if (! @unlink($link)) { if (! @unlink($link)) {
$error = error_get_last(); $error = error_get_last();
throw new SystemPermissionException( throw new SystemPermissionException(
'Could not disable module "%s" due to file system errors. ' 'Cannot enable module "%s" at %s due to file system errors. '
. 'Please check path and mounting points because this is not a permission error. ' . 'Please check path and mounting points because this is not a permission error. '
. 'Primary error was: %s', . 'Primary error was: %s',
$name, $name,
$this->enableDir,
$error['message'] $error['message']
); );
} }

View File

@ -1,20 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Data;
/**
* Interface for browsing data
*/
interface Browsable
{
/**
* Paginate data
*
* @param int $itemsPerPage Number of items per page
* @param int $pageNumber Current page number
*
* @return Zend_Paginator
*/
public function paginate($itemsPerPage = null, $pageNumber = null);
}

View File

@ -5,4 +5,4 @@ namespace Icinga\Data;
use Countable; use Countable;
interface QueryInterface extends Browsable, Fetchable, Filterable, Limitable, Sortable, Countable {}; interface QueryInterface extends Fetchable, Filterable, Limitable, Sortable, Countable {};

View File

@ -3,14 +3,12 @@
namespace Icinga\Data; namespace Icinga\Data;
use Icinga\Application\Icinga; use ArrayIterator;
use IteratorAggregate;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Web\Paginator\Adapter\QueryAdapter;
use Zend_Paginator;
use Exception;
use Icinga\Exception\IcingaException; use Icinga\Exception\IcingaException;
class SimpleQuery implements QueryInterface, Queryable class SimpleQuery implements QueryInterface, Queryable, IteratorAggregate
{ {
/** /**
* Query data source * Query data source
@ -91,6 +89,16 @@ class SimpleQuery implements QueryInterface, Queryable
*/ */
protected function init() {} protected function init() {}
/**
* Return a iterable for this query's result
*
* @return ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->fetchAll());
}
/** /**
* Get the data source * Get the data source
* *
@ -319,35 +327,6 @@ class SimpleQuery implements QueryInterface, Queryable
return $this->limitOffset; return $this->limitOffset;
} }
/**
* Paginate data
*
* Auto-detects pagination parameters from request when unset
*
* @param int $itemsPerPage Number of items per page
* @param int $pageNumber Current page number
*
* @return Zend_Paginator
*/
public function paginate($itemsPerPage = null, $pageNumber = null)
{
if ($itemsPerPage === null || $pageNumber === null) {
// Detect parameters from request
$request = Icinga::app()->getFrontController()->getRequest();
if ($itemsPerPage === null) {
$itemsPerPage = $request->getParam('limit', 25);
}
if ($pageNumber === null) {
$pageNumber = $request->getParam('page', 0);
}
}
$this->limit($itemsPerPage, $pageNumber * $itemsPerPage);
$paginator = new Zend_Paginator(new QueryAdapter($this));
$paginator->setItemCountPerPage($itemsPerPage);
$paginator->setCurrentPageNumber($pageNumber);
return $paginator;
}
/** /**
* Retrieve an array containing all rows of the result set * Retrieve an array containing all rows of the result set
* *

View File

@ -3,15 +3,13 @@
namespace Icinga\File; namespace Icinga\File;
use Icinga\Data\Browsable;
class Csv class Csv
{ {
protected $query; protected $query;
protected function __construct() {} protected function __construct() {}
public static function fromQuery(Browsable $query) public static function fromQuery($query)
{ {
$csv = new Csv(); $csv = new Csv();
$csv->query = $query; $csv->query = $query;

View File

@ -26,6 +26,13 @@ class FileReader implements Selectable, Countable
*/ */
protected $filename; protected $filename;
/**
* Cache for static::count()
*
* @var int
*/
protected $count = null;
/** /**
* Create a new reader * Create a new reader
* *
@ -51,7 +58,7 @@ class FileReader implements Selectable, Countable
*/ */
public function iterate() public function iterate()
{ {
return new FileIterator($this->filename, $this->fields); return new LogFileIterator($this->filename, $this->fields);
} }
/** /**
@ -71,7 +78,10 @@ class FileReader implements Selectable, Countable
*/ */
public function count() public function count()
{ {
return iterator_count($this->iterate()); if ($this->count === null) {
$this->count = iterator_count($this->iterate());
}
return $this->count;
} }
/** /**

View File

@ -0,0 +1,155 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Protocol\File;
use Icinga\Exception\IcingaException;
use SplFileObject;
use Iterator;
/**
* Iterate over a log file, yielding the regex fields of the log messages
*/
class LogFileIterator implements Iterator
{
/**
* Log file
*
* @var SplFileObject
*/
protected $file;
/**
* A PCRE string with the fields to extract
* from the log messages as named subpatterns
*
* @var string
*/
protected $fields;
/**
* Value for static::current()
*
* @var string
*/
protected $current;
/**
* Index for static::key()
*
* @var int
*/
protected $index;
/**
* Value for static::valid()
*
* @var boolean
*/
protected $valid;
/**
* @var string
*/
protected $next = null;
/**
* @param string $filename The log file's name
* @param string $fields A PCRE string with the fields to extract
* from the log messages as named subpatterns
*/
public function __construct($filename, $fields)
{
$this->file = new SplFileObject($filename);
$this->file->setFlags(
SplFileObject::DROP_NEW_LINE |
SplFileObject::READ_AHEAD
);
$this->fields = $fields;
}
public function rewind()
{
$this->file->rewind();
$this->index = 0;
$this->nextMessage();
}
public function next()
{
$this->file->next();
++$this->index;
$this->nextMessage();
}
/**
* @return string
*/
public function current()
{
return $this->current;
}
/**
* @return int
*/
public function key()
{
return $this->index;
}
/**
* @return boolean
*/
public function valid()
{
return $this->valid;
}
protected function nextMessage()
{
$message = $this->next === null ? array() : array($this->next);
$this->valid = null;
while ($this->file->valid()) {
if (false === ($res = preg_match(
$this->fields, $current = $this->file->current()
))) {
throw new IcingaException('Failed at preg_match()');
}
if (empty($message)) {
if ($res === 1) {
$message[] = $current;
}
} else if ($res === 1) {
$this->next = $current;
$this->valid = true;
break;
} else {
$message[] = $current;
}
$this->file->next();
}
if ($this->valid === null) {
$this->next = null;
$this->valid = ! empty($message);
}
if ($this->valid) {
while (! empty($message)) {
$matches = array();
if (false === ($res = preg_match(
$this->fields, implode(PHP_EOL, $message), $matches
))) {
throw new IcingaException('Failed at preg_match()');
}
if ($res === 1) {
$this->current = $matches;
return;
}
array_pop($message);
}
$this->valid = false;
}
}
}

View File

@ -413,30 +413,30 @@ class User
/** /**
* Whether the user has a given permission * Whether the user has a given permission
* *
* @param string $permission * @param string $requiredPermission
* *
* @return bool * @return bool
*/ */
public function can($permission) public function can($requiredPermission)
{ {
if (isset($this->permissions['*']) || isset($this->permissions[$permission])) { if (isset($this->permissions['*']) || isset($this->permissions[$requiredPermission])) {
return true; return true;
} }
// If the permission to check contains a wildcard, grant the permission if any permit related to the permission // If the permission to check contains a wildcard, grant the permission if any permit related to the permission
// matches // matches
$any = strpos($permission, '*'); $any = strpos($requiredPermission, '*');
foreach ($this->permissions as $permitted) { foreach ($this->permissions as $grantedPermission) {
if ($any !== false) { if ($any !== false && strpos($grantedPermission, '*') === false) {
$wildcard = $any; $wildcard = $any;
} else { } else {
// If the permit contains a wildcard, grant the permission if it's related to the permit // If the permit contains a wildcard, grant the permission if it's related to the permit
$wildcard = strpos($permitted, '*'); $wildcard = strpos($grantedPermission, '*');
} }
if ($wildcard !== false) { if ($wildcard !== false) {
if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { if (substr($requiredPermission, 0, $wildcard) === substr($grantedPermission, 0, $wildcard)) {
return true; return true;
} }
} elseif ($permission === $permitted) { } elseif ($requiredPermission === $grantedPermission) {
return true; return true;
} }
} }

View File

@ -3,7 +3,13 @@
namespace Icinga\Web; namespace Icinga\Web;
use Zend_Paginator;
use Icinga\Data\Sortable;
use Icinga\Data\QueryInterface;
use Icinga\Web\Paginator\Adapter\QueryAdapter;
use Icinga\Web\Controller\ModuleActionController; use Icinga\Web\Controller\ModuleActionController;
use Icinga\Web\Widget\Limiter;
use Icinga\Web\Widget\SortBox;
/** /**
* This is the controller all modules should inherit from * This is the controller all modules should inherit from
@ -12,4 +18,130 @@ use Icinga\Web\Controller\ModuleActionController;
*/ */
class Controller extends ModuleActionController class Controller extends ModuleActionController
{ {
/**
* @see ActionController::init
*/
public function init()
{
parent::init();
$this->handleSortControlSubmit();
}
/**
* Check whether the sort control has been submitted and redirect using GET parameters
*/
protected function handleSortControlSubmit()
{
$request = $this->getRequest();
if (! $request->isPost()) {
return;
}
if (($sort = $request->getPost('sort'))) {
$url = Url::fromRequest();
$url->setParam('sort', $sort);
if (($dir = $request->getPost('dir'))) {
$url->setParam('dir', $dir);
} else {
$url->removeParam('dir');
}
$this->redirectNow($url);
}
}
/**
* Create a SortBox widget and apply its sort rules on the given query
*
* The widget is set on the `sortBox' view property only if the current view has not been requested as compact
*
* @param array $columns An array containing the sort columns, with the
* submit value as the key and the label as the value
* @param Sortable $query Query to apply the user chosen sort rules on
*
* @return $this
*/
protected function setupSortControl(array $columns, Sortable $query = null)
{
$request = $this->getRequest();
$sortBox = SortBox::create('sortbox-' . $request->getActionName(), $columns);
$sortBox->setRequest($request);
if ($query) {
$sortBox->setQuery($query);
$sortBox->handleRequest($request);
}
if (! $this->view->compact) {
$this->view->sortBox = $sortBox;
}
return $this;
}
/**
* Create a Limiter widget at the `limiter' view property
*
* In case the current view has been requested as compact this method does nothing.
*
* @param int $itemsPerPage Default number of items per page
*
* @return $this
*/
protected function setupLimitControl($itemsPerPage = 25)
{
if (! $this->view->compact) {
$this->view->limiter = new Limiter();
$this->view->limiter->setDefaultLimit($itemsPerPage);
}
return $this;
}
/**
* Apply the given page limit and number on the given query and setup a paginator for it
*
* The $itemsPerPage and $pageNumber parameters are only applied if not available in the current request.
* The paginator is set on the `paginator' view property only if the current view has not been requested as compact.
*
* @param QueryInterface $query The query to create a paginator for
* @param int $itemsPerPage Default number of items per page
* @param int $pageNumber Default page number
*
* @return $this
*/
protected function setupPaginationControl(QueryInterface $query, $itemsPerPage = 25, $pageNumber = 0)
{
$request = $this->getRequest();
$limit = $request->getParam('limit', $itemsPerPage);
$page = $request->getParam('page', $pageNumber);
$query->limit($limit, $page * $limit);
if (! $this->view->compact) {
$paginator = new Zend_Paginator(new QueryAdapter($query));
$paginator->setItemCountPerPage($limit);
$paginator->setCurrentPageNumber($page);
$this->view->paginator = $paginator;
}
return $this;
}
/**
* Set the view property `filterEditor' to the given FilterEditor
*
* In case the current view has been requested as compact this method does nothing.
*
* @param Form $editor The FilterEditor
*
* @return $this
*/
protected function setupFilterControl($editor)
{
if (! $this->view->compact) {
$this->view->filterEditor = $editor;
}
return $this;
}
} }

View File

@ -87,6 +87,7 @@ class ActionController extends Zend_Controller_Action
$this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe'); $this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe');
$this->_helper->layout()->moduleName = false; $this->_helper->layout()->moduleName = false;
$this->view->compact = $request->getParam('view') === 'compact';
if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) { if ($this->rerenderLayout = $request->getUrl()->shift('renderLayout')) {
$this->xhrLayout = 'body'; $this->xhrLayout = 'body';
} }
@ -315,13 +316,18 @@ class ActionController extends Zend_Controller_Action
if ($redirect !== null) { if ($redirect !== null) {
$login->setParam('redirect', '__SELF__'); $login->setParam('redirect', '__SELF__');
} }
$this->_response->setHttpResponseCode(403); $this->_response->setHttpResponseCode(403);
} elseif ($redirect !== null) { } elseif ($redirect !== null) {
if (! $redirect instanceof Url) { if (! $redirect instanceof Url) {
$redirect = Url::fromPath($redirect); $redirect = Url::fromPath($redirect);
} }
$login->setParam('redirect', $redirect->getRelativeUrl());
if (($relativeUrl = $redirect->getRelativeUrl())) {
$login->setParam('redirect', $relativeUrl);
} }
}
$this->rerenderLayout()->redirectNow($login); $this->rerenderLayout()->redirectNow($login);
} }

View File

@ -38,6 +38,28 @@ class Form extends Zend_Form
*/ */
const DEFAULT_SUFFIX = '_default'; const DEFAULT_SUFFIX = '_default';
/**
* The type of the notification for the error
*/
const NOTIFICATION_ERROR = 0;
/**
* The type of the notification for the warning
*/
const NOTIFICATION_WARNING = 2;
/**
* The type of the notification for the info
*/
const NOTIFICATION_INFO = 4;
/**
* The notifications of the form
*
* @var array
*/
protected $notifications = array();
/** /**
* Whether this form has been created * Whether this form has been created
* *
@ -1009,6 +1031,7 @@ class Form extends Zend_Form
} }
$this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true)) $this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
->addDecorator('FormNotifications')
->addDecorator('FormDescriptions') ->addDecorator('FormDescriptions')
->addDecorator('FormElements') ->addDecorator('FormElements')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form')) //->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
@ -1208,4 +1231,57 @@ class Form extends Zend_Form
throw new SecurityException('No permission for %s', $permission); throw new SecurityException('No permission for %s', $permission);
} }
} }
/**
* Return all form notifications
*
* @return array
*/
public function getNotifications()
{
return $this->notifications;
}
/**
* Add a typed message to the notifications
*
* @param string $message The message which would be displayed to the user
*
* @param int $type The type of the message notification
*/
public function addNotification($message, $type = self::NOTIFICATION_ERROR)
{
$this->notifications[$message] = $type;
$this->markAsError();
}
/**
* Add a error message to notifications
*
* @param string $message
*/
public function error($message)
{
$this->addNotification($message, $type = self::NOTIFICATION_ERROR);
}
/**
* Add a warning message to notifications
*
* @param string $message
*/
public function warning($message)
{
$this->addNotification($message, $type = self::NOTIFICATION_WARNING);
}
/**
* Add a info message to notifications
*
* @param string $message
*/
public function info($message)
{
$this->addNotification($message, $type = self::NOTIFICATION_INFO);
}
} }

View File

@ -0,0 +1,95 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Form\Decorator;
use Zend_Form_Decorator_Abstract;
use Icinga\Web\Form as Form;
/**
* Decorator to add a list of notifications at the top of a form
*/
class FormNotifications extends Zend_Form_Decorator_Abstract
{
/**
* Render form descriptions
*
* @param string $content The html rendered so far
*
* @return string The updated html
*/
public function render($content = '')
{
$form = $this->getElement();
if (! $form instanceof Form) {
return $content;
}
$view = $form->getView();
if ($view === null) {
return $content;
}
$notifications = $this->recurseForm($form);
if (empty($notifications)) {
return $content;
}
$html = '<ul class="form-notifications">';
asort($notifications);
foreach ($notifications as $message => $type) {
$html .= '<li class="'.self::getNotificationTypeName($type).'">' . $view->escape($message) . '</li>';
}
switch ($this->getPlacement()) {
case self::APPEND:
return $content . $html . '</ul>';
case self::PREPEND:
return $html . '</ul>' . $content;
}
}
/**
* Recurse the given form and return the notifications for it and all of its subforms
*
* @param Form $form The form to recurse
*
* @return array
*/
protected function recurseForm(Form $form)
{
$notifications = $form->getNotifications();
foreach ($form->getSubForms() as $subForm) {
$notifications = $notifications + $this->recurseForm($subForm);
}
return $notifications;
}
/**
* Get the readable type name of the notification
*
* @param $type Type of the message
*
* @return string
*/
public static function getNotificationTypeName($type)
{
switch ($type) {
case Form::NOTIFICATION_ERROR:
return 'error';
break;
case Form::NOTIFICATION_WARNING:
return 'warning';
break;
case Form::NOTIFICATION_INFO:
return 'info';
break;
default:
return 'unknown';
}
}
}

View File

@ -117,7 +117,11 @@ class Menu implements RecursiveIterator
foreach ($props as $key => $value) { foreach ($props as $key => $value) {
$method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key)))); $method = 'set' . implode('', array_map('ucfirst', explode('_', strtolower($key))));
if ($key === 'renderer') { if ($key === 'renderer') {
$class = '\Icinga\Web\Menu\\' . $value; $value = '\\' . ltrim($value, '\\');
if (class_exists($value)) {
$value = new $value;
} else {
$class = '\Icinga\Web\Menu' . $value;
if (!class_exists($class)) { if (!class_exists($class)) {
throw new ConfigurationError( throw new ConfigurationError(
sprintf('ItemRenderer with class "%s" does not exist', $class) sprintf('ItemRenderer with class "%s" does not exist', $class)
@ -125,6 +129,7 @@ class Menu implements RecursiveIterator
} }
$value = new $class; $value = new $class;
} }
}
if (method_exists($this, $method)) { if (method_exists($this, $method)) {
$this->{$method}($value); $this->{$method}($value);
} else { } else {
@ -229,7 +234,8 @@ class Menu implements RecursiveIterator
$section = $this->add(t('System'), array( $section = $this->add(t('System'), array(
'icon' => 'wrench', 'icon' => 'wrench',
'priority' => 200 'priority' => 200,
'renderer' => 'ProblemMenuItemRenderer'
)); ));
$section->add(t('Configuration'), array( $section->add(t('Configuration'), array(
'url' => 'config', 'url' => 'config',
@ -464,6 +470,26 @@ class Menu implements RecursiveIterator
return $this->permission; return $this->permission;
} }
/**
* Get parent menu
*
* @return \Icinga\Web\Menu
*/
public function getParent()
{
return $this->parent;
}
/**
* Get submenus
*
* @return array
*/
public function getSubMenus()
{
return $this->subMenus;
}
/** /**
* Set permission a user is required to have granted to display the menu item * Set permission a user is required to have granted to display the menu item
* *

View File

@ -9,15 +9,9 @@ use Icinga\Web\Url;
/** /**
* A menu item with a link that surpasses the regular navigation link behavior * A menu item with a link that surpasses the regular navigation link behavior
*/ */
class ForeignMenuItemRenderer implements MenuItemRenderer { class ForeignMenuItemRenderer extends MenuItemRenderer
public function render(Menu $menu)
{ {
return sprintf( protected $attributes = array(
'<a href="%s" target="_self">%s%s<span></span></a>', 'target' => '_self'
$menu->getUrl() ?: '#',
$menu->getIcon() ? '<img aria-hidden="true" src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
htmlspecialchars($menu->getTitle())
); );
} }
}

View File

@ -3,11 +3,108 @@
namespace Icinga\Web\Menu; namespace Icinga\Web\Menu;
use Icinga\Application\Icinga;
use Icinga\Web\Menu; use Icinga\Web\Menu;
use Icinga\Web\Url;
use Icinga\Web\View;
/**
* Default MenuItemRenderer class
*/
class MenuItemRenderer
{
/**
* Contains <a> element specific attributes
*
* @var array
*/
protected $attributes = array();
/**
* View
*
* @var View|null
*/
protected $view;
/**
* Set the view
*
* @param View $view
*
* @return $this
*/
public function setView(View $view)
{
$this->view = $view;
return $this;
}
/**
* Get the view
*
* @return View
*/
public function getView()
{
if ($this->view === null) {
$this->view = Icinga::app()->getViewRenderer()->view;
}
return $this->view;
}
/** /**
* Renders the html content of a single menu item * Renders the html content of a single menu item
*
* @param Menu $menu
*
* @return string
*/ */
interface MenuItemRenderer { public function render(Menu $menu)
public function render(Menu $menu); {
return $this->createLink($menu);
}
/**
* Creates a menu item link element
*
* @param Menu $menu
*
* @return string
*/
public function createLink(Menu $menu)
{
if ($menu->getIcon() && strpos($menu->getIcon(), '.') === false) {
return sprintf(
'<a href="%s"%s><i aria-hidden="true" class="icon-%s"></i>%s</a>',
$menu->getUrl() ? : '#',
$this->getAttributes(),
$menu->getIcon(),
$this->getView()->escape($menu->getTitle())
);
}
return sprintf(
'<a href="%s"%s>%s%s<span></span></a>',
$menu->getUrl() ? : '#',
$this->getAttributes(),
$menu->getIcon() ? '<img aria-hidden="true" src="' . Url::fromPath($menu->getIcon()) . '" class="icon" /> ' : '',
$this->getView()->escape($menu->getTitle())
);
}
/**
* Returns <a> element specific attributes if present
*
* @return string
*/
protected function getAttributes()
{
$attributes = '';
$view = $this->getView();
foreach ($this->attributes as $attribute => $value) {
$attributes .= ' ' . $view->escape($attribute) . '="' . $view->escape($value) . '"';
}
return $attributes;
}
} }

View File

@ -3,10 +3,62 @@
namespace Icinga\Web\Menu; namespace Icinga\Web\Menu;
class ProblemMenuItemRenderer extends MonitoringMenuItemRenderer use Icinga\Web\Menu;
class ProblemMenuItemRenderer extends MenuItemRenderer
{ {
protected $columns = array( /**
'hosts_down_unhandled', * Set of summarized problems from submenus
'services_critical_unhandled' *
* @var array
*/
protected $summary = array();
/**
* Renders the html content of a single menu item and summarizes submenu problems
*
* @param Menu $menu
*
* @return string
*/
public function render(Menu $menu)
{
if ($menu->getParent() !== null && $menu->hasSubMenus()) {
/** @var $submenu Menu */
foreach ($menu->getSubMenus() as $submenu) {
$renderer = $submenu->getRenderer();
if (method_exists($renderer, 'getSummary')) {
if ($renderer->getSummary() !== null) {
$this->summary[] = $renderer->getSummary();
}
}
}
}
return $this->getBadge() . $this->createLink($menu);
}
/**
* Get the problem badge
*
* @return string
*/
protected function getBadge()
{
if (count($this->summary) > 0) {
$problems = 0;
$titles = array();
foreach ($this->summary as $summary) {
$problems += $summary['problems'];
$titles[] = $summary['title'];
}
return sprintf(
'<div title="%s" class="badge-container"><span class="badge badge-critical">%s</span></div>',
implode(', ', $titles),
$problems
); );
} }
return '';
}
}

View File

@ -4,6 +4,7 @@
namespace Icinga\Web; namespace Icinga\Web;
use Exception; use Exception;
use Icinga\Web\Menu\MenuItemRenderer;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
use Icinga\Application\Logger; use Icinga\Application\Logger;
use Icinga\Web\Menu\PermittedMenuItemFilter; use Icinga\Web\Menu\PermittedMenuItemFilter;
@ -32,6 +33,11 @@ class MenuRenderer extends RecursiveIteratorIterator
*/ */
protected $useCustomRenderer = false; protected $useCustomRenderer = false;
/**
* @var MenuItemRenderer
*/
protected $defaultRenderer;
/** /**
* Create a new MenuRenderer * Create a new MenuRenderer
* *
@ -45,6 +51,7 @@ class MenuRenderer extends RecursiveIteratorIterator
} else { } else {
$this->url = Url::fromPath($url); $this->url = Url::fromPath($url);
} }
$this->defaultRenderer = new MenuItemRenderer();
parent::__construct(new PermittedMenuItemFilter($menu), RecursiveIteratorIterator::CHILD_FIRST); parent::__construct(new PermittedMenuItemFilter($menu), RecursiveIteratorIterator::CHILD_FIRST);
} }
@ -114,22 +121,8 @@ class MenuRenderer extends RecursiveIteratorIterator
Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage()); Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage());
} }
} }
if ($child->getIcon() && strpos($child->getIcon(), '.') === false) {
return sprintf( return $this->defaultRenderer->render($child);
'<a href="%s"><i aria-hidden="true" class="icon-%s"></i>%s</a>',
$child->getUrl() ?: '#',
$child->getIcon(),
htmlspecialchars($child->getTitle())
);
}
return sprintf(
'<a href="%s">%s%s</a>',
$child->getUrl() ?: '#',
$child->getIcon()
? '<img aria-hidden="true" src="' . Url::fromPath($child->getIcon()) . '" class="icon" /> '
: '',
htmlspecialchars($child->getTitle())
);
} }
/** /**

View File

@ -77,7 +77,7 @@ class PhpSession extends Session
} }
} }
$sessionSavePath = session_save_path(); $sessionSavePath = session_save_path() ?: sys_get_temp_dir();
if (session_module_name() === 'files' && !is_writable($sessionSavePath)) { if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable."); throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable.");
} }

View File

@ -26,7 +26,8 @@ class StyleSheet
'css/icinga/pagination.less', 'css/icinga/pagination.less',
'css/icinga/monitoring-colors.less', 'css/icinga/monitoring-colors.less',
'css/icinga/selection-toolbar.less', 'css/icinga/selection-toolbar.less',
'css/icinga/login.less' 'css/icinga/login.less',
'css/icinga/controls.less'
); );
public static function compileForPdf() public static function compileForPdf()

View File

@ -128,6 +128,7 @@ class HistoryColorGrid extends AbstractWidget {
'aria-label="' . $entry['caption'] . '" ' . 'aria-label="' . $entry['caption'] . '" ' .
'title="' . $entry['caption'] . '" ' . 'title="' . $entry['caption'] . '" ' .
'href="' . $entry['url'] . '" ' . 'href="' . $entry['url'] . '" ' .
'data-tooltip-delay="0"' .
'></a>'; '></a>';
} else { } else {
return '<span ' . return '<span ' .

View File

@ -6,6 +6,7 @@ namespace Icinga\Web\Widget;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression; use Icinga\Data\Filter\FilterExpression;
use Icinga\Data\Filter\FilterChain; use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterOr;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
@ -39,6 +40,8 @@ class FilterEditor extends AbstractWidget
protected $ignoreParams = array(); protected $ignoreParams = array();
protected $searchColumns = null;
/** /**
* @var string * @var string
*/ */
@ -73,6 +76,12 @@ class FilterEditor extends AbstractWidget
return $this->filter; return $this->filter;
} }
public function setSearchColumns(array $searchColumns)
{
$this->searchColumns = $searchColumns;
return $this;
}
public function setUrl($url) public function setUrl($url)
{ {
$this->url = $url; $this->url = $url;
@ -147,6 +156,26 @@ class FilterEditor extends AbstractWidget
return $filter; return $filter;
} }
protected function resetSearchColumns(Filter &$filter)
{
if ($filter->isChain()) {
$filters = &$filter->filters();
if (!($empty = empty($filters))) {
foreach ($filters as $k => &$f) {
if (false === $this->resetSearchColumns($f)) {
unset($filters[$k]);
}
}
}
return $empty || !empty($filters);
}
return $filter->isExpression() ? !(
in_array($filter->getColumn(), $this->searchColumns)
&&
$filter->getSign() === '='
) : true;
}
public function handleRequest($request) public function handleRequest($request)
{ {
$this->setUrl($request->getUrl()->without($this->ignoreParams)); $this->setUrl($request->getUrl()->without($this->ignoreParams));
@ -179,14 +208,15 @@ class FilterEditor extends AbstractWidget
$filter = $this->getFilter(); $filter = $this->getFilter();
if ($search !== null) { if ($search !== null) {
if ($this->searchColumns === null) {
if (strpos($search, '=') === false) { if (strpos($search, '=') === false) {
// TODO: Ask the view for (multiple) search columns // TODO: Ask the view for (multiple) search columns
switch($request->getActionName()) { switch($request->getActionName()) {
case 'services': case 'services':
$searchCol = 'service_description'; $searchCol = 'service';
break; break;
case 'hosts': case 'hosts':
$searchCol = 'host_name'; $searchCol = 'host';
break; break;
case 'hostgroups': case 'hostgroups':
$searchCol = 'hostgroup'; $searchCol = 'hostgroup';
@ -203,11 +233,23 @@ class FilterEditor extends AbstractWidget
} }
$search = ltrim($search); $search = ltrim($search);
$filter = $this->mergeRootExpression($filter, $searchCol, '=', "*$search*"); $filter = $this->mergeRootExpression($filter, $searchCol, '=', "*$search*");
} else { } else {
list($k, $v) = preg_split('/=/', $search); list($k, $v) = preg_split('/=/', $search);
$filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v)); $filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v));
} }
} else {
if (false === $this->resetSearchColumns($filter)) {
$filter = Filter::matchAll();
}
$filters = array();
$search = ltrim($search);
foreach ($this->searchColumns as $searchColumn) {
$filters[] = Filter::expression($searchColumn, '=', "*$search*");
}
$filter->andFilter(new FilterOr($filters));
}
$url = $this->url()->setQueryString( $url = $this->url()->setQueryString(
$filter->toQueryString() $filter->toQueryString()
)->addParams($preserve); )->addParams($preserve);
@ -649,7 +691,7 @@ class FilterEditor extends AbstractWidget
public function renderSearch() public function renderSearch()
{ {
$html = ' <form method="post" class="inline dontprint" action="' $html = ' <form method="post" class="search inline dontprint" action="'
. $this->preservedUrl() . $this->preservedUrl()
. '"><input type="text" name="q" style="width: 8em" class="search" value="" placeholder="' . '"><input type="text" name="q" style="width: 8em" class="search" value="" placeholder="'
. t('Search...') . t('Search...')
@ -678,20 +720,22 @@ class FilterEditor extends AbstractWidget
public function render() public function render()
{ {
if (! $this->preservedUrl()->getParam('modifyFilter')) { if (! $this->preservedUrl()->getParam('modifyFilter')) {
return $this->renderSearch() . $this->shorten($this->filter, 50); return '<div class="filter">' . $this->renderSearch() . $this->shorten($this->filter, 50) . '</div>';
} }
return $this->renderSearch() return '<div class="filter">'
. $this->renderSearch()
. '<form action="' . '<form action="'
. Url::fromRequest() . Url::fromRequest()
. '" class="filterEditor" method="POST">' . '" class="editor" method="POST">'
. '<ul class="tree widgetFilter"><li>' . '<ul class="tree"><li>'
. $this->renderFilter($this->filter) . $this->renderFilter($this->filter)
. '</li></ul>' . '</li></ul>'
. '<div style="float: right">' . '<div class="buttons">'
. '<input type="submit" name="submit" value="Apply" />' . '<input type="submit" name="submit" value="Apply" />'
. '<input type="submit" name="cancel" value="Cancel" />' . '<input type="submit" name="cancel" value="Cancel" />'
. '</div>' . '</div>'
. '</form>'; . '</form>'
. '</div>';
} }
protected function shorten($string, $length) protected function shorten($string, $length)

View File

@ -21,6 +21,8 @@ class Limiter extends AbstractWidget
private $pages; private $pages;
private $default;
public function setUrl(Url $url) public function setUrl(Url $url)
{ {
$this->url = $url; $this->url = $url;
@ -39,13 +41,19 @@ class Limiter extends AbstractWidget
return $this; return $this;
} }
public function setDefaultLimit($limit)
{
$this->default = $limit;
return $this;
}
public function render() public function render()
{ {
if ($this->url === null) { if ($this->url === null) {
$this->url = Url::fromRequest(); $this->url = Url::fromRequest();
} }
$currentLimit = (int) $this->url->getParam('limit', 25); // Default?? $currentLimit = (int) $this->url->getParam('limit', $this->default);
$availableLimits = array( $availableLimits = array(
10 => '10', 10 => '10',
25 => '25', 25 => '25',

View File

@ -3,21 +3,20 @@
namespace Icinga\Web\Widget; namespace Icinga\Web\Widget;
use Zend_Form_Element_Submit;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Request; use Icinga\Web\Request;
use Icinga\Web\Form\Decorator\ConditionalHidden; use Icinga\Data\Sortable;
use Icinga\Application\Icinga;
/** /**
* Sortbox widget * SortBox widget
* *
* The "SortBox" Widget allows you to create a generic sort input for sortable views. * The "SortBox" Widget allows you to create a generic sort input for sortable views. It automatically creates a form
* It automatically creates a form containing a select box with all sort options and a * containing a select box with all sort options and a dropbox with the sort direction. It also handles automatic
* dropbox with the sort direction. It also handles automatic submission of sorting changes and draws an additional * submission of sorting changes and draws an additional submit button when JavaScript is disabled.
* submit button when JavaScript is disabled.
* *
* The constructor takes an string for the component name ad an array containing the select options, where the key is * The constructor takes an string for the component name and an array containing the select options, where the key is
* the value to be submitted and the value is the label that will be shown. You then should call applyRequest in order * the value to be submitted and the value is the label that will be shown. You then should call setRequest in order
* to make sure the form is correctly populated when a request with a sort parameter is being made. * to make sure the form is correctly populated when a request with a sort parameter is being made.
* *
* Example: * Example:
@ -26,41 +25,44 @@ use Icinga\Web\Form\Decorator\ConditionalHidden;
* $this->getRequest()->getActionName(), * $this->getRequest()->getActionName(),
* $columns * $columns
* ); * );
* $this->view->sortControl->applyRequest($this->getRequest()); * $this->view->sortControl->setRequest($this->getRequest());
* </code></pre> * </code></pre>
* By default the sortBox uses the GET parameter 'sort' for the sorting key and 'dir' for the sorting direction
*
*/ */
class SortBox extends AbstractWidget class SortBox extends AbstractWidget
{ {
/** /**
* An array containing all sort columns with their associated labels * An array containing all sort columns with their associated labels
* *
* @var array * @var array
*/ */
private $sortFields; protected $sortFields;
/** /**
* The name of the form that will be created * The name of the form that will be created
* *
* @var string * @var string
*/ */
private $name; protected $name;
/** /**
* A request object used for initial form population * A request object used for initial form population
* *
* @var \Icinga\Web\Request * @var Request
*/ */
private $request; protected $request;
/**
* What to apply sort parameters on
*
* @var Sortable
*/
protected $query = null;
/** /**
* Create a SortBox with the entries from $sortFields * Create a SortBox with the entries from $sortFields
* *
* @param string $name The name of the sort form * @param string $name The name for the SortBox
* @param array $sortFields An array containing the columns and their labels to be displayed * @param array $sortFields An array containing the columns and their labels to be displayed in the SortBox
* in the sort select box
*/ */
public function __construct($name, array $sortFields) public function __construct($name, array $sortFields)
{ {
@ -69,13 +71,12 @@ class SortBox extends AbstractWidget
} }
/** /**
* Create a SortBox with the entries from $sortFields * Create a SortBox
* *
* @param string $name The name of the sort form * @param string $name The name for the SortBox
* @param array $sortFields An array containing the columns and their labels to be displayed * @param array $sortFields An array containing the columns and their labels to be displayed in the SortBox
* in the sort select box
* *
* @return static * @return SortBox
*/ */
public static function create($name, array $sortFields) public static function create($name, array $sortFields)
{ {
@ -89,67 +90,80 @@ class SortBox extends AbstractWidget
* *
* @return $this * @return $this
*/ */
public function applyRequest($request) public function setRequest($request)
{ {
$this->request = $request; $this->request = $request;
return $this; return $this;
} }
/** /**
* Create a submit button that is hidden via the ConditionalDecorator * @param Sortable $query
* in order to allow sorting changes to be submitted in a JavaScript-less environment
* *
* @return Zend_Form_Element_Submit The submit button that is hidden by default * @return $this
* @see ConditionalDecorator
*/ */
private function createFallbackSubmitButton() public function setQuery(Sortable $query)
{ {
$manualSubmitButton = new Zend_Form_Element_Submit( $this->query = $query;
array( return $this;
'name' => 'submit_' . $this->name, }
'label' => 'Sort',
'class' => '', public function handleRequest(Request $request = null)
'condition' => 0, {
'value' => '{{SUBMIT_ICON}}' if ($this->query !== null) {
) if ($request === null) {
); $request = Icinga::app()->getFrontController()->getRequest();
$manualSubmitButton->addDecorator(new ConditionalHidden()); }
$manualSubmitButton->setAttrib('addLabelPlaceholder', true); if ($sort = $request->getParam('sort')) {
return $manualSubmitButton; $this->query->order($sort, $request->getParam('dir'));
}
}
return $this;
} }
/** /**
* Renders this widget via the given view and returns the * Render this SortBox as HTML
* HTML as a string
* *
* @return string * @return string
*/ */
public function render() public function render()
{ {
$form = new Form(); $form = new Form();
$form->setAttrib('class', 'inline');
$form->setMethod('POST');
$form->setTokenDisabled(); $form->setTokenDisabled();
$form->setName($this->name); $form->setName($this->name);
$form->addElement('select', 'sort', array( $form->setAttrib('class', 'sort-control inline');
'label' => 'Sort By',
'multiOptions' => $this->sortFields, $form->addElement(
'style' => 'width: 12em', 'select',
'autosubmit' => true 'sort',
array(
'autosubmit' => true,
'label' => $this->view()->translate('Sort by'),
'multiOptions' => $this->sortFields
)
);
$form->getElement('sort')->setDecorators(array(
array('ViewHelper'),
array('Label')
)); ));
$form->addElement('select', 'dir', array( $form->addElement(
'select',
'dir',
array(
'autosubmit' => true,
'multiOptions' => array( 'multiOptions' => array(
'asc' => 'Asc', 'asc' => 'Asc',
'desc' => 'Desc', 'desc' => 'Desc',
), ),
'style' => 'width: 5em', 'decorators' => array(
'autosubmit' => true array('ViewHelper')
)); )
$sort = $form->getElement('sort')->setDecorators(array('ViewHelper')); )
$dir = $form->getElement('dir')->setDecorators(array('ViewHelper')); );
if ($this->request) { if ($this->request) {
$form->populate($this->request->getParams()); $form->populate($this->request->getParams());
} }
return $form; return $form;
} }
} }

View File

@ -24,7 +24,7 @@ class DashboardAction implements Tabextension
'dashboard', 'dashboard',
array( array(
'icon' => 'dashboard', 'icon' => 'dashboard',
'label' => 'Add To Dashboard', 'label' => t('Add To Dashboard'),
'url' => Url::fromPath('dashboard/new-dashlet'), 'url' => Url::fromPath('dashboard/new-dashlet'),
'urlParams' => array( 'urlParams' => array(
'url' => rawurlencode(Url::fromRequest()->getRelativeUrl()) 'url' => rawurlencode(Url::fromRequest()->getRelativeUrl())

View File

@ -22,7 +22,7 @@ class DashboardSettings implements Tabextension
'dashboard_add', 'dashboard_add',
array( array(
'icon' => 'img/icons/dashboard.png', 'icon' => 'img/icons/dashboard.png',
'label' => t('Add To Dashboard'), 'label' => t('Add New Pane Or Dashlet'),
'url' => Url::fromPath('dashboard/new-dashlet') 'url' => Url::fromPath('dashboard/new-dashlet')
) )
); );

View File

@ -49,7 +49,7 @@ EOT;
*/ */
private $closeTpl = <<< 'EOT' private $closeTpl = <<< 'EOT'
<li class="dropdown" style="float: right;"> <li class="dropdown" style="float: right;">
<a href="#" class="dropdown-toggle close-toggle">X</a> <a href="#" class="dropdown-toggle close-toggle"> <i aria-hidden="true" class="icon-cancel"></i> </a>
</li> </li>
EOT; EOT;

View File

@ -1,6 +1,7 @@
<div class="controls"></div> <div class="controls">
<?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs->showOnlyCloseButton(); ?> <?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs->showOnlyCloseButton(); ?>
<h1><?= $this->translate('Available documentations'); ?></h1> <h1><?= $this->translate('Available documentations'); ?></h1>
</div>
<div class="content"> <div class="content">
<ul> <ul>
<li><?= $this->qlink( <li><?= $this->qlink(

View File

@ -5,9 +5,9 @@ namespace Icinga\Module\Doc;
use Icinga\Module\Doc\Renderer\DocSectionRenderer; use Icinga\Module\Doc\Renderer\DocSectionRenderer;
use Icinga\Module\Doc\Renderer\DocTocRenderer; use Icinga\Module\Doc\Renderer\DocTocRenderer;
use Icinga\Web\Controller\ModuleActionController; use Icinga\Web\Controller;
class DocController extends ModuleActionController class DocController extends Controller
{ {
/** /**
* Render a chapter * Render a chapter

View File

@ -6,6 +6,7 @@ use Icinga\Chart\Unit\LinearUnit;
use Icinga\Chart\Unit\StaticAxis; use Icinga\Chart\Unit\StaticAxis;
use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Web\Widget\SelectBox; use Icinga\Module\Monitoring\Web\Widget\SelectBox;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Url; use Icinga\Web\Url;
class Monitoring_AlertsummaryController extends Controller class Monitoring_AlertsummaryController extends Controller
@ -44,7 +45,7 @@ class Monitoring_AlertsummaryController extends Controller
'label' => $this->translate('Alert Summary'), 'label' => $this->translate('Alert Summary'),
'url' => Url::fromRequest() 'url' => Url::fromRequest()
) )
)->activate('alertsummary'); )->extend(new DashboardAction())->activate('alertsummary');
$this->view->title = $this->translate('Alert Summary'); $this->view->title = $this->translate('Alert Summary');
$this->view->intervalBox = $this->createIntervalBox(); $this->view->intervalBox = $this->createIntervalBox();
@ -59,18 +60,20 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host', 'host_name',
'host_display_name', 'host_display_name',
'service', 'service_description',
'service_display_name', 'service_display_name',
'notification_output', 'notification_output',
'notification_contact', 'notification_contact_name',
'notification_start_time', 'notification_start_time',
'notification_state' 'notification_state'
) )
); );
$this->view->notifications = $query;
$this->view->notifications = $query->paginate(); $this->setupLimitControl();
$this->setupPaginationControl($this->view->notifications);
} }
/** /**
@ -85,12 +88,7 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host', 'notification_start_time'
'service',
'notification_output',
'notification_contact',
'notification_start_time',
'notification_state'
) )
); );
@ -138,12 +136,7 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host', 'notification_start_time'
'service',
'notification_output',
'notification_contact',
'notification_start_time',
'notification_state'
) )
); );
@ -210,12 +203,7 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host', 'notification_start_time'
'service',
'notification_output',
'notification_contact',
'notification_start_time',
'notification_state'
) )
); );
@ -263,20 +251,9 @@ class Monitoring_AlertsummaryController extends Controller
$interval = $this->getInterval(); $interval = $this->getInterval();
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'EventHistory', 'eventHistory',
array( array(
'host_name', 'timestamp'
'service_description',
'object_type',
'timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type',
'host',
'service',
'service_host_name'
) )
); );
@ -338,11 +315,7 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host',
'service',
'notification_object_id', 'notification_object_id',
'notification_output',
'notification_contact',
'notification_start_time', 'notification_start_time',
'notification_state', 'notification_state',
'acknowledgement_entry_time' 'acknowledgement_entry_time'
@ -507,12 +480,12 @@ class Monitoring_AlertsummaryController extends Controller
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'notification', 'notification',
array( array(
'host', 'host_name',
'host_display_name', 'host_display_name',
'service', 'service_description',
'service_display_name', 'service_display_name',
'notification_output', 'notification_output',
'notification_contact', 'notification_contact_name',
'notification_start_time', 'notification_start_time',
'notification_state' 'notification_state'
) )
@ -520,7 +493,7 @@ class Monitoring_AlertsummaryController extends Controller
$query->order('notification_start_time', 'desc'); $query->order('notification_start_time', 'desc');
return $query->paginate(5); return $query->limit(5);
} }
/** /**

View File

@ -16,11 +16,6 @@ use Icinga\Chart\Unit\LinearUnit;
class Monitoring_ChartController extends Controller class Monitoring_ChartController extends Controller
{ {
public function init()
{
$this->view->compact = $this->_request->getParam('view') === 'compact';
}
private function drawLogChart1() private function drawLogChart1()
{ {
$chart = new GridChart(); $chart = new GridChart();

View File

@ -0,0 +1,100 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction;
/**
* Display detailed information about a comment
*/
class Monitoring_CommentController extends Controller
{
/**
* The fetched comment
*
* @var stdClass
*/
protected $comment;
/**
* Fetch the first comment with the given id and add tabs
*
* @throws Zend_Controller_Action_Exception
*/
public function init()
{
$commentId = $this->params->get('comment_id');
$this->comment = $this->backend->select()->from('comment', array(
'id' => 'comment_internal_id',
'objecttype' => 'comment_objecttype',
'comment' => 'comment_data',
'author' => 'comment_author_name',
'timestamp' => 'comment_timestamp',
'type' => 'comment_type',
'persistent' => 'comment_is_persistent',
'expiration' => 'comment_expiration',
'host_name',
'service_description',
'host_display_name',
'service_display_name'
))->where('comment_internal_id', $commentId)->getQuery()->fetchRow();
if (false === $this->comment) {
throw new Zend_Controller_Action_Exception($this->translate('Comment not found'));
}
$this->getTabs()->add(
'comment',
array(
'title' => $this->translate(
'Display detailed information about a comment.'
),
'icon' => 'comment',
'label' => $this->translate('Comment'),
'url' =>'monitoring/comments/show'
)
)->activate('comment')->extend(new DashboardAction());
}
/**
* Display comment detail view
*/
public function showAction()
{
$listCommentsLink = Url::fromPath('monitoring/list/comments')
->setQueryString('comment_type=(comment|ack)');
$this->view->comment = $this->comment;
if ($this->hasPermission('monitoring/command/comment/delete')) {
$this->view->delCommentForm = $this->createDelCommentForm();
$this->view->delCommentForm->populate(
array(
'redirect' => $listCommentsLink,
'comment_id' => $this->comment->id,
'comment_is_service' => isset($this->comment->service_description)
)
);
}
}
/**
* Create a command form to delete a single comment
*
* @return DeleteCommentsCommandForm
*/
private function createDelCommentForm()
{
$this->assertPermission('monitoring/command/comment/delete');
$delCommentForm = new DeleteCommentCommandForm();
$delCommentForm->setAction(
Url::fromPath('monitoring/comment/show')
->setParam('comment_id', $this->comment->id)
);
$delCommentForm->handleRequest();
return $delCommentForm;
}
}

View File

@ -0,0 +1,100 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentsCommandForm;
use Icinga\Web\Url;
use Icinga\Data\Filter\Filter;
/**
* Display detailed information about a comment
*/
class Monitoring_CommentsController extends Controller
{
/**
* The fetched comments
*
* @var array
*/
protected $comments;
/**
* Fetch all comments matching the current filter and add tabs
*
* @throws Zend_Controller_Action_Exception
*/
public function init()
{
$this->filter = Filter::fromQueryString(str_replace(
'comment_id',
'comment_internal_id',
(string)$this->params
));
$this->comments = $this->backend->select()->from('comment', array(
'id' => 'comment_internal_id',
'objecttype' => 'comment_objecttype',
'comment' => 'comment_data',
'author' => 'comment_author_name',
'timestamp' => 'comment_timestamp',
'type' => 'comment_type',
'persistent' => 'comment_is_persistent',
'expiration' => 'comment_expiration',
'host_name',
'service_description',
'host_display_name',
'service_display_name'
))->addFilter($this->filter)->getQuery()->fetchAll();
if (false === $this->comments) {
throw new Zend_Controller_Action_Exception($this->translate('Comment not found'));
}
$this->getTabs()->add(
'comments',
array(
'title' => $this->translate(
'Display detailed information about multiple comments.'
),
'icon' => 'comment',
'label' => $this->translate('Comments'),
'url' =>'monitoring/comments/show'
)
)->activate('comments');
}
/**
* Display the detail view for a comment list
*/
public function showAction()
{
$this->view->comments = $this->comments;
$this->view->listAllLink = Url::fromPath('monitoring/list/comments')
->setQueryString($this->filter->toQueryString());
$this->view->removeAllLink = Url::fromPath('monitoring/comments/delete-all')
->setParams($this->params);
}
/**
* Display the form for removing a comment list
*/
public function deleteAllAction()
{
$this->assertPermission('monitoring/command/comment/delete');
$listCommentsLink = Url::fromPath('monitoring/list/comments')
->setQueryString('comment_type=(comment|ack)');
$delCommentForm = new DeleteCommentsCommandForm();
$delCommentForm->setTitle($this->view->translate('Remove all Comments'));
$delCommentForm->addDescription(sprintf(
$this->translate('Confirm removal of %d comments.'),
count($this->comments)
));
$delCommentForm->setComments($this->comments)
->setRedirectUrl($listCommentsLink)
->handleRequest();
$this->view->delCommentForm = $delCommentForm;
$this->view->comments = $this->comments;
$this->view->listAllLink = Url::fromPath('monitoring/list/comments')
->setQueryString($this->filter->toQueryString());
}
}

View File

@ -4,7 +4,7 @@
use Icinga\Web\Notification; use Icinga\Web\Notification;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Forms\ConfirmRemovalForm; use Icinga\Forms\ConfirmRemovalForm;
use Icinga\Web\Controller\ModuleActionController; use Icinga\Web\Controller;
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm; use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
use Icinga\Module\Monitoring\Forms\Config\InstanceConfigForm; use Icinga\Module\Monitoring\Forms\Config\InstanceConfigForm;
use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm; use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm;
@ -12,7 +12,7 @@ use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm;
/** /**
* Configuration controller for editing monitoring resources * Configuration controller for editing monitoring resources
*/ */
class Monitoring_ConfigController extends ModuleActionController class Monitoring_ConfigController extends Controller
{ {
/** /**
* Display a list of available backends and instances * Display a list of available backends and instances

View File

@ -0,0 +1,141 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Object\Service;
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction;
/**
* Display detailed information about a downtime
*/
class Monitoring_DowntimeController extends Controller
{
/**
* The fetched downtime
*
* @var stdClass
*/
protected $downtime;
/**
* If the downtime is a service or not
*
* @var boolean
*/
protected $isService;
/**
* Fetch the downtime matching the given id and add tabs
*
* @throws Zend_Controller_Action_Exception
*/
public function init()
{
$downtimeId = $this->params->get('downtime_id');
$this->downtime = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id',
'objecttype' => 'downtime_objecttype',
'comment' => 'downtime_comment',
'author_name' => 'downtime_author_name',
'start' => 'downtime_start',
'scheduled_start' => 'downtime_scheduled_start',
'scheduled_end' => 'downtime_scheduled_end',
'end' => 'downtime_end',
'duration' => 'downtime_duration',
'is_flexible' => 'downtime_is_flexible',
'is_fixed' => 'downtime_is_fixed',
'is_in_effect' => 'downtime_is_in_effect',
'entry_time' => 'downtime_entry_time',
'host_state' => 'downtime_host_state',
'service_state' => 'downtime_service_state',
'host_name',
'host',
'service',
'service_description',
'host_display_name',
'service_display_name'
))->where('downtime_internal_id', $downtimeId)->getQuery()->fetchRow();
if (false === $this->downtime) {
throw new Zend_Controller_Action_Exception($this->translate('Downtime not found'));
}
if (isset($this->downtime->service_description)) {
$this->isService = true;
} else {
$this->isService = false;
}
$this->getTabs()
->add(
'downtime',
array(
'title' => $this->translate(
'Display detailed information about a downtime.'
),
'icon' => 'plug',
'label' => $this->translate('Downtime'),
'url' =>'monitoring/downtimes/show'
)
)->activate('downtime')->extend(new DashboardAction());
}
/**
* Display the detail view for a downtime
*/
public function showAction()
{
$this->view->downtime = $this->downtime;
$this->view->isService = $this->isService;
$this->view->stateName = isset($this->downtime->service_description) ?
Service::getStateText($this->downtime->service_state) :
Host::getStateText($this->downtime->host_state);
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes');
$this->view->showHostLink = Url::fromPath('monitoring/host/show')
->setParam('host', $this->downtime->host);
$this->view->showServiceLink = Url::fromPath('monitoring/service/show')
->setParam('host', $this->downtime->host)
->setParam('service', $this->downtime->service_description);
if ($this->hasPermission('monitoring/command/downtime/delete')) {
$this->view->delDowntimeForm = $this->createDelDowntimeForm();
$this->view->delDowntimeForm->populate(
array(
'redirect' => Url::fromPath('monitoring/list/downtimes'),
'downtime_id' => $this->downtime->id,
'downtime_is_service' => $this->isService
)
);
}
}
/**
* Receive DeleteDowntimeCommandForm post from other controller
*/
public function removeAction()
{
$this->assertHttpMethod('POST');
$this->createDelDowntimeForm();
}
/**
* Create a command form to delete a single comment
*
* @return DeleteDowntimeCommandForm
*/
private function createDelDowntimeForm()
{
$this->assertPermission('monitoring/command/downtime/delete');
$delDowntimeForm = new DeleteDowntimeCommandForm();
$delDowntimeForm->setAction(
Url::fromPath('monitoring/downtime/show')
->setParam('downtime_id', $this->downtime->id)
);
$delDowntimeForm->handleRequest();
return $delDowntimeForm;
}
}

View File

@ -0,0 +1,130 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Data\Filter\Filter;
use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Object\Service;
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimesCommandForm;
use Icinga\Web\Url;
/**
* Display detailed information about a downtime
*/
class Monitoring_DowntimesController extends Controller
{
/**
* The fetched downtimes
*
* @var array
*/
protected $downtimes;
/**
* A filter matching all current downtimes
*
* @var Filter
*/
protected $filter;
/**
* Fetch all downtimes matching the current filter and add tabs
*
* @throws Zend_Controller_Action_Exception
*/
public function init()
{
$this->filter = Filter::fromQueryString(str_replace(
'downtime_id',
'downtime_internal_id',
(string)$this->params
));
$this->downtimes = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id',
'objecttype' => 'downtime_objecttype',
'comment' => 'downtime_comment',
'author_name' => 'downtime_author_name',
'start' => 'downtime_start',
'scheduled_start' => 'downtime_scheduled_start',
'scheduled_end' => 'downtime_scheduled_end',
'end' => 'downtime_end',
'duration' => 'downtime_duration',
'is_flexible' => 'downtime_is_flexible',
'is_fixed' => 'downtime_is_fixed',
'is_in_effect' => 'downtime_is_in_effect',
'entry_time' => 'downtime_entry_time',
'host_state' => 'downtime_host_state',
'service_state' => 'downtime_service_state',
'host_name',
'host',
'service',
'service_description',
'host_display_name',
'service_display_name'
))->addFilter($this->filter)->getQuery()->fetchAll();
if (false === $this->downtimes) {
throw new Zend_Controller_Action_Exception(
$this->translate('Downtime not found')
);
}
$this->getTabs()->add(
'downtimes',
array(
'title' => $this->translate(
'Display detailed information about multiple downtimes.'
),
'icon' => 'plug',
'label' => $this->translate('Downtimes'),
'url' =>'monitoring/downtimes/show'
)
)->activate('downtimes');
foreach ($this->downtimes as $downtime) {
if (isset($downtime->service_description)) {
$downtime->isService = true;
} else {
$downtime->isService = false;
}
if ($downtime->isService) {
$downtime->stateText = Service::getStateText($downtime->service_state);
} else {
$downtime->stateText = Host::getStateText($downtime->host_state);
}
}
}
/**
* Display the detail view for a downtime list
*/
public function showAction()
{
$this->view->downtimes = $this->downtimes;
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes')
->setQueryString($this->filter->toQueryString());
$this->view->removeAllLink = Url::fromPath('monitoring/downtimes/delete-all')
->setParams($this->params);
}
/**
* Display the form for removing a downtime list
*/
public function deleteAllAction()
{
$this->assertPermission('monitoring/command/downtime/delete');
$this->view->downtimes = $this->downtimes;
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes')
->setQueryString($this->filter->toQueryString());
$delDowntimeForm = new DeleteDowntimesCommandForm();
$delDowntimeForm->setTitle($this->view->translate('Remove all Downtimes'));
$delDowntimeForm->addDescription(sprintf(
$this->translate('Confirm removal of %d downtimes.'),
count($this->downtimes)
));
$delDowntimeForm->setRedirectUrl(Url::fromPath('monitoring/list/downtimes'));
$delDowntimeForm->setDowntimes($this->downtimes)->handleRequest();
$this->view->delDowntimeForm = $delDowntimeForm;
}
}

View File

@ -1,6 +1,7 @@
<?php <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Exception\MissingParameterException;
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
@ -26,12 +27,22 @@ class Monitoring_HostController extends MonitoredObjectController
*/ */
public function init() public function init()
{ {
if ($this->params->get('host') === null) {
throw new MissingParameterException(
$this->translate('Required parameter \'%s\' is missing'),
'host'
);
}
$host = new Host($this->backend, $this->params->get('host')); $host = new Host($this->backend, $this->params->get('host'));
$this->applyRestriction('monitoring/hosts/filter', $host); $this->applyRestriction('monitoring/hosts/filter', $host);
if ($host->fetch() === false) { if ($host->fetch() === false) {
throw new Zend_Controller_Action_Exception($this->translate('Host not found')); throw new Zend_Controller_Action_Exception(
sprintf($this->translate('Host \'%s\' not found'), $this->params->get('host')),
404
);
} }
$this->object = $host; $this->object = $host;
$this->createTabs(); $this->createTabs();

View File

@ -15,6 +15,7 @@ use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\HostList; use Icinga\Module\Monitoring\Object\HostList;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget\Chart\InlinePie; use Icinga\Web\Widget\Chart\InlinePie;
use Icinga\Web\Widget\Tabextension\DashboardAction;
class Monitoring_HostsController extends Controller class Monitoring_HostsController extends Controller
{ {
@ -26,7 +27,7 @@ class Monitoring_HostsController extends Controller
public function init() public function init()
{ {
$hostList = new HostList($this->backend); $hostList = new HostList($this->backend);
$hostList->setFilter(Filter::fromQueryString((string) $this->params)); $hostList->setFilter(Filter::fromQueryString((string) $this->params->without('view')));
$this->hostList = $hostList; $this->hostList = $hostList;
} }
@ -80,7 +81,7 @@ class Monitoring_HostsController extends Controller
'label' => $this->translate('Hosts'), 'label' => $this->translate('Hosts'),
'url' => Url::fromRequest() 'url' => Url::fromRequest()
) )
)->activate('show'); )->extend(new DashboardAction())->activate('show');
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); $checkNowForm = new CheckNowCommandForm();
$checkNowForm $checkNowForm
@ -123,7 +124,7 @@ class Monitoring_HostsController extends Controller
} }
if ((bool) $host->in_downtime === true) { if ((bool) $host->in_downtime === true) {
$objectsInDowntime[] = $host; $objectsInDowntime[] = $host;
$downtimeFilterExpressions[] = Filter::where('downtime_host', $host->getName()); $downtimeFilterExpressions[] = Filter::where('host_name', $host->getName());
} }
++$hostStates[$host::getStateText($host->state)]; ++$hostStates[$host::getStateText($host->state)];
} }

View File

@ -9,7 +9,6 @@ use Icinga\Web\Url;
use Icinga\Web\Widget\Tabextension\DashboardAction; use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Widget\Tabextension\OutputFormat; use Icinga\Web\Widget\Tabextension\OutputFormat;
use Icinga\Web\Widget\Tabs; use Icinga\Web\Widget\Tabs;
use Icinga\Web\Widget\SortBox;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Web\Widget; use Icinga\Web\Widget;
use Icinga\Module\Monitoring\Forms\StatehistoryForm; use Icinga\Module\Monitoring\Forms\StatehistoryForm;
@ -21,12 +20,8 @@ class Monitoring_ListController extends Controller
*/ */
public function init() public function init()
{ {
parent::init();
$this->createTabs(); $this->createTabs();
$this->view->compact = $this->_request->getParam('view') === 'compact';
if ($this->_request->getParam('view') === 'inline') {
$this->view->compact = true;
$this->view->inline = true;
}
} }
/** /**
@ -47,25 +42,6 @@ class Monitoring_ListController extends Controller
return $query; return $query;
} }
protected function hasBetterUrl()
{
$request = $this->getRequest();
$url = Url::fromRequest();
if ($this->getRequest()->isPost()) {
if ($request->getPost('sort')) {
$url->setParam('sort', $request->getPost('sort'));
if ($request->getPost('dir')) {
$url->setParam('dir', $request->getPost('dir'));
} else {
$url->removeParam('dir');
}
return $url;
}
}
return false;
}
/** /**
* Overwrite the backend to use (used for testing) * Overwrite the backend to use (used for testing)
* *
@ -81,10 +57,6 @@ class Monitoring_ListController extends Controller
*/ */
public function hostsAction() public function hostsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
// Handle soft and hard states // Handle soft and hard states
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') { if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
$stateColumn = 'host_hard_state'; $stateColumn = 'host_hard_state';
@ -123,19 +95,9 @@ class Monitoring_ListController extends Controller
'host_current_check_attempt', 'host_current_check_attempt',
'host_max_check_attempts' 'host_max_check_attempts'
), $this->extraColumns())); ), $this->extraColumns()));
$this->filterQuery($query); $this->filterQuery($query);
$this->applyRestriction('monitoring/hosts/filter', $query); $this->applyRestriction('monitoring/hosts/filter', $query);
$this->view->hosts = $query;
$this->setupSortControl(array(
'host_severity' => $this->translate('Severity'),
'host_state' => $this->translate('Current State'),
'host_display_name' => $this->translate('Hostname'),
'host_address' => $this->translate('Address'),
'host_last_check' => $this->translate('Last Check')
));
$this->view->hosts = $query->paginate();
$this->view->stats = $this->backend->select()->from('statusSummary', array( $this->view->stats = $this->backend->select()->from('statusSummary', array(
'hosts_total', 'hosts_total',
@ -148,6 +110,16 @@ class Monitoring_ListController extends Controller
'hosts_unreachable_unhandled', 'hosts_unreachable_unhandled',
'hosts_pending', 'hosts_pending',
))->getQuery()->fetchRow(); ))->getQuery()->fetchRow();
$this->setupLimitControl();
$this->setupPaginationControl($this->view->hosts);
$this->setupSortControl(array(
'host_severity' => $this->translate('Severity'),
'host_state' => $this->translate('Current State'),
'host_display_name' => $this->translate('Hostname'),
'host_address' => $this->translate('Address'),
'host_last_check' => $this->translate('Last Check')
), $query);
} }
/** /**
@ -155,10 +127,6 @@ class Monitoring_ListController extends Controller
*/ */
public function servicesAction() public function servicesAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
// Handle soft and hard states // Handle soft and hard states
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') { if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
$stateColumn = 'service_hard_state'; $stateColumn = 'service_hard_state';
@ -170,11 +138,9 @@ class Monitoring_ListController extends Controller
$this->addTitleTab('services', $this->translate('Services'), $this->translate('List services')); $this->addTitleTab('services', $this->translate('Services'), $this->translate('List services'));
$this->view->showHost = true; $this->view->showHost = true;
if ($host = $this->_getParam('host')) { if (strpos($this->params->get('host_name', '*'), '*') === false) {
if (strpos($host, '*') === false) {
$this->view->showHost = false; $this->view->showHost = false;
} }
}
$this->setAutorefreshInterval(10); $this->setAutorefreshInterval(10);
$columns = array_merge(array( $columns = array_merge(array(
@ -213,11 +179,12 @@ class Monitoring_ListController extends Controller
'max_check_attempts' => 'service_max_check_attempts' 'max_check_attempts' => 'service_max_check_attempts'
), $this->extraColumns()); ), $this->extraColumns());
$query = $this->backend->select()->from('serviceStatus', $columns); $query = $this->backend->select()->from('serviceStatus', $columns);
$this->filterQuery($query); $this->filterQuery($query);
$this->applyRestriction('monitoring/services/filter', $query); $this->applyRestriction('monitoring/services/filter', $query);
$this->view->services = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->services);
$this->setupSortControl(array( $this->setupSortControl(array(
'service_severity' => $this->translate('Service Severity'), 'service_severity' => $this->translate('Service Severity'),
'service_state' => $this->translate('Current Service State'), 'service_state' => $this->translate('Current Service State'),
@ -228,15 +195,7 @@ class Monitoring_ListController extends Controller
'host_display_name' => $this->translate('Hostname'), 'host_display_name' => $this->translate('Hostname'),
'host_address' => $this->translate('Host Address'), 'host_address' => $this->translate('Host Address'),
'host_last_check' => $this->translate('Last Host Check') 'host_last_check' => $this->translate('Last Host Check')
)); ), $query);
$limit = $this->params->get('limit');
$this->view->limit = $limit;
if ($limit === 0) {
$this->view->services = $query->getQuery()->fetchAll();
} else {
// TODO: Workaround, paginate should be able to fetch limit from new params
$this->view->services = $query->paginate($this->params->get('limit'));
}
$this->view->stats = $this->backend->select()->from('statusSummary', array( $this->view->stats = $this->backend->select()->from('statusSummary', array(
'services_total', 'services_total',
@ -255,7 +214,6 @@ class Monitoring_ListController extends Controller
'services_unknown_handled', 'services_unknown_handled',
'services_pending', 'services_pending',
))->getQuery()->fetchRow(); ))->getQuery()->fetchRow();
} }
/** /**
@ -263,16 +221,14 @@ class Monitoring_ListController extends Controller
*/ */
public function downtimesAction() public function downtimesAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('downtimes', $this->translate('Downtimes'), $this->translate('List downtimes')); $this->addTitleTab('downtimes', $this->translate('Downtimes'), $this->translate('List downtimes'));
$this->setAutorefreshInterval(12); $this->setAutorefreshInterval(12);
$query = $this->backend->select()->from('downtime', array( $query = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id', 'id' => 'downtime_internal_id',
'objecttype' => 'downtime_objecttype', 'objecttype' => 'downtime_objecttype',
'comment' => 'downtime_comment', 'comment' => 'downtime_comment',
'author' => 'downtime_author', 'author_name' => 'downtime_author_name',
'start' => 'downtime_start', 'start' => 'downtime_start',
'scheduled_start' => 'downtime_scheduled_start', 'scheduled_start' => 'downtime_scheduled_start',
'scheduled_end' => 'downtime_scheduled_end', 'scheduled_end' => 'downtime_scheduled_end',
@ -282,16 +238,18 @@ class Monitoring_ListController extends Controller
'is_fixed' => 'downtime_is_fixed', 'is_fixed' => 'downtime_is_fixed',
'is_in_effect' => 'downtime_is_in_effect', 'is_in_effect' => 'downtime_is_in_effect',
'entry_time' => 'downtime_entry_time', 'entry_time' => 'downtime_entry_time',
'host' => 'host_name',
'service' => 'service_description',
'host_state' => 'downtime_host_state', 'host_state' => 'downtime_host_state',
'service_state' => 'downtime_service_state', 'service_state' => 'downtime_service_state',
'host_name',
'service_description',
'host_display_name', 'host_display_name',
'service_display_name' 'service_display_name'
)); ));
$this->filterQuery($query); $this->filterQuery($query);
$this->view->downtimes = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->downtimes);
$this->setupSortControl(array( $this->setupSortControl(array(
'downtime_is_in_effect' => $this->translate('Is In Effect'), 'downtime_is_in_effect' => $this->translate('Is In Effect'),
'host_display_name' => $this->translate('Host'), 'host_display_name' => $this->translate('Host'),
@ -303,12 +261,11 @@ class Monitoring_ListController extends Controller
'downtime_scheduled_start' => $this->translate('Scheduled Start'), 'downtime_scheduled_start' => $this->translate('Scheduled Start'),
'downtime_scheduled_end' => $this->translate('Scheduled End'), 'downtime_scheduled_end' => $this->translate('Scheduled End'),
'downtime_duration' => $this->translate('Duration') 'downtime_duration' => $this->translate('Duration')
)); ), $query);
$this->view->downtimes = $query->paginate();
if ($this->Auth()->hasPermission('monitoring/command/downtime/delete')) { if ($this->Auth()->hasPermission('monitoring/command/downtime/delete')) {
$this->view->delDowntimeForm = new DeleteDowntimeCommandForm(); $this->view->delDowntimeForm = new DeleteDowntimeCommandForm();
$this->view->delDowntimeForm->handleRequest();
} }
} }
@ -317,38 +274,37 @@ class Monitoring_ListController extends Controller
*/ */
public function notificationsAction() public function notificationsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab( $this->addTitleTab(
'notifications', 'notifications',
$this->translate('Notifications'), $this->translate('Notifications'),
$this->translate('List notifications') $this->translate('List notifications')
); );
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$query = $this->backend->select()->from('notification', array( $query = $this->backend->select()->from('notification', array(
'host', 'host_name',
'service', 'service_description',
'notification_output', 'notification_output',
'notification_contact', 'notification_contact_name',
'notification_start_time', 'notification_start_time',
'notification_state', 'notification_state',
'host_display_name', 'host_display_name',
'service_display_name' 'service_display_name'
)); ));
$this->filterQuery($query); $this->filterQuery($query);
$this->view->notifications = $query->paginate(); $this->view->notifications = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->notifications);
$this->setupSortControl(array( $this->setupSortControl(array(
'notification_start_time' => $this->translate('Notification Start') 'notification_start_time' => $this->translate('Notification Start')
)); ), $query);
} }
public function contactsAction() public function contactsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('contacts', $this->translate('Contacts'), $this->translate('List contacts')); $this->addTitleTab('contacts', $this->translate('Contacts'), $this->translate('List contacts'));
$query = $this->backend->select()->from('contact', array( $query = $this->backend->select()->from('contact', array(
'contact_name', 'contact_name',
'contact_id', 'contact_id',
@ -370,8 +326,10 @@ class Monitoring_ListController extends Controller
'contact_notify_host_downtime', 'contact_notify_host_downtime',
)); ));
$this->filterQuery($query); $this->filterQuery($query);
$this->view->contacts = $query->paginate(); $this->view->contacts = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->contacts);
$this->setupSortControl(array( $this->setupSortControl(array(
'contact_name' => $this->translate('Name'), 'contact_name' => $this->translate('Name'),
'contact_alias' => $this->translate('Alias'), 'contact_alias' => $this->translate('Alias'),
@ -379,14 +337,11 @@ class Monitoring_ListController extends Controller
'contact_pager' => $this->translate('Pager Address / Number'), 'contact_pager' => $this->translate('Pager Address / Number'),
'contact_notify_service_timeperiod' => $this->translate('Service Notification Timeperiod'), 'contact_notify_service_timeperiod' => $this->translate('Service Notification Timeperiod'),
'contact_notify_host_timeperiod' => $this->translate('Host Notification Timeperiod') 'contact_notify_host_timeperiod' => $this->translate('Host Notification Timeperiod')
)); ), $query);
} }
public function eventgridAction() public function eventgridAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('eventgrid', $this->translate('Event Grid'), $this->translate('Show the Event Grid')); $this->addTitleTab('eventgrid', $this->translate('Event Grid'), $this->translate('Show the Event Grid'));
$form = new StatehistoryForm(); $form = new StatehistoryForm();
@ -426,14 +381,12 @@ class Monitoring_ListController extends Controller
public function contactgroupsAction() public function contactgroupsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab( $this->addTitleTab(
'contactgroups', 'contactgroups',
$this->translate('Contact Groups'), $this->translate('Contact Groups'),
$this->translate('List contact groups') $this->translate('List contact groups')
); );
$query = $this->backend->select()->from('contactgroup', array( $query = $this->backend->select()->from('contactgroup', array(
'contactgroup_name', 'contactgroup_name',
'contactgroup_alias', 'contactgroup_alias',
@ -441,7 +394,7 @@ class Monitoring_ListController extends Controller
'contact_alias', 'contact_alias',
'contact_email', 'contact_email',
'contact_pager', 'contact_pager',
))->order('contactgroup_alias'); ));
$this->filterQuery($query); $this->filterQuery($query);
// Fetch and prepare all contact groups: // Fetch and prepare all contact groups:
@ -458,32 +411,37 @@ class Monitoring_ListController extends Controller
} }
// TODO: Find a better naming // TODO: Find a better naming
$this->view->groupData = $groupData; $this->view->groupData = $groupData;
$this->setupSortControl(array(
'contactgroup_name' => $this->translate('Contactgroup Name'),
'contactgroup_alias' => $this->translate('Contactgroup Alias')
), $query);
} }
public function commentsAction() public function commentsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('comments', $this->translate('Comments'), $this->translate('List comments')); $this->addTitleTab('comments', $this->translate('Comments'), $this->translate('List comments'));
$this->setAutorefreshInterval(12); $this->setAutorefreshInterval(12);
$query = $this->backend->select()->from('comment', array( $query = $this->backend->select()->from('comment', array(
'id' => 'comment_internal_id', 'id' => 'comment_internal_id',
'objecttype' => 'comment_objecttype', 'objecttype' => 'comment_objecttype',
'comment' => 'comment_data', 'comment' => 'comment_data',
'author' => 'comment_author', 'author' => 'comment_author_name',
'timestamp' => 'comment_timestamp', 'timestamp' => 'comment_timestamp',
'type' => 'comment_type', 'type' => 'comment_type',
'persistent' => 'comment_is_persistent', 'persistent' => 'comment_is_persistent',
'expiration' => 'comment_expiration', 'expiration' => 'comment_expiration',
'host' => 'comment_host', 'host_name',
'service' => 'comment_service', 'service_description',
'host_display_name', 'host_display_name',
'service_display_name' 'service_display_name'
)); ));
$this->filterQuery($query); $this->filterQuery($query);
$this->view->comments = $query->paginate(); $this->view->comments = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->comments);
$this->setupSortControl( $this->setupSortControl(
array( array(
'comment_timestamp' => $this->translate('Comment Timestamp'), 'comment_timestamp' => $this->translate('Comment Timestamp'),
@ -491,27 +449,27 @@ class Monitoring_ListController extends Controller
'service_display_name' => $this->translate('Service'), 'service_display_name' => $this->translate('Service'),
'comment_type' => $this->translate('Comment Type'), 'comment_type' => $this->translate('Comment Type'),
'comment_expiration' => $this->translate('Expiration') 'comment_expiration' => $this->translate('Expiration')
) ),
$query
); );
if ($this->Auth()->hasPermission('monitoring/command/comment/delete')) { if ($this->Auth()->hasPermission('monitoring/command/comment/delete')) {
$this->view->delCommentForm = new DeleteCommentCommandForm(); $this->view->delCommentForm = new DeleteCommentCommandForm();
$this->view->delCommentForm->handleRequest();
} }
} }
public function servicegroupsAction() public function servicegroupsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab( $this->addTitleTab(
'servicegroups', 'servicegroups',
$this->translate('Service Groups'), $this->translate('Service Groups'),
$this->translate('List service groups') $this->translate('List service groups')
); );
$this->setAutorefreshInterval(12); $this->setAutorefreshInterval(12);
$query = $this->backend->select()->from('groupsummary', array( $query = $this->backend->select()->from('groupsummary', array(
'servicegroup', 'servicegroup_name',
'servicegroup_alias', 'servicegroup_alias',
'hosts_up', 'hosts_up',
'hosts_unreachable_handled', 'hosts_unreachable_handled',
@ -540,7 +498,10 @@ class Monitoring_ListController extends Controller
// TODO(el): Can't default to the sort rules of the data view because it's meant for both host groups and // TODO(el): Can't default to the sort rules of the data view because it's meant for both host groups and
// service groups. We should separate them. // service groups. We should separate them.
$this->filterQuery($query); $this->filterQuery($query);
$this->view->servicegroups = $query->paginate(); $this->view->servicegroups = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->servicegroups);
$this->setupSortControl(array( $this->setupSortControl(array(
'services_severity' => $this->translate('Severity'), 'services_severity' => $this->translate('Severity'),
'servicegroup_alias' => $this->translate('Service Group Name'), 'servicegroup_alias' => $this->translate('Service Group Name'),
@ -550,18 +511,16 @@ class Monitoring_ListController extends Controller
'services_critical' => $this->translate('Services CRITICAL'), 'services_critical' => $this->translate('Services CRITICAL'),
'services_warning' => $this->translate('Services WARNING'), 'services_warning' => $this->translate('Services WARNING'),
'services_pending' => $this->translate('Services PENDING') 'services_pending' => $this->translate('Services PENDING')
)); ), $query);
} }
public function hostgroupsAction() public function hostgroupsAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('hostgroups', $this->translate('Host Groups'), $this->translate('List host groups')); $this->addTitleTab('hostgroups', $this->translate('Host Groups'), $this->translate('List host groups'));
$this->setAutorefreshInterval(12); $this->setAutorefreshInterval(12);
$query = $this->backend->select()->from('groupsummary', array( $query = $this->backend->select()->from('groupsummary', array(
'hostgroup', 'hostgroup_name',
'hostgroup_alias', 'hostgroup_alias',
'hosts_up', 'hosts_up',
'hosts_unreachable_handled', 'hosts_unreachable_handled',
@ -569,6 +528,12 @@ class Monitoring_ListController extends Controller
'hosts_down_handled', 'hosts_down_handled',
'hosts_down_unhandled', 'hosts_down_unhandled',
'hosts_pending', 'hosts_pending',
'hosts_up_last_state_change',
'hosts_pending_last_state_change',
'hosts_down_last_state_change_handled',
'hosts_unreachable_last_state_change_handled',
'hosts_down_last_state_change_unhandled',
'hosts_unreachable_last_state_change_unhandled',
'services_ok', 'services_ok',
'services_unknown_handled', 'services_unknown_handled',
'services_unknown_unhandled', 'services_unknown_unhandled',
@ -590,7 +555,10 @@ class Monitoring_ListController extends Controller
// TODO(el): Can't default to the sort rules of the data view because it's meant for both host groups and // TODO(el): Can't default to the sort rules of the data view because it's meant for both host groups and
// service groups. We should separate them. // service groups. We should separate them.
$this->filterQuery($query); $this->filterQuery($query);
$this->view->hostgroups = $query->paginate(); $this->view->hostgroups = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->hostgroups);
$this->setupSortControl(array( $this->setupSortControl(array(
'services_severity' => $this->translate('Severity'), 'services_severity' => $this->translate('Severity'),
'hostgroup_alias' => $this->translate('Host Group Name'), 'hostgroup_alias' => $this->translate('Host Group Name'),
@ -600,14 +568,11 @@ class Monitoring_ListController extends Controller
'services_critical' => $this->translate('Services CRITICAL'), 'services_critical' => $this->translate('Services CRITICAL'),
'services_warning' => $this->translate('Services WARNING'), 'services_warning' => $this->translate('Services WARNING'),
'services_pending' => $this->translate('Services PENDING') 'services_pending' => $this->translate('Services PENDING')
)); ), $query);
} }
public function eventhistoryAction() public function eventhistoryAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab( $this->addTitleTab(
'eventhistory', 'eventhistory',
$this->translate('Event Overview'), $this->translate('Event Overview'),
@ -625,24 +590,21 @@ class Monitoring_ListController extends Controller
'attempt', 'attempt',
'max_attempts', 'max_attempts',
'output', 'output',
'type', 'type'
'host',
'service'
)); ));
$this->filterQuery($query); $this->filterQuery($query);
$this->view->history = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->history);
$this->setupSortControl(array( $this->setupSortControl(array(
'timestamp' => $this->translate('Occurence') 'timestamp' => $this->translate('Occurence')
)); ), $query);
$this->view->history = $query->paginate();
} }
public function servicegridAction() public function servicegridAction()
{ {
if ($url = $this->hasBetterUrl()) {
return $this->redirectNow($url);
}
$this->addTitleTab('servicegrid', $this->translate('Service Grid'), $this->translate('Show the Service Grid')); $this->addTitleTab('servicegrid', $this->translate('Service Grid'), $this->translate('Show the Service Grid'));
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$query = $this->backend->select()->from('serviceStatus', array( $query = $this->backend->select()->from('serviceStatus', array(
@ -656,7 +618,7 @@ class Monitoring_ListController extends Controller
$this->setupSortControl(array( $this->setupSortControl(array(
'host_name' => $this->translate('Hostname'), 'host_name' => $this->translate('Hostname'),
'service_description' => $this->translate('Service description') 'service_description' => $this->translate('Service description')
)); ), $query);
$pivot = $query->pivot('service_description', 'host_name'); $pivot = $query->pivot('service_description', 'host_name');
$this->view->pivot = $pivot; $this->view->pivot = $pivot;
$this->view->horizontalPaginator = $pivot->paginateXAxis(); $this->view->horizontalPaginator = $pivot->paginateXAxis();
@ -667,17 +629,17 @@ class Monitoring_ListController extends Controller
{ {
$editor = Widget::create('filterEditor') $editor = Widget::create('filterEditor')
->setQuery($query) ->setQuery($query)
->preserveParams('limit', 'sort', 'dir', 'format', 'view', 'backend', 'stateType', 'addColumns') ->preserveParams(
'limit', 'sort', 'dir', 'format', 'view', 'backend',
'stateType', 'addColumns', '_dev'
)
->ignoreParams('page') ->ignoreParams('page')
->handleRequest($this->getRequest()); ->handleRequest($this->getRequest());
$query->applyFilter($editor->getFilter()); $query->applyFilter($editor->getFilter());
$this->view->filterEditor = $editor; $this->setupFilterControl($editor);
$this->view->filter = $editor->getFilter(); $this->view->filter = $editor->getFilter();
if ($sort = $this->params->get('sort')) {
$query->order($sort, $this->params->get('dir'));
}
$this->handleFormatRequest($query); $this->handleFormatRequest($query);
return $query; return $query;
} }
@ -694,21 +656,6 @@ class Monitoring_ListController extends Controller
return $columns; return $columns;
} }
/**
* Create a sort control box at the 'sortControl' view parameter
*
* @param array $columns An array containing the sort columns, with the
* submit value as the key and the value as the label
*/
private function setupSortControl(array $columns)
{
$this->view->sortControl = new SortBox(
'sortbox-' . $this->getRequest()->getActionName(),
$columns
);
$this->view->sortControl->applyRequest($this->getRequest());
}
protected function addTitleTab($action, $title, $tip) protected function addTitleTab($action, $title, $tip)
{ {
$this->getTabs()->add($action, array( $this->getTabs()->add($action, array(
@ -726,15 +673,6 @@ class Monitoring_ListController extends Controller
*/ */
private function createTabs() private function createTabs()
{ {
$tabs = $this->getTabs(); $this->getTabs()->extend(new OutputFormat())->extend(new DashboardAction());
if (in_array($this->_request->getActionName(), array(
'hosts',
'services',
'eventhistory',
'eventgrid',
'notifications'
))) {
$tabs->extend(new OutputFormat())->extend(new DashboardAction());
}
} }
} }

View File

@ -1,6 +1,7 @@
<?php <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm; use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm; use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm;
@ -29,7 +30,7 @@ class Monitoring_ProcessController extends Controller
'label' => $this->translate('Monitoring Health'), 'label' => $this->translate('Monitoring Health'),
'url' =>'monitoring/process/info' 'url' =>'monitoring/process/info'
) )
); )->extend(new DashboardAction());
} }
/** /**
@ -48,8 +49,10 @@ class Monitoring_ProcessController extends Controller
array( array(
'is_currently_running', 'is_currently_running',
'process_id', 'process_id',
'endpoint_name',
'program_start_time', 'program_start_time',
'status_update_time', 'status_update_time',
'program_version',
'last_command_check', 'last_command_check',
'last_log_rotation', 'last_log_rotation',
'global_service_event_handler', 'global_service_event_handler',

View File

@ -1,6 +1,7 @@
<?php <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Exception\MissingParameterException;
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
@ -25,12 +26,22 @@ class Monitoring_ServiceController extends MonitoredObjectController
*/ */
public function init() public function init()
{ {
if ($this->params->get('host') === null || $this->params->get('service') === null) {
throw new MissingParameterException(
$this->translate('One of the required parameters \'%s\' is missing'),
'host or service'
);
}
$service = new Service($this->backend, $this->params->get('host'), $this->params->get('service')); $service = new Service($this->backend, $this->params->get('host'), $this->params->get('service'));
$this->applyRestriction('monitoring/services/filter', $service); $this->applyRestriction('monitoring/services/filter', $service);
if ($service->fetch() === false) { if ($service->fetch() === false) {
throw new Zend_Controller_Action_Exception($this->translate('Service not found')); throw new Zend_Controller_Action_Exception(
sprintf($this->translate('Service \'%s\' not found'), $this->params->get('service')),
404
);
} }
$this->object = $service; $this->object = $service;
$this->createTabs(); $this->createTabs();

View File

@ -16,6 +16,7 @@ use Icinga\Module\Monitoring\Object\Service;
use Icinga\Module\Monitoring\Object\ServiceList; use Icinga\Module\Monitoring\Object\ServiceList;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget\Chart\InlinePie; use Icinga\Web\Widget\Chart\InlinePie;
use Icinga\Web\Widget\Tabextension\DashboardAction;
class Monitoring_ServicesController extends Controller class Monitoring_ServicesController extends Controller
{ {
@ -27,7 +28,9 @@ class Monitoring_ServicesController extends Controller
public function init() public function init()
{ {
$serviceList = new ServiceList($this->backend); $serviceList = new ServiceList($this->backend);
$serviceList->setFilter(Filter::fromQueryString((string) $this->params->without('service_problem', 'service_handled'))); $serviceList->setFilter(Filter::fromQueryString(
(string) $this->params->without(array('service_problem', 'service_handled', 'view'))
));
$this->serviceList = $serviceList; $this->serviceList = $serviceList;
} }
@ -101,7 +104,7 @@ class Monitoring_ServicesController extends Controller
'label' => $this->translate('Services'), 'label' => $this->translate('Services'),
'url' => Url::fromRequest() 'url' => Url::fromRequest()
) )
)->activate('show'); )->extend(new DashboardAction())->activate('show');
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); $checkNowForm = new CheckNowCommandForm();
$checkNowForm $checkNowForm
@ -158,8 +161,8 @@ class Monitoring_ServicesController extends Controller
if ((bool) $service->in_downtime === true) { if ((bool) $service->in_downtime === true) {
$objectsInDowntime[] = $service; $objectsInDowntime[] = $service;
$downtimeFilterExpressions[] = Filter::matchAll( $downtimeFilterExpressions[] = Filter::matchAll(
Filter::where('downtime_host', $service->getHost()->getName()), Filter::where('host_name', $service->getHost()->getName()),
Filter::where('downtime_service', $service->getName()) Filter::where('service_description', $service->getName())
); );
} }
++$serviceStates[$service::getStateText($service->state)]; ++$serviceStates[$service::getStateText($service->state)];

View File

@ -1,7 +1,6 @@
<?php <?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Application\Benchmark;
use Icinga\Module\Monitoring\Object\MonitoredObject; use Icinga\Module\Monitoring\Object\MonitoredObject;
use Icinga\Web\Hook; use Icinga\Web\Hook;
use Icinga\Web\Url; use Icinga\Web\Url;
@ -10,8 +9,6 @@ use Icinga\Web\Widget\Tabextension\OutputFormat;
use Icinga\Web\Widget\Tabextension\DashboardAction; use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Module\Monitoring\Backend; use Icinga\Module\Monitoring\Backend;
use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service;
/** /**
* Class Monitoring_ShowController * Class Monitoring_ShowController
@ -73,9 +70,12 @@ class Monitoring_ShowController extends Controller
{ {
$this->getTabs()->activate('history'); $this->getTabs()->activate('history');
$this->view->object->fetchEventHistory(); $this->view->object->fetchEventHistory();
$this->view->history = $this->view->object->eventhistory->getQuery()->paginate($this->params->get('limit', 50)); $this->view->history = $this->view->object->eventhistory;
$this->handleFormatRequest($this->view->object->eventhistory); $this->handleFormatRequest($this->view->object->eventhistory);
$this->fetchHostStats(); $this->fetchHostStats();
$this->setupLimitControl(50);
$this->setupPaginationControl($this->view->history, 50);
} }
public function servicesAction() public function servicesAction()
@ -115,11 +115,11 @@ class Monitoring_ShowController extends Controller
public function contactAction() public function contactAction()
{ {
$contactName = $this->getParam('contact'); $contactName = $this->getParam('contact_name');
if (! $contactName) { if (! $contactName) {
throw new Zend_Controller_Action_Exception( throw new Zend_Controller_Action_Exception(
$this->translate('The parameter `contact\' is required'), $this->translate('The parameter `contact_name\' is required'),
404 404
); );
} }
@ -145,9 +145,7 @@ class Monitoring_ShowController extends Controller
'contact_notify_host_flapping', 'contact_notify_host_flapping',
'contact_notify_host_downtime', 'contact_notify_host_downtime',
)); ));
$query->where('contact_name', $contactName); $query->where('contact_name', $contactName);
$contact = $query->getQuery()->fetchRow(); $contact = $query->getQuery()->fetchRow();
if ($contact) { if ($contact) {
@ -156,13 +154,13 @@ class Monitoring_ShowController extends Controller
'command_name' 'command_name'
))->where('contact_id', $contact->contact_id); ))->where('contact_id', $contact->contact_id);
$this->view->commands = $commands->paginate(); $this->view->commands = $commands;
$notifications = $this->backend->select()->from('notification', array( $notifications = $this->backend->select()->from('notification', array(
'host', 'host_name',
'service', 'service_description',
'notification_output', 'notification_output',
'notification_contact', 'notification_contact_name',
'notification_start_time', 'notification_start_time',
'notification_state', 'notification_state',
'host_display_name', 'host_display_name',
@ -170,9 +168,9 @@ class Monitoring_ShowController extends Controller
)); ));
$notifications->where('contact_object_id', $contact->contact_object_id); $notifications->where('contact_object_id', $contact->contact_object_id);
$this->view->notifications = $notifications;
$this->view->compact = true; $this->setupLimitControl();
$this->view->notifications = $notifications->paginate(); $this->setupPaginationControl($this->view->notifications);
} }
$this->view->contact = $contact; $this->view->contact = $contact;

View File

@ -2,6 +2,7 @@
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
use Icinga\Module\Monitoring\Controller as MonitoringController; use Icinga\Module\Monitoring\Controller as MonitoringController;
use Icinga\Web\Widget\Tabextension\DashboardAction;
use Icinga\Web\Url; use Icinga\Web\Url;
class Monitoring_TacticalController extends MonitoringController class Monitoring_TacticalController extends MonitoringController
@ -18,7 +19,7 @@ class Monitoring_TacticalController extends MonitoringController
'label' => $this->translate('Tactical Overview'), 'label' => $this->translate('Tactical Overview'),
'url' => Url::fromRequest() 'url' => Url::fromRequest()
) )
)->activate('tactical_overview'); )->extend(new DashboardAction())->activate('tactical_overview');
$this->view->statusSummary = $this->backend->select()->from( $this->view->statusSummary = $this->backend->select()->from(
'statusSummary', 'statusSummary',

View File

@ -10,6 +10,7 @@ use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Timeline\TimeLine; use Icinga\Module\Monitoring\Timeline\TimeLine;
use Icinga\Module\Monitoring\Timeline\TimeRange; use Icinga\Module\Monitoring\Timeline\TimeRange;
use Icinga\Module\Monitoring\Web\Widget\SelectBox; use Icinga\Module\Monitoring\Web\Widget\SelectBox;
use Icinga\Web\Widget\Tabextension\DashboardAction;
class Monitoring_TimelineController extends Controller class Monitoring_TimelineController extends Controller
{ {
@ -22,7 +23,7 @@ class Monitoring_TimelineController extends Controller
'label' => $this->translate('Timeline'), 'label' => $this->translate('Timeline'),
'url' => Url::fromRequest() 'url' => Url::fromRequest()
) )
)->activate('timeline'); )->extend(new DashboardAction())->activate('timeline');
$this->view->title = $this->translate('Timeline'); $this->view->title = $this->translate('Timeline');
// TODO: filter for hard_states (precedence adjustments necessary!) // TODO: filter for hard_states (precedence adjustments necessary!)

View File

@ -215,8 +215,14 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
->setFeature($feature) ->setFeature($feature)
->setEnabled($enabled); ->setEnabled($enabled);
$this->getTransport($this->request)->send($toggleFeature); $this->getTransport($this->request)->send($toggleFeature);
if ($this->status->{$feature} != $enabled) {
Notification::success($enabled
? $this->translate('Enabling feature..')
: $this->translate('Disabling feature..')
);
}
} }
Notification::success($this->translate('Toggling feature..'));
return true; return true;
} }
} }

View File

@ -4,12 +4,13 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object; namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand; use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification; use Icinga\Web\Notification;
/** /**
* Form for deleting host or service comments * Form for deleting host or service comments
*/ */
class DeleteCommentCommandForm extends ObjectsCommandForm class DeleteCommentCommandForm extends CommandForm
{ {
/** /**
* (non-PHPDoc) * (non-PHPDoc)
@ -26,12 +27,22 @@ class DeleteCommentCommandForm extends ObjectsCommandForm
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$this->addElements(array( $this->addElements(
array(
array( array(
'hidden', 'hidden',
'comment_id', 'comment_id',
array( array(
'required' => true, 'required' => true,
'validators' => array('NotEmpty'),
'decorators' => array('ViewHelper')
)
),
array(
'hidden',
'comment_is_service',
array(
'filters' => array('Boolean'),
'decorators' => array('ViewHelper') 'decorators' => array('ViewHelper')
) )
), ),
@ -42,7 +53,8 @@ class DeleteCommentCommandForm extends ObjectsCommandForm
'decorators' => array('ViewHelper') 'decorators' => array('ViewHelper')
) )
) )
)); )
);
return $this; return $this;
} }
@ -74,14 +86,10 @@ class DeleteCommentCommandForm extends ObjectsCommandForm
*/ */
public function onSuccess() public function onSuccess()
{ {
foreach ($this->objects as $object) { $cmd = new DeleteCommentCommand();
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ $cmd->setIsService($this->getElement('comment_is_service')->getValue())
$delComment = new DeleteCommentCommand();
$delComment
->setObject($object)
->setCommentId($this->getElement('comment_id')->getValue()); ->setCommentId($this->getElement('comment_id')->getValue());
$this->getTransport($this->request)->send($delComment); $this->getTransport($this->request)->send($cmd);
}
$redirect = $this->getElement('redirect')->getValue(); $redirect = $this->getElement('redirect')->getValue();
if (! empty($redirect)) { if (! empty($redirect)) {
$this->setRedirectUrl($redirect); $this->setRedirectUrl($redirect);

View File

@ -0,0 +1,88 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification;
/**
* Form for deleting host or service comments
*/
class DeleteCommentsCommandForm extends CommandForm
{
/**
* The comments deleted on success
*
* @var array
*/
protected $comments;
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
*/
public function init()
{
$this->setAttrib('class', 'inline');
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/
public function createElements(array $formData = array())
{
$this->addElements(array(
array(
'hidden',
'redirect',
array('decorators' => array('ViewHelper'))
)
));
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
*/
public function getSubmitLabel()
{
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/
public function onSuccess()
{
foreach ($this->comments as $comment) {
$cmd = new DeleteCommentCommand();
$cmd->setCommentId($comment->id)
->setIsService(isset($comment->service_description));
$this->getTransport($this->request)->send($cmd);
}
$redirect = $this->getElement('redirect')->getValue();
if (! empty($redirect)) {
$this->setRedirectUrl($redirect);
}
Notification::success($this->translate('Deleting comment..'));
return true;
}
/**
* Set the comments to be deleted upon success
*
* @param array $comments
*
* @return this fluent interface
*/
public function setComments(array $comments)
{
$this->comments = $comments;
return $this;
}
}

View File

@ -4,12 +4,13 @@
namespace Icinga\Module\Monitoring\Forms\Command\Object; namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand; use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification; use Icinga\Web\Notification;
/** /**
* Form for deleting host or service downtimes * Form for deleting host or service downtimes
*/ */
class DeleteDowntimeCommandForm extends ObjectsCommandForm class DeleteDowntimeCommandForm extends CommandForm
{ {
/** /**
* (non-PHPDoc) * (non-PHPDoc)
@ -26,12 +27,22 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$this->addElements(array( $this->addElements(
array(
array( array(
'hidden', 'hidden',
'downtime_id', 'downtime_id',
array( array(
'required' => true, 'required' => true,
'validators' => array('NotEmpty'),
'decorators' => array('ViewHelper')
)
),
array(
'hidden',
'downtime_is_service',
array(
'filters' => array('Boolean'),
'decorators' => array('ViewHelper') 'decorators' => array('ViewHelper')
) )
), ),
@ -42,7 +53,8 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm
'decorators' => array('ViewHelper') 'decorators' => array('ViewHelper')
) )
) )
)); )
);
return $this; return $this;
} }
@ -74,19 +86,16 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm
*/ */
public function onSuccess() public function onSuccess()
{ {
foreach ($this->objects as $object) { $cmd = new DeleteDowntimeCommand();
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ $cmd->setDowntimeId($this->getElement('downtime_id')->getValue());
$delDowntime = new DeleteDowntimeCommand(); $cmd->setIsService($this->getElement('downtime_is_service')->getValue());
$delDowntime $this->getTransport($this->request)->send($cmd);
->setObject($object)
->setDowntimeId($this->getElement('downtime_id')->getValue());
$this->getTransport($this->request)->send($delDowntime);
}
$redirect = $this->getElement('redirect')->getValue(); $redirect = $this->getElement('redirect')->getValue();
if (! empty($redirect)) { if (! empty($redirect)) {
$this->setRedirectUrl($redirect); $this->setRedirectUrl($redirect);
} }
Notification::success($this->translate('Deleting downtime..')); Notification::success($this->translate('Deleting downtime.'));
return true; return true;
} }
} }

View File

@ -0,0 +1,88 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Forms\Command\Object;
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
use \Icinga\Module\Monitoring\Forms\Command\CommandForm;
use Icinga\Web\Notification;
/**
* Form for deleting host or service downtimes
*/
class DeleteDowntimesCommandForm extends CommandForm
{
/**
* The downtimes to delete on success
*
* @var array
*/
protected $downtimes;
/**
* (non-PHPDoc)
* @see \Zend_Form::init() For the method documentation.
*/
public function init()
{
$this->setAttrib('class', 'inline');
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/
public function createElements(array $formData = array())
{
$this->addElements(array(
array(
'hidden',
'redirect',
array('decorators' => array('ViewHelper'))
)
));
return $this;
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
*/
public function getSubmitLabel()
{
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
}
/**
* (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/
public function onSuccess()
{
foreach ($this->downtimes as $downtime) {
$delDowntime = new DeleteDowntimeCommand();
$delDowntime->setDowntimeId($downtime->id);
$delDowntime->setIsService(isset($downtime->service_description));
$this->getTransport($this->request)->send($delDowntime);
}
$redirect = $this->getElement('redirect')->getValue();
if (! empty($redirect)) {
$this->setRedirectUrl($redirect);
}
Notification::success($this->translate('Deleting downtime.'));
return true;
}
/**
* Set the downtimes to be deleted upon success
*
* @param type $downtimes
*
* @return $this
*/
public function setDowntimes(array $downtimes)
{
$this->downtimes = $downtimes;
return $this;
}
}

View File

@ -17,29 +17,20 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm
public function init() public function init()
{ {
$this->addDescription( $this->addDescription(
$this->translate( $this->translate('This command is used to send custom notifications about hosts or services.')
'This command is used to send custom notifications for hosts or'
. ' services.'
)
); );
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
*/ */
public function getSubmitLabel() public function getSubmitLabel()
{ {
return $this->translatePlural( return $this->translatePlural('Send custom notification', 'Send custom notifications', count($this->objects));
'Send custom notification',
'Send custom notifications',
count($this->objects)
);
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
@ -64,9 +55,8 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm
'label' => $this->translate('Forced'), 'label' => $this->translate('Forced'),
'value' => false, 'value' => false,
'description' => $this->translate( 'description' => $this->translate(
'If you check this option, a notification is sent' 'If you check this option, the notification is sent out regardless of time restrictions and'
. 'regardless of the current time and whether' . ' whether or not notifications are enabled.'
. ' notifications are enabled.'
) )
) )
), ),
@ -77,8 +67,7 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm
'label' => $this->translate('Broadcast'), 'label' => $this->translate('Broadcast'),
'value' => false, 'value' => false,
'description' => $this->translate( 'description' => $this->translate(
'If you check this option, a notification is sent to' 'If you check this option, the notification is sent out to all normal and escalated contacts.'
. ' all normal and escalated contacts.'
) )
) )
) )
@ -87,24 +76,24 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/ */
public function onSuccess() public function onSuccess()
{ {
foreach ($this->objects as $object) { foreach ($this->objects as $object) {
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
$comment = new SendCustomNotificationCommand(); $notification = new SendCustomNotificationCommand();
$comment->setObject($object); $notification
$comment->setComment($this->getElement('comment')->getValue()); ->setObject($object)
$comment->setAuthor($this->request->getUser()->getUsername()); ->setComment($this->getElement('comment')->getValue())
$comment->setForced($this->getElement('forced')->isChecked()); ->setAuthor($this->request->getUser()->getUsername())
$comment->setBroadcast($this->getElement('broadcast')->isChecked()); ->setForced($this->getElement('forced')->isChecked())
$this->getTransport($this->request)->send($comment); ->setBroadcast($this->getElement('broadcast')->isChecked());
$this->getTransport($this->request)->send($notification);
} }
Notification::success($this->translatePlural( Notification::success($this->translatePlural(
'Send custom notification..', 'Sending custom notification..',
'Send custom notifications..', 'Sending custom notifications..',
count($this->objects) count($this->objects)
)); ));
return true; return true;

View File

@ -30,7 +30,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : ''; $toggleDisabled = $this->hasPermission('monitoring/command/feature/object') ? null : '';
$this->addElements(array( $this->addElements(array(
array( array(
'checkbox', 'checkbox',

View File

@ -3,6 +3,10 @@
namespace Icinga\Module\Monitoring\Forms\Config; namespace Icinga\Module\Monitoring\Forms\Config;
use Exception;
use Icinga\Data\ConfigObject;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form;
use InvalidArgumentException; use InvalidArgumentException;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
@ -271,4 +275,63 @@ class BackendConfigForm extends ConfigForm
) )
); );
} }
/**
* Validate the ido instance schema resource
*
* @param Form $form
* @param ConfigObject $resourceConfig
*
* @return bool Whether validation succeeded or not
*/
public static function isValidIdoSchema(Form $form, ConfigObject $resourceConfig)
{
try {
$resource = ResourceFactory::createResource($resourceConfig);
$result = $resource->select()->from('icinga_dbversion', array('version'));
$result->fetchOne();
} catch (Exception $e) {
$form->addError(
$form->translate(
'IDO schema validation failed, it looks like that the IDO schema is missing in the given database.'
)
);
return false;
}
return true;
}
/**
* Validate the ido instance availability
*
* @param Form $form
* @param ConfigObject $resourceConfig
*
* @return bool Whether validation succeeded or not
*/
public static function isValidIdoInstance(Form $form, ConfigObject $resourceConfig)
{
$resource = ResourceFactory::createResource($resourceConfig);
$result = $resource->select()->from('icinga_instances', array('instance_name'));
$instances = $result->fetchAll();
if (count($instances) === 1) {
return true;
} elseif (count($instances) > 1) {
$form->warning(
$form->translate(
'IDO instance validation failed, because there are multiple instances available.'
)
);
return false;
}
$form->error(
$form->translate(
'IDO instance validation failed, because there is no IDO instance available.'
)
);
return false;
}
} }

View File

@ -3,6 +3,8 @@
namespace Icinga\Module\Monitoring\Forms\Setup; namespace Icinga\Module\Monitoring\Forms\Setup;
use Icinga\Data\ConfigObject;
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Forms\Config\Resource\DbResourceForm; use Icinga\Forms\Config\Resource\DbResourceForm;
@ -53,8 +55,21 @@ class IdoResourcePage extends Form
} }
if (false === isset($data['skip_validation']) || $data['skip_validation'] == 0) { if (false === isset($data['skip_validation']) || $data['skip_validation'] == 0) {
if (false === DbResourceForm::isValidResource($this)) { $configObject = new ConfigObject($this->getValues());
$this->addSkipValidationCheckbox(); if (false === DbResourceForm::isValidResource($this, $configObject)) {
$this->addSkipValidationCheckbox($this->translate(
'Check this to not to validate connectivity with the given database server'
));
return false;
} elseif (false === BackendConfigForm::isValidIdoSchema($this, $configObject)) {
$this->addSkipValidationCheckbox($this->translate(
'Check this to not to validate the ido schema'
));
return false;
} elseif (false === BackendConfigForm::isValidIdoInstance($this, $configObject)) {
$this->addSkipValidationCheckbox($this->translate(
'Check this to not to validate the ido instance'
));
return false; return false;
} }
} }
@ -65,17 +80,21 @@ class IdoResourcePage extends Form
/** /**
* Add a checkbox to the form by which the user can skip the connection validation * Add a checkbox to the form by which the user can skip the connection validation
*/ */
protected function addSkipValidationCheckbox() protected function addSkipValidationCheckbox($description = '')
{ {
if (empty($description)) {
$description = $this->translate(
'Proceed without any further (custom) validation'
);
}
$this->addElement( $this->addElement(
'checkbox', 'checkbox',
'skip_validation', 'skip_validation',
array( array(
'required' => true, 'required' => true,
'label' => $this->translate('Skip Validation'), 'label' => $this->translate('Skip Validation'),
'description' => $this->translate( 'description' => $description
'Check this to not to validate connectivity with the given database server'
)
) )
); );
} }

View File

@ -15,8 +15,12 @@ class Zend_View_Helper_Customvar extends Zend_View_Helper_Abstract
public function customvar($struct) public function customvar($struct)
{ {
if (is_string($struct) || is_int($struct) || is_float($struct)) { if (is_scalar($struct)) {
return $this->view->escape((string) $struct); return $this->view->escape(
is_string($struct)
? $struct
: var_export($struct, true)
);
} elseif (is_array($struct)) { } elseif (is_array($struct)) {
return $this->renderArray($struct); return $this->renderArray($struct);
} elseif (is_object($struct)) { } elseif (is_object($struct)) {
@ -38,7 +42,7 @@ class Zend_View_Helper_Customvar extends Zend_View_Helper_Abstract
protected function renderObject($object) protected function renderObject($object)
{ {
if (empty($object)) { if (0 === count((array) $object)) {
return '{}'; return '{}';
} }
$out = "{<ul>\n"; $out = "{<ul>\n";

View File

@ -1,12 +1,13 @@
<?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em;" class="dontprint"> <div style="float: right;" class="dontprint">
<?= $intervalBox; ?> <?= $intervalBox; ?>
</div> </div>
<?= $this->widget('limiter') ?> <?= $this->limiter; ?>
<?= $this->paginationControl($notifications, null, null, array('preserve' => $this->preserve)) ?> <?= $this->paginator; ?>
</div> </div>
<?php endif ?>
<div class="content alertsummary"> <div class="content alertsummary">
<!-- <h1><?= $this->translate('Alert summary'); ?></h1> --> <!-- <h1><?= $this->translate('Alert summary'); ?></h1> -->
@ -59,8 +60,7 @@
<div class="alertsummary-flex"> <div class="alertsummary-flex">
<?= $this->partial('list/notifications.phtml', array( <?= $this->partial('list/notifications.phtml', array(
'notifications' => $this->recentAlerts, 'notifications' => $this->recentAlerts,
'compact' => true, 'compact' => true
'inline' => true
)); ?> )); ?>
</div> </div>
</div> </div>
@ -71,8 +71,7 @@
<div class="alertsummary-flex"> <div class="alertsummary-flex">
<?= $this->partial('list/notifications.phtml', array( <?= $this->partial('list/notifications.phtml', array(
'notifications' => $this->notifications, 'notifications' => $this->notifications,
'compact' => true, 'compact' => true
'inline' => true
)); ?> )); ?>
</div> </div>
</div> </div>

View File

@ -0,0 +1,11 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtime-header.phtml'); ?>
</div>
<div class="content object-command">
<?= $delDowntimeForm; ?>
</div>

View File

@ -0,0 +1,81 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<div data-base-target='_next'>
<?= $this->render('partials/comment/comment-header.phtml'); ?>
</div>
</div>
<div class="content">
<h3><?= $this->translate('Comment detail information') ?></h3>
<table class="avp">
<tbody>
<tr data-base-target='_next'>
<?php if ($this->comment->objecttype === 'service'): ?>
<th> <?= $this->translate('Service') ?> </th>
<td>
<?= $this->icon('service', $this->translate('Service')); ?>
<?= $this->link()->service(
$this->comment->service_description,
$this->comment->service_display_name,
$this->comment->host_name,
$this->comment->host_display_name
);
?>
</td>
<?php else: ?>
<th> <?= $this->translate('Host') ?> </th>
<td>
<?= $this->icon('host', $this->translate('Host')); ?>
<?= $this->link()->host(
$this->comment->host_name,
$this->comment->host_display_name
);
?>
</td>
<?php endif ?>
</tr>
<tr>
<th><?= $this->translate('Author') ?></th>
<td><?= $this->icon('user', $this->translate('User')) ?> <?= $this->escape($this->comment->author) ?></td>
</tr>
<tr>
<th><?= $this->translate('Persistent') ?></th>
<td><?= $this->escape($this->comment->persistent) ? $this->translate('Yes') : $this->translate('No') ?></td>
</tr>
<tr>
<th><?= $this->translate('Created') ?></th>
<td><?= date('d.m.y H:i' ,$this->escape($this->comment->timestamp)) ?></td>
</tr>
<tr>
<th><?= $this->translate('Expires') ?></th>
<td>
<?= $this->comment->expiration ? sprintf(
$this->translate('This comment expires on %s at %s.'),
date('d.m.y', $this->comment->expiration),
date('H:i', $this->comment->expiration)
) : $this->translate('This comment does not expire.');
?>
</td>
</tr>
<?php if (isset($delCommentForm)): // Form is unset if the current user lacks the respective permission ?>
<tr class="newsection">
<th><?= $this->translate('Commands') ?></th>
<td>
<?= $delCommentForm ?>
</td>
</tr>
<?php endif ?>
</tbody>
</table>
</div>

View File

@ -0,0 +1,12 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/comment/comments-header.phtml'); ?>
</div>
<div class="content object-command">
<?= $delCommentForm ?>
</div>

View File

@ -0,0 +1,34 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<div data-base-target='_next'>
<?= $this->render('partials/comment/comments-header.phtml'); ?>
</div>
</div>
<div class="content">
<h3><?= $this->icon('reschedule') ?> <?= $this->translate('Commands') ?> </h3>
<p>
<?= sprintf(
$this->translate('Issue commands to all %s selected comments.'),
'<b>' . count($comments) . '</b>'
)
?>
<div>
<?= $this->qlink(
sprintf(
$this->translate('Remove all %d scheduled comments'),
count($comments)
),
$removeAllLink,
null,
array(
'icon' => 'trash',
'title' => $this->translate('Remove all selected comments.')
)
) ?>
</div>
</p>
</div>

View File

@ -0,0 +1,11 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtime-header.phtml'); ?>
</div>
<div class="content object-command">
<?= $delDowntimeForm; ?>
</div>

View File

@ -0,0 +1,121 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtime-header.phtml'); ?>
</div>
<div class="content">
<h3><?= $this->translate('Downtime detail information') ?></h3>
<table class="avp">
<tbody>
<tr>
<th>
<?= $this->isService ? $this->translate('Service') : $this->translate('Host') ?>
</th>
<td data-base-target="_next">
<?php if ($this->isService): ?>
<?php
$link = $this->link()->service(
$downtime->service_description,
$downtime->service_display_name,
$downtime->host_name,
$downtime->host_display_name
);
$icon = $this->icon('service', $this->translate('Service'));
?>
<?php else: ?>
<?php
$icon = $this->icon('host', $this->translate('Host'));
$link = $this->link()->host($downtime->host_name, $downtime->host_display_name)
?>
<?php endif ?>
<?= $icon ?>
<?= $link ?>
</td>
</tr>
<tr title="<?= $this->translate('The name of the person who scheduled this downtime'); ?>">
<th><?= $this->translate('Author') ?></th>
<td><?= $this->icon('user', $this->translate('User')) ?> <?= $this->escape($this->downtime->author_name) ?></td>
</tr>
<tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>">
<th><?= $this->translate('Comment') ?></th>
<td><?= $this->icon('comment', $this->translate('Comment')) ?> <?= $this->escape($this->downtime->comment) ?></td>
</tr>
<tr title="<?= $this->translate('Date and time this downtime was entered'); ?>">
<th><?= $this->translate('Entry Time') ?></th>
<td> <?= date('d.m.y H:i' ,$this->escape($this->downtime->entry_time)) ?></td>
</tr>
<tr class="newsection">
<th><?= $this->escape(
$this->downtime->is_flexible ?
$this->translate('Flexible') : $this->translate('Fixed')
); ?></th>
<td>
<?= $this->escape(
$this->downtime->is_flexible ?
$this->translate('Flexible downtimes have a hard start and end time,'
. ' but also an additional restriction on the duration in which '
. ' the host or service may actually be down.') :
$this->translate('Fixed downtimes have a static start and end time.')
); ?>
</td>
</tr>
<tr title="<?= $this->translate('The date/time the scheduled downtime is'
. ' supposed to start. If this is a flexible (non-fixed) downtime, '
. 'this refers to the earliest possible time that the downtime'
. ' can start'); ?>">
<th><?= $this->translate('Scheduled start') ?></th>
<td><?= date('d.m.y H:i', $this->downtime->scheduled_start) ?></td>
</tr>
<tr title="<?= $this->translate('The date/time the scheduled downtime is '
. 'supposed to end. If this is a flexible (non-fixed) downtime, '
. 'this refers to the last possible time that the downtime can '
. 'start'); ?>">
<th><?= $this->translate('Scheduled end') ?></th>
<td><?= date('d.m.y H:i', $this->downtime->scheduled_end) ?></td>
</tr>
<?php if ($this->downtime->is_flexible): ?>
<tr title="<?= $this->translate('Indicates the number of seconds that the '
. 'scheduled downtime should last. This is usually only needed if'
. ' this is a flexible downtime, which can start at a variable '
. 'time, but lasts for the specified duration'); ?>">
<th tit><?= $this->translate('Duration') ?></th>
<td><?= $this->format()->duration($this->escape($this->downtime->duration)); ?></td>
</tr>
<tr title="<?= $this->translate('he date/time the scheduled downtime was'
. ' actually started'); ?>">
<th><?= $this->translate('Actual start time') ?></th>
<td><?= date('d.m.y H:i', $downtime->start); ?></td>
</tr>
<tr title="<?= $this->translate('The date/time the scheduled downtime '
. 'actually ended'); ?>">
<th><?= $this->translate('Actual end time') ?></th>
<td><?= date('d.m.y H:i', $downtime->end); ?></td>
</tr>
<?php endif; ?>
<tr class="newsection">
<th><?= $this->translate('In effect') ?></th>
<td>
<?= $this->escape(
$this->downtime->is_in_effect ?
$this->translate('Yes') : $this->translate('No')
);
?>
</td>
</tr>
<?php if (isset($delDowntimeForm)): // Form is unset if the current user lacks the respective permission ?>
<tr class="newsection">
<th><?= $this->translate('Commands') ?></th>
<td>
<?= $delDowntimeForm ?>
</td>
</tr>
<?php endif ?>
</tbody>
</table>
</div>

View File

@ -0,0 +1,12 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtimes-header.phtml'); ?>
</div>
<div class="content object-command">
<?= $delDowntimeForm ?>
</div>

View File

@ -0,0 +1,33 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtimes-header.phtml'); ?>
</p>
</div>
<div class="content">
<h3><?= $this->icon('reschedule') ?> <?= $this->translate('Commands') ?> </h3>
<p>
<?= sprintf(
$this->translate('Issue commands to all %s selected downtimes.'),
'<b>' . count($downtimes) . '</b>'
)
?>
<div>
<?= $this->qlink(
sprintf(
$this->translate('Remove all %d scheduled downtimes'),
count($downtimes)
),
$removeAllLink,
null,
array(
'icon' => 'trash',
'title' => $this->translate('Remove all selected downtimes.')
)
) ?>
</div>
</p>
</div>

View File

@ -1,4 +1,7 @@
<div class="controls"> <div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/host/object-header.phtml') ?> <?= $this->render('partials/host/object-header.phtml') ?>
<?= $this->render('partials/host/servicesummary.phtml') ?> <?= $this->render('partials/host/servicesummary.phtml') ?>
</div> </div>

View File

@ -1,9 +1,12 @@
<div class="controls"> <div class="controls">
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<?= $this->render('partials/host/objects-header.phtml'); ?> <?= $this->render('partials/host/objects-header.phtml'); ?>
</div> </div>
<div class="content"> <div class="content">
<?php if (($hostCount = count($objects)) === 0): ?> <?php if (($hostCount = count($objects)) === 0): ?>
<?= $this->translate('No hosts matching the filter'); ?> <?= $this->translate('No hosts found matching the filter'); ?>
<?php else: ?> <?php else: ?>
<h3><?= sprintf($this->translatePlural('%u Host', '%u Hosts', $hostCount), $hostCount); ?></h3> <h3><?= sprintf($this->translatePlural('%u Host', '%u Hosts', $hostCount), $hostCount); ?></h3>
<div><?= $this->qlink( <div><?= $this->qlink(

View File

@ -1,66 +1,70 @@
<?php if (false === $this->compact): ?> <?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs->render($this); ?> <?= $this->tabs; ?>
<div style="margin: 1em" class="dontprint"> <div class="dontprint">
<?= $this->translate('Sort by'); ?> <?= $this->sortControl->render($this); ?> <?= $this->render('list/components/selectioninfo.phtml'); ?>
</div> </div>
<?= $this->widget('limiter', array('url' => $this->url, 'max' => $comments->count())); ?> <div class="tinystatesummary">
<?= $this->paginationControl($comments, null, null, array('preserve' => $this->preserve)); ?> <?= count($comments) ?> <?= $this->translate('Comments') ?>:
</div>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?php if (count($comments) === 0): ?>
<?= $this->translate('No comments matching the filter'); ?>
</div>
<?php return; endif ?>
<table data-base-target="_next" class="action comments">
<tbody>
<?php foreach ($comments as $comment): ?>
<?php <?php
switch ($comment->type) {
case 'flapping': if (count($comments) === 0) {
$icon = 'flapping'; echo $this->translate('No comments found matching the filter') . '</div>';
$title = $this->translate('Flapping'); return;
$tooltip = $this->translate('Comment was caused by a flapping host or service.');
break;
case 'comment':
$icon = 'user';
$title = $this->translate('User Comment');
$tooltip = $this->translate('Comment was created by an user.');
break;
case 'downtime':
$icon = 'plug';
$title = $this->translate('Downtime');
$tooltip = $this->translate('Comment was caused by a downtime.');
case 'ack':
$icon = 'ok';
$title = $this->translate('Acknowledgement');
$tooltip = $this->translate('Comment was caused by an acknowledgement.');
} }
?> ?>
<table data-base-target="_next"
class="action comments multiselect"
data-icinga-multiselect-url="/icingaweb2/monitoring/comments/show"
data-icinga-multiselect-data="comment_id">
<tbody>
<?php foreach ($comments as $comment):
$this->comment = $comment; ?>
<tr class="state invalid"> <tr class="state invalid">
<td class="state" style="width: 12em;"> <td class="state" style="width: 12em;">
<?= $this->icon($icon, $tooltip) ?> <?= $this->render('partials/comment/comment-description.phtml'); ?>
<br>
<strong><?= $this->escape($title); ?></strong>
<br>
<?= $this->prefixedTimeSince($comment->timestamp); ?>
</td> </td>
<td> <td>
<?php if ($comment->objecttype === 'service'): ?> <?php if ($comment->objecttype === 'service'): ?>
<?= $this->icon('service', $this->translate('Service')); ?> <?= $this->icon('service', $this->translate('Service')); ?>
<?= $this->link()->service(
$comment->service, $comment->service_display_name, $comment->host, $comment->host_display_name <?= $this->qlink(
) ?> sprintf(
$this->translate('%s on %s', 'Service running on host'),
$comment->service_display_name,
$comment->host_display_name
),
'monitoring/comment/show',
array('comment_id' => $comment->id),
array('title' => sprintf(
$this->translate('Show detailed information for comment on %s for %s'),
$comment->service_display_name,
$comment->host_display_name
))) ?>
<?php else: ?> <?php else: ?>
<?= $this->icon('host', $this->translate('Host')); ?> <?= $this->icon('host', $this->translate('Host')); ?>
<?= $this->link()->host($comment->host, $comment->host_display_name) ?>
<?= $this->qlink(
$comment->host_display_name,
'monitoring/comment/show',
array('comment_id' => $comment->id),
array('title' => sprintf(
$this->translate('Show detailed information for comment on %s'),
$comment->host_display_name
))) ?>
<?php endif ?> <?php endif ?>
<br> <br>
<?= $this->icon('comment', $this->translate('Comment')); ?> <?= isset($comment->author) <?= $this->icon('comment', $this->translate('Comment')); ?> <?= isset($comment->author)
? '[' . $comment->author . '] ' ? '[' . $this->escape($comment->author) . '] '
: ''; : '';
?><?= $this->escape($comment->comment); ?> ?><?= $this->escape($comment->comment); ?>
<br> <br>
@ -79,12 +83,12 @@
<td style="width: 2em" data-base-target="self"> <td style="width: 2em" data-base-target="self">
<?php <?php
$delCommentForm = clone $delCommentForm; $delCommentForm = clone $delCommentForm;
$delCommentForm->populate(array('comment_id' => $comment->id, 'redirect' => $this->url)); $delCommentForm->populate(
if ($comment->objecttype === 'host') { array(
$delCommentForm->setAction($this->url('monitoring/host/delete-comment', array('host' => $comment->host))); 'comment_id' => $comment->id,
} else { 'comment_is_service' => isset($comment->service_description)
$delCommentForm->setAction($this->url('monitoring/service/delete-comment', array('host' => $comment->host, 'service' => $comment->service))); )
} );
echo $delCommentForm; echo $delCommentForm;
?> ?>
</td> </td>

View File

@ -1,17 +1,22 @@
<?php if (! $this->compact): ?> <?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<div class="boxview" data-base-target="_next">
<?php <?php
if (count($groupData) === 0) {
echo mt('monitoring', 'No contacts matching the filter');
}
foreach ($groupData as $groupName => $groupInfo): ?> if (count($groupData) === 0) {
echo $this->translate('No contactgroups found matching the filter') . '</div>';
return;
}
?>
<div class="boxview" data-base-target="_next">
<?php foreach ($groupData as $groupName => $groupInfo): ?>
<div class="box contactgroup"> <div class="box contactgroup">
<h2><?= $groupInfo['alias']; ?></h2> <h2><?= $groupInfo['alias']; ?></h2>
<?php if ($groupInfo['alias'] !== $groupName): ?> <?php if ($groupInfo['alias'] !== $groupName): ?>
@ -24,7 +29,7 @@ foreach ($groupData as $groupName => $groupInfo): ?>
<?= $this->qlink( <?= $this->qlink(
$c->contact_alias, $c->contact_alias,
'monitoring/show/contact', 'monitoring/show/contact',
array('contact' => $c->contact_name), array('contact_name' => $c->contact_name),
array('title' => sprintf( array('title' => sprintf(
$this->translate('Show detailed information about %s'), $this->translate('Show detailed information about %s'),
$c->contact_alias $c->contact_alias

View File

@ -1,24 +1,27 @@
<?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em"> <?= $this->sortBox; ?>
<?= $this->sortControl->render($this); ?> <?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?= $this->paginationControl($contacts, null, null, array('preserve' => $this->preserve)); ?> <?php endif ?>
</div>
<div data-base-target="_next" class="content contacts"> <div data-base-target="_next" class="content contacts">
<?php <?php
if (count($contacts) === 0) { if (count($contacts) === 0) {
echo $this->translate('No contacts matching the filter'); echo $this->translate('No contacts found matching the filter') . '</div>';
return; return;
} }
foreach ($contacts as $contact): ?> ?>
<?php foreach ($contacts as $contact): ?>
<div class="contact"> <div class="contact">
<?= $this->img('/static/gravatar', array('email' => $contact->contact_email)); ?> <?= $this->img('/static/gravatar', array('email' => $contact->contact_email)); ?>
<strong><?= $this->qlink( <strong><?= $this->qlink(
$contact->contact_name, $contact->contact_name,
'monitoring/show/contact', 'monitoring/show/contact',
array('contact' => $contact->contact_name), array('contact_name' => $contact->contact_name),
array('title' => sprintf( array('title' => sprintf(
$this->translate('Show detailed information about %s'), $this->translate('Show detailed information about %s'),
$contact->contact_alias $contact->contact_alias

View File

@ -1,36 +1,39 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
?> if (! $this->compact): ?>
<?php if (false === $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs->render($this); ?> <?= $this->tabs; ?>
<div style="margin: 1em" class="dontprint"> <div class="dontprint">
<?= $this->translate('Sort by'); ?> <?= $this->sortControl->render($this); ?> <?= $this->render('list/components/selectioninfo.phtml'); ?>
<?php if (! $this->filterEditor): ?>
<?= $this->filterPreview ?>
<?php endif; ?>
</div> </div>
<?= $this->widget('limiter', array('url' => $this->url, 'max' => $downtimes->count())); ?> <div class="tinystatesummary">
<?= $this->paginationControl($downtimes, null, null, array('preserve' => $this->preserve)); ?> <?= count($downtimes) ?> <?= $this->translate('Downtimes') ?>
</div>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?= $this->filterEditor ?> <?php
<?php if (count($downtimes) === 0): ?>
<?= $this->translate('No active downtimes'); ?>
</div>
<?php return; endif ?>
<table data-base-target="_next" class="action"> if (count($downtimes) === 0) {
echo $this->translate('No downtimes found matching the filter,'
. ' maybe the downtime already expired.') . '</div>';
return;
}
?>
<table data-base-target="_next"
class="action multiselect"
data-icinga-multiselect-url="/icingaweb2/monitoring/downtimes/show"
data-icinga-multiselect-data="downtime_id">
<tbody> <tbody>
<?php foreach ($downtimes as $downtime): ?> <?php foreach ($downtimes as $downtime): ?>
<?php <?php
if (isset($downtime->service)) { if (isset($downtime->service_description)) {
$isService = true; $isService = true;
$stateName = Service::getStateText($downtime->service_state); $stateName = Service::getStateText($downtime->service_state);
} else { } else {
@ -54,23 +57,30 @@ use Icinga\Module\Monitoring\Object\Service;
?> ?>
</td> </td>
<td> <td>
<?php if ($isService): ?> <?php
<?= $this->icon('service', $this->translate('Service')); ?> if ($isService) {
<?= $this->link()->service( echo $this->icon('service');
$downtime->service, $downtime->service_display_name, $downtime->host, $downtime->host_display_name } else {
) ?> echo $this->icon('host');
<?php else: ?> }
<?= $this->icon('host', $this->translate('Host')); ?> ?>
<?= $this->link()->host($downtime->host, $downtime->host_display_name) ?> <?= $this->qlink(
<?php endif ?> sprintf($this->translate('%s on %s', 'Service running on host'), $downtime->service_display_name, $downtime->host_display_name),
'monitoring/downtime/show',
array('downtime_id' => $downtime->id),
array('title' => sprintf(
$this->translate('Show detailed information for downtime on %s for %s'),
$downtime->service_display_name,
$downtime->host_display_name
))) ?>
<br> <br>
<?= $this->icon('comment', $this->translate('Comment')); ?> [<?= $this->escape($downtime->author) ?>] <?= $this->escape($downtime->comment) ?> <?= $this->icon('comment', $this->translate('Comment')); ?> [<?= $this->escape($downtime->author_name) ?>] <?= $this->escape($downtime->comment) ?>
<br> <br>
<small> <small>
<?php if ($downtime->is_flexible): ?> <?php if ($downtime->is_flexible): ?>
<?php if ($downtime->is_in_effect): ?> <?php if ($downtime->is_in_effect): ?>
<?= sprintf( <?= sprintf(
isset($downtime->service) $isService
? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.') ? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.')
: $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'), : $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'),
date('d.m.y', $downtime->start), date('d.m.y', $downtime->start),
@ -81,7 +91,7 @@ use Icinga\Module\Monitoring\Object\Service;
); ?> ); ?>
<?php else: ?> <?php else: ?>
<?= sprintf( <?= sprintf(
isset($downtime->service) $isService
? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.') ? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.')
: $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'), : $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'),
date('d.m.y H:i', $downtime->scheduled_start), date('d.m.y H:i', $downtime->scheduled_start),
@ -92,7 +102,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php else: ?> <?php else: ?>
<?php if ($downtime->is_in_effect): ?> <?php if ($downtime->is_in_effect): ?>
<?= sprintf( <?= sprintf(
isset($downtime->service) $isService
? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.') ? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.')
: $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'), : $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'),
date('d.m.y', $downtime->start), date('d.m.y', $downtime->start),
@ -102,7 +112,7 @@ use Icinga\Module\Monitoring\Object\Service;
); ?> ); ?>
<?php else: ?> <?php else: ?>
<?= sprintf( <?= sprintf(
isset($downtime->service) $isService
? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.') ? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.')
: $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'), : $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
date('d.m.y', $downtime->scheduled_start), date('d.m.y', $downtime->scheduled_start),
@ -118,12 +128,12 @@ use Icinga\Module\Monitoring\Object\Service;
<td style="width: 2em" data-base-target="self"> <td style="width: 2em" data-base-target="self">
<?php <?php
$delDowntimeForm = clone $delDowntimeForm; $delDowntimeForm = clone $delDowntimeForm;
$delDowntimeForm->populate(array('downtime_id' => $downtime->id, 'redirect' => $this->url)); $delDowntimeForm->populate(
if (! isset($downtime->service)) { array(
$delDowntimeForm->setAction($this->url('monitoring/host/delete-downtime', array('host' => $downtime->host))); 'downtime_id' => $downtime->id,
} else { 'downtime_is_service' => isset($downtime->service_description)
$delDowntimeForm->setAction($this->url('monitoring/service/delete-downtime', array('host' => $downtime->host, 'service' => $downtime->service))); )
} );
echo $delDowntimeForm; echo $delDowntimeForm;
?> ?>
</td> </td>

View File

@ -1,21 +1,25 @@
<?php <?php
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Web\Widget\Chart\HistoryColorGrid; use Icinga\Web\Widget\Chart\HistoryColorGrid;
?>
if (! $this->compact): ?>
<? if (! $compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs->render($this); ?> <?= $this->tabs; ?>
<div class="fake-controls"> <?= $this->sortBox; ?>
<?= $form ?> <?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
<?= $form; ?>
</div> </div>
</div> <?php endif ?>
<? endif; ?>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<?php <?php
if (count($summary) === 0) {
echo $this->translate('No state changes in the selected time period.') . '</div>';
return;
}
$settings = array( $settings = array(
'cnt_up' => array( 'cnt_up' => array(
'tooltip' => $this->translate('%d hosts ok on %s'), 'tooltip' => $this->translate('%d hosts ok on %s'),
@ -63,11 +67,8 @@ $to = intval($form->getValue('to', time()));
if ($to - $from > 315360000) { if ($to - $from > 315360000) {
$from = $to - 315360000; $from = $to - 315360000;
} }
$data = array();
if (count($summary) === 0) { $data = array();
echo $this->translate('No state changes in the selected time period.');
}
foreach ($summary as $entry) { foreach ($summary as $entry) {
$day = $entry->day; $day = $entry->day;
$value = $entry->$column; $value = $entry->$column;

View File

@ -1,32 +1,23 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
?> if (! $this->compact): ?>
<?php if (false === $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em" class="dontprint"> <?= $this->sortBox; ?>
<div style="float: right"> <?= $this->limiter; ?>
<?= $this->translate('Sort by') ?> <?= $this->sortControl ?> <?= $this->paginator; ?>
</div> <?= $this->filterEditor; ?>
</div>
<?= $this->widget('limiter', array('url' => $this->url, 'max' => $this->history->count())); ?>
<?= $this->paginationControl($history, null, null, array('preserve' => $this->preserve)); ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?= $this->filterEditor ?> <?php
<?php if (empty($history)): ?> if (count($history) === 0) {
<?= $this->translate('No history events matching the filter') ?> echo $this->translate('No history events found matching the filter') . '</div>';
</div> return;
<?php return; endif ?> }
?>
<table data-base-target="_next" class="action"> <table data-base-target="_next" class="action">
<tbody> <tbody>
<?php foreach ($history as $event): ?> <?php foreach ($history as $event): ?>
@ -34,7 +25,7 @@ use Icinga\Module\Monitoring\Object\Service;
$icon = 'help'; $icon = 'help';
$title = $event->type; $title = $event->type;
$stateName = 'invalid'; $stateName = 'invalid';
$isService = isset($event->service); $isService = isset($event->service_description);
switch ($event->type) { switch ($event->type) {
case 'notify': case 'notify':
$icon = 'bell'; $icon = 'bell';
@ -99,10 +90,10 @@ use Icinga\Module\Monitoring\Object\Service;
<td> <td>
<?php if ($isService): ?> <?php if ($isService): ?>
<?= $this->link()->service( <?= $this->link()->service(
$event->service, $event->service_display_name, $event->host, $event->host_display_name $event->service_description, $event->service_display_name, $event->host_name, $event->host_display_name
) ?> ) ?>
<?php else: ?> <?php else: ?>
<?= $this->link()->host($event->host, $event->host_display_name) ?> <?= $this->link()->host($event->host_name, $event->host_display_name) ?>
<?php endif ?> <?php endif ?>
<br> <br>
<div> <div>

View File

@ -1,25 +1,24 @@
<?php if ($this->compact): ?>
<div class="content">
<?php else: ?>
<div class="controls">
<?= $this->tabs ?>
<div style="margin: 1em;" class="dontprint">
<?= $this->translate('Sort by'); ?> <?= $this->sortControl->render($this); ?>
</div>
<?= $this->widget('limiter')->setMaxLimit(count($hostgroups)); ?>
<?= $this->paginationControl($hostgroups, null, null, array('preserve' => $this->preserve)); ?>
</div>
<div class="content">
<?= $this->filterEditor; ?>
<?php endif ?>
<?php <?php
use Icinga\Module\Monitoring\Object\Host;
if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs; ?>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div>
<?php endif ?>
<div class="content">
<?php
if (count($hostgroups) === 0) { if (count($hostgroups) === 0) {
echo $this->translate('No host groups matching the filter'); echo $this->translate('No hostgroups found matching the filter') . '</div>';
echo '</div>';
return; return;
} }
?> ?>
<table class="groupview" data-base-target="_next"> <table class="groupview action" data-base-target="_next">
<thead> <thead>
<th><?= $this->translate('Last Problem'); ?></th> <th><?= $this->translate('Last Problem'); ?></th>
<th><?= $this->translate('Host Group'); ?></th> <th><?= $this->translate('Host Group'); ?></th>
@ -27,62 +26,45 @@
<th><?= $this->translate('Service States'); ?></th> <th><?= $this->translate('Service States'); ?></th>
</thead> </thead>
<tbody> <tbody>
<?php foreach ($hostgroups as $h): ?> <?php foreach ($hostgroups as $h):
<tr href="<?= $this->href('monitoring/list/hosts', array('hostgroup' => $h->hostgroup)) ?>"> if ($h->hosts_down_unhandled) {
<?php if ($h->services_critical_last_state_change_unhandled): ?> $handled = false;
<td class="state change critical unhandled"> $state = Host::STATE_DOWN;
<strong><?= $this->translate('CRITICAL'); ?></strong> $lastStateChange = $h->hosts_down_last_state_change_unhandled;
} elseif ($h->hosts_unreachable_unhandled) {
$handled = false;
$state = Host::STATE_UNREACHABLE;
$lastStateChange = $h->hosts_unreachable_last_state_change_unhandled;
} else {
$handled = true;
if ($h->hosts_down_handled) {
$state = Host::STATE_DOWN;
$lastStateChange = $h->hosts_down_last_state_change_handled;
} elseif ($h->hosts_unreachable_handled) {
$state = Host::STATE_UNREACHABLE;
$lastStateChange = $h->hosts_unreachable_last_state_change_handled;
} elseif ($h->hosts_up) {
$state = Host::STATE_UP;
$lastStateChange = $h->hosts_up_last_state_change;
} else {
$state = Host::STATE_PENDING;
$lastStateChange = $h->hosts_pending_last_state_change;
}
}
?>
<tr class="state <?= Host::getStateText($state) ?><?= $handled ? ' handled' : '' ?>" href="<?=
$this->href('monitoring/list/hosts', array('hostgroup_name' => $h->hostgroup_name))
?>">
<td class="state">
<strong><?= Host::getStateText($state, true); ?></strong>
<br> <br>
<?= $this->prefixedTimeSince($h->services_critical_last_state_change_unhandled); ?> <?= $this->prefixedTimeSince($lastStateChange); ?>
</td> </td>
<?php elseif ($h->services_unknown_last_state_change_unhandled): ?>
<td class="state change unknown unhandled">
<strong><?= $this->translate('UNKNOWN'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_unknown_last_state_change_unhandled); ?>
</td>
<?php elseif ($h->services_warning_last_state_change_unhandled): ?>
<td class="state change warning unhandled">
<strong><?= $this->translate('WARNING'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_warning_last_state_change_unhandled); ?>
</td>
<?php elseif ($h->services_critical_last_state_change_handled): ?>
<td class="state change critical">
<strong><?= $this->translate('CRITICAL'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_critical_last_state_change_handled); ?>
</td>
<?php elseif ($h->services_unknown_last_state_change_handled): ?>
<td class="state change unknown">
<strong><?= $this->translate('UNKNOWN'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_unknown_last_state_change_handled); ?>
</td>
<?php elseif ($h->services_warning_last_state_change_handled): ?>
<td class="state change warning">
<strong><?= $this->translate('WARNING'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_warning_last_state_change_handled); ?>
</td>
<?php elseif ($h->services_ok_last_state_change): ?>
<td class="state change ok">
<strong><?= $this->translate('OK'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_ok_last_state_change); ?>
</td>
<?php else: ?>
<td class="state change pending">
<strong><?= $this->translate('PENDING'); ?></strong>
<br>
<?= $this->prefixedTimeSince($h->services_pending_last_state_change); ?>
</td>
<?php endif ?>
<td class="groupname"> <td class="groupname">
<?= $this->qlink( <?= $this->qlink(
$h->hostgroup_alias, $h->hostgroup_alias,
'monitoring/list/hosts', 'monitoring/list/hosts',
array('hostgroup' => $h->hostgroup), array('hostgroup_name' => $h->hostgroup_name),
array('title' => sprintf($this->translate('List all hosts in the group "%s"'), $h->hostgroup_alias)) array('title' => sprintf($this->translate('List all hosts in the group "%s"'), $h->hostgroup_alias))
); ?> ); ?>
</td> </td>
@ -90,14 +72,14 @@
<?= $this->qlink( <?= $this->qlink(
$h->services_total, $h->services_total,
'monitoring/list/services', 'monitoring/list/services',
array('hostgroup' => $h->hostgroup), array('hostgroup_name' => $h->hostgroup_name),
array('title' => sprintf( array('title' => sprintf(
$this->translate('List all services of all hosts in host group "%s"'), $this->translate('List all services of all hosts in host group "%s"'),
$h->hostgroup_alias $h->hostgroup_alias
)) ))
); ?> ); ?>
</td> </td>
<td class="state"> <td>
<?php if ($h->services_ok): ?> <?php if ($h->services_ok): ?>
<span class="state ok"> <span class="state ok">
<?= $this->qlink( <?= $this->qlink(
@ -105,7 +87,7 @@
'monitoring/list/services', 'monitoring/list/services',
array( array(
'service_state' => 0, 'service_state' => 0,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -132,7 +114,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -156,7 +138,7 @@
array( array(
'service_state' => 2, 'service_state' => 2,
'service_handled' => 1, 'service_handled' => 1,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -186,7 +168,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -210,7 +192,7 @@
array( array(
'service_state' => 3, 'service_state' => 3,
'service_handled' => 1, 'service_handled' => 1,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -240,7 +222,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -264,7 +246,7 @@
array( array(
'service_state' => 1, 'service_state' => 1,
'service_handled' => 1, 'service_handled' => 1,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -291,7 +273,7 @@
'monitoring/list/services', 'monitoring/list/services',
array( array(
'service_state' => 99, 'service_state' => 99,
'hostgroup' => $h->hostgroup, 'hostgroup_name' => $h->hostgroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(

View File

@ -1,33 +1,25 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
if ($this->compact): ?> if (! $this->compact): ?>
<div class="content">
<?php else: ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em;" class="dontprint"> <div class="dontprint">
<?= $this->render('list/components/selectioninfo.phtml') ?> <?= $this->render('list/components/selectioninfo.phtml'); ?>
<?= $this->render('list/components/hostssummary.phtml') ?> <?= $this->render('list/components/hostssummary.phtml'); ?>
<?= $this->translate('Sort by') ?> <?= $this->sortControl->render($this) ?>
</div> </div>
<?= $this->sortBox; ?>
<?= $this->widget('limiter')->setMaxLimit($this->hosts->count()) ?> <?= $this->limiter; ?>
<?= $this->paginationControl($hosts, null, null, array('preserve' => $this->preserve)) ?> <?= $this->paginator; ?>
<?= $this->selectionToolbar('multi', $this->href('monitoring/hosts/show?' . $this->filter->toQueryString())) ?> <?= $this->selectionToolbar('multi', $this->href('monitoring/hosts/show?' . $this->filter->toQueryString())); ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?>
<div class="content"> <div class="content">
<?= $this->filterEditor ?>
<?php <?php
endif; if (count($hosts) === 0) {
echo $this->translate('No hosts found matching the filter') . '</div>';
if ($hosts->count() === 0) {
echo $this->translate('No hosts matching the filter');
if (! $this->compact) {
echo '</div>';
}
return; return;
} }
?> ?>

View File

@ -1,30 +1,28 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
?> if (! $this->compact): ?>
<?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div class="dontprint" style="margin: 1em;"> <?= $this->sortBox; ?>
<?= $this->translate('Sort by') ?> <?= $this->sortControl->render($this) ?> <?= $this->limiter; ?>
</div> <?= $this->paginator; ?>
<?= $this->widget('limiter') ?> <?= $this->filterEditor; ?>
<?= $this->paginationControl($notifications, null, null, array('preserve' => $this->preserve)) ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?php if (count($notifications) === 0): ?> <?php
<?= $this->translate('No notifications matching the filter') ?>
<?php return; endif ?>
if (count($notifications) === 0) {
echo $this->translate('No notifications found matching the filter') . '</div>';
return;
}
?>
<table data-base-target="_next" class="action"> <table data-base-target="_next" class="action">
<tbody> <tbody>
<?php foreach ($notifications as $notification): <?php foreach ($notifications as $notification):
if (isset($notification->service)) { if (isset($notification->service_description)) {
$isService = true; $isService = true;
$stateName = Service::getStateText($notification->notification_state); $stateName = Service::getStateText($notification->notification_state);
} else { } else {
@ -44,14 +42,14 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($isService): ?> <?php if ($isService): ?>
<?= $this->icon('service', $this->translate('Service')); ?> <?= $this->icon('service', $this->translate('Service')); ?>
<?= $this->link()->service( <?= $this->link()->service(
$notification->service, $notification->service_description,
$notification->service_display_name, $notification->service_display_name,
$notification->host, $notification->host_name,
$notification->host_display_name $notification->host_display_name
) ?> ) ?>
<?php else: ?> <?php else: ?>
<?= $this->icon('host', $this->translate('Host')); ?> <?= $this->icon('host', $this->translate('Host')); ?>
<?= $this->link()->host($notification->host, $notification->host_display_name) ?> <?= $this->link()->host($notification->host_name, $notification->host_display_name) ?>
<?php endif ?> <?php endif ?>
<br> <br>
<?= $this->escape($this->ellipsis($notification->notification_output, 10000)) ?> <?= $this->escape($this->ellipsis($notification->notification_output, 10000)) ?>
@ -61,9 +59,9 @@ use Icinga\Module\Monitoring\Object\Service;
<?= sprintf( <?= sprintf(
$this->translate('Sent to %s'), $this->translate('Sent to %s'),
$this->qlink( $this->qlink(
$notification->notification_contact, $notification->notification_contact_name,
'monitoring/show/contact', 'monitoring/show/contact',
array('contact' => $notification->notification_contact) array('contact_name' => $notification->notification_contact_name)
) )
) ?> ) ?>
</small> </small>

View File

@ -1,28 +1,28 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
?> if (! $this->compact): ?>
<?php if (!$this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs; ?> <?= $this->tabs; ?>
<div style="margin: 1em;" class="dontprint"> <?= $this->sortBox; ?>
<?= $this->translate('Sort by'); ?> <?= $this->sortControl; ?> <?= $this->limiter; ?>
</div> <?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<table class="pivot servicestates">
<?php <?php
$hasHeader = false; $hasHeader = false;
$pivotData = $this->pivot->toArray(); $pivotData = $this->pivot->toArray();
if (count($pivotData) === 0) {
echo $this->translate('No services found matching the filter') . '</div>';
return;
}
$hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')'; $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')';
?> ?>
<table class="pivot servicestates">
<?php if (count($pivotData) === 0): ?>
<?= $this->translate('No Services matching the filter'); ?>
<?php endif ?>
<?php foreach ($pivotData as $host_name => $serviceStates): ?> <?php foreach ($pivotData as $host_name => $serviceStates): ?>
<?php if (!$hasHeader): ?> <?php if (!$hasHeader): ?>
<thead> <thead>

View File

@ -1,21 +1,17 @@
<?php if ($this->compact): ?> <?php if (! $this->compact): ?>
<div class="content">
<?php else: ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em;" class="dontprint"> <?= $this->sortBox; ?>
<?= $this->translate('Sort by'); ?> <?= $this->sortControl->render($this); ?> <?= $this->limiter; ?>
</div> <?= $this->paginator; ?>
<?= $this->widget('limiter')->setMaxLimit(count($servicegroups)); ?>
<?= $this->paginationControl($servicegroups, null, null, array('preserve' => $this->preserve)); ?>
</div>
<div class="content">
<?= $this->filterEditor; ?> <?= $this->filterEditor; ?>
</div>
<?php endif ?> <?php endif ?>
<div class="content">
<?php <?php
if (count($servicegroups) === 0) { if (count($servicegroups) === 0) {
echo $this->translate('No service groups matching the filter'); echo $this->translate('No servicegroups found matching the filter') . '</div>';
echo '</div>';
return; return;
} }
?> ?>
@ -28,7 +24,7 @@
</thead> </thead>
<tbody> <tbody>
<?php foreach ($servicegroups as $s): ?> <?php foreach ($servicegroups as $s): ?>
<tr href="<?= $this->href('monitoring/list/services', array('servicegroup' => $s->servicegroup)); ?>"> <tr href="<?= $this->href('monitoring/list/services', array('servicegroup_name' => $s->servicegroup_name)); ?>">
<?php if ($s->services_critical_last_state_change_unhandled): ?> <?php if ($s->services_critical_last_state_change_unhandled): ?>
<td class="state change critical unhandled"> <td class="state change critical unhandled">
<strong><?= $this->translate('CRITICAL'); ?></strong> <strong><?= $this->translate('CRITICAL'); ?></strong>
@ -82,7 +78,7 @@
<?= $this->qlink( <?= $this->qlink(
$s->servicegroup_alias, $s->servicegroup_alias,
'monitoring/list/services', 'monitoring/list/services',
array('servicegroup' => $s->servicegroup), array('servicegroup_name' => $s->servicegroup_name),
array('title' => sprintf($this->translate('List all services in the group "%s"'), $s->servicegroup_alias)) array('title' => sprintf($this->translate('List all services in the group "%s"'), $s->servicegroup_alias))
); ?> ); ?>
</td> </td>
@ -97,7 +93,7 @@
'monitoring/list/services', 'monitoring/list/services',
array( array(
'service_state' => 0, 'service_state' => 0,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -124,7 +120,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -148,7 +144,7 @@
array( array(
'service_state' => 2, 'service_state' => 2,
'service_handled' => 1, 'service_handled' => 1,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -178,7 +174,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -202,7 +198,7 @@
array( array(
'service_state' => 3, 'service_state' => 3,
'service_handled' => 1, 'service_handled' => 1,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -232,7 +228,7 @@
'service_acknowledged' => 0, 'service_acknowledged' => 0,
'service_in_downtime' => 0, 'service_in_downtime' => 0,
'host_problem' => 0, 'host_problem' => 0,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -256,7 +252,7 @@
array( array(
'service_state' => 1, 'service_state' => 1,
'service_handled' => 1, 'service_handled' => 1,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(
@ -283,7 +279,7 @@
'monitoring/list/services', 'monitoring/list/services',
array( array(
'service_state' => 99, 'service_state' => 99,
'servicegroup' => $s->servicegroup, 'servicegroup_name' => $s->servicegroup_name,
'sort' => 'service_severity' 'sort' => 'service_severity'
), ),
array( array(

View File

@ -6,39 +6,31 @@ $selfUrl = 'monitoring/list/services';
if (! $this->compact): ?> if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs; ?>
<div style="margin: 1em;" class="dontprint"> <div class="dontprint">
<?= $this->render('list/components/selectioninfo.phtml') ?> <?= $this->render('list/components/selectioninfo.phtml'); ?>
<?= $this->render('list/components/servicesummary.phtml') ?> <?= $this->render('list/components/servicesummary.phtml'); ?>
<div style="float: right">
<?= $this->translate('Sort by') ?> <?= $this->sortControl ?>
</div> </div>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
</div> </div>
<?php if ($this->limit === 0): ?>
<?= $this->widget('limiter') ?>
<?php else: ?>
<?= $this->widget('limiter')->setCurrentPageCount($this->services->count()) ?>
<?= $this->paginationControl($services, null, null, array('preserve' => $this->preserve)) ?>
<?php endif ?> <?php endif ?>
</div>
<div class="content"> <div class="content">
<?= $this->filterEditor ?> <?php
<?php else: ?>
<div class="content"> if (count($services) === 0) {
<?php endif ?> echo $this->translate('No services found matching the filter') . '</div>';
return;
}
?>
<table data-base-target="_next" <table data-base-target="_next"
class="action multiselect <?php if ($this->compact): ?> compact<?php endif ?>" style="table-layout: auto;" class="action multiselect <?php if ($this->compact): ?> compact<?php endif ?>" style="table-layout: auto;"
data-icinga-multiselect-url="<?= $this->href("monitoring/services/show") ?>" data-icinga-multiselect-url="<?= $this->href("monitoring/services/show") ?>"
data-icinga-multiselect-data="service,host"> data-icinga-multiselect-data="service,host">
<tbody> <tbody>
<?php <?php foreach ($services as $service):
if (count($services) === 0) {
echo mt('monitoring', 'No services matching the filter');
}
foreach ($services as $service):
$serviceLink = $this->href( $serviceLink = $this->href(
'monitoring/service/show', 'monitoring/service/show',
array( array(

View File

@ -0,0 +1,27 @@
<?php
switch ($comment->type) {
case 'flapping':
$icon = 'flapping';
$title = $this->translate('Flapping');
$tooltip = $this->translate('Comment was caused by a flapping host or service.');
break;
case 'comment':
$icon = 'user';
$title = $this->translate('User Comment');
$tooltip = $this->translate('Comment was created by an user.');
break;
case 'downtime':
$icon = 'plug';
$title = $this->translate('Downtime');
$tooltip = $this->translate('Comment was caused by a downtime.');
break;
case 'ack':
$icon = 'ok';
$title = $this->translate('Acknowledgement');
$tooltip = $this->translate('Comment was caused by an acknowledgement.');
break;
}
?>
<strong><?= $this->escape($title); ?></strong><br>
<?= $this->icon($icon, $tooltip) ?>
<?= $this->prefixedTimeSince($comment->timestamp); ?>

View File

@ -0,0 +1,18 @@
<?php if ($comment->objecttype === 'service'): ?>
<?= $this->icon('service', $this->translate('Service')); ?>
<?= $this->link()->service(
$comment->service_description,
$comment->service_display_name,
$comment->host_name,
$comment->host_display_name
); ?>
<?php else: ?>
<?= $this->icon('host', $this->translate('Host')); ?>
<?= $this->link()->host($comment->host_name, $comment->host_display_name); ?>
<?php endif ?>
<br>
<?= $this->icon('comment', $this->translate('Comment')); ?> <?= isset($comment->author)
? '[' . $this->escape($comment->author) . '] '
: '';
?><?= $this->escape($comment->comment); ?>

View File

@ -0,0 +1,10 @@
<table class="action">
<tr class="state invalid">
<td class="state" style="width: 12em;">
<?= $this->render('partials/comment/comment-description.phtml'); ?>
</td>
<td>
<?= $this->render('partials/comment/comment-detail.phtml'); ?>
</td>
</tr>
</table>

View File

@ -0,0 +1,30 @@
<table class="action">
<?php $i = 0; foreach ($comments as $comment):
if (++ $i > 5) {
continue;
}
$this->comment = $comment;
?>
<tr class="state invalid">
<td class="state" style="width: 12em;">
<?= $this->render('partials/comment/comment-description.phtml'); ?>
</td>
<td>
<?= $this->render('partials/comment/comment-detail.phtml'); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<p>
<?= $this->qlink(
sprintf($this->translate('List all %d comments …'), count($comments)),
$listAllLink,
null,
array(
'title' => $this->translate('List all'),
'data-base-target' => "_next"
)
) ?>
</p>

View File

@ -0,0 +1,67 @@
<table class="action">
<tr class="state <?= $stateName; ?><?= $downtime->is_in_effect ? ' handled' : ''; ?>">
<td class="state">
<strong><?= $downtime->is_in_effect ? $this->translate('Expires') : $this->translate('Starts'); ?></strong>
<br>
<?=
$this->dateTimeRenderer(
($downtime->is_in_effect ? $downtime->end : $downtime->start),
true
)->render(
$this->translate('on %s', 'datetime'),
$this->translate('at %s', 'time'),
$this->translate('in %s', 'timespan')
);
?>
</td>
<td>
<small>
<?php if ($downtime->is_flexible): ?>
<?php if ($downtime->is_in_effect): ?>
<?= sprintf(
$this->isService
? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.')
: $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'),
date('d.m.y', $downtime->start),
date('H:i', $downtime->start),
$this->format()->duration($downtime->duration),
date('d.m.y', $downtime->end),
date('H:i', $downtime->end)
); ?>
<?php else: ?>
<?= sprintf(
$this->isService
? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.')
: $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'),
date('d.m.y H:i', $downtime->scheduled_start),
date('d.m.y H:i', $downtime->scheduled_end),
$this->format()->duration($downtime->duration)
); ?>
<?php endif ?>
<?php else: ?>
<?php if ($downtime->is_in_effect): ?>
<?= sprintf(
$this->isService
? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.')
: $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'),
date('d.m.y', $downtime->start),
date('H:i', $downtime->start),
date('d.m.y', $downtime->end),
date('H:i', $downtime->end)
); ?>
<?php else: ?>
<?= sprintf(
$this->isService
? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.')
: $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
date('d.m.y', $downtime->scheduled_start),
date('H:i', $downtime->scheduled_start),
date('d.m.y', $downtime->scheduled_end),
date('H:i', $downtime->scheduled_end)
); ?>
<?php endif ?>
<?php endif ?>
</small>
</td>
</tr>
</table>

View File

@ -0,0 +1,92 @@
<table class="action">
<tbody>
<?php $i = 0; foreach ($downtimes as $downtime):
if (++ $i > 5) {
continue;
} ?>
<tr class="state <?= $downtime->stateText ?>">
<td class="state">
<strong><?= $downtime->is_in_effect ? $this->translate('Expires') : $this->translate('Starts'); ?></strong>
<br>
<?=
$this->dateTimeRenderer(
($downtime->is_in_effect ? $downtime->end : $downtime->start),
true
)->render(
$this->translate('on %s', 'datetime'),
$this->translate('at %s', 'time'),
$this->translate('in %s', 'timespan')
);
?>
</td>
<td class="name oneline">
<?php if ($downtime->isService): ?>
<?= $this->icon('service', $this->translate('Service')) ?>
<b><?= $downtime->service ?> on <?= $downtime->host_name ?>.</b>
<?php else: ?>
<?= $this->icon('host', $this->translate('Host')) ?>
<b><?= $downtime->host_name ?>.</b>
<?php endif; ?>
<?php if ($downtime->is_flexible): ?>
<?php if ($downtime->is_in_effect): ?>
<?= sprintf(
$this->isService
? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.')
: $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'),
date('d.m.y', $downtime->start),
date('H:i', $downtime->start),
$this->format()->duration($downtime->duration),
date('d.m.y', $downtime->end),
date('H:i', $downtime->end)
); ?>
<?php else: ?>
<?= sprintf(
$this->isService
? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.')
: $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'),
date('d.m.y H:i', $downtime->scheduled_start),
date('d.m.y H:i', $downtime->scheduled_end),
$this->format()->duration($downtime->duration)
); ?>
<?php endif ?>
<?php else: ?>
<?php if ($downtime->is_in_effect): ?>
<?= sprintf(
$this->isService
? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.')
: $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'),
date('d.m.y', $downtime->start),
date('H:i', $downtime->start),
date('d.m.y', $downtime->end),
date('H:i', $downtime->end)
); ?>
<?php else: ?>
<?= sprintf(
$this->isService
? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.')
: $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
date('d.m.y', $downtime->scheduled_start),
date('H:i', $downtime->scheduled_start),
date('d.m.y', $downtime->scheduled_end),
date('H:i', $downtime->scheduled_end)
); ?>
<?php endif ?>
<?php endif ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p>
<?= $this->qlink(
sprintf($this->translate('List all %d downtimes …'), count($downtimes)),
$listAllLink,
null,
array(
'title' => $this->translate('List all'),
'data-base-target' => "_next"
)
) ?>
</p>

View File

@ -1,11 +1,7 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
?> ?>
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<table class="objectstate"> <table class="objectstate">
<tr class="state <?= Host::getStateText($object->host_state); ?><?= $object->host_handled ? ' handled' : ''; ?>"> <tr class="state <?= Host::getStateText($object->host_state); ?><?= $object->host_handled ? ' handled' : ''; ?>">
<td class="state"> <td class="state">

View File

@ -1,6 +1,3 @@
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<?php if (($hostCount = count($objects)) > 0): ?> <?php if (($hostCount = count($objects)) > 0): ?>
<div class="hbox-item"> <div class="hbox-item">
<strong><?= sprintf($this->translatePlural('Host (%u)', 'Hosts (%u)', $hostCount), $hostCount); ?></strong> <strong><?= sprintf($this->translatePlural('Host (%u)', 'Hosts (%u)', $hostCount), $hostCount); ?></strong>

View File

@ -1,12 +1,8 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
?> ?>
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<table class="objectstate"> <table class="objectstate">
<tr class="state <?= Host::getStateText($object->host_state); ?><?= $object->host_handled ? ' handled' : ''; ?>"> <tr class="state <?= Host::getStateText($object->host_state); ?><?= $object->host_handled ? ' handled' : ''; ?>">
<td class="state"> <td class="state">

Some files were not shown because too many files have changed in this diff Show More