Merge branch 'master' into bugfix/time-formatting-6778

Conflicts:
	modules/monitoring/application/views/scripts/list/comments.phtml
	modules/monitoring/application/views/scripts/list/hostgroups.phtml
	modules/monitoring/application/views/scripts/process/info.phtml
	modules/monitoring/application/views/scripts/show/components/downtime.phtml
	modules/monitoring/application/views/scripts/show/components/notifications.phtml
	modules/monitoring/public/css/module.less
This commit is contained in:
Eric Lippmann 2015-05-21 14:57:01 +02:00
commit 54577d04bd
183 changed files with 5869 additions and 1978 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

@ -11,11 +11,11 @@ use Icinga\Web\Form;
class ConfirmRemovalForm extends Form class ConfirmRemovalForm extends Form
{ {
/** /**
* Initalize this form * Initialize this form
*/ */
public function init() public function init()
{ {
$this->setName('form_confirm_removal'); $this->setName('form_confirm_removal');
$this->setSubmitLabel($this->translate('Confirm Removal')); $this->getSubmitLabel() ?: $this->setSubmitLabel($this->translate('Confirm Removal'));
} }
} }

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

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>
<body> <body>
<a href="/monitoring/host/show?host_name=localhost" <a href="/monitoring/host/show?host=localhost"
title="Show detailed information about the host localhost" title="Show detailed information about the host localhost"
aria-label="Show detailed information about the host localhost">localhost</a> aria-label="Show detailed information about the host localhost">localhost</a>
</body> </body>

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

@ -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

@ -286,7 +286,6 @@ class LdapUserBackend extends UserBackend
$users[] = $row->{$this->userNameAttribute}; $users[] = $row->{$this->userNameAttribute};
} }
} }
return $users; return $users;
} }
} }

View File

@ -167,7 +167,7 @@ class Params
* *
* @throws MissingParameterException If the parameter was not given * @throws MissingParameterException If the parameter was not given
*/ */
public function req($name, $strict = true) public function getRequired($name, $strict = true)
{ {
if ($this->has($name)) { if ($this->has($name)) {
$value = $this->get($name); $value = $this->get($name);
@ -258,6 +258,30 @@ class Params
return $result; return $result;
} }
/**
* Require and remove a parameter
*
* @param string $name Name of the parameter
* @param bool $strict Whether the parameter's value must not be the empty string
*
* @return mixed
*
* @throws MissingParameterException If the parameter was not given
*/
public function shiftRequired($name, $strict = true)
{
if ($this->has($name)) {
$value = $this->get($name);
if (! $strict || strlen($value) > 0) {
$this->shift($name);
return $value;
}
}
$e = new MissingParameterException(t('Required parameter \'%s\' missing'), $name);
$e->setParameter($name);
throw $e;
}
/** /**
* Put the given value onto the argument stack * Put the given value onto the argument stack
* *

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

@ -12,7 +12,6 @@ class FilterExpression extends Filter
public function __construct($column, $sign, $expression) public function __construct($column, $sign, $expression)
{ {
$column = trim($column); $column = trim($column);
$expression = is_array($expression) ? array_map('trim', $expression) : trim($expression);
$this->column = $column; $this->column = $column;
$this->sign = $sign; $this->sign = $sign;
$this->expression = $expression; $this->expression = $expression;

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

@ -9,7 +9,8 @@ namespace Icinga\Protocol\Ldap;
* Provides information about the available encryption mechanisms (StartTLS), the supported * Provides information about the available encryption mechanisms (StartTLS), the supported
* LDAP protocol (v2/v3), vendor-specific extensions or protocols controls and extensions. * LDAP protocol (v2/v3), vendor-specific extensions or protocols controls and extensions.
*/ */
class Capability { class Capability
{
const LDAP_SERVER_START_TLS_OID = '1.3.6.1.4.1.1466.20037'; const LDAP_SERVER_START_TLS_OID = '1.3.6.1.4.1.1466.20037';

View File

@ -281,31 +281,6 @@ class Query
return $this->sort_columns; return $this->sort_columns;
} }
/**
* Return a pagination adapter for the current query
*
* @return \Zend_Paginator
*/
public function paginate($limit = null, $page = null)
{
if ($page === null || $limit === null) {
$request = \Zend_Controller_Front::getInstance()->getRequest();
if ($page === null) {
$page = $request->getParam('page', 0);
}
if ($limit === null) {
$limit = $request->getParam('limit', 20);
}
}
$paginator = new \Zend_Paginator(
// TODO: Adapter doesn't fit yet:
new \Icinga\Web\Paginator\Adapter\QueryAdapter($this)
);
$paginator->setItemCountPerPage($limit);
$paginator->setCurrentPageNumber($page);
return $paginator;
}
/** /**
* Add a filter expression to this query * Add a filter expression to this query
* *

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

@ -6,7 +6,8 @@ namespace Icinga\Util;
/** /**
* Provide functions to change and convert colors. * Provide functions to change and convert colors.
*/ */
class Color { class Color
{
/** /**
* Convert a given color string to an rgb-array containing * Convert a given color string to an rgb-array containing
* each color as a decimal value. * each color as a decimal value.

View File

@ -79,4 +79,59 @@ class String
return $matches; return $matches;
} }
/**
* Check if a string ends with a different string
*
* @param $haystack The string to search for matches
* @param $needle The string to match at the start of the haystack
*
* @return bool Whether or not needle is at the beginning of haystack
*/
public static function endsWith($haystack, $needle)
{
return $needle === '' ||
(($temp = strlen($haystack) - strlen($needle)) >= 0 && false !== strpos($haystack, $needle, $temp));
}
/**
* Generates an array of strings that constitutes the cartesian product of all passed sets, with all
* string combinations concatenated using the passed join-operator.
*
* <pre>
* cartesianProduct(
* array(array('foo', 'bar'), array('mumble', 'grumble', null)),
* '_'
* );
* => array('foo_mumble', 'foo_grumble', 'bar_mumble', 'bar_grumble', 'foo', 'bar')
* </pre>
*
* @param array $sets An array of arrays containing all sets for which the cartesian
* product should be calculated.
* @param string $glue The glue used to join the strings, defaults to ''.
*
* @returns array The cartesian product in one array of strings.
*/
public static function cartesianProduct(array $sets, $glue = '')
{
$product = null;
foreach ($sets as $set) {
if (! isset($product)) {
$product = $set;
} else {
$newProduct = array();
foreach ($product as $strA) {
foreach ($set as $strB) {
if ($strB === null) {
$newProduct []= $strA;
} else {
$newProduct []= $strA . $glue . $strB;
}
}
}
$product = $newProduct;
}
}
return $product;
}
} }

View File

@ -3,7 +3,12 @@
namespace Icinga\Web; namespace Icinga\Web;
use Zend_Controller_Action_Exception;
use Icinga\Data\Sortable;
use Icinga\Data\QueryInterface;
use Icinga\Web\Controller\ModuleActionController; use Icinga\Web\Controller\ModuleActionController;
use Icinga\Web\Widget\Limiter;
use Icinga\Web\Widget\Paginator;
use Icinga\Web\Widget\SortBox; use Icinga\Web\Widget\SortBox;
/** /**
@ -14,17 +19,140 @@ use Icinga\Web\Widget\SortBox;
class Controller extends ModuleActionController class Controller extends ModuleActionController
{ {
/** /**
* Create a sort control box at the 'sortControl' view parameter * @see ActionController::init
*
* @param array $columns An array containing the sort columns, with the
* submit value as the key and the label as the value
*/ */
protected function setupSortControl(array $columns) public function init()
{ {
$req = $this->getRequest(); parent::init();
$this->view->sortControl = SortBox::create( $this->handleSortControlSubmit();
'sortbox-' . $req->getActionName(), }
$columns
)->applyRequest($req); /**
* 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);
}
}
/**
* Immediately respond w/ HTTP 404
*
* @param $message
*
* @throws Zend_Controller_Action_Exception
*/
public function httpNotFound($message)
{
throw new Zend_Controller_Action_Exception($message, 404);
}
/**
* 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 > 0 ? ($page - 1) * $limit : 0);
if (! $this->view->compact) {
$paginator = new Paginator();
$paginator->setQuery($query);
$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';
} }

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,13 +117,18 @@ 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($class)) { if (class_exists($value)) {
throw new ConfigurationError( $value = new $value;
sprintf('ItemRenderer with class "%s" does not exist', $class) } else {
); $class = '\Icinga\Web\Menu' . $value;
if (!class_exists($class)) {
throw new ConfigurationError(
sprintf('ItemRenderer with class "%s" does not exist', $class)
);
}
$value = new $class;
} }
$value = new $class;
} }
if (method_exists($this, $method)) { if (method_exists($this, $method)) {
$this->{$method}($value); $this->{$method}($value);
@ -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) protected $attributes = array(
{ 'target' => '_self'
return sprintf( );
'<a href="%s" target="_self">%s%s<span></span></a>',
$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;
/** /**
* Renders the html content of a single menu item * Default MenuItemRenderer class
*/ */
interface MenuItemRenderer { class MenuItemRenderer
public function render(Menu $menu); {
/**
* 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
*
* @param Menu $menu
*
* @return string
*/
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

@ -54,7 +54,7 @@ class UrlParams
* *
* @throws MissingParameterException If the parameter was not given * @throws MissingParameterException If the parameter was not given
*/ */
public function req($name, $strict = true) public function getRequired($name, $strict = true)
{ {
if ($this->has($name)) { if ($this->has($name)) {
$value = $this->get($name); $value = $this->get($name);
@ -138,6 +138,30 @@ class UrlParams
return $ret; return $ret;
} }
/**
* Require and remove a parameter
*
* @param string $name Name of the parameter
* @param bool $strict Whether the parameter's value must not be the empty string
*
* @return mixed
*
* @throws MissingParameterException If the parameter was not given
*/
public function shiftRequired($name, $strict = true)
{
if ($this->has($name)) {
$value = $this->get($name);
if (! $strict || strlen($value) > 0) {
$this->shift($name);
return $value;
}
}
$e = new MissingParameterException(t('Required parameter \'%s\' missing'), $name);
$e->setParameter($name);
throw $e;
}
public function addEncoded($param, $value = true) public function addEncoded($param, $value = true)
{ {
$this->params[] = array($param, $this->cleanupValue($value)); $this->params[] = array($param, $this->cleanupValue($value));

View File

@ -127,7 +127,8 @@ class HistoryColorGrid extends AbstractWidget {
. ' opacity: ' . $this->opacity . ';" ' . . ' opacity: ' . $this->opacity . ';" ' .
'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

@ -5,11 +5,13 @@ namespace Icinga\Web\Widget\Chart;
use Icinga\Chart\PieChart; use Icinga\Chart\PieChart;
use Icinga\Module\Monitoring\Plugin\PerfdataSet; use Icinga\Module\Monitoring\Plugin\PerfdataSet;
use Icinga\Util\String;
use Icinga\Web\Widget\AbstractWidget; use Icinga\Web\Widget\AbstractWidget;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Util\Format; use Icinga\Util\Format;
use Icinga\Application\Logger; use Icinga\Application\Logger;
use Icinga\Exception\IcingaException; use Icinga\Exception\IcingaException;
use stdClass;
/** /**
* A SVG-PieChart intended to be displayed as a small icon next to labels, to offer a better visualization of the * A SVG-PieChart intended to be displayed as a small icon next to labels, to offer a better visualization of the
@ -27,6 +29,45 @@ class InlinePie extends AbstractWidget
const NUMBER_FORMAT_BYTES = 'bytes'; const NUMBER_FORMAT_BYTES = 'bytes';
const NUMBER_FORMAT_RATIO = 'ratio'; const NUMBER_FORMAT_RATIO = 'ratio';
public static $colorsHostStates = array(
'#44bb77', // up
'#ff99aa', // down
'#cc77ff', // unreachable
'#77aaff' // pending
);
public static $colorsHostStatesHandledUnhandled = array(
'#44bb77', // up
'#44bb77',
'#ff99aa', // down
'#ff5566',
'#cc77ff', // unreachable
'#aa44ff',
'#77aaff', // pending
'#77aaff'
);
public static $colorsServiceStates = array(
'#44bb77', // Ok
'#ffaa44', // Warning
'#ff99aa', // Critical
'#aa44ff', // Unknown
'#77aaff' // Pending
);
public static $colorsServiceStatesHandleUnhandled = array(
'#44bb77', // Ok
'#44bb77',
'#ffaa44', // Warning
'#ffcc66',
'#ff99aa', // Critical
'#ff5566',
'#cc77ff', // Unknown
'#aa44ff',
'#77aaff', // Pending
'#77aaff'
);
/** /**
* The template string used for rendering this widget * The template string used for rendering this widget
* *
@ -231,4 +272,19 @@ EOD;
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template); $template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
return $template; return $template;
} }
public static function createFromStateSummary(stdClass $states, $title, array $colors)
{
$handledUnhandledStates = array();
foreach ($states as $key => $value) {
if (String::endsWith($key, '_handled') || String::endsWith($key, '_unhandled')) {
$handledUnhandledStates[$key] = $value;
}
}
$chart = new self(array_values($handledUnhandledStates), $title, $colors);
return $chart
->setSize(50)
->setTitle('')
->setSparklineClass('sparkline-multi');
}
} }

View File

@ -6,9 +6,11 @@ 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;
use Icinga\Web\Notification;
use Exception; use Exception;
/** /**
@ -39,6 +41,8 @@ class FilterEditor extends AbstractWidget
protected $ignoreParams = array(); protected $ignoreParams = array();
protected $searchColumns = null;
/** /**
* @var string * @var string
*/ */
@ -73,6 +77,19 @@ class FilterEditor extends AbstractWidget
return $this->filter; return $this->filter;
} }
/**
* Set columns to search in
*
* @param array $searchColumns
*
* @return $this
*/
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 +164,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,33 +216,25 @@ class FilterEditor extends AbstractWidget
$filter = $this->getFilter(); $filter = $this->getFilter();
if ($search !== null) { if ($search !== null) {
if (strpos($search, '=') === false) { if (empty($this->searchColumns)) {
// TODO: Ask the view for (multiple) search columns if (strpos($search, '=') === false) {
switch($request->getActionName()) { Notification::error(mt('monitoring', 'Cannot search here'));
case 'services': return $this;
$searchCol = 'service'; } else {
break; list($k, $v) = preg_split('/=/', $search);
case 'hosts': $filter = $this->mergeRootExpression($filter, trim($k), '=', ltrim($v));
$searchCol = 'host';
break;
case 'hostgroups':
$searchCol = 'hostgroup';
break;
case 'servicegroups':
$searchCol = 'servicegroup';
break;
default:
$searchCol = null;
} }
if ($searchCol === null) {
throw new Exception('Cannot search here');
}
$filter = $this->mergeRootExpression($filter, $searchCol, '=', "*$search*");
} else { } else {
list($k, $v) = preg_split('/=/', $search); if (false === $this->resetSearchColumns($filter)) {
$filter = $this->mergeRootExpression($filter, $k, '=', $v); $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(
@ -405,10 +434,10 @@ class FilterEditor extends AbstractWidget
if ($this->addTo && $this->addTo === $filter->getId()) { if ($this->addTo && $this->addTo === $filter->getId()) {
return return
preg_replace( preg_replace(
'/ class="autosubmit"/', '/ class="autosubmit"/',
' class="autofocus"', ' class="autofocus"',
$this->selectOperator() $this->selectOperator()
) )
. '<ul><li>' . '<ul><li>'
. $this->selectColumn($filter) . $this->selectColumn($filter)
. $this->selectSign($filter) . $this->selectSign($filter)
@ -649,13 +678,13 @@ 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...')
. '" /></form>'; . '" /></form>';
if ($this->filter->isEmpty()) { if ($this->filter->isEmpty()) {
$title = t('Filter this list'); $title = t('Filter this list');
} else { } else {
$title = t('Modify this filter'); $title = t('Modify this filter');
@ -678,20 +707,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">'
. '<form action="' . $this->renderSearch()
. Url::fromRequest() . '<form action="'
. '" class="filterEditor" method="POST">' . Url::fromRequest()
. '<ul class="tree widgetFilter"><li>' . '" class="editor" method="POST">'
. $this->renderFilter($this->filter) . '<ul class="tree"><li>'
. '</li></ul>' . $this->renderFilter($this->filter)
. '<div style="float: right">' . '</li></ul>'
. '<input type="submit" name="submit" value="Apply" />' . '<div class="buttons">'
. '<input type="submit" name="cancel" value="Cancel" />' . '<input type="submit" name="submit" value="Apply" />'
. '</div>' . '<input type="submit" name="cancel" value="Cancel" />'
. '</form>'; . '</div>'
. '</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

@ -0,0 +1,168 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Widget;
use Icinga\Data\QueryInterface;
use Icinga\Exception\ProgrammingError;
/**
* Paginator
*/
class Paginator extends AbstractWidget
{
/**
* The query the paginator widget is created for
*
* @var QueryInterface
*/
protected $query;
/**
* The view script in use
*
* @var string|array
*/
protected $viewScript = array('mixedPagination.phtml', 'default');
/**
* Set the query to create the paginator widget for
*
* @param QueryInterface $query
*
* @return $this
*/
public function setQuery(QueryInterface $query)
{
$this->query = $query;
return $this;
}
/**
* Set the view script to use
*
* @param string|array $script
*
* @return $this
*/
public function setViewScript($script)
{
$this->viewScript = $script;
return $this;
}
/**
* Render this paginator
*/
public function render()
{
if ($this->query === null) {
throw new ProgrammingError('Need a query to create the paginator widget for');
}
$itemCountPerPage = $this->query->getLimit();
if (! $itemCountPerPage) {
return ''; // No pagination required
}
$totalItemCount = count($this->query);
$pageCount = (int) ceil($totalItemCount / $itemCountPerPage);
$currentPage = $this->query->hasOffset() ? ($this->query->getOffset() / $itemCountPerPage) + 1 : 1;
$pagesInRange = $this->getPages($pageCount, $currentPage);
$variables = array(
'totalItemCount' => $totalItemCount,
'pageCount' => $pageCount,
'itemCountPerPage' => $itemCountPerPage,
'first' => 1,
'current' => $currentPage,
'last' => $pageCount,
'pagesInRange' => $pagesInRange,
'firstPageInRange' => min($pagesInRange),
'lastPageInRange' => max($pagesInRange)
);
if ($currentPage > 1) {
$variables['previous'] = $currentPage - 1;
}
if ($currentPage < $pageCount) {
$variables['next'] = $currentPage + 1;
}
if (is_array($this->viewScript)) {
if ($this->viewScript[1] !== null) {
return $this->view()->partial($this->viewScript[0], $this->viewScript[1], $variables);
}
return $this->view()->partial($this->viewScript[0], $variables);
}
return $this->view()->partial($this->viewScript, $variables);
}
/**
* Returns an array of "local" pages given the page count and current page number
*
* @return array
*/
protected function getPages($pageCount, $currentPage)
{
$range = array();
if ($pageCount < 10) {
// Show all pages if we have less than 10
for ($i = 1; $i < 10; $i++) {
if ($i > $pageCount) {
break;
}
$range[$i] = $i;
}
} else {
// More than 10 pages:
foreach (array(1, 2) as $i) {
$range[$i] = $i;
}
if ($currentPage < 6 ) {
// We are on page 1-5 from
for ($i = 1; $i <= 7; $i++) {
$range[$i] = $i;
}
} else {
// Current page > 5
$range[] = '...';
if (($pageCount - $currentPage) < 5) {
// Less than 5 pages left
$start = 5 - ($pageCount - $currentPage);
} else {
$start = 1;
}
for ($i = $currentPage - $start; $i < ($currentPage + (4 - $start)); $i++) {
if ($i > $pageCount) {
break;
}
$range[$i] = $i;
}
}
if ($currentPage < ($pageCount - 2)) {
$range[] = '...';
}
foreach (array($pageCount - 1, $pageCount) as $i) {
$range[$i] = $i;
}
}
if (empty($range)) {
$range[] = 1;
}
return $range;
}
}

View File

@ -3,64 +3,66 @@
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:
* <pre><code> * <pre><code>
* $this->view->sortControl = new SortBox( * $this->view->sortControl = new SortBox(
* $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)
{ {
@ -85,71 +86,84 @@ class SortBox extends AbstractWidget
/** /**
* Apply the parameters from the given request on this SortBox * Apply the parameters from the given request on this SortBox
* *
* @param Request $request The request to use for populating the form * @param Request $request The request to use for populating the form
* *
* @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(
'multiOptions' => array( 'select',
'asc' => 'Asc', 'dir',
'desc' => 'Desc', array(
), 'autosubmit' => true,
'style' => 'width: 5em', 'multiOptions' => array(
'autosubmit' => true 'asc' => 'Asc',
)); 'desc' => 'Desc',
$sort = $form->getElement('sort')->setDecorators(array('ViewHelper')); ),
$dir = $form->getElement('dir')->setDecorators(array('ViewHelper')); 'decorators' => array(
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

@ -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();
@ -69,8 +70,10 @@ class Monitoring_AlertsummaryController extends Controller
'notification_state' 'notification_state'
) )
); );
$this->view->notifications = $query;
$this->view->notifications = $query->paginate(); $this->setupLimitControl();
$this->setupPaginationControl($this->view->notifications);
} }
/** /**
@ -490,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();
@ -168,7 +163,7 @@ class Monitoring_ChartController extends Controller
public function hostgroupAction() public function hostgroupAction()
{ {
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'groupsummary', 'hostgroupsummary',
array( array(
'hostgroup', 'hostgroup',
'hosts_up', 'hosts_up',
@ -199,7 +194,7 @@ class Monitoring_ChartController extends Controller
public function servicegroupAction() public function servicegroupAction()
{ {
$query = $this->backend->select()->from( $query = $this->backend->select()->from(
'groupsummary', 'servicegroupsummary',
array( array(
'servicegroup', 'servicegroup',
'services_ok', 'services_ok',

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') . sprintf(' (%d)', count($this->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

@ -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') . sprintf(' (%d)', count($this->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,18 +27,33 @@ class Monitoring_HostController extends MonitoredObjectController
*/ */
public function init() public function init()
{ {
$host = new Host($this->backend, $this->params->get('host_name')); 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'));
$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();
$this->getTabs()->activate('host'); $this->getTabs()->activate('host');
} }
/**
* Get host actions from hook
*
* @return array
*/
protected function getHostActions() protected function getHostActions()
{ {
$urls = array(); $urls = array();
@ -56,7 +72,7 @@ class Monitoring_HostController extends MonitoredObjectController
*/ */
public function showAction() public function showAction()
{ {
$this->view->hostActions = $this->getHostActions(); $this->view->actions = $this->getHostActions();
parent::showAction(); parent::showAction();
} }

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\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterEqual;
use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm;
@ -10,11 +11,11 @@ use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
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\Tabextension\DashboardAction;
class Monitoring_HostsController extends Controller class Monitoring_HostsController extends Controller
{ {
@ -25,51 +26,14 @@ class Monitoring_HostsController extends Controller
public function init() public function init()
{ {
// Support switching from service-view using the host and service selection. The filter would error
// on any occurrence of a filter based on service.
$filterString = preg_replace('/(service=[^)&]*)/', '', (string)$this->params);
$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;
}
protected function handleCommandForm(ObjectsCommandForm $form)
{
$this->hostList->setColumns(array(
'host_name',
'host_state',
'host_problem',
'host_handled',
'host_acknowledged',
'host_in_downtime'
));
$form
->setObjects($this->hostList)
->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams($this->params))
->handleRequest();
$hostStates = array(
Host::getStateText(Host::STATE_UP) => 0,
Host::getStateText(Host::STATE_DOWN) => 0,
Host::getStateText(Host::STATE_UNREACHABLE) => 0,
Host::getStateText(Host::STATE_PENDING) => 0,
);
foreach ($this->hostList as $host) {
++$hostStates[$host::getStateText($host->state)];
}
$this->view->form = $form;
$this->view->objects = $this->hostList;
$this->view->hostStates = $hostStates;
$this->view->hostStatesPieChart = $this->createPieChart(
$hostStates,
$this->translate('Host State'),
array('#44bb77', '#FF5566', '#E066FF', '#77AAFF')
);
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
return $form;
}
public function showAction()
{
$this->getTabs()->add( $this->getTabs()->add(
'show', 'show',
array( array(
@ -77,10 +41,53 @@ class Monitoring_HostsController extends Controller
$this->translate('Show summarized information for %u hosts'), $this->translate('Show summarized information for %u hosts'),
count($this->hostList) count($this->hostList)
), ),
'label' => $this->translate('Hosts'), 'label' => $this->translate('Hosts') . sprintf(' (%d)', count($this->hostList)),
'url' => Url::fromRequest() 'url' => Url::fromRequest(),
'icon' => 'host'
) )
)->activate('show'); )->extend(new DashboardAction())->activate('show');
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts')->setQueryString($filterString);
}
protected function handleCommandForm(ObjectsCommandForm $form)
{
$this->hostList->setColumns(array(
'host_icon_image',
'host_name',
'host_state',
'host_problem',
'host_handled',
'host_acknowledged',
'host_in_downtime',
'host_last_ack',
'host_is_flapping',
'host_last_comment',
'host_output',
'host_notifications_enabled',
'host_active_checks_enabled',
'host_passive_checks_enabled'
));
$form
->setObjects($this->hostList)
->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams($this->params))
->handleRequest();
$this->view->form = $form;
$this->view->objects = $this->hostList;
$this->view->stats = $this->hostList->getStateSummary();
$this->view->hostStatesPieChart = InlinePie::createFromStateSummary(
$this->view->stats,
$this->translate('Host State'),
InlinePie::$colorsHostStatesHandledUnhandled
);
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
return $form;
}
public function showAction()
{
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); $checkNowForm = new CheckNowCommandForm();
$checkNowForm $checkNowForm
@ -88,45 +95,26 @@ class Monitoring_HostsController extends Controller
->handleRequest(); ->handleRequest();
$this->view->checkNowForm = $checkNowForm; $this->view->checkNowForm = $checkNowForm;
$this->hostList->setColumns(array( $this->hostList->setColumns(array(
'host_icon_image',
'host_name', 'host_name',
'host_state', 'host_state',
'host_problem', 'host_problem',
'host_handled', 'host_handled',
'host_acknowledged', 'host_acknowledged',
'host_in_downtime'/*, 'host_in_downtime',
'host_passive_checks_enabled', 'host_last_ack',
'host_is_flapping',
'host_last_comment',
'host_output',
'host_notifications_enabled', 'host_notifications_enabled',
'host_event_handler_enabled',
'host_flap_detection_enabled',
'host_active_checks_enabled', 'host_active_checks_enabled',
'host_passive_checks_enabled'
/*'host_event_handler_enabled',
'host_flap_detection_enabled',
'host_obsessing'*/ 'host_obsessing'*/
)); ));
$unhandledObjects = array();
$unhandledFilterExpressions = array(); $acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
$acknowledgedObjects = array();
$objectsInDowntime = array();
$downtimeFilterExpressions = array();
$hostStates = array(
Host::getStateText(Host::STATE_UP) => 0,
Host::getStateText(Host::STATE_DOWN) => 0,
Host::getStateText(Host::STATE_UNREACHABLE) => 0,
Host::getStateText(Host::STATE_PENDING) => 0,
);
foreach ($this->hostList as $host) {
/** @var Host $host */
if ((bool) $host->problem === true && (bool) $host->handled === false) {
$unhandledObjects[] = $host;
$unhandledFilterExpressions[] = Filter::where('host', $host->getName());
}
if ((bool) $host->acknowledged === true) {
$acknowledgedObjects[] = $host;
}
if ((bool) $host->in_downtime === true) {
$objectsInDowntime[] = $host;
$downtimeFilterExpressions[] = Filter::where('host_name', $host->getName());
}
++$hostStates[$host::getStateText($host->state)];
}
if (! empty($acknowledgedObjects)) { if (! empty($acknowledgedObjects)) {
$removeAckForm = new RemoveAcknowledgementCommandForm(); $removeAckForm = new RemoveAcknowledgementCommandForm();
$removeAckForm $removeAckForm
@ -134,43 +122,68 @@ class Monitoring_HostsController extends Controller
->handleRequest(); ->handleRequest();
$this->view->removeAckForm = $removeAckForm; $this->view->removeAckForm = $removeAckForm;
} }
$hostStates = (object)$this->hostList->getStateSummary();
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts');
$this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/hosts/reschedule-check'); $this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/hosts/reschedule-check');
$this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/hosts/schedule-downtime'); $this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/hosts/schedule-downtime');
$this->view->processCheckResultAllLink = Url::fromRequest()->setPath('monitoring/hosts/process-check-result'); $this->view->processCheckResultAllLink = Url::fromRequest()->setPath('monitoring/hosts/process-check-result');
$this->view->hostStates = $hostStates; $this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/hosts/add-comment');
$this->view->stats = $hostStates;
$this->view->objects = $this->hostList; $this->view->objects = $this->hostList;
$this->view->unhandledObjects = $unhandledObjects; $this->view->unhandledObjects = $this->hostList->getUnhandledObjects();
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString(); $this->view->problemObjects = $this->hostList->getProblemObjects();
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem') $this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
->setQueryString($unhandledFilterQueryString); ->setQueryString($this->hostList->getUnhandledObjects()->objectsFilter());
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime') $this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime')
->setQueryString($unhandledFilterQueryString); ->setQueryString($this->hostList->getUnhandledObjects()->objectsFilter());
$this->view->acknowledgedObjects = $acknowledgedObjects; $this->view->downtimeLink = Url::fromPath('monitoring/hosts/schedule-downtime')
$this->view->objectsInDowntime = $objectsInDowntime; ->setQueryString($this->hostList->getProblemObjects()->objectsFilter());
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes') $this->view->acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString()); $this->view->objectsInDowntime = $this->hostList->getObjectsInDowntime();
$this->view->commentsLink = Url::fromRequest() $this->view->inDowntimeLink = Url::fromPath('monitoring/list/hosts')
->setPath('monitoring/list/comments'); ->setQueryString(
$this->view->hostStatesPieChart = $this->createPieChart( $this->hostList
$hostStates, ->getObjectsInDowntime()
$this->translate('Host State'), ->objectsFilter()
array('#44bb77', '#FF5566', '#E066FF', '#77AAFF') ->toQueryString()
);
$this->view->sendCustomNotificationLink =
Url::fromRequest()->setPath(
'monitoring/hosts/send-custom-notification'
); );
$this->view->showDowntimesLink = Url::fromPath('monitoring/list/downtimes')
->setQueryString(
$this->hostList
->objectsFilter()
->andFilter(FilterEqual::where('downtime_objecttype', 'host'))
->toQueryString()
);
$this->view->commentsLink = Url::fromRequest()->setPath('monitoring/list/comments');
$this->view->baseFilter = $this->hostList->getFilter();
$this->view->sendCustomNotificationLink = Url::fromRequest()->setPath('monitoring/hosts/send-custom-notification');
} }
protected function createPieChart(array $states, $title, array $colors) /**
* Add a host comments
*/
public function addCommentAction()
{ {
$chart = new InlinePie(array_values($states), $title, $colors); $this->assertPermission('monitoring/command/comment/add');
return $chart
->setSize(75) $form = new AddCommentCommandForm();
->setTitle('') $form->setTitle($this->translate('Add Host Comments'));
->setSparklineClass('sparkline-multi'); $this->handleCommandForm($form);
}
/**
* Delete a comment
*/
public function deleteCommentAction()
{
$this->assertPermission('monitoring/command/comment/delete');
$form = new DeleteCommentCommandForm();
$form->setTitle($this->translate('Delete Host Comments'));
$this->handleCommandForm($form);
} }
/** /**

View File

@ -12,6 +12,7 @@ use Icinga\Web\Widget\Tabs;
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;
use Icinga\Module\Monitoring\DataView\DataView;
class Monitoring_ListController extends Controller class Monitoring_ListController extends Controller
{ {
@ -20,12 +21,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;
}
} }
/** /**
@ -46,25 +43,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)
* *
@ -80,10 +58,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';
@ -121,20 +95,10 @@ class Monitoring_ListController extends Controller
'host_passive_checks_enabled', 'host_passive_checks_enabled',
'host_current_check_attempt', 'host_current_check_attempt',
'host_max_check_attempts' 'host_max_check_attempts'
), $this->extraColumns())); ), $this->addColumns()));
$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',
@ -147,6 +111,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);
} }
/** /**
@ -154,10 +128,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';
@ -208,13 +178,14 @@ class Monitoring_ListController extends Controller
'service_passive_checks_enabled', 'service_passive_checks_enabled',
'current_check_attempt' => 'service_current_check_attempt', 'current_check_attempt' => 'service_current_check_attempt',
'max_check_attempts' => 'service_max_check_attempts' 'max_check_attempts' => 'service_max_check_attempts'
), $this->extraColumns()); ), $this->addColumns());
$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'),
@ -225,15 +196,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',
@ -252,7 +215,6 @@ class Monitoring_ListController extends Controller
'services_unknown_handled', 'services_unknown_handled',
'services_pending', 'services_pending',
))->getQuery()->fetchRow(); ))->getQuery()->fetchRow();
} }
/** /**
@ -260,11 +222,9 @@ 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',
@ -286,9 +246,11 @@ class Monitoring_ListController extends Controller
'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'),
@ -300,12 +262,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();
} }
} }
@ -314,15 +275,13 @@ 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_name', 'host_name',
'service_description', 'service_description',
@ -334,18 +293,19 @@ class Monitoring_ListController extends Controller
'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',
@ -367,8 +327,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'),
@ -376,14 +338,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();
@ -423,14 +382,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',
@ -438,7 +395,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:
@ -455,15 +412,18 @@ 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',
@ -479,8 +439,10 @@ class Monitoring_ListController extends Controller
'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'),
@ -488,123 +450,110 @@ 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(
'servicegroup_name', $query = $this->backend->select()->from('servicegroupsummary', array(
'servicegroup_alias',
'hosts_up',
'hosts_unreachable_handled',
'hosts_unreachable_unhandled',
'hosts_down_handled', 'hosts_down_handled',
'hosts_down_unhandled', 'hosts_down_unhandled',
'hosts_pending', 'hosts_pending',
'services_ok', 'hosts_unreachable_handled',
'services_unknown_handled', 'hosts_unreachable_unhandled',
'services_unknown_unhandled', 'hosts_up',
'servicegroup_alias',
'servicegroup_name',
'services_critical_handled', 'services_critical_handled',
'services_critical_unhandled',
'services_warning_handled',
'services_warning_unhandled',
'services_pending',
'services_ok_last_state_change',
'services_pending_last_state_change',
'services_warning_last_state_change_handled',
'services_critical_last_state_change_handled', 'services_critical_last_state_change_handled',
'services_unknown_last_state_change_handled',
'services_warning_last_state_change_unhandled',
'services_critical_last_state_change_unhandled', 'services_critical_last_state_change_unhandled',
'services_critical_unhandled',
'services_ok',
'services_ok_last_state_change',
'services_pending',
'services_pending_last_state_change',
'services_total',
'services_unknown_handled',
'services_unknown_last_state_change_handled',
'services_unknown_last_state_change_unhandled', 'services_unknown_last_state_change_unhandled',
'services_total' 'services_unknown_unhandled',
))->order('services_severity')->order('servicegroup_alias'); 'services_warning_handled',
// TODO(el): Can't default to the sort rules of the data view because it's meant for both host groups and 'services_warning_last_state_change_handled',
// service groups. We should separate them. 'services_warning_last_state_change_unhandled',
'services_warning_unhandled'
));
$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'),
'services_total' => $this->translate('Total Services'), 'services_total' => $this->translate('Total Services')
'services_ok' => $this->translate('Services OK'), ), $query);
'services_unknown' => $this->translate('Services UNKNOWN'),
'services_critical' => $this->translate('Services CRITICAL'),
'services_warning' => $this->translate('Services WARNING'),
'services_pending' => $this->translate('Services PENDING')
));
} }
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(
'hostgroup_name', $query = $this->backend->select()->from('hostgroupsummary', array(
'hostgroup_alias', 'hostgroup_alias',
'hosts_up', 'hostgroup_name',
'hosts_unreachable_handled',
'hosts_unreachable_unhandled',
'hosts_down_handled', 'hosts_down_handled',
'hosts_down_last_state_change_handled',
'hosts_down_last_state_change_unhandled',
'hosts_down_unhandled', 'hosts_down_unhandled',
'hosts_pending', 'hosts_pending',
'services_ok', 'hosts_pending_last_state_change',
'services_unknown_handled', 'hosts_total',
'services_unknown_unhandled', 'hosts_unreachable_handled',
'hosts_unreachable_last_state_change_handled',
'hosts_unreachable_last_state_change_unhandled',
'hosts_unreachable_unhandled',
'hosts_up',
'hosts_up_last_state_change',
'services_critical_handled', 'services_critical_handled',
'services_critical_unhandled', 'services_critical_unhandled',
'services_warning_handled', 'services_ok',
'services_warning_unhandled',
'services_pending', 'services_pending',
'services_ok_last_state_change', 'services_total',
'services_pending_last_state_change', 'services_unknown_handled',
'services_warning_last_state_change_handled', 'services_unknown_unhandled',
'services_critical_last_state_change_handled', 'services_warning_handled',
'services_unknown_last_state_change_handled', 'services_warning_unhandled'
'services_warning_last_state_change_unhandled',
'services_critical_last_state_change_unhandled',
'services_unknown_last_state_change_unhandled',
'services_total'
))->order('services_severity')->order('hostgroup_alias');
// 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.
$this->filterQuery($query);
$this->view->hostgroups = $query->paginate();
$this->setupSortControl(array(
'services_severity' => $this->translate('Severity'),
'hostgroup_alias' => $this->translate('Host Group Name'),
'services_total' => $this->translate('Total Services'),
'services_ok' => $this->translate('Services OK'),
'services_unknown' => $this->translate('Services UNKNOWN'),
'services_critical' => $this->translate('Services CRITICAL'),
'services_warning' => $this->translate('Services WARNING'),
'services_pending' => $this->translate('Services PENDING')
)); ));
$this->filterQuery($query);
$this->view->hostgroups = $query;
$this->setupLimitControl();
$this->setupPaginationControl($this->view->hostgroups);
$this->setupSortControl(array(
'hosts_severity' => $this->translate('Severity'),
'hostgroup_alias' => $this->translate('Host Group Name'),
'hosts_total' => $this->translate('Total Hosts'),
'services_total' => $this->translate('Total Services')
), $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'),
@ -626,18 +575,17 @@ class Monitoring_ListController extends Controller
)); ));
$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(
@ -651,33 +599,47 @@ 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();
$this->view->verticalPaginator = $pivot->paginateYAxis(); $this->view->verticalPaginator = $pivot->paginateYAxis();
} }
protected function filterQuery($query) /**
* Apply filters on a DataView
*
* @param DataView $dataView The DataView to apply filters on
*
* @return DataView $dataView
*/
protected function filterQuery(DataView $dataView)
{ {
$editor = Widget::create('filterEditor') $editor = Widget::create('filterEditor')
->setQuery($query) ->setQuery($dataView)
->preserveParams('limit', 'sort', 'dir', 'format', 'view', 'backend', 'stateType', 'addColumns') ->preserveParams(
'limit', 'sort', 'dir', 'format', 'view', 'backend',
'stateType', 'addColumns', '_dev'
)
->ignoreParams('page') ->ignoreParams('page')
->setSearchColumns($dataView->getSearchColumns())
->handleRequest($this->getRequest()); ->handleRequest($this->getRequest());
$query->applyFilter($editor->getFilter()); $dataView->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')) { $this->handleFormatRequest($dataView);
$query->order($sort, $this->params->get('dir')); return $dataView;
}
$this->handleFormatRequest($query);
return $query;
} }
protected function extraColumns() /**
* Get columns to be added from URL parameter 'addColumns'
* and assign to $this->view->addColumns (as array)
*
* @return array
*/
protected function addColumns()
{ {
$columns = preg_split( $columns = preg_split(
'~,~', '~,~',
@ -685,7 +647,7 @@ class Monitoring_ListController extends Controller
-1, -1,
PREG_SPLIT_NO_EMPTY PREG_SPLIT_NO_EMPTY
); );
$this->view->extraColumns = $columns; $this->view->addColumns = $columns;
return $columns; return $columns;
} }
@ -706,15 +668,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;
@ -9,6 +10,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommand
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController; use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController;
use Icinga\Web\Hook;
class Monitoring_ServiceController extends MonitoredObjectController class Monitoring_ServiceController extends MonitoredObjectController
{ {
@ -25,22 +27,56 @@ class Monitoring_ServiceController extends MonitoredObjectController
*/ */
public function init() public function init()
{ {
$service = new Service( if ($this->params->get('host') === null || $this->params->get('service') === null) {
$this->backend, throw new MissingParameterException(
$this->params->get('host_name'), $this->translate('One of the required parameters \'%s\' is missing'),
$this->params->get('service_description') 'host or 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();
$this->getTabs()->activate('service'); $this->getTabs()->activate('service');
} }
/**
* Get service actions from hook
*
* @return array
*/
protected function getServiceActions()
{
$urls = array();
foreach (Hook::all('Monitoring\\ServiceActions') as $hook) {
foreach ($hook->getActionsForService($this->object) as $id => $url) {
$urls[$id] = $url;
}
}
return $urls;
}
/**
* Show a service
*/
public function showAction()
{
$this->view->actions = $this->getServiceActions();
parent::showAction();
}
/** /**
* Acknowledge a service problem * Acknowledge a service problem
*/ */

View File

@ -10,12 +10,12 @@ use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm; use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
use Icinga\Module\Monitoring\Object\Host;
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\Tabextension\DashboardAction;
class Monitoring_ServicesController extends Controller class Monitoring_ServicesController extends Controller
{ {
@ -27,70 +27,12 @@ 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(
$this->serviceList = $serviceList; (string) $this->params->without(array('service_problem', 'service_handled', 'view'))
}
protected function handleCommandForm(ObjectsCommandForm $form)
{
$this->serviceList->setColumns(array(
'host_name',
'host_state',
'service_description',
'service_state',
'service_problem',
'service_handled',
'service_acknowledged',
'service_in_downtime'
)); ));
$this->serviceList = $serviceList;
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/services');
$form
->setObjects($this->serviceList)
->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams($this->params))
->handleRequest();
$serviceStates = array(
Service::getStateText(Service::STATE_OK) => 0,
Service::getStateText(Service::STATE_WARNING) => 0,
Service::getStateText(Service::STATE_CRITICAL) => 0,
Service::getStateText(Service::STATE_UNKNOWN) => 0,
Service::getStateText(Service::STATE_PENDING) => 0
);
$knownHostStates = array();
$hostStates = array(
Host::getStateText(Host::STATE_UP) => 0,
Host::getStateText(Host::STATE_DOWN) => 0,
Host::getStateText(Host::STATE_UNREACHABLE) => 0,
Host::getStateText(Host::STATE_PENDING) => 0,
);
foreach ($this->serviceList as $service) {
++$serviceStates[$service::getStateText($service->state)];
if (! isset($knownHostStates[$service->getHost()->getName()])) {
$knownHostStates[$service->getHost()->getName()] = true;
++$hostStates[$service->getHost()->getStateText($service->host_state)];
}
}
$this->view->form = $form;
$this->view->objects = $this->serviceList;
$this->view->serviceStates = $serviceStates;
$this->view->hostStates = $hostStates;
$this->view->serviceStatesPieChart = $this->createPieChart(
$serviceStates,
$this->translate('Service State'),
array('#44bb77', '#FFCC66', '#FF5566', '#E066FF', '#77AAFF')
);
$this->view->hostStatesPieChart = $this->createPieChart(
$hostStates,
$this->translate('Host State'),
array('#44bb77', '#FF5566', '#E066FF', '#77AAFF')
);
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
return $form;
}
public function showAction()
{
$this->getTabs()->add( $this->getTabs()->add(
'show', 'show',
array( array(
@ -98,10 +40,54 @@ class Monitoring_ServicesController extends Controller
$this->translate('Show summarized information for %u services'), $this->translate('Show summarized information for %u services'),
count($this->serviceList) count($this->serviceList)
), ),
'label' => $this->translate('Services'), 'label' => $this->translate('Services') . sprintf(' (%d)', count($this->serviceList)),
'url' => Url::fromRequest() 'url' => Url::fromRequest(),
'icon' => 'services'
) )
)->activate('show'); )->extend(new DashboardAction())->activate('show');
}
protected function handleCommandForm(ObjectsCommandForm $form)
{
$this->serviceList->setColumns(array(
'host_icon_image',
'host_name',
'host_output',
'host_state',
'host_problem',
'host_handled',
'service_icon_image',
'service_description',
'service_state',
'service_problem',
'service_handled',
'service_acknowledged',
'service_in_downtime',
'service_is_flapping',
'service_output',
'service_last_ack',
'service_last_comment',
'service_notifications_enabled',
'service_active_checks_enabled',
'service_passive_checks_enabled'
));
$form
->setObjects($this->serviceList)
->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams($this->params))
->handleRequest();
$this->view->form = $form;
$this->view->objects = $this->serviceList;
$this->view->stats = $this->serviceList->getServiceStateSummary();
$this->view->serviceStates = true;
$this->view->hostStates = $this->serviceList->getHostStateSummary();
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
return $form;
}
public function showAction()
{
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); $checkNowForm = new CheckNowCommandForm();
$checkNowForm $checkNowForm
@ -109,65 +95,33 @@ class Monitoring_ServicesController extends Controller
->handleRequest(); ->handleRequest();
$this->view->checkNowForm = $checkNowForm; $this->view->checkNowForm = $checkNowForm;
$this->serviceList->setColumns(array( $this->serviceList->setColumns(array(
'host_icon_image',
'host_name', 'host_name',
'host_output',
'host_state', 'host_state',
'host_problem',
'host_handled',
'service_icon_image',
'service_output',
'service_description', 'service_description',
'service_state', 'service_state',
'service_problem', 'service_problem',
'service_handled', 'service_handled',
'service_acknowledged', 'service_acknowledged',
'service_in_downtime'/*, 'service_in_downtime',
'service_passive_checks_enabled', 'service_is_flapping',
'service_last_comment',
'service_last_ack',
'service_notifications_enabled', 'service_notifications_enabled',
'service_active_checks_enabled',
'service_passive_checks_enabled'
/*
'service_event_handler_enabled', 'service_event_handler_enabled',
'service_flap_detection_enabled', 'service_flap_detection_enabled',
'service_active_checks_enabled',
'service_obsessing'*/ 'service_obsessing'*/
)); ));
$unhandledObjects = array();
$unhandledFilterExpressions = array(); $acknowledgedObjects = $this->serviceList->getAcknowledgedObjects();
$acknowledgedObjects = array();
$objectsInDowntime = array();
$downtimeFilterExpressions = array();
$serviceStates = array(
Service::getStateText(Service::STATE_OK) => 0,
Service::getStateText(Service::STATE_WARNING) => 0,
Service::getStateText(Service::STATE_CRITICAL) => 0,
Service::getStateText(Service::STATE_UNKNOWN) => 0,
Service::getStateText(Service::STATE_PENDING) => 0
);
$knownHostStates = array();
$hostStates = array(
Host::getStateText(Host::STATE_UP) => 0,
Host::getStateText(Host::STATE_DOWN) => 0,
Host::getStateText(Host::STATE_UNREACHABLE) => 0,
Host::getStateText(Host::STATE_PENDING) => 0,
);
foreach ($this->serviceList as $service) {
/** @var Service $service */
if ((bool) $service->problem === true && (bool) $service->handled === false) {
$unhandledObjects[] = $service;
$unhandledFilterExpressions[] = Filter::matchAll(
Filter::where('host', $service->getHost()->getName()),
Filter::where('service', $service->getName())
);
}
if ((bool) $service->acknowledged === true) {
$acknowledgedObjects[] = $service;
}
if ((bool) $service->in_downtime === true) {
$objectsInDowntime[] = $service;
$downtimeFilterExpressions[] = Filter::matchAll(
Filter::where('host_name', $service->getHost()->getName()),
Filter::where('service_description', $service->getName())
);
}
++$serviceStates[$service::getStateText($service->state)];
if (! isset($knownHostStates[$service->getHost()->getName()])) {
$knownHostStates[$service->getHost()->getName()] = true;
++$hostStates[$service->getHost()->getStateText($service->host_state)];
}
}
if (! empty($acknowledgedObjects)) { if (! empty($acknowledgedObjects)) {
$removeAckForm = new RemoveAcknowledgementCommandForm(); $removeAckForm = new RemoveAcknowledgementCommandForm();
$removeAckForm $removeAckForm
@ -175,53 +129,70 @@ class Monitoring_ServicesController extends Controller
->handleRequest(); ->handleRequest();
$this->view->removeAckForm = $removeAckForm; $this->view->removeAckForm = $removeAckForm;
} }
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/services');
$this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/services/reschedule-check'); $this->view->rescheduleAllLink = Url::fromRequest()->setPath('monitoring/services/reschedule-check');
$this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/services/schedule-downtime'); $this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/services/schedule-downtime');
$this->view->processCheckResultAllLink = Url::fromRequest()->setPath( $this->view->processCheckResultAllLink = Url::fromRequest()->setPath(
'monitoring/services/process-check-result' 'monitoring/services/process-check-result'
); );
$this->view->hostStates = $hostStates; $this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/services/add-comment');
$this->view->serviceStates = $serviceStates; $this->view->deleteCommentLink = Url::fromRequest()->setPath('monitoring/services/delete-comment');
$this->view->stats = $this->serviceList->getServiceStateSummary();
$this->view->hostStats = $this->serviceList->getHostStateSummary();
$this->view->objects = $this->serviceList; $this->view->objects = $this->serviceList;
$this->view->unhandledObjects = $unhandledObjects; $this->view->unhandledObjects = $this->serviceList->getUnhandledObjects();
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString(); $this->view->problemObjects = $this->serviceList->getProblemObjects();
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/services/acknowledge-problem') $this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/services/acknowledge-problem')
->setQueryString($unhandledFilterQueryString); ->setQueryString($this->serviceList->getUnhandledObjects()->objectsFilter()->toQueryString());
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime') $this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime')
->setQueryString($unhandledFilterQueryString); ->setQueryString($this->serviceList->getUnhandledObjects()->objectsFilter()->toQueryString());
$this->view->downtimeLink = Url::fromPath('monitoring/services/schedule-downtime')
->setQueryString($this->serviceList->getProblemObjects()->objectsFilter()->toQueryString());
$this->view->acknowledgedObjects = $acknowledgedObjects; $this->view->acknowledgedObjects = $acknowledgedObjects;
$this->view->objectsInDowntime = $objectsInDowntime; $this->view->objectsInDowntime = $this->serviceList->getObjectsInDowntime();
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes') $this->view->inDowntimeLink = Url::fromPath('monitoring/list/services')
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString()); ->setQueryString($this->serviceList->getObjectsInDowntime()
->objectsFilter(array('host' => 'host_name', 'service' => 'service_description'))->toQueryString());
$this->view->showDowntimesLink = Url::fromPath('monitoring/downtimes/show')
->setQueryString(
$this->serviceList->getObjectsInDowntime()
->objectsFilter()->toQueryString()
);
$this->view->commentsLink = Url::fromRequest() $this->view->commentsLink = Url::fromRequest()
->setPath('monitoring/list/comments'); ->setPath('monitoring/list/comments');
$this->view->serviceStatesPieChart = $this->createPieChart( $this->view->baseFilter = $this->serviceList->getFilter();
$serviceStates, $this->view->sendCustomNotificationLink = Url::fromRequest()->setPath(
$this->translate('Service State'), 'monitoring/services/send-custom-notification'
array('#44bb77', '#FFCC66', '#FF5566', '#E066FF', '#77AAFF')
); );
$this->view->hostStatesPieChart = $this->createPieChart(
$hostStates,
$this->translate('Host State'),
array('#44bb77', '#FF5566', '#E066FF', '#77AAFF')
);
$this->view->sendCustomNotificationLink =
Url::fromRequest()->setPath(
'monitoring/services/send-custom-notification'
);
} }
protected function createPieChart(array $states, $title, array $colors) /**
* Add a service comment
*/
public function addCommentAction()
{ {
$chart = new InlinePie(array_values($states), $title, $colors); $this->assertPermission('monitoring/command/comment/add');
return $chart
->setSize(75) $form = new AddCommentCommandForm();
->setTitle('') $form->setTitle($this->translate('Add Service Comments'));
->setSparklineClass('sparkline-multi'); $this->handleCommandForm($form);
} }
/**
* Delete a comment
*/
public function deleteCommentAction()
{
$this->assertPermission('monitoring/command/comment/delete');
$form = new DeleteCommentCommandForm();
$form->setTitle($this->translate('Delete Service Comments'));
$this->handleCommandForm($form);
}
/** /**
* Acknowledge service problems * Acknowledge service problems
*/ */

View File

@ -70,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()
@ -142,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) {
@ -153,7 +154,7 @@ 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_name', 'host_name',
@ -167,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;
@ -188,13 +189,13 @@ class Monitoring_ShowController extends Controller
if ($object->getType() === $object::TYPE_HOST) { if ($object->getType() === $object::TYPE_HOST) {
$isService = false; $isService = false;
$params = array( $params = array(
'host_name' => $object->getName() 'host' => $object->getName()
); );
} else { } else {
$isService = true; $isService = true;
$params = array( $params = array(
'host_name' => $object->getHost()->getName(), 'host' => $object->getHost()->getName(),
'service_description' => $object->getName() 'service' => $object->getName()
); );
} }
$tabs = $this->getTabs(); $tabs = $this->getTabs();
@ -207,7 +208,7 @@ class Monitoring_ShowController extends Controller
), ),
'label' => $this->translate('Host'), 'label' => $this->translate('Host'),
'icon' => 'host', 'icon' => 'host',
'url' => 'monitoring/host/show', 'url' => 'monitoring/show/host',
'urlParams' => $params, 'urlParams' => $params,
) )
); );
@ -222,7 +223,7 @@ class Monitoring_ShowController extends Controller
), ),
'label' => $this->translate('Service'), 'label' => $this->translate('Service'),
'icon' => 'service', 'icon' => 'service',
'url' => 'monitoring/service/show', 'url' => 'monitoring/show/service',
'urlParams' => $params, 'urlParams' => $params,
) )
); );

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

@ -7,6 +7,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
{ {
@ -19,7 +20,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

@ -85,7 +85,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS, ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS,
array( array(
'label' => $this->translate('Active Host Checks Being Executed'), 'label' => $this->translate('Active Host Checks'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -94,7 +94,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS, ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS,
array( array(
'label' => $this->translate('Active Service Checks Being Executed'), 'label' => $this->translate('Active Service Checks'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -103,7 +103,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS, ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS,
array( array(
'label' => $this->translate('Event Handlers Enabled'), 'label' => $this->translate('Event Handlers'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -112,7 +112,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION, ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION,
array( array(
'label' => $this->translate('Flap Detection Enabled'), 'label' => $this->translate('Flap Detection'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -121,7 +121,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS, ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS,
array( array(
'label' => $this->translate('Notifications Enabled'), 'label' => $this->translate('Notifications'),
'autosubmit' => true, 'autosubmit' => true,
'description' => $notificationDescription, 'description' => $notificationDescription,
'decorators' => array( 'decorators' => array(
@ -159,7 +159,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS, ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS,
array( array(
'label' => $this->translate('Passive Host Checks Being Accepted'), 'label' => $this->translate('Passive Host Checks'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -168,7 +168,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS, ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS,
array( array(
'label' => $this->translate('Passive Service Checks Being Accepted'), 'label' => $this->translate('Passive Service Checks'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -177,7 +177,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA, ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA,
array( array(
'label' => $this->translate('Performance Data Being Processed'), 'label' => $this->translate('Performance Data'),
'autosubmit' => true, 'autosubmit' => true,
'disabled' => $toggleDisabled 'disabled' => $toggleDisabled
) )
@ -209,14 +209,63 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
public function onSuccess() public function onSuccess()
{ {
$this->assertPermission('monitoring/command/feature/instance'); $this->assertPermission('monitoring/command/feature/instance');
$notifications = array(
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS => array(
$this->translate('Enabling active host checks..'),
$this->translate('Disabling active host checks..')
),
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS => array(
$this->translate('Enabling active service checks..'),
$this->translate('Disabling active service checks..')
),
ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS => array(
$this->translate('Enabling event handlers..'),
$this->translate('Disabling event handlers..')
),
ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION => array(
$this->translate('Enabling flap detection..'),
$this->translate('Disabling flap detection..')
),
ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS => array(
$this->translate('Enabling notifications..'),
$this->translate('Disabling notifications..')
),
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING => array(
$this->translate('Enabling obsessing over hosts..'),
$this->translate('Disabling obsessing over hosts..')
),
ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING => array(
$this->translate('Enabling obsessing over services..'),
$this->translate('Disabling obsessing over services..')
),
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS => array(
$this->translate('Enabling passive host checks..'),
$this->translate('Disabling passive host checks..')
),
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS => array(
$this->translate('Enabling passive service checks..'),
$this->translate('Disabling passive service checks..')
),
ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA => array(
$this->translate('Enabling performance data..'),
$this->translate('Disabling performance data..')
)
);
foreach ($this->getValues() as $feature => $enabled) { foreach ($this->getValues() as $feature => $enabled) {
$toggleFeature = new ToggleInstanceFeatureCommand(); $toggleFeature = new ToggleInstanceFeatureCommand();
$toggleFeature $toggleFeature
->setFeature($feature) ->setFeature($feature)
->setEnabled($enabled); ->setEnabled($enabled);
$this->getTransport($this->request)->send($toggleFeature); $this->getTransport($this->request)->send($toggleFeature);
if ((bool) $this->status->{$feature} !== (bool) $enabled) {
Notification::success(
$notifications[$feature][$enabled ? 0 : 1]
);
}
} }
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,23 +27,34 @@ class DeleteCommentCommandForm extends ObjectsCommandForm
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$this->addElements(array( $this->addElements(
array( array(
'hidden',
'comment_id',
array( array(
'required' => true, 'hidden',
'decorators' => array('ViewHelper') 'comment_id',
) array(
), 'required' => true,
array( 'validators' => array('NotEmpty'),
'hidden', 'decorators' => array('ViewHelper')
'redirect', )
),
array( array(
'decorators' => array('ViewHelper') 'hidden',
'comment_is_service',
array(
'filters' => array('Boolean'),
'decorators' => array('ViewHelper')
)
),
array(
'hidden',
'redirect',
array(
'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(); ->setCommentId($this->getElement('comment_id')->getValue());
$delComment $this->getTransport($this->request)->send($cmd);
->setObject($object)
->setCommentId($this->getElement('comment_id')->getValue());
$this->getTransport($this->request)->send($delComment);
}
$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)
@ -19,33 +20,44 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm
{ {
$this->setAttrib('class', 'inline'); $this->setAttrib('class', 'inline');
} }
/** /**
* (non-PHPDoc) * (non-PHPDoc)
* @see \Icinga\Web\Form::createElements() For the method documentation. * @see \Icinga\Web\Form::createElements() For the method documentation.
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$this->addElements(array( $this->addElements(
array( array(
'hidden',
'downtime_id',
array( array(
'required' => true, 'hidden',
'decorators' => array('ViewHelper') 'downtime_id',
) array(
), 'required' => true,
array( 'validators' => array('NotEmpty'),
'hidden', 'decorators' => array('ViewHelper')
'redirect', )
),
array( array(
'decorators' => array('ViewHelper') 'hidden',
'downtime_is_service',
array(
'filters' => array('Boolean'),
'decorators' => array('ViewHelper')
)
),
array(
'hidden',
'redirect',
array(
'decorators' => array('ViewHelper')
)
) )
) )
)); );
return $this; return $this;
} }
/** /**
* (non-PHPDoc) * (non-PHPDoc)
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation. * @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
@ -67,26 +79,23 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm
); );
return $this; return $this;
} }
/** /**
* (non-PHPDoc) * (non-PHPDoc)
* @see \Icinga\Web\Form::onSuccess() For the method documentation. * @see \Icinga\Web\Form::onSuccess() For the method documentation.
*/ */
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

@ -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',
@ -117,6 +117,34 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
public function onSuccess() public function onSuccess()
{ {
$this->assertPermission('monitoring/command/feature/object'); $this->assertPermission('monitoring/command/feature/object');
$notifications = array(
ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS => array(
$this->translate('Enabling active checks..'),
$this->translate('Disabling active checks..')
),
ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS => array(
$this->translate('Enabling passive checks..'),
$this->translate('Disabling passive checks..')
),
ToggleObjectFeatureCommand::FEATURE_OBSESSING => array(
$this->translate('Enabling obsessing..'),
$this->translate('Disabling obsessing..')
),
ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS => array(
$this->translate('Enabling notifications..'),
$this->translate('Disabling notifications..')
),
ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER => array(
$this->translate('Enabling event handler..'),
$this->translate('Disabling event handler..')
),
ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION => array(
$this->translate('Enabling flap detection..'),
$this->translate('Disabling flap detection..')
)
);
foreach ($this->objects as $object) { foreach ($this->objects as $object) {
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
foreach ($this->getValues() as $feature => $enabled) { foreach ($this->getValues() as $feature => $enabled) {
@ -127,10 +155,13 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
->setObject($object) ->setObject($object)
->setEnabled($enabled); ->setEnabled($enabled);
$this->getTransport($this->request)->send($toggleFeature); $this->getTransport($this->request)->send($toggleFeature);
Notification::success(
$notifications[$feature][$enabled ? 0 : 1]
);
} }
} }
} }
Notification::success($this->translate('Toggling feature..'));
return true; return true;
} }
} }

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

@ -0,0 +1,39 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
/**
* Generate icons to describe a given hosts state
*/
class Zend_View_Helper_HostFlags extends Zend_View_Helper_Abstract
{
public function hostFlags($host)
{
$icons = array();
if (! $host->host_handled && $host->host_state > 0) {
$icons[] = $this->view->icon('attention-alt', $this->view->translate('Unhandled'));
}
if ($host->host_acknowledged) {
$icons[] = $this->view->icon('ok', $this->view->translate('Acknowledged'));
}
if ($host->host_is_flapping) {
$icons[] = $this->view->icon('flapping', $this->view->translate('Flapping'));
}
if (! $host->host_notifications_enabled) {
$icons[] = $this->view->icon('bell-off-empty', $this->view->translate('Notifications Disabled'));
}
if ($host->host_in_downtime) {
$icons[] = $this->view->icon('plug', $this->view->translate('In Downtime'));
}
if (! $host->host_active_checks_enabled) {
if (! $host->host_passive_checks_enabled) {
$icons[] = $this->view->icon('eye-off', $this->view->translate('Active And Passive Checks Disabled'));
} else {
$icons[] = $this->view->icon('eye-off', $this->view->translate('Active Checks Disabled'));
}
}
if (isset($host->host_last_comment) && $host->host_last_comment !== null) {
$icons[] = $this->view->icon('comment', $this->view->translate('Last Comment: ') . $host->host_last_comment);
}
return $icons;
}
}

View File

@ -0,0 +1,46 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
/**
* Generate icons to describe a given hosts state
*/
class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
{
/**
* Create dispatch instance
*
* @return \Zend_View_Helper_IconImage
*/
public function iconImage()
{
return $this;
}
/**
* Display the image_icon of a MonitoredObject
*
* @param MonitoredObject|stdClass $object The host or service
* @return string
*/
public function host($object)
{
if ($object->host_icon_image && ! preg_match('/[\'"]/', $object->host_icon_image)) {
return $this->view->icon($this->view->resolveMacros($object->host_icon_image, $object));
}
return '';
}
/**
* Display the image_icon of a MonitoredObject
*
* @param MonitoredObject|stdClass $object The host or service
* @return string
*/
public function service($object)
{
if ($object->service_icon_image && ! preg_match('/[\'"]/', $object->service_icon_image)) {
return $this->view->icon($this->view->resolveMacros($object->service_icon_image, $object));
}
return '';
}
}

View File

@ -33,7 +33,7 @@ class Zend_View_Helper_Link extends Zend_View_Helper_Abstract
return $this->view->qlink( return $this->view->qlink(
$linkText, $linkText,
'monitoring/host/show', 'monitoring/host/show',
array('host_name' => $host), array('host' => $host),
array('title' => sprintf($this->view->translate('Show detailed information for host %s'), $host)) array('title' => sprintf($this->view->translate('Show detailed information for host %s'), $host))
); );
} }
@ -55,7 +55,7 @@ class Zend_View_Helper_Link extends Zend_View_Helper_Abstract
$this->view->qlink( $this->view->qlink(
$serviceLinkText, $serviceLinkText,
'monitoring/service/show', 'monitoring/service/show',
array('host_name' => $host, 'service_description' => $service), array('host' => $host, 'service' => $service),
array('title' => sprintf( array('title' => sprintf(
$this->view->translate('Show detailed information for service %s on host %s'), $this->view->translate('Show detailed information for service %s on host %s'),
$service, $service,

View File

@ -65,7 +65,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
parse_str($m[1], $params); parse_str($m[1], $params);
if (isset($params['host'])) { if (isset($params['host'])) {
$tag->setAttribute('href', $this->view->baseUrl( $tag->setAttribute('href', $this->view->baseUrl(
'/monitoring/host/show?host_name=' . urlencode($params['host'] '/monitoring/host/show?host=' . urlencode($params['host']
))); )));
} }
} else { } else {

View File

@ -1,24 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
class Zend_View_Helper_SelectionToolbar extends Zend_View_Helper_Abstract
{
/**
* Create a selection toolbar
*
* @param $type
* @param null $target
*
* @return string
*/
public function selectionToolbar($type, $target = null)
{
return '';
if ($type == 'multi') {
return '<div class="selection-toolbar">'
. '<a href="' . $target . '" data-base-target="_next"> Show All </a> </div>';
} else {
return '';
}
}
}

View File

@ -0,0 +1,40 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
class Zend_View_Helper_ServiceFlags extends Zend_View_Helper_Abstract
{
public function serviceFlags($service) {
$icons = array();
if (!$service->service_handled && $service->service_state > 0) {
$icons[] = $this->view->icon('attention-alt', $this->view->translate('Unhandled'));
}
if ($service->service_acknowledged && !$service->service_in_downtime) {
$icons[] = $this->view->icon('ok', $this->view->translate('Acknowledged') . (
$service->service_last_ack ? ': ' . $service->service_last_ack : ''
));
}
if ($service->service_is_flapping) {
$icons[] = $this->view->icon('flapping', $this->view->translate('Flapping')) ;
}
if (!$service->service_notifications_enabled) {
$icons[] = $this->view->icon('bell-off-empty', $this->view->translate('Notifications Disabled'));
}
if ($service->service_in_downtime) {
$icons[] = $this->view->icon('plug', $this->view->translate('In Downtime'));
}
if (isset($service->service_last_comment) && $service->service_last_comment !== null) {
$icons[] = $this->view->icon(
'comment',
$this->view->translate('Last Comment: ') . $service->service_last_comment
);
}
if (!$service->service_active_checks_enabled) {
if (!$service->service_passive_checks_enabled) {
$icons[] = $this->view->icon('eye-off', $this->view->translate('Active And Passive Checks Disabled'));
} else {
$icons[] = $this->view->icon('eye-off', $this->view->translate('Active Checks Disabled'));
}
}
return $icons;
}
}

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,25 @@
<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 multi-commands">
<h3><?= $this->icon('reschedule') ?> <?= $this->translate('Commands') ?> </h3>
<?= $this->qlink(
sprintf(
$this->translate('Remove %d comments'),
count($comments)
),
$removeAllLink,
null,
array(
'icon' => 'trash',
'title' => $this->translate('Remove all selected comments.')
)
) ?>
</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,24 @@
<div class="controls">
<?php if (! $this->compact): ?>
<?= $this->tabs; ?>
<?php endif ?>
<?= $this->render('partials/downtime/downtimes-header.phtml'); ?>
</p>
</div>
<div class="content multi-commands">
<h3><?= $this->icon('reschedule') ?> <?= $this->translate('Commands') ?> </h3>
<?= $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>

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,124 +1,231 @@
<div class="controls"> <div data-base-target='_next' class="controls">
<?php if (! $this->compact): ?>
<?= $tabs; ?>
<?php endif ?>
<?= $this->render('list/components/hostssummary.phtml') ?>
<?= $this->render('partials/host/objects-header.phtml'); ?> <?= $this->render('partials/host/objects-header.phtml'); ?>
</div> </div>
<div class="content">
<div class="content multi-commands">
<h3>
<?= $this->icon('reschedule') ?>
<?= $this->translate('Commands') ?>
</h3>
<p>
<?= sprintf($this->translatePlural(
'Issue commands to %s selected host:',
'Issue commands to all %s selected hosts:',
count($objects)
), '<b>' . count($objects) . '</b>') ?>
</p>
<?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> <?= $checkNowForm; ?>
<div><?= $this->qlink(
sprintf($this->translate('List all %u hosts'), $hostCount), <br>
$listAllLink <?= $this->qlink(
); ?></div> $this->translate('Reschedule next checks'),
<div>
<?= $checkNowForm; ?>
</div>
<div><?= $this->qlink(
sprintf($this->translate('Reschedule the next check for all %u hosts'), $hostCount),
$rescheduleAllLink, $rescheduleAllLink,
null, null,
array('icon' => 'reschedule') array('icon' => 'reschedule')
); ?></div> ); ?>
<div><?= $this->qlink(
sprintf($this->translate('Schedule a downtime for all %u hosts'), $hostCount), <br>
<?= $this->qlink(
$this->translate('Schedule downtimes'),
$downtimeAllLink, $downtimeAllLink,
null, null,
array('icon' => 'plug') array('icon' => 'plug')
); ?></div> ); ?>
<div><?= $this->qlink(
sprintf($this->translate('Submit a passive check result for all %u hosts'), $hostCount), <br>
<?= $this->qlink(
$this->translate('Submit passive check results'),
$processCheckResultAllLink, $processCheckResultAllLink,
null, null,
array('icon' => 'reply') array('icon' => 'reply')
); ?></div> ); ?>
<br>
<?= $this->qlink(
$this->translate('Add comments'),
$addCommentLink,
null,
array('icon' => 'comment')
); ?>
<?php if ($this->hasPermission('monitoring/command/send-custom-notification')): ?> <?php if ($this->hasPermission('monitoring/command/send-custom-notification')): ?>
<div><?= $this->qlink( <br>
sprintf($this->translate('Send a custom notification for all %u hosts'), $hostCount), <?= $this->qlink(
$sendCustomNotificationLink, sprintf($this->translate('Send a custom notification for all %u hosts'), $hostCount),
null, $sendCustomNotificationLink,
array('icon' => 'comment') null,
); ?></div> array('icon' => 'comment')
); ?>
<?php endif; ?> <?php endif; ?>
<?php if (($unhandledCount = count($unhandledObjects)) > 0): ?>
<div> <?php
<h3><?= sprintf( $unhandledCount = count($unhandledObjects);
$this->translatePlural( $problemCount = count($problemObjects);
'%u Unhandled Host Problem', ?>
'%u Unhandled Host Problems',
$unhandledCount <?php if ($problemCount || $unhandledCount): ?>
), <h3>
$unhandledCount <?= $this->icon('attention-alt') ?>
); ?></h3> <?= $this->translatePlural(
<div><?= $this->qlink( 'Problem',
sprintf( 'Problems',
$unhandledCount + $problemCount
) ?>
</h3>
<?php if ($problemCount): ?>
<p>
<?= sprintf(
$this->translatePlural( $this->translatePlural(
'Schedule a downtime for %u unhandled host problem', 'There is %s problem.',
'Schedule a downtime for %u unhandled host problems', 'There are %s problems.',
$problemCount
),
'<b>' . $problemCount . '</b>'
); ?>
</p>
<?= $this->qlink(
sprintf(
$this->translatePlural(
'Schedule a downtime for %u problem host',
'Schedule a downtime for %u problem hosts',
$problemCount
),
$problemCount
),
$downtimeLink,
null,
array('icon' => 'plug')
); ?>
<?php endif; ?>
<?php if ($unhandledCount): ?>
<p>
<?= sprintf(
$this->translatePlural(
'There is %s unhandled problem host, issue commands to the problematic host:',
'There are %s unhandled problem hosts, issue commands to the problematic hosts:',
$unhandledCount
),
'<span class="badge badge-critical">' . $unhandledCount . '</span>'
); ?>
</p>
<?= $this->qlink(
sprintf(
$this->translatePlural(
'Schedule a downtime for %u unhandled problem host',
'Schedule a downtime for %u unhandled problem hosts',
$unhandledCount
),
$unhandledCount
),
$downtimeUnhandledLink,
null,
array('icon' => 'plug')
); ?>
<br>
<?= $this->qlink(
sprintf(
$this->translatePlural(
'Acknowledge %u unhandled problem host',
'Acknowledge %u unhandled problem hosts',
$unhandledCount
),
$unhandledCount $unhandledCount
), ),
$unhandledCount $acknowledgeUnhandledLink,
), null,
$downtimeUnhandledLink, array('icon' => 'ok')
null, ); ?>
array('icon' => 'plug')
); ?></div> <?php endif; ?>
<div><?= $this->qlink( <?php endif;?>
sprintf(
$this->translatePlural(
'Acknowledge %u unhandled host problem',
'Acknowledge %u unhandled host problems',
$unhandledCount
),
$unhandledCount
),
$acknowledgeUnhandledLink,
null,
array('icon' => 'ok')
); ?></div>
</div>
<?php endif ?>
<?php if (($acknowledgedCount = count($acknowledgedObjects)) > 0): ?> <?php if (($acknowledgedCount = count($acknowledgedObjects)) > 0): ?>
<div> <div>
<h2><?= sprintf( <h3><?= $this->icon('ok', $this->translate('Acknowledgements')) ?> <?= $this->translate('Acknowledgements') ?></h3>
<?= sprintf(
$this->translatePlural( $this->translatePlural(
'%u Acknowledged Host Problem', '%s Acknowledged Host Problem',
'%u Acknowledged Host Problems', '%s Acknowledged Host Problems',
$acknowledgedCount $acknowledgedCount
), ),
$acknowledgedCount '<b>' . $acknowledgedCount . '</b>'
); ?></h2> ); ?>
<?= $removeAckForm ?> <?= $removeAckForm ?>
</div> </div>
<?php endif ?> <?php endif ?>
<?php if (($inDowntimeCount = count($objectsInDowntime)) > 0): ?>
<h2><?= $this->qlink( <?php $scheduledDowntimeCount = count($objects->getScheduledDowntimes()) ?>
sprintf(
$this->translatePlural( <?php if ($scheduledDowntimeCount): ?>
'List %u host currently in downtime', <h3><?= $this->icon('plug', $this->translate('Downtimes'))?> <?=$this->translate('Downtimes')?></h3>
'List %u hosts currently in downtime', <?= $this->qlink(
$inDowntimeCount sprintf(
$this->translatePlural(
'%s scheduled downtime',
'%s scheduled downtimes',
$scheduledDowntimeCount
),
$scheduledDowntimeCount
), ),
$inDowntimeCount $showDowntimesLink,
), null,
$inDowntimeLink, array('data-base-target' => '_next')
null, );?>
array('icon' => 'plug') <?= sprintf($this->translate('on all selected hosts.')) ?>
); ?></h2>
<?php if (($inDowntimeCount = count($objectsInDowntime)) > 0): ?>
<br>
<?= $this->qlink(
sprintf(
$this->translatePlural(
'%s host',
'%s hosts',
$inDowntimeCount
),
$inDowntimeCount
),
$inDowntimeLink,
null,
array('data-base-target' => '_next')
); ?>
<?= $this->translate('are currently in downtime.') ?>
<?php endif; ?>
<?php endif ?> <?php endif ?>
<?php if (($commentCount = count($objects->getComments())) > 0): ?> <?php if (($commentCount = count($objects->getComments())) > 0): ?>
<h2><?= $this->qlink( <h3> <?= $this->icon('comment', $this->translate('Comments'))?> <?=$this->translate('Comments') ?></h3>
<?= $this->qlink(
sprintf( sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host comment', '%s comment',
'List %u host comments', '%s comments',
$commentCount $commentCount
), ),
$commentCount $commentCount
), ),
$commentsLink, $commentsLink,
null, null,
array('icon' => 'comment') array('data-base-target' => '_next')
); ?></h2> ); ?>
<?= $this->translate('on all selected hosts.') ?>
<?php endif ?> <?php endif ?>
<?php endif ?> <?php endif ?>
</div> </div>

View File

@ -1,71 +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): ?> <?php
<?= $this->translate('No comments matching the filter'); ?>
</div>
<?php return; endif ?>
<table data-base-target="_next" class="action comments"> if (count($comments) === 0) {
echo $this->translate('No comments found matching the filter') . '</div>';
return;
}
?>
<table data-base-target="_next"
class="action comments multiselect"
data-icinga-multiselect-url="/icingaweb2/monitoring/comments/show"
data-icinga-multiselect-data="comment_id">
<tbody> <tbody>
<?php foreach ($comments as $comment): ?> <?php foreach ($comments as $comment):
<?php $this->comment = $comment; ?>
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;
}
?>
<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->timeAgo($comment->timestamp, $this->compact); ?>
</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_description, <?= $this->qlink(
$comment->service_display_name, sprintf(
$comment->host_name, $this->translate('%s on %s', 'Service running on host'),
$comment->host_display_name $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_name, $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>
@ -83,17 +82,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( 'comment_id' => $comment->id,
$this->url('monitoring/host/delete-comment', array('host_name' => $comment->host_name)) 'comment_is_service' => isset($comment->service_description)
); )
} else { );
$delCommentForm->setAction($this->url('monitoring/service/delete-comment', array(
'host_name' => $comment->host_name,
'service_description' => $comment->service_description
)));
}
echo $delCommentForm; echo $delCommentForm;
?> ?>
</td> </td>

View File

@ -1,7 +1,17 @@
<?php <?php
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Data\Filter\Filter;
function urlAddFilterOptional($url, $filter, $optional) {
$url = Url::fromPath($url);
$f = $filter;
if (isset($optional)) {
$f = Filter::matchAll($filter, $optional);
}
return $url->setQueryString($f->toQueryString());
}
$this->baseFilter = isset($this->baseFilter) ? $this->baseFilter : null;
$selfUrl = 'monitoring/list/hosts'; $selfUrl = 'monitoring/list/hosts';
$currentUrl = Url::fromRequest()->getRelativeUrl(); $currentUrl = Url::fromRequest()->getRelativeUrl();
?><div class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : ''; ?>> ?><div class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : ''; ?>>
@ -10,17 +20,22 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<?php if ($this->stats->hosts_up): ?> <?php if ($this->stats->hosts_up): ?>
<span class="state ok<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 0))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state ok<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 0))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_up, $this->stats->hosts_up,
$selfUrl, urlAddFilterOptional(
array('host_state' => 0), $selfUrl,
array('title' => sprintf( Filter::where('host_state', 0),
$this->translatePlural( $this->baseFilter
'List %u host that is currently in state UP',
'List %u hosts which are currently in state UP',
$this->stats->hosts_up
), ),
$this->stats->hosts_up null,
)) array('title' => sprintf(
$this->translatePlural(
'List %u host that is currently in state UP',
'List %u hosts which are currently in state UP',
$this->stats->hosts_up
),
$this->stats->hosts_up
)
)
); ?> ); ?>
</span> </span>
<?php endif; ?> <?php endif; ?>
@ -29,11 +44,12 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="state critical<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 1, 'host_unhandled' => 1))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state critical<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 1, 'host_unhandled' => 1))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_down_unhandled, $this->stats->hosts_down_unhandled,
$selfUrl, urlAddFilterOptional(
array( $selfUrl,
'host_state' => 1, Filter::matchAll(Filter::where('host_state', 1), Filter::where('host_unhandled', 1)),
'host_unhandled' => 1 $this->baseFilter
), ),
null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host that is currently in state DOWN', 'List %u host that is currently in state DOWN',
@ -49,11 +65,12 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="state handled critical<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 1, 'host_unhandled' =>0))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state handled critical<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 1, 'host_unhandled' =>0))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_down_handled, $this->stats->hosts_down_handled,
$selfUrl, urlAddFilterOptional(
array( $selfUrl,
'host_state' => 1, Filter::matchAll(Filter::where('host_state', 1), Filter::where('host_unhandled', 0)),
'host_unhandled' => 0 $this->baseFilter
), ),
null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host that is currently in state DOWN (Acknowledged)', 'List %u host that is currently in state DOWN (Acknowledged)',
@ -74,11 +91,12 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="state unknown<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 2, 'host_unhandled' => 1))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state unknown<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 2, 'host_unhandled' => 1))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_unreachable_unhandled, $this->stats->hosts_unreachable_unhandled,
$selfUrl, urlAddFilterOptional(
array( $selfUrl,
'host_state' => 2, Filter::matchAll(Filter::where('host_state', 2), Filter::where('host_unhandled', 1)),
'host_unhandled' => 1 $this->baseFilter
), ),
null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host that is currently in state UNREACHABLE', 'List %u host that is currently in state UNREACHABLE',
@ -94,11 +112,12 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="state handled unknown<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 2, 'host_unhandled' => 0))->getRelativeUrl() ? ' active' : '' ?>"> <span class="state handled unknown<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 2, 'host_unhandled' => 0))->getRelativeUrl() ? ' active' : '' ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_unreachable_handled, $this->stats->hosts_unreachable_handled,
$selfUrl, urlAddFilterOptional(
array( $selfUrl,
'host_state' => 2, Filter::matchAll(Filter::where('host_state', 2), Filter::where('host_unhandled', 0)),
'host_unhandled' => 0 $this->baseFilter
), ),
null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host that is currently in state UNREACHABLE (Acknowledged)', 'List %u host that is currently in state UNREACHABLE (Acknowledged)',
@ -119,8 +138,12 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="state pending<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 99))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state pending<?= $currentUrl === Url::fromPath($selfUrl, array('host_state' => 99))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->hosts_pending, $this->stats->hosts_pending,
$selfUrl, urlAddFilterOptional(
array('host_state' => 99), $selfUrl,
Filter::where('host_state', 99),
$this->baseFilter
),
null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u host that is currently in state PENDING', 'List %u host that is currently in state PENDING',

View File

@ -1,8 +1,19 @@
<?php <?php
use Icinga\Data\Filter\Filter;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
function urlAddFilterOptional($url, $filter, $optional) {
$url = Url::fromPath($url);
$f = $filter;
if (isset($optional)) {
$f = Filter::matchAll($filter, $optional);
}
return $url->setQueryString($f->toQueryString());
}
$this->baseFilter = isset($this->baseFilter) ? $this->baseFilter : null;
$selfUrl = 'monitoring/list/services'; $selfUrl = 'monitoring/list/services';
$currentUrl = Url::fromRequest()->getRelativeUrl(); $currentUrl = Url::fromRequest()->getRelativeUrl();
?><div class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : ''; ?>> ?><div class="tinystatesummary" <?= $this->compact ? ' data-base-target="col1"' : ''; ?>>
@ -10,19 +21,21 @@ $currentUrl = Url::fromRequest()->getRelativeUrl();
<span class="badges"> <span class="badges">
<?php if ($this->stats->services_ok): ?> <?php if ($this->stats->services_ok): ?>
<span class="state ok<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 0))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state ok<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 0))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?=
$this->stats->services_ok, $this->qlink(
$selfUrl, $this->stats->services_ok,
array('service_state' => 0), urlAddFilterOptional($selfUrl, Filter::where('service_state', 0), $this->baseFilter),
array('title' => sprintf( null,
$this->translatePlural( array('title' => sprintf(
'List %u service that is currently in state OK', $this->translatePlural(
'List %u services which are currently in state OK', 'List %u service that is currently in state OK',
'List %u services which are currently in state OK',
$this->stats->services_ok
),
$this->stats->services_ok $this->stats->services_ok
), ))
$this->stats->services_ok );
)) ?>
); ?>
</span> </span>
<?php endif ?> <?php endif ?>
<?php <?php
@ -31,12 +44,18 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $
if ($this->stats->$pre) { if ($this->stats->$pre) {
$handled = $pre . '_handled'; $handled = $pre . '_handled';
$unhandled = $pre . '_unhandled'; $unhandled = $pre . '_unhandled';
$paramsHandled = array('service_state' => $stateId, 'service_handled' => 1); $paramsHandled = Filter::matchAll(
$paramsUnhandled = array('service_state' => $stateId, 'service_handled' => 0); Filter::where('service_state', $stateId),
Filter::where('service_handled', 1)
);
$paramsUnhandled = Filter::matchAll(
Filter::where('service_state', $stateId),
Filter::where('service_handled', 0)
);
if ($this->stats->$unhandled) { if ($this->stats->$unhandled) {
$compareUrl = Url::fromPath($selfUrl, $paramsUnhandled)->getRelativeUrl(); $compareUrl = Url::fromPath($selfUrl)->setQueryString($paramsUnhandled->toQueryString())->getRelativeUrl();
} else { } else {
$compareUrl = Url::fromPath($selfUrl, $paramsHandled)->getRelativeUrl(); $compareUrl = Url::fromPath($selfUrl)->setQueryString($paramsUnhandled->toQueryString())->getRelativeUrl();
} }
if ($compareUrl === $currentUrl) { if ($compareUrl === $currentUrl) {
@ -50,8 +69,8 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $
echo $this->qlink( echo $this->qlink(
$this->stats->$unhandled, $this->stats->$unhandled,
$selfUrl, urlAddFilterOptional($selfUrl, $paramsUnhandled, $this->baseFilter),
$paramsUnhandled, null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state %s', 'List %u service that is currently in state %s',
@ -65,7 +84,7 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $
} }
if ($this->stats->$handled) { if ($this->stats->$handled) {
if (Url::fromPath($selfUrl, $paramsHandled)->getRelativeUrl() === $currentUrl) { if (Url::fromPath($selfUrl)->setQueryString($paramsHandled->toQueryString())->getRelativeUrl() === $currentUrl) {
$active = ' active'; $active = ' active';
} else { } else {
$active = ''; $active = '';
@ -75,8 +94,8 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $
} }
echo $this->qlink( echo $this->qlink(
$this->stats->$handled, $this->stats->$handled,
$selfUrl, urlAddFilterOptional($selfUrl, $paramsHandled, $this->baseFilter),
$paramsHandled, null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state %s (Acknowledged)', 'List %u service that is currently in state %s (Acknowledged)',
@ -99,8 +118,8 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $
<span class="state pending<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 99))->getRelativeUrl() ? ' active' : ''; ?>"> <span class="state pending<?= $currentUrl === Url::fromPath($selfUrl, array('service_state' => 99))->getRelativeUrl() ? ' active' : ''; ?>">
<?= $this->qlink( <?= $this->qlink(
$this->stats->services_pending, $this->stats->services_pending,
$selfUrl, urlAddFilterOptional($selfUrl, Filter::where('service_state', 99), $this->baseFilter),
array('service_state' => 99), null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state PENDING', 'List %u service that is currently in state PENDING',

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): ?>

View File

@ -1,18 +1,21 @@
<?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; ?>
</div> <?= $this->paginator; ?>
<?= $this->paginationControl($contacts, null, null, array('preserve' => $this->preserve)); ?> <?= $this->filterEditor; ?>
</div> </div>
<?php endif ?>
<div data-base-target="_next" class="content contacts"> <div data-base-target="_next" class="content contacts">
<?php <?php
if (count($contacts) === 0) {
echo $this->translate('No contacts matching the filter'); if (count($contacts) === 0) {
return; echo $this->translate('No contacts found matching the filter') . '</div>';
} 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(

View File

@ -1,32 +1,35 @@
<?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): ?> </div>
<?= $this->filterPreview ?> <div class="tinystatesummary">
<?php endif; ?> <?= count($downtimes) ?> <?= $this->translate('Downtimes') ?>
</div> </div>
<?= $this->widget('limiter', array('url' => $this->url, 'max' => $downtimes->count())); ?> <?= $this->sortBox; ?>
<?= $this->paginationControl($downtimes, null, null, array('preserve' => $this->preserve)); ?> <?= $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
@ -45,15 +48,22 @@ use Icinga\Module\Monitoring\Object\Service;
<?= $downtime->is_in_effect ? $this->timeSince($downtime->start, $this->compact) : $this->timeUntil($downtime->start, $this->compact) ?> <?= $downtime->is_in_effect ? $this->timeSince($downtime->start, $this->compact) : $this->timeUntil($downtime->start, $this->compact) ?>
</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_description, $downtime->service_display_name, $downtime->host_name, $downtime->host_display_name } else {
) ?> echo $this->icon('host');
<?php else: ?> }
<?= $this->icon('host', $this->translate('Host')); ?> ?>
<?= $this->link()->host($downtime->host_name, $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_name) ?>] <?= $this->escape($downtime->comment) ?> <?= $this->icon('comment', $this->translate('Comment')); ?> [<?= $this->escape($downtime->author_name) ?>] <?= $this->escape($downtime->comment) ?>
<br> <br>
@ -109,15 +119,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 (! $isService) { array(
$delDowntimeForm->setAction($this->url('monitoring/host/delete-downtime', array('host_name' => $downtime->host_name))); 'downtime_id' => $downtime->id,
} else { 'downtime_is_service' => isset($downtime->service_description)
$delDowntimeForm->setAction($this->url('monitoring/service/delete-downtime', array( )
'host_name' => $downtime->host_name, );
'service_description' => $downtime->service_description
)));
}
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 (! $compact): ?>
<div class="controls">
<?= $this->tabs->render($this); ?>
<div class="fake-controls">
<?= $form ?>
</div>
</div>
<? endif; ?>
if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs; ?>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<?= $this->paginator; ?>
<?= $this->filterEditor; ?>
<?= $form; ?>
</div>
<?php 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 (count($history) === 0): ?> 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): ?>

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