diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create.js index 413eafa9fa..db9f0e3390 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create.js @@ -76,7 +76,7 @@ define(function(require) { var wizardTabInstance; $.each(WIZARD_TABS, function(index, wizardTab) { try { - wizardTabInstance = new wizardTab(); + wizardTabInstance = new wizardTab({listener: that}); wizardTabInstance.contentHTML = wizardTabInstance.html(); that.wizardTabs.push(wizardTabInstance); } catch (err) { @@ -97,6 +97,8 @@ define(function(require) { FormPanel.prototype.submitWizard = _submitWizard; FormPanel.prototype.submitAdvanced = _submitAdvanced; FormPanel.prototype.fill = _fill; + FormPanel.prototype.notify = _notify; + FormPanel.prototype.retrieve = _retrieve; return FormPanel; @@ -134,7 +136,7 @@ define(function(require) { }); } - function _submitWizard(context) { + function _retrieve(context) { var templateJSON = {} $.each(this.wizardTabs, function(index, wizardTab) { $.extend(true, templateJSON, wizardTab.retrieve($('#' + wizardTab.wizardTabId, context))); @@ -154,6 +156,12 @@ define(function(require) { delete templateJSON["VCENTER_PUBLIC_CLOUD"]; } + return templateJSON; + } + + function _submitWizard(context) { + var templateJSON = this.retrieve(context); + if (this.action == "create") { Sunstone.runAction("Template.create", {'vmtemplate': templateJSON}); return false; @@ -188,5 +196,34 @@ define(function(require) { $.each(this.wizardTabs, function(index, wizardTab) { wizardTab.fill($('#' + wizardTab.wizardTabId, context), templateJSON); }); + + // After all tabs have been filled, perform a notify + this.notify(); + } + + var in_progress = false; + + function _notify() { + var that = this; + + // Avoid lots of calls (debounce) + if(in_progress){ + return; + } + + in_progress = true; + + setTimeout(function(){ + var context = that.formContext; + var templateJSON = that.retrieve(context); + + $.each(that.wizardTabs, function(index, wizardTab) { + if (wizardTab.notify != undefined){ + wizardTab.notify($('#' + wizardTab.wizardTabId, context), templateJSON); + } + }); + + in_progress = false; + }, 500); } }); 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 180915779e..ea670a1cdd 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 @@ -45,7 +45,7 @@ define(function(require) { CONSTRUCTOR */ - function WizardTab() { + function WizardTab(opts) { if (!Config.isTemplateCreationTabEnabled('network')) { throw "Wizard Tab not enabled"; } @@ -54,6 +54,10 @@ define(function(require) { this.icon = 'fa-globe'; this.title = Locale.tr("Network"); this.classes = "hypervisor only_kvm only_vcenter" + + if(opts.listener != undefined){ + this.listener = opts.listener; + } } WizardTab.prototype.constructor = WizardTab; @@ -98,6 +102,12 @@ define(function(require) { }); that.addNicTab(context); + + if(that.listener != undefined){ + $(context).on("change", "input", function(){ + that.listener.notify(); + }); + } } function _retrieve(context) { @@ -202,5 +212,9 @@ define(function(require) { $("#" + LINKS_CONTAINER_ID + " li", context).each(function(index) { $("a", this).html(Locale.tr("NIC") + ' ' + index + " "); }) + + if(this.listener != undefined){ + this.listener.notify(); + } } }); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os.js index 3bdbe999c0..977c29efaf 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os.js @@ -169,6 +169,7 @@ define(function(require) { WizardTab.prototype.onShow = _onShow; WizardTab.prototype.retrieve = _retrieve; WizardTab.prototype.fill = _fill; + WizardTab.prototype.notify = _notify; return WizardTab; @@ -192,6 +193,28 @@ define(function(require) { var that = this; Foundation.reflow(context, 'tabs'); + context.on("click", "button.boot-order-up", function(){ + var tr = $(this).closest("tr"); + tr.prev().before(tr); + + _refreshBootValue(context); + + return false; + }); + + context.on("click", "button.boot-order-down", function(){ + var tr = $(this).closest("tr"); + tr.next().after(tr); + + _refreshBootValue(context); + + return false; + }); + + $("table.boot-order tbody", context).on("change", "input", function(){ + _refreshBootValue(context); + }); + var kernelDSContext = $(".kernel_ds", context); var kernelDSInputsContext = $("#kernel_path_inputs", context); $("input[name='kernel_type']", context).change(function() { @@ -251,15 +274,7 @@ define(function(require) { $.extend(osJSON, WizardFields.retrieve('.kernelTab', context)); $.extend(osJSON, WizardFields.retrieve('.ramdiskTab', context)); - var boot = ""; - var val; - for (var i = 0; i < 3; i++) { - val = $('#BOOT_' + i, context).val(); - if (val != undefined && val.length > 0) { - if (boot.length > 0) {boot += ","} - boot += val; - } - } + var boot = _retrieveBootValue(context); if (boot.length > 0) { osJSON["BOOT"] = boot; @@ -288,11 +303,7 @@ define(function(require) { WizardFields.fill(context, osJSON); if (osJSON && osJSON['BOOT']) { - var boot_vals = osJSON['BOOT'].split(","); - - for (var i = 0; i < 3 && i < boot_vals.length; i++) { - $('#BOOT_' + i, context).val(boot_vals[i]); - } + _fillBootValue(context, osJSON['BOOT']); } delete templateJSON['OS']; @@ -304,4 +315,108 @@ define(function(require) { delete templateJSON['FEATURES']; } } + + //---------------------------------------------------------------------------- + // Boot order + //---------------------------------------------------------------------------- + + function _retrieveBootValue(context) { + return $("table.boot-order", context).attr("value"); + } + + function _fillBootValue(context, value) { + return $("table.boot-order", context).attr("value", value); + } + + function _refreshBootValue(context) { + var table = $("table.boot-order", context); + + var devices = []; + + $.each($("tr", table), function(){ + if ($("input", this).is(":checked")){ + devices.push( $(this).attr("value") ); + } + }); + + table.attr("value", devices.join(',')); + } + + function _addBootRow(context, value, label) { + $("table.boot-order tbody", context).append( + ''+ + ''+ + ''+value+''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''); + } + + function _notify(context, templateJSON) { + var table = $("table.boot-order", context); + var prev_value = $(table).attr("value"); + + $("table.boot-order tbody", context).html(""); + + if (templateJSON.DISK != undefined){ + var disks = templateJSON.DISK; + + if (!$.isArray(disks)){ + disks = [disks]; + } + + $.each(disks, function(i,disk){ + var label = ' '; + + if (disk.IMAGE != undefined){ + label += disk.IMAGE; + } else if (disk.IMAGE_ID != undefined){ + label += Locale.tr("Image ID") + " " + disk.IMAGE_ID; + } else { + label += Locale.tr("Volatile"); + } + + _addBootRow(context, 'disk'+i, label); + }); + } + + if (templateJSON.NIC != undefined){ + var nics = templateJSON.NIC; + + if (!$.isArray(nics)){ + nics = [nics]; + } + $.each(nics, function(i,nic){ + var label = ' '; + + if (nic.NETWORK != undefined){ + label += nic.NETWORK; + } else if (nic.NETWORK_ID != undefined){ + label += Locale.tr("Network ID") + " " + nic.NETWORK_ID; + } else { + label += Locale.tr("Manual settings"); + } + + _addBootRow(context, 'nic'+i, label); + }); + } + + if (prev_value.length > 0){ + var pos = 0; + + $.each(prev_value.split(','), function(i,device){ + var tr = $('tr[value="'+device+'"]', table); + + if(tr.length > 0){ + $($("tr", table)[pos]).before(tr); + $("input", tr).click(); + + pos += 1; + } + }); + } + } }); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os/html.hbs index e7e24e5c76..bb8aaeab8a 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/os/html.hbs @@ -62,46 +62,16 @@ -
-
+
-
-
- -
-
- + + + +
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js index 7bd07255e7..78a22523d9 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage.js @@ -45,7 +45,7 @@ define(function(require) { CONSTRUCTOR */ - function WizardTab() { + function WizardTab(opts) { if (!Config.isTemplateCreationTabEnabled('storage')) { throw "Wizard Tab not enabled"; } @@ -54,6 +54,10 @@ define(function(require) { this.icon = 'fa-tasks'; this.title = Locale.tr("Storage"); this.classes = "hypervisor only_kvm only_vcenter" + + if(opts.listener != undefined){ + this.listener = opts.listener; + } } WizardTab.prototype.constructor = WizardTab; @@ -98,6 +102,12 @@ define(function(require) { }); that.addDiskTab(context); + + if(that.listener != undefined){ + $(context).on("change", "input", function(){ + that.listener.notify(); + }); + } } function _retrieve(context) { @@ -186,5 +196,9 @@ define(function(require) { $("#" + LINKS_CONTAINER_ID + " li", context).each(function(index) { $("a", this).html(Locale.tr("Disk") + ' ' + index + " "); }) + + if(this.listener != undefined){ + this.listener.notify(); + } } }); diff --git a/src/sunstone/public/app/tabs/vms-tab/form-panels/updateconf.js b/src/sunstone/public/app/tabs/vms-tab/form-panels/updateconf.js index d993d604b0..2131639b00 100644 --- a/src/sunstone/public/app/tabs/vms-tab/form-panels/updateconf.js +++ b/src/sunstone/public/app/tabs/vms-tab/form-panels/updateconf.js @@ -153,5 +153,14 @@ define(function(require) { $.each(this.wizardTabs, function(index, wizardTab) { wizardTab.fill($('#' + wizardTab.wizardTabId, context), templateJSON); }); + + // After all tabs have been filled, perform a notify. + // There isn't a proper listener because this wizard does not allow to edit + // the disks and nics + $.each(this.wizardTabs, function(index, wizardTab) { + if (wizardTab.notify != undefined){ + wizardTab.notify($('#' + wizardTab.wizardTabId, context), templateJSON); + } + }); } }); diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/conf.js b/src/sunstone/public/app/tabs/vms-tab/panels/conf.js index 276e228801..0f0d06548b 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/conf.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/conf.js @@ -97,7 +97,7 @@ define(function(require) { Sunstone.showFormPanel(TAB_ID, UPDATECONF_FORM_ID, "updateconf", function(formPanelInstance, context) { - formPanelInstance.fill(context, that.element.ID, that.conf); + formPanelInstance.fill(context, that.element.ID, that.element.TEMPLATE); }); return false; diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/conf/html.hbs b/src/sunstone/public/app/tabs/vms-tab/panels/conf/html.hbs index 2281a7e250..80e7ad2072 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/conf/html.hbs +++ b/src/sunstone/public/app/tabs/vms-tab/panels/conf/html.hbs @@ -18,7 +18,7 @@
{{#isTabActionEnabled "vms-tab" "VM.updateconf"}} - diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js index 6c5e2accca..7ef96f04b1 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js @@ -149,7 +149,7 @@ define(function(require) { var disks = []; if ($.isArray(that.element.TEMPLATE.DISK)) - disks = that.element.TEMPLATE.DISK; + disks = that.element.TEMPLATE.DISK.slice(0); // clone else if (!$.isEmptyObject(that.element.TEMPLATE.DISK)) disks = [that.element.TEMPLATE.DISK]; diff --git a/src/sunstone/public/app/utils/form-panels/form-panel.js b/src/sunstone/public/app/utils/form-panels/form-panel.js index 518c0f5bd5..2d16cfec74 100644 --- a/src/sunstone/public/app/utils/form-panels/form-panel.js +++ b/src/sunstone/public/app/utils/form-panels/form-panel.js @@ -22,6 +22,8 @@ define(function(require) { var Sunstone = require('sunstone'); function BaseFormPanel() { + this.formContext = $("#" + this.tabId+" div[form-panel-id="+this.formPanelId+"]"); + return this; } diff --git a/src/sunstone/public/app/utils/tab-datatable.js b/src/sunstone/public/app/utils/tab-datatable.js index 32df58f4aa..31671a0a7c 100644 --- a/src/sunstone/public/app/utils/tab-datatable.js +++ b/src/sunstone/public/app/utils/tab-datatable.js @@ -765,9 +765,9 @@ define(function(require) { $('#select_resource_' + that.dataTableId, section).hide(); $('.label', section).hide(); - $('#selected_resource_id_' + that.dataTableId, section).val(aData[that.selectOptions.id_index]).change(); + $('#selected_resource_id_' + that.dataTableId, section).val(aData[that.selectOptions.id_index]).trigger("change"); - $('#selected_resource_name_' + that.dataTableId, section).text(aData[that.selectOptions.name_index]).change(); + $('#selected_resource_name_' + that.dataTableId, section).text(aData[that.selectOptions.name_index]).trigger("change"); $('#selected_resource_name_' + that.dataTableId, section).show(); that.selectOptions.select_callback(aData, that.selectOptions); @@ -937,10 +937,10 @@ define(function(require) { // $('input.check_item', this).prop('checked', true); if (row_id !== undefined) { - $('#selected_resource_id_' + that.dataTableId, section).val(row_id).change(); + $('#selected_resource_id_' + that.dataTableId, section).val(row_id).trigger("change"); } - $('#selected_resource_name_' + that.dataTableId, section).text(row_name).change(); + $('#selected_resource_name_' + that.dataTableId, section).text(row_name).trigger("change"); $('#selected_resource_name_' + that.dataTableId, section).show(); that.refreshResourceTableSelect(section, that.dataTableId);