From 46abb8a36ef20039b8b31385dc29aa9813033d4d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 27 Jun 2013 10:14:15 +0200 Subject: [PATCH] Add library/Icinga/Web/Widget from the incubator refs #4301 --- library/Icinga/Web/Widget/AbstractWidget.php | 12 +- library/Icinga/Web/Widget/Dashboard.php | 195 ++++++++++++++++++ .../Icinga/Web/Widget/Dashboard/Component.php | 117 +++++++++++ library/Icinga/Web/Widget/Dashboard/Pane.php | 105 ++++++++++ library/Icinga/Web/Widget/Form.php | 61 +++++- library/Icinga/Web/Widget/Tab.php | 33 ++- library/Icinga/Web/Widget/Tabs.php | 53 ++++- 7 files changed, 541 insertions(+), 35 deletions(-) create mode 100644 library/Icinga/Web/Widget/Dashboard.php create mode 100644 library/Icinga/Web/Widget/Dashboard/Component.php create mode 100644 library/Icinga/Web/Widget/Dashboard/Pane.php diff --git a/library/Icinga/Web/Widget/AbstractWidget.php b/library/Icinga/Web/Widget/AbstractWidget.php index 81c6b835c..214032413 100644 --- a/library/Icinga/Web/Widget/AbstractWidget.php +++ b/library/Icinga/Web/Widget/AbstractWidget.php @@ -1,7 +1,8 @@ module_name = $module_name; + } foreach ($properties as $key => $val) { $this->$key = $val; } diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php new file mode 100644 index 000000000..964a71e35 --- /dev/null +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -0,0 +1,195 @@ + null, + 'tabParam' => 'pane' + ); + + protected function init() + { + if ($this->url === null) { + $this->url = Url::current()->without($this->tabParam); + } + } + + public function activate($name) + { + $this->tabs()->activate($name); + } + + public function tabs() + { + if ($this->tabs === null) { + $this->tabs = Widget::create('tabs'); + foreach ($this->panes as $key => $pane) { + $this->tabs->add($key, array( + 'title' => $pane->getTitle(), + 'url' => clone($this->url), + 'urlParams' => array($this->tabParam => $key) + )); + } + } + + return $this->tabs; + } + + public function isWritable() + { + return is_writable($this->configfile); + } + + public function store() + { + if (! @file_put_contents($this->configfile, $this->toIni())) { + return false; + } else { + return $this; + } + } + + public function readConfig(ZfConfig $config) + { + $this->configfile = Config::getInstance()->getConfigDir() + . '/dashboard.ini'; + $this->config = $config; + $this->panes = array(); + $this->loadConfigPanes(); + return $this; + } + + public function setComponentUrl($pane, $component, $url) + { + if ($component === null && strpos($pane, '.')) { + list($pane, $component) = preg_split('~\.~', $pane, 2); + } + $pane = $this->getPane($pane); + if ($pane->hasComponent($component)) { + $pane->getComponent($component)->setUrl($url); + } else { + $pane->addComponent($component, $url); + } + return $this; + } + + public function removeComponent($pane, $component) + { + if ($component === null && strpos($pane, '.')) { + list($pane, $component) = preg_split('~\.~', $pane, 2); + } + $this->getPane($pane)->removeComponent($component); + return $this; + } + + public function paneEnum() + { + $list = array(); + foreach ($this->panes as $name => $pane) { + $list[$name] = $pane->getTitle(); + } + return $list; + } + + public function getComponentEnum() + { + $list = array(); + foreach ($this->panes as $name => $pane) { + foreach ($pane->getComponents() as $component) { + $list[$name . '.' . $component->getTitle()] = + $pane->getTitle() . ': ' . $component->getTitle(); + } + } + return $list; + } + + public function addPane(Pane $pane) + { + $this->panes[$pane->getName()] = $pane; + return $this; + } + + public function getPane($name) + { + return $this->panes[$name]; + } + + public function renderAsHtml() + { + if (empty($this->panes)) { + return ''; + } + + return $this->tabs() . $this->getActivePane(); + } + + public function getActivePane() + { + $active = $this->tabs()->getActiveName(); + if (! $active) { + if ($active = Url::current()->getParam($this->tabParam)) { + $this->activate($active); + } else { + reset($this->panes); + $active = key($this->panes); + $this->activate($active); + } + } + + return $this->panes[$active]; + } + + public function toIni() + { + $ini = ''; + foreach ($this->panes as $pane) { + $ini .= $pane->toIni(); + } + return $ini; + } + + protected function loadConfigPanes() + { + $items = $this->config->dashboard->toArray(); + $app = Icinga::app(); + foreach ($items as $key => $item) { + if (false === strstr($key, '.')) { + $pane = new Pane($key); + if (isset($item['title'])) { + $pane->setTitle($item['title']); + } + $this->addPane($pane); + } else { + list($dashboard, $title) = preg_split('~\.~', $key, 2); + $base_url = $item['base_url']; + + $module = substr($base_url, 0, strpos($base_url, '/')); + $whitelist = array(); + if (! $app->hasModule($module)) { + continue; + } + + unset($item['base_url']); + $this->getPane($dashboard)->addComponent( + $title, + Url::create($base_url, $item) + ); + } + } + } +} + diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php new file mode 100644 index 000000000..81fe64d62 --- /dev/null +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -0,0 +1,117 @@ +title = $title; + if ($url instanceof Url) { + $this->url = $url; + } else { + $this->url = Url::create($url); + } + } + + /** + * Retrieve this components title + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Retrieve my url + * + * @return Url + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set this components URL + * + * @param string|Url $url Component URL + * @return self + */ + public function setUrl($url) + { + if ($url instanceof Url) { + $this->url = $url; + } else { + $this->url = Url::create($url); + } + return $this; + } + + protected function iniPair($key, $val) + { + return sprintf( + "%s = %s\n", + $key, + $this->quoteIni($val) + ); + } + + protected function quoteIni($str) + { + return '"' . $str . '"'; + } + + public function toIni() + { + $ini = $this->iniPair('base_url', $this->url->getScript()); + foreach ($this->url->getParams() as $key => $val) { + $ini .= $this->iniPair($key, $val); + } + return $ini; + } + + /** + * Render this components HTML + */ + public function __toString() + { + $url = clone($this->url); + $url->addParams(array('view' => 'compact')); + if (isset($_GET['layout'])) { + $url->addParams(array('layout' => $_GET['layout'])); + } + + $htm = '
' + . "\n" + . '

' + . htmlspecialchars($this->title) + . "

\n" + . '' + . "\n
\n"; + return $htm; + } +} + diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php new file mode 100644 index 000000000..6fee43df6 --- /dev/null +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -0,0 +1,105 @@ +name = $name; + $this->title = $name; + } + + public function getName() + { + return $this->name; + } + + public function getTitle() + { + return $this->title; + } + + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + public function hasComponent($title) + { + return array_key_exists($title, $this->components); + } + + public function getComponent($title) + { + if ($this->hasComponent($title)) { + return $this->components[$title]; + } + throw new ProgrammingError(sprintf( + 'Trying to access invalid component: %s', + $title + )); + } + + public function removeComponent($title) + { + if ($this->hasComponent($title)) { + unset($this->components[$title]); + } + return $this; + } + + public function getComponents() + { + return $this->components; + } + + public function addComponent($component, $url = null) + { + if ($component instanceof Component) { + $this->components[$component->title] = $component; + } elseif (is_string($component) && $url !== null) { + $this->components[$component] = new Component($component, $url); + } else{ + throw new ConfigurationError('You messed up your dashboard'); + } + return $this; + } + + protected function quoteIni($str) + { + return '"' . $str . '"'; + } + + public function toIni() + { + $ini = sprintf( + "[%s]\ntitle = %s\n", + $this->getName(), + $this->quoteIni($this->getTitle()) + ) . "\n"; + + foreach ($this->components as $title => $component) { + $ini .= sprintf( + "[%s.%s]\n", + $this->getName(), + $title + ) . $component->toIni() . "\n"; + } + return $ini; + } + + public function __toString() + { + return implode('', $this->components); + } +} + diff --git a/library/Icinga/Web/Widget/Form.php b/library/Icinga/Web/Widget/Form.php index 9719c4bf7..0c89f0135 100644 --- a/library/Icinga/Web/Widget/Form.php +++ b/library/Icinga/Web/Widget/Form.php @@ -1,22 +1,26 @@ * @author Icinga-Web Team * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License - * @deprecated Because of HTML creation of PHP< */ class Form extends AbstractWidget { protected $form; protected $properties = array( - 'name' => null + 'name' => null, + 'options' => null ); public function __call($func, $args) @@ -26,14 +30,48 @@ class Form extends AbstractWidget protected function init() { - // Load form by name given in props? - $class = 'Icinga\\Web\\Form\\' . ucfirst($this->name) . 'Form'; - $file = ICINGA_APPDIR - . '/forms/authentication/' - . ucfirst($this->name) - . 'Form.php'; + // 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->moduleManager()->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->form = new $class($this->options); } public function renderAsHtml() @@ -41,3 +79,4 @@ class Form extends AbstractWidget return (string) $this->form; } } + diff --git a/library/Icinga/Web/Widget/Tab.php b/library/Icinga/Web/Widget/Tab.php index fa5ce64ed..a8ea47f68 100644 --- a/library/Icinga/Web/Widget/Tab.php +++ b/library/Icinga/Web/Widget/Tab.php @@ -1,7 +1,8 @@ * @author Icinga-Web Team * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License - * @deprecated Because of HTML creation of PHP< */ class Tab extends AbstractWidget { @@ -39,16 +39,18 @@ class Tab extends AbstractWidget * @var array */ protected $properties = array( - 'name' => null, - 'title' => '', - 'url' => null, + 'name' => null, + 'title' => '', + 'url' => null, 'urlParams' => array(), - 'icon' => null, + 'icon' => null, ); /** * Health check at initialization time - * @throws \Icinga\Exception\ProgrammingError if tab name is missing + * + * @throws Icinga\Exception\ProgrammingError if tab name is missing + * * @return void */ protected function init() @@ -72,7 +74,7 @@ class Tab extends AbstractWidget */ public function setActive($active = true) { - $this->active = (bool)$active; + $this->active = (bool) $active; return $this; } @@ -97,15 +99,10 @@ class Tab extends AbstractWidget $class = $this->isActive() ? ' 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; } if ($this->url !== null) { $tab = $view->qlink( diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index b3f4e9593..25e379688 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -1,10 +1,13 @@ * @author Icinga-Web Team * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License - * @deprecated Because of HTML creation of PHP< */ class Tabs extends AbstractWidget { @@ -39,6 +41,8 @@ class Tabs extends AbstractWidget */ protected $tab_class = 'nav-tabs'; + protected $specialActions = false; + /** * Activate the tab with the given name * @@ -172,6 +176,12 @@ class Tabs extends AbstractWidget return $this; } + public function enableSpecialActions() + { + $this->specialActions = true; + return $this; + } + /** * This is where the tabs are going to be rendered * @@ -189,6 +199,43 @@ class Tabs extends AbstractWidget foreach ($this->tabs as $tab) { $html .= $tab; } + + $special = array(); + $special[] = $this->view()->qlink( + 'PDF', + Url::current(), + array('filetype' => 'pdf'), + array('target' => '_blank') + ); + + $special[] = $this->view()->qlink( + 'Basket', + Url::create('basket/add'), + array('url' => Url::current()->getRelative()) + ); + + $special[] = $this->view()->qlink( + 'Dashboard', + Url::create('dashboard/addurl'), + array('url' => Url::current()->getRelative()) + ); + $auth = Auth::getInstance(); + // if ($this->specialActions && ! empty($special) && $auth->isAuthenticated() && $auth->getUsername() === 'admin') { + if ($this->specialActions) { + $html .= ' + + '; + + } $html .= "\n"; return $html; }