Add documentation, add errorhandling and sizing
The optional width/height parameter can be set in the ini to change the dashboard components size, documentation has been added and in the error case a message with the configuration is shown refs #4192
This commit is contained in:
parent
f8bb478f0e
commit
2b25757e20
|
@ -52,7 +52,6 @@ class ConfigurationController extends ActionController
|
||||||
);
|
);
|
||||||
|
|
||||||
$tabBuilder->build();
|
$tabBuilder->build();
|
||||||
|
|
||||||
$this->view->tabs = $tabBuilder->getTabs();
|
$this->view->tabs = $tabBuilder->getTabs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,25 @@ use Icinga\Web\Url;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Web\Widget\Dashboard;
|
use Icinga\Web\Widget\Dashboard;
|
||||||
use Icinga\Application\Config as IcingaConfig;
|
use Icinga\Application\Config as IcingaConfig;
|
||||||
use Icinga\Exception\ConfigurationError;
|
|
||||||
use Icinga\Form\Dashboard\AddUrlForm;
|
use Icinga\Form\Dashboard\AddUrlForm;
|
||||||
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle creation, removal and displaying of dashboards, panes and components
|
||||||
|
*
|
||||||
|
* @see Icinga\Web\Widget\Dashboard for more information about dashboards
|
||||||
|
*/
|
||||||
class DashboardController extends ActionController
|
class DashboardController extends ActionController
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a dashboard from the provided config
|
||||||
|
*
|
||||||
|
* @param string $config The config to read the dashboard from, or 'dashboard/dashboard' if none is given
|
||||||
|
*
|
||||||
|
* @return Dashboard
|
||||||
|
*/
|
||||||
private function getDashboard($config = 'dashboard/dashboard')
|
private function getDashboard($config = 'dashboard/dashboard')
|
||||||
{
|
{
|
||||||
$dashboard = new Dashboard();
|
$dashboard = new Dashboard();
|
||||||
|
@ -18,6 +32,10 @@ class DashboardController extends ActionController
|
||||||
return $dashboard;
|
return $dashboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a component from the pane identified by the 'pane' parameter
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function removecomponentAction()
|
public function removecomponentAction()
|
||||||
{
|
{
|
||||||
$pane = $this->_getParam('pane');
|
$pane = $this->_getParam('pane');
|
||||||
|
@ -35,13 +53,17 @@ class DashboardController extends ActionController
|
||||||
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $pane)));
|
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $pane)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the form for adding new components or add the new component if submitted
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function addurlAction()
|
public function addurlAction()
|
||||||
{
|
{
|
||||||
$form = new AddUrlForm();
|
$form = new AddUrlForm();
|
||||||
$form->setRequest($this->_request);
|
$form->setRequest($this->_request);
|
||||||
$this->view->form = $form;
|
$this->view->form = $form;
|
||||||
|
|
||||||
|
|
||||||
if ($form->isSubmittedAndValid()) {
|
if ($form->isSubmittedAndValid()) {
|
||||||
$dashboard = $this->getDashboard();
|
$dashboard = $this->getDashboard();
|
||||||
$dashboard->setComponentUrl(
|
$dashboard->setComponentUrl(
|
||||||
|
@ -49,23 +71,26 @@ class DashboardController extends ActionController
|
||||||
$form->getValue('component'),
|
$form->getValue('component'),
|
||||||
ltrim($form->getValue('url'), '/')
|
ltrim($form->getValue('url'), '/')
|
||||||
);
|
);
|
||||||
$this->persistDashboard($dashboard);
|
try {
|
||||||
$this->redirectNow(
|
|
||||||
Url::fromPath(
|
|
||||||
'dashboard',
|
|
||||||
array(
|
|
||||||
'pane' => $form->getValue('pane')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function persistDashboard(Dashboard $dashboard)
|
|
||||||
{
|
|
||||||
$dashboard->store();
|
$dashboard->store();
|
||||||
|
$this->redirectNow(
|
||||||
|
Url::fromPath('dashboard',array('pane' => $form->getValue('pane')))
|
||||||
|
);
|
||||||
|
} catch (ConfigurationError $exc) {
|
||||||
|
$this->_helper->viewRenderer('show_configuration');
|
||||||
|
$this->view->exceptionMessage = $exc->getMessage();
|
||||||
|
$this->view->iniConfigurationString = $dashboard->toIni();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the dashboard with the pane set in the 'pane' request parameter
|
||||||
|
*
|
||||||
|
* If no pane is submitted or the submitted one doesn't exist, the default pane is
|
||||||
|
* displayed (normally the first one)
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
$dashboard = $this->getDashboard();
|
$dashboard = $this->getDashboard();
|
||||||
|
@ -75,10 +100,10 @@ class DashboardController extends ActionController
|
||||||
$dashboard->activate($dashboardName);
|
$dashboard->activate($dashboardName);
|
||||||
}
|
}
|
||||||
$this->view->tabs = $dashboard->getTabs();
|
$this->view->tabs = $dashboard->getTabs();
|
||||||
$this->view->tabs->add("Add", array(
|
$this->view->tabs->add('Add', array(
|
||||||
"title" => "Add Url",
|
'title' => 'Add Url',
|
||||||
"iconCls" => "plus",
|
'iconCls' => 'plus',
|
||||||
"url" => Url::fromPath("dashboard/addurl")
|
'url' => Url::fromPath('dashboard/addurl')
|
||||||
));
|
));
|
||||||
$this->view->dashboard = $dashboard;
|
$this->view->dashboard = $dashboard;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<br/>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<h4><i class="icon-warning-sign"> </i>Saving dashboard failed</h4>
|
||||||
|
<br/>
|
||||||
|
<p>
|
||||||
|
Your dashboard couldn't be stored (error: "<?= $this->exceptionMessage ?>"). This could have one or more
|
||||||
|
of the following reasons:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>You don't have permissions to write to the dashboard file</li>
|
||||||
|
<li>Something went wrong while writing the file</li>
|
||||||
|
<li>There's an application error preventing you from persisting the configuration</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Details can be seen in your application log (if you don't have access to this file, call your administrator in this case).
|
||||||
|
<br/>
|
||||||
|
In case you can access the configuration file (config/dashboard/dashboard.ini) by yourself, you can open it and
|
||||||
|
insert the config manually:
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
<?= $this->escape($this->iniConfigurationString) ?>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</p>
|
|
@ -1,11 +0,0 @@
|
||||||
[test]
|
|
||||||
title = "test"
|
|
||||||
[test.test]
|
|
||||||
url = "test"
|
|
||||||
|
|
||||||
[test.test2]
|
|
||||||
url = "test2"
|
|
||||||
|
|
||||||
[test.dsgdgs]
|
|
||||||
url = "dsdsgdsg"
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# The dashboard
|
||||||
|
|
||||||
|
The icingaweb dashboard allows you to display different views on one page. You can create customized overviews over
|
||||||
|
the objects you're interested in and can add and remove elements.
|
||||||
|
|
||||||
|
## Dashboard, Panes and Components
|
||||||
|
|
||||||
|
![Dashboard structure][dashboards1]
|
||||||
|
|
||||||
|
* The building blocks of dashboards are components - those represent a single URL and display it's content (often in
|
||||||
|
a more condensed layout)
|
||||||
|
* Different components can be added to a pane and will be shown their. All panes are shown as tabs on top of the dashboard,
|
||||||
|
whereas the title is used for the text in the tab
|
||||||
|
* The dashboard itself is just the view containing the panes
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration files
|
||||||
|
|
||||||
|
By default, the config/dashboard/dashboard.ini is used for storing dashboards in the following format:
|
||||||
|
|
||||||
|
[PaneName] ; Define a new Pane
|
||||||
|
title = "PaneTitle" ; The title of the pane as displayed in the tabls
|
||||||
|
|
||||||
|
[PaneName.Component1] ; Define a new component 'Component 1' underneat the pane
|
||||||
|
url = "/url/for/component1" ; the url that will be displayed, with view=compact as URL parameter appended
|
||||||
|
height = "500px" ; optional height setting
|
||||||
|
width = "400px" ; optional width setting
|
||||||
|
|
||||||
|
[test.My hosts] ; Another component, here with host
|
||||||
|
url = "monitoring/list/hosts" ; the url of the component
|
||||||
|
; Notice the missing height/width definition
|
||||||
|
|
||||||
|
[test.My services] ; And another pane
|
||||||
|
url = "monitoring/list/services" ; With service url
|
||||||
|
|
||||||
|
[test2] ; Define a second pane
|
||||||
|
title = "test2" ; with the title
|
||||||
|
|
||||||
|
[test2.test] ; Add a component to the second pane
|
||||||
|
url = "/monitoring/show/host/host1" ; ...and define it's url
|
||||||
|
|
||||||
|
|
||||||
|
[dashboards1]: res/Dashboard.png
|
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
|
@ -48,7 +48,7 @@ class Dimension
|
||||||
private $unit = self::UNIT_PX;
|
private $unit = self::UNIT_PX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Dimension object with the given size and unit
|
* Create a new Dimension object with the given size and unit
|
||||||
*
|
*
|
||||||
* @param int $value The new value
|
* @param int $value The new value
|
||||||
* @param string $unit The unit to use (default: px)
|
* @param string $unit The unit to use (default: px)
|
||||||
|
@ -71,7 +71,7 @@ class Dimension
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true when the value is > 0
|
* Return true when the value is > 0
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
@ -81,7 +81,7 @@ class Dimension
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying value without unit information
|
* Return the underlying value without unit information
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +91,17 @@ class Dimension
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns this value with it's according unit as a string
|
* Return the unit used for the value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUnit()
|
||||||
|
{
|
||||||
|
return $this->unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return this value with it's according unit as a string
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -103,12 +113,19 @@ class Dimension
|
||||||
return $this->value.$this->unit;
|
return $this->value.$this->unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Dimension object from a string containing the numeric value and the dimension (e.g. 200px, 20%)
|
||||||
|
*
|
||||||
|
* @param $string The string to parse
|
||||||
|
*
|
||||||
|
* @return Dimension
|
||||||
|
*/
|
||||||
public static function fromString($string)
|
public static function fromString($string)
|
||||||
{
|
{
|
||||||
$matches = array();
|
$matches = array();
|
||||||
if (!preg_match_all('/^ *([0-9]+)(px|pt|em|\%) */i', $string, $matches)) {
|
if (!preg_match_all('/^ *([0-9]+)(px|pt|em|\%) */i', $string, $matches)) {
|
||||||
throw new InvalidArgumentException($string.' is not a valid dimension');
|
return new Dimension(0);
|
||||||
}
|
}
|
||||||
return new Dimension(intval($matches[1]), $matches[2]);
|
return new Dimension(intval($matches[1][0]), $matches[2][0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,80 +12,121 @@ use Icinga\Web\Widget\Dashboard\Component as DashboardComponent;
|
||||||
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dashboards display multiple views on a single page
|
||||||
|
*
|
||||||
|
* The terminology is as follows:
|
||||||
|
* - Component: A single view showing a specific url
|
||||||
|
* - Pane: Aggregates one or more components on one page, displays it's title as a tab
|
||||||
|
* - Dashboard: Shows all panes
|
||||||
|
*
|
||||||
|
*/
|
||||||
class Dashboard implements Widget
|
class Dashboard implements Widget
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
* The configuration containing information about this dashboard
|
||||||
|
*
|
||||||
* @var IcingaConfig;
|
* @var IcingaConfig;
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
private $configfile;
|
|
||||||
|
/**
|
||||||
|
* An array containing all panes of this dashboard
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
private $panes = array();
|
private $panes = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The @see Icinga\Web\Widget\Tabs object for displaying displayable panes
|
||||||
|
*
|
||||||
|
* @var Tabs
|
||||||
|
*/
|
||||||
private $tabs;
|
private $tabs;
|
||||||
|
|
||||||
private $url = null;
|
/**
|
||||||
|
* The parameter that will be added to identify panes
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $tabParam = 'pane';
|
private $tabParam = 'pane';
|
||||||
|
|
||||||
|
/**
|
||||||
public function __construct()
|
* Set the given tab name as active.
|
||||||
{
|
*
|
||||||
if ($this->url === null) {
|
* @param string $name The tab name to activate
|
||||||
$this->url = Url::fromRequest()->getUrlWithout($this->tabParam);
|
*
|
||||||
}
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public function activate($name)
|
public function activate($name)
|
||||||
{
|
{
|
||||||
$this->getTabs()->activate($name);
|
$this->getTabs()->activate($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tab object used to navigate through this dashboard
|
||||||
|
*
|
||||||
|
* @return Tabs
|
||||||
|
*/
|
||||||
public function getTabs()
|
public function getTabs()
|
||||||
{
|
{
|
||||||
|
$url = Url::fromRequest()->getUrlWithout($this->tabParam);
|
||||||
if ($this->tabs === null) {
|
if ($this->tabs === null) {
|
||||||
$this->tabs = new Tabs();
|
$this->tabs = new Tabs();
|
||||||
foreach ($this->panes as $key => $pane) {
|
foreach ($this->panes as $key => $pane) {
|
||||||
|
|
||||||
$this->tabs->add($key, array(
|
$this->tabs->add($key, array(
|
||||||
'title' => $pane->getTitle(),
|
'title' => $pane->getTitle(),
|
||||||
'url' => clone($this->url),
|
'url' => clone($url),
|
||||||
'urlParams' => array($this->tabParam => $key)
|
'urlParams' => array($this->tabParam => $key)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->tabs;
|
return $this->tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isWritable()
|
/**
|
||||||
{
|
* Store the current dashboard with all it's panes and components to the given file (or the default one if none is
|
||||||
return is_writable($this->configfile);
|
* given)
|
||||||
}
|
*
|
||||||
|
*
|
||||||
|
* @param string $file The filename to store this dashboard as an ini
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
* @throws \Icinga\Exception\ConfigurationError If persisting fails, details are written to the log
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function store($file = null)
|
public function store($file = null)
|
||||||
{
|
{
|
||||||
if ($file === null) {
|
if ($file === null) {
|
||||||
$file = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
|
$file = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
|
||||||
}
|
}
|
||||||
$this->configfile = $file;
|
|
||||||
if (!$this->isWritable()) {
|
if (!is_writable($file)) {
|
||||||
Logger::error("Tried to persist dashboard to %s, but path is not writeable", $this->configfile);
|
Logger::error('Tried to persist dashboard to %s, but path is not writeable', $file);
|
||||||
throw new ConfigurationError('Can\'t persist dashboard');
|
throw new ConfigurationError('Can\'t persist dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! @file_put_contents($this->configfile, $this->toIni())) {
|
if (! @file_put_contents($file, $this->toIni())) {
|
||||||
$error = error_get_last();
|
$error = error_get_last();
|
||||||
if ($error == NULL) {
|
if ($error == NULL) {
|
||||||
$error = "Unknown error";
|
$error = 'Unknown error';
|
||||||
} else {
|
} else {
|
||||||
$error = $error["message"];
|
$error = $error['message'];
|
||||||
}
|
}
|
||||||
Logger::error("Tried to persist dashboard to %s, but got error: %s", $this->configfile, $error);
|
Logger::error('Tried to persist dashboard to %s, but got error: %s', $file, $error);
|
||||||
throw new ConfigurationError('Can\'t persist dashboard');
|
throw new ConfigurationError('Can\'t persist dashboard');
|
||||||
} else {
|
} else {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate this dashboard via the given configuration file
|
||||||
|
*
|
||||||
|
* @param IcingaConfig $config The configuration file to populate this dashboard with
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function readConfig(IcingaConfig $config)
|
public function readConfig(IcingaConfig $config)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
@ -94,6 +135,11 @@ class Dashboard implements Widget
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty pane with the given title
|
||||||
|
*
|
||||||
|
* @param $title
|
||||||
|
*/
|
||||||
public function createPane($title)
|
public function createPane($title)
|
||||||
{
|
{
|
||||||
$pane = new Pane($title);
|
$pane = new Pane($title);
|
||||||
|
@ -102,12 +148,22 @@ class Dashboard implements Widget
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update or adds a new component with the given url to a pane
|
||||||
|
*
|
||||||
|
* @TODO: Should only allow component objects to be added directly as soon as we store more information
|
||||||
|
*
|
||||||
|
* @param string $pane The pane to add the component to
|
||||||
|
* @param Component|string $component The component to add or the title of the newly created component
|
||||||
|
* @param $url The url to use for the component
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function setComponentUrl($pane, $component, $url)
|
public function setComponentUrl($pane, $component, $url)
|
||||||
{
|
{
|
||||||
if ($component === null && strpos($pane, '.')) {
|
if ($component === null && strpos($pane, '.')) {
|
||||||
list($pane, $component) = preg_split('~\.~', $pane, 2);
|
list($pane, $component) = preg_split('~\.~', $pane, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->panes[$pane])) {
|
if (!isset($this->panes[$pane])) {
|
||||||
$this->createPane($pane);
|
$this->createPane($pane);
|
||||||
}
|
}
|
||||||
|
@ -120,6 +176,13 @@ class Dashboard implements Widget
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if a pane doesn't exist or doesn't have any components in it
|
||||||
|
*
|
||||||
|
* @param string $pane The name of the pane to check for emptyness
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function isEmptyPane($pane)
|
public function isEmptyPane($pane)
|
||||||
{
|
{
|
||||||
$paneObj = $this->getPane($pane);
|
$paneObj = $this->getPane($pane);
|
||||||
|
@ -130,6 +193,15 @@ class Dashboard implements Widget
|
||||||
return !empty($cmps);
|
return !empty($cmps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a component $component from the given pane
|
||||||
|
*
|
||||||
|
* @param string $pane The pane to remove the component from
|
||||||
|
* @param Component|string $component The component to remove or it's name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function removeComponent($pane, $component)
|
public function removeComponent($pane, $component)
|
||||||
{
|
{
|
||||||
if ($component === null && strpos($pane, '.')) {
|
if ($component === null && strpos($pane, '.')) {
|
||||||
|
@ -143,6 +215,11 @@ class Dashboard implements Widget
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array with pane name=>title format used for comboboxes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getPaneKeyTitleArray()
|
public function getPaneKeyTitleArray()
|
||||||
{
|
{
|
||||||
$list = array();
|
$list = array();
|
||||||
|
@ -152,24 +229,26 @@ class Dashboard implements Widget
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getComponentEnum()
|
/**
|
||||||
{
|
* Add a pane object to this dashboard
|
||||||
$list = array();
|
*
|
||||||
foreach ($this->panes as $name => $pane) {
|
* @param Pane $pane The pane to add
|
||||||
foreach ($pane->getComponents() as $component) {
|
*
|
||||||
$list[$name . '.' . $component->getTitle()] =
|
* @return $this
|
||||||
$pane->getTitle() . ': ' . $component->getTitle();
|
*/
|
||||||
}
|
|
||||||
}
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPane(Pane $pane)
|
public function addPane(Pane $pane)
|
||||||
{
|
{
|
||||||
$this->panes[$pane->getName()] = $pane;
|
$this->panes[$pane->getName()] = $pane;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the pane with the provided name or null if it doesn't exit
|
||||||
|
*
|
||||||
|
* @param string $name The name of the pane to return
|
||||||
|
*
|
||||||
|
* @return null|Pane The pane or null if no pane with the given name exists
|
||||||
|
*/
|
||||||
public function getPane($name)
|
public function getPane($name)
|
||||||
{
|
{
|
||||||
if (!isset($this->panes[$name]))
|
if (!isset($this->panes[$name]))
|
||||||
|
@ -177,15 +256,22 @@ class Dashboard implements Widget
|
||||||
return $this->panes[$name];
|
return $this->panes[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Icinga\Web\Widget::render
|
||||||
|
*/
|
||||||
public function render(\Zend_View_Abstract $view)
|
public function render(\Zend_View_Abstract $view)
|
||||||
{
|
{
|
||||||
if (empty($this->panes)) {
|
if (empty($this->panes)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
return $this->determineActivePane()->render($view);
|
||||||
return $this->getActivePane()->render($view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates the default pane of this dashboard and returns it's name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
private function setDefaultPane()
|
private function setDefaultPane()
|
||||||
{
|
{
|
||||||
reset($this->panes);
|
reset($this->panes);
|
||||||
|
@ -194,7 +280,12 @@ class Dashboard implements Widget
|
||||||
return $active;
|
return $active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActivePane()
|
/**
|
||||||
|
* Determine the active pane either by the selected tab or the current request
|
||||||
|
*
|
||||||
|
* @return Pane The currently active pane
|
||||||
|
*/
|
||||||
|
public function determineActivePane()
|
||||||
{
|
{
|
||||||
$active = $this->getTabs()->getActiveName();
|
$active = $this->getTabs()->getActiveName();
|
||||||
if (! $active) {
|
if (! $active) {
|
||||||
|
@ -211,6 +302,11 @@ class Dashboard implements Widget
|
||||||
return $this->panes[$active];
|
return $this->panes[$active];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ini string describing this dashboard
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toIni()
|
public function toIni()
|
||||||
{
|
{
|
||||||
$ini = '';
|
$ini = '';
|
||||||
|
@ -220,22 +316,23 @@ class Dashboard implements Widget
|
||||||
return $ini;
|
return $ini;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadConfigPanes()
|
/**
|
||||||
|
* Load all config panes from @see Dashboard::$config
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function loadConfigPanes()
|
||||||
{
|
{
|
||||||
$items = $this->config;
|
$items = $this->config;
|
||||||
$app = Icinga::app();
|
|
||||||
foreach ($items->keys() as $key) {
|
foreach ($items->keys() as $key) {
|
||||||
$item = $this->config->get($key, false);
|
$item = $this->config->get($key, false);
|
||||||
if (false === strstr($key, '.')) {
|
if (false === strstr($key, '.')) {
|
||||||
$this->addPane(Pane::fromIni($key, $item));
|
$this->addPane(Pane::fromIni($key, $item));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
list($paneName, $title) = explode('.', $key , 2);
|
list($paneName, $title) = explode('.', $key, 2);
|
||||||
$pane = $this->getPane($paneName);
|
$pane = $this->getPane($paneName);
|
||||||
$pane->addComponent(DashboardComponent::fromIni($title, $item, $pane));
|
$pane->addComponent(DashboardComponent::fromIni($title, $item, $pane));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,49 @@ use Zend_Config;
|
||||||
/**
|
/**
|
||||||
* A dashboard pane component
|
* A dashboard pane component
|
||||||
*
|
*
|
||||||
* Needs a title and an URL
|
* This is the element displaying a specific view in icinga2web
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class Component implements Widget
|
class Component implements Widget
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The url of this Component
|
||||||
|
*
|
||||||
|
* @var \Icinga\Web\Url
|
||||||
|
*/
|
||||||
private $url;
|
private $url;
|
||||||
private $title;
|
|
||||||
private $width;
|
|
||||||
private $height;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The title being displayed on top of the component
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the component, if set
|
||||||
|
*
|
||||||
|
* @var Dimension|null
|
||||||
|
*/
|
||||||
|
private $width = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the component, if set
|
||||||
|
*
|
||||||
|
* @var Dimension|null
|
||||||
|
*/
|
||||||
|
private $height = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pane containing this component, needed for the 'remove button'
|
||||||
* @var Pane
|
* @var Pane
|
||||||
*/
|
*/
|
||||||
private $pane;
|
private $pane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template string used for rendering this widget
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $template =<<<'EOD'
|
private $template =<<<'EOD'
|
||||||
|
|
||||||
<div class="icinga-container dashboard" icingatitle="{TITLE}" style="{DIMENSION}">
|
<div class="icinga-container dashboard" icingatitle="{TITLE}" style="{DIMENSION}">
|
||||||
|
@ -39,7 +67,13 @@ class Component implements Widget
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new component displaying the given url in the provided pane
|
||||||
|
*
|
||||||
|
* @param string $title The title to use for this component
|
||||||
|
* @param Url|string $url The url this component uses for displaying information
|
||||||
|
* @param Pane $pane The pane this Component will be added to
|
||||||
|
*/
|
||||||
public function __construct($title, $url, Pane $pane)
|
public function __construct($title, $url, Pane $pane)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
|
@ -51,18 +85,28 @@ EOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the with for this component or use the default width if null is provided
|
||||||
|
*
|
||||||
|
* @param Dimension|null $width The width to use or null to use the default width
|
||||||
|
*/
|
||||||
public function setWidth(Dimension $width = null)
|
public function setWidth(Dimension $width = null)
|
||||||
{
|
{
|
||||||
$this->width = $width;
|
$this->width = $width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the with for this component or use the default height if null is provided
|
||||||
|
*
|
||||||
|
* @param Dimension|null $height The height to use or null to use the default height
|
||||||
|
*/
|
||||||
public function setHeight(Dimension $height = null)
|
public function setHeight(Dimension $height = null)
|
||||||
{
|
{
|
||||||
$this->height = $height;
|
$this->height = $height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve this components title
|
* Retrieve the components title
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -72,7 +116,7 @@ EOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve my url
|
* Retrieve the components url
|
||||||
*
|
*
|
||||||
* @return Url
|
* @return Url
|
||||||
*/
|
*/
|
||||||
|
@ -82,10 +126,11 @@ EOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this components URL
|
* Set the components URL
|
||||||
*
|
*
|
||||||
* @param string|Url $url Component URL
|
* @param string|Url $url The url to use, either as an Url object or as a path
|
||||||
* @return self
|
*
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setUrl($url)
|
public function setUrl($url)
|
||||||
{
|
{
|
||||||
|
@ -97,35 +142,29 @@ EOD;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function iniPair($key, $val)
|
/**
|
||||||
{
|
* Return this component in a suitable format and encoding for ini files
|
||||||
return sprintf(
|
*
|
||||||
"%s = %s\n",
|
* @return string
|
||||||
$key,
|
*/
|
||||||
$this->quoteIni($val)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function quoteIni($str)
|
|
||||||
{
|
|
||||||
return '"' . $str . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toIni()
|
public function toIni()
|
||||||
{
|
{
|
||||||
$ini = $this->iniPair('url', $this->url->getRelativeUrl());
|
$ini = 'url = "'.$this->url->getRelativeUrl().'"'.PHP_EOL;
|
||||||
foreach ($this->url->getParams() as $key => $val) {
|
foreach ($this->url->getParams() as $key => $val) {
|
||||||
$ini .= $this->iniPair($key, $val);
|
$ini .= $key.' = "'.$val.'"'.PHP_EOL;
|
||||||
}
|
}
|
||||||
if ($this->height !== null) {
|
if ($this->height !== null) {
|
||||||
$ini .= 'height: '.((string) $this->height).'\n';
|
$ini .= 'height = "'.((string) $this->height).'"'.PHP_EOL;
|
||||||
}
|
}
|
||||||
if ($this->width !== null) {
|
if ($this->width !== null) {
|
||||||
$ini .= 'width: '.((string) $this->width).'\n';
|
$ini .= 'width = "'.((string) $this->width).'"'.PHP_EOL;
|
||||||
}
|
}
|
||||||
return $ini;
|
return $ini;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Widget::render()
|
||||||
|
*/
|
||||||
public function render(\Zend_View_Abstract $view)
|
public function render(\Zend_View_Abstract $view)
|
||||||
{
|
{
|
||||||
$url = clone($this->url);
|
$url = clone($this->url);
|
||||||
|
@ -141,14 +180,18 @@ EOD;
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
$html = str_replace("{URL}", $url->getAbsoluteUrl(), $this->template);
|
$html = str_replace("{URL}", $url->getAbsoluteUrl(), $this->template);
|
||||||
$html = str_replace("{REMOVE_URL}", $removeUrl, $html);
|
$html = str_replace("{REMOVE_URL}", $removeUrl, $html);
|
||||||
$html = str_replace("{STYLE}", $this->getBoxSizeAsCSS(), $html);
|
$html = str_replace("{DIMENSION}", $this->getBoxSizeAsCSS(), $html);
|
||||||
$html = str_replace("{TITLE}", $view->escape($this->getTitle()), $html);
|
$html = str_replace("{TITLE}", $view->escape($this->getTitle()), $html);
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the height and width deifnition (if given) in CSS format
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getBoxSizeAsCSS()
|
private function getBoxSizeAsCSS()
|
||||||
{
|
{
|
||||||
$style = "";
|
$style = "";
|
||||||
|
@ -158,8 +201,18 @@ EOD;
|
||||||
if ($this->width) {
|
if ($this->width) {
|
||||||
$style .= 'width:'.(string) $this->width.';';
|
$style .= 'width:'.(string) $this->width.';';
|
||||||
}
|
}
|
||||||
|
return $style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a @see Component instance from the given Zend config, using the provided title
|
||||||
|
*
|
||||||
|
* @param $title The title for this component
|
||||||
|
* @param Zend_Config $config The configuration defining url, parameters, height, width, etc.
|
||||||
|
* @param Pane $pane The pane this component belongs to
|
||||||
|
*
|
||||||
|
* @return Component A newly created Component for use in the Dashboard
|
||||||
|
*/
|
||||||
public static function fromIni($title, Zend_Config $config, Pane $pane)
|
public static function fromIni($title, Zend_Config $config, Pane $pane)
|
||||||
{
|
{
|
||||||
$height = null;
|
$height = null;
|
||||||
|
|
|
@ -7,39 +7,97 @@ use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Web\Widget\Widget;
|
use Icinga\Web\Widget\Widget;
|
||||||
use Zend_Config;
|
use Zend_Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pane, displaying different Dashboard components
|
||||||
|
*
|
||||||
|
*/
|
||||||
class Pane implements Widget
|
class Pane implements Widget
|
||||||
{
|
{
|
||||||
protected $name;
|
/**
|
||||||
protected $title;
|
* The name of this pane, as defined in the ini file
|
||||||
protected $components = array();
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title of this pane, as displayed in the dashboard tabs
|
||||||
|
* @TODO: Currently the same as $name, evaluate if distinguishing is needed
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of @see Components that are displayed in this pane
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $components = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new pane
|
||||||
|
*
|
||||||
|
* @param $name The pane to create
|
||||||
|
*/
|
||||||
public function __construct($name)
|
public function __construct($name)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->title = $name;
|
$this->title = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of this pane
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title of this pane
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getTitle()
|
public function getTitle()
|
||||||
{
|
{
|
||||||
return $this->title;
|
return $this->title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite the title of this pane
|
||||||
|
*
|
||||||
|
* @param string $title The new title to use for this pane
|
||||||
|
* @return Pane $this
|
||||||
|
*/
|
||||||
public function setTitle($title)
|
public function setTitle($title)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if a component with the given title exists in this pane
|
||||||
|
*
|
||||||
|
* @param string $title The title of the component to check for existence
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function hasComponent($title)
|
public function hasComponent($title)
|
||||||
{
|
{
|
||||||
return array_key_exists($title, $this->components);
|
return array_key_exists($title, $this->components);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a component with the given name if existing
|
||||||
|
*
|
||||||
|
* @param string $title The title of the component to return
|
||||||
|
*
|
||||||
|
* @return Component The component with the given title
|
||||||
|
* @throws ProgrammingError If the component doesn't exist
|
||||||
|
*/
|
||||||
public function getComponent($title)
|
public function getComponent($title)
|
||||||
{
|
{
|
||||||
if ($this->hasComponent($title)) {
|
if ($this->hasComponent($title)) {
|
||||||
|
@ -51,6 +109,12 @@ class Pane implements Widget
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the component with the given title if it exists in this pane
|
||||||
|
*
|
||||||
|
* @param string $title The pane
|
||||||
|
* @return Pane $this
|
||||||
|
*/
|
||||||
public function removeComponent($title)
|
public function removeComponent($title)
|
||||||
{
|
{
|
||||||
if ($this->hasComponent($title)) {
|
if ($this->hasComponent($title)) {
|
||||||
|
@ -59,11 +123,19 @@ class Pane implements Widget
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all components added at this pane
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getComponents()
|
public function getComponents()
|
||||||
{
|
{
|
||||||
return $this->components;
|
return $this->components;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Widget::render
|
||||||
|
*/
|
||||||
public function render(\Zend_View_Abstract $view)
|
public function render(\Zend_View_Abstract $view)
|
||||||
{
|
{
|
||||||
$html = PHP_EOL;
|
$html = PHP_EOL;
|
||||||
|
@ -73,6 +145,15 @@ class Pane implements Widget
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a component to this pane, optionally creating it if $component is a string
|
||||||
|
*
|
||||||
|
* @param string|Component $component The component object or title (if a new component will be created)
|
||||||
|
* @param string|null $url An Url to be used when component is a string
|
||||||
|
*
|
||||||
|
* @return Pane $this
|
||||||
|
* @throws \Icinga\Exception\ConfigurationError
|
||||||
|
*/
|
||||||
public function addComponent($component, $url = null)
|
public function addComponent($component, $url = null)
|
||||||
{
|
{
|
||||||
if ($component instanceof Component) {
|
if ($component instanceof Component) {
|
||||||
|
@ -80,24 +161,24 @@ class Pane implements Widget
|
||||||
} elseif (is_string($component) && $url !== null) {
|
} elseif (is_string($component) && $url !== null) {
|
||||||
$this->components[$component] = new Component($component, $url, $this);
|
$this->components[$component] = new Component($component, $url, $this);
|
||||||
} else{
|
} else{
|
||||||
throw new ConfigurationError('You messed up your dashboard');
|
throw new ConfigurationError('Invalid component added: '.$component);
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function quoteIni($str)
|
/**
|
||||||
{
|
* Return the ini representation of this pane as a string
|
||||||
return '"' . $str . '"';
|
*
|
||||||
}
|
* @return string
|
||||||
|
*/
|
||||||
public function toIni()
|
public function toIni()
|
||||||
{
|
{
|
||||||
if (empty($this->components))
|
if (empty($this->components))
|
||||||
{
|
{
|
||||||
return "";
|
return '';
|
||||||
}
|
}
|
||||||
$ini = '['.$this->getName().']'.PHP_EOL.
|
$ini = '['.$this->getName().']'.PHP_EOL.
|
||||||
'title = '.$this->quoteIni($this->getTitle()).PHP_EOL;
|
'title = "'.$this->getTitle().'"'.PHP_EOL;
|
||||||
|
|
||||||
foreach ($this->components as $title => $component) {
|
foreach ($this->components as $title => $component) {
|
||||||
// component header
|
// component header
|
||||||
|
@ -108,6 +189,14 @@ class Pane implements Widget
|
||||||
return $ini;
|
return $ini;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new pane with the title $title from the given configuration
|
||||||
|
*
|
||||||
|
* @param $title The title for this pane
|
||||||
|
* @param Zend_Config $config The configuration to use for setup
|
||||||
|
*
|
||||||
|
* @return Pane
|
||||||
|
*/
|
||||||
public static function fromIni($title, Zend_Config $config)
|
public static function fromIni($title, Zend_Config $config)
|
||||||
{
|
{
|
||||||
$pane = new Pane($title);
|
$pane = new Pane($title);
|
||||||
|
|
|
@ -60,6 +60,8 @@ class Monitoring_ListController extends ModuleActionController
|
||||||
$state_column = 'service_hard_state';
|
$state_column = 'service_hard_state';
|
||||||
$state_change_column = 'service_last_hard_state_change';
|
$state_change_column = 'service_last_hard_state_change';
|
||||||
}
|
}
|
||||||
|
$this->compactView = "services-compact";
|
||||||
|
|
||||||
|
|
||||||
$this->view->services = $this->query('status', array(
|
$this->view->services = $this->query('status', array(
|
||||||
'host_name',
|
'host_name',
|
||||||
|
|
Loading…
Reference in New Issue