mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-05-28 04:36:06 -04:00
migrate.js: Enhance detection of modules with support for Icinga DB
This commit is contained in:
parent
59e3d79c36
commit
a098d7e6fc
4 changed files with 263 additions and 89 deletions
|
|
@ -8,7 +8,6 @@ use Icinga\Application\Config;
|
|||
use Icinga\Module\Icingadb\Forms\SetAsBackendConfigForm;
|
||||
use Icinga\Module\Icingadb\Forms\DatabaseConfigForm;
|
||||
use Icinga\Module\Icingadb\Forms\RedisConfigForm;
|
||||
use Icinga\Module\Icingadb\Forms\SetAsBackendForm;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
|
|
@ -50,11 +49,6 @@ class ConfigController extends Controller
|
|||
|
||||
public function backendAction()
|
||||
{
|
||||
// migration.js
|
||||
(new SetAsBackendForm())
|
||||
->setRedirectUrl('__BACK__')
|
||||
->handleRequest();
|
||||
|
||||
$form = new SetAsBackendConfigForm();
|
||||
$form->handleRequest();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ namespace Icinga\Module\Icingadb\Controllers;
|
|||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Module\Icingadb\Compat\UrlMigrator;
|
||||
use Icinga\Module\Icingadb\Forms\SetAsBackendForm;
|
||||
use Icinga\Module\Icingadb\Hook\IcingadbSupportHook;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Web\Hook;
|
||||
use ipl\Html\HtmlString;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class MigrateController extends Controller
|
||||
|
|
@ -70,4 +73,52 @@ class MigrateController extends Controller
|
|||
->sendResponse();
|
||||
exit;
|
||||
}
|
||||
|
||||
public function checkboxSubmitAction()
|
||||
{
|
||||
$this->assertHttpMethod('post');
|
||||
|
||||
$form = (new SetAsBackendForm())
|
||||
->setOnSuccess(function () use (&$form) {
|
||||
$this->addPart(HtmlString::create('"bogus"'), 'Behavior:Migrate');
|
||||
$form->save($form->getElement('backend')->isChecked());
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
}
|
||||
|
||||
public function backendSupportAction()
|
||||
{
|
||||
$this->assertHttpMethod('post');
|
||||
if (! $this->getRequest()->isApiRequest()) {
|
||||
$this->httpBadRequest('No API request');
|
||||
}
|
||||
|
||||
if (
|
||||
! preg_match('/([^;]*);?/', $this->getRequest()->getHeader('Content-Type'), $matches)
|
||||
|| $matches[1] !== 'application/json'
|
||||
) {
|
||||
$this->httpBadRequest('No JSON content');
|
||||
}
|
||||
|
||||
$supportList = [];
|
||||
foreach (Hook::all('Icingadb/IcingadbSupport') as $hook) {
|
||||
/** @var IcingadbSupportHook $hook */
|
||||
$supportList[$hook->getModule()->getName()] = $hook->supportsIcingaDb();
|
||||
}
|
||||
|
||||
$moduleSupportStates = [];
|
||||
foreach ($this->getRequest()->getPost() as $moduleName) {
|
||||
if (isset($supportList[$moduleName])) {
|
||||
$moduleSupportStates[] = $supportList[$moduleName];
|
||||
} else {
|
||||
$moduleSupportStates[] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->getResponse()
|
||||
->json()
|
||||
->setSuccessData($moduleSupportStates)
|
||||
->sendResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,4 @@ class SetAsBackendForm extends SetAsBackendConfigForm
|
|||
$this->removeElement('btn_submit');
|
||||
$this->removeElement('btn_submit_session');
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$this->save($this->getElement('backend')->isChecked());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@
|
|||
' <button type="button" value="0"><i class="icon-"></i></button>\n' +
|
||||
'</li>';
|
||||
|
||||
const BACKEND_FORM = '<form id="setAsBackendForm" name="IcingaModuleIcingadbFormsSetAsBackendForm" class="icinga-form icinga-controls" method="post" action="icingadb/config/backend">\n' +
|
||||
const BACKEND_FORM = '<form id="setAsBackendForm" name="IcingaModuleIcingadbFormsSetAsBackendForm" ' +
|
||||
'class="icinga-form icinga-controls" method="post" action="icingadb/migrate/checkbox-submit" ' +
|
||||
'data-base-target="migrate-popup-backend-submit-blackhole">\n' +
|
||||
' <div class="wrapper">\n' +
|
||||
' <div class="checkbox-label">\n' +
|
||||
' <span><label for="setAsBackendForm-checkbox">Use Icinga DB As Backend</label></span>\n' +
|
||||
|
|
@ -35,6 +37,7 @@
|
|||
' </label>\n' +
|
||||
' </div>\n' +
|
||||
' <input type="hidden" name="formUID" value="IcingaModuleIcingadbFormsSetAsBackendForm" id="IcingaModuleIcingadbFormsSetAsBackendForm">\n' +
|
||||
' <div id="migrate-popup-backend-submit-blackhole"></div>\n' +
|
||||
'</form>';
|
||||
|
||||
/**
|
||||
|
|
@ -47,13 +50,11 @@
|
|||
|
||||
this.icinga = icinga;
|
||||
this.knownMigrations = {};
|
||||
this.knownBackendSupport = {};
|
||||
this.urlMigrationReadyState = null;
|
||||
this.backendSupportReadyState = null;
|
||||
this.backendSupportRelated = {};
|
||||
this.$popup = null;
|
||||
this.supportedModules = [
|
||||
'/director',
|
||||
'/businessprocess',
|
||||
'/jira/',
|
||||
'/cube/'
|
||||
];
|
||||
|
||||
// Some persistence, we don't want to annoy our users too much
|
||||
this.storage = Icinga.Storage.BehaviorStorage('icingadb.migrate');
|
||||
|
|
@ -63,7 +64,6 @@
|
|||
|
||||
// We don't want to ask the server to migrate non-monitoring urls
|
||||
this.isMonitoringUrl = new RegExp('^' + icinga.config.baseUrl + '/monitoring/');
|
||||
this.isSupportedModule = new RegExp('^' + icinga.config.baseUrl + '(' + this.supportedModules.join('|') +')');
|
||||
this.on('rendered', this.onRendered, this);
|
||||
this.on('close-column', this.onColumnClose, this);
|
||||
this.on('click', '#migrate-popup button.close', this.onClose, this);
|
||||
|
|
@ -74,17 +74,32 @@
|
|||
|
||||
Migrate.prototype = new Icinga.EventListener();
|
||||
|
||||
Migrate.prototype.update = function (data) {
|
||||
if (data !== 'bogus') {
|
||||
return;
|
||||
}
|
||||
|
||||
$.each(this.backendSupportRelated, (id, _) => {
|
||||
let $container = $('#' + id);
|
||||
let req = this.icinga.loader.loadUrl($container.data('icingaUrl'), $container);
|
||||
req.addToHistory = false;
|
||||
req.scripted = true;
|
||||
});
|
||||
};
|
||||
|
||||
Migrate.prototype.onRendered = function(event) {
|
||||
var _this = event.data.self;
|
||||
var $target = $(event.target);
|
||||
|
||||
if (! $target.is('#main > .container')) {
|
||||
var attrUrl = $target.attr('data-icinga-url');
|
||||
var dataUrl = $target.data('icingaUrl');
|
||||
if (!! attrUrl && attrUrl !== dataUrl) {
|
||||
// Search urls are redirected, update any migration suggestions
|
||||
_this.prepareMigration($target);
|
||||
return;
|
||||
if ($target.is('#main .container')) {
|
||||
var attrUrl = $target.attr('data-icinga-url');
|
||||
var dataUrl = $target.data('icingaUrl');
|
||||
if (!! attrUrl && attrUrl !== dataUrl) {
|
||||
// Search urls are redirected, update any migration suggestions
|
||||
_this.prepareMigration($target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We are else really only interested in top-level containers
|
||||
|
|
@ -108,41 +123,47 @@
|
|||
};
|
||||
|
||||
Migrate.prototype.prepareMigration = function($target) {
|
||||
var urls = {};
|
||||
var href;
|
||||
var wantBackendForm = false;
|
||||
let urls = {};
|
||||
let modules = {}
|
||||
|
||||
var _this = this;
|
||||
$target.each(function () {
|
||||
var $container = $(this);
|
||||
href = $container.data('icingaUrl');
|
||||
$target.each((_, container) => {
|
||||
let $container = $(container);
|
||||
let href = $container.data('icingaUrl');
|
||||
let containerId = $container.attr('id');
|
||||
|
||||
if (typeof href !== 'undefined') {
|
||||
if (href.match(_this.isMonitoringUrl)) {
|
||||
var containerId = $container.attr('id');
|
||||
|
||||
if (
|
||||
typeof _this.previousMigrations[containerId] !== 'undefined'
|
||||
&& _this.previousMigrations[containerId] === href
|
||||
) {
|
||||
delete _this.previousMigrations[containerId];
|
||||
} else {
|
||||
urls[containerId] = href;
|
||||
}
|
||||
} else if (href.match(_this.isSupportedModule)) {
|
||||
wantBackendForm = true;
|
||||
if (typeof href !== 'undefined' && href.match(this.isMonitoringUrl)) {
|
||||
if (
|
||||
typeof this.previousMigrations[containerId] !== 'undefined'
|
||||
&& this.previousMigrations[containerId] === href
|
||||
) {
|
||||
delete this.previousMigrations[containerId];
|
||||
} else {
|
||||
_this.removeBackendCheckboxForm();
|
||||
urls[containerId] = href;
|
||||
}
|
||||
}
|
||||
|
||||
let moduleName = $container.data('icingaModule');
|
||||
if (!! moduleName && moduleName !== 'default' && moduleName !== 'monitoring' && moduleName !== 'icingadb') {
|
||||
modules[containerId] = moduleName;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.icinga.utils.objectKeys(urls).length) {
|
||||
if (Object.keys(urls).length) {
|
||||
this.setUrlMigrationReadyState(false);
|
||||
this.migrateMonitoringUrls(urls);
|
||||
} else if (wantBackendForm) {
|
||||
this.prepareBackendCheckboxForm();
|
||||
} else {
|
||||
this.cleanupSuggestions();
|
||||
this.setUrlMigrationReadyState(null);
|
||||
}
|
||||
|
||||
if (Object.keys(modules).length) {
|
||||
this.setBackendSupportReadyState(false);
|
||||
this.prepareBackendCheckboxForm(modules);
|
||||
} else {
|
||||
this.setBackendSupportReadyState(null);
|
||||
}
|
||||
|
||||
if (this.urlMigrationReadyState === null && this.backendSupportReadyState === null) {
|
||||
this.cleanupPopup();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -166,12 +187,26 @@
|
|||
// Container moved
|
||||
$suggestion.attr('id', 'suggest-' + $newContainer.attr('id'));
|
||||
$suggestion.data('containerId', $newContainer.attr('id'));
|
||||
} else {
|
||||
// Container closed
|
||||
$suggestion.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let backendSupportRelated = { ..._this.backendSupportRelated };
|
||||
$.each(backendSupportRelated, (id, module) => {
|
||||
let $container = $('#' + id);
|
||||
if (! $container.length || $container.data('icingaModule') !== module) {
|
||||
let $newContainer = $('#main > .container').filter(function () {
|
||||
return $(this).data('icingaModule') === module;
|
||||
});
|
||||
if ($newContainer.length) {
|
||||
_this.backendSupportRelated[$newContainer.attr('id')] = module;
|
||||
}
|
||||
|
||||
delete _this.backendSupportRelated[id];
|
||||
}
|
||||
});
|
||||
|
||||
_this.cleanupPopup();
|
||||
};
|
||||
|
||||
Migrate.prototype.onClose = function(event) {
|
||||
|
|
@ -232,7 +267,6 @@
|
|||
containerIds = [],
|
||||
containerUrls = [];
|
||||
|
||||
this.removeBackendCheckboxForm();
|
||||
$.each(urls, function (containerId, containerUrl) {
|
||||
if (typeof _this.knownMigrations[containerUrl] === 'undefined') {
|
||||
containerUrls.push(containerUrl);
|
||||
|
|
@ -253,11 +287,11 @@
|
|||
req.urls = urls;
|
||||
req.urlIndexToContainerId = containerIds;
|
||||
req.done(this.processUrlMigrationResults);
|
||||
req.always(_this.cleanupSuggestions);
|
||||
req.always(() => this.changeUrlMigrationReadyState(true));
|
||||
} else {
|
||||
// All urls have already been migrated once, show popup immediately
|
||||
this.addSuggestions(urls);
|
||||
this.cleanupSuggestions();
|
||||
this.changeUrlMigrationReadyState(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -283,43 +317,85 @@
|
|||
this.addSuggestions(req.urls);
|
||||
};
|
||||
|
||||
Migrate.prototype.prepareBackendCheckboxForm = function() {
|
||||
var $popup = this.Popup();
|
||||
var checkboxForm = $popup.find('.suggestion-area > #setAsBackendForm');
|
||||
Migrate.prototype.prepareBackendCheckboxForm = function(modules) {
|
||||
let containerIds = [];
|
||||
let moduleNames = [];
|
||||
|
||||
this.cleanupSuggestions(); // remove links
|
||||
if (! checkboxForm.length) {
|
||||
$popup.find('.suggestion-area > ul').after($(BACKEND_FORM));
|
||||
}
|
||||
|
||||
var req = $.ajax({
|
||||
context : this,
|
||||
type : 'get',
|
||||
url : this.icinga.config.baseUrl + '/icingadb/migrate/checkbox-state'
|
||||
$.each(modules, (id, module) => {
|
||||
if (typeof this.knownBackendSupport[module] === 'undefined') {
|
||||
containerIds.push(id);
|
||||
moduleNames.push(module);
|
||||
}
|
||||
});
|
||||
|
||||
req.done(this.setCheckboxState);
|
||||
if (moduleNames.length) {
|
||||
let req = $.ajax({
|
||||
context : this,
|
||||
type : 'post',
|
||||
url : this.icinga.config.baseUrl + '/icingadb/migrate/backend-support',
|
||||
headers : { 'Accept': 'application/json' },
|
||||
contentType : 'application/json',
|
||||
data : JSON.stringify(moduleNames)
|
||||
});
|
||||
|
||||
req.modules = modules;
|
||||
req.moduleIndexToContainerId = containerIds;
|
||||
req.done(this.processBackendSupportResults);
|
||||
req.always(() => this.changeBackendSupportReadyState(true));
|
||||
} else {
|
||||
// All modules have already been checked once, show popup immediately
|
||||
this.setupBackendCheckboxForm(modules);
|
||||
this.changeBackendSupportReadyState(true);
|
||||
}
|
||||
};
|
||||
|
||||
Migrate.prototype.processBackendSupportResults = function(data, textStatus, req) {
|
||||
let result = data.data;
|
||||
|
||||
$.each(result, (i, state) => {
|
||||
let containerId = req.moduleIndexToContainerId[i];
|
||||
this.knownBackendSupport[req.modules[containerId]] = state;
|
||||
});
|
||||
|
||||
this.setupBackendCheckboxForm(req.modules);
|
||||
};
|
||||
|
||||
Migrate.prototype.setupBackendCheckboxForm = function(modules) {
|
||||
let supportedModules = {};
|
||||
|
||||
$.each(modules, (id, module) => {
|
||||
if (this.knownBackendSupport[module]) {
|
||||
supportedModules[id] = module;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(supportedModules).length) {
|
||||
let $form = this.Popup().find('.suggestion-area > #setAsBackendForm');
|
||||
if (! $form.length) {
|
||||
$form = $(BACKEND_FORM);
|
||||
this.Popup().find('.suggestion-area > ul').after($form);
|
||||
}
|
||||
|
||||
this.backendSupportRelated = { ...this.backendSupportRelated, ...supportedModules };
|
||||
|
||||
let req = $.ajax({
|
||||
context : this,
|
||||
type : 'get',
|
||||
url : this.icinga.config.baseUrl + '/icingadb/migrate/checkbox-state'
|
||||
});
|
||||
|
||||
req.done(this.setCheckboxState);
|
||||
}
|
||||
};
|
||||
|
||||
Migrate.prototype.setCheckboxState = function(isChecked, textStatus, req) {
|
||||
var $form = this.Popup().find('.suggestion-area > #setAsBackendForm');
|
||||
var $checkbox = $form.find('input#setAsBackendForm-checkbox');
|
||||
|
||||
this.Popup().find('p').hide();
|
||||
|
||||
$checkbox.prop('checked', isChecked);
|
||||
this.showPopup();
|
||||
}
|
||||
|
||||
Migrate.prototype.removeBackendCheckboxForm = function () {
|
||||
var $backendCheckboxForm = this.Popup().find('.suggestion-area > #setAsBackendForm');
|
||||
if ($backendCheckboxForm.length) {
|
||||
$backendCheckboxForm.remove();
|
||||
}
|
||||
|
||||
this.Popup().find('p').show();
|
||||
}
|
||||
|
||||
Migrate.prototype.addSuggestions = function(urls) {
|
||||
var _this = this,
|
||||
hasSuggestions = false,
|
||||
|
|
@ -368,9 +444,7 @@
|
|||
|
||||
Migrate.prototype.cleanupSuggestions = function() {
|
||||
var _this = this,
|
||||
toBeRemoved = [],
|
||||
willBeEmpty = true,
|
||||
$hasBackendForm = this.Popup().find('.suggestion-area > #setAsBackendForm').length > 0;
|
||||
toBeRemoved = [];
|
||||
this.Popup().find('li').each(function () {
|
||||
var $suggestion = $(this);
|
||||
var $container = $('#' + $suggestion.data('containerId'));
|
||||
|
|
@ -384,26 +458,58 @@
|
|||
|| containerUrl === _this.knownMigrations[containerUrl]
|
||||
) {
|
||||
toBeRemoved.push($suggestion);
|
||||
} else {
|
||||
willBeEmpty = false;
|
||||
}
|
||||
});
|
||||
|
||||
if ($hasBackendForm) {
|
||||
willBeEmpty = false;
|
||||
return toBeRemoved;
|
||||
};
|
||||
|
||||
Migrate.prototype.cleanupBackendForm = function () {
|
||||
let $form = this.Popup().find('#setAsBackendForm');
|
||||
if (! $form.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (willBeEmpty) {
|
||||
let stillRelated = {};
|
||||
$.each(this.backendSupportRelated, (id, module) => {
|
||||
let $container = $('#' + id);
|
||||
if ($container.length && $container.data('icingaModule') === module) {
|
||||
stillRelated[id] = module;
|
||||
}
|
||||
});
|
||||
|
||||
this.backendSupportRelated = stillRelated;
|
||||
|
||||
if (Object.keys(stillRelated).length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $form;
|
||||
};
|
||||
|
||||
Migrate.prototype.cleanupPopup = function () {
|
||||
let toBeRemoved = this.cleanupSuggestions();
|
||||
let hasBackendForm = this.cleanupBackendForm();
|
||||
|
||||
if (hasBackendForm !== true && this.Popup().find('li').length === toBeRemoved.length) {
|
||||
this.hidePopup(function () {
|
||||
// Let the transition finish first, looks cleaner
|
||||
$.each(toBeRemoved, function (_, $suggestion) {
|
||||
$suggestion.remove();
|
||||
});
|
||||
|
||||
if (typeof hasBackendForm === 'object') {
|
||||
hasBackendForm.remove();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$.each(toBeRemoved, function (_, $suggestion) {
|
||||
$suggestion.remove();
|
||||
});
|
||||
|
||||
if (typeof hasBackendForm === 'object') {
|
||||
hasBackendForm.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -450,6 +556,34 @@
|
|||
}
|
||||
};
|
||||
|
||||
Migrate.prototype.setUrlMigrationReadyState = function (state) {
|
||||
this.urlMigrationReadyState = state;
|
||||
};
|
||||
|
||||
Migrate.prototype.changeUrlMigrationReadyState = function (state) {
|
||||
this.setUrlMigrationReadyState(state);
|
||||
|
||||
if (this.backendSupportReadyState !== false) {
|
||||
this.backendSupportReadyState = null;
|
||||
this.urlMigrationReadyState = null;
|
||||
this.cleanupPopup();
|
||||
}
|
||||
};
|
||||
|
||||
Migrate.prototype.setBackendSupportReadyState = function (state) {
|
||||
this.backendSupportReadyState = state;
|
||||
};
|
||||
|
||||
Migrate.prototype.changeBackendSupportReadyState = function (state) {
|
||||
this.setBackendSupportReadyState(state);
|
||||
|
||||
if (this.urlMigrationReadyState !== false) {
|
||||
this.backendSupportReadyState = null;
|
||||
this.urlMigrationReadyState = null;
|
||||
this.cleanupPopup();
|
||||
}
|
||||
};
|
||||
|
||||
Migrate.prototype.Popup = function() {
|
||||
// Node.contains() is used due to `?renderLayout`
|
||||
if (this.$popup === null || ! document.body.contains(this.$popup[0])) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue