Support _dashlet parameter

* It's bound to the `Window` object
* If there's a request header, it's set
* If there's a request param, it's set
* It's preserved trough redirects not changing the path
* If no redirect happens, a response header is set
* JS accepts the response header always, maintains a data-attribute
* JS transmits it in a request header, if it's not GET and not changing the path
This commit is contained in:
Johannes Meyer 2022-04-25 12:00:44 +02:00
parent efcd14ce0a
commit 84373cdf34
5 changed files with 78 additions and 3 deletions

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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;

View File

@ -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 = $('<div>' + req.responseText + '</div>'); // div helps getting an XML tree

View File

@ -231,7 +231,8 @@
'data-icinga-refresh': $col.data('icingaRefresh'),
'data-last-update': $col.data('lastUpdate'),
'data-icinga-module': $col.data('icingaModule'),
'data-icinga-container-id': $col[0].dataset.icingaContainerId
'data-icinga-container-id': $col[0].dataset.icingaContainerId,
'data-icinga-dashlet-id': $col[0].dataset.icingaDashletId
},
'class': $col.attr('class')
};
@ -242,6 +243,7 @@
$col.removeData('lastUpdate');
$col.removeData('icingaModule');
delete $col[0].dataset.icingaContainerId;
delete $col[0].dataset.icingaDashletId;
$col.removeAttr('class').attr('class', 'container');
return props;
},
@ -255,6 +257,10 @@
$col.data('lastUpdate', backup['data']['data-last-update']);
$col.data('icingaModule', backup['data']['data-icinga-module']);
$col[0].dataset.icingaContainerId = backup['data']['data-icinga-container-id'];
if (backup['data']['data-icinga-dashlet-id']) {
$col[0].dataset.icingaDashletId = backup['data']['data-icinga-dashlet-id'];
}
},
triggerWindowResize: function () {
@ -342,6 +348,7 @@
$c.removeData('lastUpdate');
$c.removeData('icingaModule');
delete $c[0].dataset.icingaContainerId;
delete $c[0].dataset.icingaDashletId;
$c.removeAttr('class').attr('class', 'container');
this.icinga.loader.stopPendingRequestsFor($c);
$c.trigger('close-column');