js: Enhance server side container closing (#5065)

* Let response header `X-Icinga-Container` either influence a request's
`$target` or `$redirectTarget`, but not both

* Issuing a `__CLOSE__` in a detail url still closes `#col2` and
refreshes `#col1`
* Issuing a `__CLOSE__` for a nested container still empties it
* Issuing a `__CLOSE__` in a modal, now refreshes the modal openers
container (now also `#col1`)
This commit is contained in:
Johannes Meyer 2023-08-11 16:07:38 +02:00 committed by GitHub
commit 243192ba93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 18 deletions

View File

@ -40,7 +40,7 @@
var $a = $(event.currentTarget); var $a = $(event.currentTarget);
var url = $a.attr('href'); var url = $a.attr('href');
var $modal = _this.$ghost.clone(); var $modal = _this.$ghost.clone();
var $urlTarget = _this.icinga.loader.getLinkTargetFor($a, false); var $redirectTarget = $a.closest('.container');
_this.modalOpener = event.currentTarget; _this.modalOpener = event.currentTarget;
@ -50,8 +50,8 @@
// Add showCompact, we don't want controls in a modal // Add showCompact, we don't want controls in a modal
url = _this.icinga.utils.addUrlFlag(url, 'showCompact'); url = _this.icinga.utils.addUrlFlag(url, 'showCompact');
// Set the toggle's base target on the modal to use it as redirect target // Set the toggle's container to use it as redirect target
$modal.data('redirectTarget', $urlTarget); $modal.data('redirectTarget', $redirectTarget);
// Final preparations, the id is required so that it's not `display:none` anymore // Final preparations, the id is required so that it's not `display:none` anymore
$modal.attr('id', 'modal'); $modal.attr('id', 'modal');
@ -68,7 +68,7 @@
if (req.status >= 500) { if (req.status >= 500) {
// Yes, that's done twice (by us and by the base fail handler), // Yes, that's done twice (by us and by the base fail handler),
// but `renderContentToContainer` does too many useful things.. // but `renderContentToContainer` does too many useful things..
_this.icinga.loader.renderContentToContainer(req.responseText, $urlTarget, req.action); _this.icinga.loader.renderContentToContainer(req.responseText, $redirectTarget, req.action);
} else if (req.status > 0) { } else if (req.status > 0) {
var msg = $(req.responseText).find('.error-message').text(); var msg = $(req.responseText).find('.error-message').text();
if (msg && msg !== errorThrown) { if (msg && msg !== errorThrown) {
@ -115,7 +115,6 @@
var req = _this.icinga.loader.submitForm($form, $autoSubmittedBy, $button); var req = _this.icinga.loader.submitForm($form, $autoSubmittedBy, $button);
req.addToHistory = false; req.addToHistory = false;
req.$redirectTarget = $modal.data('redirectTarget');
req.done(function (data, textStatus, req) { req.done(function (data, textStatus, req) {
var title = req.getResponseHeader('X-Icinga-Title'); var title = req.getResponseHeader('X-Icinga-Title');
if (!! title) { if (!! title) {
@ -129,6 +128,10 @@
delete $modal[0].dataset.noIcingaAjax; delete $modal[0].dataset.noIcingaAjax;
}); });
if (! ('baseTarget' in $form[0].dataset)) {
req.$redirectTarget = $modal.data('redirectTarget');
}
if (typeof $autoSubmittedBy === 'undefined') { if (typeof $autoSubmittedBy === 'undefined') {
// otherwise the form is submitted several times by clicking the "Submit" button several times // otherwise the form is submitted several times by clicking the "Submit" button several times
$form.find('input[type=submit],button[type=submit],button:not([type])').prop('disabled', true); $form.find('input[type=submit],button[type=submit],button:not([type])').prop('disabled', true);

View File

@ -565,24 +565,35 @@
return true; return true;
} else if (redirect.match(/__CLOSE__/)) { } else if (redirect.match(/__CLOSE__/)) {
if (req.$redirectTarget.is('#col1')) { if (req.$target.is('#col1') && req.$redirectTarget.is('#col1')) {
icinga.logger.warn('Cannot close #col1'); icinga.logger.warn('Cannot close #col1');
return false; return false;
} }
if (req.$redirectTarget.is('.container') && req.$redirectTarget.parent().closest('.container').length > 0) { if (req.$redirectTarget.is('.container') && ! req.$redirectTarget.is('#main > :scope')) {
// If it is a container that is not a top level container, we just empty it // If it is a container that is not a top level container, we just empty it
req.$redirectTarget.empty(); req.$redirectTarget.empty();
return true; return true;
} }
if (! req.$redirectTarget.is('#col2')) {
icinga.logger.debug('Cannot close container', req.$redirectTarget);
return false;
}
// Close right column as requested // Close right column as requested
icinga.ui.layout1col(); icinga.ui.layout1col();
if (!! req.getResponseHeader('X-Icinga-Extra-Updates')) {
icinga.logger.debug('Not refreshing #col1 due to outstanding extra updates');
return true;
}
// Refresh left column and produce a new history state for it // Refresh left column and produce a new history state for it
var $col1 = $('#col1'); let $refreshTarget = $('#col1');
var col1Url = icinga.history.getCol1State(); let refreshUrl = icinga.history.getCol1State();
var refresh = this.loadUrl(col1Url, $col1); let refresh = this.loadUrl(refreshUrl, $refreshTarget);
refresh.addToHistory = true;
refresh.scripted = true; refresh.scripted = true;
var _this = this; var _this = this;
@ -590,7 +601,7 @@
// TODO: Find a better solution than a hardcoded one // TODO: Find a better solution than a hardcoded one
// This is still the *cheat* to get live results // This is still the *cheat* to get live results
// (in case there's a delay and a change is not instantly effective) // (in case there's a delay and a change is not instantly effective)
var secondRefresh = _this.loadUrl(col1Url, $col1); var secondRefresh = _this.loadUrl(refreshUrl, $refreshTarget);
if (secondRefresh !== refresh) { if (secondRefresh !== refresh) {
// Only change these properties if it's not still the first refresh // Only change these properties if it's not still the first refresh
secondRefresh.addToHistory = false; secondRefresh.addToHistory = false;
@ -699,6 +710,7 @@
var target = req.getResponseHeader('X-Icinga-Container'); var target = req.getResponseHeader('X-Icinga-Container');
var newBody = false; var newBody = false;
var oldNotifications = false; var oldNotifications = false;
var isRedirect = !! req.getResponseHeader('X-Icinga-Redirect');
if (target) { if (target) {
if (target === 'ignore') { if (target === 'ignore') {
return; return;
@ -706,17 +718,26 @@
var $newTarget = this.identifyLinkTarget(target, req.$target); var $newTarget = this.identifyLinkTarget(target, req.$target);
if ($newTarget.length) { if ($newTarget.length) {
// If we change the target, oncomplete will fail to clean up if (isRedirect) {
// This fixes the problem, not using req.$target would be better req.$redirectTarget = $newTarget;
delete this.requests[req.$target.attr('id')]; } else {
// If we change the target, oncomplete will fail to clean up.
// This fixes the problem, not using req.$target would be better
delete this.requests[req.$target.attr('id')];
req.$target = $newTarget; req.$target = $newTarget;
req.$redirectTarget = $newTarget; }
if (target === 'layout') { if (target === 'layout') {
oldNotifications = $('#notifications li').detach(); oldNotifications = $('#notifications li').detach();
this.icinga.ui.layout1col(); this.icinga.ui.layout1col();
newBody = true; newBody = true;
} else if ($newTarget.attr('id') === 'col2') {
if (_this.icinga.ui.isOneColLayout()) {
_this.icinga.ui.layout2col();
} else if (target === '_next') {
_this.icinga.ui.moveToLeft();
}
} }
} }
} }
@ -735,7 +756,7 @@
this.icinga.ui.reloadCss(); this.icinga.ui.reloadCss();
} }
if (req.getResponseHeader('X-Icinga-Redirect')) { if (isRedirect) {
return; return;
} }
@ -993,7 +1014,18 @@
return; return;
} }
_this.loadUrl(url, $target).addToHistory = false; if (url === '__CLOSE__') {
if ($target.is('#col2')) {
_this.icinga.ui.layout1col();
} else if ($target.is('#main > :scope')) {
_this.icinga.logger.warn('Invalid target ID. Cannot close ', $target);
} else if ($target.is('.container')) {
// If it is a container that is not a top level container, we just empty it
$target.empty();
}
} else {
_this.loadUrl(url, $target).addToHistory = false;
}
}); });
} }