From a23f61de27b6b6f9b5c87cea659c3c835855172a Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 30 Aug 2017 19:26:07 -0400 Subject: [PATCH 01/19] Added support for "playbook" type Automate method Added angular form to be displayed when user selects to add/edit "playbook" type Automate method, all other types are still using old haml form https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 374 ++++++++++++++++++ app/controllers/application_controller.rb | 29 ++ app/controllers/miq_ae_class_controller.rb | 110 +++++- .../_ansible_form_options_angular.html.haml | 14 +- .../_angular_method_form.html.haml | 65 +++ app/views/miq_ae_class/_method_form.html.haml | 2 +- .../miq_ae_class/_method_inputs.html.haml | 5 +- config/routes.rb | 2 + 8 files changed, 586 insertions(+), 15 deletions(-) create mode 100644 app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js create mode 100644 app/views/miq_ae_class/_angular_method_form.html.haml diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js new file mode 100644 index 00000000000..b83faf7bf4e --- /dev/null +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -0,0 +1,374 @@ +ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'aeMethodFormId', 'currentRegion', 'miqService', 'postService', 'API', function($http, $scope, aeMethodFormId, currentRegion, miqService, postService, API) { + var vm = this; + var sort_options = "&sort_by=name&sort_order=ascending" + var init = function() { + vm.aeMethodModel = { + name: '', + display_name: '', + location: '', + namespace_path: '', + class_id:'', + language:'', + scope:'', + key: '', + key_value: '', + provisioning_repository_id: '', + provisioning_playbook_id: '', + provisioning_machine_credential_id: '', + provisioning_network_credential_id: '', + provisioning_cloud_credential_id: '', + provisioning_inventory: 'localhost', + provisioning_key: '', + provisioning_value: '', + provisioning_variables: {}, + provisioning_verbosity: '0', + provisioning_editMode: false, + }; + getVerbosityTypes(); + vm.provisioning_cloud_type = ''; + vm.currentRegion = currentRegion; + vm.formId = aeMethodFormId; + vm.afterGet = false; + vm.model = "aeMethodModel"; + + ManageIQ.angular.scope = $scope; + + $http.get('method_form_fields/' + aeMethodFormId) + .then(getMethodFormData) + .catch(miqService.handleFailure); + + if (aeMethodFormId == 'new') { + $scope.newRecord = true; + vm.formOptions(); + vm.formCloudCredentials(null, null); + } else { + vm.newRecord = false; + $scope.newRecord = false; + } + vm.afterGet = true; + + }; + + function getMethodFormData(response) { + var data = response.data; + + vm.aeMethodModel.name = data.name; + vm.aeMethodModel.display_name = data.display_name; + vm.aeMethodModel.namespace_path = data.namespace_path; + vm.aeMethodModel.location = data.location; + vm.aeMethodModel.class_id = data.class_id; + vm.aeMethodModel.language = data.language; + vm.aeMethodModel.scope = data.scope; + vm.formOptions(); + vm.formCloudCredentials(data.cloud_credential_id); + getConfigInfo(data['config_info']); + vm.modelCopy = angular.copy(vm.aeMethodModel); + } + + var getVerbosityTypes = function() { + vm['verbosity_types'] = { + "0": "0 (Normal)", + "1": "1 (Verbose)", + "2": "2 (More Verbose)", + "3": "3 (Debug)", + "4": "4 (Connection Debug)", + "5": "5 (WinRM Debug)" + }; + } + + var getCredentialType = function (credentialId) { + var url = '/api/authentications/' + credentialId; + API.get(url).then(function (data) { + vm.provisioning_cloud_type = data.type; + + if (vm.cloud_types[vm.provisioning_cloud_type] !== 'undefined') { + vm['_provisioning_cloud_type'] = data.type; + getCloudCredentialsforType(data.type); + } + }) + }; + + var setIfDefined = function(value) { + return (typeof value !== 'undefined') ? value : ''; + }; + + var getConfigInfo = function (configData) { + vm.aeMethodModel.provisioning_repository_id = configData['repository_id']; + vm.aeMethodModel.provisioning_playbook_id = configData['playbook_id']; + vm.aeMethodModel.provisioning_machine_credential_id = configData['credential_id']; + vm.aeMethodModel.provisioning_network_credential_id = configData['network_credential_id']; + vm.aeMethodModel.provisioning_cloud_credential_id = setIfDefined(configData['cloud_credential_id']); + vm.aeMethodModel.provisioning_inventory = configData['hosts']; + vm.aeMethodModel.provisioning_key = ''; + vm.aeMethodModel.provisioning_value = ''; + + if (configData['verbosity'] === undefined) { + vm.aeMethodModel.provisioning_verbosity = '0'; + } else { + vm.aeMethodModel.provisioning_verbosity = configData['verbosity']; + } + + setExtraVars('provisioning_variables', configData['extra_vars']); + }; + + var setExtraVars = function (variableName, extraVars) { + if (typeof extraVars !== 'undefined') { + vm.aeMethodModel[variableName] = {}; + for (var key in extraVars) { + vm.aeMethodModel[variableName][key] = extraVars[key]; + } + } + $scope.checkFormPristine(); + } + + $scope.resetClicked = function() { + vm.aeMethodModel = angular.copy(vm.modelCopy); + vm.formOptions(); + cloudCredentialsList(vm.aeMethodModel.cloud_credential_id); + $scope.angularForm.$setUntouched(true); + $scope.angularForm.$setPristine(true); + miqService.miqFlash("warn", __("All changes have been reset")); + }; + + var methodEditButtonClicked = function(buttonName) { + miqService.sparkleOn(); + var url = '/miq_ae_class/add_update_method/' + aeMethodFormId + '?button=' + buttonName; + miqService.miqAjaxButton(url, setConfigInfo(vm.aeMethodModel)) + }; + + $scope.cancelClicked = function() { + methodEditButtonClicked('cancel'); + $scope.angularForm.$setPristine(true); + }; + + $scope.saveClicked = function() { + methodEditButtonClicked('save'); + $scope.angularForm.$setPristine(true); + }; + + $scope.addClicked = function() { + methodEditButtonClicked('add'); + $scope.angularForm.$setPristine(true); + }; + + var formatExtraVars = function(extraVars){ + if (typeof extraVars !== 'undefined') { + formattedExtraVars = {}; + for (var key in extraVars) { + formattedExtraVars[key] = extraVars[key]; + } + } + return formattedExtraVars; + } + + var setConfigInfo = function(configData) { + alert(JSON.stringify(configData)) + method = { + name: configData["name"], + display_name: configData["display_name"], + class_id: configData["class_id"], + language: configData["language"], + scope: configData["scope"], + location: "playbook", + repository_id: configData["provisioning_repository_id"], + playbook_id: configData["provisioning_playbook_id"], + credential_id: configData["provisioning_machine_credential_id"], + hosts: configData["provisioning_inventory"], + verbosity: configData["provisioning_verbosity"], + extra_vars: formatExtraVars(configData["provisioning_variables"]) + } + if (configData["provisioning_network_credential_id"] !== '') + method['network_credential_id'] = configData["provisioning_network_credential_id"]; + + if (configData["provisioning_cloud_credential_id"] !== '') + method['cloud_credential_id'] = configData["provisioning_cloud_credential_id"]; + return method; + } + + + // list of service catalogs + vm.formOptions = function() { + // list of repositories + API.get("/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=" + vm.currentRegion + sort_options).then(function(data) { + vm.repositories = data.resources; + vm._provisioning_repository = _.find(vm.repositories, {id: vm.aeMethodModel.provisioning_repository_id}); + }) + + // list of machine credentials + API.get("/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name" + sort_options).then(function(data) { + vm.machine_credentials = data.resources; + vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm.aeMethodModel.provisioning_machine_credential_id}); + }) + + // list of network credentials + API.get("/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name" + sort_options).then(function(data) { + vm.network_credentials = data.resources; + vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm.aeMethodModel.provisioning_network_credential_id}); + }) + }; + + // list of cloud credentials + vm.formCloudCredentials = function(provisionCredentialId) { + API.options('/api/authentications').then(function(data) { + var cloud_types = {}; + angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(cred_object, cred_type) { + if (cred_object.type == 'cloud') + cloud_types[cred_type] = cred_object.label; + }); + vm.cloud_types = getSortedHash(cloud_types); + cloudCredentialsList(provisionCredentialId); + }); + }; + + var cloudCredentialsList = function(provisionCredentialId) { + if (provisionCredentialId) { + getCredentialType('provisioning', provisionCredentialId); + } else { + vm._provisioning_cloud_type = ''; + vm._provisioning_cloud_credential_id = ''; + } + }; + + var getSortedHash = function(inputHash) { + var sortedHash = Object.keys(inputHash) + .map(function(key) { + return ({"k": key, "v": inputHash[key]}) + }) + .sort(function(a, b) { + return a.v.localeCompare(b.v) + }) + .reduce(function(o, e) { + o[e.k] = e.v; + return o; + }, {}); + return sortedHash; + }; + + // get playbooks for selected repository + vm.repositoryChanged = function(id) { + API.get("/api/configuration_script_sources/" + id + "/configuration_script_payloads?expand=resources&filter[]=region_number=" + vm.currentRegion + sort_options).then(function (data) { + vm.provisioning_playbooks = data.resources; + // if repository has changed + if (id !== vm.aeMethodModel.provisioning_repository_id) { + vm.aeMethodModel.provisioning_playbook_id = ''; + vm.aeMethodModel.provisioning_repository_id = id; + getRemoveResourcesTypes(); + } else { + findObjectForDropDown('_playbook', '_playbooks'); + } + }) + }; + + $scope.$watch('vm._provisioning_repository', function(value) { + if (value) { + vm.repositoryChanged(value.id) + } else { + vm.aeMethodModel['provisioning_repository_id'] = ''; + } + $scope.checkFormPristine(); + }); + + $scope.checkFormPristine = function() { + if (angular.equals(vm.aeMethodModel, vm.modelCopy)) { + $scope.angularForm.$setPristine(); + } else { + $scope.angularForm.$setDirty(); + } + }; + + $scope.cloudTypeChanged = function(value) { + var valueChanged = (value !== vm.provisioning_cloud_type); + if (value) { + vm.provisioning_cloud_type = value; + } else { + vm.provisioning_cloud_type = ''; + } + if (valueChanged) { + var typ = vm.provisioning_cloud_type; + vm.aeMethodModel.provisioning_cloud_credential_id = ''; + getCloudCredentialsforType(typ); + } + $scope.checkFormPristine(); + }; + + vm.fieldsRequired = function(prefix) { + return prefix === 'provisioning'; + }; + + var getCloudCredentialsforType = function(typ) { + // list of cloud credentials based upon selected cloud type + var url = '/api/authentications?collection_class=' + typ + '&expand=resources&attributes=id,name' + sort_options; + API.get(url).then(function(data) { + vm.provisioning_cloud_credentials = data.resources; + findObjectForDropDown('provisioning_cloud_credential', '_cloud_credentials'); + }) + }; + + var findObjectForDropDown = function(fieldName, listName) { + vm['_provisioning' + fieldName] = _.find(vm['provisioning' + listName], {id: vm.aeMethodModel['provisioning' + fieldName + '_id']}); + $scope.checkFormPristine(); + }; + + $scope.$watch('vm._provisioning_cloud_type', function(value) { + $scope.cloudTypeChanged(value); + }) + + vm.addKeyValue = function() { + vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.provisioning_key] = vm.aeMethodModel.provisioning_value; + vm.aeMethodModel.provisioning_key = ''; + vm.aeMethodModel.provisioning_value = ''; + } + + vm.provisioning_repository_selected = function() { + return vm.aeMethodModel.provisioning_repository_id !== ''; + } + + vm.removeKeyValue = function(key) { + delete vm.aeMethodModel.provisioning_variables[key]; + $scope.checkFormPristine(); + } + + vm.editKeyValue = function(key, key_value, index) { + vm.aeMethodModel.provisioning_editMode = true; + vm.aeMethodModel.s_index = index; + vm.aeMethodModel.key = key; + vm.aeMethodModel.key_value = key_value; + vm.aeMethodModel.original_key = key; + vm.aeMethodModel.original_key_value = key_value; + } + + vm.cancelKeyValue = function() { + vm.aeMethodModel.provisioning_editMode = false; + vm.aeMethodModel.s_index = ''; + vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.original_key] = vm.aeMethodModel.original_key_value; + } + + vm.saveKeyValue = function(index) { + vm.aeMethodModel.provisioning_editMode = false; + vm.aeMethodModel.s_index = ''; + // delete key if key name was edited, and a add new key to hash with new name + if (vm.aeMethodModel.original_key !== vm.aeMethodModel.key) + delete vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.original_key]; + + vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.key] = vm.aeMethodModel.key_value; + } + + vm.variablesEmpty = function() { + field = vm.aeMethodModel.provisioning_variables; + return Object.keys(field).length === 0; + }; + + // watch for all the drop downs on screen + "provisioning_playbook provisioning_machine_credential provisioning_network_credential provisioning_cloud_credential".split(" ").forEach(idWatch) + + function idWatch(name) { + field_name = "vm._" + name; + $scope.$watch(field_name, function(value) { + if (value) + vm.aeMethodModel[name + '_id'] = value.id; + $scope.checkFormPristine(); + }); + } + + init(); +}]); diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6064c9270d2..65ee7588607 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1794,6 +1794,35 @@ def build_created_audit(rec, eh) } end + def build_saved_audit_hash(old_record_attributes, new_record, add) + name = new_record.respond_to?(:name) ? new_record.name : new_record.description + msg = if add + _("[%{name}] Record added (") % {:name => name} + else + _("[%{name}] Record updated (") % {:name => name} + end + event = "#{new_record.class.to_s.downcase}_record_#{add ? "add" : "update"}" + + attribute_difference = new_record.attributes.to_a - old_record_attributes.to_a + attribute_difference = Hash[*attribute_difference.flatten] + + difference_messages = [] + + attribute_difference.each do |key, value| + difference_messages << _("%{key} changed to %{value}") % {:key => key, :value => value} + end + + msg = msg + difference_messages.join(", ") + ")" + + { + :event => event, + :target_id => new_record.id, + :target_class => new_record.class.base_class.name, + :userid => session[:userid], + :message => msg + } + end + # Build the audit object when a record is saved, including all of the changed fields # params - rec = db record, eh = edit hash containing current and new values def build_saved_audit(rec, eh) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index b4129e356c0..3183483edda 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -304,7 +304,7 @@ def replace_right_cell(options = {}) presenter.replace('flash_msg_div', r[:partial => "layouts/flash_msg"]) if @flash_array - if @in_a_form + if @in_a_form && !@angular_form action_url = create_action_url(nodes.first) # incase it was hidden for summary screen, and incase there were no records on show_list presenter.show(:paging_div, :form_buttons_div) @@ -496,9 +496,10 @@ def edit_method else id = x_node.split('-') end - @ae_method = find_record_with_rbac(MiqAeMethod, from_cid(id[1])) - set_method_form_vars - @in_a_form = true + @record = @ae_method = find_record_with_rbac(MiqAeMethod, from_cid(id[1])) + @current_region = MiqRegion.my_region.region + set_method_form_vars unless @ae_method.location == "playbook" + @in_a_form = @angular_form = true session[:changed] = @changed = false replace_right_cell end @@ -902,7 +903,15 @@ def form_method_field_changed render :update do |page| page << javascript_prologue page.replace_html('form_div', :partial => 'method_form', :locals => {:prefix => ""}) if @edit[:new][:location] == 'expression' - page.replace_html(@refresh_div, :partial => @refresh_partial) if @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) + if @edit[:new][:location] == "playbook" + @record = @ae_method + @current_region = MiqRegion.my_region.region + page.replace_html(@refresh_div, :partial => 'angular_method_form') + page << javascript_hide("form_buttons_div") + else + page.replace_html(@refresh_div, :partial => @refresh_partial) if @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) + end + if params[:cls_field_datatype] if session[:field_data][:datatype] == "password" page << javascript_hide("cls_field_default_value") @@ -964,6 +973,36 @@ def form_method_field_changed end end + def method_form_fields + method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) + data = method.data ? JSON.parse(method.data) : {} + method_hash = { + :name => method.name, + :display_name => method.display_name, + :namespace_path => @sb[:namespace_path], + :class_id => method.id ? method.class_id : MiqAeClass.find(from_cid(x_node.split("-").last)).id, + :location => 'playbook', + :language => 'ruby', + :scope => "instance", + :config_info => { + :repository_id => data['repository_id'] || '', + :playbook_id => data['playbook_id'] || '', + :credential_id => data['credential_id'] || '', + :network_credential_id => data['network_credential_id'] || '', + :cloud_credential_id => data['cloud_credential_id'] || '', + :hosts => data['hosts'], + :verbosity => data['verbosity'], + :extra_vars => { + :sleep => '40', + :pkg => 'httpd', + :user => 'root', + :host => 'localhost' + }, + } + } + render :json => method_hash + end + # AJAX driven routine to check for changes in ANY field on the form def form_ns_field_changed return unless load_edit("aens_edit__#{params[:id]}", "replace_cell__explorer") @@ -1102,6 +1141,66 @@ def update_ns end end + def add_update_method + assert_privileges("miq_ae_method_edit") + case params[:button] + when "cancel" + if params[:id] && params[:id] != "new" + method = find_record_with_rbac(MiqAeMethod, params[:id]) + add_flash(_("Edit of %{model} \"%{name}\" was cancelled by the user") % {:model => ui_lookup(:model => "MiqAeMethod"), :name => method.name}) + else + add_flash(_("Add of %{model} was cancelled by the user") % {:model => ui_lookup(:model => "MiqAeMethod")}) + end + replace_right_cell + when "add","save" + method = params[:id] != "new" ? find_record_with_rbac(MiqAeMethod, params[:id]) : MiqAeMethod.new + method.name = params["name"] + method.display_name = params["display_name"] + method.location = params["location"] + method.language = params["language"] + method.scope = params["scope"] + method.class_id = params[:class_id] + method.data = set_playbook_data.to_json + begin + method.save! + rescue => bang + add_flash(_("Error during 'save': %{error_message}") % {:error_message => bang.message}, :error) + javascript_flash + else + old_method_attributes = method.attributes.clone + add_flash(_("%{model} \"%{name}\" was saved") % {:model => ui_lookup(:model => "MiqAeMethod"), :name => method.name}) + AuditEvent.success(build_saved_audit_hash(old_method_attributes, method, params[:button] == "add")) + replace_right_cell(:replace_trees => [:ae]) + return + end + end + end + + def set_playbook_data + data = { + :repository_id => params['repository_id'], + :playbook_id => params['playbook_id'], + :credential_id => params['credential_id'], + :hosts => params['hosts'], + :verbosity => params['verbosity'], + :extra_vars => { + :sleep => '40', + :pkg => 'httpd', + :user => 'root', + :host => 'localhost' + } + } + data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] + data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] + data + end + {"name"=>"test1", "display_name"=>"testing", "class_id"=>"10000000000122", "language"=>"ruby", "scope"=>"instance", + "location"=>"playbook", + "repository_id"=>"10r14", + "playbook_id"=>"10r154", + "credential_id"=>"10r64", + "hosts"=>"localhost1", "verbosity"=>"0", "extra_vars"=>{"sleep"=>"40", "pkg"=>"httpd", "user"=>"root", "host"=>"localhost"}, "button"=>"save", "id"=>"10000000001069"} + def update_method assert_privileges("miq_ae_method_edit") return unless load_edit("aemethod_edit__#{params[:id]}", "replace_cell__explorer") @@ -2195,7 +2294,6 @@ def set_method_record_vars(miqaemethod) miqaemethod.scope = @edit[:new][:scope] miqaemethod.location = @edit[:new][:location] miqaemethod.language = @edit[:new][:language] - miqaemethod.data = @edit[:new][:data] miqaemethod.data = if @edit[:new][:location] == 'expression' data_for_expression else diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index a914cbc3969..72bb84430d4 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -107,8 +107,7 @@ "checkchange" => true} %span.help-block{"ng-show" => "angularForm.#{prefix}_inventory.$error.miqrequired"} = _("Required") - - .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_execution_ttl.$invalid}"} + .form-group{"ng-if" =>"#{ng_model}.#{prefix}_execution_ttl!==undefined","ng-class" => "{'has-error': angularForm.#{prefix}_execution_ttl.$invalid}"} %label.col-md-3.control-label{"for" => "#{prefix}_execution_ttl"} = _("Max TTL (mins)") .col-md-9 @@ -138,9 +137,10 @@ %label.col-md-3.control-label = _('Verbosity') .col-md-9 - %select{"ng-model" => "vm.catalogItemModel.#{prefix}_verbosity", + %select{"ng-model" => "vm.#{ng_model}.#{prefix}_verbosity", "name" => "#{prefix}_verbosity", 'ng-options' => 'v as k for (v, k) in vm.verbosity_types', + "checkchange" => "", 'pf-select' => true} - if prefix == "retirement" @@ -148,8 +148,8 @@ %label.col-md-3.control-label{"for" => "catalog_id"} = _('Remove resources?') .col-md-9 - %select{"ng-model" => "vm.catalogItemModel.retirement_remove_resources", - "name" => "vm.catalogItemModel.retirement_remove_resources", + %select{"ng-model" => "vm.#{ng_model}.retirement_remove_resources", + "name" => "vm.#{ng_model}.retirement_remove_resources", 'ng-options' => "v as k for (k, v) in vm.remove_resources_types", :checkchange => true, "pf-select" => true} @@ -223,7 +223,7 @@ %span{:class => "pficon pficon-delete"} - if prefix == "provisioning" - .form-group + .form-group{"ng-if" =>"#{ng_model}.#{prefix}_dialog_existing!==undefined"} %label.col-md-3.control-label = _("Dialog") .col-md-3 @@ -243,7 +243,7 @@ %span.help-block{"ng-show" => "angularForm.#{prefix}_dialog_id.$error.$invalid"} = _("Required") - .form-group + .form-group{"ng-if" =>"#{ng_model}.#{prefix}_dialog_existing!==undefined"} %label.col-md-3.control-label .col-md-3 %label.radio-inline diff --git a/app/views/miq_ae_class/_angular_method_form.html.haml b/app/views/miq_ae_class/_angular_method_form.html.haml new file mode 100644 index 00000000000..c76c98f83b1 --- /dev/null +++ b/app/views/miq_ae_class/_angular_method_form.html.haml @@ -0,0 +1,65 @@ +- @angular_form = true +%form.form-horizontal#form_div{"name" => "angularForm", + "ng-controller" => "aeMethodFormController as vm", + "miq-form" => 'true', + "ng-show" => "vm.afterGet", + "model" => "vm.aeMethodModel", + "model-copy" => 'vm.modelCopy'} + = render :partial => "layouts/flash_msg" + %div + .form-group + %label.col-md-2.control-label{"for" => "name"} + = _("Type") + .col-md-8 + {{vm.aeMethodModel.location}} + %input{:type => 'hidden', :id => "location", :value => "vm.aeMethodModel.location"} + %input{:type => 'hidden', :id => "scope", :value => "vm.aeMethodModel.scope"} + %input{:type => 'hidden', :id => "language", :value => "vm.aeMethodModel.language"} + %input{:type => 'hidden', :id => "class_id", :value => "vm.aeMethodModel.class_id"} + + .form-group + %label.col-md-2.control-label{"for" => "name"} + = Dictionary.gettext('fqname', :type => :column, :notfound => :titleize) + .col-md-8 + {{vm.aeMethodModel.namespace_path}} + + .form-group{"ng-class" => "{'has-error': angularForm.name.$invalid}"} + %label.col-md-2.control-label{"for" => "name"} + = _("Name") + .col-md-8 + %input.form-control{"type" => "text", + "id" => "name", + "name" => "name", + "ng-model" => "vm.aeMethodModel.name", + "maxlength" => 40, + "miqrequired" => "", + "checkchange" => "", + "auto-focus" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.miqrequired"} + = _("Required") + .form-group{"ng-class" => "{'has-error': angularForm.display_name.$invalid}"} + %label.col-md-2.control-label{"for" => "display_name"} + = _("Display Name") + .col-md-8 + %input.form-control{"type" => "text", + "id" => "display_name", + "name" => "display_name", + "ng-model" => "vm.aeMethodModel.display_name", + "maxlength" => 60, + "miqrequired" => "", + "checkchange" => ""} + %span.help-block{"ng-show" => "angularForm.display_name.$error.miqrequired"} + = _("Required") + + = render :partial => "layouts/angular/ansible_form_options_angular", + :locals => {:ng_show => true, + :ng_model => "vm.aeMethodModel", + :id => @record.id, + :prefix => "provisioning", + :basic_info_needed => true} + = render :partial => "layouts/angular/x_edit_buttons_angular" + +:javascript + ManageIQ.angular.app.value('aeMethodFormId', '#{@record.id || "new"}'); + ManageIQ.angular.app.value('currentRegion', '#{@current_region}'); + miq_bootstrap('#form_div'); diff --git a/app/views/miq_ae_class/_method_form.html.haml b/app/views/miq_ae_class/_method_form.html.haml index 48b04cefd90..9c6a1fe8384 100644 --- a/app/views/miq_ae_class/_method_form.html.haml +++ b/app/views/miq_ae_class/_method_form.html.haml @@ -95,4 +95,4 @@ 'data-click_url' => {:url => url2}.to_json} %i{:class => "fa fa-angle-#{icon} fa-lg"} - = render :partial => "inputs" + = render :partial => "inputs" diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index e23c0c8053f..d40a4da8c2a 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -74,5 +74,8 @@ %td= record.datatype.blank? ? 'string' : record.datatype - else #method_form_div - = render :partial => "method_form", :locals => {:prefix => ""} + - if @record.location == "playbook" + = render :partial => "angular_method_form", :locals => {:prefix => ""} + - else + = render :partial => "method_form", :locals => {:prefix => ""} %br diff --git a/config/routes.rb b/config/routes.rb index 2f95697cf4c..6a829ebc7fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2152,8 +2152,10 @@ :miq_ae_class => { :get => %w( explorer + method_form_fields ), :post => %w( + add_update_method ae_tree_select ae_tree_select_toggle change_tab From efd1a3501a0bcf4c16aaf26314790bf7f877fe53 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Tue, 5 Sep 2017 15:00:09 -0400 Subject: [PATCH 02/19] Further changes to use Anugularized Input Parameters table. And some other minor cleanup/changes --- .../miq_ae_class/ae_method_form_controller.js | 100 ++++++++++------ app/controllers/miq_ae_class_controller.rb | 52 ++++++-- .../_ansible_form_options_angular.html.haml | 112 +++++++++++++++++- 3 files changed, 214 insertions(+), 50 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index b83faf7bf4e..82e0d7fb22d 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -12,6 +12,8 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a scope:'', key: '', key_value: '', + key_type: 'string', + available_datatypes: '', provisioning_repository_id: '', provisioning_playbook_id: '', provisioning_machine_credential_id: '', @@ -20,7 +22,8 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a provisioning_inventory: 'localhost', provisioning_key: '', provisioning_value: '', - provisioning_variables: {}, + provisioning_type: 'string', + provisioning_inputs: [], provisioning_verbosity: '0', provisioning_editMode: false, }; @@ -59,6 +62,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.class_id = data.class_id; vm.aeMethodModel.language = data.language; vm.aeMethodModel.scope = data.scope; + vm.aeMethodModel.available_datatypes = data.available_datatypes; vm.formOptions(); vm.formCloudCredentials(data.cloud_credential_id); getConfigInfo(data['config_info']); @@ -98,7 +102,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_machine_credential_id = configData['credential_id']; vm.aeMethodModel.provisioning_network_credential_id = configData['network_credential_id']; vm.aeMethodModel.provisioning_cloud_credential_id = setIfDefined(configData['cloud_credential_id']); - vm.aeMethodModel.provisioning_inventory = configData['hosts']; + vm.aeMethodModel.provisioning_inventory = configData['hosts'] ? configData['hosts'] : 'localhost'; vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; @@ -107,19 +111,20 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a } else { vm.aeMethodModel.provisioning_verbosity = configData['verbosity']; } - - setExtraVars('provisioning_variables', configData['extra_vars']); + setExtraVars('provisioning_inputs', configData['extra_vars']); }; var setExtraVars = function (variableName, extraVars) { if (typeof extraVars !== 'undefined') { - vm.aeMethodModel[variableName] = {}; - for (var key in extraVars) { - vm.aeMethodModel[variableName][key] = extraVars[key]; - } + vm.aeMethodModel[variableName] = []; + extraVars.forEach( function (arrayItem) + { + var input_vars = [arrayItem.name, arrayItem.default_value, arrayItem.datatype, arrayItem.id]; + vm.aeMethodModel[variableName].push(input_vars); + }); } $scope.checkFormPristine(); - } + }; $scope.resetClicked = function() { vm.aeMethodModel = angular.copy(vm.modelCopy); @@ -151,18 +156,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a $scope.angularForm.$setPristine(true); }; - var formatExtraVars = function(extraVars){ - if (typeof extraVars !== 'undefined') { - formattedExtraVars = {}; - for (var key in extraVars) { - formattedExtraVars[key] = extraVars[key]; - } - } - return formattedExtraVars; - } - var setConfigInfo = function(configData) { - alert(JSON.stringify(configData)) method = { name: configData["name"], display_name: configData["display_name"], @@ -175,7 +169,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a credential_id: configData["provisioning_machine_credential_id"], hosts: configData["provisioning_inventory"], verbosity: configData["provisioning_verbosity"], - extra_vars: formatExtraVars(configData["provisioning_variables"]) + extra_vars: configData["provisioning_inputs"] } if (configData["provisioning_network_credential_id"] !== '') method['network_credential_id'] = configData["provisioning_network_credential_id"]; @@ -268,6 +262,20 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a $scope.checkFormPristine(); }); + $scope.$watch('vm.aeMethodModel.key_type', function(value) { + if (value && vm.aeMethodModel.key_type == vm.aeMethodModel.original_key_type) { + vm.aeMethodModel.key_value = ''; + } + $scope.checkFormPristine(); + }); + + $scope.$watch('vm.aeMethodModel.provisioning_type', function(value) { + if (value) { + vm.aeMethodModel.provisioning_value = ''; + } + $scope.checkFormPristine(); + }); + $scope.checkFormPristine = function() { if (angular.equals(vm.aeMethodModel, vm.modelCopy)) { $scope.angularForm.$setPristine(); @@ -314,47 +322,69 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a }) vm.addKeyValue = function() { - vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.provisioning_key] = vm.aeMethodModel.provisioning_value; - vm.aeMethodModel.provisioning_key = ''; - vm.aeMethodModel.provisioning_value = ''; + var valid = validate_input_name(vm.aeMethodModel.provisioning_key); + if (!valid) + return miqService.miqFlash("error", __("Inputs name must be unique")); + else { + vm.aeMethodModel.provisioning_inputs.push( + [vm.aeMethodModel.provisioning_key, vm.aeMethodModel.provisioning_value, vm.aeMethodModel.provisioning_type]); + vm.aeMethodModel.provisioning_key = ''; + vm.aeMethodModel.provisioning_value = ''; + vm.aeMethodModel.provisioning_type = 'string'; + } } vm.provisioning_repository_selected = function() { return vm.aeMethodModel.provisioning_repository_id !== ''; } - vm.removeKeyValue = function(key) { - delete vm.aeMethodModel.provisioning_variables[key]; + vm.removeKeyValue = function(type, key, key_value, key_type, index) { + vm.aeMethodModel.provisioning_inputs.splice(index, 1); $scope.checkFormPristine(); } - vm.editKeyValue = function(key, key_value, index) { + vm.editKeyValue = function(type, key, key_value, key_type, index) { vm.aeMethodModel.provisioning_editMode = true; vm.aeMethodModel.s_index = index; vm.aeMethodModel.key = key; vm.aeMethodModel.key_value = key_value; + vm.aeMethodModel.key_type = key_type; vm.aeMethodModel.original_key = key; vm.aeMethodModel.original_key_value = key_value; + vm.aeMethodModel.original_key_type = key_type; } - vm.cancelKeyValue = function() { + vm.cancelKeyValue = function(index) { vm.aeMethodModel.provisioning_editMode = false; vm.aeMethodModel.s_index = ''; - vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.original_key] = vm.aeMethodModel.original_key_value; + vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.original_key + vm.aeMethodModel.provisioning_inputs[index][1] = vm.aeMethodModel.original_key_value; + vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.original_key_type; } - vm.saveKeyValue = function(index) { + vm.saveKeyValue = function(type, index) { + var valid = validate_input_name(vm.aeMethodModel.key); + if (!valid) + return miqService.miqFlash("error", __("Input Name must be unique")); vm.aeMethodModel.provisioning_editMode = false; vm.aeMethodModel.s_index = ''; - // delete key if key name was edited, and a add new key to hash with new name - if (vm.aeMethodModel.original_key !== vm.aeMethodModel.key) - delete vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.original_key]; + vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.key; + vm.aeMethodModel.provisioning_inputs[index][1] = vm.aeMethodModel.key_value; + vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.key_type; + } - vm.aeMethodModel.provisioning_variables[vm.aeMethodModel.key] = vm.aeMethodModel.key_value; + var validate_input_name = function(input_name){ + var valid = true; + vm.aeMethodModel.provisioning_inputs.forEach( function (input) + { + if (input[0] === input_name) + valid = false; + }); + return valid; } vm.variablesEmpty = function() { - field = vm.aeMethodModel.provisioning_variables; + field = vm.aeMethodModel.provisioning_inputs; return Object.keys(field).length === 0; }; diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 3183483edda..de378ee0835 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -984,6 +984,7 @@ def method_form_fields :location => 'playbook', :language => 'ruby', :scope => "instance", + :available_datatypes => MiqAeField.available_datatypes_for_ui, :config_info => { :repository_id => data['repository_id'] || '', :playbook_id => data['playbook_id'] || '', @@ -992,12 +993,19 @@ def method_form_fields :cloud_credential_id => data['cloud_credential_id'] || '', :hosts => data['hosts'], :verbosity => data['verbosity'], - :extra_vars => { - :sleep => '40', - :pkg => 'httpd', - :user => 'root', - :host => 'localhost' - }, + # :extra_vars => { + # :sleep => '40', + # :pkg => 'httpd', + # :user => 'root', + # :host => 'localhost' + # }, + # :extra_vars => [ + # ['sleep', '40', 'string'], + # ['pkg', 'httpd', 'string'], + # ['user', 'root', 'string'], + # ['host', 'localhost', "string"] + # ] + :extra_vars => method.inputs } } render :json => method_hash @@ -1162,7 +1170,12 @@ def add_update_method method.class_id = params[:class_id] method.data = set_playbook_data.to_json begin - method.save! + MiqAeMethod.transaction do + to_save, to_delete = set_playbook_inputs(method) + method.inputs.destroy(MiqAeField.where(:id => to_delete)) + method.inputs = to_save + method.save! + end rescue => bang add_flash(_("Error during 'save': %{error_message}") % {:error_message => bang.message}, :error) javascript_flash @@ -1176,6 +1189,25 @@ def add_update_method end end + def set_playbook_inputs(method) + existing_inputs = method.inputs + new_inputs = params[:extra_vars] + inputs_to_save = [] + inputs_to_delete = [] + new_inputs.each do |i, input| + field = input.length == 4 ? MiqAeField.find_by(:id => input.last) : MiqAeField.new + field.name = input[0] + field.default_value = input[1] == "" ? nil : input[1] + field.datatype = input[2] + field.priority = i + inputs_to_save.push(field) + end + existing_inputs.each do |existing_input| + inputs_to_delete.push(existing_input.id) unless inputs_to_save.any? {|i| i.id == existing_input.id } + end + return inputs_to_save, inputs_to_delete + end + def set_playbook_data data = { :repository_id => params['repository_id'], @@ -1194,12 +1226,6 @@ def set_playbook_data data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] data end - {"name"=>"test1", "display_name"=>"testing", "class_id"=>"10000000000122", "language"=>"ruby", "scope"=>"instance", - "location"=>"playbook", - "repository_id"=>"10r14", - "playbook_id"=>"10r154", - "credential_id"=>"10r64", - "hosts"=>"localhost1", "verbosity"=>"0", "extra_vars"=>{"sleep"=>"40", "pkg"=>"httpd", "user"=>"root", "host"=>"localhost"}, "button"=>"save", "id"=>"10000000001069"} def update_method assert_privileges("miq_ae_method_edit") diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 72bb84430d4..429920fd9a3 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -153,7 +153,8 @@ 'ng-options' => "v as k for (k, v) in vm.remove_resources_types", :checkchange => true, "pf-select" => true} - .col-md-12.col-lg-6 + + .col-md-12.col-lg-6{'ng-if' => "#{ng_model}.#{prefix}_variables!==undefined"} .form-group %label.col-md-3.control-label = _("Variables & Default Values") @@ -217,7 +218,7 @@ %i.pficon.pficon-close %div{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)", :class => "btn-container"} - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue('#{prefix}', this.key, this.key_value, $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue('#{prefix}', this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} %span{:class => "pficon pficon-edit"} %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue('#{prefix}', this.key, this.key_value, $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} %span{:class => "pficon pficon-delete"} @@ -259,3 +260,110 @@ "checkchange" => ""} %span.help-block{"ng-show" => "angularForm.#{prefix}_dialog_name.$error.$invalid"} = _("Required") + +.row{'ng-if' => "#{ng_model}.#{prefix}_inputs"} + .col-md-12.col-lg-12 + .form-group + %label + = _("Input Parameters") + .col-md-6 + %table.table + %tr + %td + %input{:type => "text", + 'ng-model' => "#{ng_model}.#{prefix}_key", + :name => "#{prefix}_key", + "placeholder" => "Variable", + "checkchange" => ""} + %span.help-block{"ng-show" => "(#{ng_model}.#{prefix}_key === '' && #{ng_model}.#{prefix}_value !== '')"} + = _("Required") + %td + %input{:type => "text", + 'ng-model' => "#{ng_model}.#{prefix}_value", + 'ng-if' => "#{ng_model}.#{prefix}_type != 'password'", + :name => "#{prefix}_value", + "placeholder" => "Default value", + "checkchange" => ""} + %input{"type" => "password", + :name => "#{prefix}_value", + 'ng-if' => "#{ng_model}.#{prefix}_type == 'password'", + 'ng-model' => "#{ng_model}.#{prefix}_value", + "placeholder" => placeholder_if_present("#{ng_model}.#{prefix}_value"), + "ng-change" => "", + "miqrequired" => ""} + %span.help-block{"ng-show" => "(#{ng_model}.#{prefix}_key !== '' && #{ng_model}.#{prefix}_value === '')"} + = _("Required") + %td + %select{"ng-model" => "#{ng_model}.#{prefix}_type", + "name" => "#{prefix}_type", + 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", + 'ng-change' => '', + "pf-select" => true} + %td + %button{:class => "btn btn-link", + :type => "button", + "ng-click" => "vm.addKeyValue('#{prefix}')", + "ng-if" => "(#{ng_model}.#{prefix}_key != '' && #{ng_model}.#{prefix}_value != '')"} + %span{:class => "fa fa-plus tag-add"} + + #inputs_div + .form-group + %label.col-md-4.control-label + .col-md-12 + %table.table.table-bordered.table-striped + %thead + %th + = _("Input Name") + %th + = _("Default value") + %th + = _("Data Type") + %th + = _("Actions") + %tbody + %tr{"ng-repeat" => "arr in #{ng_model}.#{prefix}_inputs track by $index", "ng-form" => "rowForm"} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[0]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %input.form-control{:type => "text", + :name => "key", + 'ng-model' => "#{ng_model}.key", + "ng-change" => "", + "miqrequired" => ""} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[2] == 'password' ? '******' : arr[1]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %input.form-control{:type => "text", + :name => "key_value", + 'ng-if' => "#{ng_model}.key_type != 'password'", + 'ng-model' => "#{ng_model}.key_value", + "ng-change" => "", + "miqrequired" => ""} + %input.form-control{"type" => "password", + :name => "key_value", + 'ng-if' => "#{ng_model}.key_type == 'password'", + 'ng-model' => "#{ng_model}.key_value", + "placeholder" => placeholder_if_present("#{ng_model}.key_value"), + "ng-change" => "", + "miqrequired" => ""} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[2]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %select.form-control{"ng-model" => "#{ng_model}.key_type", + "name" => "key_type", + 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", + "ng-change" => '', + "pf-select" => true} + + %td.table-view-pf-select + %div{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %button{:class => "btn btn-link", :type => "button", "ng-disabled" => "(#{ng_model}.key === '' || #{ng_model}.key_value === '')", "ng-click" => "vm.saveKeyValue('#{prefix}', $index)"} + %i.pficon.pficon-save + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.cancelKeyValue($index)"} + %i.pficon.pficon-close + + %div{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)", :class => "btn-container"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue('#{prefix}', this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %span{:class => "pficon pficon-edit"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue('#{prefix}', this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %span{:class => "pficon pficon-delete"} From 272f46512c2829359d648be1d6676b7d7ebafd3c Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Tue, 5 Sep 2017 22:27:22 -0400 Subject: [PATCH 03/19] Added changes to show playbook data on method summary screen. Moved couple of common methods to application controller. Removed some unrequired/leftover code https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 2 +- app/controllers/application_controller.rb | 18 ++++++++++ app/controllers/catalog_controller.rb | 18 ---------- app/controllers/miq_ae_class_controller.rb | 33 +++++++++---------- .../_ansible_form_options_angular.html.haml | 2 +- .../miq_ae_class/_method_inputs.html.haml | 32 ++++++++++++++++++ 6 files changed, 67 insertions(+), 38 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 82e0d7fb22d..a8485836588 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -106,7 +106,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; - if (configData['verbosity'] === undefined) { + if (configData['verbosity'] === undefined || configData['verbosity'] == '') { vm.aeMethodModel.provisioning_verbosity = '0'; } else { vm.aeMethodModel.provisioning_verbosity = configData['verbosity']; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 65ee7588607..6905bab6f42 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2336,4 +2336,22 @@ def build_accordions_and_trees @accords = allowed_features.map(&:accord_hash) set_active_elements(allowed_features.first) end + + def fetch_name_from_object(klass, id) + klass.find_by(:id => from_cid(id)).try(:name) + end + + def verbosity_display(verbosity) + verbosity ||= "0" + verbosity_hsh = { + "0" => "0 (Normal)", + "1" => "1 (Verbose)", + "2" => "2 (More Verbose)", + "3" => "3 (Debug)", + "4" => "4 (Connection Debug)", + "5" => "5 (WinRM Debug)" + } + verbosity_hsh[verbosity.to_s] + end + helper_method :verbosity_display end diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 7285045a83e..e11219d4378 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -832,20 +832,6 @@ def remove_resources_display(remove_resources) end helper_method :remove_resources_display - def verbosity_display(verbosity) - verbosity ||= "0" - verbosity_hsh = { - "0" => "0 (Normal)", - "1" => "1 (Verbose)", - "2" => "2 (More Verbose)", - "3" => "3 (Debug)", - "4" => "4 (Connection Debug)", - "5" => "5 (WinRM Debug)" - } - verbosity_hsh[verbosity.to_s] - end - helper_method :verbosity_display - def features [{:role => "svc_catalog_accord", :role_any => true, @@ -1872,10 +1858,6 @@ def fetch_playbook_details playbook_details end - def fetch_name_from_object(klass, id) - klass.find_by(:id => id).try(:name) - end - def fetch_dialog(playbook_details, dialog_id, key) return nil if dialog_id.nil? dialog = Dialog.find_by(:id => dialog_id) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index de378ee0835..046efd9f315 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -993,18 +993,6 @@ def method_form_fields :cloud_credential_id => data['cloud_credential_id'] || '', :hosts => data['hosts'], :verbosity => data['verbosity'], - # :extra_vars => { - # :sleep => '40', - # :pkg => 'httpd', - # :user => 'root', - # :host => 'localhost' - # }, - # :extra_vars => [ - # ['sleep', '40', 'string'], - # ['pkg', 'httpd', 'string'], - # ['user', 'root', 'string'], - # ['host', 'localhost', "string"] - # ] :extra_vars => method.inputs } } @@ -1215,12 +1203,6 @@ def set_playbook_data :credential_id => params['credential_id'], :hosts => params['hosts'], :verbosity => params['verbosity'], - :extra_vars => { - :sleep => '40', - :pkg => 'httpd', - :user => 'root', - :host => 'localhost' - } } data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] @@ -2680,11 +2662,26 @@ def get_method_node_info(id) if @record.location == 'expression' hash = YAML.load(@record.data) @expression = hash[:expression] ? MiqExpression.new(hash[:expression]).to_human : "" + elsif @record.location == "playbook" + fetch_playbook_details end domain_overrides set_right_cell_text(x_node, @record) end + def fetch_playbook_details + @playbook_details = {} + data = JSON.parse(@record.data) + @playbook_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, data['repository_id']) + @playbook_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, data['playbook_id']) + @playbook_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, data['credential_id']) + @playbook_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, data['network_credential_id']) if data['network_credential_id'] + @playbook_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, data['cloud_credential_id']) if data['cloud_credential_id'] + @playbook_details[:verbosity] = data['verbosity'] + @playbook_details[:hosts] = data['hosts'] + @playbook_details + end + def get_class_node_info(id) @sb[:active_tab] = "instances" if !@in_a_form && !params[:button] && !params[:pressed] begin diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 429920fd9a3..dfe61a0949e 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -137,7 +137,7 @@ %label.col-md-3.control-label = _('Verbosity') .col-md-9 - %select{"ng-model" => "vm.#{ng_model}.#{prefix}_verbosity", + %select{"ng-model" => "#{ng_model}.#{prefix}_verbosity", "name" => "#{prefix}_verbosity", 'ng-options' => 'v as k for (v, k) in vm.verbosity_types', "checkchange" => "", diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index d40a4da8c2a..9b89d277754 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -50,6 +50,38 @@ :read_only => true} - elsif @ae_method.location == 'expression' = @expression + - elsif @ae_method.location == 'playbook' + .form-horizontal.static + .form-group + %label.col-md-2.control-label + = _('Repository') + .col-md-8 + = h(@playbook_details[:repository]) + .form-group + %label.col-md-2.control-label + = _('Playbook') + .col-md-8 + = h(@playbook_details[:playbook]) + .form-group + %label.col-md-2.control-label + = _('Machine Credential') + .col-md-8 + = h(@playbook_details[:machine_credential]) + .form-group + %label.col-md-2.control-label + = _('Cloud Credential') + .col-md-8 + = h(@playbook_details[:cloud_credential]) + .form-group + %label.col-md-2.control-label + = _('Hosts') + .col-md-8 + = h(@playbook_details[:hosts]) + .form-group + %label.col-md-2.control-label + = _('Verbosity') + .col-md-8 + = h(verbosity_display(@playbook_details[:verbosity])) - else = @ae_method.data -# show inputs parameters grid if there are any inputs From 3f39230254971b960adfbfd32490c5578b9be738 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 6 Sep 2017 09:30:48 -0400 Subject: [PATCH 04/19] Addressed rubocop comments https://www.pivotaltracker.com/story/show/149747321 --- app/controllers/application_controller.rb | 8 ++-- app/controllers/miq_ae_class_controller.rb | 48 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6905bab6f42..60f8c8ed84e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1797,10 +1797,10 @@ def build_created_audit(rec, eh) def build_saved_audit_hash(old_record_attributes, new_record, add) name = new_record.respond_to?(:name) ? new_record.name : new_record.description msg = if add - _("[%{name}] Record added (") % {:name => name} - else - _("[%{name}] Record updated (") % {:name => name} - end + _("[%{name}] Record added (") % {:name => name} + else + _("[%{name}] Record updated (") % {:name => name} + end event = "#{new_record.class.to_s.downcase}_record_#{add ? "add" : "update"}" attribute_difference = new_record.attributes.to_a - old_record_attributes.to_a diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 046efd9f315..06dd0cde569 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -908,8 +908,8 @@ def form_method_field_changed @current_region = MiqRegion.my_region.region page.replace_html(@refresh_div, :partial => 'angular_method_form') page << javascript_hide("form_buttons_div") - else - page.replace_html(@refresh_div, :partial => @refresh_partial) if @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) + elsif @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) + page.replace_html(@refresh_div, :partial => @refresh_partial) end if params[:cls_field_datatype] @@ -977,23 +977,23 @@ def method_form_fields method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) data = method.data ? JSON.parse(method.data) : {} method_hash = { - :name => method.name, - :display_name => method.display_name, - :namespace_path => @sb[:namespace_path], - :class_id => method.id ? method.class_id : MiqAeClass.find(from_cid(x_node.split("-").last)).id, - :location => 'playbook', - :language => 'ruby', - :scope => "instance", + :name => method.name, + :display_name => method.display_name, + :namespace_path => @sb[:namespace_path], + :class_id => method.id ? method.class_id : MiqAeClass.find(from_cid(x_node.split("-").last)).id, + :location => 'playbook', + :language => 'ruby', + :scope => "instance", :available_datatypes => MiqAeField.available_datatypes_for_ui, - :config_info => { - :repository_id => data['repository_id'] || '', - :playbook_id => data['playbook_id'] || '', - :credential_id => data['credential_id'] || '', + :config_info => { + :repository_id => data['repository_id'] || '', + :playbook_id => data['playbook_id'] || '', + :credential_id => data['credential_id'] || '', :network_credential_id => data['network_credential_id'] || '', - :cloud_credential_id => data['cloud_credential_id'] || '', - :hosts => data['hosts'], - :verbosity => data['verbosity'], - :extra_vars => method.inputs + :cloud_credential_id => data['cloud_credential_id'] || '', + :hosts => data['hosts'], + :verbosity => data['verbosity'], + :extra_vars => method.inputs } } render :json => method_hash @@ -1148,7 +1148,7 @@ def add_update_method add_flash(_("Add of %{model} was cancelled by the user") % {:model => ui_lookup(:model => "MiqAeMethod")}) end replace_right_cell - when "add","save" + when "add", "save" method = params[:id] != "new" ? find_record_with_rbac(MiqAeMethod, params[:id]) : MiqAeMethod.new method.name = params["name"] method.display_name = params["display_name"] @@ -1159,7 +1159,7 @@ def add_update_method method.data = set_playbook_data.to_json begin MiqAeMethod.transaction do - to_save, to_delete = set_playbook_inputs(method) + to_save, to_delete = playbook_inputs(method) method.inputs.destroy(MiqAeField.where(:id => to_delete)) method.inputs = to_save method.save! @@ -1177,7 +1177,7 @@ def add_update_method end end - def set_playbook_inputs(method) + def playbook_inputs(method) existing_inputs = method.inputs new_inputs = params[:extra_vars] inputs_to_save = [] @@ -1191,7 +1191,7 @@ def set_playbook_inputs(method) inputs_to_save.push(field) end existing_inputs.each do |existing_input| - inputs_to_delete.push(existing_input.id) unless inputs_to_save.any? {|i| i.id == existing_input.id } + inputs_to_delete.push(existing_input.id) unless inputs_to_save.any? { |i| i.id == existing_input.id } end return inputs_to_save, inputs_to_delete end @@ -1199,10 +1199,10 @@ def set_playbook_inputs(method) def set_playbook_data data = { :repository_id => params['repository_id'], - :playbook_id => params['playbook_id'], + :playbook_id => params['playbook_id'], :credential_id => params['credential_id'], - :hosts => params['hosts'], - :verbosity => params['verbosity'], + :hosts => params['hosts'], + :verbosity => params['verbosity'], } data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] From 52b70b1e5ebe36d0d174b733a7b974a12f909e06 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Thu, 7 Sep 2017 15:50:54 -0400 Subject: [PATCH 05/19] Made some minor changes to new ipnut parameter table styling Fixed minor bug found during testing with validation of input parameter name. https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 10 +++++---- .../_ansible_form_options_angular.html.haml | 21 +++++++------------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index a8485836588..ea2cab4e81b 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -322,7 +322,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a }) vm.addKeyValue = function() { - var valid = validate_input_name(vm.aeMethodModel.provisioning_key); + var valid = validate_input_name(vm.aeMethodModel.provisioning_key, 0); if (!valid) return miqService.miqFlash("error", __("Inputs name must be unique")); else { @@ -363,7 +363,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a } vm.saveKeyValue = function(type, index) { - var valid = validate_input_name(vm.aeMethodModel.key); + var valid = validate_input_name(vm.aeMethodModel.key, index); if (!valid) return miqService.miqFlash("error", __("Input Name must be unique")); vm.aeMethodModel.provisioning_editMode = false; @@ -373,11 +373,13 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.key_type; } - var validate_input_name = function(input_name){ + var validate_input_name = function(input_name, index){ var valid = true; vm.aeMethodModel.provisioning_inputs.forEach( function (input) { - if (input[0] === input_name) + // validate input name if input name is changed for current input parameter + // or when new one is being added + if (input_name !== vm.aeMethodModel.provisioning_inputs[index][0] && input[0] === input_name) valid = false; }); return valid; diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index dfe61a0949e..4beccf7cc10 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -267,15 +267,15 @@ %label = _("Input Parameters") .col-md-6 - %table.table + %table.table.table-bordered.table-striped %tr %td %input{:type => "text", 'ng-model' => "#{ng_model}.#{prefix}_key", :name => "#{prefix}_key", - "placeholder" => "Variable", + "placeholder" => "Input Name", "checkchange" => ""} - %span.help-block{"ng-show" => "(#{ng_model}.#{prefix}_key === '' && #{ng_model}.#{prefix}_value !== '')"} + %span.help-block{"ng-show" => "#{ng_model}.#{prefix}_key === ''"} = _("Required") %td %input{:type => "text", @@ -289,21 +289,18 @@ 'ng-if' => "#{ng_model}.#{prefix}_type == 'password'", 'ng-model' => "#{ng_model}.#{prefix}_value", "placeholder" => placeholder_if_present("#{ng_model}.#{prefix}_value"), - "ng-change" => "", - "miqrequired" => ""} - %span.help-block{"ng-show" => "(#{ng_model}.#{prefix}_key !== '' && #{ng_model}.#{prefix}_value === '')"} - = _("Required") + "ng-change" => ""} %td %select{"ng-model" => "#{ng_model}.#{prefix}_type", "name" => "#{prefix}_type", 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", 'ng-change' => '', "pf-select" => true} - %td + %td{"ng-if" => "#{ng_model}.#{prefix}_key != ''"} %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.addKeyValue('#{prefix}')", - "ng-if" => "(#{ng_model}.#{prefix}_key != '' && #{ng_model}.#{prefix}_value != '')"} + "ng-if" => "#{ng_model}.#{prefix}_key != ''"} %span{:class => "fa fa-plus tag-add"} #inputs_div @@ -337,15 +334,13 @@ :name => "key_value", 'ng-if' => "#{ng_model}.key_type != 'password'", 'ng-model' => "#{ng_model}.key_value", - "ng-change" => "", - "miqrequired" => ""} + "ng-change" => ""} %input.form-control{"type" => "password", :name => "key_value", 'ng-if' => "#{ng_model}.key_type == 'password'", 'ng-model' => "#{ng_model}.key_value", "placeholder" => placeholder_if_present("#{ng_model}.key_value"), - "ng-change" => "", - "miqrequired" => ""} + "ng-change" => ""} %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} {{arr[2]}} %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} From 3b188939c00d1ff945f6ae5fe3361970264cb5a4 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Sun, 10 Sep 2017 12:23:23 -0400 Subject: [PATCH 06/19] Addressed some of the code climate warnings. Added 'playbookReusableCodeMixin' for playbook related common methods. https://www.pivotaltracker.com/story/show/149747321 --- .../catalog/catalog_item_form_controller.js | 243 ++----------- .../miq_ae_class/ae_method_form_controller.js | 332 +++++------------- .../playbook-reusable-code-mixin.js | 199 +++++++++++ app/controllers/application_controller.rb | 2 +- app/controllers/host_controller.rb | 29 -- app/controllers/miq_ae_class_controller.rb | 3 +- app/controllers/ops_controller/ops_rbac.rb | 2 +- .../ops_controller/settings/schedules.rb | 31 +- .../_ansible_form_options_angular.html.haml | 10 +- .../_angular_method_form.html.haml | 2 +- 10 files changed, 337 insertions(+), 516 deletions(-) create mode 100644 app/assets/javascripts/controllers/playbook-reusable-code-mixin.js diff --git a/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js b/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js index e740dacfe6d..e4b926b1d82 100644 --- a/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js +++ b/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js @@ -1,6 +1,5 @@ -ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalogItemFormId', 'currentRegion', 'miqService', 'postService', 'API', 'catalogItemDataFactory', function($scope, catalogItemFormId, currentRegion, miqService, postService, API, catalogItemDataFactory) { +ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalogItemFormId', 'currentRegion', 'miqService', 'postService', 'catalogItemDataFactory', 'playbookReusableCodeMixin', function($scope, catalogItemFormId, currentRegion, miqService, postService, catalogItemDataFactory, playbookReusableCodeMixin) { var vm = this; - var sort_options = '&sort_by=name&sort_order=ascending'; var init = function() { vm.catalogItemModel = { name: '', @@ -40,21 +39,21 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog retirement_become_enabled: false, retirement_verbosity: '0', }; - getVerbosityTypes(); - getRemoveResourcesTypes(); + vm.model = 'catalogItemModel'; + vm.verbosity_types = playbookReusableCodeMixin.getVerbosityTypes(); + playbookReusableCodeMixin.getRemoveResourcesTypes(vm); vm.provisioning_cloud_type = ''; vm.retirement_cloud_type = ''; vm.currentRegion = currentRegion; vm.formId = catalogItemFormId; vm.afterGet = false; - vm.model = 'catalogItemModel'; ManageIQ.angular.scope = $scope; if (catalogItemFormId === 'new') { $scope.newRecord = true; - vm.formOptions(); - vm.formCloudCredentials(null, null); + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.formCloudCredentials(vm, null, null); vm.afterGet = true; vm.modelCopy = angular.copy(vm.catalogItemModel); } else { @@ -66,8 +65,8 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog vm.catalogItemModel.display = catalogItemData.display; vm.catalogItemModel.catalog_id = catalogItemData.service_template_catalog_id; vm.catalogItemModel.provisioning_dialog_id = catalogItemData.provisioning_dialog_id; - vm.formOptions(); - vm.formCloudCredentials(catalogItemData.config_info.provision.cloud_credential_id, catalogItemData.config_info.retirement.cloud_credential_id); + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.formCloudCredentials(vm, catalogItemData.config_info.provision.cloud_credential_id, catalogItemData.config_info.retirement.cloud_credential_id); getConfigInfo(catalogItemData.config_info); vm.afterGet = true; vm.modelCopy = angular.copy(vm.catalogItemModel); @@ -75,56 +74,12 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog } }; - var getVerbosityTypes = function() { - vm['verbosity_types'] = { - '0': '0 (Normal)', - '1': '1 (Verbose)', - '2': '2 (More Verbose)', - '3': '3 (Debug)', - '4': '4 (Connection Debug)', - '5': '5 (WinRM Debug)', - }; - }; - - var getRemoveResourcesTypes = function() { - if (vm.catalogItemModel.retirement_repository_id === undefined || vm.catalogItemModel.retirement_repository_id === '') { - vm.catalogItemModel.retirement_remove_resources = 'yes_without_playbook'; - vm['remove_resources_types'] = { - 'No': 'no_without_playbook', - 'Yes': 'yes_without_playbook', - }; - } else { - vm.catalogItemModel.retirement_remove_resources = 'no_with_playbook'; - vm['remove_resources_types'] = { - 'No': 'no_with_playbook', - 'Before Playbook runs': 'pre_with_playbook', - 'After Playbook runs': 'post_with_playbook', - }; - } - }; - - var getCredentialType = function(prefix, credentialId) { - var url = '/api/authentications/' + credentialId; - API.get(url).then(function(data) { - vm[prefix + '_cloud_type'] = data.type; - - if (vm.cloud_types[vm[prefix + '_cloud_type']] !== 'undefined') { - vm['_' + prefix + '_cloud_type'] = data.type; - getCloudCredentialsforType(prefix, data.type); - } - }); - }; - - var setIfDefined = function(value) { - return (typeof value !== 'undefined') ? value : ''; - }; - var getConfigInfo = function(configData) { vm.catalogItemModel.provisioning_repository_id = configData.provision.repository_id; vm.catalogItemModel.provisioning_playbook_id = configData.provision.playbook_id; vm.catalogItemModel.provisioning_machine_credential_id = configData.provision.credential_id; vm.catalogItemModel.provisioning_network_credential_id = configData.provision.network_credential_id; - vm.catalogItemModel.provisioning_cloud_credential_id = setIfDefined(configData.provision.cloud_credential_id); + vm.catalogItemModel.provisioning_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.provision.cloud_credential_id); vm.catalogItemModel.provisioning_execution_ttl = configData.provision.execution_ttl; vm.catalogItemModel.provisioning_inventory = configData.provision.hosts; vm.catalogItemModel.provisioning_dialog_existing = configData.provision.dialog_id ? 'existing' : 'create'; @@ -149,7 +104,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog if (typeof configData.retirement.repository_id !== 'undefined') { vm.catalogItemModel.retirement_repository_id = configData.retirement.repository_id; vm.catalogItemModel.retirement_playbook_id = configData.retirement.playbook_id; - getRemoveResourcesTypes(); + playbookReusableCodeMixin.getRemoveResourcesTypes(vm); vm.catalogItemModel.retirement_remove_resources = configData.retirement.remove_resources; vm.catalogItemModel.retirement_machine_credential_id = configData.retirement.credential_id; } @@ -166,7 +121,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog } vm.catalogItemModel.retirement_network_credential_id = configData.retirement.network_credential_id; - vm.catalogItemModel.retirement_cloud_credential_id = setIfDefined(configData.retirement.cloud_credential_id); + vm.catalogItemModel.retirement_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.retirement.cloud_credential_id); vm.catalogItemModel.retirement_execution_ttl = configData.retirement.execution_ttl; vm.catalogItemModel.retirement_inventory = configData.retirement.hosts; vm.catalogItemModel.retirement_key = ''; @@ -181,7 +136,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog vm.catalogItemModel[variableName][key] = extraVars[key]['default']; } } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }; var redirectUrl = '/catalog/explorer/' + catalogItemFormId; @@ -199,8 +154,8 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog $scope.resetClicked = function() { vm.catalogItemModel = angular.copy(vm.modelCopy); - vm.formOptions(); - cloudCredentialsList(vm.catalogItemModel.provisioning_cloud_credential_id, vm.catalogItemModel.retirement_cloud_credential_id); + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.cloudCredentialsList(vm, vm.catalogItemModel.provisioning_cloud_credential_id, vm.catalogItemModel.retirement_cloud_credential_id); $scope.angularForm.$setUntouched(true); $scope.angularForm.$setPristine(true); miqService.miqFlash('warn', __('All changes have been reset')); @@ -296,101 +251,6 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog return catalog_item; }; - - // list of service catalogs - vm.formOptions = function() { - API.get('/api/service_catalogs/?expand=resources&attributes=id,name' + sort_options).then(function(data) { - vm.catalogs = data.resources; - vm._catalog = _.find(vm.catalogs, {id: vm.catalogItemModel.catalog_id}); - }); - - // list of service dialogs - API.get('/api/service_dialogs/?expand=resources&attributes=id,label&sort_by=label&sort_order=ascending').then(function(data) { - vm.dialogs = data.resources; - vm._provisioning_dialog = _.find(vm.dialogs, {id: vm.catalogItemModel.provisioning_dialog_id}); - }); - - // list of repositories - API.get('/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=' + vm.currentRegion + sort_options).then(function(data) { - vm.repositories = data.resources; - vm._retirement_repository = _.find(vm.repositories, {id: vm.catalogItemModel.retirement_repository_id}); - vm._provisioning_repository = _.find(vm.repositories, {id: vm.catalogItemModel.provisioning_repository_id}); - }); - - // list of machine credentials - API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name' + sort_options).then(function(data) { - vm.machine_credentials = data.resources; - vm._retirement_machine_credential = _.find(vm.machine_credentials, {id: vm.catalogItemModel.retirement_machine_credential_id}); - vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm.catalogItemModel.provisioning_machine_credential_id}); - }); - - // list of network credentials - API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name' + sort_options).then(function(data) { - vm.network_credentials = data.resources; - vm._retirement_network_credential = _.find(vm.network_credentials, {id: vm.catalogItemModel.retirement_network_credential_id}); - vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm.catalogItemModel.provisioning_network_credential_id}); - }); - }; - - // list of cloud credentials - vm.formCloudCredentials = function(provisionCredentialId, retirementCredentialId) { - API.options('/api/authentications').then(function(data) { - var cloud_types = {}; - angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(cred_object, cred_type) { - if (cred_object.type === 'cloud') { - cloud_types[cred_type] = cred_object.label; - } - }); - vm.cloud_types = getSortedHash(cloud_types); - cloudCredentialsList(provisionCredentialId, retirementCredentialId); - }); - }; - - var cloudCredentialsList = function(provisionCredentialId, retirementCredentialId) { - if (provisionCredentialId) { - getCredentialType('provisioning', provisionCredentialId); - } else { - vm._provisioning_cloud_type = ''; - vm._provisioning_cloud_credential_id = ''; - } - if (retirementCredentialId) { - getCredentialType('retirement', retirementCredentialId); - } else { - vm._retirement_cloud_type = ''; - vm._retirement_cloud_credential_id = ''; - } - }; - - var getSortedHash = function(inputHash) { - var sortedHash = Object.keys(inputHash) - .map(function(key) { - return ({'k': key, 'v': inputHash[key]}); - }) - .sort(function(a, b) { - return a.v.localeCompare(b.v); - }) - .reduce(function(o, e) { - o[e.k] = e.v; - return o; - }, {}); - return sortedHash; - }; - - // get playbooks for selected repository - vm.repositoryChanged = function(prefix, id) { - API.get('/api/configuration_script_sources/' + id + '/configuration_script_payloads?expand=resources&filter[]=region_number=' + vm.currentRegion + sort_options).then(function(data) { - vm[prefix + '_playbooks'] = data.resources; - // if repository has changed - if (id !== vm.catalogItemModel[prefix + '_repository_id']) { - vm.catalogItemModel[prefix + '_playbook_id'] = ''; - vm.catalogItemModel[prefix + '_repository_id'] = id; - getRemoveResourcesTypes(); - } else { - findObjectForDropDown(prefix, '_playbook', '_playbooks'); - } - }); - }; - // reset fields when retirement playbook type is changed $scope.$watch('vm._retirement_playbook', function(value) { if (value && (vm.catalogItemModel.retirement_inventory === undefined || vm.catalogItemModel.retirement_inventory === '')) { @@ -401,68 +261,31 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog $scope.$watch('vm._provisioning_repository', function(value) { if (value) { - vm.repositoryChanged('provisioning', value.id); + playbookReusableCodeMixin.repositoryChanged(vm, 'provisioning', value.id); } else { vm.catalogItemModel['provisioning_repository_id'] = ''; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); $scope.$watch('vm._retirement_repository', function(value) { if (value) { - vm.repositoryChanged('retirement', value.id); + vm.repositoryChanged(vm, 'retirement', value.id); } else { vm.catalogItemModel['retirement_playbook_id'] = ''; vm.catalogItemModel['retirement_repository_id'] = ''; - getRemoveResourcesTypes(); + playbookReusableCodeMixin.getRemoveResourcesTypes(vm); } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); - $scope.checkFormPristine = function() { - if (angular.equals(vm.catalogItemModel, vm.modelCopy)) { - $scope.angularForm.$setPristine(); - } else { - $scope.angularForm.$setDirty(); - } - }; - - $scope.cloudTypeChanged = function(prefix, value) { - var valueChanged = (value !== vm[prefix + '_cloud_type']); - if (value) { - vm[prefix + '_cloud_type'] = value; - } else { - vm[prefix + '_cloud_type'] = ''; - } - if (valueChanged) { - var typ = vm[prefix + '_cloud_type']; - vm.catalogItemModel[prefix + '_cloud_credential_id'] = ''; - getCloudCredentialsforType(prefix, typ); - } - $scope.checkFormPristine(); - }; - - var getCloudCredentialsforType = function(prefix, typ) { - // list of cloud credentials based upon selected cloud type - var url = '/api/authentications?collection_class=' + typ + '&expand=resources&attributes=id,name' + sort_options; - API.get(url).then(function(data) { - vm[prefix + '_cloud_credentials'] = data.resources; - findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials'); - }); - }; - - var findObjectForDropDown = function(prefix, fieldName, listName) { - vm['_' + prefix + fieldName] = _.find(vm[prefix + listName], {id: vm.catalogItemModel[prefix + fieldName + '_id']}); - $scope.checkFormPristine(); - }; - $scope.$watch('vm._retirement_playbook', function(value) { if (value) { vm.catalogItemModel['retirement_playbook_id'] = value.id; } else { vm.catalogItemModel['retirement_playbook_id'] = ''; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); $scope.$watch('vm.catalogItemModel.display', function(value) { @@ -471,11 +294,13 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog }); $scope.$watch('vm._provisioning_cloud_type', function(value) { - $scope.cloudTypeChanged('provisioning', value); + playbookReusableCodeMixin.cloudTypeChanged(vm, 'provisioning', value); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); $scope.$watch('vm._retirement_cloud_type', function(value) { - $scope.cloudTypeChanged('retirement', value); + $scope.cloudTypeChanged(vm, 'retirement', value); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); vm.addKeyValue = function(prefix) { @@ -501,7 +326,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog vm.removeKeyValue = function(prefix, key) { delete vm.catalogItemModel[prefix + '_variables'][key]; - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }; vm.editKeyValue = function(prefix, key, key_value, index) { @@ -550,12 +375,12 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog 'catalog provisioning_playbook retirement_playbook provisioning_machine_credential retirement_machine_credential provisioning_network_credential retirement_network_credential provisioning_cloud_credential retirement_cloud_credential provisioning_dialog'.split(' ').forEach(idWatch); function idWatch(name) { - var field_name = 'vm._' + name; - $scope.$watch(field_name, function(value) { + var fieldName = 'vm._' + name; + $scope.$watch(fieldName, function(value) { if (value) { vm.catalogItemModel[name + '_id'] = value.id; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); } @@ -563,12 +388,12 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog 'retirement_remove_resources'.split(' ').forEach(typeWatch); function typeWatch(name) { - var field_name = 'vm.catalogItemModel.' + name; - $scope.$watch(field_name, function(value) { + var fieldName = 'vm.catalogItemModel.' + name; + $scope.$watch(fieldName, function(value) { if (value) { vm.catalogItemModel[name] = value; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }); } @@ -578,7 +403,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog $scope.copyProvisioning = function() { closeConfirmationModal(); - vm.formOptions(); + playbookReusableCodeMixin.formOptions(vm); vm.catalogItemModel.retirement_repository_id = vm.catalogItemModel.provisioning_repository_id; vm.catalogItemModel.retirement_playbook_id = vm.catalogItemModel.provisioning_playbook_id; vm.catalogItemModel.retirement_machine_credential_id = vm.catalogItemModel.provisioning_machine_credential_id; @@ -593,8 +418,8 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog vm.catalogItemModel.retirement_key = ''; vm.catalogItemModel.retirement_value = ''; vm.catalogItemModel.retirement_variables = angular.copy(vm.catalogItemModel.provisioning_variables); - getRemoveResourcesTypes(); - $scope.checkFormPristine(); + playbookReusableCodeMixin.getRemoveResourcesTypes(vm); + playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm); }; var closeConfirmationModal = function() { diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index ea2cab4e81b..a33a8f769dc 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -1,15 +1,14 @@ -ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'aeMethodFormId', 'currentRegion', 'miqService', 'postService', 'API', function($http, $scope, aeMethodFormId, currentRegion, miqService, postService, API) { +ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'aeMethodFormId', 'currentRegion', 'miqService', 'playbookReusableCodeMixin', function($http, $scope, aeMethodFormId, currentRegion, miqService, playbookReusableCodeMixin) { var vm = this; - var sort_options = "&sort_by=name&sort_order=ascending" var init = function() { vm.aeMethodModel = { name: '', display_name: '', location: '', namespace_path: '', - class_id:'', - language:'', - scope:'', + class_id: '', + language: '', + scope: '', key: '', key_value: '', key_type: 'string', @@ -27,7 +26,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a provisioning_verbosity: '0', provisioning_editMode: false, }; - getVerbosityTypes(); + vm.verbosity_types = playbookReusableCodeMixin.getVerbosityTypes(); vm.provisioning_cloud_type = ''; vm.currentRegion = currentRegion; vm.formId = aeMethodFormId; @@ -39,22 +38,16 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a $http.get('method_form_fields/' + aeMethodFormId) .then(getMethodFormData) .catch(miqService.handleFailure); - - if (aeMethodFormId == 'new') { - $scope.newRecord = true; - vm.formOptions(); - vm.formCloudCredentials(null, null); - } else { - vm.newRecord = false; - $scope.newRecord = false; + vm.saveable = miqService.saveable; + vm.newRecord = aeMethodFormId === 'new'; + if (aeMethodFormId === 'new') { + playbookReusableCodeMixin.formOptions(vm); } vm.afterGet = true; - }; function getMethodFormData(response) { var data = response.data; - vm.aeMethodModel.name = data.name; vm.aeMethodModel.display_name = data.display_name; vm.aeMethodModel.namespace_path = data.namespace_path; @@ -63,73 +56,45 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.language = data.language; vm.aeMethodModel.scope = data.scope; vm.aeMethodModel.available_datatypes = data.available_datatypes; - vm.formOptions(); - vm.formCloudCredentials(data.cloud_credential_id); - getConfigInfo(data['config_info']); + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.formCloudCredentials(vm, data.config_info.cloud_credential_id, null); + getConfigInfo(data.config_info); vm.modelCopy = angular.copy(vm.aeMethodModel); } - var getVerbosityTypes = function() { - vm['verbosity_types'] = { - "0": "0 (Normal)", - "1": "1 (Verbose)", - "2": "2 (More Verbose)", - "3": "3 (Debug)", - "4": "4 (Connection Debug)", - "5": "5 (WinRM Debug)" - }; - } - - var getCredentialType = function (credentialId) { - var url = '/api/authentications/' + credentialId; - API.get(url).then(function (data) { - vm.provisioning_cloud_type = data.type; - - if (vm.cloud_types[vm.provisioning_cloud_type] !== 'undefined') { - vm['_provisioning_cloud_type'] = data.type; - getCloudCredentialsforType(data.type); - } - }) - }; - - var setIfDefined = function(value) { - return (typeof value !== 'undefined') ? value : ''; - }; - - var getConfigInfo = function (configData) { - vm.aeMethodModel.provisioning_repository_id = configData['repository_id']; - vm.aeMethodModel.provisioning_playbook_id = configData['playbook_id']; - vm.aeMethodModel.provisioning_machine_credential_id = configData['credential_id']; - vm.aeMethodModel.provisioning_network_credential_id = configData['network_credential_id']; - vm.aeMethodModel.provisioning_cloud_credential_id = setIfDefined(configData['cloud_credential_id']); - vm.aeMethodModel.provisioning_inventory = configData['hosts'] ? configData['hosts'] : 'localhost'; + var getConfigInfo = function(configData) { + vm.aeMethodModel.provisioning_repository_id = configData.repository_id; + vm.aeMethodModel.provisioning_playbook_id = configData.playbook_id; + vm.aeMethodModel.provisioning_machine_credential_id = configData.credential_id; + vm.aeMethodModel.provisioning_network_credential_id = configData.network_credential_id; + vm.aeMethodModel.provisioning_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.cloud_credential_id); + vm.aeMethodModel.provisioning_inventory = configData.hosts ? configData.hosts : 'localhost'; vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; - if (configData['verbosity'] === undefined || configData['verbosity'] == '') { + if (configData.verbosity === undefined || configData.verbosity === '') { vm.aeMethodModel.provisioning_verbosity = '0'; } else { - vm.aeMethodModel.provisioning_verbosity = configData['verbosity']; + vm.aeMethodModel.provisioning_verbosity = configData.verbosity; } - setExtraVars('provisioning_inputs', configData['extra_vars']); + setExtraVars('provisioning_inputs', configData.extra_vars); }; - var setExtraVars = function (variableName, extraVars) { - if (typeof extraVars !== 'undefined') { + var setExtraVars = function(variableName, extraVars) { + if (extraVars !== 'undefined') { vm.aeMethodModel[variableName] = []; - extraVars.forEach( function (arrayItem) - { - var input_vars = [arrayItem.name, arrayItem.default_value, arrayItem.datatype, arrayItem.id]; - vm.aeMethodModel[variableName].push(input_vars); + extraVars.forEach(function(arrayItem) { + var inputVars = [arrayItem.name, arrayItem.default_value, arrayItem.datatype, arrayItem.id]; + vm.aeMethodModel[variableName].push(inputVars); }); } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); }; - $scope.resetClicked = function() { + vm.resetClicked = function() { vm.aeMethodModel = angular.copy(vm.modelCopy); - vm.formOptions(); - cloudCredentialsList(vm.aeMethodModel.cloud_credential_id); + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.cloudCredentialsList(vm, vm.aeMethodModel.provisioning_cloud_credential_id); $scope.angularForm.$setUntouched(true); $scope.angularForm.$setPristine(true); miqService.miqFlash("warn", __("All changes have been reset")); @@ -138,267 +103,156 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a var methodEditButtonClicked = function(buttonName) { miqService.sparkleOn(); var url = '/miq_ae_class/add_update_method/' + aeMethodFormId + '?button=' + buttonName; - miqService.miqAjaxButton(url, setConfigInfo(vm.aeMethodModel)) + miqService.miqAjaxButton(url, setConfigInfo(vm.aeMethodModel, vm.modelCopy)); }; - $scope.cancelClicked = function() { + vm.cancelClicked = function() { methodEditButtonClicked('cancel'); $scope.angularForm.$setPristine(true); }; - $scope.saveClicked = function() { + vm.saveClicked = function() { methodEditButtonClicked('save'); $scope.angularForm.$setPristine(true); }; - $scope.addClicked = function() { + vm.addClicked = function() { methodEditButtonClicked('add'); $scope.angularForm.$setPristine(true); }; var setConfigInfo = function(configData) { - method = { - name: configData["name"], - display_name: configData["display_name"], - class_id: configData["class_id"], - language: configData["language"], - scope: configData["scope"], + var method = { + name: configData.name, + display_name: configData.display_name, + class_id: configData.class_id, + language: configData.language, + scope: configData.scope, location: "playbook", - repository_id: configData["provisioning_repository_id"], - playbook_id: configData["provisioning_playbook_id"], - credential_id: configData["provisioning_machine_credential_id"], - hosts: configData["provisioning_inventory"], - verbosity: configData["provisioning_verbosity"], - extra_vars: configData["provisioning_inputs"] + repository_id: configData.provisioning_repository_id, + playbook_id: configData.provisioning_playbook_id, + credential_id: configData.provisioning_machine_credential_id, + hosts: configData.provisioning_inventory, + verbosity: configData.provisioning_verbosity, + extra_vars: configData.provisioning_inputs, + }; + if (configData.provisioning_network_credential_id !== '') { + method.network_credential_id = configData.provisioning_network_credential_id; } - if (configData["provisioning_network_credential_id"] !== '') - method['network_credential_id'] = configData["provisioning_network_credential_id"]; - - if (configData["provisioning_cloud_credential_id"] !== '') - method['cloud_credential_id'] = configData["provisioning_cloud_credential_id"]; - return method; - } - - // list of service catalogs - vm.formOptions = function() { - // list of repositories - API.get("/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=" + vm.currentRegion + sort_options).then(function(data) { - vm.repositories = data.resources; - vm._provisioning_repository = _.find(vm.repositories, {id: vm.aeMethodModel.provisioning_repository_id}); - }) - - // list of machine credentials - API.get("/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name" + sort_options).then(function(data) { - vm.machine_credentials = data.resources; - vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm.aeMethodModel.provisioning_machine_credential_id}); - }) - - // list of network credentials - API.get("/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name" + sort_options).then(function(data) { - vm.network_credentials = data.resources; - vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm.aeMethodModel.provisioning_network_credential_id}); - }) - }; - - // list of cloud credentials - vm.formCloudCredentials = function(provisionCredentialId) { - API.options('/api/authentications').then(function(data) { - var cloud_types = {}; - angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(cred_object, cred_type) { - if (cred_object.type == 'cloud') - cloud_types[cred_type] = cred_object.label; - }); - vm.cloud_types = getSortedHash(cloud_types); - cloudCredentialsList(provisionCredentialId); - }); - }; - - var cloudCredentialsList = function(provisionCredentialId) { - if (provisionCredentialId) { - getCredentialType('provisioning', provisionCredentialId); - } else { - vm._provisioning_cloud_type = ''; - vm._provisioning_cloud_credential_id = ''; + if (configData.provisioning_cloud_credential_id !== '') { + method.cloud_credential_id = configData.provisioning_cloud_credential_id; } - }; - - var getSortedHash = function(inputHash) { - var sortedHash = Object.keys(inputHash) - .map(function(key) { - return ({"k": key, "v": inputHash[key]}) - }) - .sort(function(a, b) { - return a.v.localeCompare(b.v) - }) - .reduce(function(o, e) { - o[e.k] = e.v; - return o; - }, {}); - return sortedHash; - }; - - // get playbooks for selected repository - vm.repositoryChanged = function(id) { - API.get("/api/configuration_script_sources/" + id + "/configuration_script_payloads?expand=resources&filter[]=region_number=" + vm.currentRegion + sort_options).then(function (data) { - vm.provisioning_playbooks = data.resources; - // if repository has changed - if (id !== vm.aeMethodModel.provisioning_repository_id) { - vm.aeMethodModel.provisioning_playbook_id = ''; - vm.aeMethodModel.provisioning_repository_id = id; - getRemoveResourcesTypes(); - } else { - findObjectForDropDown('_playbook', '_playbooks'); - } - }) + return method; }; $scope.$watch('vm._provisioning_repository', function(value) { if (value) { - vm.repositoryChanged(value.id) + playbookReusableCodeMixin.repositoryChanged(vm, 'provisioning', value.id); } else { - vm.aeMethodModel['provisioning_repository_id'] = ''; + vm.aeMethodModel.provisioning_repository_id = ''; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); }); $scope.$watch('vm.aeMethodModel.key_type', function(value) { - if (value && vm.aeMethodModel.key_type == vm.aeMethodModel.original_key_type) { + if (value && vm.aeMethodModel.key_type === vm.aeMethodModel.original_key_type) { vm.aeMethodModel.key_value = ''; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); }); $scope.$watch('vm.aeMethodModel.provisioning_type', function(value) { if (value) { vm.aeMethodModel.provisioning_value = ''; } - $scope.checkFormPristine(); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); }); - $scope.checkFormPristine = function() { - if (angular.equals(vm.aeMethodModel, vm.modelCopy)) { - $scope.angularForm.$setPristine(); - } else { - $scope.angularForm.$setDirty(); - } - }; - - $scope.cloudTypeChanged = function(value) { - var valueChanged = (value !== vm.provisioning_cloud_type); - if (value) { - vm.provisioning_cloud_type = value; - } else { - vm.provisioning_cloud_type = ''; - } - if (valueChanged) { - var typ = vm.provisioning_cloud_type; - vm.aeMethodModel.provisioning_cloud_credential_id = ''; - getCloudCredentialsforType(typ); - } - $scope.checkFormPristine(); - }; - vm.fieldsRequired = function(prefix) { return prefix === 'provisioning'; }; - var getCloudCredentialsforType = function(typ) { - // list of cloud credentials based upon selected cloud type - var url = '/api/authentications?collection_class=' + typ + '&expand=resources&attributes=id,name' + sort_options; - API.get(url).then(function(data) { - vm.provisioning_cloud_credentials = data.resources; - findObjectForDropDown('provisioning_cloud_credential', '_cloud_credentials'); - }) - }; - - var findObjectForDropDown = function(fieldName, listName) { - vm['_provisioning' + fieldName] = _.find(vm['provisioning' + listName], {id: vm.aeMethodModel['provisioning' + fieldName + '_id']}); - $scope.checkFormPristine(); - }; - $scope.$watch('vm._provisioning_cloud_type', function(value) { - $scope.cloudTypeChanged(value); - }) + playbookReusableCodeMixin.cloudTypeChanged(vm, 'provisioning', value); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }); vm.addKeyValue = function() { - var valid = validate_input_name(vm.aeMethodModel.provisioning_key, 0); - if (!valid) + var valid = validateInputName(vm.aeMethodModel.provisioning_key, 0); + if (! valid) { return miqService.miqFlash("error", __("Inputs name must be unique")); - else { + } else { vm.aeMethodModel.provisioning_inputs.push( [vm.aeMethodModel.provisioning_key, vm.aeMethodModel.provisioning_value, vm.aeMethodModel.provisioning_type]); vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; vm.aeMethodModel.provisioning_type = 'string'; } - } + }; vm.provisioning_repository_selected = function() { return vm.aeMethodModel.provisioning_repository_id !== ''; - } + }; - vm.removeKeyValue = function(type, key, key_value, key_type, index) { + vm.removeKeyValue = function(index) { vm.aeMethodModel.provisioning_inputs.splice(index, 1); - $scope.checkFormPristine(); - } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }; - vm.editKeyValue = function(type, key, key_value, key_type, index) { + vm.editKeyValue = function(key, keyValue, keyType, index) { vm.aeMethodModel.provisioning_editMode = true; vm.aeMethodModel.s_index = index; vm.aeMethodModel.key = key; - vm.aeMethodModel.key_value = key_value; - vm.aeMethodModel.key_type = key_type; + vm.aeMethodModel.key_value = keyValue; + vm.aeMethodModel.key_type = keyType; vm.aeMethodModel.original_key = key; - vm.aeMethodModel.original_key_value = key_value; - vm.aeMethodModel.original_key_type = key_type; - } + vm.aeMethodModel.original_key_value = keyValue; + vm.aeMethodModel.original_key_type = keyType; + }; vm.cancelKeyValue = function(index) { vm.aeMethodModel.provisioning_editMode = false; vm.aeMethodModel.s_index = ''; - vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.original_key + vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.original_key; vm.aeMethodModel.provisioning_inputs[index][1] = vm.aeMethodModel.original_key_value; vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.original_key_type; - } + }; - vm.saveKeyValue = function(type, index) { - var valid = validate_input_name(vm.aeMethodModel.key, index); - if (!valid) + vm.saveKeyValue = function(index) { + var valid = validateInputName(vm.aeMethodModel.key, index); + if (! valid) { return miqService.miqFlash("error", __("Input Name must be unique")); + } vm.aeMethodModel.provisioning_editMode = false; vm.aeMethodModel.s_index = ''; vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.key; vm.aeMethodModel.provisioning_inputs[index][1] = vm.aeMethodModel.key_value; vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.key_type; - } + }; - var validate_input_name = function(input_name, index){ + var validateInputName = function(inputName, index) { var valid = true; - vm.aeMethodModel.provisioning_inputs.forEach( function (input) - { + vm.aeMethodModel.provisioning_inputs.forEach(function(input) { // validate input name if input name is changed for current input parameter // or when new one is being added - if (input_name !== vm.aeMethodModel.provisioning_inputs[index][0] && input[0] === input_name) + if (inputName !== vm.aeMethodModel.provisioning_inputs[index][0] && input[0] === inputName) { valid = false; + } }); return valid; - } - - vm.variablesEmpty = function() { - field = vm.aeMethodModel.provisioning_inputs; - return Object.keys(field).length === 0; }; // watch for all the drop downs on screen - "provisioning_playbook provisioning_machine_credential provisioning_network_credential provisioning_cloud_credential".split(" ").forEach(idWatch) + "provisioning_playbook provisioning_machine_credential provisioning_network_credential provisioning_cloud_credential".split(" ").forEach(idWatch); function idWatch(name) { - field_name = "vm._" + name; - $scope.$watch(field_name, function(value) { - if (value) + var fieldName = "vm._" + name; + $scope.$watch(fieldName, function(value) { + if (value) { vm.aeMethodModel[name + '_id'] = value.id; - $scope.checkFormPristine(); + } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); }); } diff --git a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js new file mode 100644 index 00000000000..6622db06d4a --- /dev/null +++ b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js @@ -0,0 +1,199 @@ +ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', function(API) { + var sortOptions = "&sort_by=name&sort_order=ascending"; + + var getSortedHash = function(inputHash) { + var sortedHash = Object.keys(inputHash) + .map(function(key) { + return ({"k": key, "v": inputHash[key]}); + }) + .sort(function(a, b) { + return a.v.localeCompare(b.v); + }) + .reduce(function(o, e) { + o[e.k] = e.v; + return o; + }, {}); + return sortedHash; + }; + + var getVerbosityTypes = function() { + return { + "0": "0 (Normal)", + "1": "1 (Verbose)", + "2": "2 (More Verbose)", + "3": "3 (Debug)", + "4": "4 (Connection Debug)", + "5": "5 (WinRM Debug)", + }; + }; + + var checkFormPristine = function(model, modelCopy, form) { + if (angular.equals(model, modelCopy)) { + form.$setPristine(); + } else { + form.$setDirty(); + } + }; + + var getCloudCredentialsforType = function(prefix, typ, vm) { + // list of cloud credentials based upon selected cloud type + var url = '/api/authentications?collection_class=' + typ + '&expand=resources&attributes=id,name' + sortOptions; + API.get(url).then(function(data) { + vm[prefix + '_cloud_credentials'] = data.resources; + findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials', vm); + }); + }; + + var findObjectForDropDown = function(prefix, fieldName, listName, vm) { + vm['_' + prefix + fieldName] = _.find(vm[prefix + listName], {id: vm[vm.model][prefix + fieldName + '_id']}); + }; + + var setIfDefined = function(value) { + return (typeof value !== 'undefined') ? value : ''; + }; + + var cloudCredentialsList = function(vm, provisionCredentialId, retirementCredentialId) { + if (provisionCredentialId) { + getCredentialType('provisioning', provisionCredentialId, vm); + } else { + vm._provisioning_cloud_type = ''; + vm._provisioning_cloud_credential_id = ''; + } + if (vm[vm.model].retirement_cloud_credential_id !== undefined) { + if (retirementCredentialId) { + getCredentialType('retirement', retirementCredentialId, vm); + } else { + vm._retirement_cloud_type = ''; + vm._retirement_cloud_credential_id = ''; + } + } + }; + + var getCredentialType = function(prefix, credentialId, vm) { + var url = '/api/authentications/' + credentialId; + API.get(url).then(function(data) { + vm[prefix + '_cloud_type'] = data.type; + if (vm.cloudTypes[vm[prefix + '_cloud_type']] !== 'undefined') { + vm['_' + prefix + '_cloud_type'] = data.type; + getCloudCredentialsforType(prefix, data.type, vm); + } + }); + }; + + // list of service catalogs + var formOptions = function(vm) { + if (vm[vm.model].catalog_id !== undefined) { + API.get('/api/service_catalogs/?expand=resources&attributes=id,name' + sortOptions).then(function(data) { + vm.catalogs = data.resources; + vm._catalog = _.find(vm.catalogs, {id: vm[vm.model].catalog_id}); + }); + } + + // list of service dialogs + if (vm[vm.model].provisioning_dialog_id !== undefined) { + API.get('/api/service_dialogs/?expand=resources&attributes=id,label&sort_by=label&sort_order=ascending').then( + function(data) { + vm.dialogs = data.resources; + vm._provisioning_dialog = _.find(vm.dialogs, {id: vm[vm.model].provisioning_dialog_id}); + }); + } + + // list of repositories + API.get('/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=' + vm.currentRegion + sortOptions).then(function(data) { + vm.repositories = data.resources; + vm._retirement_repository = _.find(vm.repositories, {id: vm[vm.model].retirement_repository_id}); + vm._provisioning_repository = _.find(vm.repositories, {id: vm[vm.model].provisioning_repository_id}); + }); + + // list of machine credentials + API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name' + sortOptions).then(function(data) { + vm.machine_credentials = data.resources; + vm._retirement_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].retirement_machine_credential_id}); + vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].provisioning_machine_credential_id}); + }); + + // list of network credentials + API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name' + sortOptions).then(function(data) { + vm.network_credentials = data.resources; + vm._retirement_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].retirement_network_credential_id}); + vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].provisioning_network_credential_id}); + }); + }; + + // list of cloud credentials + var formCloudCredentials = function(vm, provisionCredentialId, retirementCredentialId) { + API.options('/api/authentications').then(function(data) { + var cloudTypes = {}; + angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(credObject, credType) { + if (credObject.type === 'cloud') { + cloudTypes[credType] = credObject.label; + } + }); + vm.cloudTypes = getSortedHash(cloudTypes); + cloudCredentialsList(vm, provisionCredentialId, retirementCredentialId); + }); + }; + + // get playbooks for selected repository + var repositoryChanged = function(vm, prefix, id) { + API.get('/api/configuration_script_sources/' + id + '/configuration_script_payloads?expand=resources&filter[]=region_number=' + vm.currentRegion + sortOptions).then(function(data) { + vm[prefix + '_playbooks'] = data.resources; + // if repository has changed + if (id !== vm[vm.model][prefix + '_repository_id']) { + vm[vm.model][prefix + '_playbook_id'] = ''; + vm[vm.model][prefix + '_repository_id'] = id; + if (vm[vm.model].retirement_remove_resources !== undefined) { + getRemoveResourcesTypes(); + } + } else { + findObjectForDropDown(prefix, '_playbook', '_playbooks', vm); + } + }); + }; + + var getRemoveResourcesTypes = function(vm) { + if (vm[vm.model].retirement_repository_id === undefined || vm[vm.model].retirement_repository_id === '') { + vm[vm.model].retirement_remove_resources = 'yes_without_playbook'; + vm.remove_resources_types = { + 'No': 'no_without_playbook', + 'Yes': 'yes_without_playbook', + }; + } else { + vm[vm.model].retirement_remove_resources = 'no_with_playbook'; + vm.remove_resources_types = { + 'No': 'no_with_playbook', + 'Before Playbook runs': 'pre_with_playbook', + 'After Playbook runs': 'post_with_playbook', + }; + } + }; + + var cloudTypeChanged = function(vm, prefix, value) { + var valueChanged = (value !== vm.provisioning_cloud_type); + if (value) { + vm.provisioning_cloud_type = value; + } else { + vm.provisioning_cloud_type = ''; + } + if (valueChanged) { + var typ = vm.provisioning_cloud_type; + vm[vm.model].provisioning_cloud_credential_id = ''; + getCloudCredentialsforType(prefix, typ, vm); + } + }; + + return { + checkFormPristine: checkFormPristine, + cloudCredentialsList: cloudCredentialsList, + cloudTypeChanged: cloudTypeChanged, + getVerbosityTypes: getVerbosityTypes, + getSortedHash: getSortedHash, + getCloudCredentialsforType: getCloudCredentialsforType, + getRemoveResourcesTypes: getRemoveResourcesTypes, + findObjectForDropDown: findObjectForDropDown, + formOptions: formOptions, + formCloudCredentials: formCloudCredentials, + repositoryChanged: repositoryChanged, + setIfDefined: setIfDefined, + }; +}]); diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 60f8c8ed84e..51199c070ca 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1794,7 +1794,7 @@ def build_created_audit(rec, eh) } end - def build_saved_audit_hash(old_record_attributes, new_record, add) + def build_saved_audit_hash_angular(old_record_attributes, new_record, add) name = new_record.respond_to?(:name) ? new_record.name : new_record.description msg = if add _("[%{name}] Record added (") % {:name => name} diff --git a/app/controllers/host_controller.rb b/app/controllers/host_controller.rb index 3b454243fa5..2aa6e4eebcc 100644 --- a/app/controllers/host_controller.rb +++ b/app/controllers/host_controller.rb @@ -309,35 +309,6 @@ def update end end - def build_saved_audit_hash_angular(old_attributes, new_record, add) - name = new_record.respond_to?(:name) ? new_record.name : new_record.description - msg = if add - _("[%{name}] Record added (") % {:name => name} - else - _("[%{name}] Record updated (") % {:name => name} - end - event = "#{new_record.class.to_s.downcase}_record_#{add ? "add" : "update"}" - - attribute_difference = new_record.attributes.to_a - old_attributes.to_a - attribute_difference = Hash[*attribute_difference.flatten] - - difference_messages = [] - - attribute_difference.each do |key, value| - difference_messages << _("%{key} changed to %{value}") % {:key => key, :value => value} - end - - msg = msg + difference_messages.join(", ") + ")" - - { - :event => event, - :target_id => new_record.id, - :target_class => new_record.class.base_class.name, - :userid => session[:userid], - :message => msg - } - end - # handle buttons pressed on the button bar def button @edit = session[:edit] # Restore @edit for adv search box diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 06dd0cde569..f3abf8fbc14 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -976,6 +976,7 @@ def form_method_field_changed def method_form_fields method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) data = method.data ? JSON.parse(method.data) : {} + p "XXXXX #{data['cloud_credential_id']}" method_hash = { :name => method.name, :display_name => method.display_name, @@ -1170,7 +1171,7 @@ def add_update_method else old_method_attributes = method.attributes.clone add_flash(_("%{model} \"%{name}\" was saved") % {:model => ui_lookup(:model => "MiqAeMethod"), :name => method.name}) - AuditEvent.success(build_saved_audit_hash(old_method_attributes, method, params[:button] == "add")) + AuditEvent.success(build_saved_audit_hash_angular(old_method_attributes, method, params[:button] == "add")) replace_right_cell(:replace_trees => [:ae]) return end diff --git a/app/controllers/ops_controller/ops_rbac.rb b/app/controllers/ops_controller/ops_rbac.rb index e2f47527c4c..4aaad61151d 100644 --- a/app/controllers/ops_controller/ops_rbac.rb +++ b/app/controllers/ops_controller/ops_rbac.rb @@ -133,7 +133,7 @@ def rbac_tenant_edit_save_add return end - AuditEvent.success(build_saved_audit_hash(old_tenant_attributes, tenant, params[:button] == "add")) + AuditEvent.success(build_saved_audit_hash_angular(old_tenant_attributes, tenant, params[:button] == "add")) add_flash(_("%{model} \"%{name}\" was saved") % {:model => tenant_type_title_string(params[:divisible] == "true"), :name => tenant.name}) if params[:button] == "add" diff --git a/app/controllers/ops_controller/settings/schedules.rb b/app/controllers/ops_controller/settings/schedules.rb index ea7764acd4d..71772288817 100644 --- a/app/controllers/ops_controller/settings/schedules.rb +++ b/app/controllers/ops_controller/settings/schedules.rb @@ -70,7 +70,7 @@ def schedule_edit add_flash(_("Error when adding a new schedule: %{message}") % {:message => bang.message}, :error) javascript_flash else - AuditEvent.success(build_saved_audit_hash(old_schedule_attributes, schedule, params[:button] == "add")) + AuditEvent.success(build_saved_audit_hash_angular(old_schedule_attributes, schedule, params[:button] == "add")) add_flash(_("%{model} \"%{name}\" was saved") % {:model => ui_lookup(:model => "MiqSchedule"), :name => schedule.name}) if params[:button] == "add" @@ -257,35 +257,6 @@ def log_depot_validate private - def build_saved_audit_hash(old_schedule_attributes, new_schedule, add) - name = new_schedule.respond_to?(:name) ? new_schedule.name : new_schedule.description - msg = if add - _("[%{name}] Record added (") % {:name => name} - else - _("[%{name}] Record updated (") % {:name => name} - end - event = "#{new_schedule.class.to_s.downcase}_record_#{add ? "add" : "update"}" - - attribute_difference = new_schedule.attributes.to_a - old_schedule_attributes.to_a - attribute_difference = Hash[*attribute_difference.flatten] - - difference_messages = [] - - attribute_difference.each do |key, value| - difference_messages << _("%{key} changed to %{value}") % {:key => key, :value => value} - end - - msg = msg + difference_messages.join(", ") + ")" - - { - :event => event, - :target_id => new_schedule.id, - :target_class => new_schedule.class.base_class.name, - :userid => session[:userid], - :message => msg - } - end - def schedule_check_compliance?(schedule) schedule.sched_action && schedule.sched_action[:method] && schedule.sched_action[:method] == "check_compliance" end diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 4beccf7cc10..1be3702c7ea 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -78,7 +78,7 @@ .col-md-9 %select{"ng-model" => "vm._#{prefix}_cloud_type", "name" => "#{prefix}_cloud_type", - 'ng-options' => "k as v for (k,v) in vm.cloud_types", + 'ng-options' => "k as v for (k,v) in vm.cloudTypes", "pf-select" => true} %option{"value" => ""} = "<#{_('Choose')}>" @@ -299,7 +299,7 @@ %td{"ng-if" => "#{ng_model}.#{prefix}_key != ''"} %button{:class => "btn btn-link", :type => "button", - "ng-click" => "vm.addKeyValue('#{prefix}')", + "ng-click" => "vm.addKeyValue()", "ng-if" => "#{ng_model}.#{prefix}_key != ''"} %span{:class => "fa fa-plus tag-add"} @@ -352,13 +352,13 @@ %td.table-view-pf-select %div{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} - %button{:class => "btn btn-link", :type => "button", "ng-disabled" => "(#{ng_model}.key === '' || #{ng_model}.key_value === '')", "ng-click" => "vm.saveKeyValue('#{prefix}', $index)"} + %button{:class => "btn btn-link", :type => "button", "ng-disabled" => "#{ng_model}.key === ''", "ng-click" => "vm.saveKeyValue($index)"} %i.pficon.pficon-save %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.cancelKeyValue($index)"} %i.pficon.pficon-close %div{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)", :class => "btn-container"} - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue('#{prefix}', this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue(this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} %span{:class => "pficon pficon-edit"} - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue('#{prefix}', this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue($index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} %span{:class => "pficon pficon-delete"} diff --git a/app/views/miq_ae_class/_angular_method_form.html.haml b/app/views/miq_ae_class/_angular_method_form.html.haml index c76c98f83b1..a848434c34b 100644 --- a/app/views/miq_ae_class/_angular_method_form.html.haml +++ b/app/views/miq_ae_class/_angular_method_form.html.haml @@ -57,7 +57,7 @@ :id => @record.id, :prefix => "provisioning", :basic_info_needed => true} - = render :partial => "layouts/angular/x_edit_buttons_angular" + = render :partial => "layouts/angular/generic_form_buttons" :javascript ManageIQ.angular.app.value('aeMethodFormId', '#{@record.id || "new"}'); From 1f82622fbf26a6e14f945f7e639ad7ed51c9c4fb Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Sun, 17 Sep 2017 16:28:20 -0400 Subject: [PATCH 07/19] Added "Escalate Privilege" switch to playbook method form https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 3 +++ app/controllers/miq_ae_class_controller.rb | 14 ++++++++------ .../_ansible_form_options_angular.html.haml | 4 ++-- app/views/miq_ae_class/_method_inputs.html.haml | 5 +++++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index a33a8f769dc..8bb524df332 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -25,6 +25,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a provisioning_inputs: [], provisioning_verbosity: '0', provisioning_editMode: false, + provisioning_become_enabled: false, }; vm.verbosity_types = playbookReusableCodeMixin.getVerbosityTypes(); vm.provisioning_cloud_type = ''; @@ -69,6 +70,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_network_credential_id = configData.network_credential_id; vm.aeMethodModel.provisioning_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.cloud_credential_id); vm.aeMethodModel.provisioning_inventory = configData.hosts ? configData.hosts : 'localhost'; + vm.aeMethodModel.provisioning_become_enabled = configData.become_enabled === 'true' ? true : false; vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; @@ -134,6 +136,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a credential_id: configData.provisioning_machine_credential_id, hosts: configData.provisioning_inventory, verbosity: configData.provisioning_verbosity, + become_enabled: configData.provisioning_become_enabled, extra_vars: configData.provisioning_inputs, }; if (configData.provisioning_network_credential_id !== '') { diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index f3abf8fbc14..c1bf8f14451 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -976,7 +976,6 @@ def form_method_field_changed def method_form_fields method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) data = method.data ? JSON.parse(method.data) : {} - p "XXXXX #{data['cloud_credential_id']}" method_hash = { :name => method.name, :display_name => method.display_name, @@ -994,6 +993,7 @@ def method_form_fields :cloud_credential_id => data['cloud_credential_id'] || '', :hosts => data['hosts'], :verbosity => data['verbosity'], + :become_enabled => data['become_enabled'] || false, :extra_vars => method.inputs } } @@ -1199,11 +1199,12 @@ def playbook_inputs(method) def set_playbook_data data = { - :repository_id => params['repository_id'], - :playbook_id => params['playbook_id'], - :credential_id => params['credential_id'], - :hosts => params['hosts'], - :verbosity => params['verbosity'], + :repository_id => params['repository_id'], + :playbook_id => params['playbook_id'], + :credential_id => params['credential_id'], + :hosts => params['hosts'], + :become_enabled => params['become_enabled'], + :verbosity => params['verbosity'], } data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] @@ -2679,6 +2680,7 @@ def fetch_playbook_details @playbook_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, data['network_credential_id']) if data['network_credential_id'] @playbook_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, data['cloud_credential_id']) if data['cloud_credential_id'] @playbook_details[:verbosity] = data['verbosity'] + @playbook_details[:become_enabled] = data['become_enabled'] == 'true' ? _("Yes") : _("No") @playbook_details[:hosts] = data['hosts'] @playbook_details end diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 1be3702c7ea..3a1b6ebacec 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -98,6 +98,7 @@ .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_inventory.$invalid}"} %label.col-md-3.control-label = _("Hosts") + {{vm.aeMethodModel.provisioning_become_enabled}} .col-md-9 %input.form-control{:type => "text", 'ng-model' => "#{ng_model}.#{prefix}_inventory", @@ -119,8 +120,7 @@ "checkchange" => true} %span{"style"=>"color:red", "ng-show" => "angularForm.#{prefix}_execution_ttl.$invalid"} = _("Max TTL value must be numeric") - - #escalate_privilege{"ng-if" => "vm.retirement_playbook_selected('#{prefix}')"} + #escalate_privilege{"ng-if" => "(#{ng_model}.#{prefix}_become_enabled!=='undefined' || vm.retirement_playbook_selected('#{prefix}'))"} .form-group %label.col-md-3.control-label = _("Escalate Privilege") diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index 9b89d277754..56c8e8956a1 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -77,6 +77,11 @@ = _('Hosts') .col-md-8 = h(@playbook_details[:hosts]) + .form-group + %label.col-md-2.control-label + = _('Escalate Privilege') + .col-md-8 + = h(@playbook_details[:become_enabled]) .form-group %label.col-md-2.control-label = _('Verbosity') From a3aabac679b9682d37aa5f0458ccfae20f00c8e2 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Sun, 17 Sep 2017 22:48:23 -0400 Subject: [PATCH 08/19] Fixed code to get method editor working when clicking on items from list Needed to add checks if @angular_form is set to handle screens differently for Playbook type method add/edit. https://www.pivotaltracker.com/story/show/149747321 --- app/controllers/application_controller.rb | 2 +- app/controllers/miq_ae_class_controller.rb | 26 +++++--- app/views/miq_ae_class/_all_tabs.html.haml | 2 +- .../miq_ae_class/_class_instances.html.haml | 61 ++++++++++--------- .../miq_ae_class/_class_methods.html.haml | 7 ++- app/views/miq_ae_class/_inputs.html.haml | 2 +- .../miq_ae_class/_method_inputs.html.haml | 15 +++-- 7 files changed, 63 insertions(+), 52 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 51199c070ca..55420c82671 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2304,7 +2304,7 @@ def validate_before_save? public :validate_before_save? def determine_record_id_for_presenter - if @in_a_form + if @in_a_form && !@angular_form @edit && @edit[:rec_id] else @record.try!(:id) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index c1bf8f14451..e3d6dc380ee 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -270,7 +270,7 @@ def replace_right_cell(options = {}) (%w(save add).include?(params[:button]) && replace_trees) add_nodes = open_parent_nodes(@record) if params[:button] == "copy" || params[:action] == "x_show" - get_node_info(x_node) if !@in_a_form && @button != "reset" + get_node_info(x_node) if !@in_a_form && !@angular_form && @button != "reset" c_tb = build_toolbar(center_toolbar_filename) unless @in_a_form h_tb = build_toolbar("x_history_tb") @@ -325,7 +325,7 @@ def replace_right_cell(options = {}) presenter[:lock_sidebar] = @in_a_form && @edit - if @record.kind_of?(MiqAeMethod) && !@in_a_form + if @record.kind_of?(MiqAeMethod) && !@in_a_form && !@angular_form presenter.set_visibility(!@record.inputs.blank?, :params_div) end @@ -496,10 +496,13 @@ def edit_method else id = x_node.split('-') end - @record = @ae_method = find_record_with_rbac(MiqAeMethod, from_cid(id[1])) - @current_region = MiqRegion.my_region.region - set_method_form_vars unless @ae_method.location == "playbook" - @in_a_form = @angular_form = true + @ae_method = find_record_with_rbac(MiqAeMethod, from_cid(id[1])) + if @ae_method.location == "playbook" + angular_form_specific_data + else + set_method_form_vars + @in_a_form = true + end session[:changed] = @changed = false replace_right_cell end @@ -904,8 +907,7 @@ def form_method_field_changed page << javascript_prologue page.replace_html('form_div', :partial => 'method_form', :locals => {:prefix => ""}) if @edit[:new][:location] == 'expression' if @edit[:new][:location] == "playbook" - @record = @ae_method - @current_region = MiqRegion.my_region.region + angular_form_specific_data page.replace_html(@refresh_div, :partial => 'angular_method_form') page << javascript_hide("form_buttons_div") elsif @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) @@ -1737,6 +1739,14 @@ def refresh_git_domain private + def angular_form_specific_data + @record = @ae_method + @ae_class = ae_class_for_instance_or_method(@ae_method) + @current_region = MiqRegion.my_region.region + @angular_form = true + end + helper_method :angular_form_specific_data + def validate_expression(task) if @edit[@expkey][:expression]["???"] == "???" add_flash(_("Error during '%{task}': Expression element is required") % {:task => _(task)}, :error) diff --git a/app/views/miq_ae_class/_all_tabs.html.haml b/app/views/miq_ae_class/_all_tabs.html.haml index 09095de6581..043637dcf90 100644 --- a/app/views/miq_ae_class/_all_tabs.html.haml +++ b/app/views/miq_ae_class/_all_tabs.html.haml @@ -71,6 +71,6 @@ if (ManageIQ.editor !== null) ManageIQ.editor.refresh(); -# disable any other tabs on screen when in edit -- if @in_a_form +- if @in_a_form || @angular_form :javascript miq_tabs_disable_inactive('#ae_tabs'); diff --git a/app/views/miq_ae_class/_class_instances.html.haml b/app/views/miq_ae_class/_class_instances.html.haml index 9e289cc3fb6..1dc4ae02344 100644 --- a/app/views/miq_ae_class/_class_instances.html.haml +++ b/app/views/miq_ae_class/_class_instances.html.haml @@ -1,31 +1,32 @@ #class_instances_div - - if !@in_a_form - %h3= _('Instances') - - if @record.ae_instances.present? - %table#class_instances_grid.table.table-striped.table-bordered.table-hover.table-clickable.table-checkable - %thead - %th.table-view-pf-select - %input.checkall{:type => 'checkbox', :title => _('Check All')} - %th - %th - %tbody{'data-click-url' => '/miq_ae_class/tree_select/'} - - @record.ae_instances.order(:name).each do |record| - - next if record.name == '$' - - cls_cid = "#{class_prefix(record.class)}-#{ApplicationRecord.compress_id(record.id)}" - %tr{'data-click-id' => cls_cid} - %td.table-view-pf-select.noclick - %input{:type => 'checkbox', :value => cls_cid} - %td.table-view-pf-select - %i{:class => record.decorate.fonticon} - %td - = record_name(record) - :javascript - $(function () { - $('#class_instances_grid').miqGrid(); - }); - - else - = render :partial => "layouts/info_msg", - :locals => {:message => _("No instances found")} - - elsif @edit[:new][:ae_inst] - #form_div - = render :partial => "instance_form", :locals => {:prefix => "cls_"} + - unless @angular_form + - if !@in_a_form + %h3= _('Instances') + - if @record.ae_instances.present? + %table#class_instances_grid.table.table-striped.table-bordered.table-hover.table-clickable.table-checkable + %thead + %th.table-view-pf-select + %input.checkall{:type => 'checkbox', :title => _('Check All')} + %th + %th + %tbody{'data-click-url' => '/miq_ae_class/tree_select/'} + - @record.ae_instances.order(:name).each do |record| + - next if record.name == '$' + - cls_cid = "#{class_prefix(record.class)}-#{ApplicationRecord.compress_id(record.id)}" + %tr{'data-click-id' => cls_cid} + %td.table-view-pf-select.noclick + %input{:type => 'checkbox', :value => cls_cid} + %td.table-view-pf-select + %i{:class => record.decorate.fonticon} + %td + = record_name(record) + :javascript + $(function () { + $('#class_instances_grid').miqGrid(); + }); + - else + = render :partial => "layouts/info_msg", + :locals => {:message => _("No instances found")} + - elsif @edit[:new][:ae_inst] + #form_div + = render :partial => "instance_form", :locals => {:prefix => "cls_"} diff --git a/app/views/miq_ae_class/_class_methods.html.haml b/app/views/miq_ae_class/_class_methods.html.haml index 43c324aeff1..9290f600673 100644 --- a/app/views/miq_ae_class/_class_methods.html.haml +++ b/app/views/miq_ae_class/_class_methods.html.haml @@ -1,5 +1,5 @@ #class_methods_div - - if !@in_a_form + - if !@in_a_form && !@angular_form %h3= _('Methods') - if @record.ae_methods.present? %table#class_methods_grid.table.table-striped.table-bordered.table-hover.table-clickable.table-checkable @@ -26,6 +26,7 @@ - else = render :partial => "layouts/info_msg", :locals => {:message => _("No methods found")} - - elsif @edit[:new][:fields] + - elsif @angular_form || @edit[:new][:fields] .form_div - = render :partial => "method_form", :locals => {:prefix => "cls_"} + - partial_name = @angular_form ? 'angular_method_form' : 'method_form' + = render :partial => partial_name, :locals => {:prefix => "cls_"} diff --git a/app/views/miq_ae_class/_inputs.html.haml b/app/views/miq_ae_class/_inputs.html.haml index 4acf2de8b9b..5c9c354301f 100644 --- a/app/views/miq_ae_class/_inputs.html.haml +++ b/app/views/miq_ae_class/_inputs.html.haml @@ -1,4 +1,4 @@ -#inputs_div{:style => @sb[:squash_state] ? "display: none;" : ""} +%inputs_div{:style => @sb[:squash_state] ? "display: none;" : ""} - url = url_for_only_path(:action => 'form_method_field_changed', :id => (@ae_method.id || 'new')) - obs = {:interval => '.5', :url => url}.to_json - prefix = row_selected_in_grid? ? "cls_" : "" diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index 56c8e8956a1..fb9051ba8df 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -1,5 +1,11 @@ #method_inputs_div - - if !@in_a_form && @ae_method + - if @in_a_form || @angular_form + #method_form_div + - if @ae_method.location == "playbook" + = render :partial => "angular_method_form", :locals => {:prefix => ""} + - else + = render :partial => "method_form", :locals => {:prefix => ""} + - else %h3 = _('Main Info') .form-horizontal.static @@ -109,10 +115,3 @@ - else = record.default_value %td= record.datatype.blank? ? 'string' : record.datatype - - else - #method_form_div - - if @record.location == "playbook" - = render :partial => "angular_method_form", :locals => {:prefix => ""} - - else - = render :partial => "method_form", :locals => {:prefix => ""} - %br From 0c94382d9735ae172a25d15f4906ba3c9d251375 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 18 Sep 2017 13:55:43 -0400 Subject: [PATCH 09/19] split input form table into a separate view, can be reused if needed. https://www.pivotaltracker.com/story/show/149747321 --- .../_ansible_form_options_angular.html.haml | 103 +----------------- .../_angular_inputs_form.html.haml | 100 +++++++++++++++++ 2 files changed, 103 insertions(+), 100 deletions(-) create mode 100644 app/views/miq_ae_class/_angular_inputs_form.html.haml diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 3a1b6ebacec..4c9dd272183 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -262,103 +262,6 @@ = _("Required") .row{'ng-if' => "#{ng_model}.#{prefix}_inputs"} - .col-md-12.col-lg-12 - .form-group - %label - = _("Input Parameters") - .col-md-6 - %table.table.table-bordered.table-striped - %tr - %td - %input{:type => "text", - 'ng-model' => "#{ng_model}.#{prefix}_key", - :name => "#{prefix}_key", - "placeholder" => "Input Name", - "checkchange" => ""} - %span.help-block{"ng-show" => "#{ng_model}.#{prefix}_key === ''"} - = _("Required") - %td - %input{:type => "text", - 'ng-model' => "#{ng_model}.#{prefix}_value", - 'ng-if' => "#{ng_model}.#{prefix}_type != 'password'", - :name => "#{prefix}_value", - "placeholder" => "Default value", - "checkchange" => ""} - %input{"type" => "password", - :name => "#{prefix}_value", - 'ng-if' => "#{ng_model}.#{prefix}_type == 'password'", - 'ng-model' => "#{ng_model}.#{prefix}_value", - "placeholder" => placeholder_if_present("#{ng_model}.#{prefix}_value"), - "ng-change" => ""} - %td - %select{"ng-model" => "#{ng_model}.#{prefix}_type", - "name" => "#{prefix}_type", - 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", - 'ng-change' => '', - "pf-select" => true} - %td{"ng-if" => "#{ng_model}.#{prefix}_key != ''"} - %button{:class => "btn btn-link", - :type => "button", - "ng-click" => "vm.addKeyValue()", - "ng-if" => "#{ng_model}.#{prefix}_key != ''"} - %span{:class => "fa fa-plus tag-add"} - - #inputs_div - .form-group - %label.col-md-4.control-label - .col-md-12 - %table.table.table-bordered.table-striped - %thead - %th - = _("Input Name") - %th - = _("Default value") - %th - = _("Data Type") - %th - = _("Actions") - %tbody - %tr{"ng-repeat" => "arr in #{ng_model}.#{prefix}_inputs track by $index", "ng-form" => "rowForm"} - %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} - {{arr[0]}} - %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} - %input.form-control{:type => "text", - :name => "key", - 'ng-model' => "#{ng_model}.key", - "ng-change" => "", - "miqrequired" => ""} - %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} - {{arr[2] == 'password' ? '******' : arr[1]}} - %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} - %input.form-control{:type => "text", - :name => "key_value", - 'ng-if' => "#{ng_model}.key_type != 'password'", - 'ng-model' => "#{ng_model}.key_value", - "ng-change" => ""} - %input.form-control{"type" => "password", - :name => "key_value", - 'ng-if' => "#{ng_model}.key_type == 'password'", - 'ng-model' => "#{ng_model}.key_value", - "placeholder" => placeholder_if_present("#{ng_model}.key_value"), - "ng-change" => ""} - %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} - {{arr[2]}} - %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} - %select.form-control{"ng-model" => "#{ng_model}.key_type", - "name" => "key_type", - 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", - "ng-change" => '', - "pf-select" => true} - - %td.table-view-pf-select - %div{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} - %button{:class => "btn btn-link", :type => "button", "ng-disabled" => "#{ng_model}.key === ''", "ng-click" => "vm.saveKeyValue($index)"} - %i.pficon.pficon-save - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.cancelKeyValue($index)"} - %i.pficon.pficon-close - - %div{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)", :class => "btn-container"} - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue(this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} - %span{:class => "pficon pficon-edit"} - %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue($index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} - %span{:class => "pficon pficon-delete"} + = render :partial => "miq_ae_class/angular_inputs_form", + :locals => {:ng_model => "vm.aeMethodModel", + :prefix => "provisioning"} diff --git a/app/views/miq_ae_class/_angular_inputs_form.html.haml b/app/views/miq_ae_class/_angular_inputs_form.html.haml new file mode 100644 index 00000000000..fff2a5a4106 --- /dev/null +++ b/app/views/miq_ae_class/_angular_inputs_form.html.haml @@ -0,0 +1,100 @@ +.col-md-12.col-lg-12 + .form-group + %label + = _("Input Parameters") + .col-md-6 + %table.table.table-bordered.table-striped + %tr + %td + %input{:type => "text", + 'ng-model' => "#{ng_model}.#{prefix}_key", + :name => "#{prefix}_key", + "placeholder" => "Input Name", + "checkchange" => ""} + %span.help-block{"ng-show" => "#{ng_model}.#{prefix}_key === ''"} + = _("Required") + %td + %input{:type => "text", + 'ng-model' => "#{ng_model}.#{prefix}_value", + 'ng-if' => "#{ng_model}.#{prefix}_type != 'password'", + :name => "#{prefix}_value", + "placeholder" => "Default value", + "checkchange" => ""} + %input{"type" => "password", + :name => "#{prefix}_value", + 'ng-if' => "#{ng_model}.#{prefix}_type == 'password'", + 'ng-model' => "#{ng_model}.#{prefix}_value", + "placeholder" => placeholder_if_present("#{ng_model}.#{prefix}_value"), + "ng-change" => ""} + %td + %select{"ng-model" => "#{ng_model}.#{prefix}_type", + "name" => "#{prefix}_type", + 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", + 'ng-change' => '', + "pf-select" => true} + %td{"ng-if" => "#{ng_model}.#{prefix}_key != ''"} + %button{:class => "btn btn-link", + :type => "button", + "ng-click" => "vm.addKeyValue()", + "ng-if" => "#{ng_model}.#{prefix}_key != ''"} + %span{:class => "fa fa-plus tag-add"} + + #inputs_div + .form-group + %label.col-md-4.control-label + .col-md-12 + %table.table.table-bordered.table-striped + %thead + %th + = _("Input Name") + %th + = _("Default value") + %th + = _("Data Type") + %th + = _("Actions") + %tbody + %tr{"ng-repeat" => "arr in #{ng_model}.#{prefix}_inputs track by $index", "ng-form" => "rowForm"} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[0]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %input.form-control{:type => "text", + :name => "key", + 'ng-model' => "#{ng_model}.key", + "ng-change" => "", + "miqrequired" => ""} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[2] == 'password' ? '******' : arr[1]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %input.form-control{:type => "text", + :name => "key_value", + 'ng-if' => "#{ng_model}.key_type != 'password'", + 'ng-model' => "#{ng_model}.key_value", + "ng-change" => ""} + %input.form-control{"type" => "password", + :name => "key_value", + 'ng-if' => "#{ng_model}.key_type == 'password'", + 'ng-model' => "#{ng_model}.key_value", + "placeholder" => placeholder_if_present("#{ng_model}.key_value"), + "ng-change" => ""} + %td{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)"} + {{arr[2]}} + %td{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %select.form-control{"ng-model" => "#{ng_model}.key_type", + "name" => "key_type", + 'ng-options' => "v as v for v in #{ng_model}.available_datatypes", + "ng-change" => '', + "pf-select" => true} + + %td.table-view-pf-select + %div{"ng-if" => "#{ng_model}.#{prefix}_editMode && $index === #{ng_model}.s_index"} + %button{:class => "btn btn-link", :type => "button", "ng-disabled" => "#{ng_model}.key === ''", "ng-click" => "vm.saveKeyValue($index)"} + %i.pficon.pficon-save + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.cancelKeyValue($index)"} + %i.pficon.pficon-close + + %div{"ng-if" => "!#{ng_model}.#{prefix}_editMode || (#{ng_model}.#{prefix}_editMode && $index !== #{ng_model}.s_index)", :class => "btn-container"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.editKeyValue(this.arr[0], this.arr[1], this.arr[2], $index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %span{:class => "pficon pficon-edit"} + %button{:class => "btn btn-link", :type => "button", "ng-click" => "vm.removeKeyValue($index)", "ng-disabled" => "#{ng_model}.#{prefix}_editMode"} + %span{:class => "pficon pficon-delete"} From 4129ba3a215d93defc4006b01dfb7592a8bed62c Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Tue, 19 Sep 2017 16:29:28 -0400 Subject: [PATCH 10/19] Fixed nil.id error when trying to add playbook type method. https://www.pivotaltracker.com/story/show/149747321 --- app/controllers/miq_ae_class_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index e3d6dc380ee..b48eb09034e 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -903,11 +903,11 @@ def form_method_field_changed end @changed = (@edit[:new] != @edit[:current]) @edit[:default_verify_status] = @edit[:new][:location] == "inline" && @edit[:new][:data] && @edit[:new][:data] != "" + angular_form_specific_data if @edit[:new][:location] == "playbook" render :update do |page| page << javascript_prologue page.replace_html('form_div', :partial => 'method_form', :locals => {:prefix => ""}) if @edit[:new][:location] == 'expression' if @edit[:new][:location] == "playbook" - angular_form_specific_data page.replace_html(@refresh_div, :partial => 'angular_method_form') page << javascript_hide("form_buttons_div") elsif @refresh_div && (params[:cls_method_location] || params[:exp_object] || params[:cls_exp_object]) @@ -1745,7 +1745,6 @@ def angular_form_specific_data @current_region = MiqRegion.my_region.region @angular_form = true end - helper_method :angular_form_specific_data def validate_expression(task) if @edit[@expkey][:expression]["???"] == "???" From 16cf97b27474fc08aa7a70898a135d7195b162a2 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 20 Sep 2017 13:30:09 -0400 Subject: [PATCH 11/19] Changed playbook data keys to be saved/read as symbols - removed a leftover debugging statement from view - moved methods that should be private to private area https://www.pivotaltracker.com/n/projects/1613907/stories/149747321 --- app/controllers/miq_ae_class_controller.rb | 104 +++++++++--------- .../_ansible_form_options_angular.html.haml | 1 - 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index b48eb09034e..4f3850916f6 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -977,7 +977,7 @@ def form_method_field_changed def method_form_fields method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) - data = method.data ? JSON.parse(method.data) : {} + data = method.data ? YAML.load(method.data) : {} method_hash = { :name => method.name, :display_name => method.display_name, @@ -988,14 +988,14 @@ def method_form_fields :scope => "instance", :available_datatypes => MiqAeField.available_datatypes_for_ui, :config_info => { - :repository_id => data['repository_id'] || '', - :playbook_id => data['playbook_id'] || '', - :credential_id => data['credential_id'] || '', - :network_credential_id => data['network_credential_id'] || '', - :cloud_credential_id => data['cloud_credential_id'] || '', - :hosts => data['hosts'], - :verbosity => data['verbosity'], - :become_enabled => data['become_enabled'] || false, + :repository_id => data[:repository_id] || '', + :playbook_id => data[:playbook_id] || '', + :credential_id => data[:credential_id] || '', + :network_credential_id => data[:network_credential_id] || '', + :cloud_credential_id => data[:cloud_credential_id] || '', + :hosts => data[:hosts], + :verbosity => data[:verbosity], + :become_enabled => data[:become_enabled] || false, :extra_vars => method.inputs } } @@ -1159,7 +1159,7 @@ def add_update_method method.language = params["language"] method.scope = params["scope"] method.class_id = params[:class_id] - method.data = set_playbook_data.to_json + method.data = YAML.dump(set_playbook_data) begin MiqAeMethod.transaction do to_save, to_delete = playbook_inputs(method) @@ -1180,39 +1180,6 @@ def add_update_method end end - def playbook_inputs(method) - existing_inputs = method.inputs - new_inputs = params[:extra_vars] - inputs_to_save = [] - inputs_to_delete = [] - new_inputs.each do |i, input| - field = input.length == 4 ? MiqAeField.find_by(:id => input.last) : MiqAeField.new - field.name = input[0] - field.default_value = input[1] == "" ? nil : input[1] - field.datatype = input[2] - field.priority = i - inputs_to_save.push(field) - end - existing_inputs.each do |existing_input| - inputs_to_delete.push(existing_input.id) unless inputs_to_save.any? { |i| i.id == existing_input.id } - end - return inputs_to_save, inputs_to_delete - end - - def set_playbook_data - data = { - :repository_id => params['repository_id'], - :playbook_id => params['playbook_id'], - :credential_id => params['credential_id'], - :hosts => params['hosts'], - :become_enabled => params['become_enabled'], - :verbosity => params['verbosity'], - } - data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] - data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] - data - end - def update_method assert_privileges("miq_ae_method_edit") return unless load_edit("aemethod_edit__#{params[:id]}", "replace_cell__explorer") @@ -1739,6 +1706,39 @@ def refresh_git_domain private + def playbook_inputs(method) + existing_inputs = method.inputs + new_inputs = params[:extra_vars] + inputs_to_save = [] + inputs_to_delete = [] + new_inputs.each do |i, input| + field = input.length == 4 ? MiqAeField.find_by(:id => input.last) : MiqAeField.new + field.name = input[0] + field.default_value = input[1] == "" ? nil : input[1] + field.datatype = input[2] + field.priority = i + inputs_to_save.push(field) + end + existing_inputs.each do |existing_input| + inputs_to_delete.push(existing_input.id) unless inputs_to_save.any? { |i| i.id == existing_input.id } + end + return inputs_to_save, inputs_to_delete + end + + def set_playbook_data + data = { + :repository_id => params['repository_id'], + :playbook_id => params['playbook_id'], + :credential_id => params['credential_id'], + :hosts => params['hosts'], + :become_enabled => params['become_enabled'], + :verbosity => params['verbosity'], + } + data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] + data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] + data + end + def angular_form_specific_data @record = @ae_method @ae_class = ae_class_for_instance_or_method(@ae_method) @@ -2682,15 +2682,15 @@ def get_method_node_info(id) def fetch_playbook_details @playbook_details = {} - data = JSON.parse(@record.data) - @playbook_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, data['repository_id']) - @playbook_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, data['playbook_id']) - @playbook_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, data['credential_id']) - @playbook_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, data['network_credential_id']) if data['network_credential_id'] - @playbook_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, data['cloud_credential_id']) if data['cloud_credential_id'] - @playbook_details[:verbosity] = data['verbosity'] - @playbook_details[:become_enabled] = data['become_enabled'] == 'true' ? _("Yes") : _("No") - @playbook_details[:hosts] = data['hosts'] + data = YAML.load(@record.data) + @playbook_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, data[:repository_id]) + @playbook_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, data[:playbook_id]) + @playbook_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, data[:credential_id]) + @playbook_details[:network_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential, data[:network_credential_id]) if data[:network_credential_id] + @playbook_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, data[:cloud_credential_id]) if data[:cloud_credential_id] + @playbook_details[:verbosity] = data[:verbosity] + @playbook_details[:become_enabled] = data[:become_enabled] == 'true' ? _("Yes") : _("No") + @playbook_details[:hosts] = data[:hosts] @playbook_details end diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 4c9dd272183..b83059e4af0 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -98,7 +98,6 @@ .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_inventory.$invalid}"} %label.col-md-3.control-label = _("Hosts") - {{vm.aeMethodModel.provisioning_become_enabled}} .col-md-9 %input.form-control{:type => "text", 'ng-model' => "#{ng_model}.#{prefix}_inventory", From 3865ee3aab3defeaf5e2d02e712af0e883f6db82 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Wed, 20 Sep 2017 21:47:51 -0400 Subject: [PATCH 12/19] Store API.get promises and resolve them together. - Made changes to store all API.get promises and resolve them all at once and set afterGet flag to load the form - Fixed a repositoryChanged method call https://www.pivotaltracker.com/story/show/149747321 --- .../catalog/catalog_item_form_controller.js | 4 +- .../miq_ae_class/ae_method_form_controller.js | 1 - .../playbook-reusable-code-mixin.js | 118 +++++++++++------- 3 files changed, 75 insertions(+), 48 deletions(-) diff --git a/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js b/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js index e4b926b1d82..3723a676f9d 100644 --- a/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js +++ b/app/assets/javascripts/controllers/catalog/catalog_item_form_controller.js @@ -54,7 +54,6 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog $scope.newRecord = true; playbookReusableCodeMixin.formOptions(vm); playbookReusableCodeMixin.formCloudCredentials(vm, null, null); - vm.afterGet = true; vm.modelCopy = angular.copy(vm.catalogItemModel); } else { vm.newRecord = false; @@ -68,7 +67,6 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog playbookReusableCodeMixin.formOptions(vm); playbookReusableCodeMixin.formCloudCredentials(vm, catalogItemData.config_info.provision.cloud_credential_id, catalogItemData.config_info.retirement.cloud_credential_id); getConfigInfo(catalogItemData.config_info); - vm.afterGet = true; vm.modelCopy = angular.copy(vm.catalogItemModel); }); } @@ -270,7 +268,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', 'catalog $scope.$watch('vm._retirement_repository', function(value) { if (value) { - vm.repositoryChanged(vm, 'retirement', value.id); + playbookReusableCodeMixin.repositoryChanged(vm, 'retirement', value.id); } else { vm.catalogItemModel['retirement_playbook_id'] = ''; vm.catalogItemModel['retirement_repository_id'] = ''; diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 8bb524df332..3cc497c3d1b 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -44,7 +44,6 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a if (aeMethodFormId === 'new') { playbookReusableCodeMixin.formOptions(vm); } - vm.afterGet = true; }; function getMethodFormData(response) { diff --git a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js index 6622db06d4a..5d8b2e3fd92 100644 --- a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js +++ b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js @@ -1,5 +1,6 @@ -ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', function(API) { +ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqService', function(API, $q, miqService) { var sortOptions = "&sort_by=name&sort_order=ascending"; + var allApiPromises = []; var getSortedHash = function(inputHash) { var sortedHash = Object.keys(inputHash) @@ -38,10 +39,15 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', function(API) var getCloudCredentialsforType = function(prefix, typ, vm) { // list of cloud credentials based upon selected cloud type var url = '/api/authentications?collection_class=' + typ + '&expand=resources&attributes=id,name' + sortOptions; - API.get(url).then(function(data) { - vm[prefix + '_cloud_credentials'] = data.resources; - findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials', vm); - }); + allApiPromises.push(API.get(url) + .then(function(data) { + vm[prefix + '_cloud_credentials'] = data.resources; + findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials', vm); + }) + ); + + $q.all(allApiPromises) + .then(retrievedFormData(vm)); }; var findObjectForDropDown = function(prefix, fieldName, listName, vm) { @@ -71,67 +77,91 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', function(API) var getCredentialType = function(prefix, credentialId, vm) { var url = '/api/authentications/' + credentialId; - API.get(url).then(function(data) { - vm[prefix + '_cloud_type'] = data.type; - if (vm.cloudTypes[vm[prefix + '_cloud_type']] !== 'undefined') { - vm['_' + prefix + '_cloud_type'] = data.type; - getCloudCredentialsforType(prefix, data.type, vm); - } - }); + allApiPromises.push(API.get(url) + .then(function(data) { + vm[prefix + '_cloud_type'] = data.type; + if (vm.cloudTypes[vm[prefix + '_cloud_type']] !== 'undefined') { + vm['_' + prefix + '_cloud_type'] = data.type; + getCloudCredentialsforType(prefix, data.type, vm); + } + }) + ); }; // list of service catalogs var formOptions = function(vm) { + miqService.sparkleOn(); if (vm[vm.model].catalog_id !== undefined) { - API.get('/api/service_catalogs/?expand=resources&attributes=id,name' + sortOptions).then(function(data) { - vm.catalogs = data.resources; - vm._catalog = _.find(vm.catalogs, {id: vm[vm.model].catalog_id}); - }); + allApiPromises.push(API.get('/api/service_catalogs/?expand=resources&attributes=id,name' + sortOptions) + .then(function(data) { + vm.catalogs = data.resources; + vm._catalog = _.find(vm.catalogs, {id: vm[vm.model].catalog_id}); + }) + ); } // list of service dialogs if (vm[vm.model].provisioning_dialog_id !== undefined) { - API.get('/api/service_dialogs/?expand=resources&attributes=id,label&sort_by=label&sort_order=ascending').then( - function(data) { + allApiPromises.push(API.get('/api/service_dialogs/?expand=resources&attributes=id,label&sort_by=label&sort_order=ascending') + .then(function(data) { vm.dialogs = data.resources; vm._provisioning_dialog = _.find(vm.dialogs, {id: vm[vm.model].provisioning_dialog_id}); - }); + }) + ); } // list of repositories - API.get('/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=' + vm.currentRegion + sortOptions).then(function(data) { - vm.repositories = data.resources; - vm._retirement_repository = _.find(vm.repositories, {id: vm[vm.model].retirement_repository_id}); - vm._provisioning_repository = _.find(vm.repositories, {id: vm[vm.model].provisioning_repository_id}); - }); + allApiPromises.push(API.get('/api/configuration_script_sources?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource&expand=resources&attributes=id,name&filter[]=region_number=' + vm.currentRegion + sortOptions) + .then(function(data) { + vm.repositories = data.resources; + vm._retirement_repository = _.find(vm.repositories, {id: vm[vm.model].retirement_repository_id}); + vm._provisioning_repository = _.find(vm.repositories, {id: vm[vm.model].provisioning_repository_id}); + }) + ); // list of machine credentials - API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name' + sortOptions).then(function(data) { - vm.machine_credentials = data.resources; - vm._retirement_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].retirement_machine_credential_id}); - vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].provisioning_machine_credential_id}); - }); + allApiPromises.push(API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name' + sortOptions) + .then(function(data) { + vm.machine_credentials = data.resources; + vm._retirement_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].retirement_machine_credential_id}); + vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].provisioning_machine_credential_id}); + }) + ); // list of network credentials - API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name' + sortOptions).then(function(data) { - vm.network_credentials = data.resources; - vm._retirement_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].retirement_network_credential_id}); - vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].provisioning_network_credential_id}); - }); + allApiPromises.push(API.get('/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::NetworkCredential&expand=resources&attributes=id,name' + sortOptions) + .then(function(data) { + vm.network_credentials = data.resources; + vm._retirement_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].retirement_network_credential_id}); + vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].provisioning_network_credential_id}); + }) + ); + + $q.all(allApiPromises) + .then(retrievedFormData(vm)); }; + function retrievedFormData(vm) { + vm.afterGet = true; + miqService.sparkleOff(); + } + // list of cloud credentials var formCloudCredentials = function(vm, provisionCredentialId, retirementCredentialId) { - API.options('/api/authentications').then(function(data) { - var cloudTypes = {}; - angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(credObject, credType) { - if (credObject.type === 'cloud') { - cloudTypes[credType] = credObject.label; - } - }); - vm.cloudTypes = getSortedHash(cloudTypes); - cloudCredentialsList(vm, provisionCredentialId, retirementCredentialId); - }); + allApiPromises.push(API.options('/api/authentications') + .then(function(data) { + var cloudTypes = {}; + angular.forEach(data.data.credential_types.embedded_ansible_credential_types, function(credObject, credType) { + if (credObject.type === 'cloud') { + cloudTypes[credType] = credObject.label; + } + }); + vm.cloudTypes = getSortedHash(cloudTypes); + cloudCredentialsList(vm, provisionCredentialId, retirementCredentialId); + }) + ); + $q.all(allApiPromises) + .then(retrievedFormData(vm)); }; // get playbooks for selected repository From 98035d97397584894feb74e923d8bd89a874f7ea Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 25 Sep 2017 13:51:12 -0400 Subject: [PATCH 13/19] Removed "Hosts" field from playbook method screens https://www.pivotaltracker.com/story/show/149747321 --- .../controllers/miq_ae_class/ae_method_form_controller.js | 3 --- app/controllers/miq_ae_class_controller.rb | 3 --- .../layouts/angular/_ansible_form_options_angular.html.haml | 2 +- app/views/miq_ae_class/_method_inputs.html.haml | 5 ----- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 3cc497c3d1b..c1febad7b39 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -18,7 +18,6 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a provisioning_machine_credential_id: '', provisioning_network_credential_id: '', provisioning_cloud_credential_id: '', - provisioning_inventory: 'localhost', provisioning_key: '', provisioning_value: '', provisioning_type: 'string', @@ -68,7 +67,6 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_machine_credential_id = configData.credential_id; vm.aeMethodModel.provisioning_network_credential_id = configData.network_credential_id; vm.aeMethodModel.provisioning_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.cloud_credential_id); - vm.aeMethodModel.provisioning_inventory = configData.hosts ? configData.hosts : 'localhost'; vm.aeMethodModel.provisioning_become_enabled = configData.become_enabled === 'true' ? true : false; vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; @@ -133,7 +131,6 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a repository_id: configData.provisioning_repository_id, playbook_id: configData.provisioning_playbook_id, credential_id: configData.provisioning_machine_credential_id, - hosts: configData.provisioning_inventory, verbosity: configData.provisioning_verbosity, become_enabled: configData.provisioning_become_enabled, extra_vars: configData.provisioning_inputs, diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 4f3850916f6..733e346553f 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -993,7 +993,6 @@ def method_form_fields :credential_id => data[:credential_id] || '', :network_credential_id => data[:network_credential_id] || '', :cloud_credential_id => data[:cloud_credential_id] || '', - :hosts => data[:hosts], :verbosity => data[:verbosity], :become_enabled => data[:become_enabled] || false, :extra_vars => method.inputs @@ -1730,7 +1729,6 @@ def set_playbook_data :repository_id => params['repository_id'], :playbook_id => params['playbook_id'], :credential_id => params['credential_id'], - :hosts => params['hosts'], :become_enabled => params['become_enabled'], :verbosity => params['verbosity'], } @@ -2690,7 +2688,6 @@ def fetch_playbook_details @playbook_details[:cloud_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::CloudCredential, data[:cloud_credential_id]) if data[:cloud_credential_id] @playbook_details[:verbosity] = data[:verbosity] @playbook_details[:become_enabled] = data[:become_enabled] == 'true' ? _("Yes") : _("No") - @playbook_details[:hosts] = data[:hosts] @playbook_details end diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index b83059e4af0..5bf1154c306 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -95,7 +95,7 @@ %option{"value" => ""} = "<#{_('Choose')}>" - .form-group{"ng-class" => "{'has-error': angularForm.#{prefix}_inventory.$invalid}"} + .form-group{"ng-if" =>"#{ng_model}.#{prefix}_inventory!==undefined", "ng-class" => "{'has-error': angularForm.#{prefix}_inventory.$invalid}"} %label.col-md-3.control-label = _("Hosts") .col-md-9 diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index fb9051ba8df..8fd3bfd62a8 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -78,11 +78,6 @@ = _('Cloud Credential') .col-md-8 = h(@playbook_details[:cloud_credential]) - .form-group - %label.col-md-2.control-label - = _('Hosts') - .col-md-8 - = h(@playbook_details[:hosts]) .form-group %label.col-md-2.control-label = _('Escalate Privilege') From d939cf6b6fb85b672e97297bd939f1de651b294b Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 25 Sep 2017 16:50:29 -0400 Subject: [PATCH 14/19] Addressed PR comments. https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 13 +++--- .../playbook-reusable-code-mixin.js | 40 ++++++++++--------- app/controllers/miq_ae_class_controller.rb | 2 +- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index c1febad7b39..4287fbb83ba 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -181,13 +181,13 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a var valid = validateInputName(vm.aeMethodModel.provisioning_key, 0); if (! valid) { return miqService.miqFlash("error", __("Inputs name must be unique")); - } else { - vm.aeMethodModel.provisioning_inputs.push( - [vm.aeMethodModel.provisioning_key, vm.aeMethodModel.provisioning_value, vm.aeMethodModel.provisioning_type]); - vm.aeMethodModel.provisioning_key = ''; - vm.aeMethodModel.provisioning_value = ''; - vm.aeMethodModel.provisioning_type = 'string'; } + vm.aeMethodModel.provisioning_inputs.push( + [vm.aeMethodModel.provisioning_key, vm.aeMethodModel.provisioning_value, vm.aeMethodModel.provisioning_type]); + vm.aeMethodModel.provisioning_key = ''; + vm.aeMethodModel.provisioning_value = ''; + vm.aeMethodModel.provisioning_type = 'string'; + return true; }; vm.provisioning_repository_selected = function() { @@ -228,6 +228,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a vm.aeMethodModel.provisioning_inputs[index][0] = vm.aeMethodModel.key; vm.aeMethodModel.provisioning_inputs[index][1] = vm.aeMethodModel.key_value; vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.key_type; + return true; }; var validateInputName = function(inputName, index) { diff --git a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js index 5d8b2e3fd92..57aa4686856 100644 --- a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js +++ b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js @@ -44,10 +44,8 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm[prefix + '_cloud_credentials'] = data.resources; findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials', vm); }) + .catch(miqService.handleFailure) ); - - $q.all(allApiPromises) - .then(retrievedFormData(vm)); }; var findObjectForDropDown = function(prefix, fieldName, listName, vm) { @@ -85,6 +83,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ getCloudCredentialsforType(prefix, data.type, vm); } }) + .catch(miqService.handleFailure) ); }; @@ -97,6 +96,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm.catalogs = data.resources; vm._catalog = _.find(vm.catalogs, {id: vm[vm.model].catalog_id}); }) + .catch(miqService.handleFailure) ); } @@ -107,6 +107,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm.dialogs = data.resources; vm._provisioning_dialog = _.find(vm.dialogs, {id: vm[vm.model].provisioning_dialog_id}); }) + .catch(miqService.handleFailure) ); } @@ -117,6 +118,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm._retirement_repository = _.find(vm.repositories, {id: vm[vm.model].retirement_repository_id}); vm._provisioning_repository = _.find(vm.repositories, {id: vm[vm.model].provisioning_repository_id}); }) + .catch(miqService.handleFailure) ); // list of machine credentials @@ -126,6 +128,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm._retirement_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].retirement_machine_credential_id}); vm._provisioning_machine_credential = _.find(vm.machine_credentials, {id: vm[vm.model].provisioning_machine_credential_id}); }) + .catch(miqService.handleFailure) ); // list of network credentials @@ -135,10 +138,8 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm._retirement_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].retirement_network_credential_id}); vm._provisioning_network_credential = _.find(vm.network_credentials, {id: vm[vm.model].provisioning_network_credential_id}); }) + .catch(miqService.handleFailure) ); - - $q.all(allApiPromises) - .then(retrievedFormData(vm)); }; function retrievedFormData(vm) { @@ -159,6 +160,7 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ vm.cloudTypes = getSortedHash(cloudTypes); cloudCredentialsList(vm, provisionCredentialId, retirementCredentialId); }) + .catch(miqService.handleFailure) ); $q.all(allApiPromises) .then(retrievedFormData(vm)); @@ -166,19 +168,21 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ // get playbooks for selected repository var repositoryChanged = function(vm, prefix, id) { - API.get('/api/configuration_script_sources/' + id + '/configuration_script_payloads?expand=resources&filter[]=region_number=' + vm.currentRegion + sortOptions).then(function(data) { - vm[prefix + '_playbooks'] = data.resources; - // if repository has changed - if (id !== vm[vm.model][prefix + '_repository_id']) { - vm[vm.model][prefix + '_playbook_id'] = ''; - vm[vm.model][prefix + '_repository_id'] = id; - if (vm[vm.model].retirement_remove_resources !== undefined) { - getRemoveResourcesTypes(); + API.get('/api/configuration_script_sources/' + id + '/configuration_script_payloads?expand=resources&filter[]=region_number=' + vm.currentRegion + sortOptions) + .then(function(data) { + vm[prefix + '_playbooks'] = data.resources; + // if repository has changed + if (id !== vm[vm.model][prefix + '_repository_id']) { + vm[vm.model][prefix + '_playbook_id'] = ''; + vm[vm.model][prefix + '_repository_id'] = id; + if (vm[vm.model].retirement_remove_resources !== undefined) { + getRemoveResourcesTypes(); + } + } else { + findObjectForDropDown(prefix, '_playbook', '_playbooks', vm); } - } else { - findObjectForDropDown(prefix, '_playbook', '_playbooks', vm); - } - }); + }) + .catch(miqService.handleFailure); }; var getRemoveResourcesTypes = function(vm) { diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 733e346553f..bde37b97837 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -976,7 +976,7 @@ def form_method_field_changed end def method_form_fields - method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find_by(:id => params[:id]) + method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find(params[:id]) data = method.data ? YAML.load(method.data) : {} method_hash = { :name => method.name, From 7c2369a324a0111427b749f24d418da020e2c0df Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Tue, 26 Sep 2017 09:42:16 -0400 Subject: [PATCH 15/19] Made a minor fix to validate unique input parameter name. https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 4287fbb83ba..87f8e93526c 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -178,7 +178,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a }); vm.addKeyValue = function() { - var valid = validateInputName(vm.aeMethodModel.provisioning_key, 0); + var valid = validateInputName(vm.aeMethodModel.provisioning_key, 0, "add"); if (! valid) { return miqService.miqFlash("error", __("Inputs name must be unique")); } @@ -219,7 +219,7 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a }; vm.saveKeyValue = function(index) { - var valid = validateInputName(vm.aeMethodModel.key, index); + var valid = validateInputName(vm.aeMethodModel.key, index, "edit"); if (! valid) { return miqService.miqFlash("error", __("Input Name must be unique")); } @@ -231,12 +231,12 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a return true; }; - var validateInputName = function(inputName, index) { + var validateInputName = function(inputName, index, type) { var valid = true; - vm.aeMethodModel.provisioning_inputs.forEach(function(input) { + vm.aeMethodModel.provisioning_inputs.forEach(function(input, i) { // validate input name if input name is changed for current input parameter // or when new one is being added - if (inputName !== vm.aeMethodModel.provisioning_inputs[index][0] && input[0] === inputName) { + if ((type === "add" && input[0] === inputName) || (type === "edit" && index !== i && input[0] === inputName)) { valid = false; } }); From 634324e142669ac010342bf110ab3ccc22ab2ff0 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Thu, 28 Sep 2017 15:20:17 -0400 Subject: [PATCH 16/19] Attempt to address code climate warning. Hoping to fix code climate warning for "Avoid using a variable and instead use chaining with the getter syntax." https://www.pivotaltracker.com/story/show/149747321 --- .../controllers/miq_ae_class/ae_method_form_controller.js | 7 +++++-- .../controllers/playbook-reusable-code-mixin.js | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 87f8e93526c..39a4ed5a475 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -1,4 +1,7 @@ -ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'aeMethodFormId', 'currentRegion', 'miqService', 'playbookReusableCodeMixin', function($http, $scope, aeMethodFormId, currentRegion, miqService, playbookReusableCodeMixin) { +ManageIQ.angular.app.controller('aeMethodFormController', aeMethodFormController); +aeMethodFormController.$inject = ['$http', '$scope', 'aeMethodFormId', 'currentRegion', 'miqService', 'playbookReusableCodeMixin']; + +function aeMethodFormController($http, $scope, aeMethodFormId, currentRegion, miqService, playbookReusableCodeMixin) { var vm = this; var init = function() { vm.aeMethodModel = { @@ -257,4 +260,4 @@ ManageIQ.angular.app.controller('aeMethodFormController', ['$http', '$scope', 'a } init(); -}]); +} diff --git a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js index 57aa4686856..af5ef2db659 100644 --- a/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js +++ b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js @@ -1,4 +1,7 @@ -ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqService', function(API, $q, miqService) { +ManageIQ.angular.app.service('playbookReusableCodeMixin', playbookReusableCodeMixin); +playbookReusableCodeMixin.$inject = ['API', '$q', 'miqService']; + +function playbookReusableCodeMixin(API, $q, miqService) { var sortOptions = "&sort_by=name&sort_order=ascending"; var allApiPromises = []; @@ -230,4 +233,4 @@ ManageIQ.angular.app.service('playbookReusableCodeMixin', ['API', '$q', 'miqServ repositoryChanged: repositoryChanged, setIfDefined: setIfDefined, }; -}]); +} From b824f1936d759d25e26c268028250919ced4d3a4 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 2 Oct 2017 11:53:58 -0400 Subject: [PATCH 17/19] Replaced YAML.load with YAML.safe_load to address Hakiri warning. https://www.pivotaltracker.com/story/show/149747321 --- app/controllers/miq_ae_class_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index bde37b97837..ca829f6c5b0 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -977,7 +977,15 @@ def form_method_field_changed def method_form_fields method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find(params[:id]) - data = method.data ? YAML.load(method.data) : {} + whitelist_symbols = [:repository_id, + :playbook_id, + :credential_id, + :network_credential_id, + :cloud_credential_id, + :verbosity, + :become_enabled] + data = method.data ? YAML.safe_load(method.data, [Symbol], whitelist_symbols, false, nil) : {} + method_hash = { :name => method.name, :display_name => method.display_name, From b24d48d92d0e4c06ce18a8d22afd86c8a2b09d6a Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 2 Oct 2017 12:25:25 -0400 Subject: [PATCH 18/19] Addressed other rubocop/pr review comments https://www.pivotaltracker.com/story/show/149747321 --- .../miq_ae_class/ae_method_form_controller.js | 2 +- app/controllers/application_controller.rb | 12 ++++++------ app/controllers/miq_ae_class_controller.rb | 11 +++++++++-- .../angular/_ansible_form_options_angular.html.haml | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js index 39a4ed5a475..da9b724ca3d 100644 --- a/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -70,7 +70,7 @@ function aeMethodFormController($http, $scope, aeMethodFormId, currentRegion, mi vm.aeMethodModel.provisioning_machine_credential_id = configData.credential_id; vm.aeMethodModel.provisioning_network_credential_id = configData.network_credential_id; vm.aeMethodModel.provisioning_cloud_credential_id = playbookReusableCodeMixin.setIfDefined(configData.cloud_credential_id); - vm.aeMethodModel.provisioning_become_enabled = configData.become_enabled === 'true' ? true : false; + vm.aeMethodModel.provisioning_become_enabled = configData.become_enabled === 'true'; vm.aeMethodModel.provisioning_key = ''; vm.aeMethodModel.provisioning_value = ''; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 55420c82671..218e37ae32d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2344,12 +2344,12 @@ def fetch_name_from_object(klass, id) def verbosity_display(verbosity) verbosity ||= "0" verbosity_hsh = { - "0" => "0 (Normal)", - "1" => "1 (Verbose)", - "2" => "2 (More Verbose)", - "3" => "3 (Debug)", - "4" => "4 (Connection Debug)", - "5" => "5 (WinRM Debug)" + "0" => _("0 (Normal)"), + "1" => _("1 (Verbose)"), + "2" => _("2 (More Verbose)"), + "3" => _("3 (Debug)"), + "4" => _("4 (Connection Debug)"), + "5" => _("5 (WinRM Debug)") } verbosity_hsh[verbosity.to_s] end diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index ca829f6c5b0..81394c138e0 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -1166,7 +1166,7 @@ def add_update_method method.language = params["language"] method.scope = params["scope"] method.class_id = params[:class_id] - method.data = YAML.dump(set_playbook_data) + method.data = YAML.dump(set_playbook_data) begin MiqAeMethod.transaction do to_save, to_delete = playbook_inputs(method) @@ -2688,7 +2688,14 @@ def get_method_node_info(id) def fetch_playbook_details @playbook_details = {} - data = YAML.load(@record.data) + whitelist_symbols = [:repository_id, + :playbook_id, + :credential_id, + :network_credential_id, + :cloud_credential_id, + :verbosity, + :become_enabled] + data = YAML.safe_load(@record.data, [Symbol], whitelist_symbols, false, nil) @playbook_details[:repository] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ConfigurationScriptSource, data[:repository_id]) @playbook_details[:playbook] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::Playbook, data[:playbook_id]) @playbook_details[:machine_credential] = fetch_name_from_object(ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential, data[:credential_id]) diff --git a/app/views/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index 5bf1154c306..b37aa33057b 100644 --- a/app/views/layouts/angular/_ansible_form_options_angular.html.haml +++ b/app/views/layouts/angular/_ansible_form_options_angular.html.haml @@ -107,7 +107,7 @@ "checkchange" => true} %span.help-block{"ng-show" => "angularForm.#{prefix}_inventory.$error.miqrequired"} = _("Required") - .form-group{"ng-if" =>"#{ng_model}.#{prefix}_execution_ttl!==undefined","ng-class" => "{'has-error': angularForm.#{prefix}_execution_ttl.$invalid}"} + .form-group{"ng-if" =>"#{ng_model}.#{prefix}_execution_ttl!==undefined", "ng-class" => "{'has-error': angularForm.#{prefix}_execution_ttl.$invalid}"} %label.col-md-3.control-label{"for" => "#{prefix}_execution_ttl"} = _("Max TTL (mins)") .col-md-9 From d24f42314d116879223f6921cff22bf19767d6e4 Mon Sep 17 00:00:00 2001 From: Harpreet Kataria Date: Mon, 2 Oct 2017 13:59:28 -0400 Subject: [PATCH 19/19] Added helper method to use while display data in view. - Addressed more PR review comments - Fixed broken spec test https://www.pivotaltracker.com/story/show/149747321 --- app/controllers/application_controller.rb | 1 + app/controllers/miq_ae_class_controller.rb | 18 +++--- app/helpers/view_formatting_helper.rb | 13 ++++ .../miq_ae_class/_method_inputs.html.haml | 60 ++++--------------- .../_method_inputs.html.haml_spec.rb | 1 + 5 files changed, 34 insertions(+), 59 deletions(-) create mode 100644 app/helpers/view_formatting_helper.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 218e37ae32d..a59ab500d53 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -39,6 +39,7 @@ class ApplicationController < ActionController::Base helper JsHelper helper QuadiconHelper helper ImageEncodeHelper + helper ViewFormattingHelper helper CloudResourceQuotaHelper diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 81394c138e0..737f4723b68 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -1733,16 +1733,14 @@ def playbook_inputs(method) end def set_playbook_data - data = { - :repository_id => params['repository_id'], - :playbook_id => params['playbook_id'], - :credential_id => params['credential_id'], - :become_enabled => params['become_enabled'], - :verbosity => params['verbosity'], - } - data[:network_credential_id] = params['network_credential_id'] if params['network_credential_id'] - data[:cloud_credential_id] = params['cloud_credential_id'] if params['cloud_credential_id'] - data + params_list = %i(repository_id + playbook_id + credential_id + become_enabled + verbosity + network_credential_id + cloud_credential_id) + copy_params_if_set({}, params, params_list) end def angular_form_specific_data diff --git a/app/helpers/view_formatting_helper.rb b/app/helpers/view_formatting_helper.rb new file mode 100644 index 00000000000..185a66b911c --- /dev/null +++ b/app/helpers/view_formatting_helper.rb @@ -0,0 +1,13 @@ +module ViewFormattingHelper + def format_form_group(label, value = nil) + output = content_tag(:label, :class => "col-md-2 control-label") do + _(label) + end + output << content_tag(:div, :class => "col-md-8") do + content_tag(:p, :class => "form-control-static") do + value + end + end + output + end +end diff --git a/app/views/miq_ae_class/_method_inputs.html.haml b/app/views/miq_ae_class/_method_inputs.html.haml index 8fd3bfd62a8..b1d797c4650 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -10,35 +10,15 @@ = _('Main Info') .form-horizontal.static .form-group - %label.col-md-2.control-label - = _('Type') - .col-md-8 - %p.form-control-static - = @ae_method.location + = format_form_group(_('Type'), @ae_method.location) .form-group - %label.col-md-2.control-label - = Dictionary.gettext('fqname', :type => :column, :notfound => :titleize) - .col-md-8 - %p.form-control-static - = h(@sb[:namespace_path]) + = format_form_group(Dictionary.gettext('fqname', :type => :column, :notfound => :titleize), @sb[:namespace_path]) .form-group - %label.col-md-2.control-label - = _('Name') - .col-md-8 - %p.form-control-static - = @ae_method.name + = format_form_group(_('Name'), @ae_method.name) .form-group - %label.col-md-2.control-label - = _('Display Name') - .col-md-8 - %p.form-control-static - = @ae_method.display_name + = format_form_group(_('Display Name'), @ae_method.display_name) .form-group - %label.col-md-2.control-label - = _('Created On') - .col-md-8 - %p.form-control-static - = h(format_timezone(@ae_method.created_on, Time.zone, "gtl")) + = format_form_group(_('Created On'), format_timezone(@ae_method.created_on, Time.zone, "gtl")) = render :partial => "domain_overrides", :locals => {:node_prefix => "aem", :model => "Method"} %h3= (@ae_method.location == 'builtin') ? _('Builtin name') : _('Data') - if @ae_method.location == "inline" @@ -59,35 +39,17 @@ - elsif @ae_method.location == 'playbook' .form-horizontal.static .form-group - %label.col-md-2.control-label - = _('Repository') - .col-md-8 - = h(@playbook_details[:repository]) + = format_form_group(_('Repository'), @playbook_details[:repository]) .form-group - %label.col-md-2.control-label - = _('Playbook') - .col-md-8 - = h(@playbook_details[:playbook]) + = format_form_group(_('Playbook'), @playbook_details[:playbook]) .form-group - %label.col-md-2.control-label - = _('Machine Credential') - .col-md-8 - = h(@playbook_details[:machine_credential]) + = format_form_group(_('Machine Credential'), @playbook_details[:machine_credential]) .form-group - %label.col-md-2.control-label - = _('Cloud Credential') - .col-md-8 - = h(@playbook_details[:cloud_credential]) + = format_form_group(_('Cloud Credential'), @playbook_details[:cloud_credential]) .form-group - %label.col-md-2.control-label - = _('Escalate Privilege') - .col-md-8 - = h(@playbook_details[:become_enabled]) + = format_form_group(_('Escalate Privilege'), @playbook_details[:become_enabled]) .form-group - %label.col-md-2.control-label - = _('Verbosity') - .col-md-8 - = h(verbosity_display(@playbook_details[:verbosity])) + = format_form_group(_('Verbosity'), verbosity_display(@playbook_details[:verbosity])) - else = @ae_method.data -# show inputs parameters grid if there are any inputs diff --git a/spec/views/miq_ae_class/_method_inputs.html.haml_spec.rb b/spec/views/miq_ae_class/_method_inputs.html.haml_spec.rb index b3c3edf25a3..486a2506f36 100644 --- a/spec/views/miq_ae_class/_method_inputs.html.haml_spec.rb +++ b/spec/views/miq_ae_class/_method_inputs.html.haml_spec.rb @@ -1,5 +1,6 @@ describe "miq_ae_class/_method_inputs.html.haml" do include Spec::Support::AutomationHelper + helper(ViewFormattingHelper) context 'display method inputs' do before do