diff --git a/application/controllers/AuthenticationController.php b/application/controllers/AuthenticationController.php
index e0a3e6b8d..d500f23e6 100644
--- a/application/controllers/AuthenticationController.php
+++ b/application/controllers/AuthenticationController.php
@@ -84,6 +84,8 @@ class AuthenticationController extends ActionController
}
}
+
+
/**
* Action handle logout
*/
diff --git a/application/controllers/ConfigurationController.php b/application/controllers/ConfigurationController.php
index ae895695c..334d0a3e8 100644
--- a/application/controllers/ConfigurationController.php
+++ b/application/controllers/ConfigurationController.php
@@ -28,7 +28,7 @@
use Icinga\Application\Benchmark;
use Icinga\Authentication\Manager;
use Icinga\Web\ActionController;
-use Icinga\Web\Hook\Configuration\ConfigurationTab;
+use Icinga\Web\Widget\Tabs;
use Icinga\Web\Hook\Configuration\ConfigurationTabBuilder;
/**
@@ -48,11 +48,10 @@ class ConfigurationController extends ActionController
public function indexAction()
{
$tabBuilder = new ConfigurationTabBuilder(
- $this->widget('tabs')
+ new Tabs()
);
$tabBuilder->build();
-
$this->view->tabs = $tabBuilder->getTabs();
}
}
diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php
new file mode 100644
index 000000000..2182fb793
--- /dev/null
+++ b/application/controllers/DashboardController.php
@@ -0,0 +1,141 @@
+
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author Icinga Development Team
+ */
+// {{{ICINGA_LICENSE_HEADER}}}
+
+use Icinga\Web\ActionController;
+use Icinga\Web\Url;
+use Icinga\Application\Icinga;
+use Icinga\Web\Widget\Dashboard;
+use Icinga\Config\Config as IcingaConfig;
+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
+{
+
+ /**
+ * 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')
+ {
+ $dashboard = new Dashboard();
+ $dashboard->readConfig(IcingaConfig::app($config));
+ return $dashboard;
+ }
+
+ /**
+ * Remove a component from the pane identified by the 'pane' parameter
+ *
+ */
+ public function removecomponentAction()
+ {
+ $pane = $this->_getParam('pane');
+ $dashboard = $this->getDashboard();
+ try {
+ $dashboard->removeComponent(
+ $pane,
+ $this->_getParam('component')
+ )->store();
+ $this->redirectNow(Url::fromPath('dashboard', array('pane' => $pane)));
+ } catch (ConfigurationError $exc ) {
+
+ $this->_helper->viewRenderer('show_configuration');
+ $this->view->exceptionMessage = $exc->getMessage();
+ $this->view->iniConfigurationString = $dashboard->toIni();
+ }
+ }
+
+
+ /**
+ * Display the form for adding new components or add the new component if submitted
+ *
+ */
+ public function addurlAction()
+ {
+ $form = new AddUrlForm();
+ $form->setRequest($this->_request);
+ $this->view->form = $form;
+
+ if ($form->isSubmittedAndValid()) {
+ $dashboard = $this->getDashboard();
+ $dashboard->setComponentUrl(
+ $form->getValue('pane'),
+ $form->getValue('component'),
+ ltrim($form->getValue('url'), '/')
+ );
+ try {
+ $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()
+ {
+ $dashboard = $this->getDashboard();
+
+ if ($this->_getParam('pane')) {
+ $pane = $this->_getParam('pane');
+ $dashboard->activate($pane);
+ }
+ $this->view->tabs = $dashboard->getTabs();
+ $this->view->tabs->add(
+ 'Add',
+ array(
+ 'title' => 'Add Url',
+ 'iconCls' => 'plus',
+ 'url' => Url::fromPath('dashboard/addurl')
+ )
+ );
+ $this->view->dashboard = $dashboard;
+ }
+}
+
+// @codingStandardsIgnoreEnd
\ No newline at end of file
diff --git a/application/controllers/ModulesController.php b/application/controllers/ModulesController.php
index 9fb215978..fc5fdfdaf 100644
--- a/application/controllers/ModulesController.php
+++ b/application/controllers/ModulesController.php
@@ -33,8 +33,7 @@
use Icinga\Web\ActionController;
use Icinga\Application\Icinga;
use Icinga\Web\Hook\Configuration\ConfigurationTabBuilder;
-use Icinga\Application\Modules\Manager as ModuleManager;
-use Zend_Controller_Action as ZfActionController;
+use Icinga\Web\Widget\Tabs;
/**
* Handle module depending frontend actions
@@ -60,9 +59,7 @@ class ModulesController extends ActionController
*/
public function indexAction()
{
- $tabBuilder = new ConfigurationTabBuilder(
- $this->widget('tabs')
- );
+ $tabBuilder = new ConfigurationTabBuilder(new Tabs());
$tabBuilder->build();
diff --git a/application/controllers/StaticController.php b/application/controllers/StaticController.php
index 7e1ebb5ae..bb86e60ef 100644
--- a/application/controllers/StaticController.php
+++ b/application/controllers/StaticController.php
@@ -72,8 +72,9 @@ class StaticController extends ActionController
public function imgAction()
{
- $module = $this->_getParam('moduleName');
+ $module = $this->_getParam('module_name');
$file = $this->_getParam('file');
+
$basedir = Icinga::app()->getModuleManager()->getModule($module)->getBaseDir();
$filePath = $basedir . '/public/img/' . $file;
@@ -102,7 +103,7 @@ class StaticController extends ActionController
) . ' GMT');
readfile($filePath);
- $this->_viewRenderer->setNoRender();
+ return;
}
public function javascriptAction()
@@ -110,17 +111,16 @@ class StaticController extends ActionController
$module = $this->_getParam('module_name');
$file = $this->_getParam('file');
+ if (!Icinga::app()->getModuleManager()->hasEnabled($module)) {
+ echo "/** Module not enabled **/";
+ return;
+ }
$basedir = Icinga::app()->getModuleManager()->getModule($module)->getBaseDir();
$filePath = $basedir . '/public/js/' . $file;
if (!file_exists($filePath)) {
- throw new ActionException(
- sprintf(
- '%s does not exist',
- $filePath
- ),
- 404
- );
+ echo "/** Module has no js files **/";
+ return;
}
$hash = md5_file($filePath);
$response = $this->getResponse();
@@ -143,7 +143,8 @@ class StaticController extends ActionController
} else {
readfile($filePath);
}
- $this->_viewRenderer->setNoRender();
+
+ return;
}
}
diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php
new file mode 100644
index 000000000..571891ac7
--- /dev/null
+++ b/application/forms/Dashboard/AddUrlForm.php
@@ -0,0 +1,136 @@
+ 'Dashboard',
+ 'required' => true,
+ 'style' => 'display:inline-block',
+ 'multiOptions' => $dashboard->getPaneKeyTitleArray()
+ )
+ );
+
+ $newDashboardBtn = new Zend_Form_Element_Submit(
+ 'create_new_pane',
+ array(
+ 'label' => '+',
+ 'required' => false,
+ 'style' => 'display:inline-block'
+ )
+ );
+
+ $newDashboardBtn->removeDecorator('DtDdWrapper');
+ $selectPane->removeDecorator('DtDdWrapper');
+ $selectPane->removeDecorator('htmlTag');
+
+
+ $this->addElement($selectPane);
+ $this->addElement($newDashboardBtn);
+ $this->enableAutoSubmit(array('create_new_pane'));
+ }
+
+ /**
+ * Add a textfield for creating a new pane to this form
+ *
+ */
+ private function addNewPaneTextField()
+ {
+ $txtCreatePane = new Zend_Form_Element_Text(
+ 'pane',
+ array(
+ 'label' => 'New dashboard title',
+ 'required' => true,
+ 'style' => 'display:inline-block'
+ )
+ );
+
+ // Marks this field as a new pane (and prevents the checkbox being displayed when validation errors occur)
+ $markAsNewPane = new Zend_Form_Element_Hidden(
+ 'create_new_pane',
+ array(
+ 'required' => true,
+ 'value' => 1
+ )
+ );
+
+ $cancelDashboardBtn = new Zend_Form_Element_Submit(
+ 'use_existing_dashboard',
+ array(
+ 'label' => 'X',
+ 'required' => false,
+ 'style' => 'display:inline-block'
+ )
+ );
+
+ $cancelDashboardBtn->removeDecorator('DtDdWrapper');
+ $txtCreatePane->removeDecorator('DtDdWrapper');
+ $txtCreatePane->removeDecorator('htmlTag');
+
+ $this->addElement($txtCreatePane);
+ $this->addElement($cancelDashboardBtn);
+ $this->addElement($markAsNewPane);
+ }
+
+ /**
+ * Add elements to this form (used by extending classes)
+ *
+ */
+ protected function create()
+ {
+ $dashboard = new Dashboard();
+ $dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
+ $this->addElement(
+ 'text',
+ 'url',
+ array(
+ 'label' => 'Url',
+ 'required' => true,
+ )
+ );
+ $elems = $dashboard->getPaneKeyTitleArray();
+
+ if (empty($elems) || // show textfield instead of combobox when no pane is available
+ ($this->getRequest()->getPost('create_new_pane', '0') && // or when a new pane should be created (+ button)
+ !$this->getRequest()->getPost('use_existing_dashboard', '0')) // and the user didn't click the 'use existing' button
+ ) {
+ $this->addNewPaneTextField();
+ } else {
+ $this->addPaneSelectionBox($dashboard);
+ }
+
+ $this->addElement(
+ 'text',
+ 'component',
+ array(
+ 'label' => 'Title',
+ 'required' => true,
+ )
+ );
+ $this->setSubmitLabel("Add to dashboard");
+ }
+}
diff --git a/application/views/scripts/configuration/index.phtml b/application/views/scripts/configuration/index.phtml
index 75703c7c9..e6445410a 100644
--- a/application/views/scripts/configuration/index.phtml
+++ b/application/views/scripts/configuration/index.phtml
@@ -1,4 +1,5 @@
-= $this->tabs; ?>
+= $this->tabs->render($this); ?>
+
Configuration
diff --git a/application/views/scripts/dashboard/addurl.phtml b/application/views/scripts/dashboard/addurl.phtml
new file mode 100644
index 000000000..c8653ae32
--- /dev/null
+++ b/application/views/scripts/dashboard/addurl.phtml
@@ -0,0 +1,3 @@
+
Add dashboard URL
+
+= $this->form->render($this); ?>
\ No newline at end of file
diff --git a/application/views/scripts/dashboard/index.phtml b/application/views/scripts/dashboard/index.phtml
new file mode 100644
index 000000000..6b1e5c9bb
--- /dev/null
+++ b/application/views/scripts/dashboard/index.phtml
@@ -0,0 +1,3 @@
+= $this->tabs->render($this); ?>
+
+= $this->dashboard->render($this); ?>
\ No newline at end of file
diff --git a/application/views/scripts/dashboard/show-configuration.phtml b/application/views/scripts/dashboard/show-configuration.phtml
new file mode 100644
index 000000000..d7421e5d1
--- /dev/null
+++ b/application/views/scripts/dashboard/show-configuration.phtml
@@ -0,0 +1,29 @@
+
+
+
Saving dashboard failed
+
+
+ Your dashboard couldn't be stored (error: "= $this->exceptionMessage; ?>"). This could have one or more
+ of the following reasons:
+
+
+
You don't have permissions to write to the dashboard file
+
Something went wrong while writing the file
+
There's an application error preventing you from persisting the configuration
+
+
+
+
+ Details can be seen in your application log (if you don't have access to this file, call your administrator in this case).
+
+ In case you can access the configuration file (config/dashboard/dashboard.ini) by yourself, you can open it and
+ insert the config manually:
+
+
\n";
- return $htm;
+ if (isset($parameters['width'])) {
+ $width = Dimension::fromString($parameters['width']);
+ unset($parameters['width']);
+ }
+
+ $cmp = new Component($title, Url::fromPath($url, $parameters), $pane);
+ $cmp->setHeight($height);
+ $cmp->setWidth($width);
+ return $cmp;
}
}
diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php
index c57aaf5d2..a5ada7056 100644
--- a/library/Icinga/Web/Widget/Dashboard/Pane.php
+++ b/library/Icinga/Web/Widget/Dashboard/Pane.php
@@ -1,54 +1,145 @@
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author Icinga Development Team
+ */
+// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Widget\Dashboard;
-use Icinga\Web\Url;
use Icinga\Exception\ConfigurationError;
+use Icinga\Exception\ProgrammingError;
+use Icinga\Web\Widget\Widget;
+use Zend_Config;
+use Zend_View_Abstract;
-class Pane
+/**
+ * A pane, displaying different Dashboard components
+ *
+ */
+class Pane implements Widget
{
- protected $name;
- protected $title;
- protected $components = array();
+ /**
+ * The name of this pane, as defined in the ini file
+ *
+ * @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)
{
$this->name = $name;
$this->title = $name;
}
+ /**
+ * Returns the name of this pane
+ *
+ * @return string
+ */
public function getName()
{
return $this->name;
}
+ /**
+ * Returns the title of this pane
+ *
+ * @return string
+ */
public function getTitle()
{
return $this->title;
}
+ /**
+ * Overwrite the title of this pane
+ *
+ * @param string $title The new title to use for this pane
+ *
+ * @return self
+ */
public function setTitle($title)
{
$this->title = $title;
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)
{
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)
{
if ($this->hasComponent($title)) {
return $this->components[$title];
}
- throw new ProgrammingError(sprintf(
- 'Trying to access invalid component: %s',
- $title
- ));
+ throw new ProgrammingError(sprintf('Trying to access invalid component: %s', $title));
}
+ /**
+ * 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)
{
if ($this->hasComponent($title)) {
@@ -57,48 +148,86 @@ class Pane
return $this;
}
+ /**
+ * Return all components added at this pane
+ *
+ * @return array
+ */
public function getComponents()
{
return $this->components;
}
-
+
+ /**
+ * @see Widget::render
+ */
+ public function render(Zend_View_Abstract $view)
+ {
+ $html = PHP_EOL;
+ foreach ($this->components as $component) {
+ $html .= PHP_EOL.$component->render($view);
+ }
+ 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 self
+ * @throws \Icinga\Exception\ConfigurationError
+ */
public function addComponent($component, $url = null)
{
if ($component instanceof Component) {
- $this->components[$component->title] = $component;
+ $this->components[$component->getTitle()] = $component;
} elseif (is_string($component) && $url !== null) {
- $this->components[$component] = new Component($component, $url);
- } else{
- throw new ConfigurationError('You messed up your dashboard');
+ $this->components[$component] = new Component($component, $url, $this);
+ } else {
+ throw new ConfigurationError('Invalid component added: ' . $component);
}
return $this;
}
- protected function quoteIni($str)
- {
- return '"' . $str . '"';
- }
-
+ /**
+ * Return the ini representation of this pane as a string
+ *
+ * @return string
+ */
public function toIni()
{
- $ini = sprintf(
- "[%s]\ntitle = %s\n",
- $this->getName(),
- $this->quoteIni($this->getTitle())
- ) . "\n";
+ if (empty($this->components)) {
+ return '';
+ }
+ $ini = '[' . $this->getName() . ']' . PHP_EOL.
+ 'title = "' . $this->getTitle() . '"' . PHP_EOL;
foreach ($this->components as $title => $component) {
- $ini .= sprintf(
- "[%s.%s]\n",
- $this->getName(),
- $title
- ) . $component->toIni() . "\n";
+ // component header
+ $ini .= '[' . $this->getName() . '.' . $title . ']' . PHP_EOL;
+ // component content
+ $ini .= $component->toIni() . PHP_EOL;
}
return $ini;
}
- public function __toString()
+ /**
+ * 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)
{
- return implode('', $this->components);
+ $pane = new Pane($title);
+ if ($config->get('title', false)) {
+ $pane->setTitle($config->get('title'));
+ }
+ return $pane;
}
}
diff --git a/library/Icinga/Web/Widget/Form.php b/library/Icinga/Web/Widget/Form.php
deleted file mode 100644
index 50525b21c..000000000
--- a/library/Icinga/Web/Widget/Form.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- * @author Icinga-Web Team
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
- */
-class Form extends AbstractWidget
-{
- protected $form;
- protected $properties = array(
- 'name' => null,
- 'options' => null
- );
-
- public function __call($func, $args)
- {
- return call_user_func_array(array($this->form, $func), $args);
- }
-
- protected function init()
- {
- // Load form by name given in props:
- $file = null;
- $fparts = array();
- $cparts = array();
- foreach (preg_split('~/~', $this->name, -1, PREG_SPLIT_NO_EMPTY) as $part) {
- $fparts[] = $part;
- $cparts[] = ucfirst($part);
- }
- array_push($fparts, ucfirst(array_pop($fparts)));
-
- $app = Icinga::app();
- $module_name = $this->view()->module_name;
- if ($module_name === 'default') {
- $module_name = null;
- }
- if ($module_name !== null) {
- $fname = $app->getModuleManager()->getModule($module_name)->getBaseDir()
- . '/application/forms/'
- . implode('/', $fparts)
- . 'Form.php';
- if (file_exists($fname)) {
- $file = $fname;
- array_unshift($cparts, ucfirst($module_name));
- }
- }
-
- if ($file === null) {
- $fname = $app->getApplicationDir('forms/')
- . implode('/', $fparts)
- . 'Form.php';
- if (file_exists($fname)) {
- $file = $fname;
- } else {
- throw new ProgrammingError(sprintf(
- 'Unable to load your form: %s',
- $this->name
- ));
- }
- }
- $class = 'Icinga\\Web\\Form\\' . implode('_', $cparts) . 'Form';
- require_once($file);
- $this->form = new $class($this->options);
- }
-
- public function renderAsHtml()
- {
- return (string) $this->form;
- }
-}
diff --git a/library/Icinga/Web/Widget/Tab.php b/library/Icinga/Web/Widget/Tab.php
index a8ea47f68..7393ea2ff 100644
--- a/library/Icinga/Web/Widget/Tab.php
+++ b/library/Icinga/Web/Widget/Tab.php
@@ -1,11 +1,35 @@
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author Icinga Development Team
*/
+// {{{ICINGA_LICENSE_HEADER}}}
+
namespace Icinga\Web\Widget;
use Icinga\Exception\ProgrammingError;
+use Zend_View_Abstract;
/**
* A single tab, usually used through the tabs widget
@@ -24,41 +48,141 @@ use Icinga\Exception\ProgrammingError;
* @author Icinga-Web Team
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
*/
-class Tab extends AbstractWidget
+class Tab implements Widget
{
/**
* Whether this tab is currently active
*
* @var bool
*/
- protected $active = false;
+ private $active = false;
/**
* Default values for widget properties
*
* @var array
*/
- protected $properties = array(
- 'name' => null,
- 'title' => '',
- 'url' => null,
- 'urlParams' => array(),
- 'icon' => null,
- );
+ private $name = null;
/**
- * Health check at initialization time
+ * The title displayed for this tab
*
- * @throws Icinga\Exception\ProgrammingError if tab name is missing
- *
- * @return void
+ * @var string
*/
- protected function init()
+ private $title = '';
+
+ /**
+ * The Url this tab points to
+ *
+ * @var string|null
+ */
+ private $url = null;
+
+ /**
+ * The parameters for this tab's Url
+ *
+ * @var array
+ */
+ private $urlParams = array();
+
+ /**
+ * The icon image to use for this tab or null if none
+ *
+ * @var string|null
+ */
+ private $icon = null;
+
+ /**
+ * The icon class to use if $icon is null
+ *
+ * @var string|null
+ */
+ private $iconCls = null;
+
+
+ /**
+ * Sets an icon image for this tab
+ *
+ * @param string $icon The url of the image to use
+ */
+ public function setIcon($icon)
{
+ $this->icon = $icon;
+ }
+
+ /**
+ * Set's an icon class that will be used in an tag if no icon image is set
+ *
+ * @param string $iconCls The CSS class of the icon to use
+ */
+ public function setIconCls($iconCls)
+ {
+ $this->iconCls = $iconCls;
+ }
+
+
+ /**
+ * @param mixed $name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @param mixed $title
+ */
+ public function setTitle($title)
+ {
+ $this->title = $title;
+ }
+
+ /**
+ * Set the Url this tab points to
+ *
+ * @param string $url The Url to use for this tab
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ }
+
+
+ /**
+ * Set the parameters to be set for this tabs Url
+ *
+ * @param array $url The Url parameters to set
+ */
+ public function setUrlParams(array $urlParams)
+ {
+ $this->urlParams = $urlParams;
+ }
+
+ /**
+ * Create a new Tab with the given properties
+ *
+ * Allowed properties are all properties for which a setter exists
+ *
+ * @param array $properties An array of properties
+ */
+ public function __construct(array $properties = array())
+ {
+ foreach ($properties as $name => $value) {
+ $setter = 'set' . ucfirst($name);
+ if (method_exists($this, $setter)) {
+ $this->$setter($value);
+ }
+ }
if ($this->name === null) {
- throw new ProgrammingError(
- 'Cannot create a nameless tab'
- );
+ throw new ProgrammingError('Cannot create a nameless tab');
}
}
@@ -78,31 +202,24 @@ class Tab extends AbstractWidget
return $this;
}
- /**
- * Whether this tab is currently active
- *
- * @return bool
- */
- public function isActive()
- {
- return $this->active;
- }
/**
- * This is where the list item HTML is created
- *
- * @return string
+ * @see Widget::render()
*/
- public function renderAsHtml()
+ public function render(Zend_View_Abstract $view)
{
- $view = $this->view();
- $class = $this->isActive() ? ' class="active"' : '';
+ $class = $this->active ? ' class="active"' : '';
$caption = $this->title;
if ($this->icon !== null) {
- $caption = $view->img($this->icon, array(
- 'width' => 16,
- 'height' => 16
- )) . ' ' . $caption;
+ $caption = $view->img(
+ $this->icon,
+ array(
+ 'width' => 16,
+ 'height' => 16
+ )
+ ) . ' ' . $caption;
+ } elseif ($this->iconCls !== null) {
+ $caption = ' ' . $caption;
}
if ($this->url !== null) {
$tab = $view->qlink(
@@ -114,6 +231,7 @@ class Tab extends AbstractWidget
} else {
$tab = $caption;
}
- return "
$tab
\n";
+
+ return '
' . $tab . '
' . PHP_EOL;
}
}
diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php
index 8e9c3483d..9ddc6cd13 100644
--- a/library/Icinga/Web/Widget/Tabs.php
+++ b/library/Icinga/Web/Widget/Tabs.php
@@ -1,8 +1,31 @@
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author Icinga Development Team
*/
+// {{{ICINGA_LICENSE_HEADER}}}
+
namespace Icinga\Web\Widget;
use Icinga\Exception\ProgrammingError;
@@ -13,36 +36,37 @@ use Countable;
/**
* Navigation tab widget
*
- * Useful if you want to create navigation tabs
- *
- * @copyright Copyright (c) 2013 Icinga-Web Team
- * @author Icinga-Web Team
- * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
*/
-class Tabs extends AbstractWidget implements Countable
+class Tabs implements Countable, Widget
{
/**
* This is where single tabs added to this container will be stored
*
* @var array
*/
- protected $tabs = array();
+ private $tabs = array();
/**
* The name of the currently activated tab
*
* @var string
*/
- protected $active;
+ private $active;
/**
* Class name(s) going to be assigned to the <ul> element
*
* @var string
*/
- protected $tab_class = 'nav-tabs';
+ private $tab_class = 'nav-tabs';
- protected $specialActions = false;
+ /**
+ * Array when special actions (dropdown) are enabled
+ * @TODO: Remove special part from tabs (Bug #4512)
+ *
+ * @var bool|array
+ */
+ private $specialActions = false;
/**
* Activate the tab with the given name
@@ -77,6 +101,11 @@ class Tabs extends AbstractWidget implements Countable
);
}
+ /**
+ * Return the name of the active tab
+ *
+ * @return string
+ */
public function getActiveName()
{
return $this->active;
@@ -118,7 +147,7 @@ class Tabs extends AbstractWidget implements Countable
*/
public function get($name)
{
- if (! $this->has($name)) {
+ if (!$this->has($name)) {
throw new ProgrammingError(
sprintf(
'There is no such tab: %s',
@@ -177,6 +206,13 @@ class Tabs extends AbstractWidget implements Countable
return $this;
}
+ /**
+ * Enable special actions (dropdown with format, basket and dashboard)
+ *
+ * @TODO: Remove special part from tabs (Bug #4512)
+ *
+ * @return $this
+ */
public function enableSpecialActions()
{
$this->specialActions = true;
@@ -184,52 +220,49 @@ class Tabs extends AbstractWidget implements Countable
}
/**
- * This is where the tabs are going to be rendered
- *
- * @return string
+ * @see Widget::render
*/
- public function renderAsHtml()
+ public function render(\Zend_View_Abstract $view)
{
- $view = $this->view();
-
if (empty($this->tabs)) {
return '';
}
- $html = '
' . "\n";
+ $html = '
' . PHP_EOL;
foreach ($this->tabs as $tab) {
- $html .= $tab;
+ $html .= $tab->render($view);
}
+ // @TODO: Remove special part from tabs (Bug #4512)
$special = array();
- $special[] = $this->view()->qlink(
- $this->view()->img('img/classic/application-pdf.png') . ' PDF',
+ $special[] = $view->qlink(
+ $view->img('img/classic/application-pdf.png') . ' PDF',
Url::fromRequest(),
array('filetype' => 'pdf'),
array('target' => '_blank', 'quote' => false)
);
- $special[] = $this->view()->qlink(
- $this->view()->img('img/classic/application-csv.png') . ' CSV',
+ $special[] = $view->qlink(
+ $view->img('img/classic/application-csv.png') . ' CSV',
Url::fromRequest(),
array('format' => 'csv'),
array('target' => '_blank', 'quote' => false)
);
- $special[] = $this->view()->qlink(
- $this->view()->img('img/classic/application-json.png') . ' JSON',
+ $special[] = $view->qlink(
+ $view->img('img/classic/application-json.png') . ' JSON',
Url::fromRequest(),
array('format' => 'json', 'quote' => false),
array('target' => '_blank', 'quote' => false)
);
- $special[] = $this->view()->qlink(
- $this->view()->img('img/classic/basket.png') . ' URL Basket',
+ $special[] = $view->qlink(
+ $view->img('img/classic/basket.png') . ' URL Basket',
Url::fromPath('basket/add'),
array('url' => Url::fromRequest()->getRelativeUrl()),
array('quote' => false)
);
- $special[] = $this->view()->qlink(
- $this->view()->img('img/classic/dashboard.png') . ' Dashboard',
+ $special[] = $view->qlink(
+ $view->img('img/classic/dashboard.png') . ' Dashboard',
Url::fromPath('dashboard/addurl'),
array('url' => Url::fromRequest()->getRelativeUrl()),
array('quote' => false)
@@ -255,11 +288,23 @@ class Tabs extends AbstractWidget implements Countable
return $html;
}
+ /**
+ * Return the number of tabs
+ *
+ * @see Countable
+ *
+ * @return int
+ */
public function count()
{
return count($this->tabs);
}
+ /**
+ * Return all tabs contained in this tab panel
+ *
+ * @return array
+ */
public function getTabs()
{
return $this->tabs;
diff --git a/library/Icinga/Web/Widget/Widget.php b/library/Icinga/Web/Widget/Widget.php
new file mode 100644
index 000000000..ab8157669
--- /dev/null
+++ b/library/Icinga/Web/Widget/Widget.php
@@ -0,0 +1,49 @@
+
+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author Icinga Development Team
+ */
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Web\Widget;
+
+use Icinga\Web\View;
+use Zend_View_Abstract;
+
+/**
+ * Abstract class for reusable view elements that can be
+ * rendered to a view
+ *
+ */
+interface Widget
+{
+ /**
+ * Renders this widget via the given view and returns the
+ * HTML as a string
+ *
+ * @param \Zend_View_Abstract $view
+ * @return string
+ */
+ public function render(Zend_View_Abstract $view);
+}
diff --git a/library/vendor/tcpdf/examples/example_059.php b/library/vendor/tcpdf/examples/example_059.php
index 6e458d5b7..57870bd3f 100755
--- a/library/vendor/tcpdf/examples/example_059.php
+++ b/library/vendor/tcpdf/examples/example_059.php
@@ -5,7 +5,7 @@
// Last Update : 2011-04-15
//
// Description : Example 059 for TCPDF class
-// Table Of Content using HTML templates.
+// Table Of Content using HTML Templates.
//
// Author: Nicola Asuni
//
@@ -19,7 +19,7 @@
/**
* Creates an example PDF TEST document using TCPDF
* @package com.tecnick.tcpdf
- * @abstract TCPDF - Example: Table Of Content using HTML templates.
+ * @abstract TCPDF - Example: Table Of Content using HTML Templates.
* @author Nicola Asuni
* @since 2010-05-06
*/
@@ -153,7 +153,7 @@ $bookmark_templates = array();
/*
* The key of the $bookmark_templates array represent the bookmark level (from 0 to n).
- * The following templates will be replaced with proper content:
+ * The following Templates will be replaced with proper content:
* #TOC_DESCRIPTION# this will be replaced with the bookmark description;
* #TOC_PAGE_NUMBER# this will be replaced with page number.
*
@@ -166,7 +166,7 @@ $bookmark_templates = array();
$bookmark_templates[0] = '
#TOC_DESCRIPTION#
#TOC_PAGE_NUMBER#
';
$bookmark_templates[1] = '
#TOC_DESCRIPTION#
#TOC_PAGE_NUMBER#
';
$bookmark_templates[2] = '
#TOC_DESCRIPTION#
#TOC_PAGE_NUMBER#
';
-// add other bookmark level templates here ...
+// add other bookmark level Templates here ...
// add table of content at page 1
// (check the example n. 45 for a text-only TOC
diff --git a/library/vendor/tcpdf/tcpdf.php b/library/vendor/tcpdf/tcpdf.php
index fccf6b117..c113071a5 100644
--- a/library/vendor/tcpdf/tcpdf.php
+++ b/library/vendor/tcpdf/tcpdf.php
@@ -76,7 +76,7 @@
// dullus for text Justification.
// Bob Vincent (pillarsdotnet@users.sourceforge.net) for
value attribute.
// Patrick Benny for text stretch suggestion on Cell().
-// Johannes Güntert for JavaScript support.
+// Johannes G�ntert for JavaScript support.
// Denis Van Nuffelen for Dynamic Form.
// Jacek Czekaj for multibyte justification
// Anthony Ferrara for the reintroduction of legacy image methods.
@@ -87,7 +87,7 @@
// Mohamad Ali Golkar, Saleh AlMatrafe, Charles Abbott for Arabic and Persian support.
// Moritz Wagner and Andreas Wurmser for graphic functions.
// Andrew Whitehead for core fonts support.
-// Esteban Joël Marín for OpenType font conversion.
+// Esteban Jo�l Mar�n for OpenType font conversion.
// Teus Hagen for several suggestions and fixes.
// Yukihiro Nakadaira for CID-0 CJK fonts fixes.
// Kosmas Papachristos for some CSS improvements.
@@ -647,7 +647,7 @@ class TCPDF {
protected $footer_font;
/**
- * Language templates.
+ * Language Templates.
* @protected
*/
protected $l;
@@ -6123,7 +6123,7 @@ class TCPDF {
* @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
* @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
0: no border (default)
1: frame
or a string containing some or all of the following characters (in any order):
L: left
T: top
R: right
B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
* @return float Return the minimal height needed for multicell method for printing the $txt param.
- * @author Alexander Escalona Fernández, Nicola Asuni
+ * @author Alexander Escalona Fern�ndez, Nicola Asuni
* @public
* @since 4.5.011
*/
@@ -6230,7 +6230,7 @@ class TCPDF {
* @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
* @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
0: no border (default)
1: frame
or a string containing some or all of the following characters (in any order):
L: left
T: top
R: right
B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
* @return float Return the minimal height needed for multicell method for printing the $txt param.
- * @author Nicola Asuni, Alexander Escalona Fernández
+ * @author Nicola Asuni, Alexander Escalona Fern�ndez
* @public
*/
public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
@@ -11442,7 +11442,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bézier control points.
+ * Append a cubic B�zier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the B�zier control points.
* The new current point shall be (x3, y3).
* @param $x1 (float) Abscissa of control point 1.
* @param $y1 (float) Ordinate of control point 1.
@@ -11460,7 +11460,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bézier control points.
+ * Append a cubic B�zier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the B�zier control points.
* The new current point shall be (x3, y3).
* @param $x2 (float) Abscissa of control point 2.
* @param $y2 (float) Ordinate of control point 2.
@@ -11476,7 +11476,7 @@ class TCPDF {
}
/**
- * Append a cubic Bézier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bézier control points.
+ * Append a cubic B�zier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the B�zier control points.
* The new current point shall be (x3, y3).
* @param $x1 (float) Abscissa of control point 1.
* @param $y1 (float) Ordinate of control point 1.
@@ -12271,7 +12271,7 @@ class TCPDF {
/**
* Insert Named Destinations.
* @protected
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G�ntert, Nicola Asuni
* @since 5.9.098 (2011-06-23)
*/
protected function _putdests() {
@@ -12499,7 +12499,7 @@ class TCPDF {
* Adds a javascript
* @param $script (string) Javascript code
* @public
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G�ntert, Nicola Asuni
* @since 2.1.002 (2008-02-12)
*/
public function IncludeJS($script) {
@@ -12528,7 +12528,7 @@ class TCPDF {
/**
* Create a javascript PDF string.
* @protected
- * @author Johannes Güntert, Nicola Asuni
+ * @author Johannes G�ntert, Nicola Asuni
* @since 2.1.002 (2008-02-12)
*/
protected function _putjavascript() {
@@ -13414,7 +13414,7 @@ class TCPDF {
* @param $private_key (mixed) private key (string or filename prefixed with 'file://')
* @param $private_key_password (string) password
* @param $extracerts (string) specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used.
- * @param $cert_type (int) The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature.
+ * @param $cert_type (int) The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page Templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature.
* @param $info (array) array of option information: Name, Location, Reason, ContactInfo.
* @public
* @author Nicola Asuni
@@ -14174,7 +14174,7 @@ class TCPDF {
* @param $col1 (array) first color (Grayscale, RGB or CMYK components).
* @param $col2 (array) second color (Grayscale, RGB or CMYK components).
* @param $coords (array) array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W�rmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14192,7 +14192,7 @@ class TCPDF {
* @param $col1 (array) first color (Grayscale, RGB or CMYK components).
* @param $col2 (array) second color (Grayscale, RGB or CMYK components).
* @param $coords (array) array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W�rmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14215,7 +14215,7 @@ class TCPDF {
* @param $coords_min (array) minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0
* @param $coords_max (array) maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1
* @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W�rmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @public
*/
@@ -14307,7 +14307,7 @@ class TCPDF {
* @param $y (float) ordinate of the top left corner of the rectangle.
* @param $w (float) width of the rectangle.
* @param $h (float) height of the rectangle.
- * @author Andreas Würmser, Nicola Asuni
+ * @author Andreas W�rmser, Nicola Asuni
* @since 3.1.000 (2008-06-09)
* @protected
*/
@@ -21301,13 +21301,13 @@ if (! $size) $size = 10;
}
/**
- * Output a Table Of Content Index (TOC) using HTML templates.
+ * Output a Table Of Content Index (TOC) using HTML Templates.
* This method must be called after all Bookmarks were set.
* Before calling this method you have to open the page using the addTOCPage() method.
* After calling this method you have to call endTOCPage() to close the TOC page.
* @param $page (int) page number where this TOC should be inserted (leave empty for current page).
* @param $toc_name (string) name to use for TOC bookmark.
- * @param $templates (array) array of html templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number.
+ * @param $templates (array) array of html Templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number.
* @param $correct_align (boolean) if true correct the number alignment (numbers must be in monospaced font like courier and right aligned on LTR, or left aligned on RTL)
* @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic.
* @param $color (array) RGB color array for title (values from 0 to 255).
@@ -21352,7 +21352,7 @@ if (! $size) $size = 10;
}
$maxpage = max($maxpage, $outline['p']);
}
- // replace templates with current values
+ // replace Templates with current values
$row = str_replace('#TOC_DESCRIPTION#', $outline['t'], $row);
$row = str_replace('#TOC_PAGE_NUMBER#', $pagenum, $row);
// add link to page
@@ -23300,7 +23300,7 @@ if (! $size) $size = 10;
}
break;
}
- case 'Q': { // quadratic Bézier curveto
+ case 'Q': { // quadratic B�zier curveto
foreach ($params as $ck => $cp) {
$params[$ck] = $cp;
if ((($ck + 1) % 4) == 0) {
@@ -23326,7 +23326,7 @@ if (! $size) $size = 10;
}
break;
}
- case 'T': { // shorthand/smooth quadratic Bézier curveto
+ case 'T': { // shorthand/smooth quadratic B�zier curveto
foreach ($params as $ck => $cp) {
$params[$ck] = $cp;
if (($ck % 2) != 0) {
diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php
index d9698642c..9b3313e8f 100644
--- a/modules/monitoring/application/controllers/ListController.php
+++ b/modules/monitoring/application/controllers/ListController.php
@@ -5,10 +5,12 @@ use Icinga\Web\Hook;
use Icinga\File\Csv;
use Monitoring\Backend;
use Icinga\Application\Benchmark;
+use Icinga\Web\Widget\Tabs;
class Monitoring_ListController extends ModuleActionController
{
protected $backend;
+ private $compactView = null;
public function init()
{
@@ -22,6 +24,7 @@ class Monitoring_ListController extends ModuleActionController
public function hostsAction()
{
Benchmark::measure("hostsAction::query()");
+ $this->compactView = "hosts-compact";
$this->view->hosts = $this->query(
'status',
array(
@@ -57,6 +60,8 @@ class Monitoring_ListController extends ModuleActionController
$state_column = 'service_hard_state';
$state_change_column = 'service_last_hard_state_change';
}
+ $this->compactView = "services-compact";
+
$this->view->services = $this->query('status', array(
'host_name',
@@ -191,6 +196,10 @@ class Monitoring_ListController extends ModuleActionController
protected function handleFormatRequest($query)
{
+ if ($this->compactView !== null && ($this->_getParam('view', false) === 'compact')) {
+ $this->_helper->viewRenderer($this->compactView);
+ }
+
if ($this->_getParam('format') === 'sql') {
echo '
'
. htmlspecialchars(wordwrap($query->getQuery()->dump()))
@@ -213,7 +222,7 @@ class Monitoring_ListController extends ModuleActionController
protected function getTabs()
{
- $tabs = $this->widget('tabs');
+ $tabs = new Tabs();
$tabs->add('services', array(
'title' => 'All services',
'icon' => 'img/classic/service.png',
diff --git a/modules/monitoring/application/controllers/ShowController.php b/modules/monitoring/application/controllers/ShowController.php
index ac08efc07..975da9c6d 100644
--- a/modules/monitoring/application/controllers/ShowController.php
+++ b/modules/monitoring/application/controllers/ShowController.php
@@ -33,6 +33,7 @@ use Icinga\Web\Hook;
use Monitoring\Object\Host;
use Monitoring\Object\Service;
use Icinga\Application\Benchmark;
+use Icinga\Web\Widget\Tabs;
/**
* Class Monitoring_ShowController
*
@@ -425,7 +426,7 @@ class Monitoring_ShowController extends ModuleActionController
protected function createTabs()
{
$object = $this->view->object;
- $tabs = $this->widget('tabs');
+ $tabs = new Tabs();
if (!$this->view->host) {
return $tabs;
}
diff --git a/modules/monitoring/application/controllers/SummaryController.php b/modules/monitoring/application/controllers/SummaryController.php
index e9eb6d952..ead0c22ec 100644
--- a/modules/monitoring/application/controllers/SummaryController.php
+++ b/modules/monitoring/application/controllers/SummaryController.php
@@ -2,6 +2,7 @@
use Icinga\Web\ModuleActionController;
use Icinga\Backend;
+use Icinga\Web\Widget\Tabs;
class Monitoring_SummaryController extends ModuleActionController
{
@@ -18,7 +19,7 @@ class Monitoring_SummaryController extends ModuleActionController
protected function getTabs()
{
- $tabs = $this->widget('tabs');
+ $tabs = new Tabs();
$tabs->add('hostgroup', array(
'title' => 'Hostgroups',
'url' => 'monitoring/summary/group',
diff --git a/modules/monitoring/application/views/scripts/list/contactgroups.phtml b/modules/monitoring/application/views/scripts/list/contactgroups.phtml
index a4841c008..77bef0553 100644
--- a/modules/monitoring/application/views/scripts/list/contactgroups.phtml
+++ b/modules/monitoring/application/views/scripts/list/contactgroups.phtml
@@ -1,4 +1,5 @@
-= $this->tabs ?>
+= $this->tabs->render($this); ?>
+