diff --git a/library/Icinga/Web/Controller/ActionController.php b/library/Icinga/Web/Controller/ActionController.php index 608159971..6852caaf8 100644 --- a/library/Icinga/Web/Controller/ActionController.php +++ b/library/Icinga/Web/Controller/ActionController.php @@ -157,6 +157,11 @@ class ActionController extends Zend_Controller_Action $this->_helper->layout()->disableLayout(); } + if (($dashletId = $this->params->shift('_dashlet')) !== null) { + // Not removed from the request's url because GET requests for the same url should still be tracked + $this->Window()->setDashletId(hex2bin($dashletId)); + } + // $auth->authenticate($request, $response, $this->requiresLogin()); if ($this->requiresLogin()) { if (! $request->isXmlHttpRequest() && $request->isApiRequest()) { diff --git a/library/Icinga/Web/Response.php b/library/Icinga/Web/Response.php index df0b842d5..e59697ed0 100644 --- a/library/Icinga/Web/Response.php +++ b/library/Icinga/Web/Response.php @@ -317,28 +317,44 @@ class Response extends Zend_Controller_Response_Http { $redirectUrl = $this->getRedirectUrl(); if ($this->getRequest()->isXmlHttpRequest()) { + $window = Window::getInstance(); + $dashletId = $window->getDashletId(); + if ($redirectUrl !== null) { if ($this->getRequest()->isGet() && Icinga::app()->getViewRenderer()->view->compact) { $redirectUrl->getParams()->set('showCompact', true); } + if ($dashletId !== null && $this->getRequest()->getUrl()->getPath() === $redirectUrl->getPath()) { + $redirectUrl->getParams()->set('_dashlet', bin2hex($dashletId)); + } + $this->setHeader('X-Icinga-Redirect', rawurlencode($redirectUrl->getAbsoluteUrl()), true); if ($this->getRerenderLayout()) { $this->setHeader('X-Icinga-Rerender-Layout', 'yes', true); } + } else { + if ($dashletId !== null) { + $this->setHeader('X-Icinga-DashletId', bin2hex($dashletId)); + } } + if ($this->getOverrideWindowId()) { - $this->setHeader('X-Icinga-WindowId', Window::getInstance()->getId(), true); + $this->setHeader('X-Icinga-WindowId', $window->getId(), true); } + if ($this->getRerenderLayout()) { $this->setHeader('X-Icinga-Container', 'layout', true); } + if ($this->isWindowReloaded()) { $this->setHeader('X-Icinga-Reload-Window', 'yes', true); } + if ($this->isReloadCss()) { $this->setHeader('X-Icinga-Reload-Css', 'now', true); } + if (($autoRefreshInterval = $this->getAutoRefreshInterval()) !== null) { $this->setHeader('X-Icinga-Refresh', $autoRefreshInterval, true); } diff --git a/library/Icinga/Web/Window.php b/library/Icinga/Web/Window.php index 158483a06..89555ad5c 100644 --- a/library/Icinga/Web/Window.php +++ b/library/Icinga/Web/Window.php @@ -19,6 +19,9 @@ class Window /** @var string */ protected $containerId; + /** @var ?string A dashlet's UUID which the current request is associated with */ + protected $dashletId; + public function __construct($id) { $parts = explode('_', $id, 2); @@ -60,6 +63,28 @@ class Window return $this->containerId ?: $this->id; } + /** + * Get the dashlet's UUID which the current request is associated with + * + * @return ?string + */ + public function getDashletId(): ?string + { + return $this->dashletId; + } + + /** + * Associate the current request with a specific dashlet + * + * @param ?string $dashletId The dashlet's UUID + * + * @return void + */ + public function setDashletId(?string $dashletId): void + { + $this->dashletId = $dashletId; + } + /** * Return a window-aware session by using the given prefix * @@ -111,13 +136,18 @@ class Window public static function getInstance() { if (! isset(static::$window)) { - $id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId'); + $request = Icinga::app()->getRequest(); + $id = $request->getHeader('X-Icinga-WindowId'); if (empty($id) || $id === static::UNDEFINED) { Icinga::app()->getResponse()->setOverrideWindowId(); $id = static::generateId(); } static::$window = new Window($id); + + if (($dashletId = $request->getHeader('X-Icinga-DashletId'))) { + static::$window->setDashletId(hex2bin($dashletId)); + } } return static::$window; diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 8d69fe826..d8c8a9945 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -266,6 +266,15 @@ headers['X-Icinga-Container'] = id; } + if (method !== 'GET' && $target[0].dataset.icingaDashletId) { + let currentUrlPath = this.icinga.utils.parseUrl($target.data('icingaUrl')).path; + let newUrlPath = this.icinga.utils.parseUrl(url).path; + + if (newUrlPath === currentUrlPath) { + headers['X-Icinga-DashletId'] = $target[0].dataset.icingaDashletId; + } + } + if (autorefresh) { headers['X-Icinga-Autorefresh'] = '1'; } @@ -776,6 +785,14 @@ this.icinga.ui.setWindowId(windowId); } + // Preserve the dashlet identifier if available, clean up if not + let dashletId = req.getResponseHeader('X-Icinga-DashletId'); + if (dashletId) { + req.$target[0].dataset.icingaDashletId = decodeURIComponent(dashletId); + } else { + delete req.$target[0].dataset.icingaDashletId; + } + // Handle search requests, still hardcoded. if (req.url.match(/^\/search/) && req.$target.data('icingaUrl').match(/^\/search/)) { var $resp = $('