app/javascript/oldjs/miq_tree.js
/* global DoNav miqClearTreeState miqDomElementExists miqJqueryRequest miqSetToolbarCount miqSparkle */
window.isReduxTree = function(treeName) {
var store = ManageIQ.redux.store.getState();
return store.hasOwnProperty(treeName);
}
window.miqTreeObject = function(tree) {
var obj;
try {
obj = $('#' + tree + 'box').treeview(true);
} catch (_ex) {
obj = $('miq-tree-view[name="' + tree + '"] > .treeview').treeview(true);
} finally {
return obj;
}
}
window.miqTreeFindNodeByKey = function(tree, key) {
var tree = miqTreeObject(tree);
if (!tree) {
console.error("miqTreeFindNodeByKey: tree '" + tree + "' does not exist.");
return;
}
return tree.getNodes().find(function(node) {
return (node.key === key);
});
}
window.miqAddNodeChildren = function(treename, key, selected_node, children) {
var node = miqTreeFindNodeByKey(treename, key);
if (node.lazyLoad) {
node.lazyLoad = false;
}
miqTreeObject(treename).addNode(children, node);
miqTreeActivateNodeSilently(treename, selected_node);
}
window.miqTreeResetState = function(treename) {
// FIXME: this is probably not enough, keeping the original dynatree code in comments for the future
miqTreeClearState(treename);
/*
var key = 'treeOpenStatex' + treename ;
delete localStorage[key + '-active'];
delete localStorage[key + '-expand'];
delete localStorage[key + '-focus'];
delete localStorage[key + '-select'];
*/
}
window.miqRemoveNodeChildren = function(treename, key) {
var node = miqTreeFindNodeByKey(treename, key);
if (node.nodes) {
node.nodes.slice().forEach(function(child) {
miqTreeObject(treename).removeNode(child);
});
}
}
window.miqTreeSelect = function(key) {
var url = '/' + ManageIQ.controller + '/tree_select/?id=' + encodeURIComponent(key.split('__')[0]);
miqJqueryRequest(url, {beforeSend: true});
}
// Activate and focus on a node within a tree given the node's key
window.miqTreeActivateNode = function(tree, key) {
miqSparkle(true);
if (isReduxTree(tree)) {
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/selectNode', key: key});
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/expandNode', key: key});
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/scrollToNode', key: key});
} else {
var node = miqTreeFindNodeByKey(tree, key);
if (node) {
miqTreeObject(tree).selectNode(node);
miqTreeScrollToNode(tree, key);
}
}
}
// Activate silently (no onActivate event) and focus on a node within a tree given the node's key
window.miqTreeActivateNodeSilently = function(tree, key) {
if (isReduxTree(tree)) {
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/selectNodeSilent', key: key});
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/expandNode', key: key});
ManageIQ.redux.store.dispatch({namespace: tree, type: '@@tree/scrollToNode', key: key});
} else {
var node = miqTreeFindNodeByKey(tree, key);
if (node) {
miqTreeObject(tree).selectNode(node, {silent: true });
miqTreeObject(tree).expandNode(node);
miqTreeScrollToNode(tree, key);
}
}
}
// Activate a node silently and fire the activation event manually
window.miqTreeForceActivateNode = function(tree, key) {
miqTreeActivateNodeSilently(tree, key);
miqTreeObject(tree).options.onNodeSelected(0, miqTreeFindNodeByKey(tree, key));
}
// expand all parent nodes of selected node on initial load
window.miqExpandParentNodes = function(treename, selected_node) {
var node = miqTreeFindNodeByKey(treename, selected_node);
if (node) {
miqTreeObject(treename).revealNode(node, {silent: true});
}
}
window.miqTreeScrollToNode = function(tree, id) {
var node = miqTreeFindNodeByKey(tree, id);
var parentPanelBody = node.$el.parents('div.panel-body');
if (parentPanelBody.length > 0) {
// Calculate the current node position relative to the scrollable panel
var nodePos = node.$el.offset().top - parentPanelBody.offset().top;
var offset = 0; // Calculate the required scrolling offset
if (nodePos < 0) {
offset = nodePos - node.$el.height();
} else if (nodePos > parentPanelBody.height()) {
offset = nodePos + node.$el.height() - parentPanelBody.height();
}
if (offset != 0) { // Scroll the panel to the node's position if necessary
parentPanelBody.animate({scrollTop: parentPanelBody.scrollTop() + offset});
}
}
}
// delete specific tree cookies
window.miqDeleteTreeCookies = function(tree_prefix) {
miqTreeClearState(tree_prefix);
}
// toggle expand/collapse all nodes in tree
window.miqTreeToggleExpand = function(treename, expand_mode) {
if (isReduxTree(treename)) {
ManageIQ.redux.store.dispatch({namespace: treename, type: '@@tree/expandAll', value: expand_mode});
} else {
expand_mode ? miqTreeObject(treename).expandAll() : miqTreeObject(treename).collapseAll();
}
}
/**
* Function for the react tree to select checked keys.
* @param {Object} tree The tree object itself.
* @return {Array} Array of keys.
*/
window.miqGetSelectedKeys = (tree) => Object.values(tree)
.filter((entry) => (entry.state && entry.state.checked))
.map((entry) => entry.attr.key);
// Generic OnCheck handler for the checkboxes in tree
window.miqOnCheckGeneric = function(key, checked) {
miqJqueryRequest(ManageIQ.tree.checkUrl + encodeURIComponent(key) + '?check=' + (checked ? '1' : '0'));
}
// OnCheck handler for the belongs to drift/compare sections tree
// Compute -> Infra -> VMs -> Compare VM's
window.miqOnCheckSections = function(key, checked, tree) {
var selectedKeys = miqGetSelectedKeys(tree);
var url = ManageIQ.tree.checkUrl + '?id=' + encodeURIComponent(key) + '&check=' + checked;
miqJqueryRequest(url, {data: {all_checked: selectedKeys}});
return true;
}
// Compute -> Infrastructure -> VMs -> Select one vm and click on genealogy
window.miqOnCheckGenealogy = (key, checked, tree) => {
Object.values(tree).find((item) => item.attr && item.attr.key === key).state.checked = checked;
const selectedKeys = window.miqGetSelectedKeys(tree);
// Activate toolbar items according to the selection
miqSetToolbarCount(selectedKeys.length);
// Inform the backend about the checkbox changes
miqJqueryRequest(`${ManageIQ.tree.checkUrl}?all_checked=${selectedKeys}`,
{ beforeSend: true, complete: true });
};
// Services -> Catalogs -> Catalog Items -> Edit item -> Tenants tree
window.miqOnCheckTenantTree = function(key) {
sendDataWithRx({
controller: 'catalogItemFormController',
key: key,
});
}
window.miqCheckAll = function(cb, treeName) {
// Set the checkboxes according to the master checkbox
ManageIQ.redux.store.dispatch({namespace: treeName, type: '@@tree/checkAll', value: cb.checked});
// Map the selected nodes into an array of keys
var selectedKeys = [];
var tree = ManageIQ.redux.store.getState()[treeName];
for (var property in tree) {
if (tree.hasOwnProperty(property) && property !== '') {
selectedKeys.push(encodeURIComponent(tree[property].attr.key));
}
}
// Activate toolbar items according to the selection
miqSetToolbarCount(selectedKeys.length);
// Inform the backend about the checkbox changes
miqJqueryRequest(ManageIQ.tree.checkUrl + '?check_all=' + encodeURIComponent(cb.checked) + '&all_checked=' + selectedKeys);
}
// Compute -> Infrastructure -> VMs -> Select one vm and click on genealogy
window.miqOnClickGeneric = function(id) {
miqJqueryRequest(ManageIQ.tree.clickUrl + encodeURIComponent(id), {beforeSend: true, complete: true});
}
// Settings -> Diagnostics -> Roles By servers tab
window.miqOnClickDiagnostics = function(id) {
var typ = id.split('-')[0]; // Break apart the node ids
if (['svr', 'role', 'asr'].includes(typ)) {
miqJqueryRequest(ManageIQ.tree.clickUrl + '?id=' + encodeURIComponent(id), {beforeSend: true, complete: true});
}
}
// Compute -> Infra -> VMs -> Select one -> Snapshot button
window.miqOnClickSnapshots = function(id) {
var pieces = id.split(/-/);
var shortId = pieces[pieces.length - 1];
miqJqueryRequest('/' + ManageIQ.controller + '/snap_pressed/' + encodeURIComponent(shortId), {beforeSend: true, complete: true});
}
// Compute -> Infra -> Networking
window.miqOnClickHostNet = function(id) {
var ids = id.split('|')[0].split('_'); // Break apart the node ids
var nid = ids[ids.length - 1].split('-'); // Get the last part of the node id
DoNav('/vm_or_template/show/' + encodeURIComponent(nid[1]));
}
window.miqOnClickSelectRbacTreeNode = function(id) {
var tree = 'rbac_tree';
miqJqueryRequest('/' + ManageIQ.controller + '/tree_select/?id=' + encodeURIComponent(id) + '&tree=' + tree, {beforeSend: true});
miqTreeScrollToNode(tree, id);
}
// Settings -> Access Control -> Roles/Edit Roles // Seems like not doing anything
window.miqOnClickMenuRoles = function(id) {
var url = ManageIQ.tree.clickUrl + '?node_id=' + encodeURIComponent(id) + '&node_clicked=1';
miqJqueryRequest(url, {
beforeSend: true,
complete: true,
no_encoding: true,
});
}
// Automate -> Expoler -> Select a class -> Copy -> Uncheck Copy to same path -> Namespace selection uses thath tree
window.miqOnClickAutomate = function(id) {
miqJqueryRequest('/' + ManageIQ.controller + '/ae_tree_select/?id=' + encodeURIComponent(id) + '&tree=automate_tree');
}
// Services -> Catalogs -> Catalog Items -> add a new item -> select Generic -> three entry point fields open it.
window.miqOnClickAutomateCatalog = function(id) {
miqJqueryRequest('/' + ManageIQ.controller + '/ae_tree_select/?id=' + encodeURIComponent(id) + '&tree=automate_catalog_tree');
}
window.miqOnClickIncludeDomainPrefix = function() {
miqJqueryRequest('/' + ManageIQ.controller + '/ae_tree_select_toggle?button=domain');
}
window.miqTreeExpandNode = function(treename, key) {
if (isReduxTree(treename)) {
ManageIQ.redux.store.dispatch({namespace: treename, type: '@@tree/expandNode', key: key});
} else {
var node = miqTreeFindNodeByKey(treename, key);
miqTreeObject(treename).expandNode(node);
}
}
window.miqTreeExpandRecursive = function(treeId, fullNodeId) {
var currId = '';
var indexOfBox = treeId.indexOf('box');
var splitNodeId = fullNodeId.split('_');
if (indexOfBox !== -1 && treeId.length - 3 === indexOfBox) {
treeId = treeId.substring(0, indexOfBox);
}
splitNodeId.forEach(function(item, key) {
if (key + 1 !== splitNodeId.length) {
if (key !== 0) {
currId += '_' + item;
} else {
currId = item;
}
miqTreeExpandNode(treeId, currId);
}
});
}
window.miqMenuChangeRow = function(action, elem) {
var grid = $('#folder_grid .panel-group');
var selected = grid.find('.panel-heading.active').parent();
switch (action) {
case 'activate':
grid.find('.panel-heading.active').removeClass('active');
$(elem).addClass('active');
break;
case 'edit':
// quick and dirty edit - FIXME use a $modal when converted to angular
var text = $(elem).text().trim();
text = prompt(__('New name?'), text);
if (text) {
$(elem).text(text);
}
break;
case 'up':
selected.prev().before(selected);
break;
case 'down':
selected.next().after(selected);
break;
case 'top':
selected.siblings().first().before(selected);
break;
case 'bottom':
selected.siblings().last().after(selected);
break;
case 'add':
var count = grid.find('.panel-heading').length;
elem = $('<div>').addClass('panel-heading');
elem.attr('id', 'folder' + count);
elem.text(__('New Folder'));
elem.on('click', function() {
return miqMenuChangeRow('activate', this);
});
elem.on('dblclick', function() {
return miqMenuChangeRow('edit', this);
});
grid.append(elem);
miqMenuChangeRow('activate', elem);
// just shows a flash message
miqJqueryRequest('/report/menu_folder_message_display?typ=add', {no_encoding: true});
break;
case 'delete':
if (!selected.length) {
break;
}
var selected_id = selected.children()[0].id.split('|-|');
if (selected_id.length === 1) {
selected.remove();
} else {
// just show a flash message
miqJqueryRequest('/report/menu_folder_message_display?typ=delete');
}
break;
case 'serialize':
var items = grid.find('.panel-heading').toArray().map(function(elem) {
return {
id: $(elem).attr('id'),
text: $(elem).text().trim(),
};
});
var serialized = JSON.stringify(items);
var url = '/report/menu_field_changed/?tree=' + encodeURIComponent(serialized);
miqJqueryRequest(url, {beforeSend: true, complete: true, no_encoding: true});
break;
}
return false;
}
window.miqSquashToggle = function(treeName) {
if (ManageIQ.tree.expandAll) {
$('#squash_button i').attr('class', 'fa fa-minus-square-o fa-lg');
$('#squash_button').prop('title', __('Collapse All'));
miqTreeToggleExpand(treeName, true);
ManageIQ.tree.expandAll = false;
} else {
$('#squash_button i').attr('class', 'fa fa-plus-square-o fa-lg');
$('#squash_button').prop('title', __('Expand All'));
miqTreeToggleExpand(treeName, false);
ManageIQ.tree.expandAll = true;
}
}
window.miqTreeClearState = function(tree) {
if (tree === undefined) {
// Clear all tree state objects
var to_remove = [];
for (var i = 0; i < sessionStorage.length; i++) {
if (sessionStorage.key(i).match('^tree_state_')) {
to_remove.push(sessionStorage.key(i));
}
}
for (var i = 0; i < to_remove.length; i++) {
sessionStorage.removeItem(to_remove[i]);
}
} else {
// Clear the state of one specific tree
sessionStorage.removeItem('tree_state_' + tree);
}
}