diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7f2b12f25f0..777642df0fd 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,6 +10,7 @@ //= require services/miq_db_backup_service //= require directives/scheduler/updateDropdownForFilter //= require directives/scheduler/updateDropdownForTimer +//= require directives/autofocus //= require directives/miqrequired //= require directives/checkchange //= require directives/verifypasswd @@ -17,6 +18,7 @@ //= require directives/repository/valid_unc_path //= require services/miq_service //= require services/timer_option_service +//= require controllers/ems_common/ems_common_form_controller.js //= require controllers/host/host_form_controller //= require controllers/provider_foreman/provider_foreman_form_controller //= require controllers/repository/repository_form_controller diff --git a/app/assets/javascripts/controllers/ems_common/ems_common_form_controller.js b/app/assets/javascripts/controllers/ems_common/ems_common_form_controller.js new file mode 100644 index 00000000000..da58c56e445 --- /dev/null +++ b/app/assets/javascripts/controllers/ems_common/ems_common_form_controller.js @@ -0,0 +1,200 @@ +ManageIQ.angularApplication.controller('emsCommonFormController', ['$http', '$scope', '$attrs', 'emsCommonFormId', 'miqService', function($http, $scope, $attrs, emsCommonFormId, miqService) { + var init = function() { + $scope.emsCommonModel = { + name: '', + emstype: '', + openstack_infra_providers_exist: false, + provider_id: '', + zone: '', + hostname: '', + api_port: '', + provider_region: '', + default_userid: '', + default_password: '', + default_verify: '', + amqp_userid: '', + amqp_password: '', + amqp_verify: '', + metrics_userid: '', + metrics_password: '', + metrics_verify: '', + ssh_keypair_userid: '', + ssh_keypair_password: '', + ssh_keypair_verify: '', + host_default_vnc_port_start: '', + host_default_vnc_port_end: '', + emstype_vm: false, + ems_common: true, + azure_tenant_id: '' + }; + $scope.formId = emsCommonFormId; + $scope.afterGet = false; + $scope.saveable = miqService.saveable; + $scope.restAjaxButton = miqService.restAjaxButton; + $scope.validateClicked = miqService.validateClicked; + $scope.modelCopy = angular.copy( $scope.emsCommonModel ); + $scope.formFieldsUrl = $attrs.formFieldsUrl; + $scope.createUrl = $attrs.createUrl; + $scope.updateUrl = $attrs.updateUrl; + $scope.model = 'emsCommonModel'; + + ManageIQ.angularApplication.$scope = $scope; + + if (emsCommonFormId == 'new') { + $scope.newRecord = true; + + miqService.sparkleOn(); + $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) { + $scope.emsCommonModel.zone = data.zone; + $scope.emsCommonModel.emstype_vm = data.emstype_vm; + $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist; + $scope.emsCommonModel.api_port = 5000; + miqService.sparkleOff(); + }); + $scope.afterGet = true; + $scope.modelCopy = angular.copy( $scope.emsCommonModel ); + } + else { + $scope.newRecord = false; + miqService.sparkleOn(); + + $http.get($scope.formFieldsUrl + emsCommonFormId).success(function(data) { + $scope.emsCommonModel.name = data.name; + $scope.emsCommonModel.emstype = data.emstype; + $scope.emsCommonModel.zone = data.zone; + $scope.emsCommonModel.hostname = data.hostname; + + $scope.emsCommonModel.openstack_infra_providers_exist = data.openstack_infra_providers_exist; + $scope.emsCommonModel.provider_id = data.provider_id.toString(); + + $scope.emsCommonModel.api_port = data.api_port; + $scope.emsCommonModel.provider_region = data.provider_region; + + $scope.emsCommonModel.default_userid = data.default_userid; + $scope.emsCommonModel.default_password = data.default_password; + $scope.emsCommonModel.default_verify = data.default_verify; + + $scope.emsCommonModel.amqp_userid = data.amqp_userid; + $scope.emsCommonModel.amqp_password = data.amqp_password; + $scope.emsCommonModel.amqp_verify = data.amqp_verify; + + $scope.emsCommonModel.azure_tenant_id = data.azure_tenant_id; + + $scope.afterGet = true; + $scope.modelCopy = angular.copy( $scope.emsCommonModel ); + + miqService.sparkleOff(); + }); + } + $scope.currentTab = "default" + + $scope.$watch("emsCommonModel.name", function() { + $scope.form = $scope.angularForm; + $scope.model = "emsCommonModel"; + }); + }; + + $scope.changeAuthTab = function(id) { + $scope.currentTab = id; + } + + $scope.canValidateBasicInfo = function () { + if ($scope.isBasicInfoValid()) + return true; + else + return false; + } + + $scope.isBasicInfoValid = function() { + if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype != "azure") && + ($scope.emsCommonModel.emstype == "ec2" || ($scope.emsCommonModel.emstype == "openstack" && $scope.emsCommonModel.hostname)) && + ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid && + $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid && + $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) { + return true; + } else if(($scope.currentTab == "amqp") && + ($scope.emsCommonModel.hostname) && + ($scope.emsCommonModel.amqp_userid != '' && $scope.angularForm.amqp_userid.$valid && + $scope.emsCommonModel.amqp_password != '' && $scope.angularForm.amqp_password.$valid && + $scope.emsCommonModel.amqp_verify != '' && $scope.angularForm.amqp_verify.$valid)) { + return true; + } else if(($scope.currentTab == "default" && $scope.emsCommonModel.emstype == "azure") && + ($scope.emsCommonModel.azure_tenant_id != '' && $scope.angularForm.azure_tenant_id.$valid) && + ($scope.emsCommonModel.default_userid != '' && $scope.angularForm.default_userid.$valid && + $scope.emsCommonModel.default_password != '' && $scope.angularForm.default_password.$valid && + $scope.emsCommonModel.default_verify != '' && $scope.angularForm.default_verify.$valid)) { + return true; + } + else + return false; + }; + + var emsCommonEditButtonClicked = function(buttonName, serializeFields, $event) { + miqService.sparkleOn(); + var url = $scope.updateUrl + '?button=' + buttonName; + miqService.restAjaxButton(url, $event.target); + }; + + var emsCommonAddButtonClicked = function(buttonName, serializeFields, $event) { + miqService.sparkleOn(); + var url = $scope.createUrl + '?button=' + buttonName; + miqService.restAjaxButton(url, $event.target); + }; + + $scope.cancelClicked = function($event) { + angular.element('#button_name').val('cancel'); + if($scope.newRecord) + emsCommonAddButtonClicked('cancel', false, $event); + else + emsCommonEditButtonClicked('cancel', false, $event); + + $scope.angularForm.$setPristine(true); + }; + + $scope.resetClicked = function() { + $scope.emsCommonModel = angular.copy( $scope.modelCopy ); + $scope.angularForm.$setPristine(true); + miqService.miqFlash("warn", "All changes have been reset"); + }; + + $scope.saveClicked = function($event, formSubmit) { + if(formSubmit) { + angular.element('#button_name').val('save'); + emsCommonEditButtonClicked('save', true, $event); + $scope.angularForm.$setPristine(true); + } + else { + $event.preventDefault(); + } + }; + + $scope.validateBClicked = function($event, credType, url, formSubmit) { + angular.element('#button_name').val('validate'); + angular.element('#cred_type').val(credType); + if(formSubmit) { + miqService.sparkleOn(); + miqService.restAjaxButton(url, $event.target); + } + else { + $event.preventDefault(); + } + }; + + $scope.addClicked = function($event, formSubmit) { + if(formSubmit) { + angular.element('#button_name').val('add'); + emsCommonAddButtonClicked('add', true, $event); + $scope.angularForm.$setPristine(true); + } + else { + $event.preventDefault(); + } + }; + + $scope.$watch('$viewContentLoaded', function() { + $scope.afterGet = true; + }); + + init(); +}]); + diff --git a/app/assets/javascripts/directives/autofocus.js b/app/assets/javascripts/directives/autofocus.js new file mode 100644 index 00000000000..210c298cffa --- /dev/null +++ b/app/assets/javascripts/directives/autofocus.js @@ -0,0 +1,14 @@ +ManageIQ.angularApplication.directive('autoFocus', ['$timeout', function($timeout) { + return { + require: 'ngModel', + link: function (scope, elem, attr, ctrl) { + scope['form_focus_' + ctrl.$name] = elem[0]; + + scope.$watch(scope['afterGet'], function() { + $timeout(function(){ + angular.element(scope['form_focus_' + ctrl.$name]).focus(); + }, 0); + }); + } + } +}]); \ No newline at end of file diff --git a/app/assets/javascripts/directives/checkchange.js b/app/assets/javascripts/directives/checkchange.js index 71e50f4c458..891ec9ac781 100644 --- a/app/assets/javascripts/directives/checkchange.js +++ b/app/assets/javascripts/directives/checkchange.js @@ -20,29 +20,29 @@ ManageIQ.angularApplication.directive('checkchange', ['miqService', function(miq miqService.miqFlashClear(); if (value == scope.modelCopy[ctrl.$name]) { - scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(true); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(); } if(scope.angularForm[scope['formchange_' + ctrl.$name]].$pristine) { checkForOverallFormPristinity(scope, ctrl); } - scope.angularForm[scope['formchange_' + ctrl.$name]].$setTouched(true); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setTouched(); return value; }); if(scope.angularForm.$pristine) - scope.angularForm.$setPristine(true); + scope.angularForm.$setPristine(); } } }]); var viewModelComparison = function(scope, ctrl) { if (ctrl.$viewValue == scope.modelCopy[ctrl.$name]) { - scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(true); - scope.angularForm[scope['formchange_' + ctrl.$name]].$setUntouched(true); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setUntouched(); scope.angularForm.$pristine = true; } else { - scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(false); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setDirty(); scope.angularForm.$pristine = false; } }; @@ -52,11 +52,11 @@ var viewModelDateComparison = function(scope, ctrl) { var copyDate = moment(scope.modelCopy[ctrl.$name]); if (modelDate.diff(copyDate, 'days') == 0) { - scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(true); - scope.angularForm[scope['formchange_' + ctrl.$name]].$setUntouched(true); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setUntouched(); scope.angularForm.$pristine = true; } else { - scope.angularForm[scope['formchange_' + ctrl.$name]].$setPristine(false); + scope.angularForm[scope['formchange_' + ctrl.$name]].$setDirty(); scope.angularForm.$pristine = false; } }; @@ -75,5 +75,5 @@ var checkForOverallFormPristinity = function(scope, ctrl) { scope.angularForm.$pristine = _.isEqual(modelCopyObject, modelObject); if (scope.angularForm.$pristine) - scope.angularForm.$setPristine(true); + scope.angularForm.$setPristine(); }; diff --git a/app/assets/javascripts/miq_application.js b/app/assets/javascripts/miq_application.js index a6baa7a62c2..8545349444c 100644 --- a/app/assets/javascripts/miq_application.js +++ b/app/assets/javascripts/miq_application.js @@ -734,6 +734,29 @@ function miqChartMenuClick(itemId) { } } +function miqRESTAjaxButton(url, button, data) { + var form = $(button).parents('form:first')[0]; + if (form) { + $(form).submit(function(e) { + e.preventDefault(); + return false; + }); + if(data != undefined) { + formData = data; + } + else { + formData = $(form).serialize(); + } + miqJqueryRequest(form.action, { + beforeSend: true, + complete: true, + data: formData + }); + } else { + miqAjaxButton(url, true); + } +} + // Handle an ajax form button press (i.e. Submit) by starting the spinning Q, // then waiting for .7 seconds for observers to finish function miqAjaxButton(url, serialize_fields) { @@ -1028,6 +1051,9 @@ function miq_tabs_init(id, url) { if ($(id + ' > ul.nav-tabs > li:not(.hidden)').length == 1) { $(id + ' > ul.nav-tabs').hide(); } + else if ($(id + ' > ul.nav-tabs > li:not(.hidden)').length > 1) { + $(id + ' > ul.nav-tabs').show(); + } } function miq_tabs_disable_inactive(id) { diff --git a/app/assets/javascripts/miq_dhtmlxgrid.js b/app/assets/javascripts/miq_dhtmlxgrid.js index 0894f62db72..e337df8c3ea 100644 --- a/app/assets/javascripts/miq_dhtmlxgrid.js +++ b/app/assets/javascripts/miq_dhtmlxgrid.js @@ -1,3 +1,16 @@ +// ES6 endsWith polyfill +if (!String.prototype.endsWith) { + String.prototype.endsWith = function(searchString, position) { + var subjectString = this.toString(); + if (position === undefined || position > subjectString.length) { + position = subjectString.length; + } + position -= searchString.length; + var lastIndex = subjectString.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + }; +} + // Functions used by MIQ for the dhtmlxtree control // Function to pass ajax request to server, to remember tree states @@ -13,6 +26,9 @@ function miqRowClick(row_id, cell_idx) { if (typeof row_url_ajax != "undefined" && row_url_ajax) { miqJqueryRequest(row_url + row_id, {beforeSend: true, complete: true}); } else { + if (!row_url.endsWith("/")) { + row_url = row_url + "/"; + } DoNav(row_url + row_id); } } diff --git a/app/assets/javascripts/services/miq_service.js b/app/assets/javascripts/services/miq_service.js index 3455663b70d..9926955f8e3 100644 --- a/app/assets/javascripts/services/miq_service.js +++ b/app/assets/javascripts/services/miq_service.js @@ -16,6 +16,14 @@ ManageIQ.angularApplication.service('miqService', function() { miqAjaxButton(url, serializeFields); }; + this.restAjaxButton = function(url, button, data) { + miqRESTAjaxButton(url, button, data); + }; + + this.jqueryRequest = function(url, options) { + miqJqueryRequest(url, options); + }; + this.sparkleOn = function() { miqSparkleOn(); }; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2b172fda5e2..7759e50c729 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2641,4 +2641,8 @@ def flip_sort_direction(direction) def skip_breadcrumb? false end + + def restful? + false + end end diff --git a/app/controllers/ems_cloud_controller.rb b/app/controllers/ems_cloud_controller.rb index 39a5a1fb13e..f13d5c44287 100644 --- a/app/controllers/ems_cloud_controller.rb +++ b/app/controllers/ems_cloud_controller.rb @@ -18,8 +18,200 @@ def index redirect_to :action => 'show_list' end + def update + assert_privileges("#{permission_prefix}_edit") + case params[:button] + when "cancel" then update_ems_button_cancel + when "save" then update_ems_button_save + when "validate" then update_ems_button_validate + end + end + + def update_ems_button_cancel + update_ems = find_by_id_filtered(model, params[:id]) + model_name = model.to_s + flash_msg = _("Edit of %{model} \"%{name}\" was cancelled by the user") % + {:model => ui_lookup(:model => model_name), + :name => update_ems.name} + render :update do |page| + if @lastaction == "show" + page.redirect_to ems_cloud_path(update_ems, :flash_msg => flash_msg) + else + page.redirect_to(:action => @lastaction, + :id => update_ems.id, + :display => session[:ems_display], + :flash_msg => flash_msg) + end + end + end + + def update_ems_button_save + update_ems = find_by_id_filtered(model, params[:id]) + set_ems_record_vars(update_ems) + if update_ems.save + update_ems.reload + flash = _("%{model} \"%{name}\" was saved") % + {:model => ui_lookup(:model => model.to_s), + :name => update_ems.name} + construct_edit_for_audit(update_ems) + AuditEvent.success(build_saved_audit(update_ems, @edit)) + render :update do |page| + page.redirect_to ems_cloud_path(update_ems, :flash_msg => flash) + end + return + else + update_ems.errors.each do |field, msg| + add_flash("#{field.to_s.capitalize} #{msg}", :error) + end + drop_breadcrumb(:name => "Edit #{ui_lookup(:table => @table_name)} '#{update_ems.name}'", + :url => "/#{@table_name}/edit/#{update_ems.id}") + @in_a_form = true + render_flash + end + end + + def update_ems_button_validate(verify_ems = nil) + verify_ems ||= find_by_id_filtered(model, params[:id]) + set_ems_record_vars(verify_ems, :validate) + @in_a_form = true + + save = params[:id] == "new" ? false : true + result, details = verify_ems.authentication_check(params[:cred_type], :save => save) + if result + add_flash(_("Credential validation was successful")) + else + add_flash(_("Credential validation was not successful: %s") % details, :error) + end + + render_flash + end + + def create + assert_privileges("#{permission_prefix}_new") + + case params[:button] + when "add" then create_ems_button_add + when "validate" then create_ems_button_validate + when "cancel" then create_ems_button_cancel + end + end + + def create_ems_button_add + ems = model.model_from_emstype(params[:emstype]).new + set_ems_record_vars(ems) unless @flash_array + if ems.valid? && ems.save + construct_edit_for_audit(ems) + AuditEvent.success(build_created_audit(ems, @edit)) + flash_msg = _("%{model} \"%{name}\" was saved") % {:model => ui_lookup(:tables => @table_name), + :name => ems.name} + render :update do |page| + page.redirect_to :action => 'show_list', + :flash_msg => flash_msg + end + else + @in_a_form = true + ems.errors.each do |field, msg| + add_flash("#{ems.class.human_attribute_name(field)} #{msg}", :error) + end + + drop_breadcrumb(:name => "Add New #{ui_lookup(:tables => table_name)}", :url => new_ems_cloud_path) + render :update do |page| + page.replace("flash_msg_div", :partial => "layouts/flash_msg") + end + end + end + + def create_ems_button_validate + ems = model.model_from_emstype(params[:emstype]).new + update_ems_button_validate(ems) + end + + def create_ems_button_cancel + model_name = model.to_s + render :update do |page| + page.redirect_to(:action => @lastaction, + :display => session[:ems_display], + :flash_msg => _("Add of %{model} was cancelled by the user") % + {:model => ui_lookup(:model => model_name)}) + end + end + + def ems_cloud_form_fields + assert_privileges("#{permission_prefix}_edit") + @ems = model.new if params[:id] == 'new' + @ems = find_by_id_filtered(model, params[:id]) if params[:id] != 'new' + + if @ems.zone.nil? || @ems.my_zone == "" + zone = "default" + else + zone = @ems.my_zone + end + + metrics_userid = @ems.has_authentication_type?(:metrics) ? @ems.authentication_userid(:metrics).to_s : "" + metrics_password = @ems.has_authentication_type?(:metrics) ? @ems.authentication_password(:metrics).to_s : "" + metrics_verify = @ems.has_authentication_type?(:metrics) ? @ems.authentication_password(:metrics).to_s : "" + + amqp_userid = @ems.has_authentication_type?(:amqp) ? @ems.authentication_userid(:amqp).to_s : "" + amqp_password = @ems.has_authentication_type?(:amqp) ? @ems.authentication_password(:amqp).to_s : "" + amqp_verify = @ems.has_authentication_type?(:amqp) ? @ems.authentication_password(:amqp).to_s : "" + + ssh_keypair_userid = @ems.has_authentication_type?(:ssh_keypair) ? @ems.authentication_userid(:ssh_keypair).to_s : "" + ssh_keypair_password = @ems.has_authentication_type?(:ssh_keypair) ? @ems.authentication_key(:ssh_keypair).to_s : "" + + bearer_token = @ems.has_authentication_type?(:bearer) ? @ems.authentication_token(:bearer).to_s : "" + bearer_verify = @ems.has_authentication_type?(:bearer) ? @ems.authentication_token(:bearer).to_s : "" + + if @ems.kind_of?(ManageIQ::Providers::Vmware::InfraManager) + host_default_vnc_port_start = @ems.host_default_vnc_port_start.to_s + host_default_vnc_port_end = @ems.host_default_vnc_port_end.to_s + end + + if @ems.kind_of?(ManageIQ::Providers::Azure::CloudManager) + azure_tenant_id = @ems.azure_tenant_id + client_id = @ems.authentication_userid ? @ems.authentication_userid : "" + client_key = @ems.authentication_password ? @ems.authentication_password : "" + end + + render :json => {:name => @ems.name, + :emstype => @ems.emstype, + :zone => zone, + :provider_id => @ems.provider_id ? @ems.provider_id : "", + :hostname => @ems.hostname, + :api_port => @ems.port, + :provider_region => @ems.provider_region, + :openstack_infra_providers_exist => retrieve_openstack_infra_providers.length > 0 ? true : false, + :default_userid => @ems.authentication_userid ? @ems.authentication_userid : "", + :default_password => @ems.authentication_password ? @ems.authentication_password : "", + :default_verify => @ems.authentication_password ? @ems.authentication_password : "", + :metrics_userid => metrics_userid, + :metrics_password => metrics_password, + :metrics_verify => metrics_verify, + :amqp_userid => amqp_userid, + :amqp_password => amqp_password, + :amqp_verify => amqp_verify, + :ssh_keypair_userid => ssh_keypair_userid, + :ssh_keypair_password => ssh_keypair_password, + :bearer_token => bearer_token, + :bearer_verify => bearer_verify, + :azure_tenant_id => azure_tenant_id ? azure_tenant_id : "", + :client_id => client_id ? client_id : "", + :client_key => client_key ? client_key : "", + :host_default_vnc_port_start => host_default_vnc_port_start, + :host_default_vnc_port_end => host_default_vnc_port_end, + :emstype_vm => @ems.kind_of?(ManageIQ::Providers::Vmware::InfraManager) + } + end + private ############################ + def table_name + self.class.table_name + end + + def no_blank(thing) + thing.blank? ? nil : thing + end + def get_session_data @title = ui_lookup(:tables => "ems_cloud") @layout = "ems_cloud" @@ -36,4 +228,72 @@ def set_session_data session[:ems_cloud_filters] = @filters session[:ems_cloud_catinfo] = @catinfo end + + def show_link(ems, options = {}) + ems_cloud_path(ems.id, options) + end + + def set_ems_record_vars(ems, mode = nil) + ems.name = params[:name] + ems.provider_region = params[:provider_region] + ems.hostname = params[:hostname] + ems.port = params[:api_port] + ems.provider_id = params[:provider_id] + ems.zone = Zone.find_by_name(params[:zone]) + + if ems.kind_of?(ManageIQ::Providers::Microsoft::InfraManager) + ems.security_protocol = params[:security_protocol] + ems.realm = params[:realm] + end + + if ems.kind_of?(ManageIQ::Providers::Vmware::InfraManager) + ems.host_default_vnc_port_start = params[:host_default_vnc_port_start].blank? ? nil : params[:host_default_vnc_port_start].to_i + ems.host_default_vnc_port_end = params[:host_default_vnc_port_end].blank? ? nil : params[:host_default_vnc_port_end].to_i + end + + ems.azure_tenant_id = params[:azure_tenant_id] if ems.kind_of?(ManageIQ::Providers::Azure::CloudManager) + + creds = {} + creds[:default] = {:userid => params[:default_userid], + :password => params[:default_password]} unless params[:default_userid].blank? + if ems.supports_authentication?(:metrics) && !params[:metrics_userid].blank? + creds[:metrics] = {:userid => params[:metrics_userid], :password => params[:metrics_password]} + end + if ems.supports_authentication?(:amqp) && !params[:amqp_userid].blank? + creds[:amqp] = {:userid => params[:amqp_userid], :password => params[:amqp_password]} + end + if ems.supports_authentication?(:ssh_keypair) && !params[:ssh_keypair_userid].blank? + creds[:ssh_keypair] = {:userid => params[:ssh_keypair_userid], :auth_key => params[:ssh_keypair_password]} + end + if ems.supports_authentication?(:bearer) && !params[:bearer_token].blank? + creds[:bearer] = {:auth_key => params[:bearer_token], :userid => "_"} # Must have userid + end + + ems.update_authentication(creds, :save => (mode != :validate)) + end + + def construct_edit_for_audit(ems) + @edit ||= {} + ems.kind_of?(ManageIQ::Providers::Azure::CloudManager) ? azure_tenant_id = ems.azure_tenant_id : azure_tenant_id = nil; + @edit[:current] = {:name => ems.name, + :provider_region => ems.provider_region, + :hostname => ems.hostname, + :azure_tenant_id => azure_tenant_id, + :port => ems.port, + :provider_id => ems.provider_id, + :zone => ems.zone + } + @edit[:new] = {:name => params[:name], + :provider_region => params[:provider_region], + :hostname => params[:hostname], + :azure_tenant_id => params[:azure_tenant_id], + :port => params[:port], + :provider_id => params[:provider_id], + :zone => params[:zone] + } + end + + def restful? + true + end end diff --git a/app/controllers/ems_common.rb b/app/controllers/ems_common.rb index d2c73509c33..ef8d2a123a7 100644 --- a/app/controllers/ems_common.rb +++ b/app/controllers/ems_common.rb @@ -9,24 +9,24 @@ def show @ems = @record = identify_record(params[:id]) return if record_no_longer_exists?(@ems) - @gtl_url = "/#{@table_name}/show/" << @ems.id.to_s << "?" + @gtl_url = show_link(@ems) << "?" @showtype = "config" drop_breadcrumb({:name=>ui_lookup(:tables=>@table_name), :url=>"/#{@table_name}/show_list?page=#{@current_page}&refresh=y"}, true) if ["download_pdf","main","summary_only"].include?(@display) get_tagdata(@ems) - drop_breadcrumb( {:name=>@ems.name + " (Summary)", :url=>"/#{@table_name}/show/#{@ems.id}"} ) + drop_breadcrumb(:name => @ems.name + " (Summary)", :url => show_link(@ems)) @showtype = "main" set_summary_pdf_data if ["download_pdf","summary_only"].include?(@display) elsif @display == "props" - drop_breadcrumb( {:name=>@ems.name+" (Properties)", :url=>"/#{@table_name}/show/#{@ems.id}?display=props"} ) + drop_breadcrumb(:name => @ems.name + " (Properties)", :url => show_link(@ems, :display => "props")) elsif @display == "ems_folders" if params[:vat] - drop_breadcrumb({:name=>@ems.name+" (VMs & Templates)", - :url=>"/#{@table_name}/show/#{@ems.id}?display=ems_folders&vat=true"}) + drop_breadcrumb(:name => @ems.name + " (VMs & Templates)", + :url => show_link(@ems, :display => "ems_folder", :vat => "true")) else - drop_breadcrumb({:name=>@ems.name+" (Hosts & Clusters)", - :url=>"/#{@table_name}/show/#{@ems.id}?display=ems_folders"} ) + drop_breadcrumb(:name => @ems.name + " (Hosts & Clusters)", + :url => show_link(@ems, :display => "ems_folders")) end @showtype = "config" build_dc_tree @@ -37,7 +37,7 @@ def show @timeline = @timeline_filter = true @lastaction = "show_timeline" tl_build_timeline # Create the timeline report - drop_breadcrumb( {:name=>"Timelines", :url=>"/#{@table_name}/show/#{@record.id}?refresh=n&display=timeline"} ) + drop_breadcrumb(:name => "Timelines", :url => show_link(@record.id, :refresh => "n", :display => "timeline")) elsif ["instances","images","miq_templates","vms"].include?(@display) || session[:display] == "vms" && params[:display].nil? if @display == "instances" title = "Instances" @@ -52,7 +52,7 @@ def show title = "VMs" kls = Vm end - drop_breadcrumb( {:name=>@ems.name+" (All #{title})", :url=>"/#{@table_name}/show/#{@ems.id}?display=#{@display}"} ) + drop_breadcrumb(:name => @ems.name + " (All #{title})", :url => show_link(@ems, :display => @display)) @view, @pages = get_view(kls, :parent=>@ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @view.extras[:auth_count] && @@ -61,7 +61,7 @@ def show end elsif @display == "availability_zones" || session[:display] == "availability_zones" && params[:display].nil? title = "Availability Zones" - drop_breadcrumb( {:name=>@ems.name+" (All #{title})", :url=>"/#{@table_name}/show/#{@ems.id}?display=#{@display}"} ) + drop_breadcrumb(:name => @ems.name + " (All #{title})", :url => show_link(@ems, :display => @display)) @view, @pages = get_view(AvailabilityZone, :parent=>@ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @view.extras[:auth_count] && @@ -71,7 +71,7 @@ def show elsif @display == "container_replicators" || session[:display] == "container_replicators" && params[:display].nil? title = ui_lookup(:tables => "container_replicators") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerReplicator, :parent => @ems) @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -83,7 +83,7 @@ def show elsif @display == "containers" || session[:display] == "containers" && params[:display].nil? title = ui_lookup(:tables => "containers") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(Container, :parent => @ems) @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -95,7 +95,7 @@ def show elsif @display == "container_nodes" || session[:display] == "container_nodes" && params[:display].nil? title = "Container Nodes" drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerNode, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -107,7 +107,7 @@ def show elsif @display == "container_services" || session[:display] == "container_services" && params[:display].nil? title = "Container Services" drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerService, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -119,7 +119,7 @@ def show elsif @display == "container_groups" || session[:display] == "container_groups" && params[:display].nil? title = "Pods" drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerGroup, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -131,7 +131,7 @@ def show elsif @display == "container_routes" || session[:display] == "container_routes" && params[:display].nil? title = ui_lookup(:tables => "container_routes") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerRoute, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -143,7 +143,7 @@ def show elsif @display == "container_projects" || session[:display] == "container_projects" && params[:display].nil? title = ui_lookup(:tables => "container_projects") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerProject, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -156,7 +156,7 @@ def show session[:display] == "container_image_registries" && params[:display].nil? title = ui_lookup(:tables => "container_image_registries") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerImageRegistry, :parent => @ems) # Get the records into a view and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -168,7 +168,7 @@ def show elsif @display == "container_images" || session[:display] == "container_images" && params[:display].nil? title = ui_lookup(:tables => "container_images") drop_breadcrumb(:name => @ems.name + " (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(ContainerImage, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] > @view.extras[:auth_count] && @view.extras[:total_count] && @@ -179,7 +179,7 @@ def show end elsif @display == "cloud_tenants" || (session[:display] == "cloud_tenants" && params[:display].nil?) title = "Cloud Tenants" - drop_breadcrumb( {:name => "#{@ems.name} (All #{title})", :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}"} ) + drop_breadcrumb(:name => "#{@ems.name} (All #{title})", :url => show_link(@ems, :display => @display)) @view, @pages = get_view(CloudTenant, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @view.extras[:auth_count] && @view.extras[:total_count] > @view.extras[:auth_count] @@ -187,7 +187,7 @@ def show end elsif @display == "flavors" || session[:display] == "flavors" && params[:display].nil? title = "Flavors" - drop_breadcrumb( {:name=>@ems.name+" (All #{title})", :url=>"/#{@table_name}/show/#{@ems.id}?display=#{@display}"} ) + drop_breadcrumb(:name => @ems.name + " (All #{title})", :url => show_link(@ems, :display => @display)) @view, @pages = get_view(Flavor, :parent=>@ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @view.extras[:auth_count] && @@ -196,7 +196,7 @@ def show end elsif @display == "security_groups" || session[:display] == "security_groups" && params[:display].nil? title = "Security Groups" - drop_breadcrumb( {:name=>@ems.name+" (All #{title})", :url=>"/#{@table_name}/show/#{@ems.id}?display=#{@display}"} ) + drop_breadcrumb(:name => @ems.name + " (All #{title})", :url => show_link(@ems, :display => @display)) @view, @pages = get_view(SecurityGroup, :parent=>@ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @view.extras[:auth_count] && @@ -204,7 +204,8 @@ def show @bottom_msg = "* You are not authorized to view " + pluralize(@view.extras[:total_count] - @view.extras[:auth_count], "other #{title.singularize}") + " on this " + ui_lookup(:tables=>@table_name) end elsif @display == "storages" || session[:display] == "storages" && params[:display].nil? - drop_breadcrumb( {:name=>@ems.name+" (All Managed #{ui_lookup(:tables=>"storages")})", :url=>"/#{@table_name}/show/#{@ems.id}?display=storages"} ) + drop_breadcrumb(:name => @ems.name + " (All Managed #{ui_lookup(:tables => "storages")})", + :url => show_link(@ems, :display => "storages")) @view, @pages = get_view(Storage, :parent=>@ems) # Get the records (into a view) and the paginator if @view.extras[:total_count] && @view.extras[:auth_count] && @view.extras[:total_count] > @view.extras[:auth_count] @@ -212,7 +213,7 @@ def show end elsif @display == "ems_clusters" drop_breadcrumb(:name => "#{@ems.name} (All #{title_for_clusters})", - :url => "/#{@table_name}/show/#{@ems.id}?display=ems_clusters") + :url => show_link(@ems, :display => "ems_clusters")) @view, @pages = get_view(EmsCluster, :parent=>@ems) # Get the records (into a view) and the paginator if @view.extras[:total_count] && @view.extras[:auth_count] && @view.extras[:total_count] > @view.extras[:auth_count] @@ -221,7 +222,7 @@ def show elsif @display == "orchestration_stacks" || session[:display] == "orchestration_stacks" && params[:display].nil? title = "Stacks" drop_breadcrumb(:name => "#{@ems.name} (All #{title})", - :url => "/#{@table_name}/show/#{@ems.id}?display=#{@display}") + :url => show_link(@ems, :display => @display)) @view, @pages = get_view(OrchestrationStack, :parent => @ems) # Get the records (into a view) and the paginator @showtype = @display if @view.extras[:total_count] && @@ -231,7 +232,7 @@ def show @bottom_msg = "* You are not authorized to view #{count_text} on this #{ui_lookup(:tables => @table_name)}" end else # Must be Hosts # FIXME !!! - drop_breadcrumb( {:name=>@ems.name+" (All Managed Hosts)", :url=>"/#{@table_name}/show/#{@ems.id}?display=hosts"} ) + drop_breadcrumb(:name => @ems.name + " (All Managed Hosts)", :url => show_link(@ems, :display => :hosts)) @view, @pages = get_view(Host, :parent=>@ems) # Get the records (into a view) and the paginator if @view.extras[:total_count] && @view.extras[:auth_count] && @view.extras[:total_count] > @view.extras[:auth_count] @@ -543,8 +544,14 @@ def button end end else - render :update do |page| - page.redirect_to :action=>@refresh_partial, :id=>@redirect_id + if params[:pressed] == "ems_cloud_edit" && params[:id] + render :update do |page| + page.redirect_to edit_ems_cloud_path(params[:id]) + end + else + render :update do |page| + page.redirect_to :action=>@refresh_partial, :id=>@redirect_id + end end end else @@ -691,6 +698,7 @@ def valid_record?(ems) # Set form variables for edit def set_form_vars + form_instance_vars @edit = Hash.new @edit[:ems_id] = @ems.id @@ -757,6 +765,18 @@ def set_form_vars session[:edit] = @edit end + def form_instance_vars + @server_zones = [] + zones = Zone.order('lower(description)') + zones.each do |zone| + @server_zones.push([zone.description, zone.name]) + end + @ems_types = Array(model.supported_types_and_descriptions_hash.invert).sort_by(&:first) + @amazon_regions = get_amazon_regions + @openstack_infra_providers = retrieve_openstack_infra_providers + @emstype_display = model.supported_types_and_descriptions_hash[@ems.emstype] + end + def get_amazon_regions regions = Hash.new ManageIQ::Providers::Amazon::Regions.all.each do |region| @@ -765,6 +785,16 @@ def get_amazon_regions return regions end + def retrieve_openstack_infra_providers + openstack_infra_providers = [] + ManageIQ::Providers::Openstack::Provider.all.each do |provider| + openstack_infra_providers = [ + [provider[:name], provider[:id]] + ] + end + openstack_infra_providers + end + # Get variables from edit form def get_form_vars @ems = @edit[:ems_id] ? model.find_by_id(@edit[:ems_id]) : model.new @@ -1026,4 +1056,10 @@ def model def permission_prefix self.class.permission_prefix end + + def show_link(ems, options = {}) + url_for(options.merge(:controller => @table_name, + :action => "show", + :id => ems.id)) + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b0bf6b339e2..00c3b23d2e1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -108,16 +108,19 @@ def controller_to_model def url_for_record(record, action="show") # Default action is show @id = to_cid(record.id) if record.kind_of?(VmOrTemplate) - return url_for_db(controller_for_vm(model_for_vm(record)), action) + return url_for_db(controller_for_vm(model_for_vm(record)), action, record) elsif record.class.respond_to?(:db_name) - return url_for_db(record.class.db_name, action) + return url_for_db(record.class.db_name, action, record) else - return url_for_db(record.class.base_class.to_s, action) + return url_for_db(record.class.base_class.to_s, action, record) end end # Create a url for a record that links to the proper controller - def url_for_db(db, action="show") # Default action is show + def url_for_db(db, action="show", item = nil) # Default action is show + if item && EmsCloud === item + return ems_cloud_path(item.id) + end if @vm && ["Account", "User", "Group", "Patch", "GuestApplication"].include?(db) return url_for(:controller => "vm_or_template", :action => @lastaction, @@ -162,6 +165,9 @@ def view_to_url(view, parent=nil) end if association == nil controller, action = db_to_controller(view.db) + if controller == "ems_cloud" && action == "show" + return ems_clouds_path + end if parent && parent.class.base_model.to_s == "MiqCimInstance" && ["CimBaseStorageExtent","SniaLocalFileSystem"].include?(view.db) return url_for(:controller=>controller, :action=>action, :id=>parent.id) + "?show=" else diff --git a/app/helpers/application_helper/toolbar_builder.rb b/app/helpers/application_helper/toolbar_builder.rb index 1738ea3206b..c9e3338fd50 100644 --- a/app/helpers/application_helper/toolbar_builder.rb +++ b/app/helpers/application_helper/toolbar_builder.rb @@ -1327,6 +1327,9 @@ def build_toolbar_save_button(tb_buttons, item, parent = nil) ridx = url.rindex('/') if url url = url.slice(0..ridx-1) if ridx end + if item[:full_path] + tb_buttons[button][:full_path] = ERB.new(item[:full_path]).result(@view_binding) + end tb_buttons[button][:url] = url if item[:url] tb_buttons[button][:explorer] = true if @explorer && !item[:url] # Add explorer = true if ajax button if item[:popup] diff --git a/app/helpers/textual_summary_helper.rb b/app/helpers/textual_summary_helper.rb index 00db3a50471..410ee2e3ee9 100644 --- a/app/helpers/textual_summary_helper.rb +++ b/app/helpers/textual_summary_helper.rb @@ -14,6 +14,12 @@ def expand_textual_summary(summary, context) summary when Symbol result = send("textual_#{summary}") + if result.kind_of?(Hash) && result[:link] && controller.send(:restful?) + restful_path = controller.send("#{controller_name}_path") + url = Addressable::URI.parse(restful_path) + url.query_values = (url.query_values || {}).merge(:display => summary) + result[:link] = url.to_s + end return result if result.kind_of?(Hash) && result[:label] automatic_label = context.class.human_attribute_name(summary, :default => summary.to_s.titleize) @@ -87,7 +93,7 @@ def textual_object_link(object, as: nil, controller: nil, feature: nil, label: n h end - def textual_collection_link(collection, as: nil, controller: nil, explorer: false, feature: nil, label: nil, link: nil) + def textual_collection_link(collection, as: nil, controller_collection: nil, explorer: false, feature: nil, label: nil, link: nil) if collection.kind_of?(Array) unless as && link raise ArgumentError, ":as and :link are both required when linking to an array", @@ -97,8 +103,8 @@ def textual_collection_link(collection, as: nil, controller: nil, explorer: fals klass = as || collection.klass.base_model - controller ||= klass.name.underscore - feature ||= "#{controller}_show_list" + controller_collection ||= klass.name.underscore + feature ||= "#{controller_collection}_show_list" label ||= ui_lookup(:models => klass.name) image = textual_collection_icon(collection, klass) @@ -110,11 +116,18 @@ def textual_collection_link(collection, as: nil, controller: nil, explorer: fals if link h[:link] = link elsif collection.respond_to?(:proxy_association) - h[:link] = url_for(:action => 'show', - :id => collection.proxy_association.owner, - :display => collection.proxy_association.reflection.name) + if controller.send(:restful?) + restful_path = controller.send("#{controller_name}_path") + url = Addressable::URI.parse(restful_path) + url.query_values = (url.query_values || {}).merge(:display => collection.proxy_association.reflection.name) + h[:link] = url.to_s + else + h[:link] = url_for(:action => 'show', + :id => collection.proxy_association.owner, + :display => collection.proxy_association.reflection.name) + end else - h[:link] = url_for(:controller => controller, + h[:link] = url_for(:controller => controller_collection, :action => 'list') end h[:title] = "Show all #{label}" diff --git a/app/models/manageiq/providers/cloud_manager.rb b/app/models/manageiq/providers/cloud_manager.rb index 03f5aa4202d..7717d4211d9 100644 --- a/app/models/manageiq/providers/cloud_manager.rb +++ b/app/models/manageiq/providers/cloud_manager.rb @@ -22,6 +22,7 @@ class CloudManager < BaseManager alias_method :all_cloud_networks, :cloud_networks + validates_presence_of :zone include HasManyOrchestrationStackMixin # Development helper method for Rails console for opening a browser to the EMS. diff --git a/app/views/ems_cloud/_form_fields.html.haml b/app/views/ems_cloud/_form_fields.html.haml deleted file mode 100644 index b61b92a8cab..00000000000 --- a/app/views/ems_cloud/_form_fields.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- if @edit[:new][:emstype] == "ec2" - %tr - %td.key= _('Region') - %td.wide - = select_tag("provider_region", - options_for_select([["<#{_('Choose')}>", nil]] + Array(@edit[:amazon_regions].invert).sort_by { |desc, _name| desc }, - @edit[:new][:provider_region]), - "data-miq_observe" => {:url => url}.to_json) -- elsif @edit[:new][:emstype].present? - %tr - %td.key= _('Hostname or IP address') - %td.wide - = text_field_tag("hostname", - @edit[:new][:hostname], - :maxlength => MAX_HOSTNAME_LEN, - "data-miq_observe" => {:interval => ".5", :url => url}.to_json, - :title => 'Hostname or IPv4/IPv6 address') diff --git a/app/views/ems_cloud/edit.html.haml b/app/views/ems_cloud/edit.html.haml index 47526934511..2c4a10d22a3 100644 --- a/app/views/ems_cloud/edit.html.haml +++ b/app/views/ems_cloud/edit.html.haml @@ -1 +1,17 @@ -= render :partial => "shared/views/ems_common/form" += form_for(@ems, + :url => ems_cloud_path(@ems), + :html => {"ng-controller" => "emsCommonFormController", + "name" => "angularForm", + "ng-show" => "afterGet", + "update-url" => "#{ems_cloud_path(@ems)}", + "form-fields-url" => "/#{controller_name}/ems_cloud_form_fields/", + "novalidate" => true}) do |f| + %input{:type => 'hidden', :id => "form_id", :value => "##{f.options[:html][:id]}"} + %input{:type => 'hidden', :id => "button_name", :name => "button", :value => "save"} + %input{:type => 'hidden', :id => "cred_type", :name => "cred_type", :value => "default"} + = render :partial => "shared/views/ems_common/angular/form" + +:javascript + ManageIQ.angularApplication.value('emsCommonFormId', '#{@ems.id || "new"}'); + angular.bootstrap($($('#form_id').val()), ['ManageIQ.angularApplication'], { strictDi: true }); + diff --git a/app/views/ems_cloud/new.html.haml b/app/views/ems_cloud/new.html.haml index 47526934511..0ae4b8c1b1e 100644 --- a/app/views/ems_cloud/new.html.haml +++ b/app/views/ems_cloud/new.html.haml @@ -1 +1,19 @@ -= render :partial => "shared/views/ems_common/form" +- url = @ems.persisted? ? ems_clouds_path(@ems) : ems_clouds_path += form_for(@ems, + :url => url, + :html => {"ng-controller" => "emsCommonFormController", + "name" => "angularForm", + "ng-show" => "afterGet", + "create-url" => "#{url}", + "form-fields-url" => "/#{controller_name}/ems_cloud_form_fields/", + "novalidate" => true}) do |f| + %input{:type => 'hidden', :id => "form_id", :value => "##{f.options[:html][:id]}"} + %input{:type => 'hidden', :id => "button_name", :name => "button", :value => "add"} + %input{:type => 'hidden', :id => "cred_type", :name => "cred_type", :value => "default"} + + = render :partial => "shared/views/ems_common/angular/form" + +:javascript + ManageIQ.angularApplication.value('emsCommonFormId', '#{@ems.id || "new"}'); + angular.bootstrap($($('#form_id').val()), ['ManageIQ.angularApplication'], { strictDi: true }); + diff --git a/app/views/layouts/_edit_form_buttons.html.haml b/app/views/layouts/_edit_form_buttons.html.haml index 4eb788aa3a9..c70e93cbcc3 100644 --- a/app/views/layouts/_edit_form_buttons.html.haml +++ b/app/views/layouts/_edit_form_buttons.html.haml @@ -1,13 +1,14 @@ - save_text ||= _("Save Changes") - save_confirm_text ||= nil - show_validate_button ||= nil -- action_url ||= "update" -- record_id ||= nil -- noreset ||= nil -- align ||= "right" -- ajax_buttons ||= false -- serialize ||= false -- continue_button ||= nil +- action_url ||= "update" +- record_id ||= nil +- noreset ||= nil +- align ||= "right" +- ajax_buttons ||= false +- serialize ||= false +- continue_button ||= nil +- restful ||= false - show_cancel_button = %w(user_edit user_update menu_tree zone_edit zone_update ldap_seq_edit rbac_group_edit rbac_group_update rbac_group_field_changed category_edit category_update timeprofile_edit timeprofile_update timeprofile_copy) - force_cancel_button ||= false @@ -43,13 +44,15 @@ :id => record_id, :button => "continue")}');") - else + - function = restful ? "miqRESTAjaxButton" : "miqAjaxButton" + - extra = restful ? ", this" : "" = button_tag(_("Save"), :class => 'btn btn-primary', :alt => save_text, :title => save_text, - :onclick => "miqAjaxButton('#{url_for(:action => action_url, + :onclick => "#{function}('#{url_for(:action => action_url, :id => record_id, - :button => "save")}');") + :button => "save")}'#{extra});") - else = button_tag(_("Save"), :class => 'btn btn-primary', diff --git a/app/views/layouts/_view_buttons.html.haml b/app/views/layouts/_view_buttons.html.haml index cda660ccba4..e776ca05874 100644 --- a/app/views/layouts/_view_buttons.html.haml +++ b/app/views/layouts/_view_buttons.html.haml @@ -8,7 +8,9 @@ - elsif !%w(all_tasks all_ui_tasks timeline diagnostics my_tasks my_ui_tasks miq_server usage).include?(@layout) | && (!@layout.starts_with?("miq_request")) && !@treesize_buttons | && @display == "main" && @showtype == "main" && !@in_a_form | - = render :partial => "layouts/dhtmlxtoolbar", :locals => {:tb => "view_tb", :tb_yaml => "summary_view_tb"} + = render :partial => "layouts/dhtmlxtoolbar", + :locals => {:tb => "view_tb", + :tb_yaml => controller.send(:restful?) ? "summary_view_restful_tb" : "summary_view_tb"} - else -# fake table to keep center_tb aligned in case there is not view_tb to show %table diff --git a/app/views/layouts/angular-bootstrap/_auth_credentials_angular_bootstrap.html.haml b/app/views/layouts/angular-bootstrap/_auth_credentials_angular_bootstrap.html.haml index 8bcb46b24ec..d9eac879689 100644 --- a/app/views/layouts/angular-bootstrap/_auth_credentials_angular_bootstrap.html.haml +++ b/app/views/layouts/angular-bootstrap/_auth_credentials_angular_bootstrap.html.haml @@ -1,16 +1,19 @@ +- ng_show ||= true - validate_url ||= 'log_depot_edit' - prefix ||= 'log' -- uid_label ||= "Username" -- pwd_label ||= "Password" +- userid_label ||= _("Username") +- password_label ||= _("Password") +- verify_label ||= _("Verify Password") - ng_reqd_userid ||= false - ng_reqd_password ||= false - ng_reqd_verify ||= "#{ng_model}.#{prefix}_password != ''" +- passwd_mismatch ||= _("Passwords do not match") %div{"ng-show" => "#{ng_show}"} .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_userid.$error.required}"} %label.col-md-2.control-label{"for" => "textInput-markup"} - = _("Username") - .col-md-8 + = userid_label + .col-md-4 %input.form-control{"type" => "text", "id" => "textInput-markup", "ng-required" => "#{ng_reqd_userid}", @@ -24,8 +27,8 @@ %div{"ng-show" => "#{ng_show}"} .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_password.$error.required}"} %label.col-md-2.control-label{"for" => "textInput-markup"} - = _("Password") - .col-md-8 + = password_label + .col-md-4 %input.form-control{"type" => "password", "id" => "textInput-markup", "ng-required" => "#{ng_reqd_password}", @@ -42,8 +45,8 @@ %div{"ng-show" => "#{ng_show}"} .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_verify.$error.required || (#{prefix}_VerifyCtrl != undefined && #{prefix}_VerifyCtrl.$error.verifypasswd)}"} %label.col-md-2.control-label{"for" => "textInput-markup"} - = _("Verify Password") - .col-md-8 + = verify_label + .col-md-4 %input.form-control{"type" => "password", "id" => "textInput-markup", "ng-required" => "#{ng_reqd_verify}", @@ -57,7 +60,7 @@ %span.help-block{"ng-show" => "angularForm.#{prefix}_verify.$error.required"} = _("Required") %span.help-block{"ng-show" => "!angularForm.#{prefix}_verify.$error.required && #{prefix}_VerifyCtrl != undefined && #{prefix}_VerifyCtrl.$error.verifypasswd"} - = _("Passwords do not match") + = passwd_mismatch %br = render :partial => "layouts/angular/form_buttons_verify_angular", :locals => {:ng_show => "#{ng_show}", diff --git a/app/views/layouts/angular/_form_buttons_verify_angular.html.haml b/app/views/layouts/angular/_form_buttons_verify_angular.html.haml index 15cb3d1d082..a6449c9e454 100644 --- a/app/views/layouts/angular/_form_buttons_verify_angular.html.haml +++ b/app/views/layouts/angular/_form_buttons_verify_angular.html.haml @@ -14,5 +14,4 @@ :alt => verify_title_on, :title => verify_title_on, "ng-show" => basic_info_needed ? "canValidateBasicInfo()" : "canValidate()", - "ng-click" => "validateClicked('#{url_for(:action => validate_url, :id => id, :type => valtype, :button => "validate")}')", -) + "ng-click" => "validateBClicked($event, '#{valtype}', '#{url_for(:action => validate_url, :id => id, :type => valtype, :button => "validate")}', true)") diff --git a/app/views/layouts/angular/_multi_auth_credentials.html.haml b/app/views/layouts/angular/_multi_auth_credentials.html.haml index b0621f5416c..2875cfb624f 100644 --- a/app/views/layouts/angular/_multi_auth_credentials.html.haml +++ b/app/views/layouts/angular/_multi_auth_credentials.html.haml @@ -1,39 +1,47 @@ - validate_url ||= (record.id || @selected_hosts) ? "update" : "create" - legendtext ||= "Credentials" -%h3 - = legendtext + #auth_tabs + %h3 + = legendtext %ul.nav.nav-tabs - = miq_tab_header('default', 'default') do + = miq_tab_header('default') do = _("Default") - - if %w(ems_cloud ems_infra).include?(params[:controller]) - - if @edit[:new][:emstype] == "rhevm" - = miq_tab_header('metrics', 'default') do - = _("C & U Database") - - if %w(openstack openstack_infra).include?(@edit[:new][:emstype]) - = miq_tab_header('amqp', 'default') do - = _("AMQP") - - if %w(openstack_infra).include?(@edit[:new][:emstype]) - = miq_tab_header('ssh_keypair', 'default') do - = _("RSA key pair") + - if %w(ems_cloud ems_infra).include?(controller_name) + = miq_tab_header('metrics') do + = _("C & U Database") + = miq_tab_header('amqp') do + = _("AMQP") + = miq_tab_header('ssh_keypair') do + = _("RSA key pair") - else - = miq_tab_header('remote', 'default') do + = miq_tab_header('remote') do = _("Remote Login") - = miq_tab_header('ws', 'default') do + = miq_tab_header('web') do = _("Web Services") - = miq_tab_header('ipmi', 'default') do + = miq_tab_header('ipmi') do = _("IPMI") .tab-content = miq_tab_content('default', 'default') do %div.style1 - %div + %div{"ng-if" => "emsCommonModel.emstype == 'ec2'"} + = render :partial => "layouts/angular-bootstrap/auth_credentials_angular_bootstrap", + :locals => {:ng_show => true, + :ng_model => "#{ng_model}", + :validate_url => validate_url, + :userid_label => _("Access Key ID"), + :password_label => _("Secret Access Key"), + :verify_label => _("Verify Secret Access Key"), + :passwd_mismatch => _("Secret Access Keys do not match"), + :id => record.id, + :prefix => "default", + :basic_info_needed => true} + %div{"ng-if" => "emsCommonModel.emstype != 'ec2'"} = render :partial => "layouts/angular-bootstrap/auth_credentials_angular_bootstrap", :locals => {:ng_show => true, :ng_model => "#{ng_model}", :validate_url => validate_url, - :uid_label => @emstype == "ec2" ? "Access Key ID" : nil, - :pwd_label => @emstype == "ec2" ? "Secret Access Key" : nil, :id => record.id, :prefix => "default", :basic_info_needed => true} @@ -62,7 +70,7 @@ = miq_tab_content('amqp', 'default') do %div.style1 %div - = render :partial => "layouts/angular-bootstrap/auth_cbredentials_angular_bootstrap", + = render :partial => "layouts/angular-bootstrap/auth_credentials_angular_bootstrap", :locals => {:ng_show => true, :ng_model => "#{ng_model}", :validate_url => validate_url, @@ -77,10 +85,14 @@ = miq_tab_content('ssh_keypair', 'default') do %div.style1 %div - = render :partial => "/layouts/auth_credentials_keypair", + = render :partial => "layouts/angular-bootstrap/auth_credentials_angular_bootstrap", :locals => {:ng_show => true, :ng_model => "#{ng_model}", :validate_url => validate_url, + :userid_label => _("Username"), + :password_label => _("Private Key"), + :verify_label => _("Verify Private Key"), + :passwd_mismatch => _("Private Keys do not match"), :id => record.id, :prefix => "ssh_keypair", :basic_info_needed => true} @@ -135,6 +147,39 @@ .col-md-12 %span{:style => "color:black"} = _("Used for access to IPMI.") + +%div{"ng-if" => "emsCommonModel.emstype == ''"} + :javascript + $('#auth_tabs').hide(); +%div{"ng-if" => "emsCommonModel.emstype == 'ec2'"} + :javascript + miq_tabs_show_hide("#amqp_tab", false); + miq_tabs_show_hide("#metrics_tab", false); + miq_tabs_show_hide("#ssh_keypair_tab", false); + miq_tabs_init('#auth_tabs'); + $('#auth_tabs').show(); +%div{"ng-if" => "emsCommonModel.emstype == 'rhevm'"} + :javascript + miq_tabs_show_hide("#amqp_tab", false); + miq_tabs_show_hide("#metrics_tab", true); + miq_tabs_show_hide("#ssh_keypair_tab", false); + miq_tabs_init('#auth_tabs'); + $('#auth_tabs').show(); +%div{"ng-if" => "emsCommonModel.emstype == 'openstack'"} + :javascript + miq_tabs_show_hide("#amqp_tab", true); + miq_tabs_show_hide("#metrics_tab", false); + miq_tabs_show_hide("#ssh_keypair_tab", false); + miq_tabs_init('#auth_tabs'); + $('#auth_tabs').show(); +%div{"ng-if" => "emsCommonModel.emstype == 'openstack_infra'"} + :javascript + miq_tabs_show_hide("#amqp_tab", true); + miq_tabs_show_hide("#metrics_tab", false); + miq_tabs_show_hide("#ssh_keypair_tab", true); + miq_tabs_init('#auth_tabs'); + $('#auth_tabs').show(); + - unless session[:host_items].nil? %div %div diff --git a/app/views/layouts/angular/_x_edit_buttons_angular.html.haml b/app/views/layouts/angular/_x_edit_buttons_angular.html.haml index ca9444c3b3c..cdcedf5fe37 100644 --- a/app/views/layouts/angular/_x_edit_buttons_angular.html.haml +++ b/app/views/layouts/angular/_x_edit_buttons_angular.html.haml @@ -1,28 +1,30 @@ .button-group = button_tag("Add", - :class => "btn btn-primary btn-disabled", + "class" => "btn btn-primary btn-disabled", :alt => "Add", :title => "Add", + "ng-click" => "addClicked($event, false)", "ng-show" => "newRecord && !saveable(angularForm)") = button_tag("Add", :class => "btn btn-primary", :alt => "Add", :title => "Add", - "ng-click" => "addClicked()", + "ng-click" => "addClicked($event, true)", "ng-show" => "newRecord && saveable(angularForm)") = button_tag("Save", :class => "btn btn-primary btn-disabled", :alt => "Save changes", :title => "Save changes", + "ng-click" => "saveClicked($event, false)", "ng-show" => "!newRecord && !saveable(angularForm)") = button_tag("Save", :class => "btn btn-primary", :alt => "Save changes", :title => "Save changes", - "ng-click" => "saveClicked()", + "ng-click" => "saveClicked($event, true)", "ng-show" => "!newRecord && saveable(angularForm)") = button_tag("Reset", @@ -38,4 +40,4 @@ :class => "btn btn-default", :alt => "Cancel", :title => "Cancel", - "ng-click" => "cancelClicked()") + "ng-click" => "cancelClicked($event)") diff --git a/app/views/layouts/quadicon/_quadicon_text.html.haml b/app/views/layouts/quadicon/_quadicon_text.html.haml index 71b5bd852d5..bdc7cb5fb85 100644 --- a/app/views/layouts/quadicon/_quadicon_text.html.haml +++ b/app/views/layouts/quadicon/_quadicon_text.html.haml @@ -70,5 +70,5 @@ %a{:href => url_for_db(db), :title => h(row['key'])} = truncate_for_quad(row['key']) - else - %a{:href => url_for_db(db), :title => h(row['name'])} + %a{:href => url_for_db(db, "show", item), :title => h(row['name'])} = truncate_for_quad(row['name']) diff --git a/app/views/shared/summary/_textual.html.haml b/app/views/shared/summary/_textual.html.haml index e4d7b6b83a3..d76f9294ea4 100644 --- a/app/views/shared/summary/_textual.html.haml +++ b/app/views/shared/summary/_textual.html.haml @@ -1,4 +1,4 @@ -- items = expand_textual_group(items) +- items = expand_textual_group(items, @record) - if items.present? %table.table.table-bordered.table-hover.table-striped %thead diff --git a/app/views/shared/views/ems_common/_form.html.haml b/app/views/shared/views/ems_common/_form.html.haml index f38313faf71..120562afccd 100644 --- a/app/views/shared/views/ems_common/_form.html.haml +++ b/app/views/shared/views/ems_common/_form.html.haml @@ -9,11 +9,11 @@ %label.control-label.col-md-2 = _('Name') .col-md-8 - = text_field_tag("name", @edit[:new][:name], - :maxlength => MAX_NAME_LEN, - "class" => "form-control", - "data-miq_focus" => true, - "data-miq_observe" => {:interval => '.5', :url => url}.to_json) + = text_field_tag("name", @ems.name, + :maxlength => MAX_NAME_LEN, + "class" => "form-control", + "data-miq_focus" => true, + "data-miq_observe" => {:interval => '.5', :url => url}.to_json) .form-group %label.control-label.col-md-2 = _('Type') @@ -102,4 +102,4 @@ :href => url_for(:action => "show_list", :flash_msg => _("Add of new %s was cancelled by the user") % name), :onclick => 'window.location = this.getAttribute("href");') - else - = render :partial => '/layouts/edit_form_buttons', :locals => {:record_id => @ems.id, :ajax_buttons => true} + = render :partial => '/layouts/edit_form_buttons', :locals => {:record_id => @ems.id, :ajax_buttons => true, :restful => true} diff --git a/app/views/shared/views/ems_common/angular/_form.html.haml b/app/views/shared/views/ems_common/angular/_form.html.haml new file mode 100644 index 00000000000..c55db1d335e --- /dev/null +++ b/app/views/shared/views/ems_common/angular/_form.html.haml @@ -0,0 +1,173 @@ +- @angularForm = true + +.form-horizontal + = render :partial => "layouts/flash_msg" + %div + .form-group{"ng-class" => "{'has-error': angularForm.name.$invalid}"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Name') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "name", + "ng-model" => "emsCommonModel.name", + "maxlength" => "#{MAX_NAME_LEN}", + "required" => "", + "checkchange" => "", + "auto-focus" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.required"} + = _("Required") + + .form-group{"ng-class" => "{'has-error': angularForm.emstype.$invalid}"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Type') + .col-md-8 + = select_tag('emstype', + options_for_select([["<#{_('Choose>')}", nil]] + @ems_types, disabled: ["<#{_('Choose')}>", nil]), + "ng-if" => "newRecord", + "ng-model" => "emsCommonModel.emstype", + "required" => "", + "checkchange" => "", + "selectpicker-for-select-tag" => "") + %div{"ng-if" => "!newRecord"} + %label.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "emstype", + "ng-if" => "!newRecord", + "readonly" => true, + "style" => "color: black; font-weight: normal;"} + = @emstype_display + + + .form-group{"ng-class" => "{'has-error': angularForm.provider_region.$invalid}", "ng-if" => "emsCommonModel.emstype == 'ec2'"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Region') + .col-md-8 + = select_tag('provider_region', + options_for_select([["<#{_('Choose')}>", nil]] + Array(@amazon_regions.invert).sort_by { |desc, _name| desc }, disabled: ["<#{_('Choose')}>", nil]), + "ng-model" => "emsCommonModel.provider_region", + "required" => "", + "checkchange" => "", + "selectpicker-for-select-tag" => "") + + .form-group{"ng-class" => "{'has-error': angularForm.hostname.$invalid}", "ng-if" => "emsCommonModel.emstype != '' && emsCommonModel.emstype == 'openstack'"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Hostname (or IPv4 or IPv6 address)') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "hostname", + "ng-model" => "emsCommonModel.hostname", + "maxlength" => "#{MAX_NAME_LEN}", + "required" => "", + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.hostname.$error.required"} + = _("Required") + + .form-group{"ng-class" => "{'has-error': angularForm.azure_tenant_id.$invalid}", "ng-if" => "emsCommonModel.emstype != '' && emsCommonModel.emstype == 'azure'"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Tenant ID') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "azure_tenant_id", + "ng-model" => "emsCommonModel.azure_tenant_id", + "required" => "", + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.azure_tenant_id.$error.required"} + = _("Required") + + .form-group{"ng-class" => "{'has-error': angularForm.api_port.$invalid}", "ng-if" => "emsCommonModel.emstype == 'openstack' || emsCommonModel.emstype == 'rhevm'"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('API Port') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "api_port", + "ng-model" => "emsCommonModel.api_port", + "maxlength" => 15, + "required" => "", + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.api_port.$error.required"} + = _("Required") + + .form-group{"ng-class" => "{'has-error': angularForm.provider_id.$invalid}", "ng-if" => "emsCommonModel.emstype == 'openstack' && emsCommonModel.openstack_infra_providers_exist"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _("Openstack Infra Provider") + .col-md-8 + = select_tag('provider_id', + options_for_select([["<#{_('blank')}>", nil]] + @openstack_infra_providers.sort_by { |name, _name| name }), + "ng-model" => "emsCommonModel.provider_id", + "checkchange" => "", + "selectpicker-for-select-tag" => "") + + .form-group{"ng-class" => "{'has-error': angularForm.zone.$invalid}"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _("Zone") + .col-md-8 + - if @server_zones.length <= 1 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "zone", + "ng-model" => "emsCommonModel.zone", + "maxlength" => 15, + "required" => "", + "checkchange" => "", + "readonly" => true, + "style" => "color: black;"} + - else + = select_tag('zone', + options_for_select([["<#{_('Choose')}>", nil]] + Array(@server_zones.invert).sort_by { |name, _name| name }), + "ng-model" => "emsCommonModel.zone", + "checkchange" => "", + "required" => "", + "selectpicker-for-select-tag" => "") + + .form-group{"ng-class" => "{'has-error': angularForm.host_default_vnc_port_start.$invalid}", "ng-if" => "emsCommonModel.emstype_vm"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Host Default VNC Start Port') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "host_default_vnc_port_start", + "ng-model" => "emsCommonModel.host_default_vnc_port_start", + "maxlength" => 6, + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.required"} + = _("Required") + + .form-group{"ng-class" => "{'has-error': angularForm.host_default_vnc_port_end.$invalid}", "ng-if" => "emsCommonModel.emstype_vm"} + %label.col-md-2.control-label{"for" => "textInput-markup"} + = _('Host Default VNC End Port') + .col-md-8 + %input.form-control{"type" => "text", + "id" => "textInput-markup", + "name" => "host_default_vnc_port_end", + "ng-model" => "emsCommonModel.host_default_vnc_port_end", + "maxlength" => 6, + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.required"} + = _("Required") + + %hr + - if controller_name == "ems_container" + = render :partial => "/layouts/container_auth", :locals => {:record => @ems} + - else + %div{"ng-show" => "emsCommonModel.emstype != '' && emsCommonModel.emstype == 'azure'"} + %h3 + = _("Credentials") + = render :partial => "/layouts/angular-bootstrap/auth_credentials_angular_bootstrap", + :locals => {:record => @ems, + :ng_model => "emsCommonModel", + :prefix => "default", + :validate_url => @ems.id ? "update" : "create", + :id => @ems.id, + :basic_info_needed => true, + :userid_label => _("Client ID"), + :password_label => _("Client Key"), + :verify_label => _("Verify Client Key"), + :passwd_mismatch => _("Client Keys do not match")} + %div{"ng-show" => "emsCommonModel.emstype != 'azure'"} + = render :partial => "/layouts/angular/multi_auth_credentials", :locals => {:record => @ems, :ng_model => "emsCommonModel"} + + = render :partial => "layouts/angular/x_edit_buttons_angular", :locals => {:record => @ems, :restful => true} \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 525faebdf3b..ded9c0cc5b5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -588,11 +588,8 @@ dialog_load discover download_data - edit - index - new + ems_cloud_form_fields protect - show show_list tagging_edit ) + @@ -600,6 +597,10 @@ :post => %w( button create + dynamic_checkbox_refresh + dynamic_list_refresh + dynamic_radio_button_refresh + dynamic_text_box_refresh form_field_changed listnav_search_selected panel_control @@ -2018,7 +2019,9 @@ CONTROLLER_ACTIONS.each do |controller_name, controller_actions| # Default route with no action to controller's index action - match "#{controller_name}", :controller => controller_name, :action => :index, :via => :get + unless controller_name == :ems_cloud + match "#{controller_name}", :controller => controller_name, :action => :index, :via => :get + end # One-by-one get/post routes for defined controllers if controller_actions.is_a?(Hash) @@ -2039,4 +2042,7 @@ end end end + + resources :ems_cloud, :as => :ems_clouds + end diff --git a/product/toolbars/ems_cloud_center_tb.yaml b/product/toolbars/ems_cloud_center_tb.yaml index 28d56304adc..6980a0ce911 100644 --- a/product/toolbars/ems_cloud_center_tb.yaml +++ b/product/toolbars/ems_cloud_center_tb.yaml @@ -21,7 +21,7 @@ :image: edit :text: 'Edit this #{ui_lookup(:table=>"ems_cloud")}' :title: 'Edit this #{ui_lookup(:table=>"ems_cloud")}' - :url: '/edit' + :full_path: <%= edit_ems_cloud_path(@ems) %> - :button: ems_cloud_delete :image: delete :text: 'Remove this #{ui_lookup(:table=>"ems_cloud")} from the VMDB' @@ -55,4 +55,4 @@ :text: 'Timelines' :title: 'Show Timelines for this #{ui_lookup(:table=>"ems_cloud")}' :url: '/show' - :url_parms: '?display=timeline' \ No newline at end of file + :url_parms: '?display=timeline' diff --git a/product/toolbars/summary_view_restful_tb.yaml b/product/toolbars/summary_view_restful_tb.yaml new file mode 100644 index 00000000000..acfdb351b4c --- /dev/null +++ b/product/toolbars/summary_view_restful_tb.yaml @@ -0,0 +1,12 @@ +# +# Toolbar config file +# +--- +:button_groups: +- :name: summary_download + :items: + - :button: download_view + :image: pdf + :title: "Download summary in PDF format" + :url: '/' + :url_parms: '?display=download_pdf' diff --git a/spec/controllers/ems_cloud_controller_spec.rb b/spec/controllers/ems_cloud_controller_spec.rb index 5c575c09e98..3ac7edeb463 100644 --- a/spec/controllers/ems_cloud_controller_spec.rb +++ b/spec/controllers/ems_cloud_controller_spec.rb @@ -5,6 +5,7 @@ before do EvmSpecHelper.seed_specific_product_features("ems_cloud_new") feature = MiqProductFeature.find_all_by_identifier(["ems_cloud_new"]) + Zone.first || FactoryGirl.create(:zone) test_user_role = FactoryGirl.create(:miq_user_role, :name => "test_user_role", :miq_product_features => feature) @@ -14,6 +15,10 @@ allow(user).to receive(:server_timezone).and_return("UTC") described_class.any_instance.stub(:set_user_time_zone) controller.stub(:check_privileges).and_return(true) + controller.stub(:assert_privileges).and_return(true) + controller.stub(:render) + FactoryGirl.create(:vmdb_database) + EvmSpecHelper.create_guid_miq_server_zone login_as user end @@ -23,5 +28,200 @@ expect(response.status).to eq(200) expect(controller.stub(:edit)).to_not be_nil end + + render_views + + it 'shows the edit page' do + expect(MiqServer.my_server).to be + FactoryGirl.create(:ems_amazon, :zone => Zone.first) + ems = ManageIQ::Providers::Amazon::CloudManager.first + get :edit, :id => ems.id + expect(response.status).to eq(200) + end + + it 'creates on post' do + expect { + post :create, { + "button" => "add", + "name" => "foo", + "emstype" => "ec2", + "provider_region" => "ap-southeast-1", + "port" => "", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]", + "metrics_userid" => "", + "metrics_password" => "[FILTERED]", + "metrics_verify" => "[FILTERED]", + "amqp_userid" => "", + "amqp_password" => "[FILTERED]", + "amqp_verify" => "[FILTERED]", + "ssh_keypair_userid" => "", + "ssh_keypair_password" => "[FILTERED]" + } + }.to change { ManageIQ::Providers::Amazon::CloudManager.count }.by(1) + end + + it 'creates an authentication record on post' do + expect { + post :create, + "button" => "add", + "hostname" => "host_openstack", + "name" => "foo_openstack", + "emstype" => "openstack", + "provider_region" => "", + "port" => "5000", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + openstack = ManageIQ::Providers::Openstack::CloudManager.where(:name => "foo_openstack") + authentication = Authentication.where(:resource_id => openstack.to_a[0].id).first + expect(authentication).not_to be_nil + }.to change { Authentication.count }.by(1) + end + + it 'updates an authentication record on post' do + post :create, + "button" => "add", + "hostname" => "host_openstack", + "name" => "foo_openstack", + "emstype" => "openstack", + "provider_region" => "", + "port" => "5000", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + openstack = ManageIQ::Providers::Openstack::CloudManager.where(:name => "foo_openstack") + authentication = Authentication.where(:resource_id => openstack.to_a[0].id).first + expect(authentication).not_to be_nil + + post :update, + "id" => openstack.to_a[0].id, + "button" => "save", + "hostname" => "host_openstack_updated", + "name" => "foo_openstack", + "emstype" => "openstack", + "provider_region" => "", + "port" => "5000", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + openstack = ManageIQ::Providers::Openstack::CloudManager.where(:name => "foo_openstack") + authentication = Authentication.where(:resource_id => openstack.to_a[0].id).first + expect(authentication.userid).to eq("foo") + expect(authentication.password).to eq("[FILTERED]") + end + + it "validates credentials for a new record" do + post :create, + "button" => "validate", + "cred_type" => "default", + "name" => "foo_ec2", + "emstype" => "ec2", + "provider_region" => "ap-southeast-1", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + end + + it "cancels a new record" do + post :create, + "button" => "cancel", + "cred_type" => "default", + "name" => "foo_ec2", + "emstype" => "ec2", + "provider_region" => "ap-southeast-1", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + end + + it "adds a record of type azure" do + post :create, + "button" => "add", + "azure_tenant_id" => "azure", + "name" => "foo_azure", + "emstype" => "azure", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + edit = controller.instance_variable_get(:@edit) + expect(edit[:new][:azure_tenant_id]).to eq("azure") + end + end + + describe "#ems_cloud_form_fields" do + before do + Zone.first || FactoryGirl.create(:zone) + described_class.any_instance.stub(:set_user_time_zone) + controller.stub(:check_privileges).and_return(true) + controller.stub(:assert_privileges).and_return(true) + end + it 'gets the ems cloud form fields on a get' do + MiqServer.stub(:my_zone).and_return("default") + post :create, + "button" => "add", + "hostname" => "host_openstack", + "name" => "foo_openstack", + "emstype" => "openstack", + "provider_region" => "", + "port" => "5000", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + openstack = ManageIQ::Providers::Openstack::CloudManager.where(:name => "foo_openstack") + get :ems_cloud_form_fields, "id" => openstack.to_a[0].id + expect(response.status).to eq(200) + expect(response.body).to include('"name":"foo_openstack"') + end + end + + describe "#show_link" do + before do + Zone.first || FactoryGirl.create(:zone) + described_class.any_instance.stub(:set_user_time_zone) + controller.stub(:check_privileges).and_return(true) + controller.stub(:assert_privileges).and_return(true) + end + it 'gets the restful show link path' do + MiqServer.stub(:my_zone).and_return("default") + post :create, + "button" => "add", + "hostname" => "host_openstack", + "name" => "foo_openstack", + "emstype" => "openstack", + "provider_region" => "", + "port" => "5000", + "zone" => "default", + "default_userid" => "foo", + "default_password" => "[FILTERED]", + "default_verify" => "[FILTERED]" + + expect(response.status).to eq(200) + openstack = ManageIQ::Providers::Openstack::CloudManager.where(:name => "foo_openstack") + show_link_actual_path = controller.send(:show_link, openstack.to_a[0]) + expect(show_link_actual_path).to eq("/ems_cloud/#{openstack.to_a[0].id}") + end end end diff --git a/spec/controllers/ems_common_controller_spec.rb b/spec/controllers/ems_common_controller_spec.rb index 7170d15eb10..5d307a49bb7 100644 --- a/spec/controllers/ems_common_controller_spec.rb +++ b/spec/controllers/ems_common_controller_spec.rb @@ -54,32 +54,6 @@ end end - context "#create" do - it "displays correct attribute name in error message when adding cloud EMS" do - set_user_privileges - controller.instance_variable_set(:@edit, {:new => {:name => "EMS 1", :emstype => "ec2"}, - :key => "ems_edit__new"}) - session[:edit] = assigns(:edit) - controller.stub(:drop_breadcrumb) - post :create, :button => "add" - flash_messages = assigns(:flash_array) - flash_messages.first[:message].should include("Region is not included in the list") - flash_messages.first[:level].should == :error - end - - it "displays correct attribute name in error message when adding infra EMS" do - set_user_privileges - controller.instance_variable_set(:@edit, {:new => {:name => "EMS 2", :emstype => "rhevm"}, - :key => "ems_edit__new"}) - session[:edit] = assigns(:edit) - controller.stub(:drop_breadcrumb) - post :create, :button => "add" - flash_messages = assigns(:flash_array) - flash_messages.first[:message].should include("Host Name can't be blank") - flash_messages.first[:level].should == :error - end - end - context "#set_record_vars" do context "strip leading/trailing whitespace from hostname/ipaddress" do after :each do diff --git a/spec/factories/ext_management_system.rb b/spec/factories/ext_management_system.rb index 41587c603fb..87d88613c18 100644 --- a/spec/factories/ext_management_system.rb +++ b/spec/factories/ext_management_system.rb @@ -72,6 +72,7 @@ # Leaf classes for ems_cloud factory :ems_amazon, :aliases => ["manageiq/providers/amazon/cloud_manager"], :class => "ManageIQ::Providers::Amazon::CloudManager", :parent => :ems_cloud do + zone { Zone.first || FactoryGirl.create(:zone) } provider_region "us-east-1" end @@ -88,6 +89,7 @@ end factory :ems_openstack, :aliases => ["manageiq/providers/openstack/cloud_manager"], :class => "ManageIQ::Providers::Openstack::CloudManager", :parent => :ems_cloud do + zone { Zone.first || FactoryGirl.create(:zone) } end factory :ems_openstack_with_authentication, :parent => :ems_openstack do @@ -128,6 +130,7 @@ end factory :ems_azure, :aliases => ["manageiq/providers/azure/cloud_manager"], :class => "ManageIQ::Providers::Azure::CloudManager", :parent => :ems_cloud do + zone { Zone.first || FactoryGirl.create(:zone) } end factory :ems_azure_with_authentication, :parent => :ems_azure do diff --git a/spec/javascripts/controllers/ems_common/ems_common_form_controller_spec.js b/spec/javascripts/controllers/ems_common/ems_common_form_controller_spec.js new file mode 100644 index 00000000000..162fb9710bf --- /dev/null +++ b/spec/javascripts/controllers/ems_common/ems_common_form_controller_spec.js @@ -0,0 +1,379 @@ +describe('emsCommonFormController', function() { + var $scope, $controller, $httpBackend, miqService, compile; + + beforeEach(module('ManageIQ.angularApplication')); + + beforeEach(inject(function(_$httpBackend_, $rootScope, _$controller_, _miqService_, _$compile_) { + miqService = _miqService_; + compile = _$compile_; + spyOn(miqService, 'miqAjaxButton'); + spyOn(miqService, 'restAjaxButton'); + spyOn(miqService, 'sparkleOn'); + spyOn(miqService, 'sparkleOff'); + $scope = $rootScope.$new(); + + var emsCommonFormResponse = { + name: '', + emstype: '', + zone: 'default', + emstype_vm: false, + openstack_infra_providers_exist: false, + api_port: '5000' + }; + $httpBackend = _$httpBackend_; + $httpBackend.whenGET('/ems_cloud/ems_cloud_form_fields/new').respond(emsCommonFormResponse); + $controller = _$controller_('emsCommonFormController', + {$scope: $scope, + $attrs: {'formFieldsUrl': '/ems_cloud/ems_cloud_form_fields/', + 'createUrl': '/ems_cloud', + 'updateUrl': '/ems_cloud/12345'}, + emsCommonFormId: 'new', + miqService: miqService + }); + })); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + describe('when the emsCommonFormId is new', function() { + beforeEach(inject(function() { + $httpBackend.flush(); + })); + + it('sets the name to blank', function () { + expect($scope.emsCommonModel.name).toEqual(''); + }); + + it('sets the type to blank', function () { + expect($scope.emsCommonModel.emstype).toEqual(''); + }); + + it('sets the zone to default', function() { + expect($scope.emsCommonModel.zone).toEqual('default'); + }); + + it('sets the emstype_vm to false', function() { + expect($scope.emsCommonModel.emstype_vm).toEqual(false); + }); + + it('sets the openstack_infra_providers_exist to false', function() { + expect($scope.emsCommonModel.openstack_infra_providers_exist).toEqual(false); + }); + + it('sets the api_port to 5000', function() { + expect($scope.emsCommonModel.api_port).toEqual(5000); + }); + }); + + describe('when the emsCommonFormId is an Amazon Id', function() { + var emsCommonFormResponse = { + id: 12345, + name: 'amz', + emstype: 'ec2', + zone: 'default', + emstype_vm: false, + provider_id: 111, + openstack_infra_providers_exist: false, + provider_region: "ap-southeast-2", + default_userid: "default_user", + default_password: "default_password", + default_verify: "default_verify" + }; + + beforeEach(inject(function(_$controller_) { + $httpBackend.whenGET('/ems_cloud/ems_cloud_form_fields/12345').respond(emsCommonFormResponse); + + $controller = _$controller_('emsCommonFormController', + {$scope: $scope, + $attrs: {'formFieldsUrl': '/ems_cloud/ems_cloud_form_fields/', + 'createUrl': '/ems_cloud', + 'updateUrl': '/ems_cloud/12345'}, + emsCommonFormId: 12345, + miqService: miqService + }); + $httpBackend.flush(); + })); + + it('sets the name to the Amazon EC2 Cloud Provider', function () { + expect($scope.emsCommonModel.name).toEqual('amz'); + }); + + it('sets the type to ec2', function () { + expect($scope.emsCommonModel.emstype).toEqual('ec2'); + }); + + it('sets the zone to default', function() { + expect($scope.emsCommonModel.zone).toEqual('default'); + }); + + it('sets the emstype_vm to false', function() { + expect($scope.emsCommonModel.emstype_vm).toEqual(false); + }); + + it('sets the openstack_infra_providers_exist to false', function() { + expect($scope.emsCommonModel.openstack_infra_providers_exist).toEqual(false); + }); + + it('sets the provider_region', function() { + expect($scope.emsCommonModel.provider_region).toEqual("ap-southeast-2"); + }); + + it('sets the default_userid', function() { + expect($scope.emsCommonModel.default_userid).toEqual("default_user"); + }); + + it('sets the default_password', function() { + expect($scope.emsCommonModel.default_password).toEqual("default_password"); + }); + + it('sets the default_verify', function() { + expect($scope.emsCommonModel.default_verify).toEqual("default_verify"); + }); + }); + + describe('when the emsCommonFormId is an Openstack Id', function() { + var emsCommonFormResponse = { + id: 12345, + name: 'myOpenstack', + hostname: '10.22.33.44', + emstype: 'openstack', + zone: 'default', + emstype_vm: false, + provider_id: 111, + openstack_infra_providers_exist: false, + default_userid: "default_user", + default_password: "default_password", + default_verify: "default_verify" + }; + + beforeEach(inject(function(_$controller_) { + $httpBackend.whenGET('/ems_cloud/ems_cloud_form_fields/12345').respond(emsCommonFormResponse); + + $controller = _$controller_('emsCommonFormController', + {$scope: $scope, + $attrs: {'formFieldsUrl': '/ems_cloud/ems_cloud_form_fields/', + 'createUrl': '/ems_cloud', + 'updateUrl': '/ems_cloud/update/'}, + emsCommonFormId: 12345, + miqService: miqService + }); + $httpBackend.flush(); + })); + + it('sets the name to the Openstack Cloud Provider', function () { + expect($scope.emsCommonModel.name).toEqual('myOpenstack'); + }); + + it('sets the type to openstack', function () { + expect($scope.emsCommonModel.emstype).toEqual('openstack'); + }); + + it('sets the hostname', function () { + expect($scope.emsCommonModel.hostname).toEqual('10.22.33.44'); + }); + + it('sets the zone to default', function() { + expect($scope.emsCommonModel.zone).toEqual('default'); + }); + + it('sets the emstype_vm to false', function() { + expect($scope.emsCommonModel.emstype_vm).toEqual(false); + }); + + it('sets the openstack_infra_providers_exist to false', function() { + expect($scope.emsCommonModel.openstack_infra_providers_exist).toEqual(false); + }); + + it('sets the default_userid', function() { + expect($scope.emsCommonModel.default_userid).toEqual("default_user"); + }); + + it('sets the default_password', function() { + expect($scope.emsCommonModel.default_password).toEqual("default_password"); + }); + + it('sets the default_verify', function() { + expect($scope.emsCommonModel.default_verify).toEqual("default_verify"); + }); + }); + + describe('when the emsCommonFormId is an Azure Id', function() { + var emsCommonFormResponse = { + id: 12345, + name: 'Azure', + azure_tenant_id: '10.22.33.44', + emstype: 'azure', + zone: 'default', + emstype_vm: false, + provider_id: 111, + openstack_infra_providers_exist: false, + default_userid: "default_user", + default_password: "default_password", + default_verify: "default_verify" + }; + + beforeEach(inject(function(_$controller_) { + $httpBackend.whenGET('/ems_cloud/ems_cloud_form_fields/12345').respond(emsCommonFormResponse); + + $controller = _$controller_('emsCommonFormController', + {$scope: $scope, + $attrs: {'formFieldsUrl': '/ems_cloud/ems_cloud_form_fields/', + 'createUrl': '/ems_cloud', + 'updateUrl': '/ems_cloud/update/'}, + emsCommonFormId: 12345, + miqService: miqService + }); + $httpBackend.flush(); + })); + + it('sets the name to the Azure Cloud Provider', function () { + expect($scope.emsCommonModel.name).toEqual('Azure'); + }); + + it('sets the type to azure', function () { + expect($scope.emsCommonModel.emstype).toEqual('azure'); + }); + + it('sets the azure_tenant_id', function () { + expect($scope.emsCommonModel.azure_tenant_id).toEqual('10.22.33.44'); + }); + + it('sets the zone to default', function() { + expect($scope.emsCommonModel.zone).toEqual('default'); + }); + + it('sets the emstype_vm to false', function() { + expect($scope.emsCommonModel.emstype_vm).toEqual(false); + }); + + it('sets the openstack_infra_providers_exist to false', function() { + expect($scope.emsCommonModel.openstack_infra_providers_exist).toEqual(false); + }); + + it('sets the default_userid', function() { + expect($scope.emsCommonModel.default_userid).toEqual("default_user"); + }); + + it('sets the default_password', function() { + expect($scope.emsCommonModel.default_password).toEqual("default_password"); + }); + + it('sets the default_verify', function() { + expect($scope.emsCommonModel.default_verify).toEqual("default_verify"); + }); + }); + + describe('#resetClicked', function() { + beforeEach(function() { + $httpBackend.flush(); + $scope.angularForm = { + $setPristine: function (value){}, + $setUntouched: function (value){}, + }; + $scope.resetClicked(); + }); + + it('sets total spinner count to be 1', function() { + expect(miqService.sparkleOn.calls.count()).toBe(1); + }); + }); + + describe('#saveClicked', function() { + beforeEach(function() { + $httpBackend.flush(); + $scope.angularForm = { + $setPristine: function (value){} + }; + $scope.saveClicked($.Event, true); + }); + + it('turns the spinner on via the miqService', function() { + expect(miqService.sparkleOn).toHaveBeenCalled(); + }); + + it('sets total spinner count to be 2', function() { + expect(miqService.sparkleOn.calls.count()).toBe(2); + }); + + it('delegates to miqService.restAjaxButton', function() { + expect(miqService.restAjaxButton).toHaveBeenCalledWith('/ems_cloud/12345?button=save', $.Event.target); + }); + }); + + describe('#addClicked', function() { + beforeEach(function() { + $httpBackend.flush(); + $scope.angularForm = { + $setPristine: function (value){} + }; + $scope.addClicked($.Event, true); + }); + + it('turns the spinner on via the miqService', function() { + expect(miqService.sparkleOn).toHaveBeenCalled(); + }); + + it('delegates to miqService.restAjaxButton', function() { + expect(miqService.restAjaxButton).toHaveBeenCalledWith('/ems_cloud?button=add', $.Event.target); + }); + }); + + describe('#cancelClicked', function() { + beforeEach(function() { + $httpBackend.flush(); + $scope.angularForm = { + $setPristine: function (value){} + }; + $scope.cancelClicked($.Event); + }); + + it('turns the spinner on via the miqService', function() { + expect(miqService.sparkleOn).toHaveBeenCalled(); + }); + + it('delegates to miqService.restAjaxButton', function() { + expect(miqService.restAjaxButton).toHaveBeenCalledWith('/ems_cloud?button=cancel', $.Event.target); + }); + }); + + describe('saveable should exist in the scope', function() { + beforeEach(function() { + $httpBackend.flush(); + }); + it('returns true', function() { + expect($scope.saveable).toBeDefined(); + }); + }); + + describe('Validates credential fields', function() { + beforeEach(function() { + $httpBackend.flush(); + var angularForm; + var element = angular.element( + '
' + ); + + compile(element)($scope); + $scope.$digest(); + angularForm = $scope.angularForm; + + $scope.angularForm.hostname.$setViewValue('abchost'); + $scope.angularForm.default_userid.$setViewValue('abcuser'); + $scope.angularForm.default_password.$setViewValue('abcpassword'); + $scope.angularForm.default_verify.$setViewValue('abcpassword'); + $scope.currentTab = "default"; + $scope.emsCommonModel.emstype = "ec2"; + }); + + it('returns true if all the Validation fields are filled in', function() { + expect($scope.canValidateBasicInfo()).toBe(true); + }); + }); +}); diff --git a/spec/javascripts/directives/autofocus_spec.js b/spec/javascripts/directives/autofocus_spec.js new file mode 100644 index 00000000000..84388123234 --- /dev/null +++ b/spec/javascripts/directives/autofocus_spec.js @@ -0,0 +1,35 @@ +describe('autofocus initialization', function() { + var $scope, form; + beforeEach(module('ManageIQ.angularApplication')); + beforeEach(inject(function($compile, $rootScope) { + $scope = $rootScope; + var element = angular.element( + '' + ); + elem = $compile(element)($rootScope); + form = $scope.angularForm; + $scope.afterGet = false; + })); + + describe('autofocus specs', function() { + it('should set focus on the name field', inject(function($timeout) { + spyOn(elem[0][0], 'focus'); + form.name.$setViewValue('amazon'); + form.type.$setViewValue('ec2'); + $scope.afterGet = true; + $timeout.flush(); + expect((elem[0][0]).focus).toHaveBeenCalled(); + })); + it('should not set the focus on type field', inject(function($timeout) { + spyOn(elem[0][1], 'focus'); + form.name.$setViewValue('amazon'); + form.type.$setViewValue('ec2'); + $scope.afterGet = true; + $timeout.flush(); + expect((elem[0][1]).focus).not.toHaveBeenCalled(); + })); + }); +}); diff --git a/spec/javascripts/support/jasmine.yml b/spec/javascripts/support/jasmine.yml index bd3d98468ac..27c1ea810bb 100644 --- a/spec/javascripts/support/jasmine.yml +++ b/spec/javascripts/support/jasmine.yml @@ -19,6 +19,7 @@ src_files: - javascripts/services/miq_service.js - javascripts/services/miq_db_backup_service.js - javascripts/services/timer_option_service.js + - javascripts/controllers/ems_common/ems_common_form_controller.js - javascripts/controllers/host/host_form_controller.js - javascripts/controllers/ops/diagnostics_database_form_controller.js - javascripts/controllers/ops/log_collection_form_controller.js @@ -26,6 +27,7 @@ src_files: - javascripts/controllers/schedule/schedule_form_controller.js - javascripts/controllers/repository/repository_form_controller.js - javascripts/controllers/retirement/retirement_form_controller.js + - javascripts/directives/autofocus.js - javascripts/directives/repository/valid_unc_path.js - javascripts/directives/checkchange.js - javascripts/directives/miq_calendar.js diff --git a/spec/models/ext_management_system_spec.rb b/spec/models/ext_management_system_spec.rb index ab628a7d380..dec5c757ad5 100644 --- a/spec/models/ext_management_system_spec.rb +++ b/spec/models/ext_management_system_spec.rb @@ -148,17 +148,18 @@ @same_host_name = "us-east-1" @different_host_name = "us-west-1" @ems = FactoryGirl.create(:ems_vmware, :hostname => @same_host_name) + @zone = Zone.first || FactoryGirl.create(:zone) end it "duplicate name" do described_class.leaf_subclasses.collect{|ems| ems.name.underscore.to_sym}.each do |t| - expect { FactoryGirl.create(t, :name => @ems.name, :hostname => @different_host_name) }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Name has already been taken") + expect { FactoryGirl.create(t, :name => @ems.name, :hostname => @different_host_name, :zone => @zone) }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Name has already been taken") end end it "duplicate hostname" do described_class.leaf_subclasses.collect{|ems| ems.name.underscore.to_sym}.each do |t| - provider = FactoryGirl.build(t, :hostname => @same_host_name) + provider = FactoryGirl.build(t, :hostname => @same_host_name, :zone => @zone) if provider.hostname_required? expect { provider.save! }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Host Name has already been taken") diff --git a/spec/routing/ems_cloud_routing_spec.rb b/spec/routing/ems_cloud_routing_spec.rb index 2eae13426fb..1f412ff3bce 100644 --- a/spec/routing/ems_cloud_routing_spec.rb +++ b/spec/routing/ems_cloud_routing_spec.rb @@ -4,10 +4,9 @@ describe EmsCloudController do let(:controller_name) { "ems_cloud" } - it_behaves_like "A controller that has advanced search routes" + it_behaves_like "A controller that has advanced search routes", true it_behaves_like "A controller that has column width routes" it_behaves_like "A controller that has compare routes" - it_behaves_like "A controller that has CRUD routes" it_behaves_like "A controller that has dialog runner routes" it_behaves_like "A controller that has discovery routes" it_behaves_like "A controller that has download_data routes" @@ -17,10 +16,8 @@ %w( dialog_load - edit - index + ems_cloud_form_fields new - show show_list ).each do |task| describe "##{task}" do @@ -32,7 +29,6 @@ %w( button - create form_field_changed listnav_search_selected save_default_search @@ -46,4 +42,34 @@ end end end + + describe "#index" do + it "routes with GET" do + expect(get("/#{controller_name}")).to route_to("#{controller_name}#index") + end + end + + describe "#create" do + it "routes with POST" do + expect(post("/#{controller_name}")).to route_to("#{controller_name}#create") + end + end + + describe "#edit" do + it "routes with GET" do + expect(get("/#{controller_name}/123/edit")).to route_to("#{controller_name}#edit", :id => "123") + end + end + + describe "#show" do + it "routes with GET" do + expect(get("/#{controller_name}/123")).to route_to("#{controller_name}#show", :id => "123") + end + end + + describe "#update" do + it "routes with POST" do + expect(post("/#{controller_name}/update/123")).to route_to("#{controller_name}#update", :id => "123") + end + end end diff --git a/spec/routing/shared_examples/advanced_search_examples.rb b/spec/routing/shared_examples/advanced_search_examples.rb index 829f5424955..bc231f518dd 100644 --- a/spec/routing/shared_examples/advanced_search_examples.rb +++ b/spec/routing/shared_examples/advanced_search_examples.rb @@ -1,11 +1,19 @@ -shared_examples_for "A controller that has advanced search routes" do +shared_examples_for "A controller that has advanced search routes" do |restful| describe "#quick_search" do it "routes with POST" do expect(post("/#{controller_name}/quick_search")).to route_to("#{controller_name}#quick_search") end - it "does not route with GET" do - expect(get("/#{controller_name}/quick_search")).not_to be_routable + if restful + it "does not route with GET" do + expect(get("/#{controller_name}/quick_search")).to route_to(:action => "show", + :controller => "ems_cloud", + :id => "quick_search") + end + else + it "does not route with GET" do + expect(get("/#{controller_name}/quick_search")).not_to be_routable + end end end @@ -20,8 +28,16 @@ expect(post("/#{controller_name}/adv_search_clear")).to route_to("#{controller_name}#adv_search_clear") end - it "does not route with GET" do - expect(get("/#{controller_name}/adv_search_clear")).not_to be_routable + if restful + it "does not route with GET" do + expect(get("/#{controller_name}/adv_search_clear")).to route_to(:action => "show", + :controller => "ems_cloud", + :id => "adv_search_clear") + end + else + it "does not route with GET" do + expect(get("/#{controller_name}/adv_search_clear")).not_to be_routable + end end end diff --git a/spec/views/ems_cloud/_form_fields.html.haml_spec.rb b/spec/views/ems_cloud/_form_fields.html.haml_spec.rb deleted file mode 100644 index da675b42f62..00000000000 --- a/spec/views/ems_cloud/_form_fields.html.haml_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require "spec_helper" - -describe "rendering fields in ems_cloud new/edit form" do - before(:each) do - @edit = {:new => {:emstype => "openstack"}, :amazon_regions => {}} - end - - it "displays Host Name" do - render :partial => "ems_cloud/form_fields", :locals => {:url => ""} - expect(rendered).to match(/Hostname/) - end - - it "doesn't display IP Address" do - render :partial => "ems_cloud/form_fields", :locals => {:url => ""} - expect(rendered).not_to match(/IP\ Address/) - end -end