diff --git a/src/sunstone/public/app/tabs/clusters-tab/datatable.js b/src/sunstone/public/app/tabs/clusters-tab/datatable.js index d313269cf1..892cf91b6b 100644 --- a/src/sunstone/public/app/tabs/clusters-tab/datatable.js +++ b/src/sunstone/public/app/tabs/clusters-tab/datatable.js @@ -88,6 +88,7 @@ define(function(require) { Table.prototype.elementArray = _elementArray; Table.prototype.preUpdateView = _preUpdateView; Table.prototype.postUpdateView = _postUpdateView; + Table.prototype.isOpenNebulaResourceInCluster = _isOpenNebulaResourceInCluster; return Table; @@ -130,4 +131,25 @@ define(function(require) { $(".total_clusters").text(this.totalClusters); } + /** + * Checks that a OpenNebula resource is in the selected clusters. + * + * @param {object} resource - OpenNebula resource: Datastore, VM, etc + * @param {function(object):string|string[]} [fnGetResourceCluster] + * - Function to get Clusters ids from resource + * @returns `true` if selected Clusters contain the resource + */ + function _isOpenNebulaResourceInCluster(resource, fnGetResourceCluster) { + var clusters = typeof fnGetResourceCluster === 'function' + ? fnGetResourceCluster(resource) + : resource.CLUSTERS.ID + + var ensuredClusters = Array.isArray(clusters) ? clusters : [clusters]; + var selectedClusterIds = this.retrieveResourceTableSelect(); + + return selectedClusterIds.length === 0 || + ensuredClusters.some(function (cluster) { + return selectedClusterIds.includes(cluster) + }); + } }); diff --git a/src/sunstone/public/app/tabs/hosts-tab/datatable.js b/src/sunstone/public/app/tabs/hosts-tab/datatable.js index 27ff200edc..e5ccd8bb92 100644 --- a/src/sunstone/public/app/tabs/hosts-tab/datatable.js +++ b/src/sunstone/public/app/tabs/hosts-tab/datatable.js @@ -119,6 +119,7 @@ define(function(require) { Table.prototype.elementArray = _elementArray; Table.prototype.preUpdateView = _preUpdateView; Table.prototype.postUpdateView = _postUpdateView; + Table.prototype.isOpenNebulaResourceInHost = _isOpenNebulaResourceInHost; return Table; @@ -288,4 +289,32 @@ define(function(require) { "" + ""; } + + /** + * Checks that a OpenNebula resource is in the selected hosts. + * + * @param {object} resource - OpenNebula resource: Datastore, VM, etc + * @param {function(object):string|string[]} [fnGetResourceCluster] + * - Function to get Clusters ids from resource + * @returns `true` if selected Hosts and the resource are in same cluster + */ + function _isOpenNebulaResourceInHost(resource, fnGetResourceCluster) { + var clusters = typeof fnGetResourceCluster === 'function' + ? fnGetResourceCluster(resource) + : resource.CLUSTERS.ID + + var ensuredClusters = Array.isArray(clusters) ? clusters : [clusters]; + var selectedHostIds = this.retrieveResourceTableSelect(); + var allHosts = this.dataTable.fnGetData(); + var id_index = this.selectOptions.id_index; + + var selectedClusters = !Array.isArray(allHosts) ? [] : allHosts + .filter(function(host) { return selectedHostIds.includes(host[id_index]) }) + .map(function(host) { return host[3] }); // cluster column => 3 + + return selectedClusters.length === 0 || + ensuredClusters.some(function (cluster) { + return selectedClusters.includes(cluster) + }); + } }); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js index 8753e927f6..9961a103b7 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js @@ -37,6 +37,7 @@ define(function(require) { CONSTANTS */ + var SCHED_TAB_ID = require('./scheduling/wizardTabId'); var WIZARD_TAB_ID = require('./network/wizardTabId'); var LINKS_CONTAINER_ID = 'template_create_network_tabs'; var CONTENTS_CONTAINER_ID = 'template_create_network_tabs_content'; @@ -105,8 +106,6 @@ define(function(require) { return false; }); - that.addNicTab(context); - if(that.listener != undefined){ $(context).on("change", "input", function(){ that.listener.notify(); @@ -195,19 +194,19 @@ define(function(require) { }); } - $.each(nics, function(nicId, nicJSON) { - if (nicId > 0) { + nics.length === 0 + ? that.addNicTab(context) + : $.each(nics, function(nicId, nicJSON) { that.addNicTab(context); - } - var nicTab = that.nicTabObjects[that.numberOfNics]; - var nicContext = $('#' + nicTab.nicTabId, context); - nicTab.fill(nicContext, nicJSON); + var nicTab = that.nicTabObjects[that.numberOfNics]; + var nicContext = $('#' + nicTab.nicTabId, context); + nicTab.fill(nicContext, nicJSON); - if (nicJSON.PARENT) { - nicTab.fill_alias(nicJSON.PARENT, nicJSON.EXTERNAL); - } - }); + if (nicJSON.PARENT) { + nicTab.fill_alias(nicJSON.PARENT, nicJSON.EXTERNAL); + } + }); that.renameTabLinks(context); that.enableRDP(context); @@ -279,7 +278,8 @@ define(function(require) { $("a", a).trigger("click"); - nicTab.setup(content); + nicTab.setup(content, $("div[id^='" + SCHED_TAB_ID + "']").data()); + content.attr("nicId", that.numberOfNics); that.renameTabLinks(context); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js index fac83fdd44..72b628a854 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js @@ -109,7 +109,7 @@ define(function(require) { * options.hide_pci {bool} true to disable the pci checkbox * options.hide_auto {bool} true to disable the selection mode auto checkbox */ - function _setup(context, options) { + function _setup(context, options = {}) { var that = this; that.context = context; @@ -123,7 +123,23 @@ define(function(require) { that.vnetsTable.initialize({ 'selectOptions': { - 'select_callback': function(aData, options) { + filter_fn: function(vnet) { + if (!options.hostsTable || !options.clustersTable) return true; + + var inHostOrCluster = $("input[name='req_select']:checked").val() === "host_select" + ? options.hostsTable.isOpenNebulaResourceInHost(vnet) + : options.clustersTable.isOpenNebulaResourceInCluster(vnet) + + if (!inHostOrCluster && $('#NETWORK', context).val() === vnet.NAME) { + that.secgroupsTable.selectResourceTableSelect({ ids: [] }); + $.each(['NETWORK_ID', 'NETWORK', 'NETWORK_UNAME', 'NETWORK_UID'], function() { + $('#' + this, context).val(''); + }) + } + + return inHostOrCluster + }, + select_callback: function(aData, options) { // If the net is selected by Id, avoid overwriting it with name+uname if ($('#NETWORK_ID', context).val() != aData[options.id_index]) { OpenNebulaNetwork.show({ @@ -144,7 +160,7 @@ define(function(require) { $('#NETWORK_UID', context).val(""); } }, - 'unselect_callback': function() { + unselect_callback: function() { // reset values that.secgroupsTable.selectResourceTableSelect({ ids: [] }); $.each(['NETWORK_ID', 'NETWORK', 'NETWORK_UNAME', 'NETWORK_UID'], function() { @@ -158,19 +174,44 @@ define(function(require) { that.secgroupsTable.refreshResourceTableSelect(); that.vnetsTable.refreshResourceTableSelect(); - var selectOptions = { - 'selectOptions': { - 'select_callback': function(aData, options) { + that.vnetsTableAuto.initialize({ + selectOptions: { + filter_fn: function(vnet) { + if (!options.hostsTable || !options.clustersTable) return true; + + return $("input[name='req_select']:checked").val() === "host_select" + ? options.hostsTable.isOpenNebulaResourceInHost(vnet) + : options.clustersTable.isOpenNebulaResourceInCluster(vnet) + }, + select_callback: function(aData, options) { that.generateRequirements(context) }, - 'unselect_callback': function(aData, options) { + unselect_callback: function(aData, options) { that.generateRequirements(context) } } + }); + that.vnetsTableAuto.refreshResourceTableSelect(); + + var updateRowSelected = function() { + that.vnetsTable.updateFn(); + that.vnetsTableAuto.updateFn(); + + if ($("td.markrowchecked", this).length > 0) { + that.vnetsTable.deselectHiddenResources(); + that.vnetsTableAuto.deselectHiddenResources(); + } + }; + + if (options.hostsTable && options.hostsTable.dataTable) { + // Filters the vnet tables by hosts + options.hostsTable.dataTable.children('tbody').on('click', 'tr', updateRowSelected) } - that.vnetsTableAuto.initialize(selectOptions); - that.vnetsTableAuto.refreshResourceTableSelect(); + if (options.clustersTable && options.clustersTable.dataTable) { + // Filters the vnet tables by cluster + options.clustersTable.dataTable.children('tbody').on('click', 'tr', updateRowSelected) + } $("input.pci-type-nic", context).on("change", function(){ var tbody = $(".pci-row tbody", context); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js index 88ff0c83cd..d705ceb15f 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js @@ -96,6 +96,9 @@ define(function(require) { Foundation.reflow(context, 'tabs'); context.on("change", "input[name='req_select']", function() { + that.datastoresTable.updateFn(); + that.datastoresTable.deselectHiddenResources(); + if ($("input[name='req_select']:checked").val() == "host_select") { $("div.host_select", context).show(); $("div.cluster_select", context).hide(); @@ -113,24 +116,49 @@ define(function(require) { WizardFields.fillInput($("#SCHED_DS_RANK", context), this.value); }); - var selectOptions = { - 'selectOptions': { - 'select_callback': function(aData, options) { + var generateCallbacks = function (updateDatastores) { + return { + select_callback: function() { + if (updateDatastores) { + that.datastoresTable.updateFn(); + that.datastoresTable.deselectHiddenResources(); + } + that.generateRequirements(context) }, - 'unselect_callback': function(aData, options) { + unselect_callback: function() { + if (updateDatastores) { + that.datastoresTable.updateFn(); + } + that.generateRequirements(context) } } } - that.hostsTable.initialize(selectOptions); - that.hostsTable.refreshResourceTableSelect(); - that.clustersTable.initialize(selectOptions); - that.clustersTable.refreshResourceTableSelect(); - that.datastoresTable.initialize(selectOptions); + that.clustersTable.initialize({ selectOptions: generateCallbacks(true) }); + that.hostsTable.initialize({ selectOptions: generateCallbacks(true) }); + that.datastoresTable.initialize({ + selectOptions: Object.assign(generateCallbacks(), { + filter_fn: function(ds) { + if (!that.hostsTable || !that.clustersTable) return true; + + return $("input[name='req_select']:checked").val() === "host_select" + ? that.hostsTable.isOpenNebulaResourceInHost(ds) + : that.clustersTable.isOpenNebulaResourceInCluster(ds) + } + }) + }); that.datastoresTable.filter("system", 10); + that.hostsTable.refreshResourceTableSelect(); + that.clustersTable.refreshResourceTableSelect(); that.datastoresTable.refreshResourceTableSelect(); + + $("#" + this.wizardTabId).data({ + hostsTable: that.hostsTable, + clustersTable: that.clustersTable, + datastoresTable: that.datastoresTable, + }); } function _retrieve(context) { diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js index a578056b2c..2098969f92 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js @@ -505,27 +505,50 @@ define(function(require) { $(".provision_uid_selector" + template_json.VMTEMPLATE.ID, context).data("usersTable", that.usersTable); $(".provision_gid_selector" + template_json.VMTEMPLATE.ID, context).data("groupTable", that.groupTable); - var selectOptions = { - "selectOptions": { - "select_callback": function(aData, options) { + + that.hostsTable.initialize({ + selectOptions: { + select_callback: function(aData, options) { + that.datastoresTable.updateFn(); + that.datastoresTable.deselectHiddenResources(); + var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable"); var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable"); generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID); }, - "unselect_callback": function(aData, options) { + unselect_callback: function(aData, options) { + that.datastoresTable.updateFn(); + var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable"); var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable"); generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID); } } - }; - that.hostsTable.initialize(selectOptions); - that.hostsTable.refreshResourceTableSelect(); - that.datastoresTable.initialize(selectOptions); - that.datastoresTable.filter("system", 10); - that.datastoresTable.refreshResourceTableSelect(); + }); + that.datastoresTable.initialize({ + selectOptions: { + filter_fn: function(ds) { + if (!that.hostsTable.dataTable) return true; + + return that.hostsTable.isOpenNebulaResourceInHost(ds) + }, + select_callback: function(aData, options) { + var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable"); + var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable"); + generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID); + }, + unselect_callback: function(aData, options) { + var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable"); + var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable"); + generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID); + } + } + }); + that.datastoresTable.filter("system", 10); + that.hostsTable.refreshResourceTableSelect(); + that.datastoresTable.refreshResourceTableSelect(); + - //select_options that.usersTable.initialize(); that.usersTable.refreshResourceTableSelect(); that.groupTable.initialize(); @@ -593,7 +616,8 @@ define(function(require) { { "forceIPv4": true, "securityGroups": Config.isFeatureEnabled("secgroups"), "name": " ", - "fieldset": false + "fieldset": false, + "hostsTable": that.hostsTable }); VMGroupSection.insert(template_json, diff --git a/src/sunstone/public/app/utils/nics-section.js b/src/sunstone/public/app/utils/nics-section.js index 48dcebd551..5c692a18b0 100644 --- a/src/sunstone/public/app/utils/nics-section.js +++ b/src/sunstone/public/app/utils/nics-section.js @@ -342,6 +342,11 @@ define(function(require) { var selectOptions = { "selectOptions": { + filter_fn: function(vnet) { + if (!options.hostsTable) return true; + + return options.hostsTable.isOpenNebulaResourceInHost(vnet) + }, "select_callback": function(aData, options) { var req_string=[]; var selected_vnets = vnetsTableAuto.retrieveResourceTableSelect(); @@ -575,9 +580,30 @@ define(function(require) { provision_nic_accordion_dd_id += 1; - vnetsTable.initialize(); + vnetsTable.initialize({ + selectOptions: { + filter_fn: function(vnet) { + if (!options.hostsTable) return true; + + return options.hostsTable.isOpenNebulaResourceInHost(vnet) + }, + } + }); vnetsTable.refreshResourceTableSelect(); + if (options.hostsTable) { + // Filters the vnet tables by cluster + options.hostsTable.dataTable.children('tbody').on('click', 'tr', function() { + vnetsTable.updateFn(); + vnetsTableAuto.updateFn(); + + if ($("td.markrowchecked", this).length > 0) { + vnetsTable.deselectHiddenResources(); + vnetsTableAuto.deselectHiddenResources(); + } + }) + } + if (options.securityGroups == true){ sgTable.initialize(); sgTable.refreshResourceTableSelect(); diff --git a/src/sunstone/public/app/utils/tab-datatable.js b/src/sunstone/public/app/utils/tab-datatable.js index 4104bca5b7..1c78d8cf2d 100644 --- a/src/sunstone/public/app/utils/tab-datatable.js +++ b/src/sunstone/public/app/utils/tab-datatable.js @@ -168,7 +168,8 @@ define(function(require) { "updateFn": _updateFn, "list": _list, "clearLabelsFilter": _clearLabelsFilter, - "getLabelsFilter": _getLabelsFilter + "getLabelsFilter": _getLabelsFilter, + "deselectHiddenResources": _deselectHiddenResources, }; return TabDatatable; @@ -1252,4 +1253,27 @@ define(function(require) { function _getLabelsFilter() { return LabelsUtils.getLabelsFilter(this.dataTable); } + + function _deselectHiddenResources() { + var id_index = this.selectOptions.id_index + var currentSelect = this.retrieveResourceTableSelect() + var ensuredCurrentSelected = Array.isArray(currentSelect) ? currentSelect : [currentSelect] + ensuredCurrentSelected = ensuredCurrentSelected.filter(function(row) { return Boolean(row) }) + + var ids = this.dataTable.fnGetData() + .filter(function(res) { return ensuredCurrentSelected.includes(res[id_index]) }) + .map(function(res) { return res[id_index] }) + + var deselectIds = ensuredCurrentSelected.filter(function(rowId) { + return !ids.includes(rowId) + }) + + if (!!deselectIds.length) { + Notifier.notifyMessage("Deselect " + this.resource + ": " + deselectIds.join(',')); + } + + this.selectResourceTableSelect({ ids }); + + return ids + } });