180 lines
6.8 KiB
JavaScript

/*! Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
;(function (Icinga, $) {
'use strict';
/**
* Behavior for the enhanced Icinga Web 2 dashboards
*
* @param {Icinga} icinga The current Icinga Object
*/
class Dashboard extends Icinga.EventListener {
constructor(icinga) {
super(icinga);
try {
this.Sortable = require('icinga/icinga-php-library/vendor/Sortable');
} catch (e) {
console.warn('Unable to provide Sortable. Library not available:', e);
return;
}
/**
* Possible type of widgets this behavior is being applied to
*
* @type {object}
*/
this.widgetTypes = { Dashlet : 'Dashlets', Dashboard : 'Dashboards', DashboardHome : 'Homes' };
this.on('rendered', '#main > .container', this.onRendered, this);
// Registers the drop event for all the widget types
this.on('end', '.dashboard-settings', this.elementDropped, this);
}
/**
* Get the widget type of the given element
*
* @param {HTMLElement} target
*
* @returns {null|string}
*/
getTypeFor(target) {
if (target.matches('.dashboard-settings')) {
if (! target.querySelector('.home-list-control:first-child')) {
return this.widgetTypes.Dashboard;
}
return this.widgetTypes.DashboardHome;
} else if (target.matches('.dashboard-item-list')) {
return this.widgetTypes.Dashboard;
} else if (target.matches('.dashlet-item-list')) {
return this.widgetTypes.Dashlet;
}
return null;
}
/**
* Set up a request with the reordered widget and post the data to the controller
*
* @param event
*
* @returns {boolean}
*/
elementDropped(event) {
let _this = event.data.self,
orgEvt = event.originalEvent,
data = {};
if (orgEvt.to === orgEvt.from && orgEvt.newIndex === orgEvt.oldIndex) {
return false;
}
let item = orgEvt.item;
switch (_this.getTypeFor(orgEvt.to)) {
case _this.widgetTypes.DashboardHome: {
let home = item.dataset.icingaHome;
data[home] = orgEvt.newIndex;
break;
}
case _this.widgetTypes.Dashboard: {
let pane = item.dataset.icingaPane,
home = orgEvt.to.closest('.home-list-control, .dashboard-settings').dataset.icingaHome;
if (orgEvt.to !== orgEvt.from) {
let homeList = orgEvt.from.closest('.home-list-control, .dashboard-settings');
data.originals = {
originalHome : homeList.dataset.icingaHome,
originalPane : pane
};
}
data[home] = { [pane] : orgEvt.newIndex };
break;
}
case _this.widgetTypes.Dashlet: {
let dashlet = item.dataset.icingaDashlet;
let parent = orgEvt.to.closest('.dashboard-list-control');
let pane = parent.dataset.icingaPane;
// If there is only default home in the dashboard manager view, there won't be rendered a
// ".home-list-control", so we need to look for an alternative
let home = parent.closest('.home-list-control, .dashboard-settings').dataset.icingaHome;
if (orgEvt.to !== orgEvt.from) {
let parent = orgEvt.from.closest('.dashboard-list-control');
let orgHome = parent.closest('.home-list-control, .dashboard-settings').dataset.icingaHome;
data.originals = {
originalHome : orgHome,
originalPane : parent.dataset.icingaPane
}
}
dashlet = { [dashlet] : orgEvt.newIndex };
data[home] = { [pane] : dashlet };
}
}
if (Object.keys(data).length) {
if (! data.originals) {
data.originals = null;
}
data = { dashboardData : JSON.stringify(data) };
let url = _this.icinga.config.baseUrl + '/dashboards/reorder-widgets';
let req = _this.icinga.loader.loadUrl(url, $('#col1'), data, 'post');
req.addToHistory = false;
req.scripted = true;
}
}
onRendered(e) {
let _this = e.data.self;
if (e.currentTarget !== e.target || ! e.target.querySelector(':scope > .dashboard-manager')) {
// This is for the editor only, which has no nested .containers but a .dashboard-manager
return;
}
e.target.querySelectorAll('.dashboard-settings, .dashboard-item-list, .dashlet-item-list')
.forEach(sortable => {
let groupName = _this.getTypeFor(sortable),
draggable;
switch (groupName) {
case _this.widgetTypes.DashboardHome:
groupName = _this.widgetTypes.DashboardHome;
draggable = '.home-list-control';
break;
case _this.widgetTypes.Dashboard:
groupName = _this.widgetTypes.Dashboard;
draggable = '.dashboard-list-control';
break;
case _this.widgetTypes.Dashlet:
groupName = _this.widgetTypes.Dashlet;
draggable = '.dashlet-list-item';
}
let options = {
scroll : true,
invertSwap : true,
dataIdAttr : 'id',
direction : 'vertical',
draggable : draggable,
handle : 'h1 > .widget-drag-initiator',
group : { name : groupName },
chosenClass : 'draggable-widget-chosen'
};
_this.Sortable.create(sortable, options);
});
}
}
Icinga.Behaviors = Icinga.Behaviors || {};
Icinga.Behaviors.Dashboard = Dashboard;
})(Icinga, jQuery);