diff --git a/application/controllers/NavigationController.php b/application/controllers/NavigationController.php
index 1d2d39f68..67c249a33 100644
--- a/application/controllers/NavigationController.php
+++ b/application/controllers/NavigationController.php
@@ -5,6 +5,7 @@ namespace Icinga\Controllers;
use Exception;
use Icinga\Application\Config;
+use Icinga\Application\Icinga;
use Icinga\Exception\NotFoundError;
use Icinga\Data\DataArray\ArrayDatasource;
use Icinga\Data\Filter\FilterMatchCaseInsensitive;
@@ -407,4 +408,25 @@ class NavigationController extends Controller
$this->httpNotFound(sprintf($this->translate('Navigation item "%s" not found'), $form->getValue('name')));
}
}
+
+ public function dashboardAction()
+ {
+ $name = $this->params->getRequired('name');
+
+ $this->getTabs()->add('dashboard', array(
+ 'active' => true,
+ 'label' => ucwords($name),
+ 'url' => Url::fromRequest()
+ ));
+
+ $menu = Icinga::app()->getMenu();
+
+ $navigation = $menu->findItem($name);
+
+ if ($navigation === null) {
+ $this->httpNotFound($this->translate('Navigation not found'));
+ }
+
+ $this->view->navigation = $navigation;
+ }
}
diff --git a/application/views/scripts/navigation/dashboard.phtml b/application/views/scripts/navigation/dashboard.phtml
new file mode 100644
index 000000000..4f1d5c290
--- /dev/null
+++ b/application/views/scripts/navigation/dashboard.phtml
@@ -0,0 +1,16 @@
+
+ = $tabs ?>
+
+
diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php
index eae0873a1..e9731fc1f 100644
--- a/library/Icinga/Application/Web.php
+++ b/library/Icinga/Application/Web.php
@@ -302,14 +302,18 @@ class Web extends EmbeddedWeb
),
'children' => array(
'about' => array(
- 'label' => t('About'),
- 'url' => 'about',
- 'priority' => 700
+ 'icon' => 'info',
+ 'description' => t('Open about page'),
+ 'label' => t('About'),
+ 'url' => 'about',
+ 'priority' => 700
),
'announcements' => array(
- 'label' => t('Announcements'),
- 'url' => 'announcements',
- 'priority' => 710
+ 'icon' => 'megaphone',
+ 'description' => t('List announcements'),
+ 'label' => t('Announcements'),
+ 'url' => 'announcements',
+ 'priority' => 710
)
)
),
@@ -320,28 +324,36 @@ class Web extends EmbeddedWeb
'priority' => 800,
'children' => array(
'application' => array(
- 'label' => t('Application'),
- 'url' => 'config/general',
- 'permission' => 'config/application/*',
- 'priority' => 810
+ 'icon' => 'wrench',
+ 'description' => t('Open application configuration'),
+ 'label' => t('Application'),
+ 'url' => 'config/general',
+ 'permission' => 'config/application/*',
+ 'priority' => 810
),
'authentication' => array(
- 'label' => t('Authentication'),
- 'permission' => 'config/authentication/*',
- 'priority' => 830,
- 'url' => 'role/list'
+ 'icon' => 'users',
+ 'description' => t('Open authentication configuration'),
+ 'label' => t('Authentication'),
+ 'permission' => 'config/authentication/*',
+ 'priority' => 830,
+ 'url' => 'role/list'
),
'navigation' => array(
- 'label' => t('Shared Navigation'),
- 'url' => 'navigation/shared',
- 'permission' => 'config/application/navigation',
- 'priority' => 840,
+ 'icon' => 'sitemap',
+ 'description' => t('Open shared navigation configuration'),
+ 'label' => t('Shared Navigation'),
+ 'url' => 'navigation/shared',
+ 'permission' => 'config/application/navigation',
+ 'priority' => 840,
),
'modules' => array(
- 'label' => t('Modules'),
- 'url' => 'config/modules',
- 'permission' => 'config/modules',
- 'priority' => 890
+ 'icon' => 'cubes',
+ 'description' => t('Open module configuration'),
+ 'label' => t('Modules'),
+ 'url' => 'config/modules',
+ 'permission' => 'config/modules',
+ 'priority' => 890
)
)
),
@@ -352,15 +364,19 @@ class Web extends EmbeddedWeb
'priority' => 900,
'children' => array(
'account' => array(
- 'label' => t('My Account'),
- 'priority' => 100,
- 'url' => 'account'
+ 'icon' => 'sliders',
+ 'description' => t('Open your account preferences'),
+ 'label' => t('My Account'),
+ 'priority' => 100,
+ 'url' => 'account'
),
'logout' => array(
- 'label' => t('Logout'),
- 'priority' => 200,
- 'attributes' => array('target' => '_self'),
- 'url' => 'authentication/logout'
+ 'icon' => 'off',
+ 'description' => t('Log out'),
+ 'label' => t('Logout'),
+ 'priority' => 200,
+ 'attributes' => array('target' => '_self'),
+ 'url' => 'authentication/logout'
)
)
)
@@ -368,10 +384,12 @@ class Web extends EmbeddedWeb
if (Logger::writesToFile()) {
$menu['system']['children']['application_log'] = array(
- 'label' => t('Application Log'),
- 'url' => 'list/applicationlog',
- 'permission' => 'application/log',
- 'priority' => 900
+ 'icon' => 'doc-text',
+ 'description' => t(''),
+ 'label' => t('Application Log'),
+ 'url' => 'list/applicationlog',
+ 'permission' => 'application/log',
+ 'priority' => 900
);
}
} else {
diff --git a/library/Icinga/Web/Navigation/Navigation.php b/library/Icinga/Web/Navigation/Navigation.php
index 3371d6c00..a7a15849c 100644
--- a/library/Icinga/Web/Navigation/Navigation.php
+++ b/library/Icinga/Web/Navigation/Navigation.php
@@ -363,7 +363,7 @@ class Navigation implements ArrayAccess, Countable, IteratorAggregate
*
* @return NavigationItem
*/
- protected function findItem($name)
+ public function findItem($name)
{
$item = $this->getItem($name);
if ($item !== null) {
diff --git a/library/Icinga/Web/Navigation/NavigationItem.php b/library/Icinga/Web/Navigation/NavigationItem.php
index d6d19dd61..17360a3f5 100644
--- a/library/Icinga/Web/Navigation/NavigationItem.php
+++ b/library/Icinga/Web/Navigation/NavigationItem.php
@@ -88,6 +88,13 @@ class NavigationItem implements IteratorAggregate
*/
protected $label;
+ /**
+ * The item's description
+ *
+ * @var string
+ */
+ protected $description;
+
/**
* This item's parent
*
@@ -481,6 +488,30 @@ class NavigationItem implements IteratorAggregate
return $this;
}
+ /**
+ * Get the item's description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ /**
+ * Set the item's description
+ *
+ * @param string $description
+ *
+ * @return $this
+ */
+ public function setDescription($description)
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
/**
* Set this item's url target
*
@@ -512,7 +543,7 @@ class NavigationItem implements IteratorAggregate
public function getUrl()
{
if ($this->url === null && $this->hasChildren()) {
- $this->setUrl(Url::fromPath('#'));
+ $this->setUrl(Url::fromPath('navigation/dashboard', array('name' => strtolower($this->getName()))));
}
return $this->url;
diff --git a/library/Icinga/Web/Navigation/Renderer/RecursiveNavigationRenderer.php b/library/Icinga/Web/Navigation/Renderer/RecursiveNavigationRenderer.php
index 02653b541..562ed37d6 100644
--- a/library/Icinga/Web/Navigation/Renderer/RecursiveNavigationRenderer.php
+++ b/library/Icinga/Web/Navigation/Renderer/RecursiveNavigationRenderer.php
@@ -162,6 +162,9 @@ class RecursiveNavigationRenderer extends RecursiveIteratorIterator implements N
foreach ($this as $item) {
/** @var NavigationItem $item */
if ($item->shouldRender()) {
+ if ($this->getDepth() > 0) {
+ $item->setIcon(null);
+ }
if ($this->getUseStandardItemRenderer()) {
$renderer = new NavigationItemRenderer();
$content = $renderer->render($item);
diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php
index 4c144e226..81cfeb6d9 100644
--- a/modules/monitoring/configuration.php
+++ b/modules/monitoring/configuration.php
@@ -130,7 +130,9 @@ $section = $this->menuSection(N_('Problems'), array(
'priority' => 20
));
$section->add(N_('Host Problems'), array(
- 'renderer' => array(
+ 'icon' => 'host',
+ 'description' => $this->translate('List current host problems'),
+ 'renderer' => array(
'MonitoringBadgeNavigationItemRenderer',
'columns' => array(
'hosts_down_unhandled' => $this->translate('%d unhandled hosts down')
@@ -142,7 +144,9 @@ $section->add(N_('Host Problems'), array(
'priority' => 50
));
$section->add(N_('Service Problems'), array(
- 'renderer' => array(
+ 'icon' => 'service',
+ 'description' => $this->translate('List current service problems'),
+ 'renderer' => array(
'MonitoringBadgeNavigationItemRenderer',
'columns' => array(
'services_critical_unhandled' => $this->translate('%d unhandled services critical')
@@ -154,12 +158,16 @@ $section->add(N_('Service Problems'), array(
'priority' => 60
));
$section->add(N_('Service Grid'), array(
- 'url' => 'monitoring/list/servicegrid?problems',
- 'priority' => 70
+ 'icon' => 'services',
+ 'description' => $this->translate('Display service problems as grid'),
+ 'url' => 'monitoring/list/servicegrid?problems',
+ 'priority' => 70
));
$section->add(N_('Current Downtimes'), array(
- 'url' => 'monitoring/list/downtimes?downtime_is_in_effect=1',
- 'priority' => 80
+ 'icon' => 'plug',
+ 'description' => $this->translate('List current downtimes'),
+ 'url' => 'monitoring/list/downtimes?downtime_is_in_effect=1',
+ 'priority' => 80
));
/*
@@ -170,40 +178,58 @@ $section = $this->menuSection(N_('Overview'), array(
'priority' => 30
));
$section->add(N_('Tactical Overview'), array(
- 'url' => 'monitoring/tactical',
- 'priority' => 40
+ 'icon' => 'chart-pie',
+ 'description' => $this->translate('Open tactical overview'),
+ 'url' => 'monitoring/tactical',
+ 'priority' => 40
));
$section->add(N_('Hosts'), array(
- 'url' => 'monitoring/list/hosts',
- 'priority' => 50
+ 'icon' => 'host',
+ 'description' => $this->translate('List hosts'),
+ 'url' => 'monitoring/list/hosts',
+ 'priority' => 50
));
$section->add(N_('Services'), array(
- 'url' => 'monitoring/list/services',
- 'priority' => 50
+ 'icon' => 'service',
+ 'description' => $this->translate('List services'),
+ 'url' => 'monitoring/list/services',
+ 'priority' => 50
));
$section->add(N_('Servicegroups'), array(
- 'url' => 'monitoring/list/servicegroups',
- 'priority' => 60
+ 'icon' => 'services',
+ 'description' => $this->translate('List service groups'),
+ 'url' => 'monitoring/list/servicegroups',
+ 'priority' => 60
));
$section->add(N_('Hostgroups'), array(
- 'url' => 'monitoring/list/hostgroups',
- 'priority' => 60
+ 'icon' => 'host',
+ 'description' => $this->translate('List host groups'),
+ 'url' => 'monitoring/list/hostgroups',
+ 'priority' => 60
));
$section->add(N_('Contacts'), array(
- 'url' => 'monitoring/list/contacts',
- 'priority' => 70
+ 'icon' => 'user',
+ 'description' => $this->translate('List contacts'),
+ 'url' => 'monitoring/list/contacts',
+ 'priority' => 70
));
$section->add(N_('Contactgroups'), array(
- 'url' => 'monitoring/list/contactgroups',
- 'priority' => 70
+ 'icon' => 'users',
+ 'description' => $this->translate('List users'),
+ 'url' => 'monitoring/list/contactgroups',
+ 'priority' => 70
));
$section->add(N_('Comments'), array(
- 'url' => 'monitoring/list/comments?comment_type=comment|comment_type=ack',
- 'priority' => 80
+ 'icon' => 'chat-empty',
+ 'description' => $this->translate('List comments'),
+ 'url' => 'monitoring/list/comments?comment_type=comment|comment_type=ack',
+ 'priority' => 80
));
$section->add(N_('Downtimes'), array(
- 'url' => 'monitoring/list/downtimes',
- 'priority' => 80
+ 'icon' => 'plug',
+ 'description' => $this->translate('List downtimes'),
+ 'url' => 'monitoring/list/downtimes',
+ 'priority' => 80
));
/*
@@ -214,20 +240,28 @@ $section = $this->menuSection(N_('History'), array(
'priority' => 90
));
$section->add(N_('Event Grid'), array(
- 'priority' => 10,
- 'url' => 'monitoring/list/eventgrid'
+ 'icon' => 'history',
+ 'description' => $this->translate('Open event grid'),
+ 'priority' => 10,
+ 'url' => 'monitoring/list/eventgrid'
));
$section->add(N_('Event Overview'), array(
- 'priority' => 20,
- 'url' => 'monitoring/list/eventhistory?timestamp>=-7%20days'
+ 'icon' => 'history',
+ 'description' => $this->translate('Open event overview'),
+ 'priority' => 20,
+ 'url' => 'monitoring/list/eventhistory?timestamp>=-7%20days'
));
$section->add(N_('Notifications'), array(
- 'priority' => 30,
- 'url' => 'monitoring/list/notifications?notification_timestamp>=-7%20days',
+ 'icon' => 'bell',
+ 'description' => $this->translate('List notifications'),
+ 'priority' => 30,
+ 'url' => 'monitoring/list/notifications?notification_timestamp>=-7%20days',
));
$section->add(N_('Timeline'), array(
- 'priority' => 40,
- 'url' => 'monitoring/timeline'
+ 'icon' => 'clock',
+ 'description' => $this->translate('Open timeline'),
+ 'priority' => 40,
+ 'url' => 'monitoring/timeline'
));
/*
@@ -243,9 +277,11 @@ $section = $this->menuSection(N_('Reporting'), array(
*/
$section = $this->menuSection(N_('System'));
$section->add(N_('Monitoring Health'), array(
- 'url' => 'monitoring/health/info',
- 'priority' => 720,
- 'renderer' => 'BackendAvailabilityNavigationItemRenderer'
+ 'icon' => 'check',
+ 'description' => $this->translate('Open monitoring health'),
+ 'url' => 'monitoring/health/info',
+ 'priority' => 720,
+ 'renderer' => 'BackendAvailabilityNavigationItemRenderer'
));
/*
diff --git a/public/css/icinga/widgets.less b/public/css/icinga/widgets.less
index 13f83ac03..610c976ce 100644
--- a/public/css/icinga/widgets.less
+++ b/public/css/icinga/widgets.less
@@ -44,6 +44,56 @@
}
}
+.dashboard-link {
+ .clearfix();
+ display: block;
+ max-width: 100%;
+ vertical-align: middle;
+ padding: 1em;
+ width: 36em;
+
+ &:hover {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+
+ -webkit-box-shadow: 0 0 0.5em 0 rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 0 0.5em 0 rgba(0, 0, 0, 0.2);
+ box-shadow: 0 0 0.5em 0 rgba(0, 0, 0, 0.2);
+
+ background-color: @tr-hover-color;
+ text-decoration: none;
+ }
+}
+
+.link-meta {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.link-label {
+ font-weight: @font-weight-bold;
+}
+
+.link-description {
+ color: @text-color-light;
+}
+
+.link-icon {
+ display: table-cell;
+ padding-right: .5em;
+ vertical-align: middle;
+
+ > i {
+ font-size: 3em;
+ opacity: 0.7;
+ }
+}
+
table.historycolorgrid {
font-size: 1.5em;
}