mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-27 07:44:04 +02:00
Merge branch 'master' into feature/restrict-custom-variables-10965
This commit is contained in:
commit
4d488ab354
@ -16,7 +16,7 @@ Icinga Core and any other monitoring backend compatible with the IDO database.
|
||||
|
||||
## Installation
|
||||
|
||||
For installing Icinga Web 2 please read [doc/installation.md](doc/installation.md).
|
||||
For installing Icinga Web 2 please read [doc/02-Installation.md](doc/02-Installation.md).
|
||||
|
||||
## Support
|
||||
|
||||
|
@ -244,20 +244,35 @@ class DashboardController extends ActionController
|
||||
if (! $this->dashboard->hasPanes()) {
|
||||
$this->view->title = 'Dashboard';
|
||||
} else {
|
||||
if ($this->_getParam('pane')) {
|
||||
$pane = $this->_getParam('pane');
|
||||
$this->dashboard->activate($pane);
|
||||
}
|
||||
if ($this->dashboard === null) {
|
||||
$this->view->title = 'Dashboard';
|
||||
} else {
|
||||
$this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard';
|
||||
if ($this->hasParam('remove')) {
|
||||
$this->dashboard->getActivePane()->removeDashlet($this->getParam('remove'));
|
||||
$this->dashboard->getConfig()->saveIni();
|
||||
$this->redirectNow(URL::fromRequest()->remove('remove'));
|
||||
$panes = array_filter(
|
||||
$this->dashboard->getPanes(),
|
||||
function ($pane) {
|
||||
return ! $pane->getDisabled();
|
||||
}
|
||||
);
|
||||
if (empty($panes)) {
|
||||
$this->view->title = 'Dashboard';
|
||||
$this->getTabs()->add('dashboard', array(
|
||||
'active' => true,
|
||||
'title' => $this->translate('Dashboard'),
|
||||
'url' => Url::fromRequest()
|
||||
));
|
||||
} else {
|
||||
if ($this->_getParam('pane')) {
|
||||
$pane = $this->_getParam('pane');
|
||||
$this->dashboard->activate($pane);
|
||||
}
|
||||
if ($this->dashboard === null) {
|
||||
$this->view->title = 'Dashboard';
|
||||
} else {
|
||||
$this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard';
|
||||
if ($this->hasParam('remove')) {
|
||||
$this->dashboard->getActivePane()->removeDashlet($this->getParam('remove'));
|
||||
$this->dashboard->getConfig()->saveIni();
|
||||
$this->redirectNow(URL::fromRequest()->remove('remove'));
|
||||
}
|
||||
$this->view->dashboard = $this->dashboard;
|
||||
}
|
||||
$this->view->dashboard = $this->dashboard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->dashboard->getPanes() as $pane): ?>
|
||||
<?php if ($pane->getDisabled()) continue; ?>
|
||||
<tr style="background-color: #f1f1f1;">
|
||||
<th colspan="2" style="text-align: left; padding: 0.5em;">
|
||||
<?= $this->escape($pane->getName()) ?>
|
||||
@ -43,7 +44,7 @@
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($dashlets as $dashlet): ?>
|
||||
<?php if ($dashlet->getDisabled() === true) continue; ?>
|
||||
<?php if ($dashlet->getDisabled()) continue; ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= $this->qlink(
|
||||
|
@ -5,16 +5,14 @@ use Icinga\Data\Reducible;
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls separated">
|
||||
<?= $tabs; ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
</div>
|
||||
<div>
|
||||
<?= $this->backendSelection; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->backendSelection ?>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
@ -45,8 +43,7 @@ if (! isset($backend)) {
|
||||
<?php if (! $groups->hasResult()): ?>
|
||||
<p><?= $this->translate('No user groups found matching the filter'); ?></p>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php return; endif ?>
|
||||
<table data-base-target="_next" class="table-row-selectable common-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -85,8 +82,9 @@ if (! isset($backend)) {
|
||||
'group' => $group->group_name
|
||||
),
|
||||
array(
|
||||
'class' => 'action-link',
|
||||
'title' => sprintf($this->translate('Remove user group %s'), $group->group_name),
|
||||
'icon' => 'trash'
|
||||
'icon' => 'cancel'
|
||||
)
|
||||
); ?>
|
||||
</td>
|
||||
|
@ -5,16 +5,14 @@ use Icinga\Data\Reducible;
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls separated">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
</div>
|
||||
<div>
|
||||
<?= $this->backendSelection ?>
|
||||
<?= $this->filterEditor ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->backendSelection ?>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
|
@ -4,7 +4,7 @@ The preferred way of installing Icinga Web 2 is to use the official package repo
|
||||
system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source.
|
||||
|
||||
In case you are upgrading from an older version of Icinga Web 2
|
||||
please make sure to read the [upgrading](installation.md#upgrading) section
|
||||
please make sure to read the [upgrading](02-Installation.md#upgrading) section
|
||||
thoroughly.
|
||||
|
||||
## <a id="installing-requirements"></a> Installing Requirements
|
||||
@ -179,7 +179,7 @@ git clone git://git.icinga.org/icingaweb2.git
|
||||
|
||||
### <a id="installing-from-source-requirements"></a> Installing Requirements from Source
|
||||
|
||||
You will need to install certain dependencies depending on your setup listed [here](installation.md#installing-requirements).
|
||||
You will need to install certain dependencies depending on your setup listed [here](02-Installation.md#installing-requirements).
|
||||
|
||||
The following example installs Apache2 as web server, MySQL as RDBMS and uses the PHP adapter for MySQL.
|
||||
Adopt the package requirements to your needs (e.g. adding ldap for authentication) and distribution.
|
||||
@ -318,7 +318,7 @@ Puppet, Ansible, Chef, etc. modules.
|
||||
> Read the documentation on the respective linked configuration sections before
|
||||
> deploying the configuration manually.
|
||||
>
|
||||
> If you are unsure about certain settings, use the [setup wizard](installation.md#web-setup-wizard-from-source) once
|
||||
> If you are unsure about certain settings, use the [setup wizard](02-Installation.md#web-setup-wizard-from-source) once
|
||||
> and then collect the generated configuration as well as sql dumps.
|
||||
|
||||
#### <a id="web-setup-manual-from-source-database"></a> Icinga Web 2 Manual Database Setup
|
||||
@ -336,7 +336,7 @@ mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql
|
||||
```
|
||||
|
||||
|
||||
Then generate a new password hash as described in the [authentication docs](authentication.md#authentication-configuration-db-setup)
|
||||
Then generate a new password hash as described in the [authentication docs](05-Authentication.md#authentication-configuration-db-setup)
|
||||
and use it to insert a new user called `icingaadmin` into the database.
|
||||
|
||||
```
|
||||
@ -349,7 +349,7 @@ quit
|
||||
#### <a id="web-setup-manual-from-source-config"></a> Icinga Web 2 Manual Configuration
|
||||
|
||||
|
||||
[resources.ini](resources.md#resources) providing the details for the Icinga Web 2 and
|
||||
[resources.ini](04-Resources.md#resources) providing the details for the Icinga Web 2 and
|
||||
Icinga 2 IDO database configuration. Example for MySQL:
|
||||
|
||||
```
|
||||
@ -375,7 +375,7 @@ username = "icinga"
|
||||
password = "icinga"
|
||||
```
|
||||
|
||||
[config.ini](configuration.md#configuration) defining general application settings.
|
||||
[config.ini](03-Configuration.md#configuration) defining general application settings.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/config.ini
|
||||
@ -391,7 +391,7 @@ type = "db"
|
||||
resource = "icingaweb2"
|
||||
```
|
||||
|
||||
[authentication.ini](authentication.md#authentication) for e.g. using the previously created database.
|
||||
[authentication.ini](05-Authentication.md#authentication) for e.g. using the previously created database.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/authentication.ini
|
||||
@ -402,7 +402,7 @@ resource = "icingaweb2"
|
||||
```
|
||||
|
||||
|
||||
[roles.ini](security.md#security) granting the previously added `icingaadmin` user all permissions.
|
||||
[roles.ini](06-Security.md#security) granting the previously added `icingaadmin` user all permissions.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/roles.ini
|
||||
@ -415,7 +415,7 @@ permissions = "*"
|
||||
#### <a id="web-setup-manual-from-source-config-monitoring-module"></a> Icinga Web 2 Manual Configuration Monitoring Module
|
||||
|
||||
|
||||
[config.ini](../modules/monitoring/doc/configuration.md#configuration) defining additional security settings.
|
||||
**config.ini** defining additional security settings.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/modules/monitoring/config.ini
|
||||
@ -424,7 +424,7 @@ vim /etc/icingaweb2/modules/monitoring/config.ini
|
||||
protected_customvars = "*pw*,*pass*,community"
|
||||
```
|
||||
|
||||
[backends.ini](../modules/monitoring/doc/configuration.md#configuration) referencing the Icinga 2 DB IDO resource.
|
||||
**backends.ini** referencing the Icinga 2 DB IDO resource.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/modules/monitoring/backends.ini
|
||||
@ -434,7 +434,7 @@ type = "ido"
|
||||
resource = "icinga2"
|
||||
```
|
||||
|
||||
[commandtransports.ini](../modules/monitoring/doc/commandtransports.md#commandtransports) defining the Icinga 2 command pipe.
|
||||
**commandtransports.ini** defining the Icinga command pipe.
|
||||
|
||||
```
|
||||
vim /etc/icingaweb2/modules/monitoring/commandtransports.ini
|
||||
@ -451,46 +451,20 @@ Finally visit Icinga Web 2 in your browser to login as `icingaadmin` user: `/ici
|
||||
|
||||
# <a id="upgrading"></a> Upgrading Icinga Web 2
|
||||
|
||||
## <a id="upgrading-to-beta2"></a> Upgrading to Icinga Web 2 Beta 2
|
||||
## <a id="upgrading-to-2.3.0"></a> Upgrading to Icinga Web 2 2.3.0
|
||||
|
||||
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
|
||||
content:
|
||||
```
|
||||
[administrators]
|
||||
users = "your_user_name, another_user_name"
|
||||
permissions = "*"
|
||||
```
|
||||
* Icinga Web 2 version 2.3.0 does not introduce any backward incompatible change.
|
||||
|
||||
After please log out from Icinga Web 2 and log in again for having all permissions granted.
|
||||
## <a id="upgrading-to-2.2.0"></a> Upgrading to Icinga Web 2 2.2.0
|
||||
|
||||
If you delegated authentication to your web server using the `autologin` backend, you have to switch to the `external`
|
||||
authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change
|
||||
affects environments that opted for not storing preferences, your new backend is `none`.
|
||||
* The menu entry `Authorization` beneath `Config` has been renamed to `Authentication`. The role, user backend and user
|
||||
group backend configuration which was previously found beneath `Authentication` has been moved to `Application`.
|
||||
|
||||
## <a id="upgrading-to-2.1.x"></a> Upgrading to Icinga Web 2 2.1.x
|
||||
|
||||
## <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
|
||||
configuration files after upgrading to Icinga Web 2 Beta 3.
|
||||
|
||||
## <a id="upgrading-to-rc1"></a> Upgrading to Icinga Web 2 Release Candidate 1
|
||||
|
||||
The first release candidate of Icinga Web 2 introduces the following non-backward compatible changes:
|
||||
|
||||
* The database schema has been adjusted and the tables `icingaweb_group` and
|
||||
`icingaweb_group_membership` were altered to ensure referential integrity.
|
||||
Please use the upgrade script located in **etc/schema/** to update your
|
||||
database schema
|
||||
|
||||
* Users who are using PostgreSQL < v9.1 are required to upgrade their
|
||||
environment to v9.1+ as this is the new minimum required version
|
||||
for utilizing PostgreSQL as database backend
|
||||
|
||||
* The restrictions `monitoring/hosts/filter` and `monitoring/services/filter`
|
||||
provided by the monitoring module were merged together. The new
|
||||
restriction is called `monitoring/filter/objects` and supports only a
|
||||
predefined subset of filter columns. Please see the module's security
|
||||
related documentation for more details.
|
||||
* Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`.
|
||||
Users who changed the configuration manually and used the option `filter` instead
|
||||
have to change it back to `group_filter`.
|
||||
|
||||
## <a id="upgrading-to-2.0.0"></a> Upgrading to Icinga Web 2 2.0.0
|
||||
|
||||
@ -514,13 +488,43 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar
|
||||
**<config-dir>/preferences/<username>/config.ini**.
|
||||
The content of the file remains unchanged.
|
||||
|
||||
## <a id="upgrading-to-2.1.x"></a> Upgrading to Icinga Web 2 2.1.x
|
||||
## <a id="upgrading-to-rc1"></a> Upgrading to Icinga Web 2 Release Candidate 1
|
||||
|
||||
* Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`.
|
||||
Users who changed the configuration manually and used the option `filter` instead
|
||||
have to change it back to `group_filter`.
|
||||
The first release candidate of Icinga Web 2 introduces the following non-backward compatible changes:
|
||||
|
||||
## <a id="upgrading-to-2.2.0"></a> Upgrading to Icinga Web 2 2.2.0
|
||||
* The database schema has been adjusted and the tables `icingaweb_group` and
|
||||
`icingaweb_group_membership` were altered to ensure referential integrity.
|
||||
Please use the upgrade script located in **etc/schema/** to update your
|
||||
database schema
|
||||
|
||||
* The menu entry `Authorization` beneath `Config` has been renamed to `Authentication`. The role, user backend and user
|
||||
group backend configuration which was previously found beneath `Authentication` has been moved to `Application`.
|
||||
* Users who are using PostgreSQL < v9.1 are required to upgrade their
|
||||
environment to v9.1+ as this is the new minimum required version
|
||||
for utilizing PostgreSQL as database backend
|
||||
|
||||
* The restrictions `monitoring/hosts/filter` and `monitoring/services/filter`
|
||||
provided by the monitoring module were merged together. The new
|
||||
restriction is called `monitoring/filter/objects` and supports only a
|
||||
predefined subset of filter columns. Please see the module's security
|
||||
related documentation for more details.
|
||||
|
||||
## <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
|
||||
configuration files after upgrading to Icinga Web 2 Beta 3.
|
||||
|
||||
## <a id="upgrading-to-beta2"></a> 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,
|
||||
you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following
|
||||
content:
|
||||
```
|
||||
[administrators]
|
||||
users = "your_user_name, another_user_name"
|
||||
permissions = "*"
|
||||
```
|
||||
|
||||
After please log out from Icinga Web 2 and log in again for having all permissions granted.
|
||||
|
||||
If you delegated authentication to your web server using the `autologin` backend, you have to switch to the `external`
|
||||
authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change
|
||||
affects environments that opted for not storing preferences, your new backend is `none`.
|
15
doc/03-Configuration.md
Normal file
15
doc/03-Configuration.md
Normal file
@ -0,0 +1,15 @@
|
||||
# <a id="configuration"></a> Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Apart from its web configuration capabilities, the local configuration is
|
||||
stored in `/etc/icingaweb2` by default (depending on your config setup).
|
||||
|
||||
File/Directory | Description
|
||||
---------------------------------------------------------
|
||||
config.ini | General configuration (logging, preferences)
|
||||
[resources.ini](04-Ressources.md) | Global resources (Icinga Web 2 database for preferences and authentication, Icinga IDO database)
|
||||
roles.ini | User specific roles (e.g. `administrators`) and permissions
|
||||
[authentication.ini](05-Authentication.md) | Authentication backends (e.g. database)
|
||||
enabledModules | Contains symlinks to enabled modules
|
||||
modules | Directory for module specific configuration
|
@ -18,29 +18,60 @@ The order of entries in the authentication configuration determines the order of
|
||||
If the current authentication method errors or if the current authentication method does not know the account being
|
||||
authenticated, the next authentication method will be used.
|
||||
|
||||
### <a id="authentication-configuration-external-authentication"></a> External Authentication
|
||||
## <a id="authentication-configuration-external-authentication"></a> External Authentication
|
||||
|
||||
For delegating authentication to the web server simply add `autologin` to your authentication configuration:
|
||||
|
||||
````
|
||||
```
|
||||
[autologin]
|
||||
backend = external
|
||||
````
|
||||
```
|
||||
|
||||
If your web server is not configured for authentication though the `autologin` section has no effect.
|
||||
If your web server is not configured for authentication though, the `autologin` section has no effect.
|
||||
|
||||
### <a id="authentication-configuration-ad-or-ldap-authentication"></a> Active Directory or LDAP Authentication
|
||||
### <a id="authentication-configuration-external-authentication-example"></a> Example Configuration for Apache and Basic Authentication
|
||||
|
||||
The following example will show you how to enable external authentication in Apache
|
||||
using **Basic access authentication**.
|
||||
|
||||
**Creating Users**
|
||||
|
||||
To create users for **basic access authentication** you can use the tool `htpasswd`. In this example **.http-users** is
|
||||
the name of the file containing the user credentials.
|
||||
|
||||
The following command creates a new file with the user **icingaadmin**. `htpasswd` will prompt you for a password.
|
||||
If you want to add more users to the file you have to omit the `-c` switch to not overwrite the file.
|
||||
|
||||
```
|
||||
sudo htpasswd -c /etc/icingaweb2/.http-users icingaadmin
|
||||
```
|
||||
|
||||
**Configuring the Web Server**
|
||||
|
||||
Add the following configuration to the **<Directory> Directive** in the **icingaweb.conf** web server
|
||||
configuration file.
|
||||
|
||||
```
|
||||
AuthType Basic
|
||||
AuthName "Icinga Web 2"
|
||||
AuthUserFile /etc/icingaweb2/.http-users
|
||||
Require valid-user
|
||||
```
|
||||
|
||||
Restart your web server to apply the changes.
|
||||
|
||||
## <a id="authentication-configuration-ad-or-ldap-authentication"></a> Active Directory or LDAP Authentication
|
||||
|
||||
If you want to authenticate against Active Directory or LDAP, you have to define a
|
||||
[LDAP resource](resources.md#resources-configuration-ldap) which will be referenced as data source for the Active Directory
|
||||
or LDAP configuration method.
|
||||
[LDAP resource](04-Resources.md#resources-configuration-ldap) which will be referenced as data source for the
|
||||
Active Directory or LDAP configuration method.
|
||||
|
||||
#### <a id="authentication-configuration-ldap-authentication"></a> LDAP
|
||||
### <a id="authentication-configuration-ldap-authentication"></a> LDAP
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**backend** | `ldap`
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources).
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](04-Resources.md#resources).
|
||||
**user_class** | LDAP user class.
|
||||
**user_name_attribute** | LDAP attribute which contains the username.
|
||||
**filter** | LDAP search filter.
|
||||
@ -60,12 +91,12 @@ Note that in case the set *user_name_attribute* holds multiple values it is requ
|
||||
values are unique. Additionally, a user will be logged in using the exact user id used to authenticate
|
||||
with Icinga Web 2 (e.g. an alias) no matter what the primary user id might actually be.
|
||||
|
||||
#### <a id="authentication-configuration-ad-authentication"></a> Active Directory
|
||||
### <a id="authentication-configuration-ad-authentication"></a> Active Directory
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**backend** | `msldap`
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](resources.md#resources).
|
||||
**resource** | The name of the LDAP resource defined in [resources.ini](04-Resources.md#resources).
|
||||
|
||||
**Example:**
|
||||
|
||||
@ -75,16 +106,16 @@ backend = msldap
|
||||
resource = my_ad
|
||||
```
|
||||
|
||||
### <a id="authentication-configuration-db-authentication"></a> Database Authentication
|
||||
## <a id="authentication-configuration-db-authentication"></a> Database Authentication
|
||||
|
||||
If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a
|
||||
[database resource](resources.md#resources-configuration-database) which will be referenced as data source for the database
|
||||
[database resource](04-Resources.md#resources-configuration-database) which will be referenced as data source for the database
|
||||
authentication method.
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**backend** | `db`
|
||||
**resource** | The name of the database resource defined in [resources.ini](resources.md#resources).
|
||||
**resource** | The name of the database resource defined in [resources.ini](04-Resources.md#resources).
|
||||
|
||||
**Example:**
|
||||
|
||||
@ -94,28 +125,28 @@ backend = db
|
||||
resource = icingaweb-mysql
|
||||
```
|
||||
|
||||
#### <a id="authentication-configuration-db-setup"></a> Database Setup
|
||||
### <a id="authentication-configuration-db-setup"></a> Database Setup
|
||||
|
||||
For authenticating against a database, you have to import one of the following database schemas:
|
||||
|
||||
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||
|
||||
After that you have to define the [database resource](resources.md#resources-configuration-database).
|
||||
After that you have to define the [database resource](04-Resources.md#resources-configuration-database).
|
||||
|
||||
**Manually Creating Users**
|
||||
|
||||
Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a password hash, please use the following
|
||||
command:
|
||||
|
||||
````
|
||||
```
|
||||
openssl passwd -1 password
|
||||
````
|
||||
```
|
||||
|
||||
> Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm.
|
||||
|
||||
Insert the user into the database using the generated password hash:
|
||||
|
||||
````
|
||||
```
|
||||
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl');
|
||||
````
|
||||
```
|
@ -21,9 +21,8 @@ things to which access can be managed: actions and objects.
|
||||
### Actions
|
||||
|
||||
Actions are all the things an Icinga Web 2 user can do, like changing a certain configuration,
|
||||
changing permissions or sending a command to the Icinga instance through the
|
||||
<a href="http://docs.icinga.org/icinga2/latest/doc/module/icinga2/toc#!/icinga2/latest/doc/module/icinga2/chapter/getting-started#setting-up-external-command-pipe">Command Pipe</a>
|
||||
in the monitoring module. All actions must be be **allowed explicitly** using permissions.
|
||||
changing permissions or sending a command to the Icinga instance through the Icinga command pipe.
|
||||
All actions must be be **allowed explicitly** using permissions.
|
||||
|
||||
A permission is a simple list of identifiers of actions a user is
|
||||
allowed to do. Permissions are described in greater detail in the
|
||||
@ -47,7 +46,7 @@ using Active Directory, and a user **icingaadmin** that is authenticated using a
|
||||
In the configuration, both can be referenced to by using their user names **icingaadmin** or **jdoe**.
|
||||
|
||||
Icinga Web 2 users and groups are not configured by a configuration file, but provided by
|
||||
an **authentication backend**. For extended information on setting up authentication backends and managing users, please read the chapter [Authentication](authentication.md#authentication).
|
||||
an **authentication backend**. For extended information on setting up authentication backends and managing users, please read the chapter [Authentication](05-Authentication.md#authentication).
|
||||
|
||||
|
||||
<div class="info-box">
|
||||
@ -59,7 +58,7 @@ an **authentication backend**. For extended information on setting up authentica
|
||||
#### Managing Users
|
||||
|
||||
When using a [Database
|
||||
as authentication backend](authentication.md#authentication-configuration-db-authentication), it is possible to create, add and delete users directly in the frontend. This configuration
|
||||
as authentication backend](05-Authentication.md#authentication-configuration-db-authentication), it is possible to create, add and delete users directly in the frontend. This configuration
|
||||
can be found at **Configuration > Authentication > Users **.
|
||||
|
||||
### Groups
|
||||
@ -70,12 +69,12 @@ A user can be member of multiple groups and will inherit all permissions and res
|
||||
|
||||
Like users, groups are identified solely by their **name** that is provided by
|
||||
a **group backend**. For extended information on setting up group backends,
|
||||
please read the chapter [Authentication](authentication.md#authentication).
|
||||
please read the chapter [Authentication](05-Authentication.md#authentication).
|
||||
|
||||
|
||||
#### Managing Groups
|
||||
|
||||
When using a [Database as an authentication backend](#authentication.md#authentication-configuration-db-authentication),
|
||||
When using a [Database as an authentication backend](05-Authentication.md#authentication-configuration-db-authentication),
|
||||
it is possible to manage groups and group memberships directly in the frontend. This configuration
|
||||
can be found at **Configuration > Authentication > Groups **.
|
||||
|
||||
@ -157,18 +156,18 @@ through a group) all permissions are added together to get the users actual perm
|
||||
|
||||
### Global Permissions
|
||||
|
||||
Name | Permits
|
||||
--------------- ----|--------------------------------------------------------
|
||||
* | Allow everything, including module-specific permissions
|
||||
config/* | Allow all configuration actions
|
||||
config/modules | Allow enabling or disabling modules
|
||||
module/<moduleName> | Allow access to module <moduleName>
|
||||
Name | Permits
|
||||
--------------------------|--------------------------------------------------------
|
||||
* | Allow everything, including module-specific permissions
|
||||
config/* | Allow all configuration actions
|
||||
config/modules | Allow enabling or disabling modules
|
||||
module/<moduleName> | Allow access to module <moduleName>
|
||||
|
||||
|
||||
### Monitoring Module Permissions
|
||||
|
||||
The built-in monitoring module defines an additional set of permissions, that
|
||||
is described in detail in the [monitoring module documentation](/icingaweb2/doc/module/doc/chapter/monitoring-security#monitoring-security).
|
||||
is described in detail in the monitoring module documentation.
|
||||
|
||||
|
||||
## <a id="restrictions"></a> Restrictions
|
||||
@ -187,7 +186,7 @@ mentioned in the section [Syntax](#syntax).
|
||||
### Filter Expressions
|
||||
|
||||
Filters operate on columns. A complete list of all available filter columns on hosts and services can be found in
|
||||
the [monitoring module documentation](/icingaweb2/doc/module/doc/chapter/monitoring-security#monitoring-security-restrictions).
|
||||
the monitoring module documentation.
|
||||
|
||||
Any filter expression that is allowed in the filtered view, is also an allowed filter expression.
|
||||
This means, that it is possible to define negations, wildcards, and even nested
|
@ -27,13 +27,13 @@ type = ini
|
||||
### <a id="preferences-configuration-db"></a> Store Preferences in a Database
|
||||
|
||||
In order to be more flexible in distributed setups you can store preferences in a MySQL or in a PostgreSQL database.
|
||||
For storing preferences in a database, you have to define a [database resource](resources.md#resources-configuration-database)
|
||||
For storing preferences in a database, you have to define a [database resource](04-Resources.md#resources-configuration-database)
|
||||
which will be referenced as resource for the preferences storage.
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**type** | `db`
|
||||
**resource** | The name of the database resource defined in [resources.ini](resources.md#resources).
|
||||
**resource** | The name of the database resource defined in [resources.ini](04-Resources.md#resources).
|
||||
|
||||
**Example:**
|
||||
|
||||
@ -50,4 +50,4 @@ For storing preferences in a database, you have to import one of the following d
|
||||
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||
|
||||
After that you have to define the [database resource](resources.md#resources-configuration-database).
|
||||
After that you have to define the [database resource](04-Resources.md#resources-configuration-database).
|
@ -1,15 +0,0 @@
|
||||
# <a id="configuration"></a> Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Apart from its web configuration capabilities, the local configuration is
|
||||
stored in `/etc/icingaweb2` by default (depending on your config setup).
|
||||
|
||||
Location | File | Description
|
||||
------------------------------|-----------------------|---------------------------
|
||||
. | config.ini | General configuration (logging, preferences)
|
||||
. | resources.ini | Global resources (Icinga Web 2 database for preferences and authentication, icinga ido database)
|
||||
. | roles.ini | User specific roles (e.g. `administrators`) and permissions
|
||||
. | [authentication.ini](authentication.md) | Authentication backends (e.g. database)
|
||||
enabledModules | Symlink | Contains symlinks to enabled modules from `/usr/share/icingaweb2/modules/*`. Defaults to [monitoring](modules/monitoring/doc/configuration.md) and `doc`.
|
||||
modules | Directory | Module specific configuration
|
@ -1,86 +0,0 @@
|
||||
# External Authentication
|
||||
|
||||
It is possible to utilize the authentication mechanism of the webserver instead
|
||||
of the internal authentication of Icinga Web 2 to authenticate users. This might
|
||||
be useful if you only have very few users and user management over **.htaccess**
|
||||
is not sufficient or if you are required to use some other authentication
|
||||
mechanism that is only available by utilizing the webserver.
|
||||
|
||||
Icinga Web 2 will entrust the complete authentication process to the
|
||||
authentication provider of the webserver, if external authentication is used.
|
||||
So it is very important that the webserver's authentication is configured
|
||||
correctly as wrong configuration might lead to unauthorized access or a
|
||||
malfunction in the login-process.
|
||||
|
||||
## Using External Authentication
|
||||
|
||||
External authentication in Icinga Web 2 requires the following preparations:
|
||||
|
||||
1. The external authentication must be set up properly to correctly
|
||||
authenticate users
|
||||
2. Icinga Web 2 must be configured to use external authentication
|
||||
|
||||
### Preparing the External Authentication Provider
|
||||
|
||||
This step depends heavily on the used webserver and authentication mechanism you
|
||||
want to use. It is not possible to cover all possibillities and you should
|
||||
probably read the documentation for your webserver to get detailed instructions
|
||||
on how to set up authentication properly.
|
||||
|
||||
In general you need to make sure that:
|
||||
|
||||
- All routes require authentication
|
||||
- Only permitted users are allowed to authenticate
|
||||
|
||||
#### Example Configuration for Apache and HTTPDigestAuthentication
|
||||
|
||||
The following example will show how to enable external authentication in Apache
|
||||
using *HTTP Digest Authentication*.
|
||||
|
||||
##### Creating users
|
||||
|
||||
To create users for digest authentication you can use the tool *htdigest*. In
|
||||
this example **.icingawebdigest** is the name of the file containing the user
|
||||
credentials.
|
||||
|
||||
This command creates a new file with the user *jdoe*. *htdigest* will prompt
|
||||
you for a password. If you want to add more users to the file you need to omit
|
||||
the *-c* parameter in all following commands to not to overwrite the file.
|
||||
|
||||
````
|
||||
sudo htdigest -c /etc/icingaweb2/.icingawebdigest "Icinga Web 2" jdoe
|
||||
````
|
||||
|
||||
##### Configuring the Webserver
|
||||
|
||||
The webserver should require authentication for all public Icinga Web 2 files.
|
||||
|
||||
````
|
||||
<Directory "/usr/share/icingaweb2/public">
|
||||
AuthType digest
|
||||
AuthName "Icinga Web 2"
|
||||
AuthDigestProvider file
|
||||
AuthUserFile /etc/icingaweb2/.icingawebdigest
|
||||
Require valid-user
|
||||
</Directory>
|
||||
````
|
||||
|
||||
To get these changes to work, make sure to enable the module for
|
||||
HTTPDigestAuthentication and restart the webserver.
|
||||
|
||||
### Preparing Icinga Web 2
|
||||
|
||||
Once external authentication is set up correctly you need to configure Icinga
|
||||
Web 2. In case you already completed the setup wizard it is likely that you are
|
||||
now finished.
|
||||
|
||||
To get Icinga Web 2 to use external authentication the file
|
||||
**config/authentication.ini** is required. Just add the following section
|
||||
called "autologin", or any name of your choice, and save your changes:
|
||||
|
||||
````
|
||||
[autologin]
|
||||
backend = external
|
||||
````
|
||||
|
||||
Congratulations! You are now logged in when visiting Icinga Web 2.
|
@ -190,7 +190,7 @@ cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completi
|
||||
cp -prv modules/{monitoring,setup,doc,translation} %{buildroot}/%{basedir}/modules
|
||||
cp -prv library/Icinga %{buildroot}/%{phpdir}
|
||||
cp -prv library/vendor/{dompdf,HTMLPurifier*,JShrink,lessphp,Parsedown,Zend} %{buildroot}/%{basedir}/library/vendor
|
||||
cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
|
||||
cp -prv public/{css,font,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
|
||||
cp -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf
|
||||
cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir}
|
||||
cp -pv packages/files/public/index.php %{buildroot}/%{basedir}/public
|
||||
|
152
library/Icinga/Application/Hook/Ticket/TicketPattern.php
Normal file
152
library/Icinga/Application/Hook/Ticket/TicketPattern.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Application\Hook\Ticket;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* A ticket pattern
|
||||
*
|
||||
* This class should be used by modules which provide implementations for the Web 2 ticket hook.
|
||||
* Have a look at the GenericTTS module for a possible use case.
|
||||
*/
|
||||
class TicketPattern implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* The result of a performed ticket match
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $match = array();
|
||||
|
||||
/**
|
||||
* The name of the TTS integration
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The ticket pattern
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $pattern;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->match[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->match) ? $this->match[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if ($offset === null) {
|
||||
$this->match[] = $value;
|
||||
} else {
|
||||
$this->match[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->match[$offset]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the result of a performed ticket match
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMatch()
|
||||
{
|
||||
return $this->match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the result of a performed ticket match
|
||||
*
|
||||
* @param array $match
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMatch(array $match)
|
||||
{
|
||||
$this->match = $match;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the TTS integration
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the TTS integration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ticket pattern
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPattern()
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ticket pattern
|
||||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPattern($pattern)
|
||||
{
|
||||
$this->pattern = $pattern;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the integration is properly configured, i.e. the pattern and the URL are not empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
return ! empty($this->pattern);
|
||||
}
|
||||
}
|
@ -3,15 +3,17 @@
|
||||
|
||||
namespace Icinga\Application\Hook;
|
||||
|
||||
use ArrayIterator;
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use Icinga\Application\Hook\Ticket\TicketPattern;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Base class for ticket hooks
|
||||
*
|
||||
* Extend this class if you want to integrate your ticketing solution Icinga Web 2
|
||||
* Extend this class if you want to integrate your ticketing solution into Icinga Web 2.
|
||||
*/
|
||||
abstract class TicketHook
|
||||
{
|
||||
@ -39,6 +41,100 @@ abstract class TicketHook
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a link for each matched element in the subject text
|
||||
*
|
||||
* @param array|TicketPattern $match Matched element according to {@link getPattern()}
|
||||
*
|
||||
* @return string Replacement string
|
||||
*/
|
||||
abstract public function createLink($match);
|
||||
|
||||
/**
|
||||
* Get the pattern(s) to search for
|
||||
*
|
||||
* Return an array of TicketPattern instances here to support multiple TTS integrations.
|
||||
*
|
||||
* @return string|TicketPattern[]
|
||||
*/
|
||||
abstract public function getPattern();
|
||||
|
||||
/**
|
||||
* Apply ticket patterns to the given text
|
||||
*
|
||||
* @param string $text
|
||||
* @param TicketPattern[] $ticketPatterns
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function applyTicketPatterns($text, array $ticketPatterns)
|
||||
{
|
||||
$out = '';
|
||||
$start = 0;
|
||||
|
||||
$iterator = new ArrayIterator($ticketPatterns);
|
||||
$iterator->rewind();
|
||||
|
||||
while ($iterator->valid()) {
|
||||
$ticketPattern = $iterator->current();
|
||||
|
||||
try {
|
||||
preg_match($ticketPattern->getPattern(), $text, $match, PREG_OFFSET_CAPTURE, $start);
|
||||
} catch (ErrorException $e) {
|
||||
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
|
||||
$iterator->next();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($match)) {
|
||||
$iterator->next();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove preg_offset from match for the ticket pattern
|
||||
$carry = array();
|
||||
array_walk($match, function ($value, $key) use (&$carry) {
|
||||
$carry[$key] = $value[0];
|
||||
}, $carry);
|
||||
$ticketPattern->setMatch($carry);
|
||||
|
||||
$offsetLeft = $match[0][1];
|
||||
$matchLength = strlen($match[0][0]);
|
||||
|
||||
$out .= substr($text, $start, $offsetLeft - $start);
|
||||
|
||||
try {
|
||||
$out .= $this->createLink($ticketPattern);
|
||||
} catch (Exception $e) {
|
||||
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
}
|
||||
|
||||
$start = $offsetLeft + $matchLength;
|
||||
}
|
||||
|
||||
$out .= substr($text, $start);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a TicketPattern instance
|
||||
*
|
||||
* @param string $name Name of the TTS integration
|
||||
* @param string $pattern Ticket pattern
|
||||
*
|
||||
* @return TicketPattern
|
||||
*/
|
||||
protected function createTicketPattern($name, $pattern)
|
||||
{
|
||||
$ticketPattern = new TicketPattern();
|
||||
$ticketPattern
|
||||
->setName($name)
|
||||
->setPattern($pattern);
|
||||
return $ticketPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hook as failed w/ the given message
|
||||
*
|
||||
@ -63,22 +159,6 @@ abstract class TicketHook
|
||||
return $this->lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pattern
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getPattern();
|
||||
|
||||
/**
|
||||
* Create a link for each matched element in the subject text
|
||||
*
|
||||
* @param array $match Array of matched elements according to {@link getPattern()}
|
||||
*
|
||||
* @return string Replacement string
|
||||
*/
|
||||
abstract public function createLink($match);
|
||||
|
||||
/**
|
||||
* Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()}
|
||||
*
|
||||
@ -101,22 +181,28 @@ abstract class TicketHook
|
||||
$this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
}
|
||||
|
||||
if (empty($pattern)) {
|
||||
$this->fail('Can\'t create ticket links: Pattern is empty');
|
||||
return $text;
|
||||
}
|
||||
try {
|
||||
$text = preg_replace_callback(
|
||||
$pattern,
|
||||
array($this, 'createLink'),
|
||||
$text
|
||||
);
|
||||
} catch (ErrorException $e) {
|
||||
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
} catch (Exception $e) {
|
||||
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
|
||||
if (is_array($pattern)) {
|
||||
$text = $this->applyTicketPatterns($text, $pattern);
|
||||
} else {
|
||||
try {
|
||||
$text = preg_replace_callback(
|
||||
$pattern,
|
||||
array($this, 'createLink'),
|
||||
$text
|
||||
);
|
||||
} catch (ErrorException $e) {
|
||||
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
} catch (Exception $e) {
|
||||
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
|
@ -5,6 +5,7 @@ namespace Icinga\Authentication;
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Role;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\User;
|
||||
@ -43,16 +44,12 @@ class AdmissionLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user permissions and restrictions
|
||||
* Apply permissions, restrictions and roles to the given user
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
* @param User $user
|
||||
*/
|
||||
public function getPermissionsAndRestrictions(User $user)
|
||||
public function applyRoles(User $user)
|
||||
{
|
||||
$permissions = array();
|
||||
$restrictions = array();
|
||||
$username = $user->getUsername();
|
||||
try {
|
||||
$roles = Config::app('roles');
|
||||
@ -62,14 +59,18 @@ class AdmissionLoader
|
||||
$username,
|
||||
$e
|
||||
);
|
||||
return array($permissions, $restrictions);
|
||||
return;
|
||||
}
|
||||
$userGroups = $user->getGroups();
|
||||
foreach ($roles as $role) {
|
||||
$permissions = array();
|
||||
$restrictions = array();
|
||||
$roleObjs = array();
|
||||
foreach ($roles as $roleName => $role) {
|
||||
if ($this->match($username, $userGroups, $role)) {
|
||||
$permissionsFromRole = StringHelper::trimSplit($role->permissions);
|
||||
$permissions = array_merge(
|
||||
$permissions,
|
||||
array_diff(StringHelper::trimSplit($role->permissions), $permissions)
|
||||
array_diff($permissionsFromRole, $permissions)
|
||||
);
|
||||
$restrictionsFromRole = $role->toArray();
|
||||
unset($restrictionsFromRole['users']);
|
||||
@ -81,8 +82,16 @@ class AdmissionLoader
|
||||
}
|
||||
$restrictions[$name][] = $restriction;
|
||||
}
|
||||
|
||||
$roleObj = new Role();
|
||||
$roleObjs[] = $roleObj
|
||||
->setName($roleName)
|
||||
->setPermissions($permissionsFromRole)
|
||||
->setRestrictions($restrictionsFromRole);
|
||||
}
|
||||
}
|
||||
return array($permissions, $restrictions);
|
||||
$user->setPermissions($permissions);
|
||||
$user->setRestrictions($restrictions);
|
||||
$user->setRoles($roleObjs);
|
||||
}
|
||||
}
|
||||
|
@ -160,9 +160,7 @@ class Auth
|
||||
}
|
||||
$user->setGroups($groups);
|
||||
$admissionLoader = new AdmissionLoader();
|
||||
list($permissions, $restrictions) = $admissionLoader->getPermissionsAndRestrictions($user);
|
||||
$user->setPermissions($permissions);
|
||||
$user->setRestrictions($restrictions);
|
||||
$admissionLoader->applyRoles($user);
|
||||
$this->user = $user;
|
||||
if ($persist) {
|
||||
$this->persistCurrentUser();
|
||||
@ -242,10 +240,10 @@ class Auth
|
||||
public function authenticateFromSession()
|
||||
{
|
||||
$this->user = Session::getSession()->get('user');
|
||||
if ($this->user !== null && $this->user->isExternalUser() === true) {
|
||||
if ($this->user !== null && $this->user->isExternalUser()) {
|
||||
list($originUsername, $field) = $this->user->getExternalUserInformation();
|
||||
$username = getenv($field); // usually REMOTE_USER here
|
||||
if ( !$username || $username !== $originUsername) {
|
||||
$username = ExternalBackend::getRemoteUser($field);
|
||||
if ($username === null || $username !== $originUsername) {
|
||||
$this->removeAuthorization();
|
||||
}
|
||||
}
|
||||
|
109
library/Icinga/Authentication/Role.php
Normal file
109
library/Icinga/Authentication/Role.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
class Role
|
||||
{
|
||||
/**
|
||||
* Name of the role
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* Permissions of the role
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $permissions = array();
|
||||
|
||||
/**
|
||||
* Restrictions of the role
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $restrictions = array();
|
||||
|
||||
/**
|
||||
* Get the name of the role
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the role
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the permissions of the role
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPermissions()
|
||||
{
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permissions of the role
|
||||
*
|
||||
* @param string[] $permissions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPermissions(array $permissions)
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restrictions of the role
|
||||
*
|
||||
* @param string $name Optional name of the restriction
|
||||
*
|
||||
* @return string[]|null
|
||||
*/
|
||||
public function getRestrictions($name = null)
|
||||
{
|
||||
$restrictions = $this->restrictions;
|
||||
|
||||
if ($name === null) {
|
||||
return $restrictions;
|
||||
}
|
||||
|
||||
if (isset($restrictions[$name])) {
|
||||
return $restrictions[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restrictions of the role
|
||||
*
|
||||
* @param string[] $restrictions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRestrictions(array $restrictions)
|
||||
{
|
||||
$this->restrictions = $restrictions;
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -35,6 +35,14 @@ class ExternalBackend implements UserBackendInterface
|
||||
$this->stripUsernameRegexp = $config->get('strip_username_regexp');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -45,11 +53,22 @@ class ExternalBackend implements UserBackendInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Get the remote user from environment or $_SERVER, if any
|
||||
*
|
||||
* @param string $variable The name variable where to read the user from
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName()
|
||||
public static function getRemoteUser($variable = 'REMOTE_USER')
|
||||
{
|
||||
return $this->name;
|
||||
$username = getenv($variable);
|
||||
if ($username !== false) {
|
||||
return $username;
|
||||
}
|
||||
if (array_key_exists($variable, $_SERVER)) {
|
||||
return $_SERVER[$variable];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -58,8 +77,8 @@ class ExternalBackend implements UserBackendInterface
|
||||
*/
|
||||
public function authenticate(User $user, $password = null)
|
||||
{
|
||||
$username = getenv('REMOTE_USER');
|
||||
if ($username !== false) {
|
||||
$username = static::getRemoteUser();
|
||||
if ($username !== null) {
|
||||
$user->setExternalUserInformation($username, 'REMOTE_USER');
|
||||
|
||||
if ($this->stripUsernameRegexp) {
|
||||
|
@ -152,11 +152,12 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
|
||||
*/
|
||||
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] =
|
||||
'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,'
|
||||
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';';
|
||||
if (array_key_exists('charset', $adapterParamaters) && $adapterParamaters['charset']) {
|
||||
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= 'SET NAMES ' . $adapterParamaters['charset']. ';';
|
||||
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\'';
|
||||
if (isset($adapterParamaters['charset'])) {
|
||||
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= ', NAMES ' . $adapterParamaters['charset'];
|
||||
unset($adapterParamaters['charset']);
|
||||
}
|
||||
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .=';';
|
||||
|
||||
$adapterParamaters['port'] = $this->config->get('port', 3306);
|
||||
break;
|
||||
|
@ -92,6 +92,6 @@ class TreeNodeIterator implements RecursiveIterator
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->children);
|
||||
return ! $this->children->count();
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,21 @@
|
||||
|
||||
namespace Icinga\Protocol\Ldap;
|
||||
|
||||
use Exception;
|
||||
use ArrayIterator;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use stdClass;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filter\FilterChain;
|
||||
use Icinga\Data\Filter\FilterExpression;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Data\Selectable;
|
||||
use Icinga\Data\Sortable;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filter\FilterChain;
|
||||
use Icinga\Data\Filter\FilterExpression;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Protocol\Ldap\LdapException;
|
||||
|
||||
/**
|
||||
* Encapsulate LDAP connections and query creation
|
||||
@ -548,6 +549,23 @@ class LdapConnection implements Selectable, Inspectable
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an LDAP entry by its DN
|
||||
*
|
||||
* @param string $dn
|
||||
* @param array|null $fields
|
||||
*
|
||||
* @return StdClass|bool
|
||||
*/
|
||||
public function fetchByDn($dn, array $fields = null)
|
||||
{
|
||||
return $this->select()
|
||||
->from('*', $fields)
|
||||
->setBase($dn)
|
||||
->setScope('base')
|
||||
->fetchRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the given LDAP credentials by establishing a connection and attempting a LDAP bind
|
||||
*
|
||||
@ -706,7 +724,7 @@ class LdapConnection implements Selectable, Inspectable
|
||||
'value' => $this->encodeSortRules($query->getOrder())
|
||||
)
|
||||
));
|
||||
} else {
|
||||
} elseif (! empty($fields)) {
|
||||
foreach ($query->getOrder() as $rule) {
|
||||
if (! in_array($rule[0], $fields, true)) {
|
||||
$fields[] = $rule[0];
|
||||
@ -825,7 +843,7 @@ class LdapConnection implements Selectable, Inspectable
|
||||
$ds = $this->getConnection();
|
||||
|
||||
$serverSorting = false;//$this->getCapabilities()->hasOid(LdapCapabilities::LDAP_SERVER_SORT_OID);
|
||||
if (! $serverSorting && $query->hasOrder()) {
|
||||
if (! $serverSorting && $query->hasOrder() && ! empty($fields)) {
|
||||
foreach ($query->getOrder() as $rule) {
|
||||
if (! in_array($rule[0], $fields, true)) {
|
||||
$fields[] = $rule[0];
|
||||
@ -1179,6 +1197,8 @@ class LdapConnection implements Selectable, Inspectable
|
||||
* @param int $deref
|
||||
*
|
||||
* @return resource|bool A search result identifier or false on error
|
||||
*
|
||||
* @throws LogicException If the LDAP query search scope is unsupported
|
||||
*/
|
||||
public function ldapSearch(
|
||||
LdapQuery $query,
|
||||
@ -1190,6 +1210,7 @@ class LdapConnection implements Selectable, Inspectable
|
||||
) {
|
||||
$queryString = (string) $query;
|
||||
$baseDn = $query->getBase() ?: $this->getDn();
|
||||
$scope = $query->getScope();
|
||||
|
||||
if (Logger::getInstance()->getLevel() === Logger::DEBUG) {
|
||||
// We're checking the level by ourself to avoid rendering the ldapsearch commandline for nothing
|
||||
@ -1213,11 +1234,12 @@ class LdapConnection implements Selectable, Inspectable
|
||||
}
|
||||
|
||||
Logger::debug("Issueing LDAP search. Use '%s' to reproduce.", sprintf(
|
||||
'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "sub" -z %u -l %u -a "%s"%s%s%s',
|
||||
'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "%s" -z %u -l %u -a "%s"%s%s%s',
|
||||
$starttlsParam,
|
||||
$ldapUrl,
|
||||
$bindParams,
|
||||
$baseDn,
|
||||
$scope,
|
||||
$sizelimit,
|
||||
$timelimit,
|
||||
$derefName,
|
||||
@ -1227,7 +1249,21 @@ class LdapConnection implements Selectable, Inspectable
|
||||
));
|
||||
}
|
||||
|
||||
return @ldap_search(
|
||||
switch($scope) {
|
||||
case LdapQuery::SCOPE_SUB:
|
||||
$function = 'ldap_search';
|
||||
break;
|
||||
case LdapQuery::SCOPE_ONE:
|
||||
$function = 'ldap_list';
|
||||
break;
|
||||
case LdapQuery::SCOPE_BASE:
|
||||
$function = 'ldap_read';
|
||||
break;
|
||||
default:
|
||||
throw new LogicException('LDAP scope %s not supported by ldapSearch', $scope);
|
||||
}
|
||||
|
||||
return @$function(
|
||||
$this->getConnection(),
|
||||
$baseDn,
|
||||
$queryString,
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
namespace Icinga\Protocol\Ldap;
|
||||
|
||||
use LogicException;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
|
||||
/**
|
||||
@ -38,6 +39,39 @@ class LdapQuery extends SimpleQuery
|
||||
*/
|
||||
protected $nativeFilter;
|
||||
|
||||
/**
|
||||
* Only fetch the entry at the base of the search
|
||||
*/
|
||||
const SCOPE_BASE = 'base';
|
||||
|
||||
/**
|
||||
* Fetch entries one below the base DN
|
||||
*/
|
||||
const SCOPE_ONE = 'one';
|
||||
|
||||
/**
|
||||
* Fetch all entries below the base DN
|
||||
*/
|
||||
const SCOPE_SUB = 'sub';
|
||||
|
||||
/**
|
||||
* All available scopes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $scopes = array(
|
||||
LdapQuery::SCOPE_BASE,
|
||||
LdapQuery::SCOPE_ONE,
|
||||
LdapQuery::SCOPE_SUB
|
||||
);
|
||||
|
||||
/**
|
||||
* LDAP search scope (default: SCOPE_SUB)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scope = LdapQuery::SCOPE_SUB;
|
||||
|
||||
/**
|
||||
* Initialize this query
|
||||
*/
|
||||
@ -223,4 +257,38 @@ class LdapQuery extends SimpleQuery
|
||||
{
|
||||
return $this->renderFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get LDAP search scope
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getScope()
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set LDAP search scope
|
||||
*
|
||||
* Valid: sub one base (Default: sub)
|
||||
*
|
||||
* @param string $scope
|
||||
*
|
||||
* @return LdapQuery
|
||||
*
|
||||
* @throws LogicException If scope value is invalid
|
||||
*/
|
||||
public function setScope($scope)
|
||||
{
|
||||
if (! in_array($scope, static::$scopes)) {
|
||||
throw new LogicException(
|
||||
'Can\'t set scope %d, it is is invalid. Use one of %s or LdapQuery\'s constants.',
|
||||
$scope, implode(', ', static::$scopes)
|
||||
);
|
||||
}
|
||||
$this->scope = $scope;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,9 +28,11 @@ class LdapUtils
|
||||
$res = ldap_explode_dn($dn, $with_type ? 0 : 1);
|
||||
|
||||
foreach ($res as $k => $v) {
|
||||
$res[$k] = preg_replace(
|
||||
'/\\\([0-9a-f]{2})/ei',
|
||||
"chr(hexdec('\\1'))",
|
||||
$res[$k] = preg_replace_callback(
|
||||
'/\\\([0-9a-f]{2})/i',
|
||||
function ($m) {
|
||||
return chr(hexdec($m[1]));
|
||||
},
|
||||
$v
|
||||
);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ namespace Icinga;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Authentication\Role;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\Web\Navigation\Navigation;
|
||||
|
||||
@ -91,6 +92,13 @@ class User
|
||||
*/
|
||||
protected $groups = array();
|
||||
|
||||
/**
|
||||
* Roles of this user
|
||||
*
|
||||
* @var Role[]
|
||||
*/
|
||||
protected $roles = array();
|
||||
|
||||
/**
|
||||
* Preferences object
|
||||
*
|
||||
@ -229,13 +237,39 @@ class User
|
||||
}
|
||||
|
||||
/**
|
||||
* Settter for restrictions
|
||||
* Set the user's restrictions
|
||||
*
|
||||
* @param array $restrictions
|
||||
* @param string[] $restrictions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRestrictions(array $restrictions)
|
||||
{
|
||||
$this->restrictions = $restrictions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the roles of the user
|
||||
*
|
||||
* @return Role[]
|
||||
*/
|
||||
public function getRoles()
|
||||
{
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the roles of the user
|
||||
*
|
||||
* @param Role[] $roles
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRoles(array $roles)
|
||||
{
|
||||
$this->roles = $roles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,14 +3,22 @@
|
||||
|
||||
namespace Icinga\Util;
|
||||
|
||||
use ArrayIterator;
|
||||
use InvalidArgumentException;
|
||||
use Iterator;
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* Iterator for traversing a directory
|
||||
*/
|
||||
class DirectoryIterator implements Iterator
|
||||
class DirectoryIterator implements RecursiveIterator
|
||||
{
|
||||
/**
|
||||
* Iterate files first
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const FILES_FIRST = 1;
|
||||
|
||||
/**
|
||||
* Current directory item
|
||||
*
|
||||
@ -26,11 +34,18 @@ class DirectoryIterator implements Iterator
|
||||
protected $extension;
|
||||
|
||||
/**
|
||||
* Directory handle
|
||||
* Scanned files
|
||||
*
|
||||
* @var resource
|
||||
* @var ArrayIterator
|
||||
*/
|
||||
private $handle;
|
||||
private $files;
|
||||
|
||||
/**
|
||||
* Iterator flags
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $flags;
|
||||
|
||||
/**
|
||||
* Current key
|
||||
@ -46,6 +61,13 @@ class DirectoryIterator implements Iterator
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Directory queue if FILES_FIRST flag is set
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $queue;
|
||||
|
||||
/**
|
||||
* Whether to skip empty files
|
||||
*
|
||||
@ -72,8 +94,9 @@ class DirectoryIterator implements Iterator
|
||||
*
|
||||
* @param string $path The path of the directory to traverse
|
||||
* @param string $extension The file extension to filter for. A leading dot is optional
|
||||
* @param int $flags Iterator flags
|
||||
*/
|
||||
public function __construct($path, $extension = null)
|
||||
public function __construct($path, $extension = null, $flags = null)
|
||||
{
|
||||
if (empty($path)) {
|
||||
throw new InvalidArgumentException('The path can\'t be empty');
|
||||
@ -82,6 +105,9 @@ class DirectoryIterator implements Iterator
|
||||
if (! empty($extension)) {
|
||||
$this->extension = '.' . ltrim($extension, '.');
|
||||
}
|
||||
if ($flags !== null) {
|
||||
$this->flags = $flags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,6 +122,23 @@ class DirectoryIterator implements Iterator
|
||||
return is_dir($path) && is_readable($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasChildren()
|
||||
{
|
||||
return static::isReadable($this->current);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return new static($this->current, $this->extension, $this->flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -110,12 +153,14 @@ class DirectoryIterator implements Iterator
|
||||
public function next()
|
||||
{
|
||||
do {
|
||||
$file = readdir($this->handle);
|
||||
if ($file === false) {
|
||||
$key = false;
|
||||
$this->files->next();
|
||||
$skip = false;
|
||||
if (! $this->files->valid()) {
|
||||
$file = false;
|
||||
$path = false;
|
||||
break;
|
||||
} else {
|
||||
$skip = false;
|
||||
$file = $this->files->current();
|
||||
do {
|
||||
if ($this->skipHidden && $file[0] === '.') {
|
||||
$skip = true;
|
||||
@ -125,7 +170,10 @@ class DirectoryIterator implements Iterator
|
||||
$path = $this->path . '/' . $file;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$skip = true;
|
||||
if ($this->flags & static::FILES_FIRST === static::FILES_FIRST) {
|
||||
$this->queue[] = array($path, $file);
|
||||
$skip = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -138,16 +186,18 @@ class DirectoryIterator implements Iterator
|
||||
$skip = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$key = $file;
|
||||
$file = $path;
|
||||
} while (0);
|
||||
}
|
||||
} while ($skip);
|
||||
|
||||
$this->current = $file;
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
$this->key = $key;
|
||||
|
||||
if ($path === false && ! empty($this->queue)) {
|
||||
list($path, $file) = array_shift($this->queue);
|
||||
}
|
||||
|
||||
$this->current = $path;
|
||||
$this->key = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,21 +221,13 @@ class DirectoryIterator implements Iterator
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->handle === null) {
|
||||
$this->handle = opendir($this->path);
|
||||
} else {
|
||||
rewinddir($this->handle);
|
||||
if ($this->files === null) {
|
||||
$files = scandir($this->path);
|
||||
natcasesort($files);
|
||||
$this->files = new ArrayIterator($files);
|
||||
}
|
||||
$this->files->rewind();
|
||||
$this->queue = array();
|
||||
$this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close directory handle if created
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->handle !== null) {
|
||||
closedir($this->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ class Autosubmit extends Zend_Form_Decorator_Abstract
|
||||
: t('Upon its value has changed, this field issues an automatic update of this page.');
|
||||
$content .= $this->getView()->icon('cw', $warning, array(
|
||||
'aria-hidden' => $isForm ? 'false' : 'true',
|
||||
'class' => 'spinner'
|
||||
'class' => 'spinner autosubmit-info'
|
||||
));
|
||||
if (! $isForm && $this->getAccessible()) {
|
||||
$content = '<span id="' . $this->getWarningId() . '" class="sr-only">' . $warning . '</span>' . $content;
|
||||
|
@ -70,7 +70,7 @@ class LessCompiler
|
||||
*/
|
||||
public function addLessFile($lessFile)
|
||||
{
|
||||
$this->lessFiles[] = $lessFile;
|
||||
$this->lessFiles[] = realpath($lessFile);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ class LessCompiler
|
||||
if (! isset($this->moduleLessFiles[$moduleName])) {
|
||||
$this->moduleLessFiles[$moduleName] = array();
|
||||
}
|
||||
$this->moduleLessFiles[$moduleName][] = $lessFile;
|
||||
$this->moduleLessFiles[$moduleName][] = realpath($lessFile);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -98,9 +98,12 @@ class LessCompiler
|
||||
*/
|
||||
public function getLessFiles()
|
||||
{
|
||||
$lessFiles = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator(
|
||||
$this->lessFiles + $this->moduleLessFiles
|
||||
)));
|
||||
$lessFiles = $this->lessFiles;
|
||||
|
||||
foreach ($this->moduleLessFiles as $moduleLessFiles) {
|
||||
$lessFiles = array_merge($lessFiles, $moduleLessFiles);
|
||||
}
|
||||
|
||||
if ($this->theme !== null) {
|
||||
$lessFiles[] = $this->theme;
|
||||
}
|
||||
|
@ -201,12 +201,6 @@ class Dashboard extends AbstractWidget
|
||||
{
|
||||
/** @var $pane Pane */
|
||||
foreach ($panes as $pane) {
|
||||
if ($pane->getDisabled()) {
|
||||
if ($this->hasPane($pane->getTitle()) === true) {
|
||||
$this->removePane($pane->getTitle());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($this->hasPane($pane->getTitle()) === true) {
|
||||
/** @var $current Pane */
|
||||
$current = $this->panes[$pane->getName()];
|
||||
@ -231,6 +225,9 @@ class Dashboard extends AbstractWidget
|
||||
$this->tabs = new Tabs();
|
||||
|
||||
foreach ($this->panes as $key => $pane) {
|
||||
if ($pane->getDisabled()) {
|
||||
continue;
|
||||
}
|
||||
$this->tabs->add(
|
||||
$key,
|
||||
array(
|
||||
|
@ -40,7 +40,7 @@ class Pane extends UserWidget
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $disabled;
|
||||
private $disabled = false;
|
||||
|
||||
/**
|
||||
* Create a new pane
|
||||
|
@ -377,8 +377,8 @@ EOT;
|
||||
array(
|
||||
$tabs,
|
||||
$drop,
|
||||
$close,
|
||||
$refresh
|
||||
$refresh,
|
||||
$close
|
||||
),
|
||||
$this->baseTpl
|
||||
);
|
||||
|
71
library/vendor/Parsedown/Parsedown.php
vendored
71
library/vendor/Parsedown/Parsedown.php
vendored
@ -17,7 +17,7 @@ class Parsedown
|
||||
{
|
||||
# ~
|
||||
|
||||
const version = '1.5.0';
|
||||
const version = '1.6.0';
|
||||
|
||||
# ~
|
||||
|
||||
@ -107,12 +107,6 @@ class Parsedown
|
||||
|
||||
# ~
|
||||
|
||||
protected $DefinitionTypes = array(
|
||||
'[' => array('Reference'),
|
||||
);
|
||||
|
||||
# ~
|
||||
|
||||
protected $unmarkedBlockTypes = array(
|
||||
'Code',
|
||||
);
|
||||
@ -169,7 +163,7 @@ class Parsedown
|
||||
|
||||
# ~
|
||||
|
||||
if (isset($CurrentBlock['incomplete']))
|
||||
if (isset($CurrentBlock['continuable']))
|
||||
{
|
||||
$Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock);
|
||||
|
||||
@ -185,8 +179,6 @@ class Parsedown
|
||||
{
|
||||
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
||||
}
|
||||
|
||||
unset($CurrentBlock['incomplete']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +218,7 @@ class Parsedown
|
||||
|
||||
if (method_exists($this, 'block'.$blockType.'Continue'))
|
||||
{
|
||||
$Block['incomplete'] = true;
|
||||
$Block['continuable'] = true;
|
||||
}
|
||||
|
||||
$CurrentBlock = $Block;
|
||||
@ -253,7 +245,7 @@ class Parsedown
|
||||
|
||||
# ~
|
||||
|
||||
if (isset($CurrentBlock['incomplete']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
||||
if (isset($CurrentBlock['continuable']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))
|
||||
{
|
||||
$CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
|
||||
}
|
||||
@ -394,16 +386,16 @@ class Parsedown
|
||||
|
||||
protected function blockFencedCode($Line)
|
||||
{
|
||||
if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
||||
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
||||
{
|
||||
$Element = array(
|
||||
'name' => 'code',
|
||||
'text' => '',
|
||||
);
|
||||
|
||||
if (isset($matches[2]))
|
||||
if (isset($matches[1]))
|
||||
{
|
||||
$class = 'language-'.$matches[2];
|
||||
$class = 'language-'.$matches[1];
|
||||
|
||||
$Element['attributes'] = array(
|
||||
'class' => $class,
|
||||
@ -673,7 +665,9 @@ class Parsedown
|
||||
|
||||
if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
||||
{
|
||||
if (in_array($matches[1], $this->textLevelElements))
|
||||
$element = strtolower($matches[1]);
|
||||
|
||||
if (in_array($element, $this->textLevelElements))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -736,8 +730,6 @@ class Parsedown
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
|
||||
$Block['markup'] .= $matches[1];
|
||||
}
|
||||
|
||||
if (isset($Block['interrupted']))
|
||||
@ -989,15 +981,13 @@ class Parsedown
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
$unexaminedText = $text;
|
||||
# $excerpt is based on the first occurrence of a marker
|
||||
|
||||
$markerPosition = 0;
|
||||
|
||||
while ($excerpt = strpbrk($unexaminedText, $this->inlineMarkerList))
|
||||
while ($excerpt = strpbrk($text, $this->inlineMarkerList))
|
||||
{
|
||||
$marker = $excerpt[0];
|
||||
|
||||
$markerPosition += strpos($unexaminedText, $marker);
|
||||
$markerPosition = strpos($text, $marker);
|
||||
|
||||
$Excerpt = array('text' => $excerpt, 'context' => $text);
|
||||
|
||||
@ -1010,34 +1000,42 @@ class Parsedown
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($Inline['position']) and $Inline['position'] > $markerPosition) # position is ahead of marker
|
||||
# makes sure that the inline belongs to "our" marker
|
||||
|
||||
if (isset($Inline['position']) and $Inline['position'] > $markerPosition)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
# sets a default inline position
|
||||
|
||||
if ( ! isset($Inline['position']))
|
||||
{
|
||||
$Inline['position'] = $markerPosition;
|
||||
}
|
||||
|
||||
# the text that comes before the inline
|
||||
$unmarkedText = substr($text, 0, $Inline['position']);
|
||||
|
||||
# compile the unmarked text
|
||||
$markup .= $this->unmarkedText($unmarkedText);
|
||||
|
||||
# compile the inline
|
||||
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);
|
||||
|
||||
# remove the examined text
|
||||
$text = substr($text, $Inline['position'] + $Inline['extent']);
|
||||
|
||||
$unexaminedText = $text;
|
||||
|
||||
$markerPosition = 0;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$unexaminedText = substr($excerpt, 1);
|
||||
# the marker does not belong to an inline
|
||||
|
||||
$markerPosition ++;
|
||||
$unmarkedText = substr($text, 0, $markerPosition + 1);
|
||||
|
||||
$markup .= $this->unmarkedText($unmarkedText);
|
||||
|
||||
$text = substr($text, $markerPosition + 1);
|
||||
}
|
||||
|
||||
$markup .= $this->unmarkedText($text);
|
||||
@ -1199,7 +1197,7 @@ class Parsedown
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/^[(]((?:[^ (]|[(][^ )]+[)])+)(?:[ ]+("[^"]+"|\'[^\']+\'))?[)]/', $remainder, $matches))
|
||||
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))
|
||||
{
|
||||
$Element['attributes']['href'] = $matches[1];
|
||||
|
||||
@ -1214,7 +1212,7 @@ class Parsedown
|
||||
{
|
||||
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
|
||||
{
|
||||
$definition = $matches[1] ? $matches[1] : $Element['text'];
|
||||
$definition = strlen($matches[1]) ? $matches[1] : $Element['text'];
|
||||
$definition = strtolower($definition);
|
||||
|
||||
$extent += strlen($matches[0]);
|
||||
@ -1360,11 +1358,6 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# ~
|
||||
|
||||
protected $unmarkedInlineTypes = array("\n" => 'Break', '://' => 'Url');
|
||||
|
||||
# ~
|
||||
|
||||
protected function unmarkedText($text)
|
||||
@ -1409,7 +1402,7 @@ class Parsedown
|
||||
|
||||
if (isset($Element['handler']))
|
||||
{
|
||||
$markup .= $this->$Element['handler']($Element['text']);
|
||||
$markup .= $this->{$Element['handler']}($Element['text']);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1483,7 +1476,7 @@ class Parsedown
|
||||
return self::$instances[$name];
|
||||
}
|
||||
|
||||
$instance = new self();
|
||||
$instance = new static();
|
||||
|
||||
self::$instances[$name] = $instance;
|
||||
|
||||
|
2
library/vendor/Parsedown/SOURCE
vendored
2
library/vendor/Parsedown/SOURCE
vendored
@ -1,4 +1,4 @@
|
||||
RELEASE=1.5.0
|
||||
RELEASE=1.6.0
|
||||
PARSEDOWN=parsedown-$RELEASE
|
||||
curl https://codeload.github.com/erusev/parsedown/tar.gz/${RELEASE} -o ${PARSEDOWN}.tar.gz
|
||||
tar xfz ${PARSEDOWN}.tar.gz --strip-components 1 ${PARSEDOWN}/Parsedown.php ${PARSEDOWN}/LICENSE.txt
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
namespace Icinga\Module\Doc\Controllers;
|
||||
|
||||
use finfo;
|
||||
use SplFileInfo;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Module\Doc\DocController;
|
||||
use Icinga\Module\Doc\Exception\DocException;
|
||||
@ -88,11 +90,12 @@ class ModuleController extends DocController
|
||||
{
|
||||
$module = $this->params->getRequired('moduleName');
|
||||
$this->assertModuleInstalled($module);
|
||||
$this->view->moduleName = $module;
|
||||
$moduleManager = Icinga::app()->getModuleManager();
|
||||
$name = $moduleManager->getModule($module)->getTitle();
|
||||
try {
|
||||
$this->renderToc(
|
||||
$this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')),
|
||||
$module,
|
||||
$name,
|
||||
'doc/module/chapter',
|
||||
array('moduleName' => $module)
|
||||
);
|
||||
@ -120,6 +123,7 @@ class ModuleController extends DocController
|
||||
$this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc')),
|
||||
$chapter,
|
||||
'doc/module/chapter',
|
||||
'doc/module/img',
|
||||
array('moduleName' => $module)
|
||||
);
|
||||
} catch (DocException $e) {
|
||||
@ -127,6 +131,60 @@ class ModuleController extends DocController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver images
|
||||
*/
|
||||
public function imageAction()
|
||||
{
|
||||
$module = $this->params->getRequired('moduleName');
|
||||
$image = $this->params->getRequired('image');
|
||||
$docPath = $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc'));
|
||||
$imagePath = realpath($docPath . '/' . $image);
|
||||
if ($imagePath === false) {
|
||||
$this->httpNotFound('%s does not exist', $image);
|
||||
}
|
||||
|
||||
$this->_helper->viewRenderer->setNoRender(true);
|
||||
$this->_helper->layout()->disableLayout();
|
||||
|
||||
$imageInfo = new SplFileInfo($imagePath);
|
||||
|
||||
$ETag = md5($imageInfo->getMTime() . $imagePath);
|
||||
$lastModified = gmdate('D, d M Y H:i:s T', $imageInfo->getMTime());
|
||||
$match = false;
|
||||
|
||||
if (isset($_SERER['HTTP_IF_NONE_MATCH'])) {
|
||||
$ifNoneMatch = explode(', ', stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
|
||||
foreach ($ifNoneMatch as $tag) {
|
||||
if ($tag === $ETag) {
|
||||
$match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
|
||||
$lastModifiedSince = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||
if ($lastModifiedSince === $lastModified) {
|
||||
$match = true;
|
||||
}
|
||||
}
|
||||
|
||||
header('ETag: "' . $ETag . '"');
|
||||
header('Cache-Control: no-transform,public,max-age=3600');
|
||||
header('Last-Modified: ' . $lastModified);
|
||||
// Set additional headers for compatibility reasons (Cache-Control should have precedence) in case
|
||||
// session.cache_limiter is set to no cache
|
||||
header('Pragma: cache');
|
||||
header('Expires: ' . gmdate('D, d M Y H:i:s T', time() + 3600));
|
||||
|
||||
if ($match) {
|
||||
header('HTTP/1.1 304 Not Modified');
|
||||
} else {
|
||||
$finfo = new finfo();
|
||||
header('Content-Type: ' . $finfo->file($imagePath, FILEINFO_MIME_TYPE));
|
||||
readfile($imagePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View a module's documentation as PDF
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
# <a id="module-documentation"></a> Writing Module Documentation
|
||||
|
||||

|
||||

|
||||
|
||||
Icinga Web 2 is capable of viewing your module's documentation, if the documentation is written in
|
||||
[Markdown](http://en.wikipedia.org/wiki/Markdown). Please refer to
|
||||
@ -50,13 +50,15 @@ This syntax is also supported in Icinga Web 2.
|
||||
|
||||
## <a id="images"></a> Including Images
|
||||
|
||||
Images must placed in the `img` directory beneath your module's `public` directory, e.g.:
|
||||
Images must placed in the `doc` directory beneath your module's root directory, e.g.:
|
||||
|
||||
example-module/public/img/doc
|
||||
/path/to/icingaweb2/modules/example-module/doc/img/example.png
|
||||
|
||||
Note that the `img` sub directory is not mandatory but good for organizing your directory structure.
|
||||
|
||||
Module images can be accessed using the following URL:
|
||||
|
||||
{baseURL}/img/{moduleName}/{file} e.g. icingaweb/img/example-module/doc/example.png
|
||||
{baseURL}/doc/module/{moduleName}/image/{image} e.g. icingaweb2/doc/module/example-module/image/img/example.png
|
||||
|
||||
Markdown's image syntax is very similar to Markdown's link syntax, but prefixed with an exclamation mark, e.g.:
|
||||
|
||||
@ -64,4 +66,4 @@ Markdown's image syntax is very similar to Markdown's link syntax, but prefixed
|
||||
|
||||
URLs to images inside your Markdown documentation files must be specified without the base URL, e.g.:
|
||||
|
||||

|
||||

|
||||
|
@ -20,6 +20,9 @@ class DocController extends Controller
|
||||
if ($this->hasParam('chapter')) {
|
||||
$this->params->set('chapter', $this->getParam('chapter'));
|
||||
}
|
||||
if ($this->hasParam('image')) {
|
||||
$this->params->set('image', $this->getParam('image'));
|
||||
}
|
||||
if ($this->hasParam('moduleName')) {
|
||||
$this->params->set('moduleName', $this->getParam('moduleName'));
|
||||
}
|
||||
@ -31,20 +34,27 @@ class DocController extends Controller
|
||||
* @param string $path Path to the documentation
|
||||
* @param string $chapter ID of the chapter
|
||||
* @param string $url URL to replace links with
|
||||
* @param string $imageUrl URL to images
|
||||
* @param array $urlParams Additional URL parameters
|
||||
*/
|
||||
protected function renderChapter($path, $chapter, $url, array $urlParams = array())
|
||||
protected function renderChapter($path, $chapter, $url, $imageUrl = null, array $urlParams = array())
|
||||
{
|
||||
$parser = new DocParser($path);
|
||||
$section = new DocSectionRenderer($parser->getDocTree(), DocSectionRenderer::decodeUrlParam($chapter));
|
||||
$this->view->section = $section
|
||||
->setHighlightSearch($this->params->get('highlight-search'))
|
||||
->setImageUrl($imageUrl)
|
||||
->setUrl($url)
|
||||
->setUrlParams($urlParams)
|
||||
->setHighlightSearch($this->params->get('highlight-search'));
|
||||
$this->view->title = $chapter;
|
||||
->setUrlParams($urlParams);
|
||||
$first = null;
|
||||
foreach ($section as $first) {
|
||||
break;
|
||||
}
|
||||
$title = $first === null ? ucfirst($chapter) : $first->getTitle();
|
||||
$this->view->title = $title;
|
||||
$this->getTabs()->add('toc', array(
|
||||
'active' => true,
|
||||
'title' => ucfirst($chapter),
|
||||
'title' => $title,
|
||||
'url' => Url::fromRequest()
|
||||
));
|
||||
$this->render('chapter', null, true);
|
||||
@ -66,10 +76,10 @@ class DocController extends Controller
|
||||
->setUrl($url)
|
||||
->setUrlParams($urlParams);
|
||||
$name = ucfirst($name);
|
||||
$this->view->title = sprintf($this->translate('%s Documentation'), $name);
|
||||
$title = sprintf($this->translate('%s Documentation'), $name);
|
||||
$this->getTabs()->add('toc', array(
|
||||
'active' => true,
|
||||
'title' => $name,
|
||||
'title' => $title,
|
||||
'url' => Url::fromRequest()
|
||||
));
|
||||
$this->render('toc', null, true);
|
||||
|
@ -4,6 +4,7 @@
|
||||
namespace Icinga\Module\Doc;
|
||||
|
||||
use CachingIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SplFileObject;
|
||||
use SplStack;
|
||||
use Icinga\Data\Tree\SimpleTree;
|
||||
@ -61,7 +62,7 @@ class DocParser
|
||||
);
|
||||
}
|
||||
$this->path = $path;
|
||||
$this->docIterator = new DirectoryIterator($path, 'md');
|
||||
$this->docIterator = new DirectoryIterator($path, 'md', DirectoryIterator::FILES_FIRST);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,9 +118,37 @@ class DocParser
|
||||
} else {
|
||||
$id = null;
|
||||
}
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
return array($header, $id, $level, $headerStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique section ID
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $filename
|
||||
* @param SimpleTree $tree
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function uuid($id, $filename, SimpleTree $tree)
|
||||
{
|
||||
$id = str_replace(' ', '-', $id);
|
||||
if ($tree->getNode($id) === null) {
|
||||
return $id;
|
||||
}
|
||||
$id = $id . '-' . md5($filename);
|
||||
$offset = 0;
|
||||
while ($tree->getNode($id)) {
|
||||
if ($offset++ === 0) {
|
||||
$id .= '-' . $offset;
|
||||
} else {
|
||||
$id = substr($id, 0, -1) . $offset;
|
||||
}
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the documentation tree
|
||||
*
|
||||
@ -128,7 +157,7 @@ class DocParser
|
||||
public function getDocTree()
|
||||
{
|
||||
$tree = new SimpleTree();
|
||||
foreach ($this->docIterator as $filename) {
|
||||
foreach (new RecursiveIteratorIterator($this->docIterator) as $filename) {
|
||||
$file = new SplFileObject($filename);
|
||||
$lastLine = null;
|
||||
$stack = new SplStack();
|
||||
@ -154,9 +183,9 @@ class DocParser
|
||||
} else {
|
||||
$noFollow = false;
|
||||
}
|
||||
if ($tree->getNode($id) !== null) {
|
||||
$id = uniqid($id);
|
||||
}
|
||||
|
||||
$id = $this->uuid($id, $filename, $tree);
|
||||
|
||||
$section = new DocSection();
|
||||
$section
|
||||
->setId($id)
|
||||
@ -178,10 +207,7 @@ class DocParser
|
||||
} else {
|
||||
if ($stack->isEmpty()) {
|
||||
$title = ucfirst($file->getBasename('.' . pathinfo($file->getFilename(), PATHINFO_EXTENSION)));
|
||||
$id = $title;
|
||||
if ($tree->getNode($id) !== null) {
|
||||
$id = uniqid($id);
|
||||
}
|
||||
$id = $this->uuid($title, $filename, $tree);
|
||||
$section = new DocSection();
|
||||
$section
|
||||
->setId($id)
|
||||
|
@ -88,14 +88,6 @@ class DocSection extends TreeNode
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
return parent::setId(str_replace(' ', '-', (string) $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header level
|
||||
*
|
||||
|
@ -13,6 +13,13 @@ use Icinga\Web\View;
|
||||
*/
|
||||
abstract class DocRenderer extends RecursiveIteratorIterator
|
||||
{
|
||||
/**
|
||||
* URL to images
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $imageUrl;
|
||||
|
||||
/**
|
||||
* URL to replace links with
|
||||
*
|
||||
@ -34,6 +41,38 @@ abstract class DocRenderer extends RecursiveIteratorIterator
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Get the URL to images
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getImageUrl()
|
||||
{
|
||||
return $this->imageUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to images
|
||||
*
|
||||
* @param string $imageUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setImageUrl($imageUrl)
|
||||
{
|
||||
$this->imageUrl = (string) $imageUrl;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Get the URL to replace links with
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to replace links with
|
||||
*
|
||||
@ -48,13 +87,13 @@ abstract class DocRenderer extends RecursiveIteratorIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to replace links with
|
||||
* Get additional URL parameters
|
||||
*
|
||||
* @return string
|
||||
* @return array
|
||||
*/
|
||||
public function getUrl()
|
||||
public function getUrlParams()
|
||||
{
|
||||
return $this->url;
|
||||
return $this->urlParams;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,13 +110,16 @@ abstract class DocRenderer extends RecursiveIteratorIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Get additional URL parameters
|
||||
* Get the view
|
||||
*
|
||||
* @return array
|
||||
* @return View
|
||||
*/
|
||||
public function getUrlParams()
|
||||
public function getView()
|
||||
{
|
||||
return $this->urlParams;
|
||||
if ($this->view === null) {
|
||||
$this->view = Icinga::app()->getViewRenderer()->view;
|
||||
}
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,19 +135,6 @@ abstract class DocRenderer extends RecursiveIteratorIterator
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
if ($this->view === null) {
|
||||
$this->view = Icinga::app()->getViewRenderer()->view;
|
||||
}
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an anchor identifier
|
||||
*
|
||||
|
@ -190,7 +190,20 @@ class DocSectionRenderer extends DocRenderer
|
||||
$xpath = new DOMXPath($doc);
|
||||
$img = $xpath->query('//img[1]')->item(0);
|
||||
/** @var \DOMElement $img */
|
||||
$img->setAttribute('src', Url::fromPath($img->getAttribute('src'))->getAbsoluteUrl());
|
||||
$path = $this->getView()->getHelper('Url')->url(
|
||||
array_merge(
|
||||
array(
|
||||
'image' => $img->getAttribute('src')
|
||||
),
|
||||
$this->urlParams
|
||||
),
|
||||
$this->imageUrl,
|
||||
false,
|
||||
false
|
||||
);
|
||||
$url = $this->getView()->url($path);
|
||||
/** @var \Icinga\Web\Url $url */
|
||||
$img->setAttribute('src', $url->getAbsoluteUrl());
|
||||
return substr_replace($doc->saveXML($img), '', -2, 1); // Replace '/>' with '>'
|
||||
}
|
||||
|
||||
@ -274,7 +287,7 @@ class DocSectionRenderer extends DocRenderer
|
||||
$html
|
||||
);
|
||||
$html = preg_replace_callback(
|
||||
'#<blockquote>.+</blockquote>#ms',
|
||||
'#<blockquote>.+?</blockquote>#ms',
|
||||
array($this, 'markupNotes'),
|
||||
$html
|
||||
);
|
||||
|
@ -25,6 +25,7 @@ pre > code {
|
||||
|
||||
.chapter a {
|
||||
border-bottom: 1px @gray-light dotted;
|
||||
font-weight: @font-weight-bold;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px @text-color solid;
|
||||
@ -60,14 +61,11 @@ pre > code {
|
||||
|
||||
a {
|
||||
&:before {
|
||||
.rounded-corners();
|
||||
|
||||
background-color: @icinga-blue;
|
||||
color: @text-color-on-icinga-blue;
|
||||
content: counter(li) ".";
|
||||
color: @icinga-blue;
|
||||
content: counters(li,".") " ";
|
||||
display: inline-block;
|
||||
font-size: small;
|
||||
margin-right: 0.25em;
|
||||
font-weight: @font-weight-bold;
|
||||
min-width: 1.5em;
|
||||
padding: 0.25em;
|
||||
text-align: center;
|
||||
|
@ -43,7 +43,22 @@ $docModulePdf = new Zend_Controller_Router_Route(
|
||||
)
|
||||
);
|
||||
|
||||
$docModuleImg = new Zend_Controller_Router_Route_Regex(
|
||||
'doc/module/([^/]+)/image/(.+)',
|
||||
array(
|
||||
'controller' => 'module',
|
||||
'action' => 'image',
|
||||
'module' => 'doc'
|
||||
),
|
||||
array(
|
||||
'moduleName' => 1,
|
||||
'image' => 2
|
||||
),
|
||||
'doc/module/%s/image/%s'
|
||||
);
|
||||
|
||||
$this->addRoute('doc/module/chapter', $docModuleChapter);
|
||||
$this->addRoute('doc/icingaweb/chapter', $docIcingaWebChapter);
|
||||
$this->addRoute('doc/module/toc', $docModuleToc);
|
||||
$this->addRoute('doc/module/pdf', $docModulePdf);
|
||||
$this->addRoute('doc/module/img', $docModuleImg);
|
||||
|
@ -55,6 +55,9 @@ class ListCommand extends Command
|
||||
$query->limit($limit, $this->params->shift('offset'));
|
||||
}
|
||||
foreach ($this->params->getParams() as $col => $filter) {
|
||||
if (strtolower($col) === 'problems') {
|
||||
$col = 'service_problem';
|
||||
}
|
||||
$query->where($col, $filter);
|
||||
}
|
||||
// $query->applyFilters($this->params->getParams());
|
||||
|
@ -49,7 +49,8 @@ class HostsController extends Controller
|
||||
'host_obsessing',
|
||||
'host_passive_checks_enabled',
|
||||
'host_problem',
|
||||
'host_state'
|
||||
'host_state',
|
||||
'instance_name'
|
||||
));
|
||||
$this->view->baseFilter = $this->hostList->getFilter();
|
||||
$this->getTabs()->add(
|
||||
|
@ -39,10 +39,18 @@ class ListController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Display host list
|
||||
* List hosts
|
||||
*/
|
||||
public function hostsAction()
|
||||
{
|
||||
$this->addTitleTab(
|
||||
'hosts',
|
||||
$this->translate('Hosts'),
|
||||
$this->translate('List hosts')
|
||||
);
|
||||
|
||||
$this->setAutorefreshInterval(10);
|
||||
|
||||
// Handle soft and hard states
|
||||
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
|
||||
$stateColumn = 'host_hard_state';
|
||||
@ -51,9 +59,8 @@ class ListController extends Controller
|
||||
$stateColumn = 'host_state';
|
||||
$stateChangeColumn = 'host_last_state_change';
|
||||
}
|
||||
$this->addTitleTab('hosts', $this->translate('Hosts'), $this->translate('List hosts'));
|
||||
$this->setAutorefreshInterval(10);
|
||||
$query = $this->backend->select()->from('hoststatus', array_merge(array(
|
||||
|
||||
$hosts = $this->backend->select()->from('hoststatus', array_merge(array(
|
||||
'host_icon_image',
|
||||
'host_icon_image_alt',
|
||||
'host_name',
|
||||
@ -71,9 +78,20 @@ class ListController extends Controller
|
||||
'host_active_checks_enabled',
|
||||
'host_passive_checks_enabled'
|
||||
), $this->addColumns()));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->hosts = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $hosts);
|
||||
$this->filterQuery($hosts);
|
||||
|
||||
$this->setupPaginationControl($hosts);
|
||||
$this->setupLimitControl();
|
||||
$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'),
|
||||
'host_last_state_change' => $this->translate('Last State Change')
|
||||
), $hosts);
|
||||
|
||||
$stats = $this->backend->select()->from('hoststatussummary', array(
|
||||
'hosts_total',
|
||||
'hosts_up',
|
||||
@ -86,28 +104,26 @@ class ListController extends Controller
|
||||
'hosts_pending',
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $stats);
|
||||
$this->view->stats = $stats;
|
||||
$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'),
|
||||
'host_last_state_change' => $this->translate('Last State Change')
|
||||
), $query);
|
||||
|
||||
$summary = $query->getQuery()->queryServiceProblemSummary();
|
||||
$summary = $hosts->getQuery()->queryServiceProblemSummary();
|
||||
$this->applyRestriction('monitoring/filter/objects', $summary);
|
||||
|
||||
$this->view->hosts = $hosts;
|
||||
$this->view->stats = $stats;
|
||||
$this->view->summary = $summary->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display service list
|
||||
* List services
|
||||
*/
|
||||
public function servicesAction()
|
||||
{
|
||||
$this->addTitleTab(
|
||||
'services',
|
||||
$this->translate('Services'),
|
||||
$this->translate('List services')
|
||||
);
|
||||
|
||||
// Handle soft and hard states
|
||||
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
|
||||
$stateColumn = 'service_hard_state';
|
||||
@ -117,14 +133,9 @@ class ListController extends Controller
|
||||
$stateChangeColumn = 'service_last_state_change';
|
||||
}
|
||||
|
||||
$this->addTitleTab('services', $this->translate('Services'), $this->translate('List services'));
|
||||
$this->view->showHost = true;
|
||||
if (strpos($this->params->get('host_name', '*'), '*') === false) {
|
||||
$this->view->showHost = false;
|
||||
}
|
||||
$this->setAutorefreshInterval(10);
|
||||
|
||||
$columns = array_merge(array(
|
||||
$services = $this->backend->select()->from('servicestatus', array_merge(array(
|
||||
'host_name',
|
||||
'host_display_name',
|
||||
'host_state',
|
||||
@ -147,14 +158,12 @@ class ListController extends Controller
|
||||
'service_notifications_enabled',
|
||||
'service_active_checks_enabled',
|
||||
'service_passive_checks_enabled'
|
||||
), $this->addColumns());
|
||||
$query = $this->backend->select()->from('servicestatus', $columns);
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->services = $query;
|
||||
), $this->addColumns()));
|
||||
$this->applyRestriction('monitoring/filter/objects', $services);
|
||||
$this->filterQuery($services);
|
||||
|
||||
$this->setupPaginationControl($services);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->services);
|
||||
$this->setupSortControl(array(
|
||||
'service_severity' => $this->translate('Service Severity'),
|
||||
'service_state' => $this->translate('Current Service State'),
|
||||
@ -166,7 +175,7 @@ class ListController extends Controller
|
||||
'host_display_name' => $this->translate('Hostname'),
|
||||
'host_address' => $this->translate('Host Address'),
|
||||
'host_last_check' => $this->translate('Last Host Check')
|
||||
), $query);
|
||||
), $services);
|
||||
|
||||
$stats = $this->backend->select()->from('servicestatussummary', array(
|
||||
'services_critical',
|
||||
@ -183,18 +192,30 @@ class ListController extends Controller
|
||||
'services_warning_unhandled'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $stats);
|
||||
|
||||
$this->view->services = $services;
|
||||
$this->view->stats = $stats;
|
||||
if (strpos($this->params->get('host_name', '*'), '*') === false) {
|
||||
$this->view->showHost = false;
|
||||
} else {
|
||||
$this->view->showHost = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the current downtimes and put them into the view property `downtimes`
|
||||
* List downtimes
|
||||
*/
|
||||
public function downtimesAction()
|
||||
{
|
||||
$this->addTitleTab('downtimes', $this->translate('Downtimes'), $this->translate('List downtimes'));
|
||||
$this->addTitleTab(
|
||||
'downtimes',
|
||||
$this->translate('Downtimes'),
|
||||
$this->translate('List downtimes')
|
||||
);
|
||||
|
||||
$this->setAutorefreshInterval(12);
|
||||
|
||||
$query = $this->backend->select()->from('downtime', array(
|
||||
$downtimes = $this->backend->select()->from('downtime', array(
|
||||
'id' => 'downtime_internal_id',
|
||||
'objecttype' => 'object_type',
|
||||
'comment' => 'downtime_comment',
|
||||
@ -215,13 +236,11 @@ class ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
|
||||
$this->view->downtimes = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $downtimes);
|
||||
$this->filterQuery($downtimes);
|
||||
|
||||
$this->setupPaginationControl($downtimes);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->downtimes);
|
||||
$this->setupSortControl(array(
|
||||
'downtime_is_in_effect' => $this->translate('Is In Effect'),
|
||||
'host_display_name' => $this->translate('Host'),
|
||||
@ -233,7 +252,9 @@ class ListController extends Controller
|
||||
'downtime_scheduled_start' => $this->translate('Scheduled Start'),
|
||||
'downtime_scheduled_end' => $this->translate('Scheduled End'),
|
||||
'downtime_duration' => $this->translate('Duration')
|
||||
), $query);
|
||||
), $downtimes);
|
||||
|
||||
$this->view->downtimes = $downtimes;
|
||||
|
||||
if ($this->Auth()->hasPermission('monitoring/command/downtime/delete')) {
|
||||
$this->view->delDowntimeForm = new DeleteDowntimeCommandForm();
|
||||
@ -242,7 +263,7 @@ class ListController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Display notification overview
|
||||
* List notifications
|
||||
*/
|
||||
public function notificationsAction()
|
||||
{
|
||||
@ -251,9 +272,10 @@ class ListController extends Controller
|
||||
$this->translate('Notifications'),
|
||||
$this->translate('List notifications')
|
||||
);
|
||||
|
||||
$this->setAutorefreshInterval(15);
|
||||
|
||||
$query = $this->backend->select()->from('notification', array(
|
||||
$notifications = $this->backend->select()->from('notification', array(
|
||||
'host_name',
|
||||
'service_description',
|
||||
'notification_output',
|
||||
@ -263,22 +285,30 @@ class ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->notifications = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $notifications);
|
||||
$this->filterQuery($notifications);
|
||||
|
||||
$this->setupPaginationControl($notifications);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->notifications);
|
||||
$this->setupSortControl(array(
|
||||
'notification_start_time' => $this->translate('Notification Start')
|
||||
), $query);
|
||||
), $notifications);
|
||||
|
||||
$this->view->notifications = $notifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* List contacts
|
||||
*/
|
||||
public function contactsAction()
|
||||
{
|
||||
$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(
|
||||
$contacts = $this->backend->select()->from('contact', array(
|
||||
'contact_name',
|
||||
'contact_alias',
|
||||
'contact_email',
|
||||
@ -286,20 +316,19 @@ class ListController extends Controller
|
||||
'contact_notify_service_timeperiod',
|
||||
'contact_notify_host_timeperiod'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->contacts = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $contacts);
|
||||
$this->filterQuery($contacts);
|
||||
|
||||
$this->setupPaginationControl($contacts);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->contacts);
|
||||
$this->setupSortControl(array(
|
||||
'contact_name' => $this->translate('Name'),
|
||||
'contact_name' => $this->translate('Name'),
|
||||
'contact_alias' => $this->translate('Alias'),
|
||||
'contact_email' => $this->translate('Email'),
|
||||
'contact_pager' => $this->translate('Pager Address / Number'),
|
||||
'contact_notify_service_timeperiod' => $this->translate('Service Notification Timeperiod'),
|
||||
'contact_notify_host_timeperiod' => $this->translate('Host Notification Timeperiod')
|
||||
), $query);
|
||||
'contact_pager' => $this->translate('Pager Address / Number')
|
||||
), $contacts);
|
||||
|
||||
$this->view->contacts = $contacts;
|
||||
}
|
||||
|
||||
public function eventgridAction()
|
||||
@ -342,6 +371,9 @@ class ListController extends Controller
|
||||
$this->view->orientation = $orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* List contact groups
|
||||
*/
|
||||
public function contactgroupsAction()
|
||||
{
|
||||
$this->addTitleTab(
|
||||
@ -350,47 +382,38 @@ class ListController extends Controller
|
||||
$this->translate('List contact groups')
|
||||
);
|
||||
|
||||
$query = $this->backend->select()->from('contactgroup', array(
|
||||
$contactGroups = $this->backend->select()->from('contactgroup', array(
|
||||
'contactgroup_name',
|
||||
'contactgroup_alias',
|
||||
'contact_name',
|
||||
'contact_alias',
|
||||
'contact_email',
|
||||
'contact_pager'
|
||||
'contact_count'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->applyRestriction('monitoring/filter/objects', $contactGroups);
|
||||
$this->filterQuery($contactGroups);
|
||||
|
||||
$this->setupPaginationControl($contactGroups);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(array(
|
||||
'contactgroup_name' => $this->translate('Contactgroup Name'),
|
||||
'contactgroup_alias' => $this->translate('Contactgroup Alias')
|
||||
), $query);
|
||||
), $contactGroups);
|
||||
|
||||
// Fetch and prepare all contact groups:
|
||||
$contactgroups = $query->getQuery()->fetchAll();
|
||||
$groupData = array();
|
||||
foreach ($contactgroups as $c) {
|
||||
if (!array_key_exists($c->contactgroup_name, $groupData)) {
|
||||
$groupData[$c->contactgroup_name] = array(
|
||||
'alias' => $c->contactgroup_alias,
|
||||
'contacts' => array()
|
||||
);
|
||||
}
|
||||
if (isset ($c->contact_name)) {
|
||||
$groupData[$c->contactgroup_name]['contacts'][] = $c;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find a better naming
|
||||
$this->view->groupData = $groupData;
|
||||
$this->view->contactGroups = $contactGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all comments
|
||||
*/
|
||||
public function commentsAction()
|
||||
{
|
||||
$this->addTitleTab('comments', $this->translate('Comments'), $this->translate('List comments'));
|
||||
$this->addTitleTab(
|
||||
'comments',
|
||||
$this->translate('Comments'),
|
||||
$this->translate('List comments')
|
||||
);
|
||||
|
||||
$this->setAutorefreshInterval(12);
|
||||
|
||||
$query = $this->backend->select()->from('comment', array(
|
||||
$comments = $this->backend->select()->from('comment', array(
|
||||
'id' => 'comment_internal_id',
|
||||
'objecttype' => 'object_type',
|
||||
'comment' => 'comment_data',
|
||||
@ -404,12 +427,11 @@ class ListController extends Controller
|
||||
'host_display_name',
|
||||
'service_display_name'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->comments = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $comments);
|
||||
$this->filterQuery($comments);
|
||||
|
||||
$this->setupPaginationControl($comments);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->comments);
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'comment_timestamp' => $this->translate('Comment Timestamp'),
|
||||
@ -418,15 +440,20 @@ class ListController extends Controller
|
||||
'comment_type' => $this->translate('Comment Type'),
|
||||
'comment_expiration' => $this->translate('Expiration')
|
||||
),
|
||||
$query
|
||||
$comments
|
||||
);
|
||||
|
||||
$this->view->comments = $comments;
|
||||
|
||||
if ($this->Auth()->hasPermission('monitoring/command/comment/delete')) {
|
||||
$this->view->delCommentForm = new DeleteCommentCommandForm();
|
||||
$this->view->delCommentForm->handleRequest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List service groups
|
||||
*/
|
||||
public function servicegroupsAction()
|
||||
{
|
||||
$this->addTitleTab(
|
||||
@ -434,9 +461,10 @@ class ListController extends Controller
|
||||
$this->translate('Service Groups'),
|
||||
$this->translate('List service groups')
|
||||
);
|
||||
|
||||
$this->setAutorefreshInterval(12);
|
||||
|
||||
$query = $this->backend->select()->from('servicegroupsummary', array(
|
||||
$serviceGroups = $this->backend->select()->from('servicegroupsummary', array(
|
||||
'servicegroup_alias',
|
||||
'servicegroup_name',
|
||||
'services_critical_handled',
|
||||
@ -449,25 +477,34 @@ class ListController extends Controller
|
||||
'services_warning_handled',
|
||||
'services_warning_unhandled'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->servicegroups = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $serviceGroups);
|
||||
$this->filterQuery($serviceGroups);
|
||||
|
||||
$this->setupPaginationControl($serviceGroups);
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->servicegroups);
|
||||
$this->setupSortControl(array(
|
||||
'services_severity' => $this->translate('Severity'),
|
||||
'servicegroup_alias' => $this->translate('Service Group Name'),
|
||||
'services_total' => $this->translate('Total Services')
|
||||
), $query);
|
||||
), $serviceGroups);
|
||||
|
||||
$this->view->serviceGroups = $serviceGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* List host groups
|
||||
*/
|
||||
public function hostgroupsAction()
|
||||
{
|
||||
$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);
|
||||
|
||||
$query = $this->backend->select()->from('hostgroupsummary', array(
|
||||
$hostGroups = $this->backend->select()->from('hostgroupsummary', array(
|
||||
'hostgroup_alias',
|
||||
'hostgroup_name',
|
||||
'hosts_down_handled',
|
||||
@ -487,18 +524,19 @@ class ListController extends Controller
|
||||
'services_warning_handled',
|
||||
'services_warning_unhandled'
|
||||
));
|
||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||
$this->filterQuery($query);
|
||||
$this->view->hostgroups = $query;
|
||||
$this->applyRestriction('monitoring/filter/objects', $hostGroups);
|
||||
$this->filterQuery($hostGroups);
|
||||
|
||||
$this->setupPaginationControl($hostGroups);
|
||||
$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);
|
||||
), $hostGroups);
|
||||
|
||||
$this->view->hostGroups = $hostGroups;
|
||||
}
|
||||
|
||||
public function eventhistoryAction()
|
||||
|
@ -41,6 +41,7 @@ class ServicesController extends Controller
|
||||
'host_name',
|
||||
'host_problem',
|
||||
'host_state',
|
||||
'instance_name',
|
||||
'service_acknowledged',
|
||||
'service_active_checks_enabled',
|
||||
'service_description',
|
||||
|
@ -58,24 +58,27 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
|
||||
*/
|
||||
public function createElements(array $formData = array())
|
||||
{
|
||||
if ((bool) $this->status->notifications_enabled) {
|
||||
if ($this->hasPermission('monitoring/command/feature/instance')) {
|
||||
$notificationDescription = null;
|
||||
$isIcinga2 = $this->getBackend()->isIcinga2($this->status->program_version);
|
||||
|
||||
if (! $isIcinga2) {
|
||||
if ((bool) $this->status->notifications_enabled) {
|
||||
if ($this->hasPermission('monitoring/command/feature/instance')) {
|
||||
$notificationDescription = sprintf(
|
||||
'<a aria-label="%1$s" class="action-link" title="%1$s" href="%2$s" data-base-target="_next">%3$s</a>',
|
||||
$this->translate('Disable notifications for a specific time on a program-wide basis'),
|
||||
$this->getView()->href('monitoring/health/disable-notifications'),
|
||||
$this->translate('Disable temporarily')
|
||||
);
|
||||
} else {
|
||||
$notificationDescription = null;
|
||||
}
|
||||
} elseif ($this->status->disable_notif_expire_time) {
|
||||
$notificationDescription = sprintf(
|
||||
'<a aria-label="%1$s" class="action-link" title="%1$s" href="%2$s" data-base-target="_next">%3$s</a>',
|
||||
$this->translate('Disable notifications for a specific time on a program-wide basis'),
|
||||
$this->getView()->href('monitoring/health/disable-notifications'),
|
||||
$this->translate('Disable temporarily')
|
||||
$this->translate('Notifications will be re-enabled in <strong>%s</strong>'),
|
||||
$this->getView()->timeUntil($this->status->disable_notif_expire_time)
|
||||
);
|
||||
} else {
|
||||
$notificationDescription = null;
|
||||
}
|
||||
} elseif ($this->status->disable_notif_expire_time) {
|
||||
$notificationDescription = sprintf(
|
||||
$this->translate('Notifications will be re-enabled in <strong>%s</strong>'),
|
||||
$this->getView()->timeUntil($this->status->disable_notif_expire_time)
|
||||
);
|
||||
} else {
|
||||
$notificationDescription = null;
|
||||
}
|
||||
|
||||
$toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : '';
|
||||
@ -138,7 +141,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
|
||||
)
|
||||
);
|
||||
|
||||
if (! $this->getBackend()->isIcinga2($this->status->program_version)) {
|
||||
if (! $isIcinga2) {
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING,
|
||||
|
@ -27,7 +27,7 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
|
||||
public function host($object)
|
||||
{
|
||||
if ($object->host_icon_image && ! preg_match('/[\'"]/', $object->host_icon_image)) {
|
||||
return $this->view->img(
|
||||
return $this->view->icon(
|
||||
Macro::resolveMacros($object->host_icon_image, $object),
|
||||
null,
|
||||
array(
|
||||
@ -50,7 +50,7 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
|
||||
public function service($object)
|
||||
{
|
||||
if ($object->service_icon_image && ! preg_match('/[\'"]/', $object->service_icon_image)) {
|
||||
return $this->view->img(
|
||||
return $this->view->icon(
|
||||
Macro::resolveMacros($object->service_icon_image, $object),
|
||||
null,
|
||||
array(
|
||||
|
@ -51,6 +51,14 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
|
||||
$isHtml = false;
|
||||
}
|
||||
$output = $this->fixLinks($output);
|
||||
// Help browsers to break words in plugin output
|
||||
$output = trim($output);
|
||||
// Add space after comma where missing
|
||||
$output = preg_replace('/,[^\s]/', ', ', $output);
|
||||
// Add zero width space after ')', ']', ':', '.', '_' and '-' if not surrounded by whitespaces
|
||||
$output = preg_replace('/([^\s])([\\)\\]:._-])([^\s])/', '$1$2​$3', $output);
|
||||
// Add zero width space before '(' and '[' if not surrounded by whitespaces
|
||||
$output = preg_replace('/([^\s])([([])([^\s])/', '$1​$2$3', $output);
|
||||
|
||||
if (! $raw) {
|
||||
if ($isHtml) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
|
@ -2,52 +2,49 @@
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<?php
|
||||
if (count($groupData) === 0) {
|
||||
echo $this->translate('No contactgroups found matching the filter') . '</div>';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<table class="action table-row-selectable common-table" data-base-target="_next">
|
||||
<?php if (! $contactGroups->hasResult()): ?>
|
||||
<p><?= $this->translate('No contact groups found matching the filter') ?></p>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table class="common-table table-row-selectable" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Contact Group ') ?></th>
|
||||
<th><?= $this->translate('Alias') ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Contact Group ') ?></th>
|
||||
<th><?= $this->translate('Alias') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<?php foreach ($groupData as $groupName => $groupInfo): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= count($groupInfo['contacts']) ?></span>
|
||||
</td>
|
||||
<?php foreach ($contactGroups as $contactGroup): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= $contactGroup->contact_count ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->qlink(
|
||||
$contactGroup->contactgroup_name,
|
||||
'monitoring/list/contacts',
|
||||
array('contactgroup_name' => $contactGroup->contactgroup_name),
|
||||
array('title' => sprintf(
|
||||
$this->translate('Show detailed information about %s'),
|
||||
$contactGroup->contactgroup_name
|
||||
))
|
||||
) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->qlink(
|
||||
$groupName,
|
||||
'monitoring/list/contacts',
|
||||
array('contactgroup_name' => $groupName),
|
||||
array('title' => sprintf(
|
||||
$this->translate('Show detailed information about %s'),
|
||||
$groupName
|
||||
))
|
||||
) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($groupInfo['alias'] !== $groupName): ?>
|
||||
<?= $groupInfo['alias'] ?>
|
||||
<?php endif ?>
|
||||
<?php if ($contactGroup->contactgroup_name !== $contactGroup->contactgroup_alias): ?>
|
||||
<?= $contactGroup->contactgroup_alias ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
|
@ -1,79 +1,83 @@
|
||||
<?php if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<?php if ($contacts->hasResult()): ?>
|
||||
<table class="action table-row-selectable common-table" data-base-target="_next">
|
||||
<thead>
|
||||
<?php if (! $contacts->hasResult()): ?>
|
||||
<p><?= $this->translate('No contacts found matching the filter') ?></p>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table class="common-table table-row-selectable" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= $this->translate('Name') ?></th>
|
||||
<th><?= $this->translate('Email') ?></th>
|
||||
<th><?= $this->translate('Pager') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($contacts->peekAhead($this->compact) as $contact): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= $this->qlink(
|
||||
$contact->contact_name,
|
||||
'monitoring/show/contact',
|
||||
array('contact_name' => $contact->contact_name),
|
||||
array('title' => sprintf(
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($contacts->peekAhead($this->compact) as $contact): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= $this->qlink(
|
||||
$contact->contact_name,
|
||||
'monitoring/show/contact',
|
||||
array('contact_name' => $contact->contact_name),
|
||||
array(
|
||||
'title' => sprintf(
|
||||
$this->translate('Show detailed information about %s'),
|
||||
$contact->contact_alias
|
||||
), 'class' => 'rowaction')
|
||||
); ?>
|
||||
</td>
|
||||
)
|
||||
)
|
||||
) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->translate('Email') ?>:
|
||||
<a href="mailto:<?= $contact->contact_email ?>"
|
||||
title="<?= sprintf($this->translate('Send a mail to %s'), $contact->contact_alias) ?>"
|
||||
aria-label="<?= sprintf($this->translate('Send a mail to %s'), $contact->contact_alias) ?>">
|
||||
<?= $this->escape($contact->contact_email) ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?= $this->translate('Email') ?>:
|
||||
<a href="mailto:<?= $contact->contact_email; ?>"
|
||||
title="<?= sprintf($this->translate('Send a mail to %s'), $contact->contact_alias); ?>"
|
||||
aria-label="<?= sprintf($this->translate('Send a mail to %s'), $contact->contact_alias); ?>">
|
||||
<?= $this->escape($contact->contact_email); ?>
|
||||
</a>
|
||||
<?php if ($contact->contact_pager): ?>
|
||||
<?= $this->escape($contact->contact_pager) ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($contact->contact_pager): ?>
|
||||
<?= $this->escape($contact->contact_pager) ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<?php if ($contact->contact_notify_service_timeperiod): ?>
|
||||
<td>
|
||||
<?= $this->escape($contact->contact_notify_service_timeperiod) ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<?php if ($contact->contact_notify_service_timeperiod): ?>
|
||||
<td>
|
||||
<?= $this->escape($contact->contact_notify_service_timeperiod) ?>
|
||||
</td>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($contact->contact_notify_host_timeperiod): ?>
|
||||
<td>
|
||||
<?= $this->escape($contact->contact_notify_host_timeperiod) ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
<?php if ($contact->contact_notify_host_timeperiod): ?>
|
||||
<td>
|
||||
<?= $this->escape($contact->contact_notify_host_timeperiod) ?>
|
||||
</td>
|
||||
<?php endif ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($contacts->hasMore()): ?>
|
||||
<?php if ($contacts->hasMore()): ?>
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'pull-right action-link'
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
); ?>
|
||||
<?php endif ?>
|
||||
<?php else: ?>
|
||||
<?= $this->translate('No contacts found matching the filter'); ?>
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -3,51 +3,56 @@ use Icinga\Module\Monitoring\Object\Host;
|
||||
use Icinga\Module\Monitoring\Object\Service;
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls separated">
|
||||
<?= $tabs ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<table data-base-target="_next"
|
||||
class="table-row-selectable state-table multiselect common-table"
|
||||
data-icinga-multiselect-url="<?= $this->href('monitoring/downtimes/show'); ?>"
|
||||
data-icinga-multiselect-controllers="<?= $this->href("monitoring/downtimes") ?>"
|
||||
data-icinga-multiselect-data="downtime_id">
|
||||
<?php if (! $downtimes->hasResult()): ?>
|
||||
<p><?= $this->translate('No downtimes found matching the filter.') ?></p>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table class="common-table state-table table-row-selectable multiselect"
|
||||
data-base-target="_next"
|
||||
data-icinga-multiselect-url="<?= $this->href('monitoring/downtimes/show') ?>"
|
||||
data-icinga-multiselect-controllers="<?= $this->href("monitoring/downtimes") ?>"
|
||||
data-icinga-multiselect-data="downtime_id">
|
||||
<tbody>
|
||||
<?php foreach ($downtimes->peekAhead($this->compact) as $downtime):
|
||||
if (isset($downtime->service_description)) {
|
||||
$this->isService = true;
|
||||
$this->stateName = Service::getStateText($downtime->service_state);
|
||||
} else {
|
||||
$this->isService = false;
|
||||
$this->stateName = Host::getStateText($downtime->host_state);
|
||||
}
|
||||
$this->downtime = $downtime;
|
||||
?>
|
||||
<tr href="<?= $this->href('monitoring/downtime/show', array('downtime_id' => $downtime->id)) ?>">
|
||||
<?= $this->render('partials/downtime/downtime-header.phtml'); ?>
|
||||
</tr>
|
||||
if (isset($downtime->service_description)) {
|
||||
$this->isService = true;
|
||||
$this->stateName = Service::getStateText($downtime->service_state);
|
||||
} else {
|
||||
$this->isService = false;
|
||||
$this->stateName = Host::getStateText($downtime->host_state);
|
||||
}
|
||||
// Set downtime for partials
|
||||
$this->downtime = $downtime;
|
||||
?>
|
||||
<tr href="<?= $this->href('monitoring/downtime/show', array('downtime_id' => $downtime->id)) ?>">
|
||||
<?= $this->render('partials/downtime/downtime-header.phtml') ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if (! $downtimes->hasResult()): ?>
|
||||
<?= $this->translate('No downtimes found matching the filter, maybe the downtime already expired.'); ?>
|
||||
<?php elseif ($downtimes->hasMore()): ?>
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'pull-right action-link'
|
||||
)
|
||||
); ?>
|
||||
</table>
|
||||
<?php if ($downtimes->hasMore()): ?>
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -4,12 +4,8 @@ use Icinga\Web\Widget\Chart\HistoryColorGrid;
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs; ?>
|
||||
<?= $this->sortBox; ?>
|
||||
<?= $this->limiter; ?>
|
||||
<?= $this->paginator; ?>
|
||||
<?= $this->filterEditor; ?>
|
||||
<?= $form; ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->form ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content" data-base-target="_next">
|
||||
|
@ -3,11 +3,11 @@
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->filterEditor ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?= $this->partial(
|
||||
|
@ -1,278 +1,280 @@
|
||||
<?php
|
||||
use Icinga\Module\Monitoring\Web\Widget\StateBadges;
|
||||
/** @var \Icinga\Module\Monitoring\DataView\Hostgroup $hostgroups */
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="content">
|
||||
<?php if (! $hostgroups->hasResult()): ?>
|
||||
<?php /** @var \Icinga\Module\Monitoring\DataView\Hostgroup $hostGroups */ if (! $hostGroups->hasResult()): ?>
|
||||
<p><?= $this->translate('No host groups found matching the filter.') ?></p>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table class="table-row-selectable common-table" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Host Group') ?></th>
|
||||
<th><?= $this->translate('Host States') ?></th>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Service States') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($hostgroups->peekAhead($this->compact) as $hostgroup): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= $hostgroup->hosts_total ?></span>
|
||||
</td>
|
||||
<th>
|
||||
<?= $this->qlink(
|
||||
$hostgroup->hostgroup_alias,
|
||||
'monitoring/list/hosts',
|
||||
array('hostgroup_name' => $hostgroup->hostgroup_name),
|
||||
array('title' => sprintf(
|
||||
$this->translate('List all hosts in the group "%s"'),
|
||||
$hostgroup->hostgroup_alias
|
||||
))
|
||||
) ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/hosts')
|
||||
->setBaseFilter($this->filterEditor->getFilter())
|
||||
->add(
|
||||
StateBadges::STATE_UP,
|
||||
$hostgroup->hosts_up,
|
||||
array(
|
||||
'host_state' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UP in the host group "%s"',
|
||||
'List %u hosts which are currently in state UP in the host group "%s"',
|
||||
array($hostgroup->hosts_up, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_DOWN,
|
||||
$hostgroup->hosts_down_unhandled,
|
||||
array(
|
||||
'host_state' => 1,
|
||||
'host_acknowledged' => 0,
|
||||
'host_in_downtime' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state DOWN in the host group "%s"',
|
||||
'List %u hosts which are currently in state DOWN in the host group "%s"',
|
||||
array($hostgroup->hosts_down_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_DOWN_HANDLED,
|
||||
$hostgroup->hosts_down_handled,
|
||||
array(
|
||||
'host_state' => 1,
|
||||
'host_handled' => 1,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state DOWN (Acknowledged) in the host group "%s"',
|
||||
'List %u hosts which are currently in state DOWN (Acknowledged) in the host group "%s"',
|
||||
array($hostgroup->hosts_down_handled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNREACHABLE,
|
||||
$hostgroup->hosts_unreachable_unhandled,
|
||||
array(
|
||||
'host_state' => 2,
|
||||
'host_acknowledged' => 0,
|
||||
'host_in_downtime' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UNREACHABLE in the host group "%s"',
|
||||
'List %u hosts which are currently in state UNREACHABLE in the host group "%s"',
|
||||
array($hostgroup->hosts_unreachable_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNREACHABLE_HANDLED,
|
||||
$hostgroup->hosts_unreachable_handled,
|
||||
array(
|
||||
'host_state' => 2,
|
||||
'host_handled' => 1,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UNREACHABLE (Acknowledged) in the host group "%s"',
|
||||
'List %u hosts which are currently in state UNREACHABLE (Acknowledged) in the host group "%s"',
|
||||
array($hostgroup->hosts_unreachable_handled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$hostgroup->hosts_pending,
|
||||
array(
|
||||
'host_state' => 99,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state PENDING in the host group "%s"',
|
||||
'List %u hosts which are currently in state PENDING in the host group "%s"',
|
||||
array($hostgroup->hosts_pending, $hostgroup->hostgroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
<td class="count-col">
|
||||
<?= $this->qlink(
|
||||
$hostgroup->services_total,
|
||||
'monitoring/list/services',
|
||||
array('hostgroup_name' => $hostgroup->hostgroup_name),
|
||||
array('title' => sprintf(
|
||||
$this->translate('List all services of all hosts in host group "%s"'),
|
||||
$hostgroup->hostgroup_alias
|
||||
), 'class' => 'badge')
|
||||
) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/services')
|
||||
->add(
|
||||
StateBadges::STATE_OK,
|
||||
$hostgroup->services_ok,
|
||||
array(
|
||||
'service_state' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state OK on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state OK on hosts in the host group "%s"',
|
||||
array($hostgroup->services_ok, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL,
|
||||
$hostgroup->services_critical_unhandled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state CRITICAL on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state CRITICAL on hosts in the host group "%s"',
|
||||
array($hostgroup->services_critical_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL_HANDLED,
|
||||
$hostgroup->services_critical_handled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostgroup->services_critical_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN,
|
||||
$hostgroup->services_unknown_unhandled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state UNKNOWN on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state UNKNOWN on hosts in the host group "%s"',
|
||||
array($hostgroup->services_unknown_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN_HANDLED,
|
||||
$hostgroup->services_unknown_handled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostgroup->services_unknown_handled, $hostgroup->hostgroup_alias)
|
||||
<table class="common-table table-row-selectable" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Host Group') ?></th>
|
||||
<th><?= $this->translate('Host States') ?></th>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Service States') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($hostGroups->peekAhead($this->compact) as $hostGroup): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= $hostGroup->hosts_total ?></span>
|
||||
</td>
|
||||
<th>
|
||||
<?= $this->qlink(
|
||||
$hostGroup->hostgroup_alias,
|
||||
'monitoring/list/hosts',
|
||||
array('hostgroup_name' => $hostGroup->hostgroup_name),
|
||||
array('title' => sprintf(
|
||||
$this->translate('List all hosts in the group "%s"'),
|
||||
$hostGroup->hostgroup_alias
|
||||
))
|
||||
) ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/hosts')
|
||||
->setBaseFilter($this->filterEditor->getFilter())
|
||||
->add(
|
||||
StateBadges::STATE_UP,
|
||||
$hostGroup->hosts_up,
|
||||
array(
|
||||
'host_state' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UP in the host group "%s"',
|
||||
'List %u hosts which are currently in state UP in the host group "%s"',
|
||||
array($hostGroup->hosts_up, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_DOWN,
|
||||
$hostGroup->hosts_down_unhandled,
|
||||
array(
|
||||
'host_state' => 1,
|
||||
'host_acknowledged' => 0,
|
||||
'host_in_downtime' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state DOWN in the host group "%s"',
|
||||
'List %u hosts which are currently in state DOWN in the host group "%s"',
|
||||
array($hostGroup->hosts_down_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_DOWN_HANDLED,
|
||||
$hostGroup->hosts_down_handled,
|
||||
array(
|
||||
'host_state' => 1,
|
||||
'host_handled' => 1,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state DOWN (Acknowledged) in the host group "%s"',
|
||||
'List %u hosts which are currently in state DOWN (Acknowledged) in the host group "%s"',
|
||||
array($hostGroup->hosts_down_handled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNREACHABLE,
|
||||
$hostGroup->hosts_unreachable_unhandled,
|
||||
array(
|
||||
'host_state' => 2,
|
||||
'host_acknowledged' => 0,
|
||||
'host_in_downtime' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UNREACHABLE in the host group "%s"',
|
||||
'List %u hosts which are currently in state UNREACHABLE in the host group "%s"',
|
||||
array($hostGroup->hosts_unreachable_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNREACHABLE_HANDLED,
|
||||
$hostGroup->hosts_unreachable_handled,
|
||||
array(
|
||||
'host_state' => 2,
|
||||
'host_handled' => 1,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state UNREACHABLE (Acknowledged) in the host group "%s"',
|
||||
'List %u hosts which are currently in state UNREACHABLE (Acknowledged) in the host group "%s"',
|
||||
array($hostGroup->hosts_unreachable_handled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$hostGroup->hosts_pending,
|
||||
array(
|
||||
'host_state' => 99,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'host_severity'
|
||||
),
|
||||
'List %u host that is currently in state PENDING in the host group "%s"',
|
||||
'List %u hosts which are currently in state PENDING in the host group "%s"',
|
||||
array($hostGroup->hosts_pending, $hostGroup->hostgroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
<td class="count-col">
|
||||
<?= $this->qlink(
|
||||
$hostGroup->services_total,
|
||||
'monitoring/list/services',
|
||||
array('hostgroup_name' => $hostGroup->hostgroup_name),
|
||||
array('title' => sprintf(
|
||||
$this->translate('List all services of all hosts in host group "%s"'),
|
||||
$hostGroup->hostgroup_alias
|
||||
), 'class' => 'badge')
|
||||
) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/services')
|
||||
->add(
|
||||
StateBadges::STATE_OK,
|
||||
$hostGroup->services_ok,
|
||||
array(
|
||||
'service_state' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state OK on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state OK on hosts in the host group "%s"',
|
||||
array($hostGroup->services_ok, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL,
|
||||
$hostGroup->services_critical_unhandled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state CRITICAL on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state CRITICAL on hosts in the host group "%s"',
|
||||
array($hostGroup->services_critical_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL_HANDLED,
|
||||
$hostGroup->services_critical_handled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state CRITICAL (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostGroup->services_critical_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN,
|
||||
$hostGroup->services_unknown_unhandled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state UNKNOWN on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state UNKNOWN on hosts in the host group "%s"',
|
||||
array($hostGroup->services_unknown_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN_HANDLED,
|
||||
$hostGroup->services_unknown_handled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state UNKNOWN (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostGroup->services_unknown_handled, $hostGroup->hostgroup_alias)
|
||||
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING,
|
||||
$hostgroup->services_warning_unhandled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state WARNING on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state WARNING on hosts in the host group "%s"',
|
||||
array($hostgroup->services_warning_unhandled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING_HANDLED,
|
||||
$hostgroup->services_warning_handled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state WARNING (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state WARNING (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostgroup->services_warning_handled, $hostgroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$hostgroup->services_pending,
|
||||
array(
|
||||
'service_state' => 99,
|
||||
'hostgroup_name' => $hostgroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state PENDING on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state PENDING on hosts in the host group "%s"',
|
||||
array($hostgroup->services_pending, $hostgroup->hostgroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($hostgroups->hasMore()): ?>
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'pull-right action-link'
|
||||
)
|
||||
) ?>
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING,
|
||||
$hostGroup->services_warning_unhandled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state WARNING on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state WARNING on hosts in the host group "%s"',
|
||||
array($hostGroup->services_warning_unhandled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING_HANDLED,
|
||||
$hostGroup->services_warning_handled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_handled' => 1,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state WARNING (Acknowledged) on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state WARNING (Acknowledged) on hosts in the host group "%s"',
|
||||
array($hostGroup->services_warning_handled, $hostGroup->hostgroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$hostGroup->services_pending,
|
||||
array(
|
||||
'service_state' => 99,
|
||||
'hostgroup_name' => $hostGroup->hostgroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %u service that is currently in state PENDING on hosts in the host group "%s"',
|
||||
'List %u services which are currently in state PENDING on hosts in the host group "%s"',
|
||||
array($hostGroup->services_pending, $hostGroup->hostgroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($hostGroups->hasMore()): ?>
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -4,14 +4,12 @@ use Icinga\Module\Monitoring\Object\Host;
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->render('list/components/hostssummary.phtml') ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->render('list/components/hostssummary.phtml') ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
@ -19,7 +17,7 @@ if (! $this->compact): ?>
|
||||
<div class="content">
|
||||
<?php if (! $hosts->hasResult()): ?>
|
||||
<p><?= $this->translate('No hosts found matching the filter.') ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table data-base-target="_next"
|
||||
class="table-row-selectable state-table multiselect"
|
||||
@ -96,14 +94,14 @@ if (! $this->compact): ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($hosts->hasMore()): ?>
|
||||
<div class="text-right">
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'action-link'
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
|
@ -4,11 +4,11 @@ use Icinga\Module\Monitoring\Object\Service;
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
@ -77,7 +77,7 @@ if (! $this->compact): ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($notifications->hasMore()): ?>
|
||||
<div class="text-right">
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')),
|
||||
|
@ -2,173 +2,175 @@
|
||||
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->tabs ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="content">
|
||||
<?php if (! $servicegroups->hasResult()): ?>
|
||||
<?php if (! $serviceGroups->hasResult()): ?>
|
||||
<p><?= $this->translate('No service groups found matching the filter.') ?></p>
|
||||
</div>
|
||||
<?php return; endif ?>
|
||||
<table class="table-row-selectable common-table" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Service Group') ?></th>
|
||||
<th><?= $this->translate('Service States') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($servicegroups->peekAhead($this->compact) as $serviceGroup): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= $serviceGroup->services_total ?></span>
|
||||
</td>
|
||||
<th>
|
||||
<?= $this->qlink(
|
||||
$serviceGroup->servicegroup_alias,
|
||||
'monitoring/list/services',
|
||||
array('servicegroup_name' => $serviceGroup->servicegroup_name),
|
||||
array('title' => sprintf($this->translate('List all services in the group "%s"'), $serviceGroup->servicegroup_alias))
|
||||
) ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/services')
|
||||
->setBaseFilter($this->filterEditor->getFilter())
|
||||
->add(
|
||||
StateBadges::STATE_OK,
|
||||
$serviceGroup->services_ok,
|
||||
array(
|
||||
'service_state' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state OK in service group "%s"',
|
||||
'List %s services which are currently in state OK in service group "%s"',
|
||||
array($serviceGroup->services_ok, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL,
|
||||
$serviceGroup->services_critical_unhandled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state CRITICAL in service group "%s"',
|
||||
'List %s services which are currently in state CRITICAL in service group "%s"',
|
||||
array($serviceGroup->services_critical_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL_HANDLED,
|
||||
$serviceGroup->services_critical_handled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state CRITICAL (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state CRITICAL (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_critical_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN,
|
||||
$serviceGroup->services_unknown_unhandled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state UNKNOWN in service group "%s"',
|
||||
'List %s services which are currently in state UNKNOWN in service group "%s"',
|
||||
array($serviceGroup->services_unknown_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN_HANDLED,
|
||||
$serviceGroup->services_unknown_handled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state UNKNOWN (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state UNKNOWN (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_unknown_handled, $serviceGroup->servicegroup_alias)
|
||||
<table class="table-row-selectable common-table" data-base-target="_next">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><?= $this->translate('Service Group') ?></th>
|
||||
<th><?= $this->translate('Service States') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($serviceGroups->peekAhead($this->compact) as $serviceGroup): ?>
|
||||
<tr>
|
||||
<td class="count-col">
|
||||
<span class="badge"><?= $serviceGroup->services_total ?></span>
|
||||
</td>
|
||||
<th>
|
||||
<?= $this->qlink(
|
||||
$serviceGroup->servicegroup_alias,
|
||||
'monitoring/list/services',
|
||||
array('servicegroup_name' => $serviceGroup->servicegroup_name),
|
||||
array('title' => sprintf($this->translate('List all services in the group "%s"'), $serviceGroup->servicegroup_alias))
|
||||
) ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
$stateBadges = new StateBadges();
|
||||
$stateBadges
|
||||
->setUrl('monitoring/list/services')
|
||||
->setBaseFilter($this->filterEditor->getFilter())
|
||||
->add(
|
||||
StateBadges::STATE_OK,
|
||||
$serviceGroup->services_ok,
|
||||
array(
|
||||
'service_state' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state OK in service group "%s"',
|
||||
'List %s services which are currently in state OK in service group "%s"',
|
||||
array($serviceGroup->services_ok, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL,
|
||||
$serviceGroup->services_critical_unhandled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state CRITICAL in service group "%s"',
|
||||
'List %s services which are currently in state CRITICAL in service group "%s"',
|
||||
array($serviceGroup->services_critical_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_CRITICAL_HANDLED,
|
||||
$serviceGroup->services_critical_handled,
|
||||
array(
|
||||
'service_state' => 2,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state CRITICAL (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state CRITICAL (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_critical_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN,
|
||||
$serviceGroup->services_unknown_unhandled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state UNKNOWN in service group "%s"',
|
||||
'List %s services which are currently in state UNKNOWN in service group "%s"',
|
||||
array($serviceGroup->services_unknown_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_UNKNOWN_HANDLED,
|
||||
$serviceGroup->services_unknown_handled,
|
||||
array(
|
||||
'service_state' => 3,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state UNKNOWN (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state UNKNOWN (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_unknown_handled, $serviceGroup->servicegroup_alias)
|
||||
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING,
|
||||
$serviceGroup->services_warning_unhandled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state WARNING in service group "%s"',
|
||||
'List %s services which are currently in state WARNING in service group "%s"',
|
||||
array($serviceGroup->services_warning_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING_HANDLED,
|
||||
$serviceGroup->services_warning_handled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state WARNING (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state WARNING (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_warning_handled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$serviceGroup->services_pending,
|
||||
array(
|
||||
'service_state' => 99,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currenlty in state PENDING in service group "%s"',
|
||||
'List %s services which are currently in state PENDING in service group "%s"',
|
||||
array($serviceGroup->services_pending, $serviceGroup->servicegroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($servicegroups->hasMore()): ?>
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'pull-right action-link'
|
||||
)
|
||||
) ?>
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING,
|
||||
$serviceGroup->services_warning_unhandled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0,
|
||||
'host_problem' => 0,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state WARNING in service group "%s"',
|
||||
'List %s services which are currently in state WARNING in service group "%s"',
|
||||
array($serviceGroup->services_warning_unhandled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_WARNING_HANDLED,
|
||||
$serviceGroup->services_warning_handled,
|
||||
array(
|
||||
'service_state' => 1,
|
||||
'service_handled' => 1,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currently in state WARNING (Acknowledged) in service group "%s"',
|
||||
'List %s services which are currently in state WARNING (Acknowledged) in service group "%s"',
|
||||
array($serviceGroup->services_warning_handled, $serviceGroup->servicegroup_alias)
|
||||
)
|
||||
->add(
|
||||
StateBadges::STATE_PENDING,
|
||||
$serviceGroup->services_pending,
|
||||
array(
|
||||
'service_state' => 99,
|
||||
'servicegroup_name' => $serviceGroup->servicegroup_name,
|
||||
'sort' => 'service_severity'
|
||||
),
|
||||
'List %s service that is currenlty in state PENDING in service group "%s"',
|
||||
'List %s services which are currently in state PENDING in service group "%s"',
|
||||
array($serviceGroup->services_pending, $serviceGroup->servicegroup_alias)
|
||||
);
|
||||
echo $stateBadges->render();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($serviceGroups->hasMore()): ?>
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -5,14 +5,12 @@ use Icinga\Module\Monitoring\Object\Service;
|
||||
if (! $this->compact): ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<div class="grid">
|
||||
<?= $this->render('list/components/servicesummary.phtml') ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<?= $this->sortBox ?>
|
||||
<?= $this->render('list/components/servicesummary.phtml') ?>
|
||||
<?= $this->render('list/components/selectioninfo.phtml') ?>
|
||||
<?= $this->paginator ?>
|
||||
<div class="sort-controls-container">
|
||||
<?= $this->limiter ?>
|
||||
<?= $this->paginator ?>
|
||||
<?= $this->sortBox ?>
|
||||
</div>
|
||||
<?= $this->filterEditor ?>
|
||||
</div>
|
||||
@ -101,16 +99,16 @@ if (! $this->compact): ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ($services->hasMore()): ?>
|
||||
<div class="text-right">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'data-base-target' => '_next',
|
||||
'class' => 'action-link'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
<div class="action-links">
|
||||
<?= $this->qlink(
|
||||
$this->translate('Show More'),
|
||||
$this->url()->without(array('view', 'limit')),
|
||||
null,
|
||||
array(
|
||||
'class' => 'action-link',
|
||||
'data-base-target' => '_next'
|
||||
)
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
@ -16,12 +16,12 @@ class ContactgroupQuery extends IdoQuery
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $groupBase = array('contactgroups' => array('cg.contactgroup_id', 'cgo.object_id'));
|
||||
protected $groupBase = array('contactgroups' => array('cg.contactgroup_id'));
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $groupOrigin = array('contacts', 'hosts', 'services');
|
||||
protected $groupOrigin = array('hosts', 'members', 'services');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -32,28 +32,8 @@ class ContactgroupQuery extends IdoQuery
|
||||
'contactgroup_name' => 'cgo.name1',
|
||||
'contactgroup_alias' => 'cg.alias COLLATE latin1_general_ci'
|
||||
),
|
||||
'contacts' => array(
|
||||
'contact_id' => 'c.contact_id',
|
||||
'contact' => 'co.name1 COLLATE latin1_general_ci',
|
||||
'contact_name' => 'co.name1',
|
||||
'contact_alias' => 'c.alias COLLATE latin1_general_ci',
|
||||
'contact_email' => 'c.email_address COLLATE latin1_general_ci',
|
||||
'contact_pager' => 'c.pager_address',
|
||||
'contact_object_id' => 'c.contact_object_id',
|
||||
'contact_has_host_notfications' => 'c.host_notifications_enabled',
|
||||
'contact_has_service_notfications' => 'c.service_notifications_enabled',
|
||||
'contact_can_submit_commands' => 'c.can_submit_commands',
|
||||
'contact_notify_service_recovery' => 'c.notify_service_recovery',
|
||||
'contact_notify_service_warning' => 'c.notify_service_warning',
|
||||
'contact_notify_service_critical' => 'c.notify_service_critical',
|
||||
'contact_notify_service_unknown' => 'c.notify_service_unknown',
|
||||
'contact_notify_service_flapping' => 'c.notify_service_flapping',
|
||||
'contact_notify_service_downtime' => 'c.notify_service_recovery',
|
||||
'contact_notify_host_recovery' => 'c.notify_host_recovery',
|
||||
'contact_notify_host_down' => 'c.notify_host_down',
|
||||
'contact_notify_host_unreachable' => 'c.notify_host_unreachable',
|
||||
'contact_notify_host_flapping' => 'c.notify_host_flapping',
|
||||
'contact_notify_host_downtime' => 'c.notify_host_downtime'
|
||||
'members' => array(
|
||||
'contact_count' => 'COUNT(cgm.contactgroup_member_id)'
|
||||
),
|
||||
'hostgroups' => array(
|
||||
'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci',
|
||||
@ -99,22 +79,18 @@ class ContactgroupQuery extends IdoQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* Join contacts
|
||||
* Join contact group members
|
||||
*/
|
||||
protected function joinContacts()
|
||||
protected function joinMembers()
|
||||
{
|
||||
$this->select->joinLeft(
|
||||
array('cgm' => $this->prefix . 'contactgroup_members'),
|
||||
'cgm.contactgroup_id = cg.contactgroup_id',
|
||||
array()
|
||||
)->joinLeft(
|
||||
)->join(
|
||||
array('co' => $this->prefix . 'objects'),
|
||||
'co.object_id = cgm.contact_object_id AND co.is_active = 1 AND co.objecttype_id = 10',
|
||||
array()
|
||||
)->joinLeft(
|
||||
array('c' => $this->prefix . 'contacts'),
|
||||
'c.contact_object_id = co.object_id',
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -11,31 +11,9 @@ class Contactgroup extends DataView
|
||||
public function getColumns()
|
||||
{
|
||||
return array(
|
||||
'instance_name',
|
||||
'contactgroup_name',
|
||||
'contactgroup_alias',
|
||||
'contact_object_id',
|
||||
'contact_id',
|
||||
'contact_name',
|
||||
'contact_alias',
|
||||
'contact_email',
|
||||
'contact_pager',
|
||||
'contact_has_host_notfications',
|
||||
'contact_has_service_notfications',
|
||||
'contact_can_submit_commands',
|
||||
'contact_notify_service_recovery',
|
||||
'contact_notify_service_warning',
|
||||
'contact_notify_service_critical',
|
||||
'contact_notify_service_unknown',
|
||||
'contact_notify_service_flapping',
|
||||
'contact_notify_service_downtime',
|
||||
'contact_notify_host_recovery',
|
||||
'contact_notify_host_down',
|
||||
'contact_notify_host_unreachable',
|
||||
'contact_notify_host_flapping',
|
||||
'contact_notify_host_downtime',
|
||||
'contact_notify_host_timeperiod',
|
||||
'contact_notify_service_timeperiod'
|
||||
'contact_count'
|
||||
);
|
||||
}
|
||||
|
||||
@ -60,9 +38,10 @@ class Contactgroup extends DataView
|
||||
public function getStaticFilterColumns()
|
||||
{
|
||||
return array(
|
||||
'contactgroup', 'contact',
|
||||
'contactgroup',
|
||||
'host', 'host_name', 'host_display_name', 'host_alias',
|
||||
'hostgroup', 'hostgroup_alias', 'hostgroup_name',
|
||||
'instance_name',
|
||||
'service', 'service_description', 'service_display_name',
|
||||
'servicegroup', 'servicegroup_alias', 'servicegroup_name'
|
||||
);
|
||||
|
@ -11,58 +11,56 @@ class HostStatus extends DataView
|
||||
public function getColumns()
|
||||
{
|
||||
return array_merge($this->getHookedColumns(), array(
|
||||
'instance_name',
|
||||
'host_name',
|
||||
'host_display_name',
|
||||
'host_alias',
|
||||
'host_acknowledged',
|
||||
'host_acknowledgement_type',
|
||||
'host_action_url',
|
||||
'host_active_checks_enabled',
|
||||
'host_active_checks_enabled_changed',
|
||||
'host_address',
|
||||
'host_address6',
|
||||
'host_state',
|
||||
'host_hard_state',
|
||||
'host_state_type',
|
||||
'host_handled',
|
||||
'host_unhandled',
|
||||
'host_in_downtime',
|
||||
'host_acknowledged',
|
||||
'host_last_state_change',
|
||||
'host_last_state_change',
|
||||
'host_last_notification',
|
||||
'host_last_check',
|
||||
'host_next_check',
|
||||
'host_alias',
|
||||
'host_check_command',
|
||||
'host_check_execution_time',
|
||||
'host_check_latency',
|
||||
'host_output',
|
||||
'host_long_output',
|
||||
'host_check_command',
|
||||
'host_check_timeperiod',
|
||||
'host_perfdata',
|
||||
'host_check_source',
|
||||
'host_passive_checks_enabled',
|
||||
'host_passive_checks_enabled_changed',
|
||||
'host_obsessing',
|
||||
'host_obsessing_changed',
|
||||
'host_notifications_enabled',
|
||||
'host_notifications_enabled_changed',
|
||||
'host_check_timeperiod',
|
||||
'host_current_check_attempt',
|
||||
'host_current_notification_number',
|
||||
'host_display_name',
|
||||
'host_event_handler_enabled',
|
||||
'host_event_handler_enabled_changed',
|
||||
'host_flap_detection_enabled',
|
||||
'host_flap_detection_enabled_changed',
|
||||
'host_active_checks_enabled',
|
||||
'host_active_checks_enabled_changed',
|
||||
'host_current_check_attempt',
|
||||
'host_max_check_attempts',
|
||||
'host_last_notification',
|
||||
'host_current_notification_number',
|
||||
'host_percent_state_change',
|
||||
'host_is_flapping',
|
||||
'host_action_url',
|
||||
'host_notes_url',
|
||||
'host_percent_state_change',
|
||||
'host_modified_host_attributes',
|
||||
'host_severity',
|
||||
'host_problem',
|
||||
'host_handled',
|
||||
'host_hard_state',
|
||||
'host_in_downtime',
|
||||
'host_ipv4',
|
||||
'host_acknowledgement_type'
|
||||
'host_is_flapping',
|
||||
'host_is_reachable',
|
||||
'host_last_check',
|
||||
'host_last_notification',
|
||||
'host_last_state_change',
|
||||
'host_long_output',
|
||||
'host_max_check_attempts',
|
||||
'host_modified_host_attributes',
|
||||
'host_name',
|
||||
'host_next_check',
|
||||
'host_notes_url',
|
||||
'host_notifications_enabled',
|
||||
'host_notifications_enabled_changed',
|
||||
'host_obsessing',
|
||||
'host_obsessing_changed',
|
||||
'host_output',
|
||||
'host_passive_checks_enabled',
|
||||
'host_passive_checks_enabled_changed',
|
||||
'host_percent_state_change',
|
||||
'host_perfdata',
|
||||
'host_problem',
|
||||
'host_severity',
|
||||
'host_state',
|
||||
'host_state_type',
|
||||
'host_unhandled',
|
||||
'instance_name'
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -11,93 +11,91 @@ class ServiceStatus extends DataView
|
||||
public function getColumns()
|
||||
{
|
||||
return array_merge($this->getHookedColumns(), array(
|
||||
'instance_name',
|
||||
'host_name',
|
||||
'host_display_name',
|
||||
'host_state',
|
||||
'host_hard_state',
|
||||
'host_state_type',
|
||||
'host_last_state_change',
|
||||
'host_acknowledged',
|
||||
'host_action_url',
|
||||
'host_active_checks_enabled',
|
||||
'host_address',
|
||||
'host_address6',
|
||||
'host_problem',
|
||||
'host_alias',
|
||||
'host_check_source',
|
||||
'host_display_name',
|
||||
'host_handled',
|
||||
'service_description',
|
||||
'service_display_name',
|
||||
'service_state',
|
||||
'service_hard_state',
|
||||
'service_in_downtime',
|
||||
'service_acknowledged',
|
||||
'service_handled',
|
||||
'service_unhandled',
|
||||
'service_output',
|
||||
'service_last_state_change',
|
||||
'service_long_output',
|
||||
'service_is_flapping',
|
||||
'service_state_type',
|
||||
'service_severity',
|
||||
'service_last_check',
|
||||
'service_notifications_enabled',
|
||||
'service_notifications_enabled_changed',
|
||||
'service_action_url',
|
||||
'service_notes',
|
||||
'service_notes_url',
|
||||
'service_last_check',
|
||||
'service_next_check',
|
||||
'service_attempt',
|
||||
'service_last_notification',
|
||||
'service_check_command',
|
||||
'service_current_notification_number',
|
||||
'host_acknowledged',
|
||||
'host_output',
|
||||
'host_long_output',
|
||||
'host_hard_state',
|
||||
'host_in_downtime',
|
||||
'host_ipv4',
|
||||
'host_is_flapping',
|
||||
'host_last_check',
|
||||
'host_notifications_enabled',
|
||||
'host_unhandled_service_count',
|
||||
'host_action_url',
|
||||
'host_notes_url',
|
||||
'host_display_name',
|
||||
'host_alias',
|
||||
'host_ipv4',
|
||||
'host_severity',
|
||||
'host_perfdata',
|
||||
'host_check_source',
|
||||
'host_active_checks_enabled',
|
||||
'host_passive_checks_enabled',
|
||||
'host_last_hard_state',
|
||||
'host_last_hard_state_change',
|
||||
'host_last_time_up',
|
||||
'host_last_state_change',
|
||||
'host_last_time_down',
|
||||
'host_last_time_unreachable',
|
||||
'host_last_time_up',
|
||||
'host_long_output',
|
||||
'host_modified_host_attributes',
|
||||
'service_hard_state',
|
||||
'service_problem',
|
||||
'service_perfdata',
|
||||
'service_check_source',
|
||||
'service_check_timeperiod',
|
||||
'host_name',
|
||||
'host_notes_url',
|
||||
'host_notifications_enabled',
|
||||
'host_output',
|
||||
'host_passive_checks_enabled',
|
||||
'host_perfdata',
|
||||
'host_problem',
|
||||
'host_severity',
|
||||
'host_state',
|
||||
'host_state_type',
|
||||
'host_unhandled_service_count',
|
||||
'instance_name',
|
||||
'service_acknowledged',
|
||||
'service_acknowledgement_type',
|
||||
'service_action_url',
|
||||
'service_active_checks_enabled',
|
||||
'service_active_checks_enabled_changed',
|
||||
'service_passive_checks_enabled',
|
||||
'service_passive_checks_enabled_changed',
|
||||
'service_last_hard_state',
|
||||
'service_last_hard_state_change',
|
||||
'service_last_time_ok',
|
||||
'service_last_time_warning',
|
||||
'service_last_time_critical',
|
||||
'service_last_time_unknown',
|
||||
'service_attempt',
|
||||
'service_check_command',
|
||||
'service_check_source',
|
||||
'service_check_timeperiod',
|
||||
'service_current_check_attempt',
|
||||
'service_max_check_attempts',
|
||||
'service_obsessing',
|
||||
'service_obsessing_changed',
|
||||
'service_current_notification_number',
|
||||
'service_description',
|
||||
'service_display_name',
|
||||
'service_event_handler_enabled',
|
||||
'service_event_handler_enabled_changed',
|
||||
'service_flap_detection_enabled',
|
||||
'service_flap_detection_enabled_changed',
|
||||
'service_modified_service_attributes',
|
||||
'service_handled',
|
||||
'service_hard_state',
|
||||
'service_host_name',
|
||||
'service_acknowledgement_type',
|
||||
'service_in_downtime',
|
||||
'service_is_flapping',
|
||||
'service_is_reachable',
|
||||
'service_last_check',
|
||||
'service_last_hard_state',
|
||||
'service_last_hard_state_change',
|
||||
'service_last_notification',
|
||||
'service_last_state_change',
|
||||
'service_last_time_critical',
|
||||
'service_last_time_ok',
|
||||
'service_last_time_unknown',
|
||||
'service_last_time_warning',
|
||||
'service_long_output',
|
||||
'service_max_check_attempts',
|
||||
'service_modified_service_attributes',
|
||||
'service_next_check',
|
||||
'service_notes',
|
||||
'service_notes_url',
|
||||
'service_notifications_enabled',
|
||||
'service_notifications_enabled_changed',
|
||||
'service_obsessing',
|
||||
'service_obsessing_changed',
|
||||
'service_output',
|
||||
'service_passive_checks_enabled',
|
||||
'service_passive_checks_enabled_changed',
|
||||
'service_perfdata',
|
||||
'service_problem',
|
||||
'service_severity',
|
||||
'service_state',
|
||||
'service_state_type',
|
||||
'service_unhandled'
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -257,6 +257,7 @@ class StateBadges extends AbstractWidget
|
||||
$groupItem = new NavigationItem(
|
||||
uniqid(),
|
||||
array(
|
||||
'cssClass' => 'state-badge-group',
|
||||
'label' => '',
|
||||
'priority' => $this->priority++
|
||||
)
|
||||
|
@ -45,16 +45,27 @@
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multi-selection info
|
||||
.selection-info {
|
||||
float: right;
|
||||
font-size: @font-size-small;
|
||||
padding: @vertical-padding / 2 0;
|
||||
.state-badge-group li {
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: help;
|
||||
.state-badge-group li:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.state-badge-group .badge {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.state-badge-group li:first-child > .badge {
|
||||
border-top-left-radius: 0.4em;
|
||||
border-bottom-left-radius: 0.4em;
|
||||
}
|
||||
|
||||
.state-badge-group li:last-child > .badge {
|
||||
border-top-right-radius: 0.4em;
|
||||
border-bottom-right-radius: 0.4em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,6 +90,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.controls > .hosts-summary,
|
||||
.controls > .services-summary {
|
||||
float: left;
|
||||
}
|
||||
|
||||
// State table in the host and service multi-selection and detail views
|
||||
.host-detail-state,
|
||||
.service-detail-state {
|
||||
@ -94,10 +110,6 @@
|
||||
|
||||
/* Generic box element */
|
||||
|
||||
.boxview a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.boxview > div.box {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
@ -126,7 +138,6 @@
|
||||
/* Any line of a box entry */
|
||||
.boxview div.box.entry a {
|
||||
display: block;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.boxview div.box.badge {
|
||||
@ -370,13 +381,7 @@ div.timeline {
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,13 +78,32 @@
|
||||
font-size: @font-size-small;
|
||||
}
|
||||
|
||||
// Plugin output in overviews
|
||||
// Plugin output in detail views
|
||||
.plugin-output,
|
||||
// Plugin output in overvies
|
||||
.overview-plugin-output {
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
hyphens: auto;
|
||||
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
// Plugin output in overvies
|
||||
.overview-plugin-output {
|
||||
color: @text-color-light;
|
||||
font-family: @font-family-fixed;
|
||||
font-size: @font-size-small;
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
// Long text in table cells overflows the table's width if the table's layout is not fixed.
|
||||
// Thus overflow-wrap will not have any effect. But w/ the following we set a width of any value
|
||||
// plus a min-width of 100% to consume the full width nonetheless which seems to always
|
||||
// instruct browsers to not overflow the table. Ridiculous.
|
||||
min-width: 100%;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
// Table for performance data in detail views
|
||||
|
@ -284,6 +284,7 @@ class GettextTranslationHelper
|
||||
'--keyword=translatePlural:1,2',
|
||||
'--keyword=translatePlural:1,2,4c',
|
||||
'--keyword=mt:2',
|
||||
'--keyword=mt:2,3c',
|
||||
'--keyword=mtp:2,3',
|
||||
'--keyword=mtp:2,3,5c',
|
||||
'--keyword=t',
|
||||
|
@ -44,7 +44,7 @@
|
||||
@tr-hover-color: #F5FDFF;
|
||||
|
||||
// Font families
|
||||
@font-family: Calibri, Helvetica, sans-serif;
|
||||
@font-family: Calibri, "Lucida Grande", sans-serif;
|
||||
@font-family-fixed: "Liberation Mono", "Lucida Console", Courier, monospace;
|
||||
@font-family-wide: Tahoma, Verdana, sans-serif;
|
||||
|
||||
@ -80,15 +80,19 @@ a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
||||
&:focus {
|
||||
outline-color: @icinga-blue;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
a:focus,
|
||||
button:focus,
|
||||
input[type="checkbox"]:focus {
|
||||
outline-color: @icinga-blue;
|
||||
outline-style: solid; // IE
|
||||
outline-style: auto;
|
||||
}
|
||||
|
||||
// Default margin for block text
|
||||
blockquote, p, pre {
|
||||
margin: 0 0 1em 0;
|
||||
|
@ -1,7 +1,49 @@
|
||||
/*! Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
// TODO(el): Rename .filter to .filter-control
|
||||
|
||||
// Hide auto sumbit info in controls but keep information for screen readers
|
||||
.controls .autosubmit-info {
|
||||
.sr-only();
|
||||
}
|
||||
|
||||
|
||||
// Backend selection control in user and group list views
|
||||
.backend-selection {
|
||||
float: left;
|
||||
|
||||
> .control-group {
|
||||
padding: 0;
|
||||
|
||||
> .control-label-group {
|
||||
text-align: left;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.backend-selection,
|
||||
.pagination-control,
|
||||
.selection-info,
|
||||
.sort-controls-container {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.backend-selection,
|
||||
.pagination-control,
|
||||
.sort-controls-container {
|
||||
// Select controls may not respect font-size thus leading to improperly vertical alignment w/o big enough line-height
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.filter {
|
||||
// Display filter control on a new line
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.limiter-control > .control-group {
|
||||
padding: 0;
|
||||
// Note that the sort-control form does not have padding as it's utilizing different decorators
|
||||
|
||||
> .control-label-group {
|
||||
text-align: left;
|
||||
@ -18,7 +60,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.limiter-control,
|
||||
.sort-control {
|
||||
// Display limiter and sort control both on the same line; floating could be used here too to achieve the same
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.pagination-control {
|
||||
// Display the pagination-control on a new line
|
||||
clear: both;
|
||||
float: left;
|
||||
|
||||
li {
|
||||
&.active {
|
||||
> a,
|
||||
@ -57,7 +109,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Multi-selection info
|
||||
.selection-info {
|
||||
float: right;
|
||||
font-size: @font-size-small;
|
||||
|
||||
&:hover {
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-control {
|
||||
margin-left: 0.25em;
|
||||
|
||||
label {
|
||||
width: auto;
|
||||
margin-right: 0.5em;
|
||||
@ -72,10 +136,16 @@
|
||||
width: 8em;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> form > i {
|
||||
.sr-only();
|
||||
}
|
||||
.sort-controls-container {
|
||||
clear: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.sort-direction-control {
|
||||
margin-left: 0.25em;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
html.no-js .sort-control form {
|
||||
|
@ -83,6 +83,10 @@ form.inline {
|
||||
margin-left: 10em;
|
||||
}
|
||||
|
||||
.autosubmit-info {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
button:hover .icon-cancel {
|
||||
color: @color-critical;
|
||||
}
|
||||
|
@ -76,7 +76,6 @@
|
||||
@gutter: 1em;
|
||||
|
||||
// x-column-layout
|
||||
|
||||
#main {
|
||||
.clearfix();
|
||||
|
||||
@ -109,6 +108,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile menu
|
||||
#mobile-menu-toggle {
|
||||
text-align: right;
|
||||
|
||||
> button {
|
||||
background: none;
|
||||
border: none;
|
||||
height: 2.5em;
|
||||
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
background-color: @gray-lighter;
|
||||
}
|
||||
|
@ -3,8 +3,6 @@
|
||||
// Login page styles
|
||||
|
||||
#login {
|
||||
font-size: 1em;
|
||||
|
||||
#icinga-logo {
|
||||
.fadein();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
}
|
||||
|
||||
.icon-col {
|
||||
text-align: center;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
@ -68,6 +69,16 @@ a:hover > .icon-cancel {
|
||||
|
||||
.button-link {
|
||||
.action-link();
|
||||
.rounded-corners(3px);
|
||||
|
||||
background: @gray-lighter;
|
||||
display: inline-block;
|
||||
padding: 0.25em 0.5em;
|
||||
|
||||
&:hover {
|
||||
background: @gray-lightest;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
// List styles
|
||||
@ -177,41 +188,6 @@ a:hover > .icon-cancel {
|
||||
width: @name-value-table-name-width;
|
||||
}
|
||||
|
||||
// TODO(el): Fix
|
||||
.controls {
|
||||
.limiter-control {
|
||||
float: right;
|
||||
padding: @vertical-padding / 2 0;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
.pagination-control {
|
||||
padding: @vertical-padding / 2 0;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
.sort-control {
|
||||
float: right;
|
||||
padding: @vertical-padding / 2 0;
|
||||
margin-bottom: 0.25em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.sort-direction-control {
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: 0.5em;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.filter {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.selection-info {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles for centering content of unknown width and height both horizontally and vertically
|
||||
*
|
||||
* Example markup:
|
||||
|
@ -56,9 +56,7 @@
|
||||
}
|
||||
|
||||
.rounded-corners(@border-radius: 0.4em) {
|
||||
-webkit-border-radius: @border-radius;
|
||||
-moz-border-radius: @border-radius;
|
||||
border-radius: @border-radius;
|
||||
border-radius: @border-radius;
|
||||
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
|
@ -29,10 +29,6 @@
|
||||
|
||||
> a {
|
||||
color: @body-bg-color;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&.active > a,
|
||||
|
@ -59,3 +59,8 @@
|
||||
#menu .active > a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.boxview a:focus {
|
||||
color: @text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -55,6 +55,20 @@
|
||||
* @returns {string|NULL} The content to be rendered, or NULL, when nothing should be changed
|
||||
*/
|
||||
Form.prototype.renderHook = function(content, $container, action, autorefresh) {
|
||||
if ($container.attr('id') === 'menu') {
|
||||
var $search = $container.find('#search');
|
||||
if ($search[0] === document.activeElement) {
|
||||
return null;
|
||||
}
|
||||
var search = $container.find('#search').val();
|
||||
if (search.length) {
|
||||
var $content = $('<div></div>').append(content);
|
||||
$content.find('#search').attr('value', search).addClass('active');
|
||||
return $content.html();
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
var origFocus = document.activeElement;
|
||||
var containerId = $container.attr('id');
|
||||
var icinga = this.icinga;
|
||||
|
@ -421,7 +421,7 @@
|
||||
var $target;
|
||||
var formerUrl;
|
||||
var remote = /^(?:[a-z]+:)\/\//;
|
||||
if (href.match(/^(mailto|javascript):/)) {
|
||||
if (href.match(/^(mailto|javascript|data):/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -100,9 +100,6 @@
|
||||
var $oldLink = $(this);
|
||||
if ($oldLink.hasAttr('type') && $oldLink.attr('type').indexOf('css') > -1) {
|
||||
var base = location.protocol + '//' + location.host;
|
||||
if (location.port) {
|
||||
base += location.port;
|
||||
}
|
||||
var url = icinga.utils.addUrlParams(
|
||||
$(this).attr('href'),
|
||||
{ id: new Date().getTime() }
|
||||
@ -587,7 +584,7 @@
|
||||
});
|
||||
|
||||
if ($layout.hasClass('minimal-layout')) {
|
||||
if (! this.mobileMenu) {
|
||||
if (! this.mobileMenu && $sidebar.length) {
|
||||
$header.css({
|
||||
top: $sidebar.outerHeight() + 'px'
|
||||
});
|
||||
@ -599,19 +596,18 @@
|
||||
zIndex: 2
|
||||
});
|
||||
$sidebar
|
||||
.on(
|
||||
'click',
|
||||
this.toggleMobileMenu
|
||||
)
|
||||
.prepend(
|
||||
$('<div id="mobile-menu-toggle"><button><i class="icon-menu"></i></button></div>')
|
||||
)
|
||||
.css({
|
||||
paddingBottom: 32,
|
||||
paddingBottom: $('#mobile-menu-toggle').height(),
|
||||
top: 0,
|
||||
zIndex: 3
|
||||
})
|
||||
.on('click', this.toggleMobileMenu)
|
||||
.prepend(
|
||||
$('<i id="mobile-menu-toggle" class="icon-menu"></i>').css({
|
||||
cursor: 'pointer',
|
||||
display: 'block',
|
||||
height: '32px'
|
||||
})
|
||||
);
|
||||
});
|
||||
$search.on('keypress', this.closeMobileMenu);
|
||||
|
||||
this.mobileMenu = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user