Merge branch 'master' into bugfix/hot-all-hostgroups-are-shown-10316

This commit is contained in:
Johannes Meyer 2015-11-13 15:37:53 +01:00
commit d321b2de79
120 changed files with 2233 additions and 2269 deletions

View File

@ -119,12 +119,6 @@ class ConfigController extends Controller
->order('name'); ->order('name');
$this->setupLimitControl(); $this->setupLimitControl();
$this->setupPaginationControl($this->view->modules); $this->setupPaginationControl($this->view->modules);
// TODO: Not working
/*$this->setupSortControl(array(
'name' => $this->translate('Modulename'),
'path' => $this->translate('Installation Path'),
'enabled' => $this->translate('State')
));*/
} }
public function moduleAction() public function moduleAction()

View File

@ -253,14 +253,6 @@ class DashboardController extends ActionController
$this->dashboard->getConfig()->saveIni(); $this->dashboard->getConfig()->saveIni();
$this->redirectNow(URL::fromRequest()->remove('remove')); $this->redirectNow(URL::fromRequest()->remove('remove'));
} }
$this->view->tabs->add(
'Add',
array(
'label' => '+',
'title' => 'Add a dashlet to an existing or new dashboard',
'url' => Url::fromPath('dashboard/new-dashlet')
)
);
$this->view->dashboard = $this->dashboard; $this->view->dashboard = $this->dashboard;
} }
} }

View File

@ -324,7 +324,6 @@ class GroupController extends AuthBackendController
array( array(
'title' => sprintf($this->translate('Show group %s'), $groupName), 'title' => sprintf($this->translate('Show group %s'), $groupName),
'label' => $this->translate('Group'), 'label' => $this->translate('Group'),
'icon' => 'users',
'url' => Url::fromPath('group/show', array('backend' => $backendName, 'group' => $groupName)) 'url' => Url::fromPath('group/show', array('backend' => $backendName, 'group' => $groupName))
) )
); );
@ -355,7 +354,6 @@ class GroupController extends AuthBackendController
array( array(
'title' => $this->translate('List users of authentication backends'), 'title' => $this->translate('List users of authentication backends'),
'label' => $this->translate('Users'), 'label' => $this->translate('Users'),
'icon' => 'user',
'url' => 'user/list' 'url' => 'user/list'
) )
); );
@ -364,7 +362,6 @@ class GroupController extends AuthBackendController
array( array(
'title' => $this->translate('List groups of user group backends'), 'title' => $this->translate('List groups of user group backends'),
'label' => $this->translate('User Groups'), 'label' => $this->translate('User Groups'),
'icon' => 'users',
'url' => 'group/list' 'url' => 'group/list'
) )
); );

View File

@ -163,7 +163,6 @@ class RoleController extends AuthBackendController
array( array(
'title' => $this->translate('List users of authentication backends'), 'title' => $this->translate('List users of authentication backends'),
'label' => $this->translate('Users'), 'label' => $this->translate('Users'),
'icon' => 'user',
'url' => 'user/list' 'url' => 'user/list'
) )
); );
@ -172,7 +171,6 @@ class RoleController extends AuthBackendController
array( array(
'title' => $this->translate('List groups of user group backends'), 'title' => $this->translate('List groups of user group backends'),
'label' => $this->translate('User Groups'), 'label' => $this->translate('User Groups'),
'icon' => 'users',
'url' => 'group/list' 'url' => 'group/list'
) )
); );

View File

@ -290,7 +290,6 @@ class UserController extends AuthBackendController
array( array(
'title' => sprintf($this->translate('Show user %s'), $userName), 'title' => sprintf($this->translate('Show user %s'), $userName),
'label' => $this->translate('User'), 'label' => $this->translate('User'),
'icon' => 'user',
'url' => Url::fromPath('user/show', array('backend' => $backendName, 'user' => $userName)) 'url' => Url::fromPath('user/show', array('backend' => $backendName, 'user' => $userName))
) )
); );
@ -321,7 +320,6 @@ class UserController extends AuthBackendController
array( array(
'title' => $this->translate('List users of authentication backends'), 'title' => $this->translate('List users of authentication backends'),
'label' => $this->translate('Users'), 'label' => $this->translate('Users'),
'icon' => 'user',
'url' => 'user/list' 'url' => 'user/list'
) )
); );
@ -330,7 +328,6 @@ class UserController extends AuthBackendController
array( array(
'title' => $this->translate('List groups of user group backends'), 'title' => $this->translate('List groups of user group backends'),
'label' => $this->translate('User Groups'), 'label' => $this->translate('User Groups'),
'icon' => 'users',
'url' => 'group/list' 'url' => 'group/list'
) )
); );

View File

@ -0,0 +1,113 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Forms\Control;
use Icinga\Web\Form;
/**
* Limiter control form
*/
class LimiterControlForm extends Form
{
/**
* CSS class for the limiter control
*
* @var string
*/
const CSS_CLASS_LIMITER = 'limiter-control';
/**
* Default limit
*
* @var int
*/
const DEFAULT_LIMIT = 50;
/**
* Selectable limits
*
* @var int[]
*/
public static $limits = array(
10 => '10',
25 => '25',
50 => '50',
100 => '100',
500 => '500'
);
/**
* Default limit for this instance
*
* @var int|null
*/
protected $defaultLimit;
/**
* {@inheritdoc}
*/
public function init()
{
$this->setAttrib('class', static::CSS_CLASS_LIMITER);
}
/**
* Get the default limit
*
* @return int
*/
public function getDefaultLimit()
{
return $this->defaultLimit !== null ? $this->defaultLimit : static::DEFAULT_LIMIT;
}
/**
* Set the default limit
*
* @param int $defaultLimit
*
* @return $this
*/
public function setDefaultLimit($defaultLimit)
{
$this->defaultLimit = (int) $defaultLimit;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRedirectUrl()
{
return $this->getRequest()->getUrl()->setParam('limit', $this->getElement('limit')->getValue());
}
/**
* {@inheritdoc}
*/
public function createElements(array $formData)
{
$this->addElement(
'select',
'limit',
array(
'autosubmit' => true,
'escape' => false,
'label' => '#',
'multiOptions' => static::$limits,
'value' => $this->getRequest()->getUrl()->getParam('limit', $this->getDefaultLimit())
)
);
}
/**
* Limiter control is always successful
*
* @return bool
*/
public function onSuccess()
{
return true;
}
}

View File

@ -96,7 +96,7 @@ class DashletForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => $this->translate("New Dashboard Title"), 'label' => $this->translate("New Dashboard Title"),
'description' => $this->translate('Enter a title for the new pane.') 'description' => $this->translate('Enter a title for the new dashboard')
) )
); );
} else { } else {
@ -107,7 +107,7 @@ class DashletForm extends Form
'required' => true, 'required' => true,
'label' => $this->translate('Dashboard'), 'label' => $this->translate('Dashboard'),
'multiOptions' => $panes, 'multiOptions' => $panes,
'description' => $this->translate('Select a pane you want to add the dashlet.') 'description' => $this->translate('Select a dashboard you want to add the dashlet to')
) )
); );
} }

View File

@ -41,7 +41,6 @@ class PreferenceForm extends Form
public function init() public function init()
{ {
$this->setName('form_config_preferences'); $this->setName('form_config_preferences');
$this->setTitle($this->translate('Preferences'));
} }
/** /**

View File

@ -1,7 +1,7 @@
<div class="controls"> <div class="controls">
<?= $tabs ?> <?= $tabs ?>
</div> </div>
<div class="content content-centered"> <div id="about" class="content content-centered">
<?= $this->img( <?= $this->img(
'img/logo_icinga_big_dark.png', 'img/logo_icinga_big_dark.png',
null, null,
@ -35,7 +35,7 @@
) ?> ) ?>
</dd> </dd>
</dl> </dl>
<div> <div class="about-social">
<?= $this->qlink( <?= $this->qlink(
null, null,
'https://www.twitter.com/icinga', 'https://www.twitter.com/icinga',
@ -54,16 +54,25 @@
'icon' => 'facebook-squared', 'icon' => 'facebook-squared',
'title' => $this->translate('Icinga on Facebook') 'title' => $this->translate('Icinga on Facebook')
) )
) ?> <?= $this->qlink(
null,
'https://plus.google.com/+icinga',
null,
array(
'target' => '_blank',
'icon' => 'google-plus-squared',
'title' => $this->translate('Icinga on Google+')
)
) ?> ) ?>
</div> </div>
<div> <div class="about-links">
<?= $this->qlink( <?= $this->qlink(
null, null,
'https://dev.icinga.org/projects/icingaweb2', 'https://dev.icinga.org/projects/icingaweb2',
null, null,
array( array(
'target' => '_blank', 'target' => '_blank',
'img' => 'img/bugreport.png', 'icon' => 'bug',
'title' => $this->translate('Report a bug') 'title' => $this->translate('Report a bug')
) )
) ?> ) ?>
@ -73,19 +82,17 @@
null, null,
array( array(
'target' => '_blank', 'target' => '_blank',
'img' => 'img/support.png', 'icon' => 'chat',
'title' => $this->translate('Support / Mailinglists') 'title' => $this->translate('Support / Mailinglists')
) )
) ?> ) ?>
</div>
<div>
<?= $this->qlink( <?= $this->qlink(
null, null,
'https://wiki.icinga.org', 'https://wiki.icinga.org',
null, null,
array( array(
'target' => '_blank', 'target' => '_blank',
'img' => 'img/wiki.png', 'icon' => 'lightbulb',
'title' => $this->translate('Icinga Wiki') 'title' => $this->translate('Icinga Wiki')
) )
) ?> ) ?>
@ -95,13 +102,13 @@
null, null,
array( array(
'target' => '_blank', 'target' => '_blank',
'img' => 'img/docs.png', 'icon' => 'doc-text',
'title' => $this->translate('Icinga Documentation') 'title' => $this->translate('Icinga Documentation')
) )
) ?> ) ?>
</div> </div>
<h2><?= $this->translate('Loaded modules') ?></h2> <h2><?= $this->translate('Loaded modules') ?></h2>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Name') ?></th> <th><?= $this->translate('Name') ?></th>

View File

@ -1,48 +1,40 @@
<?php if (! $this->compact): ?> <?php if (! $this->compact): ?>
<div class="controls"> <div class="controls">
<?= $this->tabs; ?> <?= $this->tabs ?>
<div class="grid dont-print"> <?= $this->paginator ?>
<div class="col-1-3 text-left">
<?= $this->limiter ?>
</div>
<div class="col-1-3">
<?= $this->paginator ?>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Module') ?></th> <th><?= $this->translate('Module') ?></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach ($modules as $module): ?> <?php foreach ($modules as $module): ?>
<tr> <tr>
<td> <td>
<?php if ($module->enabled && $module->loaded) { <?php if ($module->enabled && $module->loaded) {
echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name)); echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name));
} elseif (! $module->enabled) { } elseif (! $module->enabled) {
echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name)); echo $this->icon('block', sprintf($this->translate('Module %s is disabled'), $module->name));
} else { // ! $module->loaded } else { // ! $module->loaded
echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name)); echo $this->icon('block', sprintf($this->translate('Module %s has failed to load'), $module->name));
} }
echo $this->qlink( echo $this->qlink(
$module->name, $module->name,
'config/module/', 'config/module/',
array('name' => $module->name), array('name' => $module->name),
array('title' => sprintf($this->translate('Show the overview of the %s module'), $module->name), 'class' => 'rowaction') array(
); ?> 'class' => 'rowaction',
</td> 'title' => sprintf($this->translate('Show the overview of the %s module'), $module->name)
</tr> )
); ?>
</td>
</tr>
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -13,7 +13,7 @@
'title' => $this->translate('Create a new resource') 'title' => $this->translate('Create a new resource')
) )
) ?> ) ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Resource') ?></th> <th><?= $this->translate('Resource') ?></th>

View File

@ -1,5 +1,5 @@
<form id="<?= $form->getId() ?>" name="<?= $form->getName() ?>" enctype="<?= $form->getEncType() ?>" method="<?= $form->getMethod() ?>" action="<?= $form->getAction() ?>"> <form id="<?= $form->getId() ?>" name="<?= $form->getName() ?>" enctype="<?= $form->getEncType() ?>" method="<?= $form->getMethod() ?>" action="<?= $form->getAction() ?>">
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<th><?= $this->translate('Backend') ?></th> <th><?= $this->translate('Backend') ?></th>
<th></th> <th></th>

View File

@ -47,7 +47,7 @@ if (! isset($backend)) {
</div> </div>
<?php endif ?> <?php endif ?>
<table data-base-target="_next" class="action-table listing-table"> <table data-base-target="_next" class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('User Group'); ?></th> <th><?= $this->translate('User Group'); ?></th>
@ -95,4 +95,4 @@ if (! isset($backend)) {
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -69,7 +69,7 @@ if ($this->hasPermission('config/authentication/groups/edit') && $backend instan
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table data-base-target="_next" class="action-table listing-table"> <table data-base-target="_next" class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Username'); ?></th> <th><?= $this->translate('Username'); ?></th>
@ -105,4 +105,4 @@ if ($this->hasPermission('config/authentication/groups/edit') && $backend instan
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -1,37 +1,29 @@
<?php if (! $this->compact): ?> <?php if (! $this->compact): ?>
<div class="controls"> <div class="controls separated">
<?= $this->tabs; ?> <?= $this->tabs ?>
<div class="grid dont-print"> <div class="grid">
<div class="col-1-3 text-left"> <?= $this->limiter ?>
<?= $this->limiter ?> <?= $this->paginator ?>
</div>
<div class="col-1-3">
<?= $this->paginator ?>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div> </div>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?php if ($this->logData !== null): ?> <?php if ($this->logData !== null): ?>
<table class="action"> <table class="action">
<tbody> <tbody>
<?php foreach ($this->logData as $value): ?> <?php foreach ($this->logData as $value): ?>
<?php $datetime = new Datetime($value->datetime); ?> <?php $datetime = new Datetime($value->datetime) ?>
<tr class="state"> <tr class="state">
<td style="width: 6em; text-align: center"> <td style="width: 6em; text-align: center">
<?= $this->escape($datetime->format('d.m. H:i')) ?><br /> <?= $this->escape($datetime->format('d.m. H:i')) ?><br />
<?= $this->escape($value->loglevel) ?> <?= $this->escape($value->loglevel) ?>
</td> </td>
<td> <td>
<?= nl2br($this->escape($value->message), false) ?> <?= nl2br($this->escape($value->message), false) ?>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
<?php endif; ?> <?php endif ?>
</div> </div>

View File

@ -1,16 +1,8 @@
<?php if (! $this->compact): ?> <?php if (! $this->compact): ?>
<div class="controls"> <div class="controls separated">
<?= $this->tabs ?> <?= $this->tabs ?>
<div class="grid dont-print"> <div class="grid">
<div class="col-1-3 text-left"> <?= $this->sortBox ?>
<?= $this->limiter ?>
</div>
<div class="col-1-3">
<?= $this->paginator ?>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div> </div>
<?= $this->filterEditor ?> <?= $this->filterEditor ?>
</div> </div>
@ -31,7 +23,7 @@
<p><?= $this->translate('You did not create any navigation item yet.') ?></p> <p><?= $this->translate('You did not create any navigation item yet.') ?></p>
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Navigation') ?></th> <th><?= $this->translate('Navigation') ?></th>

View File

@ -3,27 +3,18 @@
use Icinga\Web\Url; use Icinga\Web\Url;
if (! $this->compact): ?> if (! $this->compact): ?>
<div class="controls"> <div class="controls separated">
<?= $this->tabs; ?> <?= $this->tabs; ?>
<div class="grid dont-print"> <div class="grid">
<div class="col-1-3 text-left"> <?= $this->sortBox ?>
<?= $this->limiter ?>
</div>
<div class="col-1-3">
<?= $this->paginator ?>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div> </div>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<?php if (count($items) === 0): ?> <?php if (count($items) === 0): ?>
<p><?= $this->translate('There are currently no navigation items being shared'); ?></p> <p><?= $this->translate('There are currently no navigation items being shared'); ?></p>
<?php else: ?> <?php else: ?>
<table class="action alternating"> <table class="table-row-selectable common-table">
<thead> <thead>
<th><?= $this->translate('Shared Navigation'); ?></th> <th><?= $this->translate('Shared Navigation'); ?></th>
<th style="width: 10em"><?= $this->translate('Type'); ?></th> <th style="width: 10em"><?= $this->translate('Type'); ?></th>
@ -74,4 +65,4 @@ if (! $this->compact): ?>
</tbody> </tbody>
</table> </table>
<?php endif ?> <?php endif ?>
</div> </div>

View File

@ -16,7 +16,7 @@
<?php /** @var \Icinga\Application\Config $roles */ if ($roles->isEmpty()): ?> <?php /** @var \Icinga\Application\Config $roles */ if ($roles->isEmpty()): ?>
<p><?= $this->translate('No roles found.') ?></p> <p><?= $this->translate('No roles found.') ?></p>
<?php return; endif ?> <?php return; endif ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Name') ?></th> <th><?= $this->translate('Name') ?></th>

View File

@ -47,7 +47,7 @@ if (! isset($backend)) {
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table data-base-target="_next" class="action-table listing-table"> <table data-base-target="_next" class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Username') ?></th> <th><?= $this->translate('Username') ?></th>
@ -89,4 +89,4 @@ if (! isset($backend)) {
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -72,7 +72,7 @@ if ($this->hasPermission('config/authentication/users/edit') && $backend instanc
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table data-base-target="_next" class="action-table listing-table"> <table data-base-target="_next" class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Group'); ?></th> <th><?= $this->translate('Group'); ?></th>
@ -108,4 +108,4 @@ if ($this->hasPermission('config/authentication/users/edit') && $backend instanc
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -14,7 +14,7 @@
) )
) ?> ) ?>
<?php if (! count($backendNames)) { return; } ?> <?php if (! count($backendNames)) { return; } ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Backend') ?></th> <th><?= $this->translate('Backend') ?></th>

View File

@ -53,7 +53,7 @@ add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main'
apt-get update apt-get update
```` ````
For other Ubuntu versions just replace trusty with your distribution's code name. For other Ubuntu versions just replace trusty with your distribution\'s code name.
**RHEL and CentOS**: **RHEL and CentOS**:
```` ````
@ -171,10 +171,10 @@ Adopt the package requirements to your needs (e.g. adding ldap for authenticatio
Example for RHEL/CentOS/Fedora: Example for RHEL/CentOS/Fedora:
```` ```
# yum install httpd mysql-server yum install httpd mysql-server
# yum install php php-gd php-intl php-ZendFramework php-ZendFramework-Db-Adapter-Pdo-Mysql yum install php php-gd php-intl php-ZendFramework php-ZendFramework-Db-Adapter-Pdo-Mysql
```` ```
The setup wizard will check the pre-requisites later on. The setup wizard will check the pre-requisites later on.
@ -311,13 +311,13 @@ Puppet, Ansible, Chef, etc. modules.
Create the database and add a new user as shown below for MySQL: Create the database and add a new user as shown below for MySQL:
```` ````
# sudo mysql -p sudo mysql -p
CREATE DATABASE icingaweb2; CREATE DATABASE icingaweb2;
GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icingaweb2.* TO 'icingaweb2'@'localhost' IDENTIFIED BY 'icingaweb2'; GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icingaweb2.* TO 'icingaweb2'@'localhost' IDENTIFIED BY 'icingaweb2';
quit quit
# mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql
```` ````
@ -325,7 +325,7 @@ Then generate a new password hash as described in the [authentication docs](auth
and use it to insert a new user called `icingaadmin` into the database. and use it to insert a new user called `icingaadmin` into the database.
```` ````
# mysql -p icingaweb2 mysql -p icingaweb2
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$1$EzxLOFDr$giVx3bGhVm4lDUAw6srGX1'); INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$1$EzxLOFDr$giVx3bGhVm4lDUAw6srGX1');
quit quit

View File

@ -348,29 +348,24 @@ abstract class ApplicationBootstrap
require $this->libDir . '/Icinga/Application/ClassLoader.php'; require $this->libDir . '/Icinga/Application/ClassLoader.php';
$this->loader = new ClassLoader(); $this->loader = new ClassLoader();
$this->loader->registerNamespace('Icinga', $this->libDir. '/Icinga'); $this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga');
$this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga', $this->appDir);
$this->loader->register(); $this->loader->register();
return $this; return $this;
} }
/** /**
* Register the Zend Autoloader * Register the Zend Autoloader - compat only - does nothing
* *
* @deprecated
* @return $this * @return $this
*/ */
public function setupZendAutoloader() public function setupZendAutoloader()
{ {
require_once 'Zend/Loader/Autoloader.php';
\Zend_Loader_Autoloader::getInstance();
\Zend_Paginator::addScrollingStylePrefixPath(
'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle'
);
return $this; return $this;
} }
/** /**
* Setup module manager * Setup module manager
* *

View File

@ -3,6 +3,8 @@
namespace Icinga\Application; namespace Icinga\Application;
use Zend_Loader_Autoloader;
/** /**
* PSR-4 class loader * PSR-4 class loader
*/ */
@ -13,6 +15,40 @@ class ClassLoader
*/ */
const NAMESPACE_SEPARATOR = '\\'; const NAMESPACE_SEPARATOR = '\\';
/**
* Icinga Web 2 module namespace prefix
*/
const MODULE_PREFIX = 'Icinga\\Module\\';
/**
* Icinga Web 2 module namespace prefix length
*
* Helps to make substr/strpos operations even faster
*/
const MODULE_PREFIX_LENGTH = 14;
/**
* A hardcoded class/subdir map for application ns prefixes
*
* When a module registers with an application directory, those
* namespace prefixes (after the module prefix) will be looked up
* in the corresponding application subdirectories
*
* @var array
*/
protected $applicationPrefixes = array(
'Clicommands' => 'clicommands',
'Controllers' => 'controllers',
'Forms' => 'forms'
);
/**
* Whether we already instantiated the ZF autoloader
*
* @var boolean
*/
protected $gotZend = false;
/** /**
* Namespaces * Namespaces
* *
@ -20,18 +56,33 @@ class ClassLoader
*/ */
private $namespaces = array(); private $namespaces = array();
/**
* Application directories
*
* @var array
*/
private $applicationDirectories = array();
/** /**
* Register a base directory for a namespace prefix * Register a base directory for a namespace prefix
* *
* Application directory is optional and provides additional lookup
* logic for hardcoded namespaces like "Forms"
*
* @param string $namespace * @param string $namespace
* @param string $directory * @param string $directory
* @param string $appDirectory
* *
* @return $this * @return $this
*/ */
public function registerNamespace($namespace, $directory) public function registerNamespace($namespace, $directory, $appDirectory = null)
{ {
$this->namespaces[$namespace] = $directory; $this->namespaces[$namespace] = $directory;
if ($appDirectory !== null) {
$this->applicationDirectories[$namespace] = $appDirectory;
}
return $this; return $this;
} }
@ -56,21 +107,177 @@ class ClassLoader
*/ */
public function getSourceFile($class) public function getSourceFile($class)
{ {
if ($file = $this->getModuleSourceFile($class)) {
return $file;
}
foreach ($this->namespaces as $namespace => $dir) { foreach ($this->namespaces as $namespace => $dir) {
if ($class === strstr($class, $namespace)) { if ($class === strstr($class, $namespace)) {
$classPath = str_replace( return $this->buildClassFilename($class, $namespace);
self::NAMESPACE_SEPARATOR,
DIRECTORY_SEPARATOR,
substr($class, strlen($namespace))
) . '.php';
if (file_exists($file = $dir . $classPath)) {
return $file;
}
} }
} }
return null; return null;
} }
/**
* Get the source file of the given module class or interface
*
* @param string $class Module class or interface name
*
* @return string|null
*/
protected function getModuleSourceFile($class)
{
if (! $this->classBelongsToModule($class)) {
return null;
}
$modules = Icinga::app()->getModuleManager();
$namespace = $this->extractModuleNamespace($class);
if ($this->hasNamespace($namespace)) {
return $this->buildClassFilename($class, $namespace);
} elseif (! $modules->loadedAllEnabledModules()) {
$moduleName = $this->extractModuleName($class);
if ($modules->hasEnabled($moduleName)) {
$modules->loadModule($moduleName);
return $this->buildClassFilename($class, $namespace);
}
}
return null;
}
/**
* Extract the Icinga module namespace from a given namespaced class name
*
* Does no validation, prefix must have been checked before
*
* @return string
*/
protected function extractModuleNamespace($class)
{
return substr(
$class,
0,
strpos($class, self::NAMESPACE_SEPARATOR, self::MODULE_PREFIX_LENGTH + 1)
);
}
/**
* Extract the Icinga module name from a given namespaced class name
*
* Does no validation, prefix must have been checked before
*
* @return string
*/
protected function extractModuleName($class)
{
return lcfirst(
substr(
$class,
self::MODULE_PREFIX_LENGTH,
strpos(
$class,
self::NAMESPACE_SEPARATOR,
self::MODULE_PREFIX_LENGTH + 1
) - self::MODULE_PREFIX_LENGTH
)
);
}
/**
* Whether the given class name belongs to a module namespace
*
* @return boolean
*/
protected function classBelongsToModule($class)
{
return substr($class, 0, self::MODULE_PREFIX_LENGTH) === self::MODULE_PREFIX;
}
/**
* Prepare a filename string for the given class
*
* Expects the given namespace to be registered with a path name
*
* @return string
*/
protected function buildClassFilename($class, $namespace)
{
$relNs = substr($class, strlen($namespace) + 1);
if ($this->namespaceHasApplictionDirectory($namespace)) {
$prefixSeparator = strpos($relNs, self::NAMESPACE_SEPARATOR);
$prefix = substr($relNs, 0, $prefixSeparator);
if ($this->isApplicationPrefix($prefix)) {
return $this->applicationDirectories[$namespace]
. DIRECTORY_SEPARATOR
. $this->applicationPrefixes[$prefix]
. $this->classToRelativePhpFilename(substr($relNs, $prefixSeparator));
}
}
return $this->namespaces[$namespace] . DIRECTORY_SEPARATOR . $this->classToRelativePhpFilename($relNs);
}
/**
* Return the relative file name for the given (namespaces) class
*
* @param string $class
*
* @return string
*/
protected function classToRelativePhpFilename($class)
{
return str_replace(
self::NAMESPACE_SEPARATOR,
DIRECTORY_SEPARATOR,
$class
) . '.php';
}
/**
* Whether given prefix (Forms, Controllers...) makes part of "application"
*
* @param string $prefix
*
* @return boolean
*/
protected function isApplicationPrefix($prefix)
{
return array_key_exists($prefix, $this->applicationPrefixes);
}
/**
* Whether the given namespace registered an application directory
*
* @return boolean
*/
protected function namespaceHasApplictionDirectory($namespace)
{
return array_key_exists($namespace, $this->applicationDirectories);
}
/**
* Require ZF autoloader
*
* @return Zend_Loader_Autoloader
*/
protected function requireZendAutoloader()
{
require_once 'Zend/Loader/Autoloader.php';
$this->gotZend = true;
return Zend_Loader_Autoloader::getInstance();
}
/** /**
* Load the given class or interface * Load the given class or interface
* *
@ -80,10 +287,22 @@ class ClassLoader
*/ */
public function loadClass($class) public function loadClass($class)
{ {
if ($file = $this->getSourceFile($class)) { // We are aware of the Zend_ prefix and lazyload it's autoloader.
require $file; // Return as fast as possible if we already did so.
return true; if (substr($class, 0, 5) === 'Zend_') {
if (! $this->gotZend) {
$this->requireZendAutoloader();
}
return false;
} }
if ($file = $this->getSourceFile($class)) {
if (file_exists($file)) {
require $file;
return true;
}
}
return false; return false;
} }

View File

@ -73,6 +73,13 @@ class Manager
*/ */
private $modulePaths = array(); private $modulePaths = array();
/**
* Whether we loaded all enabled modules
*
* @var bool
*/
private $loadedAllEnabledModules = false;
/** /**
* Create a new instance of the module manager * Create a new instance of the module manager
* *
@ -177,12 +184,28 @@ class Manager
*/ */
public function loadEnabledModules() public function loadEnabledModules()
{ {
foreach ($this->listEnabledModules() as $name) { if (! $this->loadedAllEnabledModules) {
$this->loadModule($name); foreach ($this->listEnabledModules() as $name) {
$this->loadModule($name);
}
$this->loadedAllEnabledModules = true;
} }
return $this; return $this;
} }
/**
* Whether we loaded all enabled modules
*
* @return bool
*/
public function loadedAllEnabledModules()
{
return $this->loadedAllEnabledModules;
}
/** /**
* Try to load the module and register it in the application * Try to load the module and register it in the application
* *
@ -245,6 +268,8 @@ class Manager
); );
} }
$this->loadedAllEnabledModules = false;
if (file_exists($link) && is_link($link)) { if (file_exists($link) && is_link($link)) {
return $this; return $this;
} }

View File

@ -51,6 +51,13 @@ class Module
*/ */
private $cssdir; private $cssdir;
/**
* Base application directory
*
* @var string
*/
private $appdir;
/** /**
* Library directory * Library directory
* *
@ -244,6 +251,7 @@ class Module
$this->jsdir = $basedir . '/public/js'; $this->jsdir = $basedir . '/public/js';
$this->libdir = $basedir . '/library'; $this->libdir = $basedir . '/library';
$this->configdir = $app->getConfigDir('modules/' . $name); $this->configdir = $app->getConfigDir('modules/' . $name);
$this->appdir = $basedir . '/application';
$this->localedir = $basedir . '/application/locale'; $this->localedir = $basedir . '/application/locale';
$this->formdir = $basedir . '/application/forms'; $this->formdir = $basedir . '/application/forms';
$this->controllerdir = $basedir . '/application/controllers'; $this->controllerdir = $basedir . '/application/controllers';
@ -739,6 +747,16 @@ class Module
return $this->basedir; return $this->basedir;
} }
/**
* Get the module's application directory
*
* @return string
*/
public function getApplicationDir()
{
return $this->appdir;
}
/** /**
* Get the module's library directory * Get the module's library directory
* *
@ -1043,18 +1061,13 @@ class Module
return $this; return $this;
} }
$loader = $this->app->getLoader();
$moduleName = ucfirst($this->getName()); $moduleName = ucfirst($this->getName());
$moduleLibraryDir = $this->getLibDir(). '/'. $moduleName; $this->app->getLoader()->registerNamespace(
if (is_dir($moduleLibraryDir)) { 'Icinga\\Module\\' . $moduleName,
$loader->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir); $this->getLibDir() . '/'. $moduleName,
} $this->getApplicationDir()
);
$moduleFormDir = $this->getFormDir();
if (is_dir($moduleFormDir)) {
$loader->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir);
}
$this->registeredAutoloader = true; $this->registeredAutoloader = true;
@ -1118,21 +1131,10 @@ class Module
if (! $this->app->isWeb()) { if (! $this->app->isWeb()) {
return $this; return $this;
} }
$moduleControllerDir = $this->getControllerDir();
if (is_dir($moduleControllerDir)) { return $this
$this->app->getfrontController()->addControllerDirectory(
$moduleControllerDir,
$this->getName()
);
$this->app->getLoader()->registerNamespace(
'Icinga\\Module\\' . ucfirst($this->getName()) . '\\' . Dispatcher::CONTROLLER_NAMESPACE,
$moduleControllerDir
);
}
$this
->registerLocales() ->registerLocales()
->registerRoutes(); ->registerRoutes();
return $this;
} }
/** /**
@ -1143,6 +1145,13 @@ class Module
protected function registerRoutes() protected function registerRoutes()
{ {
$router = $this->app->getFrontController()->getRouter(); $router = $this->app->getFrontController()->getRouter();
// TODO: We should not be required to do this. Please check dispatch()
$this->app->getfrontController()->addControllerDirectory(
$this->getControllerDir(),
$this->getName()
);
/** @var \Zend_Controller_Router_Rewrite $router */ /** @var \Zend_Controller_Router_Rewrite $router */
foreach ($this->routes as $name => $route) { foreach ($this->routes as $name => $route) {
$router->addRoute($name, $route); $router->addRoute($name, $route);

View File

@ -91,7 +91,6 @@ class Web extends EmbeddedWeb
->setupLogger() ->setupLogger()
->setupInternationalization() ->setupInternationalization()
->setupZendMvc() ->setupZendMvc()
->setupNamespaces()
->setupModuleManager() ->setupModuleManager()
->loadSetupModuleIfNecessary() ->loadSetupModuleIfNecessary()
->loadEnabledModules() ->loadEnabledModules()
@ -140,19 +139,37 @@ class Web extends EmbeddedWeb
return $this->viewRenderer; return $this->viewRenderer;
} }
private function hasAccessToSharedNavigationItem(& $config) private function hasAccessToSharedNavigationItem(& $config, Config $navConfig)
{ {
// TODO: Provide a more sophisticated solution // TODO: Provide a more sophisticated solution
if (isset($config['owner']) && $config['owner'] === $this->user->getUsername()) { if (isset($config['owner']) && $config['owner'] === $this->user->getUsername()) {
unset($config['owner']); unset($config['owner']);
unset($config['users']);
unset($config['groups']);
return true; return true;
} }
if (isset($config['parent']) && $navConfig->hasSection($config['parent'])) {
unset($config['owner']);
if (isset($this->accessibleMenuItems[$config['parent']])) {
return $this->accessibleMenuItems[$config['parent']];
}
$parentConfig = $navConfig->getSection($config['parent']);
$this->accessibleMenuItems[$config['parent']] = $this->hasAccessToSharedNavigationItem(
$parentConfig,
$navConfig
);
return $this->accessibleMenuItems[$config['parent']];
}
if (isset($config['users'])) { if (isset($config['users'])) {
$users = array_map('trim', explode(',', strtolower($config['users']))); $users = array_map('trim', explode(',', strtolower($config['users'])));
if (in_array('*', $users, true) || in_array($this->user->getUsername(), $users, true)) { if (in_array('*', $users, true) || in_array($this->user->getUsername(), $users, true)) {
unset($config['owner']);
unset($config['users']); unset($config['users']);
unset($config['groups']);
return true; return true;
} }
} }
@ -160,6 +177,8 @@ class Web extends EmbeddedWeb
if (isset($config['groups'])) { if (isset($config['groups'])) {
$groups = array_map('trim', explode(',', strtolower($config['groups']))); $groups = array_map('trim', explode(',', strtolower($config['groups'])));
if (in_array('*', $groups, true)) { if (in_array('*', $groups, true)) {
unset($config['owner']);
unset($config['users']);
unset($config['groups']); unset($config['groups']);
return true; return true;
} }
@ -167,6 +186,8 @@ class Web extends EmbeddedWeb
$userGroups = array_map('strtolower', $this->user->getGroups()); $userGroups = array_map('strtolower', $this->user->getGroups());
$matches = array_intersect($userGroups, $groups); $matches = array_intersect($userGroups, $groups);
if (! empty($matches)) { if (! empty($matches)) {
unset($config['owner']);
unset($config['users']);
unset($config['groups']); unset($config['groups']);
return true; return true;
} }
@ -208,8 +229,17 @@ class Web extends EmbeddedWeb
} else { } else {
$items = array(); $items = array();
foreach ($config as $name => $typeConfig) { foreach ($config as $name => $typeConfig) {
if ($this->hasAccessToSharedNavigationItem($typeConfig)) { if (isset($this->accessibleMenuItems[$name])) {
$items[$name] = $typeConfig; if ($this->accessibleMenuItems[$name]) {
$items[$name] = $typeConfig;
}
} else {
if ($this->hasAccessToSharedNavigationItem($typeConfig, $config)) {
$this->accessibleMenuItems[$name] = true;
$items[$name] = $typeConfig;
} else {
$this->accessibleMenuItems[$name] = false;
}
} }
} }
@ -292,22 +322,20 @@ class Web extends EmbeddedWeb
'cssClass' => 'user-nav-item', 'cssClass' => 'user-nav-item',
'label' => $this->user->getUsername(), 'label' => $this->user->getUsername(),
'icon' => 'user', 'icon' => 'user',
'url' => 'preference',
'priority' => 900, 'priority' => 900,
'renderer' => array( 'children' => array(
'UserNavigationItemRenderer' 'preferences' => array(
), 'label' => t('Preferences'),
), 'priority' => 100,
'logout' => array( 'url' => 'preference'
'cssClass' => 'user-nav-item', ),
'label' => t('Logout'), 'logout' => array(
'icon' => 'starttime', 'label' => t('Logout'),
'priority' => 990, 'priority' => 200,
'renderer' => array( 'target' => '_self',
'LogoutNavigationItemRenderer', 'url' => 'authentication/logout'
'target' => '_self' )
), )
'url' => 'authentication/logout'
) )
); );
@ -346,6 +374,7 @@ class Web extends EmbeddedWeb
'layoutPath' => $this->getApplicationDir('/layouts/scripts') 'layoutPath' => $this->getApplicationDir('/layouts/scripts')
) )
); );
$this->setupFrontController(); $this->setupFrontController();
$this->setupViewRenderer(); $this->setupViewRenderer();
return $this; return $this;
@ -492,24 +521,4 @@ class Web extends EmbeddedWeb
} }
return Translator::DEFAULT_LOCALE; return Translator::DEFAULT_LOCALE;
} }
/**
* Setup class loader namespaces for Icinga\Controllers and Icinga\Forms
*
* @return $this
*/
private function setupNamespaces()
{
$this
->getLoader()
->registerNamespace(
'Icinga\\' . Dispatcher::CONTROLLER_NAMESPACE,
$this->getApplicationDir('controllers')
)
->registerNamespace(
'Icinga\\Forms',
$this->getApplicationDir('forms')
);
return $this;
}
} }

View File

@ -1171,10 +1171,9 @@ class Form extends Zend_Form
$this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl(); $this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl();
} }
} elseif ($this->getIsApiTarget()) { } elseif ($this->getIsApiTarget()) {
$this->getResponse()->sendJson(array( $this->getResponse()->json()->setFailData(
'status' => 'fail', array_merge($this->getMessages(), $this->getErrorMessages())
'data' => array_merge($this->getMessages(), $this->getErrorMessages()) )->sendResponse();
));
} }
} elseif ($this->getValidatePartial()) { } elseif ($this->getValidatePartial()) {
// The form can't be processed but we may want to show validation errors though // The form can't be processed but we may want to show validation errors though

View File

@ -58,7 +58,7 @@ class FormHints extends Zend_Form_Decorator_Abstract
$hints = $this->recurseForm($form, $entirelyRequired); $hints = $this->recurseForm($form, $entirelyRequired);
if ($entirelyRequired !== null) { if ($entirelyRequired !== null) {
$hints[] = $form->getView()->translate(sprintf( $hints[] = $form->getView()->translate(sprintf(
'Required fields are marked with %s and must be filled in to complete the form.', '%s Required field',
$form->getRequiredCue() $form->getRequiredCue()
)); ));
} }

View File

@ -94,7 +94,22 @@ abstract class BadgeNavigationItemRenderer extends NavigationItemRenderer
*/ */
public function render(NavigationItem $item = null) public function render(NavigationItem $item = null)
{ {
return '<div class="clearfix">' . $this->renderBadge() . parent::render($item) . '</div>'; if ($item === null) {
$item = $this->getItem();
}
$item->setCssClass('badge-nav-item');
$this->setEscapeLabel(false);
$label = $this->view()->escape($item->getLabel());
if (($icon = $item->getIcon()) !== null) {
$label = $this->view()->icon($icon) . $label;
$item->setIcon(null);
}
$item->setLabel($this->renderBadge() . $label);
$html = parent::render($item);
if ($icon) {
$item->setIcon(true);
}
return $html;
} }
/** /**
@ -107,7 +122,7 @@ abstract class BadgeNavigationItemRenderer extends NavigationItemRenderer
if ($count = $this->getCount()) { if ($count = $this->getCount()) {
$view = $this->view(); $view = $this->view();
return sprintf( return sprintf(
'<span title="%s" class="badge pull-right state-%s">%s</span>', '<span title="%s" class="badge state-%s">%s</span>',
$view->escape($this->getTitle()), $view->escape($this->getTitle()),
$view->escape($this->getState()), $view->escape($this->getState()),
$count $count

View File

@ -1,14 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Navigation\Renderer;
use Icinga\Web\Navigation\NavigationItem;
class LogoutNavigationItemRenderer extends NavigationItemRenderer
{
public function render(NavigationItem $item = null)
{
return parent::render($item);
}
}

View File

@ -271,9 +271,11 @@ class NavigationRenderer implements RecursiveIterator, NavigationRendererInterfa
/** /**
* Return the opening markup for multiple navigation items * Return the opening markup for multiple navigation items
* *
* @param int $level
*
* @return string * @return string
*/ */
public function beginChildrenMarkup() public function beginChildrenMarkup($level = 1)
{ {
$cssClass = array(static::CSS_CLASS_NAV); $cssClass = array(static::CSS_CLASS_NAV);
if ($this->navigation->getLayout() === Navigation::LAYOUT_TABS) { if ($this->navigation->getLayout() === Navigation::LAYOUT_TABS) {
@ -282,6 +284,8 @@ class NavigationRenderer implements RecursiveIterator, NavigationRendererInterfa
$cssClass[] = static::CSS_CLASS_NAV_DROPDOWN; $cssClass[] = static::CSS_CLASS_NAV_DROPDOWN;
} }
$cssClass[] = 'nav-level-' . $level;
return '<ul class="' . join(' ', $cssClass) . '">'; return '<ul class="' . join(' ', $cssClass) . '">';
} }
@ -352,8 +356,9 @@ class NavigationRenderer implements RecursiveIterator, NavigationRendererInterfa
foreach ($this as $item) { foreach ($this as $item) {
/** @var NavigationItem $item */ /** @var NavigationItem $item */
if ($item->shouldRender()) { if ($item->shouldRender()) {
$content = $item->render();
$this->content[] = $this->beginItemMarkup($item); $this->content[] = $this->beginItemMarkup($item);
$this->content[] = $item->render(); $this->content[] = $content;
$this->content[] = $this->endItemMarkup(); $this->content[] = $this->endItemMarkup();
} }
} }

View File

@ -142,7 +142,7 @@ class RecursiveNavigationRenderer extends RecursiveIteratorIterator implements N
*/ */
public function beginChildren() public function beginChildren()
{ {
$this->content[] = $this->getInnerIterator()->beginChildrenMarkup(); $this->content[] = $this->getInnerIterator()->beginChildrenMarkup($this->getDepth() + 1);
} }
/** /**
@ -162,14 +162,15 @@ class RecursiveNavigationRenderer extends RecursiveIteratorIterator implements N
foreach ($this as $item) { foreach ($this as $item) {
/** @var NavigationItem $item */ /** @var NavigationItem $item */
if ($item->shouldRender()) { if ($item->shouldRender()) {
$this->content[] = $this->getInnerIterator()->beginItemMarkup($item);
if ($this->getUseStandardItemRenderer()) { if ($this->getUseStandardItemRenderer()) {
$renderer = new NavigationItemRenderer(); $renderer = new NavigationItemRenderer();
$this->content[] = $renderer->render($item); $content = $renderer->render($item);
} else { } else {
$this->content[] = $item->render(); $content = $item->render();
} }
$this->content[] = $this->getInnerIterator()->beginItemMarkup($item);
$this->content[] = $content;
if (! $item->hasChildren()) { if (! $item->hasChildren()) {
$this->content[] = $this->getInnerIterator()->endItemMarkup(); $this->content[] = $this->getInnerIterator()->endItemMarkup();

View File

@ -1,26 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Navigation\Renderer;
use Icinga\Web\Navigation\NavigationItem;
class UserNavigationItemRenderer extends NavigationItemRenderer
{
public function getAvatar()
{
// Temporarily disabled as of layout issues. Should be fixed once
// we have avatars
return '';
return '<img class="pull-left user-avatar"
src="/icingaweb2/static/gravatar?email=icinga%40localhost"
alt="Avatar"
aria-hidden="true">';
}
public function render(NavigationItem $item = null)
{
return '<div class="clearfix">' . $this->getAvatar() . parent::render($item) . '</div>';
}
}

View File

@ -13,15 +13,13 @@ class StyleSheet
'../application/fonts/fontello-ifont/css/ifont-embedded.css', '../application/fonts/fontello-ifont/css/ifont-embedded.css',
'css/vendor/normalize.css', 'css/vendor/normalize.css',
'css/vendor/tipsy.css', 'css/vendor/tipsy.css',
'css/icinga/themes/icinga.less', 'css/icinga/base.less',
'css/icinga/colors.less', 'css/icinga/colors.less',
'css/icinga/badges.less', 'css/icinga/badges.less',
'css/icinga/mixins.less', 'css/icinga/mixins.less',
'css/icinga/grid.less', 'css/icinga/grid.less',
'css/icinga/base.less',
'css/icinga/nav.less', 'css/icinga/nav.less',
'css/icinga/main.less', 'css/icinga/main.less',
'css/icinga/limiter.less',
'css/icinga/animation.less', 'css/icinga/animation.less',
'css/icinga/layout-colors.less', 'css/icinga/layout-colors.less',
'css/icinga/layout-structure.less', 'css/icinga/layout-structure.less',
@ -33,14 +31,13 @@ class StyleSheet
'css/icinga/forms.less', 'css/icinga/forms.less',
'css/icinga/setup.less', 'css/icinga/setup.less',
'css/icinga/widgets.less', 'css/icinga/widgets.less',
'css/icinga/pagination.less',
'css/icinga/selection-toolbar.less',
'css/icinga/login.less', 'css/icinga/login.less',
'css/icinga/about.less',
'css/icinga/controls.less', 'css/icinga/controls.less',
'css/icinga/dev.less', 'css/icinga/dev.less',
// 'css/icinga/logo.less', // 'css/icinga/logo.less',
'css/icinga/spinner.less', 'css/icinga/spinner.less',
'css/icinga/compat.less', 'css/icinga/compat.less'
); );
public static function compileForPdf() public static function compileForPdf()

View File

@ -43,7 +43,7 @@ $this->addHelperFunction('timeAgo', function ($time, $timeOnly = false) {
return ''; return '';
} }
return sprintf( return sprintf(
'<span class="text-small time-ago" title="%s">%s</span>', '<span class="relative-time time-ago" title="%s">%s</span>',
DateFormatter::formatDateTime($time), DateFormatter::formatDateTime($time),
DateFormatter::timeAgo($time, $timeOnly) DateFormatter::timeAgo($time, $timeOnly)
); );
@ -54,7 +54,7 @@ $this->addHelperFunction('timeSince', function ($time, $timeOnly = false) {
return ''; return '';
} }
return sprintf( return sprintf(
'<span class="text-small time-since" title="%s">%s</span>', '<span class="relative-time time-since" title="%s">%s</span>',
DateFormatter::formatDateTime($time), DateFormatter::formatDateTime($time),
DateFormatter::timeSince($time, $timeOnly) DateFormatter::timeSince($time, $timeOnly)
); );
@ -65,7 +65,7 @@ $this->addHelperFunction('timeUntil', function ($time, $timeOnly = false) {
return ''; return '';
} }
return sprintf( return sprintf(
'<span class="text-small time-until" title="%s">%s</span>', '<span class="relative-time time-until" title="%s">%s</span>',
DateFormatter::formatDateTime($time), DateFormatter::formatDateTime($time),
DateFormatter::timeUntil($time, $timeOnly) DateFormatter::timeUntil($time, $timeOnly)
); );

View File

@ -74,7 +74,7 @@ class InlinePie extends AbstractWidget
* @var string * @var string
*/ */
private $template =<<<'EOD' private $template =<<<'EOD'
<span sparkType="pie" class="sparkline {class}" {title} sparkWidth={size} sparkHeight={size} sparkSliceColors="[{colors}]" values="{data}"> <span sparkType="pie" class="sparkline {class}" {title} sparkSliceColors="[{colors}]" values="{data}">
</span> </span>
{noscript} {noscript}
EOD; EOD;

View File

@ -3,41 +3,13 @@
namespace Icinga\Web\Widget; namespace Icinga\Web\Widget;
use Icinga\Web\Navigation\Navigation; use Icinga\Forms\Control\LimiterControlForm;
use Icinga\Web\Url;
/** /**
* Limiter control * Limiter control widget
*/ */
class Limiter extends AbstractWidget class Limiter extends AbstractWidget
{ {
/**
* CSS class for the limiter widget
*
* @var string
*/
const CSS_CLASS_LIMITER = 'limiter-control';
/**
* Default limit
*
* @var int
*/
const DEFAULT_LIMIT = 50;
/**
* Selectable limits
*
* @var int[]
*/
public static $limits = array(
10 => '10',
25 => '25',
50 => '50',
100 => '100',
500 => '500'
);
/** /**
* Default limit for this instance * Default limit for this instance
* *
@ -48,11 +20,11 @@ class Limiter extends AbstractWidget
/** /**
* Get the default limit * Get the default limit
* *
* @return int * @return int|null
*/ */
public function getDefaultLimit() public function getDefaultLimit()
{ {
return $this->defaultLimit !== null ? $this->defaultLimit : static::DEFAULT_LIMIT; return $this->defaultLimit;
} }
/** /**
@ -73,39 +45,10 @@ class Limiter extends AbstractWidget
*/ */
public function render() public function render()
{ {
$url = Url::fromRequest(); $control = new LimiterControlForm();
$activeLimit = (int) $url->getParam('limit', $this->getDefaultLimit()); $control
$navigation = new Navigation(); ->setDefaultLimit($this->defaultLimit)
$navigation->setLayout(Navigation::LAYOUT_TABS); ->handleRequest();
foreach (static::$limits as $limit => $label) { return (string)$control;
$navigation->addItem(
'limit_' . $limit,
array(
'priority' => $limit,
'label' => $label,
'active' => $activeLimit === $limit,
'url' => $url->with(array('limit' => $limit)),
'title' => sprintf(t('Show %u rows on this page'), $limit)
)
);
}
if ($activeLimit === 0) {
$navigation->addItem(
'limit_0',
array(
'active' => true,
'label' => t('all'),
'title' => t('Show all items on this page'),
'priority' => max(array_keys(static::$limits)) + 1
)
);
}
return $navigation
->getRenderer()
->setCssClass(static::CSS_CLASS_LIMITER)
->setHeading(t('Limiter'))
->render();
} }
} }

View File

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

View File

@ -1,5 +1,5 @@
<div class="controls"> <div class="controls">
<?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs->showOnlyCloseButton() ?> <?= $this->tabs ?>
</div> </div>
<div class="content"> <div class="content">
<?= /** @var \Icinga\Module\Doc\Renderer\DocSectionRenderer $section */ $section ?> <?= /** @var \Icinga\Module\Doc\Renderer\DocSectionRenderer $section */ $section ?>

View File

@ -1,7 +1,8 @@
<div class="controls"> <div class="controls">
<?= /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs->showOnlyCloseButton(); ?> <?= $this->tabs ?>
<h1><?= $this->translate('Module documentations'); ?></h1> <h1><?= $this->translate('Module documentations'); ?></h1>
</div> </div>
<div class="content"> <div class="content">
<ul> <ul>
<?php foreach ($modules as $module): /** @var \Icinga\Application\Modules\Module $module */ ?> <?php foreach ($modules as $module): /** @var \Icinga\Application\Modules\Module $module */ ?>

View File

@ -2,7 +2,7 @@
<?= $this->tabs ?> <?= $this->tabs ?>
</div> </div>
<div class="content"> <div class="content styleguide">
<h1>Header h1</h1> <h1>Header h1</h1>
<h2>Header h2</h2> <h2>Header h2</h2>
<h3>Header h3</h3> <h3>Header h3</h3>

View File

@ -86,7 +86,9 @@ class DocTocRenderer extends DocRenderer
); );
$url = $view->url($path); $url = $view->url($path);
/** @var \Icinga\Web\Url $url */ /** @var \Icinga\Web\Url $url */
$url->setAnchor($this->encodeAnchor($section->getId())); if ($this->getDepth() > 0) {
$url->setAnchor($this->encodeAnchor($section->getId()));
}
$urlAttributes = array( $urlAttributes = array(
'data-base-target' => '_next', 'data-base-target' => '_next',
'title' => sprintf( 'title' => sprintf(

View File

@ -25,6 +25,10 @@ table {
width: 100%; width: 100%;
} }
a[name]:focus {
outline: 0;
}
th, td { th, td {
padding: 0.25rem; padding: 0.25rem;
text-align: left; text-align: left;

View File

@ -0,0 +1,29 @@
(function(Icinga) {
var Doc = function(module) {
this.module = module;
this.initialize();
this.module.icinga.logger.debug('Doc module loaded');
};
Doc.prototype = {
initialize: function()
{
this.module.on('rendered', this.rendered);
this.module.icinga.logger.debug('Doc module initialized');
},
rendered: function(event) {
var $container = $(event.currentTarget);
if ($('> .content.styleguide', $container).length) {
$container.removeClass('module-doc');
}
}
};
Icinga.availableModules.doc = Doc;
}(Icinga));

View File

@ -37,13 +37,12 @@ class HostsController extends Controller
$this->getTabs()->add( $this->getTabs()->add(
'show', 'show',
array( array(
'label' => $this->translate('Hosts') . sprintf(' (%d)', count($this->hostList)),
'title' => sprintf( 'title' => sprintf(
$this->translate('Show summarized information for %u hosts'), $this->translate('Show summarized information for %u hosts'),
count($this->hostList) count($this->hostList)
), ),
'label' => $this->translate('Hosts') . sprintf(' (%d)', count($this->hostList)), 'url' => Url::fromRequest()
'url' => Url::fromRequest(),
'icon' => 'host'
) )
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show'); )->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts'); $this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts');
@ -52,21 +51,18 @@ class HostsController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form) protected function handleCommandForm(ObjectsCommandForm $form)
{ {
$this->hostList->setColumns(array( $this->hostList->setColumns(array(
'host_icon_image',
'host_icon_image_alt',
'host_name',
'host_address',
'host_address6',
'host_state',
'host_problem',
'host_handled',
'host_acknowledged', 'host_acknowledged',
'host_active_checks_enabled',
'host_display_name',
'host_handled',
'host_in_downtime', 'host_in_downtime',
'host_is_flapping', 'host_is_flapping',
'host_output', 'host_last_state_change',
'host_name',
'host_notifications_enabled', 'host_notifications_enabled',
'host_active_checks_enabled', 'host_passive_checks_enabled',
'host_passive_checks_enabled' 'host_problem',
'host_state'
)); ));
$form $form
@ -90,24 +86,18 @@ class HostsController extends Controller
->handleRequest(); ->handleRequest();
$this->view->checkNowForm = $checkNowForm; $this->view->checkNowForm = $checkNowForm;
$this->hostList->setColumns(array( $this->hostList->setColumns(array(
'host_icon_image',
'host_icon_image_alt',
'host_name',
'host_address',
'host_address6',
'host_state',
'host_problem',
'host_handled',
'host_acknowledged', 'host_acknowledged',
'host_active_checks_enabled',
'host_display_name',
'host_handled',
'host_in_downtime', 'host_in_downtime',
'host_is_flapping', 'host_is_flapping',
'host_output', 'host_last_state_change',
'host_name',
'host_notifications_enabled', 'host_notifications_enabled',
'host_active_checks_enabled', 'host_passive_checks_enabled',
'host_passive_checks_enabled' 'host_problem',
/*'host_event_handler_enabled', 'host_state'
'host_flap_detection_enabled',
'host_obsessing'*/
)); ));
$acknowledgedObjects = $this->hostList->getAcknowledgedObjects(); $acknowledgedObjects = $this->hostList->getAcknowledgedObjects();

View File

@ -39,13 +39,12 @@ class ServicesController extends Controller
$this->getTabs()->add( $this->getTabs()->add(
'show', 'show',
array( array(
'label' => $this->translate('Services') . sprintf(' (%d)', count($this->serviceList)),
'title' => sprintf( 'title' => sprintf(
$this->translate('Show summarized information for %u services'), $this->translate('Show summarized information for %u services'),
count($this->serviceList) count($this->serviceList)
), ),
'label' => $this->translate('Services') . sprintf(' (%d)', count($this->serviceList)), 'url' => Url::fromRequest()
'url' => Url::fromRequest(),
'icon' => 'services'
) )
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show'); )->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
} }
@ -53,28 +52,23 @@ class ServicesController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form) protected function handleCommandForm(ObjectsCommandForm $form)
{ {
$this->serviceList->setColumns(array( $this->serviceList->setColumns(array(
'host_icon_image', 'host_display_name',
'host_icon_image_alt',
'host_name',
'host_address',
'host_address6',
'host_output',
'host_state',
'host_problem',
'host_handled', 'host_handled',
'service_icon_image', 'host_name',
'service_icon_image_alt', 'host_problem',
'service_description', 'host_state',
'service_state',
'service_problem',
'service_handled',
'service_acknowledged', 'service_acknowledged',
'service_active_checks_enabled',
'service_description',
'service_display_name',
'service_handled',
'service_in_downtime', 'service_in_downtime',
'service_is_flapping', 'service_is_flapping',
'service_output', 'service_last_state_change',
'service_notifications_enabled', 'service_notifications_enabled',
'service_active_checks_enabled', 'service_passive_checks_enabled',
'service_passive_checks_enabled' 'service_problem',
'service_state'
)); ));
$form $form
@ -99,32 +93,23 @@ class ServicesController extends Controller
->handleRequest(); ->handleRequest();
$this->view->checkNowForm = $checkNowForm; $this->view->checkNowForm = $checkNowForm;
$this->serviceList->setColumns(array( $this->serviceList->setColumns(array(
'host_icon_image', 'host_display_name',
'host_icon_image_alt',
'host_name',
'host_address',
'host_address6',
'host_output',
'host_state',
'host_problem',
'host_handled', 'host_handled',
'service_icon_image', 'host_name',
'service_icon_image_alt', 'host_problem',
'service_output', 'host_state',
'service_description',
'service_state',
'service_problem',
'service_handled',
'service_acknowledged', 'service_acknowledged',
'service_active_checks_enabled',
'service_description',
'service_display_name',
'service_handled',
'service_in_downtime', 'service_in_downtime',
'service_is_flapping', 'service_is_flapping',
'service_last_state_change',
'service_notifications_enabled', 'service_notifications_enabled',
'service_active_checks_enabled', 'service_passive_checks_enabled',
'service_passive_checks_enabled' 'service_problem',
/* 'service_state'
'service_event_handler_enabled',
'service_flap_detection_enabled',
'service_obsessing'*/
)); ));
$acknowledgedObjects = $this->serviceList->getAcknowledgedObjects(); $acknowledgedObjects = $this->serviceList->getAcknowledgedObjects();

View File

@ -262,7 +262,7 @@ class BackendConfigForm extends ConfigForm
array( array(
'decorators' => array( 'decorators' => array(
'FormElements', 'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'element')) array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
) )
) )
); );

View File

@ -52,7 +52,7 @@ class Zend_View_Helper_Link extends Zend_View_Helper_Abstract
public function service($service, $serviceLinkText, $host, $hostLinkText, $class = null) public function service($service, $serviceLinkText, $host, $hostLinkText, $class = null)
{ {
return sprintf( return sprintf(
'%s: %s', '%s&#58; %s',
$this->host($host, $hostLinkText), $this->host($host, $hostLinkText),
$this->view->qlink( $this->view->qlink(
$serviceLinkText, $serviceLinkText,

View File

@ -61,14 +61,14 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
$headers[$column] = $labels[$column]; $headers[$column] = $labels[$column];
} }
} }
$table = array('<td><b>' . implode('</b></td><td><b>', $headers) . '<b></td>'); $table = array('<thead><tr><th>' . implode('</th><th>', $headers) . '</th></tr></thead><tbody>');
foreach ($pieChartData as $perfdata) { foreach ($pieChartData as $perfdata) {
if ($compact && $perfdata->isVisualizable()) { if ($compact && $perfdata->isVisualizable()) {
$results[] = $perfdata->asInlinePie($color)->render(); $results[] = $perfdata->asInlinePie($color)->render();
} else { } else {
$data = array(); $data = array();
if ($perfdata->isVisualizable()) { if ($perfdata->isVisualizable()) {
$data []= $perfdata->asInlinePie($color)->render() . '&nbsp;'; $data []= $perfdata->asInlinePie($color)->render();
} elseif (isset($columns[''])) { } elseif (isset($columns[''])) {
$data []= ''; $data []= '';
} }
@ -85,9 +85,10 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
); );
} }
} }
$table []= '<tr><td>' . implode('</td><td>', $data) . '</td></tr>'; $table []= '<tr><td class="sparkline-col">' . implode('</td><td>', $data) . '</td></tr>';
} }
} }
$table[] = '</tbody>';
if ($limit > 0) { if ($limit > 0) {
$count = $compact ? count($results) : count($table); $count = $compact ? count($results) : count($table);
if ($count > $limit) { if ($count > $limit) {
@ -107,8 +108,7 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
return ''; return '';
} }
return sprintf( return sprintf(
'<table class="perfdata %s">%s</table>', '<table class="performance-data-table">%s</table>',
isset($columns['']) ? 'perfdata-piecharts' : '',
implode("\n", $table) implode("\n", $table)
); );
} }

View File

@ -40,6 +40,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
'<table style="font-size: 0.75em"', '<table style="font-size: 0.75em"',
$this->getPurifier()->purify($output) $this->getPurifier()->purify($output)
); );
$isHtml = true;
} else { } else {
// Plaintext // Plaintext
$output = preg_replace( $output = preg_replace(
@ -47,11 +48,17 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
self::$txtReplacements, self::$txtReplacements,
$this->view->escape($output) $this->view->escape($output)
); );
} $isHtml = false;
if (! $raw) {
$output = '<pre class="plugin-output">' . $output . '</pre>';
} }
$output = $this->fixLinks($output); $output = $this->fixLinks($output);
if (! $raw) {
if ($isHtml) {
$output = '<div class="pluginoutput">' . $output . '</div>';
} else {
$output = '<div class="pluginoutput preformatted">' . $output . '</div>';
}
}
return $output; return $output;
} }

View File

@ -10,12 +10,12 @@
'monitoring/config/createbackend', 'monitoring/config/createbackend',
null, null,
array( array(
'class' => 'button action-link', 'class' => 'button-link',
'icon' => 'plus', 'icon' => 'plus',
'title' => $this->translate('Create a new monitoring backend') 'title' => $this->translate('Create a new monitoring backend')
) )
) ?> ) ?>
<table class="action-table listing-table"> <table class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Monitoring Backend') ?></th> <th><?= $this->translate('Monitoring Backend') ?></th>
@ -35,7 +35,7 @@
'title' => sprintf($this->translate('Edit monitoring backend %s'), $backendName) 'title' => sprintf($this->translate('Edit monitoring backend %s'), $backendName)
) )
) ?> ) ?>
<span class="text-small">&#40;<?= sprintf( <span class="config-label-meta">&#40;<?= sprintf(
$this->translate('Type: %s'), $this->translate('Type: %s'),
$this->escape($config->type === 'ido' ? 'IDO' : ucfirst($config->type)) $this->escape($config->type === 'ido' ? 'IDO' : ucfirst($config->type))
) ?>&#41; ) ?>&#41;
@ -65,12 +65,12 @@
'monitoring/config/createtransport', 'monitoring/config/createtransport',
null, null,
array( array(
'class' => 'button action-link', 'class' => 'button-link',
'icon' => 'plus', 'icon' => 'plus',
'title' => $this->translate('Create a new command transport') 'title' => $this->translate('Create a new command transport')
) )
) ?> ) ?>
<table class="action-table listing-table"> <table class="table-row-selectable common-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Transport') ?></th> <th><?= $this->translate('Transport') ?></th>
@ -90,7 +90,7 @@
'title' => sprintf($this->translate('Edit command transport %s'), $transportName) 'title' => sprintf($this->translate('Edit command transport %s'), $transportName)
) )
); ?> ); ?>
<span class="text-small">&#40;<?= sprintf( <span class="config-label-meta">&#40;<?= sprintf(
$this->translate('Type: %s'), $this->translate('Type: %s'),
$config->host !== null ? $this->translate('Remote') : $this->translate('Local') $config->host !== null ? $this->translate('Remote') : $this->translate('Local')
) ?>&#41; ) ?>&#41;

View File

@ -1,166 +0,0 @@
<?php
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service;
function contactsLink($match, $view) {
$links = array();
foreach (preg_split('/,\s/', $match[1]) as $contact) {
$links[] = $view->qlink(
$contact,
'monitoring/show/contact',
array('contact_name' => $contact),
array('title' => sprintf($view->translate('Show detailed information about %s'), $contact))
);
}
return '[' . implode(', ', $links) . ']';
}
$self = $this;
$url = $this->url();
$limit = (int) $url->getParam('limit', 25);
if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) {
$page = 1;
}
$history->limit($limit * $page);
if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs; ?>
<?= $this->render('partials/object/host-header.phtml'); ?>
<h1><?= $this->translate('This Host\'s Event History'); ?></h1>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<a href="#load-more">
<?= $this->translate('Scroll to the bottom of this page to load additional events'); ?>
</a>
<?= $this->filterEditor; ?>
</div>
<?php endif ?>
<div class="content">
<table data-base-target="_next" class="action objecthistory">
<tbody>
<?php foreach ($history->peekAhead() as $event): ?>
<?php
$stateClass = 'invalid';
$msg = $this->escape($event->output);
$isService = isset($event->service_description);
switch ($event->type) {
case 'notify':
$icon = 'notification';
$title = $this->translate('Notification');
$stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
$msg = $msg ? preg_replace_callback(
'/^\[([^\]]+)\]/',
function($match) use ($self) { return contactsLink($match, $self); },
$msg
) : $this->translate('This notification was not sent out to any contact.');
break;
case 'comment':
$icon = 'comment';
$title = $this->translate('Comment');
break;
case 'comment_deleted':
$icon = 'remove';
$title = $this->translate('Comment deleted');
break;
case 'ack':
$icon = 'acknowledgement';
$title = $this->translate('Acknowledge');
break;
case 'ack_deleted':
$icon = 'remove';
$title = $this->translate('Ack removed');
break;
case 'dt_comment':
$icon = 'in_downtime';
$title = $this->translate('In Downtime');
break;
case 'dt_comment_deleted':
$icon = 'remove';
$title = $this->translate('Downtime removed');
break;
case 'flapping':
$icon = 'flapping';
$title = $this->translate('Flapping');
break;
case 'flapping_deleted':
$icon = 'remove';
$title = $this->translate('Flapping stopped');
break;
case 'hard_state':
$stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
$icon = 'attention-alt';
$title = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
break;
case 'soft_state':
$icon = 'spinner';
$stateClass = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
$title = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
break;
case 'dt_start':
$icon = 'downtime_start';
$title = $this->translate('Downtime Start');
break;
case 'dt_end':
$icon = 'downtime_end';
$title = $this->translate('Downtime End');
break;
}
?>
<tr>
<td class="state-col state-<?= $stateClass; ?>">
<?php if ($history->getIteratorPosition() % $limit === 0): ?>
<a id="page-<?= $history->getIteratorPosition() / $limit + 1; ?>"></a>
<?php endif ?>
<strong><?= $this->escape($title); ?></strong>
<p><?= date('d.m. H:i', $event->timestamp); ?></p>
</td>
<td>
<?php if ($isService): ?>
<?= sprintf(
$this->translate('%s on %s', 'Service running on host'),
$this->qlink(
$event->service_display_name,
'monitoring/service/show',
array(
'host' => $event->host_name,
'service' => $event->service_description
),
array('title' => sprintf(
$this->translate('Show detailed information for service %s on host %s'),
$event->service_display_name,
$event->host_display_name
))
),
$event->host_display_name
) ?>
<?php else: ?>
<?= $this->escape($event->host_name); ?>
<?php endif ?>
<p class="plugin-output">
<?= $this->icon($icon, $title); ?> <?= $this->createTicketLinks($msg) ?>
</p>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (! $history->hasResult()): ?>
<?= $this->translate('No history events found matching the filter'); ?>
<?php elseif ($history->hasMore()): ?>
<?= $this->qlink(
$this->translate('Load More'),
$url->setAnchor('page-' . ($page + 1)),
array(
'page' => $page + 1,
),
array(
'id' => 'load-more',
'class' => 'pull-right action-link'
)
); ?>
<?php endif ?>
</div>

View File

@ -12,7 +12,7 @@
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<table data-base-target="_next" <table data-base-target="_next"
class="action-table multiselect" class="table-row-selectable common-table multiselect"
data-icinga-multiselect-url="<?= $this->href('monitoring/comments/show'); ?>" data-icinga-multiselect-url="<?= $this->href('monitoring/comments/show'); ?>"
data-icinga-multiselect-related="<?= $this->href("monitoring/comments") ?>" data-icinga-multiselect-related="<?= $this->href("monitoring/comments") ?>"
data-icinga-multiselect-data="comment_id"> data-icinga-multiselect-data="comment_id">

View File

@ -8,16 +8,16 @@ if (! $stats instanceof stdClass) {
} }
?> ?>
<div class="hosts-summary"> <div class="hosts-summary">
<?= $this->qlink( <span class="hosts-link"><?= $this->qlink(
sprintf($this->translatePlural('%u Host', '%u Hosts', $stats->hosts_total), $stats->hosts_total), sprintf($this->translatePlural('%u Host', '%u Hosts', $stats->hosts_total), $stats->hosts_total),
// @TODO(el): Fix that // @TODO(el): Fix that
Url::fromPath('monitoring/list/hosts')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), Url::fromPath('monitoring/list/hosts')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()),
null, null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural('List %u host', 'List all %u hosts', $stats->hosts_total), $this->translatePlural('List %u host', 'List all %u hosts', $stats->hosts_total),
$stats->hosts_total $stats->hosts_total
)) ))
) ?>&#58; ) ?>&#58;</span>
<?php <?php
$stateBadges = new StateBadges(); $stateBadges = new StateBadges();
$stateBadges $stateBadges

View File

@ -1,6 +1,15 @@
<?php <?php
$helpMessage = $this->translate('Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to select a range of rows.', 'multiselection'); $helpMessage = $this->translate(
'Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to'
.' select a range of rows',
'Multi-selection help'
);
?> ?>
<div class="selection-info text-small" title="<?= $this->escape($helpMessage) ?>"> <div class="selection-info" title="<?= $this->escape($helpMessage) ?>">
<span class="selection-info-count">0</span> <?= $this->translate('row(s) selected', 'multiselection') ?> <?= sprintf(
/// TRANSLATORS: Please leave %s as it is because the selection counter is wrapped in a span tag for updating
/// the counter via JavaScript
$this->translate('%s row(s) selected', 'Multi-selection count'),
'<span class="selection-info-count">0</span>'
) ?>
</div> </div>

View File

@ -8,19 +8,19 @@ if (! $stats instanceof stdClass) {
} }
?> ?>
<div class="services-summary"> <div class="services-summary">
<?= $this->qlink( <span class="services-link"><?= $this->qlink(
sprintf($this->translatePlural( sprintf($this->translatePlural(
'%u Service', '%u Services', $stats->services_total), '%u Service', '%u Services', $stats->services_total),
$stats->services_total $stats->services_total
), ),
// @TODO(el): Fix that // @TODO(el): Fix that
Url::fromPath('monitoring/list/services')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()), Url::fromPath('monitoring/list/services')->setParams(isset($baseFilter) ? $baseFilter->getUrlParams() : array()),
null, null,
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural('List %u service', 'List all %u services', $stats->services_total), $this->translatePlural('List %u service', 'List all %u services', $stats->services_total),
$stats->services_total $stats->services_total
)) ))
) ?>&#58; ) ?>&#58;</span>
<?php <?php
$stateBadges = new StateBadges(); $stateBadges = new StateBadges();
$stateBadges $stateBadges

View File

@ -18,7 +18,7 @@ if (count($groupData) === 0) {
return; return;
} }
?> ?>
<table class="action action-table listing-table" data-base-target="_next"> <table class="action table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>

View File

@ -11,7 +11,7 @@
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<?php if ($contacts->hasResult()): ?> <?php if ($contacts->hasResult()): ?>
<table class="action action-table listing-table" data-base-target="_next"> <table class="action table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th><?= $this->translate('Name') ?></th> <th><?= $this->translate('Name') ?></th>

View File

@ -16,7 +16,7 @@ if (! $this->compact): ?>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<table data-base-target="_next" <table data-base-target="_next"
class="action action-table multiselect" class="table-row-selectable state-table multiselect"
data-icinga-multiselect-url="<?= $this->href('monitoring/downtimes/show'); ?>" data-icinga-multiselect-url="<?= $this->href('monitoring/downtimes/show'); ?>"
data-icinga-multiselect-controllers="<?= $this->href("monitoring/downtimes") ?>" data-icinga-multiselect-controllers="<?= $this->href("monitoring/downtimes") ?>"
data-icinga-multiselect-data="downtime_id"> data-icinga-multiselect-data="downtime_id">
@ -30,7 +30,6 @@ if (! $this->compact): ?>
$this->stateName = Host::getStateText($downtime->host_state); $this->stateName = Host::getStateText($downtime->host_state);
} }
$this->downtime = $downtime; $this->downtime = $downtime;
$this->displayComment = true;
?> ?>
<tr href="<?= $this->href('monitoring/downtime/show', array('downtime_id' => $downtime->id)) ?>"> <tr href="<?= $this->href('monitoring/downtime/show', array('downtime_id' => $downtime->id)) ?>">
<?= $this->render('partials/downtime/downtime-header.phtml'); ?> <?= $this->render('partials/downtime/downtime-header.phtml'); ?>

View File

@ -1,140 +1,17 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service;
$url = $this->url();
$limit = (int) $url->getParam('limit', 25);
if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) {
$page = 1;
}
$history->limit($limit * $page);
if (! $this->compact): ?> if (! $this->compact): ?>
<div class="controls dont-print separated"> <div class="controls dont-print separated">
<?= $this->tabs; ?> <?= $this->tabs ?>
<div class="grid"> <div class="grid">
<div class="col-1-3 text-left"> <?= $this->limiter ?>
<?= $this->limiter ?> <?= $this->sortBox ?>
</div> </div>
<div class="col-1-3"> <?= $this->filterEditor ?>
<a class="action-link" href="#load-more">
<?= $this->translate('Scroll to the bottom of this page to load additional events'); ?>
</a>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <?= $this->partial(
<table data-base-target="_next" class="action action-table"> 'partials/event-history.phtml',
<tbody> array('compact' => $this->compact, 'history' => $history, 'isOverview' => true, 'tableCssClass' => 'table-row-selectable')
<?php foreach ($history->peekAhead() as $event): ?> ) ?>
<?php
$icon = 'help';
$msg = $event->output;
$title = $event->type;
$stateName = 'invalid';
$isService = isset($event->service_description);
switch ($event->type) {
case 'notify':
$icon = 'bell';
$title = $this->translate('Notification');
$msg = $msg ?: $this->translate('This notification was not sent out to any contact.');
break;
case 'comment':
$icon = 'comment';
$title = $this->translate('Comment');
break;
case 'ack':
$icon = 'ok';
$title = $this->translate('Acknowledgement');
break;
case 'dt_comment':
$icon = 'plug';
$title = $this->translate('In Downtime');
break;
case 'flapping':
$icon = 'flapping';
$title = $this->translate('Flapping');
break;
case 'flapping_deleted':
$icon = 'ok';
$title = $this->translate('Flapping Stopped');
break;
case 'hard_state':
$icon = $isService ? 'service' : 'host';
$stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
$title = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true);
break;
case 'soft_state':
$icon = 'lightbulb';
$stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
$title = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true);
break;
case 'dt_start':
$icon = 'starttime';
$title = $this->translate('Downtime Start');
break;
case 'dt_end':
$icon = 'endtime';
$title = $this->translate('Downtime End');
break;
}
?>
<tr>
<td class="state-col state-<?= $stateName; ?>">
<?php if ($history->getIteratorPosition() % $limit === 0): ?>
<a id="page-<?= $history->getIteratorPosition() / $limit + 1; ?>"></a>
<?php endif ?>
<strong><?= $this->escape($title); ?></strong>
<p><?= $this->timeAgo($event->timestamp, $this->compact); ?></p>
</td>
<td>
<?= $this->icon($icon, $title); ?>
<?php if ($isService): ?>
<?= $this->link()->service(
$event->service_description, $event->service_display_name, $event->host_name, $event->host_display_name, 'rowaction'
) ?>
<?php else: ?>
<?= $this->link()->host($event->host_name, $event->host_display_name) ?>
<?php endif ?>
<p class="plugin-output">
<?= empty($msg) ? '' : $this->escape($msg) ?>
</p>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php if (! $history->hasResult()): ?>
<?= $this->translate('No history events found matching the filter'); ?>
<?php elseif ($history->hasMore()): ?>
<?php if ($this->compact): ?>
<?= $this->qlink(
$this->translate('Show More'),
$url->without(array('view', 'limit')),
null,
array(
'data-base-target' => '_next',
'class' => 'pull-right action-link'
)
); ?>
<?php else: ?>
<?= $this->qlink(
$this->translate('Load More'),
$url->setAnchor('page-' . ($page + 1)),
array(
'page' => $page + 1,
),
array(
'id' => 'load-more',
'class' => 'pull-right action-link'
)
); ?>
<?php endif ?>
<?php endif ?>
</div>

View File

@ -18,7 +18,7 @@ if (! $this->compact): ?>
<p><?= $this->translate('No host groups found matching the filter.') ?></p> <p><?= $this->translate('No host groups found matching the filter.') ?></p>
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>

View File

@ -22,7 +22,7 @@ if (! $this->compact): ?>
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table data-base-target="_next" <table data-base-target="_next"
class="action-table multiselect" class="table-row-selectable state-table multiselect"
data-icinga-multiselect-url="<?= $this->href('monitoring/hosts/show') ?>" data-icinga-multiselect-url="<?= $this->href('monitoring/hosts/show') ?>"
data-icinga-multiselect-controllers="<?= $this->href("monitoring/hosts") ?>" data-icinga-multiselect-controllers="<?= $this->href("monitoring/hosts") ?>"
data-icinga-multiselect-data="host"> data-icinga-multiselect-data="host">
@ -32,61 +32,63 @@ if (! $this->compact): ?>
$hostLink = $this->href('monitoring/host/show', array('host' => $host->host_name)); ?> $hostLink = $this->href('monitoring/host/show', array('host' => $host->host_name)); ?>
<tr> <tr>
<td class="state-col state-<?= $hostStateName ?><?= $host->host_handled ? ' handled' : '' ?>"> <td class="state-col state-<?= $hostStateName ?><?= $host->host_handled ? ' handled' : '' ?>">
<p> <div class="state-label"><?= Host::getStateText($host->host_state, true) ?></div>
<span class="state-label"><?= Host::getStateText($host->host_state, true) ?></span>
<?php if ((int) $host->host_state !== 99): ?> <?php if ((int) $host->host_state !== 99): ?>
<br> <div class="state-meta">
<?= $this->timeSince($host->host_last_state_change, $this->compact) ?> <?= $this->timeSince($host->host_last_state_change, $this->compact) ?>
<?php if ((int) $host->host_state > 0 && (int) $host->host_state_type === 0): ?> <?php if ((int) $host->host_state > 0 && (int) $host->host_state_type === 0): ?>
<br> <div><?= $this->translate('Soft', 'Soft state') ?> <?= $host->host_attempt ?></div>
<span class="text-small">Soft <?= $host->host_attempt ?></span> <?php endif ?>
</div>
<?php endif ?> <?php endif ?>
<?php endif ?>
</p>
</td> </td>
<td class="clearfix"> <td>
<?= $this->iconImage()->host($host) ?> <div class="state-header">
<span class="pull-right"><?= implode(' ', $this->hostFlags($host)) ?></span> <?= $this->iconImage()->host($host) ?>
<?= $this->qlink( <?= $this->qlink(
$host->host_display_name, $host->host_display_name,
$hostLink, $hostLink,
null, null,
array( array(
'title' => sprintf( 'title' => sprintf(
$this->translate('Show detailed information for host %s'), $this->translate('Show detailed information for host %s'),
$host->host_display_name $host->host_display_name
), ),
'class' => 'rowaction' 'class' => 'rowaction'
) )
) ?> ) ?>
<?php if (isset($summary[$host->host_name])): ?> <?php if (isset($summary[$host->host_name])): ?>
<span class="text-small"> (<?= $this->qlink( <span class="host-services-incidents"> &#40;<?= $this->qlink(
sprintf( sprintf(
$this->translatePlural(
'%u unhandled service', '%u unhandled services', $summary[$host->host_name]
),
$summary[$host->host_name]
),
'monitoring/list/services',
array(
'host' => $host->host_name,
'service_problem' => 1,
'service_handled' => 0
),
array(
'title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %s unhandled service problem on host %s', '%u unhandled service', '%u unhandled services', $summary[$host->host_name]
'List %s unhandled service problems on host %s',
$summary[$host->host_name]
), ),
$summary[$host->host_name], $summary[$host->host_name]
$host->host_name ),
'monitoring/list/services',
array(
'host' => $host->host_name,
'service_problem' => 1,
'service_handled' => 0
),
array(
'title' => sprintf(
$this->translatePlural(
'List %s unhandled service problem on host %s',
'List %s unhandled service problems on host %s',
$summary[$host->host_name]
),
$summary[$host->host_name],
$host->host_name
)
) )
) ) ?>&#41;</span>
) ?>)</span> <?php endif ?>
<?php endif ?> <span class="state-icons"><?= implode(' ', $this->hostFlags($host)) ?></span>
<p class="plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?></p> </div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?>
</p>
</td> </td>
<?php foreach($this->addColumns as $col): ?> <?php foreach($this->addColumns as $col): ?>
<td><?= $this->escape($host->$col) ?></td> <td><?= $this->escape($host->$col) ?></td>

View File

@ -2,8 +2,6 @@
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
$notifications->peekAhead($this->compact);
if (! $this->compact): ?> if (! $this->compact): ?>
<div class="controls separated dont-print"> <div class="controls separated dont-print">
<?= $tabs ?> <?= $tabs ?>
@ -16,22 +14,32 @@ if (! $this->compact): ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content"> <div class="content">
<table data-base-target="_next" class="action action-table"> <?php if (! $notifications->hasResult()): ?>
<p><?= $this->translate('No notifications found matching the filter.') ?></p>
</div>
<?php return; endif ?>
<table data-base-target="_next" class="table-row-selectable state-table">
<tbody> <tbody>
<?php foreach ($notifications as $notification): <?php foreach ($notifications->peekAhead($this->compact) as $notification):
if (isset($notification->service_description)) { if (isset($notification->service_description)) {
$isService = true; $isService = true;
$stateLabel = Service::getStateText($notification->notification_state, true);
$stateName = Service::getStateText($notification->notification_state); $stateName = Service::getStateText($notification->notification_state);
} else { } else {
$isService = false; $isService = false;
$stateLabel = Host::getStateText($notification->notification_state, true);
$stateName = Host::getStateText($notification->notification_state); $stateName = Host::getStateText($notification->notification_state);
} }
?> ?>
<tr> <tr>
<td class="state-col state-<?= $stateName ?>"> <td class="state-col state-<?= $stateName ?>">
<?= $this->timeAgo($notification->notification_start_time, $this->compact) ?> <div class="state-label"><?= $stateLabel ?></div>
<div class="state-meta">
<?= $this->timeAgo($notification->notification_start_time, $this->compact) ?>
</div>
</td> </td>
<td> <td>
<div class="state-header">
<?php if ($isService): ?> <?php if ($isService): ?>
<?= $this->icon('service', $this->translate('Service')); ?> <?= $this->icon('service', $this->translate('Service')); ?>
<?= $this->link()->service( <?= $this->link()->service(
@ -45,24 +53,24 @@ if (! $this->compact): ?>
<?= $this->icon('host', $this->translate('Host')); ?> <?= $this->icon('host', $this->translate('Host')); ?>
<?= $this->link()->host($notification->host_name, $notification->host_display_name) ?> <?= $this->link()->host($notification->host_name, $notification->host_display_name) ?>
<?php endif ?> <?php endif ?>
<?php if (! $this->contact): ?> <?php if (! $this->contact): ?>
<span class="pull-right text-small"> <div class="notification-recipient">
<?php if ($notification->notification_contact_name): ?> <?php if ($notification->notification_contact_name): ?>
<?= sprintf( <?= sprintf(
$this->translate('Sent to %s'), $this->translate('Sent to %s'),
$this->qlink( $this->qlink(
$notification->notification_contact_name, $notification->notification_contact_name,
'monitoring/show/contact', 'monitoring/show/contact',
array('contact_name' => $notification->notification_contact_name) array('contact_name' => $notification->notification_contact_name)
) )
) ?> ) ?>
<?php else: ?> <?php else: ?>
<?= $this->translate('This notification was not sent out to any contact.'); ?> <?= $this->translate('Sent out to any contact') ?>
<?php endif ?> <?php endif ?>
</span> </div>
<?php endif ?> <?php endif ?>
<p class="plugin-output"> </div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?> <?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?>
</p> </p>
</td> </td>
@ -70,17 +78,17 @@ if (! $this->compact): ?>
<?php endforeach ?> <?php endforeach ?>
</tbody> </tbody>
</table> </table>
<?php if (! $notifications->hasResult()): ?> <?php if ($notifications->hasMore()): ?>
<?= $this->translate('No notifications found matching the filter'); ?> <div class="text-right">
<?php elseif ($notifications->hasMore()): ?> <?= $this->qlink(
<?= $this->qlink( $this->translate('Show More'),
$this->translate('Show More'), $this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')),
$this->url(isset($notificationsUrl) ? $notificationsUrl : null)->without(array('view', 'limit')), null,
null, array(
array( 'class' => 'action-link',
'data-base-target' => '_next', 'data-base-target' => '_next'
'class' => 'pull-right action-link' )
) ); ?>
); ?> </div>
<?php endif ?> <?php endif ?>
</div> </div>

View File

@ -3,32 +3,20 @@ use Icinga\Module\Monitoring\Object\Service;
use Icinga\Web\Url; use Icinga\Web\Url;
if (! $this->compact): ?> if (! $this->compact): ?>
<div class="controls separated"> <div class="controls">
<?= $this->tabs; ?> <?= $this->tabs ?>
<div class="grid dont-print"> <?= $this->sortBox ?>
<div class="col-1-3 text-left"> <?= $this->filterEditor ?>
<?= $this->limiter ?>
</div>
<div class="col-1-3">
<?= $this->paginator ?>
</div>
<div class="col-1-3 text-right">
<?= $this->sortBox ?>
</div>
</div>
<?= $this->filterEditor; ?>
</div> </div>
<?php endif ?> <?php endif ?>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<?php <?php if (empty($pivotData)): ?>
if (empty($pivotData)) { <p><?= $this->translate('No services found matching the filter.') ?></p>
echo $this->translate('No services found matching the filter') . '</div>'; </div>
return; <?php return; endif;
}
$hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')'; $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')';
?> ?>
<table class="service-grid-table">
<table class="service-grid-table">
<thead> <thead>
<tr> <tr>
<th><?= $this->partial( <th><?= $this->partial(
@ -38,7 +26,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
'xAxisPaginator' => $horizontalPaginator, 'xAxisPaginator' => $horizontalPaginator,
'yAxisPaginator' => $verticalPaginator 'yAxisPaginator' => $verticalPaginator
) )
); ?></th> ) ?></th>
<?php foreach ($pivotHeader['cols'] as $serviceDescription => $serviceDisplayName): ?> <?php foreach ($pivotHeader['cols'] as $serviceDescription => $serviceDisplayName): ?>
<th class="rotate-45"><div><span><?= $this->qlink( <th class="rotate-45"><div><span><?= $this->qlink(
$this->ellipsis($serviceDisplayName, 18), $this->ellipsis($serviceDisplayName, 18),
@ -55,7 +43,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
</thead> </thead>
<tbody> <tbody>
<?php $i = 0; ?> <?php $i = 0 ?>
<?php foreach ($pivotHeader['rows'] as $hostName => $hostDisplayName): ?> <?php foreach ($pivotHeader['rows'] as $hostName => $hostDisplayName): ?>
<tr> <tr>
<th><?php <th><?php
@ -79,24 +67,24 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
<span class="sr-only" id="<?= $ariaDescribedById ?>"> <span class="sr-only" id="<?= $ariaDescribedById ?>">
<?= $this->escape($service->service_output) ?> <?= $this->escape($service->service_output) ?>
</span> </span>
<?= $this->qlink( <?= $this->qlink(
'', '',
'monitoring/service/show', 'monitoring/service/show',
array( array(
'host' => $hostName, 'host' => $hostName,
'service' => $serviceDescription 'service' => $serviceDescription
), ),
array( array(
'aria-describedby' => $ariaDescribedById, 'aria-describedby' => $ariaDescribedById,
'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''), 'aria-label' => sprintf(
'title' => $this->escape($service->service_output), $this->translate('Show detailed information for service %s on host %s'),
'aria-label' => sprintf( $service->service_display_name,
$this->translate('Show detailed information for service %s on host %s'), $service->host_display_name
$service->service_display_name, ),
$service->host_display_name 'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''),
'title' => $this->escape($service->service_output)
) )
) ) ?>
); ?>
</td> </td>
<?php endforeach ?> <?php endforeach ?>
<?php if (! $this->compact && $this->horizontalPaginator->getPages()->pageCount > 1): ?> <?php if (! $this->compact && $this->horizontalPaginator->getPages()->pageCount > 1): ?>
@ -110,16 +98,16 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
. $this->verticalPaginator->getItemCountPerPage() . $this->verticalPaginator->getItemCountPerPage()
), ),
array( array(
'data-base-target' => '_self', 'class' => 'action-link',
'class' => 'action-link' 'data-base-target' => '_self'
) )
) ?> ) ?>
<?= ++$i === (int) (count($pivotHeader['rows']) / 2) ? $expandLink : '' ?> <?= ++$i === (int) (count($pivotHeader['rows']) / 2) ? $expandLink : '' ?>
</td> </td>
<?php endif;?> <?php endif ?>
</tr> </tr>
<?php endforeach ?> <?php endforeach ?>
<?php if (! $this->compact && $this->verticalPaginator->getPages()->pageCount > 1): ;?> <?php if (! $this->compact && $this->verticalPaginator->getPages()->pageCount > 1): ?>
<tr> <tr>
<td colspan="<?= count($pivotHeader['cols']) + 1?>" class="service-grid-table-more"> <td colspan="<?= count($pivotHeader['cols']) + 1?>" class="service-grid-table-more">
<?php echo $this->qlink( <?php echo $this->qlink(
@ -130,13 +118,13 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
($this->verticalPaginator->getItemCountPerPage() + 20) ($this->verticalPaginator->getItemCountPerPage() + 20)
), ),
array( array(
'data-base-target' => '_self', 'class' => 'action-link',
'class' => 'action-link' 'data-base-target' => '_self'
) )
) ?> ) ?>
</td> </td>
</tr> </tr>
<?php endif;?> <?php endif ?>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -16,7 +16,7 @@ if (! $this->compact): ?>
<p><?= $this->translate('No service groups found matching the filter.') ?></p> <p><?= $this->translate('No service groups found matching the filter.') ?></p>
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table class="action-table listing-table" data-base-target="_next"> <table class="table-row-selectable common-table" data-base-target="_next">
<thead> <thead>
<th></th> <th></th>
<th><?= $this->translate('Service Group') ?></th> <th><?= $this->translate('Service Group') ?></th>

View File

@ -23,7 +23,7 @@ if (! $this->compact): ?>
</div> </div>
<?php return; endif ?> <?php return; endif ?>
<table data-base-target="_next" <table data-base-target="_next"
class="action-table multiselect<?php if ($this->compact): ?> compact<?php endif ?>" class="table-row-selectable state-table multiselect<?php if ($this->compact): ?> compact<?php endif ?>"
data-icinga-multiselect-url="<?= $this->href('monitoring/services/show') ?>" data-icinga-multiselect-url="<?= $this->href('monitoring/services/show') ?>"
data-icinga-multiselect-controllers="<?= $this->href('monitoring/services') ?>" data-icinga-multiselect-controllers="<?= $this->href('monitoring/services') ?>"
data-icinga-multiselect-data="service,host"> data-icinga-multiselect-data="service,host">
@ -45,51 +45,55 @@ if (! $this->compact): ?>
$serviceStateName = Service::getStateText($service->service_state); ?> $serviceStateName = Service::getStateText($service->service_state); ?>
<tr> <tr>
<td class="state-col state-<?= $serviceStateName ?><?= $service->service_handled ? ' handled' : '' ?>"> <td class="state-col state-<?= $serviceStateName ?><?= $service->service_handled ? ' handled' : '' ?>">
<p> <div class="state-label"><?= Service::getStateText($service->service_state, true) ?></div>
<span class="state-label"><?= Service::getStateText($service->service_state, true) ?></span> <?php if ((int) $service->service_state !== 99): ?>
<?php if ((int) $service->service_state !== 99): ?> <div class="state-meta">
<br>
<?= $this->timeSince($service->service_last_state_change, $this->compact) ?> <?= $this->timeSince($service->service_last_state_change, $this->compact) ?>
<?php if ((int) $service->service_state > 0 && (int) $service->service_state_type === 0): ?> <?php if ((int) $service->service_state > 0 && (int) $service->service_state_type === 0): ?>
<br> <div><?= $this->translate('Soft', 'Soft state') ?> <?= $service->service_attempt ?></div>
<span class="text-small">Soft <?= $service->service_attempt ?></span>
<?php endif ?> <?php endif ?>
<?php endif ?> </div>
</p> <?php endif ?>
</td> </td>
<td class="clearfix"> <td>
<?= $this->iconImage()->service($service) ?> <div class="state-header">
<span class="pull-right"><?= implode(' ', $this->serviceFlags($service)) ?></span> <?= $this->iconImage()->service($service) ?>
<?php if ($this->showHost): ?><?= $this->qlink( <?php if ($this->showHost): ?><?= $this->qlink(
$service->host_display_name $service->host_display_name
. ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : ''), . ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : ''),
$hostLink, $hostLink,
null, null,
array( array(
'title' => sprintf( 'title' => sprintf(
$this->translate('Show detailed information for host %s'), $this->translate('Show detailed information for host %s'),
$service->host_display_name $service->host_display_name
)
) )
) ) ?>&#58;
) ?>: <?php endif ?><?= $this->qlink(
<?php endif ?><?= $this->qlink( $service->service_display_name,
$service->service_display_name, $serviceLink,
$serviceLink, null,
null, array(
array( 'title' => sprintf(
'title' => sprintf( $this->translate('Show detailed information for service %s on host %s'),
$this->translate('Show detailed information for service %s on host %s'), $service->service_display_name,
$service->service_display_name, $service->host_display_name
$service->host_display_name ),
), 'class' => 'rowaction'
'class' => 'rowaction' )
) ) ?>
) ?><br /> <span class="state-icons"><?= implode(' ', $this->serviceFlags($service)) ?></span>
<div class="sparkline-box"><?= $this->perfdata($service->service_perfdata, true, 5) ?> </div> </div>
<p class="plugin-output"> <div class="overview-plugin-output-container">
<?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?> <div class="overview-performance-data">
</p> <?= $this->perfdata($service->service_perfdata, true, 5) ?>
</div>
<p class="overview-plugin-output">
<?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?>
</p>
</div>
</td> </td>
<?php foreach($this->addColumns as $col): ?> <?php foreach($this->addColumns as $col): ?>
<td><?= $this->escape($service->$col) ?></td> <td><?= $this->escape($service->$col) ?></td>

View File

@ -0,0 +1,13 @@
<?php
if (! $this->compact): ?>
<div class="controls separated">
<?= $this->tabs ?>
<?php if ($object->type === 'service') {
echo $this->render('partials/object/service-header.phtml');
} else {
echo $this->render('partials/object/host-header.phtml');
} ?>
</div>
<?php endif ?>
<?= $this->render('partials/event-history.phtml') ?>

View File

@ -21,4 +21,4 @@ switch ($comment->type) {
$tooltip = $this->translate('Comment was caused by an acknowledgement'); $tooltip = $this->translate('Comment was caused by an acknowledgement');
break; break;
} }
echo $this->icon($icon, $tooltip, array('class' => 'big-icon')); echo $this->icon($icon, $tooltip, array('class' => 'large-icon'));

View File

@ -1,4 +1,4 @@
<span class="comment-header"> <div class="comment-header">
<?php if ($comment->objecttype === 'service'): ?> <?php if ($comment->objecttype === 'service'): ?>
<?= $this->icon('service', $this->translate('Service')) ?> <?= $this->qlink( <?= $this->icon('service', $this->translate('Service')) ?> <?= $this->qlink(
$comment->host_display_name . ': ' . $comment->service_display_name, $comment->host_display_name . ': ' . $comment->service_display_name,
@ -28,27 +28,31 @@
) )
) ?> ) ?>
<?php endif ?> <?php endif ?>
<?= $this->translate('by') ?> <span class="comment-meta">
<?= $this->escape($comment->author) ?> <?= $this->translate('by') ?>
<?= $this->timeAgo($comment->timestamp) ?> <?= $this->escape($comment->author) ?>
<span class="pull-right" data-base-target="_self"> <?= $this->timeAgo($comment->timestamp) ?>
<?= $comment->persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?> <span class="meta-icons" data-base-target="_self">
<?= $comment->expiration ? $this->icon('clock', sprintf( <?= $comment->persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?>
$this->translate('This comment expires %s.'), <?= $comment->expiration ? $this->icon('clock', sprintf(
$this->timeUntil($comment->expiration) $this->translate('This comment expires %s.'),
)) : '' ?> $this->timeUntil($comment->expiration)
<?php if (isset($delCommentForm)) { )) : '' ?>
$delCommentForm = clone $delCommentForm; <?php if (isset($delCommentForm)) {
$delCommentForm->populate( $deleteButton = clone $delCommentForm;
array( /** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm $deleteButton */
'comment_id' => $comment->id, $deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action');
'comment_is_service' => isset($comment->service_description) $deleteButton->populate(
) array(
); 'comment_id' => $comment->id,
echo $delCommentForm; 'comment_is_service' => isset($comment->service_description)
} ?> )
);
echo $deleteButton;
} ?>
</span>
</span> </span>
</span> </div>
<p class="comment-text"> <p class="comment-text">
<?= $this->escape($comment->comment) ?> <?= $this->escape($comment->comment) ?>
</p> </p>

View File

@ -1,6 +1,6 @@
<table> <table>
<tr> <tr>
<td class="comment-col"> <td class="icon-col">
<?= $this->render('partials/comment/comment-description.phtml') ?> <?= $this->render('partials/comment/comment-description.phtml') ?>
</td> </td>
<td> <td>

View File

@ -2,12 +2,12 @@
<tbody> <tbody>
<?php <?php
foreach ($comments as $i => $comment): foreach ($comments as $i => $comment):
if ($i > 5) { if ($i === 5) {
break; break;
} }
?> ?>
<tr> <tr>
<td class="comment-col"> <td class="icon-col">
<?= $this->partial('partials/comment/comment-description.phtml', array('comment' => $comment)) ?> <?= $this->partial('partials/comment/comment-description.phtml', array('comment' => $comment)) ?>
</td> </td>
<td> <td>

View File

@ -1,14 +1,14 @@
<td class="state-col state-<?= $stateName; ?><?= $downtime->is_in_effect ? ' handled' : ''; ?>"> <td class="state-col state-<?= $stateName; ?><?= $downtime->is_in_effect ? ' handled' : ''; ?>">
<?php if ($downtime->start <= time() && ! $downtime->is_in_effect): ?> <?php if ($downtime->start <= time() && ! $downtime->is_in_effect): ?>
<strong><?= $this->translate('Ends'); ?></strong> <div class="state-label"><?= $this->translate('ENDS', 'Downtime status'); ?></div>
<p><?= $this->timeUntil($downtime->is_flexible ? $downtime->scheduled_end : $downtime->end, $this->compact) ?></p> <div class="state-meta"><?= $this->timeUntil($downtime->is_flexible ? $downtime->scheduled_end : $downtime->end, $this->compact) ?></div>
<?php else: ?> <?php else: ?>
<strong><?= $downtime->is_in_effect ? $this->translate('Expires') : $this->translate('Starts'); ?></strong> <div class="state-label"><?= $downtime->is_in_effect ? $this->translate('EXPIRES', 'Downtime status') : $this->translate('STARTS', 'Downtime status'); ?></div>
<p><?= $this->timeUntil($downtime->is_in_effect ? $downtime->end : $downtime->start, $this->compact) ?></p> <div class="state-meta"><?= $this->timeUntil($downtime->is_in_effect ? $downtime->end : $downtime->start, $this->compact) ?></div>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td> <td>
<span class="comment-header"> <div class="comment-header">
<?php if ($isService): ?> <?php if ($isService): ?>
<?= $this->icon('service', $this->translate('Service')); ?> <?= $this->qlink( <?= $this->icon('service', $this->translate('Service')); ?> <?= $this->qlink(
$downtime->host_display_name . ': ' . $downtime->service_display_name, $downtime->host_display_name . ': ' . $downtime->service_display_name,
@ -38,11 +38,10 @@
) )
); ?> ); ?>
<?php endif ?> <?php endif ?>
<span class="comment-meta">
<?= $this->translate('by') ?> <?= $this->translate('by') ?>
<?= $this->escape($downtime->author_name) ?> <?= $this->escape($downtime->author_name) ?>
<span class="meta-icons">
<span class="pull-right">
<?php if ($downtime->is_flexible): ?> <?php if ($downtime->is_flexible): ?>
<?= $this->icon('magic', $this->translate('This downtime is flexible')); ?> <?= $this->icon('magic', $this->translate('This downtime is flexible')); ?>
<?php endif ?> <?php endif ?>
@ -52,22 +51,23 @@
<?php endif ?> <?php endif ?>
<?php if (isset($delDowntimeForm)): // Form is unset if the current user lacks the respective permission ?> <?php if (isset($delDowntimeForm)): // Form is unset if the current user lacks the respective permission ?>
<?php <?php
$delDowntimeForm = clone $delDowntimeForm; $deleteButton = clone $delDowntimeForm;
$delDowntimeForm->populate( /** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm $deleteButton */
array( $deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action');
'downtime_id' => $downtime->id, $deleteButton->populate(
'downtime_is_service' => isset($downtime->service_description) array(
) 'downtime_id' => $downtime->id,
); 'downtime_is_service' => isset($downtime->service_description)
echo $delDowntimeForm; )
?> );
echo $deleteButton;
?>
<?php endif ?> <?php endif ?>
</span>
</span> </span>
</span> </div>
<?php if (isset ($displayComment) && $displayComment): ?> <p class="comment-text">
<p class="comment-text"> <?= $this->escape($downtime->comment) ?>
<?= $this->escape($downtime->comment) ?> </p>
</p>
<?php endif ?>
</td> </td>

View File

@ -0,0 +1,179 @@
<?php
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service;
function contactsLink($match, $view) {
$links = array();
foreach (preg_split('/,\s/', $match[1]) as $contact) {
$links[] = $view->qlink(
$contact,
'monitoring/show/contact',
array('contact_name' => $contact),
array('title' => sprintf($view->translate('Show detailed information about %s'), $contact))
);
}
return '[' . implode(', ', $links) . ']';
}
$self = $this;
$url = $this->url();
$limit = (int) $url->getParam('limit', 25);
if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) {
$page = 1;
}
/** @var \Icinga\Module\Monitoring\DataView\EventHistory $history */
$history->limit($limit * $page);
?>
<div class="content">
<?php if (! $history->hasResult()): ?>
<p><?= $this->translate('No historical events found matching the filter.') ?></p>
</div>
<?php return; endif ?>
<table class="state-table" data-base-target="_next"<?php if (isset($tableCssClass)): ?> class="<?=$tableCssClass ?>"<?php endif ?>>
<tbody>
<?php foreach ($history->peekAhead() as $event):
$icon = '';
$iconCssClass = '';
$isService = isset($event->service_description);
$msg = $event->output;
$stateName = 'no-state';
switch ($event->type) {
case 'notify':
$icon = 'bell-alt';
$label = $this->translate('NOTIFICATION');
$msg = $msg ? preg_replace_callback(
'/^\[([^\]]+)\]/',
function($match) use ($self) { return contactsLink($match, $self); },
$msg
) : $this->translate('This notification was not sent out to any contact.');
$stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
break;
case 'comment':
$icon = 'comment';
$label = $this->translate('COMMENT');
break;
case 'comment_deleted':
$icon = 'cancel';
$label = $this->translate('COMMENT DELETED');
break;
case 'ack':
$icon = 'ok';
$label = $this->translate('ACKNOWLEDGED');
break;
case 'ack_deleted':
$icon = 'ok';
$iconCssClass = 'icon-strikethrough';
$label = $this->translate('ACKNOWLEDGEMENT REMOVED');
break;
case 'dt_comment':
// TODO(el): Does not appear in history
$icon = 'plug';
$label = $this->translate('SCHEDULED DOWNTIME');
break;
case 'dt_comment_deleted':
// TODO(el): Does not appear in history
$icon = 'plug';
$iconCssClass = 'icon-strikethrough';
$label = $this->translate('DOWNTIME DELETED');
break;
case 'flapping':
// TODO(el): Icon
$label = $this->translate('FLAPPING');
break;
case 'flapping_deleted':
// TODO(el): Icon
$label = $this->translate('FLAPPING STOPPED');
break;
case 'hard_state':
$label = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true);
$stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
break;
case 'soft_state':
$label = $isService ? Service::getStateText($event->state, true) : Host::getStateText($event->state, true);
$stateName = $isService ? Service::getStateText($event->state) : Host::getStateText($event->state);
break;
case 'dt_start':
$icon = 'plug';
$label = $this->translate('DOWNTIME START');
break;
case 'dt_end':
$icon = 'plug';
$iconCssClass = 'icon-strikethrough';
$label = $this->translate('DOWNTIME END');
break;
} ?>
<tr>
<td class="state-col state-<?= $stateName ?>">
<?php if ($history->getIteratorPosition() % $limit === 0): ?>
<a id="page-<?= $history->getIteratorPosition() / $limit + 1 ?>"></a>
<?php endif ?>
<div class="state-label"><?= $this->escape($label) ?></div>
<div class="state-meta"><?= $this->timeAgo($event->timestamp, $this->compact) ?></div>
</td>
<td>
<?php if ($this->isOverview): ?>
<?= $this->qlink(
$event->host_display_name,
'monitoring/host/show',
array(
'host' => $event->host_name,
),
array('title' => sprintf(
$this->translate('Show detailed information for host %s'),
$event->host_display_name
))
) ?><?php if ($isService): ?>&#58;
<?= $this->qlink(
$event->service_display_name,
'monitoring/service/show',
array(
'host' => $event->host_name,
'service' => $event->service_description
),
array(
'class' => 'rowaction',
'title' => sprintf(
$this->translate('Show detailed information for service %s on host %s'),
$event->service_display_name,
$event->host_display_name
)
)
) ?>
<?php endif ?>
<?php endif ?>
<p class="overview-plugin-output">
<?php if ($icon) {
echo $this->icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array());
} ?>
<?= nl2br($this->createTicketLinks($this->escape($msg)), false) ?>
</p>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php if ($history->hasMore()): ?>
<div class="action-links">
<?php if ($this->compact) {
echo $this->qlink(
$this->translate('Show More'),
$url->without(array('view', 'limit')),
null,
array(
'class' => 'action-link',
'data-base-target' => '_next'
)
);
} else {
echo $this->qlink(
$this->translate('Load More'),
$url->setAnchor('page-' . ($page + 1)),
array('page' => $page + 1,),
array('class' => 'action-link')
);
} ?>
</div>
<?php endif ?>
</div>

View File

@ -1,48 +1,41 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
$i = 0; if (! ($hostCount = count($objects))): return; endif ?>
?> <table class="state-table host-detail-state">
<tbody>
<?php if (($hostCount = count($objects)) > 0): ?> <?php foreach ($objects as $i => $host): /** @var Host $host */
<table class="action state statesummary"> if ($i === 5) {
<tbody> break;
<?php foreach ($objects as $host): /** @var Host $host */ ?> } ?>
<?php <tr>
if (++ $i > 5) { <td class="state-col state-<?= Host::getStateText($host->host_state); ?><?= $host->host_handled ? ' handled' : '' ?>">
continue; <span class="sr-only"><?= Host::getStateText($host->host_state) ?></span>
} <div class="state-meta">
?> <?= $this->timeSince($host->host_last_state_change, $this->compact) ?>
</div>
<tr> </td>
<td class="state-col state-<?= Host::getStateText($host->host_state); ?><?= $host->host_handled ? ' handled' : '' ?>"> <td>
<?= Host::getStateText($host->host_state, true); ?> <?= $this->link()->host(
<br /> $host->host_name,
</td> $host->host_display_name
<td> ) ?>
<?= $this->iconImage()->host($host) ?> <?= implode(' ', $this->hostFlags($host)) ?>
<?= implode(' ', $this->hostFlags($host)) ?> </td>
<b><?= $this->escape($host->getName()); ?></b><br> </tr>
<?= $this->escape($host->host_output) ?> <?php endforeach ?>
</td> </tbody>
</tr> </table>
<?php endforeach ?> <?php if ($hostCount > 5): ?>
</tbody> <div class="hosts-link">
</table> <?= $this->qlink(
<div class="hbox-item multi-commands"> sprintf($this->translate('List all %d hosts'), $hostCount),
<?php if ($i > 5): ?> $this->url()->setPath('monitoring/list/hosts'),
<?= null,
$this->qlink( array(
sprintf($this->translate('show all %d hosts'), $i), 'data-base-target' => '_next',
$listAllLink, 'icon' => 'forward'
null, )
array( ) ?>
'icon' => 'down-open', </div>
'data-base-target' => '_next'
)
);
?>
<?php endif ?>
</div>
<?php endif ?> <?php endif ?>

View File

@ -2,36 +2,34 @@
use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Host;
/** @var Host $object */ /** @var Host $object */
?> ?>
<table> <table class="state-table host-detail-state">
<tr> <tr>
<td class="state-col state-<?= Host::getStateText($object->host_state) ?><?= $object->host_handled ? ' handled' : '' ?>"> <td class="state-col state-<?= Host::getStateText($object->host_state) ?><?= $object->host_handled ? ' handled' : '' ?>">
<p> <div class="state-header"><?= Host::getStateText($object->host_state, true) ?></div>
<?= Host::getStateText($object->host_state, true) ?> <div class="state-meta">
<br>
<?= $this->timeSince($object->host_last_state_change) ?> <?= $this->timeSince($object->host_last_state_change) ?>
</p> <?php if ((int) $object->host_state > 0 && (int) $object->host_state_type === 0): ?>
<div><?= $this->translate('Soft', 'Soft state') ?> <?= $object->host_attempt ?></div>
<?php endif ?>
</div>
</td> </td>
<td> <td>
<p> <?= $this->iconImage()->host($object) ?>
<?= $this->iconImage()->host($object) ?> <span class="selectable"><?= $this->escape($object->host_display_name) ?></span>
<span class="selectable"><?= $this->escape($object->host_display_name) ?></span> <?php if ($object->host_display_name !== $object->host_name): ?>
<?php if ($object->host_display_name !== $object->host_name): ?> <span class="selectable host-meta">&#40;<?= $this->escape($object->host_name) ?>&#41;</span>
<span class="selectable text-small">&#40;<?= $this->escape($object->host_name) ?>&#41;</span> <?php endif ?>
<?php endif ?> <?= $this->render('partials/host/statusicons.phtml') ?>
<?php if ($object->host_address6 && $object->host_address6 !== $object->host_name): ?> <?php if ($object->host_address6 && $object->host_address6 !== $object->host_name): ?>
<br> <div class="selectable host-meta" title="<?= $this->translate('IPv6 address') ?>">
<span class="selectable text-small" title="<?= $this->translate('IPv6 address') ?>"> <?= $this->escape($object->host_address6) ?>
<?= $this->escape($object->host_address6) ?> </div>
</span> <?php endif ?>
<?php endif ?> <?php if ($object->host_address && $object->host_address !== $object->host_name): ?>
<?php if ($object->host_address && $object->host_address !== $object->host_name): ?> <div class="selectable host-meta" title="<?= $this->translate('IPv4 address') ?>">
<br> <?= $this->escape($object->host_address) ?>
<span class="selectable text-small" title="<?= $this->translate('IPv4 address') ?>"> </div>
<?= $this->escape($object->host_address) ?> <?php endif ?>
</span>
<?php endif ?>
<?= $this->render('partials/host/statusicons.phtml') ?>
</p>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -3,55 +3,53 @@ use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
?> ?>
<table> <table class="state-table service-detail-state">
<tr> <tr>
<td class="state-col state-<?= Host::getStateText($object->host_state) ?><?= $object->host_handled ? ' handled' : '' ?>"> <td class="state-col state-<?= Host::getStateText($object->host_state) ?><?= $object->host_handled ? ' handled' : '' ?>">
<p> <div class="state-label"><?= Host::getStateText($object->host_state, true) ?></div>
<?= Host::getStateText($object->host_state, true) ?> <div class="state-meta">
<br>
<?= $this->timeSince($object->host_last_state_change) ?> <?= $this->timeSince($object->host_last_state_change) ?>
</p> <?php if ((int) $object->host_state > 0 && (int) $object->host_state_type === 0): ?>
<div><?= $this->translate('Soft', 'Soft state') ?> <?= $object->host_attempt ?></div>
<?php endif ?>
</div>
</td> </td>
<td> <td>
<p> <?= $this->iconImage()->host($object) ?>
<?= $this->iconImage()->service($object) ?> <span class="selectable"><?= $this->escape($object->host_display_name) ?></span>
<span class="selectable"><?= $this->escape($object->host_display_name) ?></span> <?php if ($object->host_display_name !== $object->host_name): ?>
<?php if ($object->host_display_name !== $object->host_name): ?> <span class="selectable host-meta">&#40;<?= $this->escape($object->host_name) ?>&#41;</span>
<span class="selectable text-small">&#40;<?= $this->escape($object->host_name) ?>&#41;</span> <?php endif ?>
<?php endif ?>
<?php if ($object->host_address6 && $object->host_address6 !== $object->host_name): ?>
<br>
<span class="selectable text-small" title="<?= $this->translate('IPv6 address') ?>">
<?= $this->escape($object->host_address6) ?>
</span>
<?php endif ?>
<?php if ($object->host_address && $object->host_address !== $object->host_name): ?>
<br>
<span class="selectable text-small" title="<?= $this->translate('IPv4 address') ?>">
<?= $this->escape($object->host_address) ?>
</span>
<?php endif ?>
<?= $this->render('partials/host/statusicons.phtml') ?> <?= $this->render('partials/host/statusicons.phtml') ?>
</p> <?php if ($object->host_address6 && $object->host_address6 !== $object->host_name): ?>
<div class="selectable host-meta" title="<?= $this->translate('IPv6 address') ?>">
<?= $this->escape($object->host_address6) ?>
</div>
<?php endif ?>
<?php if ($object->host_address && $object->host_address !== $object->host_name): ?>
<div class="selectable host-meta" title="<?= $this->translate('IPv4 address') ?>">
<?= $this->escape($object->host_address) ?>
</div>
<?php endif ?>
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="state-col state-<?= Service::getStateText($object->service_state) ?><?= $object->service_handled ? ' handled' : '' ?>"> <td class="state-col state-<?= Service::getStateText($object->service_state) ?><?= $object->service_handled ? ' handled' : '' ?>">
<p> <div class="state-label"><?= Service::getStateText($object->service_state, true) ?></div>
<?= Service::getStateText($object->service_state, true) ?> <div class="state-meta">
<br>
<?= $this->timeSince($object->service_last_state_change) ?> <?= $this->timeSince($object->service_last_state_change) ?>
</p> <?php if ((int) $object->service_state > 0 && (int) $object->service_state_type === 0): ?>
<div><?= $this->translate('Soft', 'Soft state') ?> <?= $object->service_attempt ?></div>
<?php endif ?>
</div>
</td> </td>
<td> <td>
<p> <?= $this->iconImage()->service($object) ?>
<?= $this->iconImage()->host($object) ?> <?= $this->translate('Service') ?>&#58; <span class="selectable"><?= $this->escape($object->service_display_name) ?></span>
<?= $this->translate('Service') ?>&#58; <span class="selectable"><?= $this->escape($object->service_display_name) ?></span>
<?php if ($object->service_display_name !== $object->service_description): ?> <?php if ($object->service_display_name !== $object->service_description): ?>
<span class="selectable text-small">&#40;<?= $this->escape($object->service_description) ?>&#41;</span> <span class="selectable service-meta">&#40;<?= $this->escape($object->service_description) ?>&#41;</span>
<?php endif ?> <?php endif ?>
<?= $this->render('partials/service/statusicons.phtml') ?> <?= $this->render('partials/service/statusicons.phtml') ?>
</p>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -1,46 +1,45 @@
<?php <?php
use Icinga\Module\Monitoring\Object\Host;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
$i = 0; if (! ($serviceCount = count($objects))): return; endif ?>
?> <table class="state-table service-detail-state">
<?php if (($serviceCount = count($objects)) > 0): ?> <tbody>
<table class='action state statesummary'> <?php foreach ($objects as $i => $service): /** @var Service $service */
<tbody> if ($i === 5) {
<?php foreach ($objects as $service): /** @var Service $service */ ?> break;
<?php } ?>
if (++ $i > 5) { <tr>
continue; <td class="state-col state-<?= Service::getStateText($service->service_state) ?><?= $service->service_handled ? ' handled' : '' ?>">
} <span class="sr-only"><?= Service::getStateText($service->service_state) ?></span>
?> <div class="state-meta">
<tr> <?= $this->timeSince($service->service_last_state_change, $this->compact) ?>
<td class="state-col state-<?= Service::getStateText($service->service_state); ?><?= $service->service_handled ? ' handled' : '' ?>"?> </div>
<?= Service::getStateText($service->service_state, true); ?><br /> </td>
</td> <td>
<td> <?= $this->link()->service(
<?= $this->iconImage()->service($service) ?> $service->service_description,
$service->service_display_name,
$service->host_name,
$service->host_display_name
. ($service->host_state != 0 ? ' (' . Host::getStateText($service->host_state, true) . ')' : '')
) ?>
<?= implode(' ', $this->serviceFlags($service)) ?> <?= implode(' ', $this->serviceFlags($service)) ?>
<b> </td>
<?= $this->escape($service->getHost()->getName()); ?>: </tr>
<?= $this->escape($service->getName()); ?> <br> <?php endforeach ?>
</b> </tbody>
<?= $this->escape($service->service_output) ?> </table>
</td> <?php if ($serviceCount > 5): ?>
</tr> <div class="services-link">
<?php endforeach ?> <?= $this->qlink(
</tbody> sprintf($this->translate('List all %d services'), $serviceCount),
</table> $this->url()->setPath('monitoring/list/services'),
<div class="hbox-item multi-commands"> null,
<?php if ($i > 5): ?> array(
<?= $this->qlink( 'data-base-target' => '_next',
sprintf($this->translate('List all %d services'), $i), 'icon' => 'forward'
$listAllLink, )
null, ) ?>
array( </div>
'icon' => 'down-open',
'data-base-target' => '_next'
)
);
?>
<?php endif ?>
</div>
<?php endif ?> <?php endif ?>

View File

@ -1,150 +0,0 @@
<?php
use Icinga\Module\Monitoring\Object\Service;
function contactsLink($match, $view) {
$links = array();
foreach (preg_split('/,\s/', $match[1]) as $contact) {
$links[] = $view->qlink(
$contact,
'monitoring/show/contact',
array('contact_name' => $contact),
array('title' => sprintf($view->translate('Show detailed information about %s'), $contact))
);
}
return '[' . implode(', ', $links) . ']';
}
$self = $this;
$url = $this->url();
$limit = (int) $url->getParam('limit', 25);
if (! $url->hasParam('page') || ($page = (int) $url->getParam('page')) < 1) {
$page = 1;
}
$history->limit($limit * $page);
if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs; ?>
<?= $this->render('partials/object/service-header.phtml'); ?>
<h1><?= $this->translate('This Service\'s Event History'); ?></h1>
<?= $this->sortBox; ?>
<?= $this->limiter; ?>
<a href="#load-more">
<?= $this->translate('Scroll to the bottom of this page to load additional events'); ?>
</a>
<?= $this->filterEditor; ?>
</div>
<?php endif ?>
<div class="content">
<table data-base-target="_next" class="action objecthistory">
<tbody>
<?php foreach ($history->peekAhead() as $event): ?>
<?php
$stateClass = 'invalid';
$msg = $this->escape($event->output);
switch ($event->type) {
case 'notify':
$icon = 'notification';
$title = $this->translate('Notification');
$stateClass = Service::getStateText($event->state);
$msg = $msg ? preg_replace_callback(
'/^\[([^\]]+)\]/',
function($match) use ($self) { return contactsLink($match, $self); },
$msg
) : $this->translate('This notification was not sent out to any contact.');
break;
case 'comment':
$icon = 'comment';
$title = $this->translate('Comment');
break;
case 'comment_deleted':
$icon = 'remove';
$title = $this->translate('Comment deleted');
break;
case 'ack':
$icon = 'acknowledgement';
$title = $this->translate('Acknowledge');
break;
case 'ack_deleted':
$icon = 'remove';
$title = $this->translate('Ack removed');
break;
case 'dt_comment':
$icon = 'in_downtime';
$title = $this->translate('In Downtime');
break;
case 'dt_comment_deleted':
$icon = 'remove';
$title = $this->translate('Downtime removed');
break;
case 'flapping':
$icon = 'flapping';
$title = $this->translate('Flapping');
break;
case 'flapping_deleted':
$icon = 'remove';
$title = $this->translate('Flapping stopped');
break;
case 'hard_state':
$stateClass = Service::getStateText($event->state);
$icon = 'attention-alt';
$title = Service::getStateText($event->state);
break;
case 'soft_state':
$icon = 'spinner';
$stateClass = Service::getStateText($event->state);
$title = Service::getStateText($event->state);
break;
case 'dt_start':
$icon = 'downtime_start';
$title = $this->translate('Downtime Start');
break;
case 'dt_end':
$icon = 'downtime_end';
$title = $this->translate('Downtime End');
break;
}
?>
<tr class="state <?= $stateClass; ?>">
<td class="state">
<?php if ($history->getIteratorPosition() % $limit === 0): ?>
<a id="page-<?= $history->getIteratorPosition() / $limit + 1; ?>"></a>
<?php endif ?>
<strong><?= $this->escape($title); ?></strong>
<br>
<?= date('d.m. H:i', $event->timestamp); ?>
</td>
<td>
<?= sprintf(
$this->translate('%s on %s', 'Service running on host'),
$this->escape($event->service_display_name),
$event->host_display_name
) ?>
<br>
<div>
<?= $this->icon($icon, $title); ?> <?= $this->createTicketLinks($msg) ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (! $history->hasResult()): ?>
<?= $this->translate('No history events found matching the filter'); ?>
<?php elseif ($history->hasMore()): ?>
<?= $this->qlink(
$this->translate('Load More'),
$url->setAnchor('page-' . ($page + 1)),
array(
'page' => $page + 1,
),
array(
'id' => 'load-more',
'class' => 'pull-right action-link'
)
); ?>
<?php endif ?>
</div>

View File

@ -7,86 +7,87 @@ if (in_array((int) $object->state, array(0, 99))) {
return; return;
} }
if ($object->acknowledged): ?> if ($object->acknowledged):
<?php $acknowledgement = $object->acknowledgement;
$acknowledgement = $object->acknowledgement; /** @var \Icinga\Module\Monitoring\Object\Acknowledgement $acknowledgement */
/** @var \Icinga\Module\Monitoring\Object\Acknowledgement $acknowledgement */ ?>
?> <tr>
<tr> <th><?= $this->translate('Acknowledged') ?></th>
<th><?= $this->translate('Acknowledged') ?></th> <td data-base-target="_self">
<td data-base-target="_self"> <dl class="comment-list">
<dl class="feed-list"> <dt class="comment-header">
<dt class="feed-author clearfix"> <?= $this->escape($acknowledgement->getAuthor()) ?>
<?= $this->escape($acknowledgement->getAuthor()) ?> <span class="comment-meta">
<span class="text-small"><?= $this->translate('acknowledged') ?></span> <?= $this->translate('acknowledged') ?>
<?= $this->timeAgo($acknowledgement->getEntryTime()) ?> <?= $this->timeAgo($acknowledgement->getEntryTime()) ?>
<?php <?php if ($acknowledgement->expires()): ?>
if ($acknowledgement->getSticky()) { <span aria-hidden="true">&#448;</span>
echo $this->icon('pin', sprintf(
$this->translate(
'Acknowledgement remains until the %1$s recovers even if the %1$s changes state'
),
$object->getType(true)
));
}
if (isset($removeAckForm)) {
$removeAckForm->setAttrib('class', $removeAckForm->getAttrib('class') . ' pull-right');
// Form is unset if the current user lacks the respective permission
echo $removeAckForm;
}
?>
</dt>
<dd class="comment-text">
<?= nl2br($this->createTicketLinks($acknowledgement->getComment()), false) ?>
</dd>
<?php if ($acknowledgement->expires()): ?>
<dd class="text-small">
<?= sprintf( <?= sprintf(
$this->translate('Expires %s'), $this->translate('Expires %s'),
$this->timeUntil($acknowledgement->getExpirationTime()) $this->timeUntil($acknowledgement->getExpirationTime())
) ?> ) ?>
</dd> <?php endif ?>
<?php endif ?> <?php if ($acknowledgement->getSticky()): ?>
</dl> <?= $this->icon('pin', sprintf(
</td> $this->translate(
</tr> 'Acknowledgement remains until the %1$s recovers even if the %1$s changes state'
),
$object->getType(true)
)) ?>
<?php endif ?>
<?php if (isset($removeAckForm)): // Form is unset if the current user lacks the respective permission ?>
<span class="meta-icons">
<?php
$removeAckForm->setAttrib('class', $removeAckForm->getAttrib('class') . ' remove-action');
echo $removeAckForm;
?>
</span>
<?php endif ?>
</span>
</dt>
<dd class="comment-text">
<p><?= nl2br($this->createTicketLinks($this->escape($acknowledgement->getComment())), false) ?></p>
</dd>
</dl>
</td>
</tr>
<?php else: ?> <?php else: ?>
<tr> <tr>
<th><?= $this->translate('Not acknowledged') ?></th> <th><?= $this->translate('Not acknowledged') ?></th>
<td> <td>
<?php if ($this->hasPermission('monitoring/command/acknowledge-problem')) { <?php if ($this->hasPermission('monitoring/command/acknowledge-problem')) {
if ($object->getType() === $object::TYPE_HOST) { if ($object->getType() === $object::TYPE_HOST) {
$ackLink = $this->href( $ackLink = $this->href(
'monitoring/host/acknowledge-problem', 'monitoring/host/acknowledge-problem',
array('host' => $object->getName()), array('host' => $object->getName()),
null,
array('class' => 'action-link')
);
} else {
$ackLink = $this->href(
'monitoring/service/acknowledge-problem',
array('host' => $object->getHost()->getName(), 'service' => $object->getName()),
null,
array('class' => 'action-link')
);
}
?>
<?= $this->qlink(
$this->translate('Acknowledge'),
$ackLink,
null, null,
array( array('class' => 'action-link')
'class' => 'action-link', );
'data-base-target' => '_self', } else {
'icon' => 'ok', $ackLink = $this->href(
'title' => $this->translate( 'monitoring/service/acknowledge-problem',
'Acknowledge this problem, suppress all future notifications for it and tag it as being handled' array('host' => $object->getHost()->getName(), 'service' => $object->getName()),
) null,
array('class' => 'action-link')
);
}
?>
<?= $this->qlink(
$this->translate('Acknowledge'),
$ackLink,
null,
array(
'class' => 'action-link',
'data-base-target' => '_self',
'icon' => 'ok',
'title' => $this->translate(
'Acknowledge this problem, suppress all future notifications for it and tag it as being handled'
) )
); ?> )
<?php } else { ); ?>
echo '&#45;'; <?php } else {
} // endif ?> echo '&#45;';
</td> } // endif ?>
</tr> </td>
</tr>
<?php endif ?> <?php endif ?>

View File

@ -4,19 +4,17 @@
<?= $this->translate('Check Source') ?> <?= $this->translate('Check Source') ?>
</th> </th>
<td> <td>
<p> <?php if ($object->is_reachable !== null) {
<?php if ($object->is_reachable !== null) { if ((bool) $object->is_reachable) {
if ((bool) $object->is_reachable) { echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok'));
echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok')); } else {
} else { echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical'));
echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical')); }
} } ?>
} ?> <?= $this->escape($object->check_source) ?>
<?= $this->escape($object->check_source) ?> <?php if ($object->is_reachable !== null): ?>
<?php if ($object->is_reachable !== null): ?> <span class="check-source-meta"><?= (bool) $object->is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?></span>
<span class="text-small"><?= (bool) $object->is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?></span> <?php endif ?>
<?php endif ?>
</p>
</td> </td>
</tr> </tr>
<?php endif ?> <?php endif ?>

View File

@ -36,40 +36,40 @@ if (empty($object->comments) && ! $addLink) {
<th><?php <th><?php
echo $this->translate('Comments'); echo $this->translate('Comments');
if (! empty($object->comments) && $addLink) { if (! empty($object->comments) && $addLink) {
echo '<br />' . $addLink; echo '<br>' . $addLink;
} }
?></th> ?></th>
<td data-base-target="_self"> <td data-base-target="_self">
<?php if (empty($object->comments)): <?php if (empty($object->comments)):
echo $addLink; echo $addLink;
else: ?> else: ?>
<dl class="feed-list"> <dl class="comment-list">
<?php foreach ($object->comments as $comment): <?php foreach ($object->comments as $comment): ?>
// Form is unset if the current user lacks the respective permission <dt class="comment-header">
if (isset($delCommentForm)) {
$deleteButton = clone($delCommentForm);
/** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm $deleteButton */
$deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' pull-right');
$deleteButton->populate(
array(
'comment_id' => $comment->id,
'comment_is_service' => isset($comment->service_description)
)
);
} else {
$deleteButton = '';
}
?>
<dt class="feed-author clearfix">
<?= $this->escape($comment->author) ?> <?= $this->escape($comment->author) ?>
<span class="text-small"><?= $this->translate('commented') ?></span> <span class="comment-meta">
<?= $this->timeAgo($comment->timestamp) ?> <?= $this->translate('commented') ?>
<?php if ($deleteButton): ?> <?= $this->timeAgo($comment->timestamp) ?>
<?= $deleteButton ?> <?php if (isset($delCommentForm)): // Form is unset if the current user lacks the respective permission ?>
<?php endif ?> <span class="meta-icons">
<?php
$deleteButton = clone($delCommentForm);
/** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm $deleteButton */
$deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action');
$deleteButton->populate(
array(
'comment_id' => $comment->id,
'comment_is_service' => isset($comment->service_description)
)
);
echo $deleteButton;
?>
</span>
<?php endif ?>
</span>
</dt> </dt>
<dd class="comment-text"> <dd class="comment-text">
<?= str_replace(array('\r\n', '\n'), '<br>', $this->createTicketLinks($comment->comment)) ?> <p><?= nl2br($this->createTicketLinks($this->escape($comment->comment)), false) ?></p>
</dd> </dd>
<?php endforeach ?> <?php endforeach ?>
</dl> </dl>

View File

@ -40,14 +40,14 @@ if (empty($object->comments) && ! $addLink) {
<th><?php <th><?php
echo $this->translate('Downtimes'); echo $this->translate('Downtimes');
if (! empty($object->downtimes) && $addLink) { if (! empty($object->downtimes) && $addLink) {
echo '<br />' . $addLink; echo '<br>' . $addLink;
} }
?></th> ?></th>
<td data-base-target="_self"> <td data-base-target="_self">
<?php if (empty($object->downtimes)): <?php if (empty($object->downtimes)):
echo $addLink; echo $addLink;
else: ?> else: ?>
<dl class="feed-list"> <dl class="comment-list">
<?php foreach ($object->downtimes as $downtime): <?php foreach ($object->downtimes as $downtime):
if ((bool) $downtime->is_in_effect) { if ((bool) $downtime->is_in_effect) {
$state = sprintf( $state = sprintf(
@ -72,30 +72,34 @@ if (empty($object->comments) && ! $addLink) {
); );
} }
} }
// Form is unset if the current user lacks the respective permission ?>
if (isset($delDowntimeForm)) { <dt class="comment-header">
$deleteButton = clone($delDowntimeForm); <?= $this->escape($downtime->author_name) ?>
$deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' pull-right'); <span class="comment-meta">
$deleteButton->populate( <?= $this->translate('created') ?>
array( <?= $this->timeAgo($downtime->entry_time) ?>
'downtime_id' => $downtime->id, <span aria-hidden="true">&#448;</span>
'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE <?= $state ?>
) <?php if (isset($delDowntimeForm)): // Form is unset if the current user lacks the respective permission ?>
); <span class="meta-icons">
} else { <?php
$deleteButton = ''; $deleteButton = clone($delDowntimeForm);
} /** @var \Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm $deleteButton */
?> $deleteButton->setAttrib('class', $deleteButton->getAttrib('class') . ' remove-action');
<dt class="clearfix feed-author"> $deleteButton->populate(
<span class="author"><?= $this->escape($downtime->author_name) ?></span> array(
<?= $this->timeAgo($downtime->entry_time) ?> 'downtime_id' => $downtime->id,
<?= $deleteButton ?> 'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE
</dt> )
<dd class="comment-text"> );
<?= str_replace(array('\r\n', '\n'), '<br>', $this->createTicketLinks($downtime->comment)) ?> echo $deleteButton;
</dd> ?>
<dd class="text-small"> </span>
<?= $state ?> <?php endif ?>
</span>
</dt>
<dd class="comment-text">
<p><?= nl2br($this->createTicketLinks($this->escape($downtime->comment)), false) ?></p>
</dd> </dd>
<?php endforeach ?> <?php endforeach ?>
</dl> </dl>

View File

@ -1,5 +1,3 @@
<div class="pluginoutput"> <h2><?= $this->translate('Plugin Output') ?></h2>
<h2><?= $this->translate('Plugin Output') ?></h2> <?= $this->pluginOutput($object->output) ?>
<?= $this->pluginOutput($object->output) ?> <?= $this->pluginOutput($object->long_output) ?>
<?= $this->pluginOutput($object->long_output) ?>
</div>

View File

@ -49,7 +49,6 @@ $service_problems = (
</div> </div>
<?php if ($service_problems || $this->statusSummary->hosts_down || $this->statusSummary->hosts_unreachable): ?> <?php if ($service_problems || $this->statusSummary->hosts_down || $this->statusSummary->hosts_unreachable): ?>
<div class="box contents"> <div class="box contents">
<strong><?= $this->translate('Services'); ?></strong>
<?= $this->partial( <?= $this->partial(
'tactical/components/parts/servicestatesummarybyhoststate.phtml', 'tactical/components/parts/servicestatesummarybyhoststate.phtml',
array( array(

View File

@ -47,7 +47,6 @@
<?php endif ?> <?php endif ?>
</div> </div>
<div class="box contents"> <div class="box contents">
<strong><?= $this->translate('Services'); ?></strong>
<?= $this->partial( <?= $this->partial(
'tactical/components/parts/servicestatesummarybyhoststate.phtml', 'tactical/components/parts/servicestatesummarybyhoststate.phtml',
array( array(

View File

@ -11,7 +11,5 @@
<?php if ($this->statusSummary->hosts_up || $this->statusSummary->hosts_pending): ?> <?php if ($this->statusSummary->hosts_up || $this->statusSummary->hosts_pending): ?>
<?= $this->render('tactical/components/ok_hosts.phtml'); ?> <?= $this->render('tactical/components/ok_hosts.phtml'); ?>
<?php endif ?> <?php endif ?>
<?= $this->render('tactical/components/monitoringfeatures.phtml'); ?>
<?= $this->render('tactical/components/hostservicechecks.phtml'); ?>
</div> </div>
</div> </div>

View File

@ -353,6 +353,5 @@ $dashboard->add(
/* /*
* CSS * CSS
*/ */
$this->provideCssFile('plugin-output.less');
$this->provideCssFile('service-grid.less'); $this->provideCssFile('service-grid.less');
$this->provideCssFile('tables.less'); $this->provideCssFile('tables.less');

View File

@ -107,6 +107,7 @@ class Service extends MonitoredObject
{ {
return $this->backend->select()->from('servicestatus', array( return $this->backend->select()->from('servicestatus', array(
'instance_name', 'instance_name',
'host_attempt',
'host_icon_image', 'host_icon_image',
'host_icon_image_alt', 'host_icon_image_alt',
'host_acknowledged', 'host_acknowledged',
@ -122,6 +123,7 @@ class Service extends MonitoredObject
'host_notifications_enabled', 'host_notifications_enabled',
'host_passive_checks_enabled', 'host_passive_checks_enabled',
'host_state', 'host_state',
'host_state_type',
'service_icon_image', 'service_icon_image',
'service_icon_image_alt', 'service_icon_image_alt',
'service_acknowledged', 'service_acknowledged',

View File

@ -400,7 +400,6 @@ class Perfdata
$data = $this->calculatePieChartData(); $data = $this->calculatePieChartData();
$pieChart = new InlinePie($data, $this); $pieChart = new InlinePie($data, $this);
$pieChart->setColors(array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd')); $pieChart->setColors(array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd'));
$pieChart->setSparklineClass('sparkline-perfdata');
if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) { if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) {
$pieChart->disableNoScript(); $pieChart->disableNoScript();

View File

@ -108,6 +108,7 @@ abstract class MonitoredObjectController extends Controller
$this->setupLimitControl(50); $this->setupLimitControl(50);
$this->setupPaginationControl($this->view->history, 50); $this->setupPaginationControl($this->view->history, 50);
$this->view->object = $this->object; $this->view->object = $this->object;
$this->render('object/detail-history', null, true);
} }
/** /**
@ -180,7 +181,6 @@ abstract class MonitoredObjectController extends Controller
$isService ? $object->getHost()->getName() : $object->getName() $isService ? $object->getHost()->getName() : $object->getName()
), ),
'label' => $this->translate('Host'), 'label' => $this->translate('Host'),
'icon' => 'host',
'url' => 'monitoring/host/show', 'url' => 'monitoring/host/show',
'urlParams' => $params 'urlParams' => $params
) )
@ -195,7 +195,6 @@ abstract class MonitoredObjectController extends Controller
$isService ? $object->getHost()->getName() : $object->getName() $isService ? $object->getHost()->getName() : $object->getName()
), ),
'label' => $this->translate('Service'), 'label' => $this->translate('Service'),
'icon' => 'service',
'url' => 'monitoring/service/show', 'url' => 'monitoring/service/show',
'urlParams' => $params 'urlParams' => $params
) )
@ -209,7 +208,6 @@ abstract class MonitoredObjectController extends Controller
$isService ? $object->getHost()->getName() : $object->getName() $isService ? $object->getHost()->getName() : $object->getName()
), ),
'label' => $this->translate('Services'), 'label' => $this->translate('Services'),
'icon' => 'services',
'url' => 'monitoring/host/services', 'url' => 'monitoring/host/services',
'urlParams' => $params 'urlParams' => $params
) )
@ -227,7 +225,6 @@ abstract class MonitoredObjectController extends Controller
: sprintf($this->translate('Show all event records of host %s'), $object->getName()) : sprintf($this->translate('Show all event records of host %s'), $object->getName())
, ,
'label' => $this->translate('History'), 'label' => $this->translate('History'),
'icon' => 'rewind',
'url' => $isService ? 'monitoring/service/history' : 'monitoring/host/history', 'url' => $isService ? 'monitoring/service/history' : 'monitoring/host/history',
'urlParams' => $params 'urlParams' => $params
) )

View File

@ -1,10 +1,17 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
// Show more and load more links in overviews
.action-links {
text-align: right;
}
// State summary badges
.state-badges { .state-badges {
display: inline-block; display: inline-block;
vertical-align: middle;
> ul > li { > ul > li {
padding-right: 5px; padding-right: @vertical-padding;
&:last-child { &:last-child {
padding-right: 0; padding-right: 0;
@ -12,16 +19,47 @@
} }
} }
// Multi-selection info
.selection-info {
float: right;
font-size: @font-size-small;
padding: @vertical-padding / 2 0;
&:hover {
cursor: help;
}
}
// Performance data pie charts
.sparkline {
height: 1em;
margin-right: 0.1em;
position: relative;
top: 0.1em;
width: 1em;
}
// Host and service summaries in detail and list views
.hosts-summary, .hosts-summary,
.services-summary { .services-summary {
.v-center(); margin-bottom: 0.5em;
margin-top: @horizontal-padding;
> .hosts-link,
> .services-link,
> .state-badges {
vertical-align: middle;
}
}
// State table in the host and service multi-selection and detail views
.host-detail-state,
.service-detail-state {
margin-bottom: 0.5em;
} }
.grid { .grid {
.hosts-summary, .hosts-summary,
.services-summary { .services-summary {
margin: 0;
.pull-left(); .pull-left();
} }
} }
@ -64,8 +102,6 @@
} }
.boxview div.box.badge { .boxview div.box.badge {
border-radius: 3px;
margin: 5px;
padding: 5px; padding: 5px;
} }
@ -79,26 +115,41 @@
/* Tactical overview element styles */ /* Tactical overview element styles */
.tactical > .boxview > div.box { .tactical > .boxview > div.box {
min-height: 30em; min-height: 45em;
padding: 0px;
} }
.tactical div.box.header { .tactical div.box.header {
min-height: 5em; margin: 10px;
border-bottom:1px solid @gray-lighter; min-height: 8em;
color: @text-color-inverted;
font-size: @font-size-dashboard;
}
.tactical div.box.badge {
border-radius: 0.0em;
} }
div.box.ok_hosts.state_up { div.box.ok_hosts.state_up {
border: 1px solid @gray-lighter; background-color: @color-ok;
border-left: 15px solid @color-ok; border: 1px solid white;
} }
div.box.problem_hosts.state_down { div.box.problem_hosts.state_down {
border: 1px solid @gray-lighter; background-color: @color-critical;
border-left: 15px solid @color-critical; border: 1px solid white;
} }
div.box.ok_hosts div.box.entry, div.box.problem_hosts div.box.entry { div.box.ok_hosts div.box.entry, div.box.problem_hosts div.box.entry {
min-width: 11.1em; min-width: 8em;
min-height: 4em;
}
.tactical div.box.contents {
background-color: white;
min-height: 13em;
font-size: @font-size-dashboard-small;
text-align: left;
} }
div.box.monitoringfeatures { div.box.monitoringfeatures {
@ -347,23 +398,36 @@ form.instance-features span.description, form.object-features span.description {
text-align: left; text-align: left;
} }
form.object-features .control-label-group { .object-features {
text-align: left; .control-label-group {
width: 150px; text-align: left;
padding: @table-column-padding;
padding-left: 0;
width: @name-value-table-name-width;
label {
font-size: inherit;
}
}
input[type="checkbox"] {
margin: @table-column-padding;
}
} }
form.object-features .control-label { div.pluginoutput {
margin-left: 7px; border-left: 5px solid @gray-lighter;
line-height: 25px; padding: 0.66em 0.33em;
} }
.custom-variables ul { .go-ahead > a {
list-style-type: none; border-bottom: 1px @gray-light dotted;
margin: 0;
padding: 0;
padding-left: @vertical-padding;
}
&:hover {
border-bottom: 1px @gray-light solid;
text-decoration: none;
}
}
//p.pluginoutput { //p.pluginoutput {
// width: 100%; // width: 100%;

View File

@ -1,13 +0,0 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
p.plugin-output {
.text-small();
font-family: @font-family-fixed;
line-height: @line-height-small;
}
pre.plugin-output {
.text-small();
line-height: @line-height-small;
white-space: pre-wrap;
}

View File

@ -1,6 +1,6 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
table.service-grid-table { .service-grid-table {
width: 0; width: 0;
white-space: nowrap; white-space: nowrap;
@ -25,7 +25,7 @@ table.service-grid-table {
} }
} }
th.rotate-45 { .rotate-45 {
height: 6em; height: 6em;
div { div {
@ -34,10 +34,14 @@ table.service-grid-table {
} }
} }
td.service-grid-table-more { .service-grid-table-more {
text-align: center; text-align: center;
a { a {
display: inline; display: inline;
} }
} }
} }
.joystick-pagination a {
color: @text-color;
}

View File

@ -2,10 +2,99 @@
@border-left-width: 6px; @border-left-width: 6px;
.count-col { // Check source reachable information in the host and service detail views
width: 60px; .check-source-meta {
font-size: @font-size-small;
} }
// Type information for backends in the monitoring config
.config-label-meta {
font-size: @font-size-small;
}
// Column for counts, e.g. host group members
.count-col {
width: 4em;
}
// Custom variables in the host and service detail view
.custom-variables > ul {
list-style-type: none;
margin: 0;
padding: 0 0 0 @vertical-padding;
&:first-child {
padding: 0;
}
}
// Host name and IP addresses in the host and service detail view
.host-meta {
color: @text-color-light;
font-size: @font-size-small;
}
// Link to unhandled services in the hosts overview
.host-services-incidents {
color: @color-critical;
font-family: @font-family-wide;
font-size: @font-size-small;
}
// Notification recipient in the notifications overview
.notification-recipient {
color: @text-color-light;
float: right;
font-size: @font-size-small;
}
// Container for plugin output and performance data in overviews
.overview-plugin-output-container {
.clearfix();
}
// Performance data pies in overviews
.overview-performance-data {
float: right;
font-size: @font-size-small;
}
// Plugin output in overviews
.overview-plugin-output {
color: @text-color-light;
font-family: @font-family-fixed;
font-size: @font-size-small;
margin: 0;
}
// Table for performance data in detail views
.performance-data-table {
width: 100%;
> thead > tr > th {
text-align: left;
}
> thead > tr > th:first-child,
> tbody > tr > td:first-child {
// Reset base padding
padding-left: 0;
}
}
// Performance data table column for sparkline pie charts in detail views
.sparkline-col {
width: 2em;
}
// Service description if in the service detail view
.service-meta {
color: @text-color-light;
font-size: @font-size-small;
}
// State column for label and duration in overviews
.state-col { .state-col {
&.state-ok, &.state-ok,
&.state-up { &.state-up {
@ -18,71 +107,97 @@
&.state-critical, &.state-critical,
&.state-down { &.state-down {
.bg-color-critical(); background-color: @color-critical;
.fg-color-inverted(); color: @text-color-inverted;
&.handled { &.handled {
.bg-color-default(); background-color: inherit;
.fg-color-default(); color: inherit;
border-left: @border-left-width solid @color-critical-handled; border-left: @border-left-width solid @color-critical-handled;
} }
} }
&.state-warning { &.state-warning {
.bg-color-warning(); background-color: @color-warning;
.fg-color-inverted(); color: @text-color-inverted;
&.handled { &.handled {
.bg-color-default(); background-color: inherit;
.fg-color-default(); color: inherit;
border-left: @border-left-width solid @color-warning-handled; border-left: @border-left-width solid @color-warning-handled;
} }
} }
&.state-unknown { &.state-unknown {
.bg-color-unknown(); background-color: @color-unknown;
.fg-color-inverted(); color: @text-color-inverted;
&.handled { &.handled {
.bg-color-default(); background-color: inherit;
.fg-color-default(); color: inherit;
border-left: @border-left-width solid @color-unknown-handled; border-left: @border-left-width solid @color-unknown-handled;
} }
} }
&.state-unreachable { &.state-unreachable {
.bg-color-unreachable(); background-color: @color-unreachable;
.fg-color-inverted(); color: @text-color-inverted;
&.handled { &.handled {
.bg-color-default(); background-color: inherit;
.fg-color-default(); color: inherit;
border-left: @border-left-width solid @color-unreachable-handled; border-left: @border-left-width solid @color-unreachable-handled;
} }
} }
// State class for history events
&.state-no-state {
border-left: @border-left-width solid @text-color-light;
}
* { * {
color: inherit; color: inherit;
} }
text-align: center; text-align: center;
width: 100px; width: 8em;
} }
.comment-col { // Wraps links, icons and meta in overviews
padding-top: 0.5em; .state-header {
vertical-align: top; .clearfix();
width: 3em;
} }
.comment-content { // State icons, e.g. acknowledged in overviews
line-height: 1.5em; .state-icons {
padding-top: 0.4em; float: right;
padding-bottom: 0.7em;
max-width: 15em;
color: @text-color-light;
} }
.comment-header { // State labels in overviews
line-height: 1.8em; .state-label {
font-family: @font-family-wide;
font-size: @font-size-small;
letter-spacing: 1px;
}
// State duration and state type information in overviews
.state-meta {
font-size: @font-size-small;
}
.state-table {
border-collapse: separate;
border-spacing: 0 1px;
width: 100%;
tr[href] {
&.active {
background-color: @gray-lighter;
}
&:hover {
background-color: @gray-lightest;
cursor: pointer;
}
}
} }

View File

@ -0,0 +1,28 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
#about {
.about-social i {
font-size: 1.7em;
color: @text-color;
}
.about-social i:hover {
color: @icinga-blue;
}
.about-links {
margin-top: 2.5em;
margin-bottom: 2.5em;
}
.about-links i {
margin: 0.5em;
padding: 0;
font-size: 5em;
color: @text-color;
}
.about-links i:hover {
color: @icinga-blue;
}
}

View File

@ -1,15 +1,21 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
@badge-line-height: 1.2;
@badge-padding: 0.25em;
.badge { .badge {
min-width: 25px; .rounded-corners();
font-family: tahoma, verdana, sans-serif;
font-weight: @font-weight-bold;
font-size: 11px;
text-align: center;
color: @text-color-inverted;
padding-left: 5px;
padding-right: 5px;
padding-top: 2px;
padding-bottom: 2px;
background-color: @gray-light; background-color: @gray-light;
color: @text-color-inverted;
display: inline-block;
font-family: @font-family-wide;
font-size: @font-size-small;
line-height: @badge-line-height;
min-width: 2em;
padding: @badge-padding;
text-align: center;
vertical-align: middle;
white-space: nowrap;
&.state-ok { &.state-ok {
.bg-color-ok(); .bg-color-ok();

View File

@ -1,5 +1,56 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
// Gray colors
@gray: #7F7F7F;
@gray-light: #C9C9C9;
@gray-lighter: #EEEEEE;
@gray-lightest: #F7F7F7;
// Icinga colors
@icinga-blue: #0095BF;
@icinga-blue-dark: #AA95BF;
@color-ok: #44bb77;
@color-warning: #ffaa44;
@color-warning-handled: #ffcc66;
@color-critical: #ff5566;
@color-critical-handled: #ff99aa;
@color-unknown: #aa44ff;
@color-unknown-handled: #cc77ff;
@color-unreachable: #aa44ff;
@color-unreachable-handled: #cc77ff;
@color-pending: #77aaff;
// Background color for <body>
@body-bg-color: #fff;
// Text colors
@text-color: #535353;
@text-color-inverted: @body-bg-color;
@text-color-light: @gray;
// Text color on <a>
@link-color: @text-color;
// Font families
@font-family: Calibri, Helvetica, sans-serif;
@font-family-fixed: "Liberation Mono", "Lucida Console", Courier, monospace;
@font-family-wide: Tahoma, Verdana, sans-serif;
// Font sizes
@font-size: 0.750em; // 12px
@font-size-small: 0.917em; // 11px
@font-size-dashboard: 3.5em; // 56px
@font-size-dashboard-small: 1.1em; // 17px
@font-weight-bold: 600;
// Set line-height w/o unit so that the line-height is dynamically calculated as font-size * line-height
@line-height: 1.5;
@table-column-padding: 0.333em; // 4px
@vertical-padding: 0.5em; // 6px
@horizontal-padding: 1em; // 12px
// Make padding not affect the final computed width of an element // Make padding not affect the final computed width of an element
html { html {
box-sizing: border-box; box-sizing: border-box;
@ -13,71 +64,93 @@ html {
a { a {
// Reset defaults // Reset defaults
color: inherit; color: inherit;
font-weight: @font-weight-bold;
text-decoration: none; text-decoration: none;
&:focus {
outline-color: @icinga-blue;
}
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
} }
blockquote { // Default margin for block text
border-left: 6px solid @gray-light; blockquote, p, pre {
color: @text-color-light; margin: 0 0 1em 0;
// Reset default margin
margin: 0;
font-family: @font-family-fixed;
padding: @vertical-padding @horizontal-padding;
} }
body { blockquote {
background-color: @body-bg-color; border-left: 5px solid @gray-lighter;
color: @text-color; padding: 0.667em 0.333em;
font-family: @font-family; }
font-size: @font-size;
h1, h2, h3, h4, h5, h6 {
font-weight: @font-weight-bold;
margin: 0.556em 0 0.333em;
} }
h1 { h1 {
border-bottom: 1px solid @gray-lightest; border-bottom: 1px solid @gray-lighter;
font-size: 18px; font-size: 1.333em;
font-weight: normal;
line-height: 22px;
} }
h2 { h2 {
border-bottom: 1px solid @gray-lightest; font-size: 1.333em;
font-size: 16px;
font-weight: normal;
line-height: 19px;
} }
p { h3 {
color: @text-color; font-size: 1.167em;
font-size: @font-size; }
line-height: @line-height;
// Remove default margin h4 {
margin: 0; font-size: 1em;
}
h5 {
font-size: @font-size-small;
}
h6 {
font-size: @font-size-small;
font-weight: normal;
} }
pre { pre {
background-color: @gray-lightest; background-color: @gray-lightest;
color: @text-color-light;
font-family: @font-family-fixed; font-family: @font-family-fixed;
font-size: @font-size-small;
padding: @vertical-padding @horizontal-padding; padding: @vertical-padding @horizontal-padding;
white-space: pre-wrap;
} }
table { td, th {
border-collapse: separate; padding: @table-column-padding;
border-spacing: 0 1px;
width: 100%;
} }
td { [class^="icon-"], [class*=" icon-"] {
padding: @vertical-padding / 2 @horizontal-padding / 2; // Smooth icons; ifont claims to have it, but it does not work in :before
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
&:before {
margin-left: 0;
}
}
#layout {
background-color: @body-bg-color;
color: @text-color;
font-family: @font-family;
}
#main > .container, #menu, #header {
font-size: @font-size;
line-height: @line-height;
} }
@media print { @media print {
.dont-print { .dont-print {
display:none; display: none;
} }
} }

View File

@ -1,9 +1,5 @@
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
.bg-color-default() {
background-color: inherit;
}
.bg-color-ok, .bg-color-ok,
.bg-color-up { .bg-color-up {
background-color: @color-ok; background-color: @color-ok;
@ -87,11 +83,3 @@
.fg-color-pending { .fg-color-pending {
color: @color-pending; color: @color-pending;
} }
.fg-color-default {
color: inherit;
}
.fg-color-inverted() {
color: @text-color-inverted;
}

View File

@ -24,10 +24,7 @@
@colorPetrol: @icinga-blue; @colorPetrol: @icinga-blue;
table.action { table.action {
.action-table(); .common-table();
a {
font-weight: normal;
}
} }
table.avp { table.avp {

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