diff --git a/app/assets/javascripts/components/ansible-credential-options.js b/app/assets/javascripts/components/ansible-credential-options.js new file mode 100644 index 00000000000..0529facef41 --- /dev/null +++ b/app/assets/javascripts/components/ansible-credential-options.js @@ -0,0 +1,51 @@ +ManageIQ.angular.app.component('ansibleCredentialOptions', { + bindings: { + model: '=', + options: '<', + type: '<', + }, + + controllerAs: 'vm', + + controller: ['$scope', function($scope) { + $scope.__ = __; + + this.setOptions = function() { + this.current_options = this.options[this.type]; + }; + + this.$onInit = function() { + this.setOptions(); + }; + + this.$onChanges = function(changes) { + this.setOptions(); + }; + }], + + template: [ + '
', + '', + '
', + // password + '
', + '', + '
', + // select + '
', + '', + '
', + // default (text) + '
', + '', + '
', + '
', + '
', + ].join('\n') +}); diff --git a/app/assets/javascripts/controllers/ansible_credentials/ansible_credentials_form_controller.js b/app/assets/javascripts/controllers/ansible_credentials/ansible_credentials_form_controller.js new file mode 100644 index 00000000000..8d728d0d1c3 --- /dev/null +++ b/app/assets/javascripts/controllers/ansible_credentials/ansible_credentials_form_controller.js @@ -0,0 +1,127 @@ +ManageIQ.angular.app.controller('ansibleCredentialsFormController', ['$window', 'credentialId', 'miqService', 'API', function($window, credentialId, miqService, API) { + var vm = this; + + var init = function() { + vm.credentialModel = { + id: null, + name: '', + type: '', + }; + + vm.credential_options = {}; + vm.select_options = []; + + vm.newRecord = credentialId === 'new'; + vm.afterGet = false; + vm.model = 'credentialModel'; + ManageIQ.angular.scope = vm; + vm.saveable = miqService.saveable; + + miqService.sparkleOn(); + + // get credential specific options for all supported credential types + API.options('/api/authentications') + .then(getCredentialOptions) + .catch(miqService.handleFailure); + + if (credentialId !== 'new') { + API.get('/api/authentications/' + credentialId) + .then(getCredentialFormData) + .catch(miqService.handleFailure); + } else { + vm.select_options.push({'label':__(''), 'value': ''}); + // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged + vm.credentialModel.organization = 1; // work-around, organization id needs to be filled in automatically by the backend + + // credential creation requires manager_resource + API.get('/api/providers?collection_class=ManageIQ::Providers::EmbeddedAutomationManager') + .then(setManagerResource) + .catch(miqService.handleFailure); + + vm.afterGet = true; + vm.modelCopy = angular.copy( vm.credentialModel ); + miqService.sparkleOff(); + } + }; + + vm.cancelClicked = function(angularForm) { + if (credentialId === 'new') { + getBack(__("Creation of new Credential was canceled by the user."), true); + } else { + getBack(sprintf(__("Edit of Credential \"%s\" was canceled by the user."), vm.credentialModel.name), true); + } + }; + + vm.resetClicked = function(angularForm) { + vm.credentialModel = angular.copy( vm.modelCopy ); + angularForm.$setPristine(true); + miqService.miqFlash("warn", __("All changes have been reset")); + }; + + vm.saveClicked = function(angularForm) { + API.put('/api/authentications/' + credentialId, vm.credentialModel) + .then(getBack(sprintf(__("Modification of Credential \"%s\" has been successfully queued."), vm.credentialModel.name), false)) + .catch(miqService.handleFailure); + }; + + vm.addClicked = function(angularForm) { + addCredentialKind(); + API.post('/api/authentications/', vm.credentialModel) + .then(getBack(sprintf(__("Add of Credential \"%s\" has been successfully queued."), vm.credentialModel.name))) + .catch(miqService.handleFailure); + }; + + function getCredentialOptions(response) { + Object.assign(vm.credential_options, response.data.credential_types.embedded_ansible_credential_types); + + for (var opt in vm.credential_options) { + vm.select_options.push({'value': opt, 'label': vm.credential_options[opt].label}); + } + } + + function getCredentialFormData(response) { + vm.credentialModel.id = response.id; + vm.credentialModel.name = response.name; + vm.credentialModel.type = response.type; + + // we need to merge options and vm.credentialModel + for (var opt in response.options) { + var item = vm.credential_options[vm.credentialModel.type]['attributes'][opt]; + + // void the password fields first + if (item.hasOwnProperty('type') && item['type'] === 'password') { + vm.credentialModel[opt] = ''; + } else { + vm.credentialModel[opt] = response.options[opt]; + } + } + + vm.modelCopy = angular.copy( vm.credentialModel ); + vm.afterGet = true; + miqService.sparkleOff(); + } + + function getBack(message, warning = false, error = false) { + var url = '/ansible_credential/show_list' + '?flash_msg=' + message + '&escape=true'; + + if (warning) { + url += '&flash_warning=true&flash_error=false'; + } else if (error) { + url += '&flash_warning=false&flash_error=true'; + } + + $window.location.href = url; + } + + function setManagerResource(response) { + vm.credentialModel.manager_resource = { "href": response.resources[0].href }; + } + + // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged + // For creation, we need to send json like: {"kind": "scm", "type": "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ScmCredential"} + function addCredentialKind() { + vm.credentialModel.kind = vm.credential_options[vm.credentialModel.type].type; + } + + init(); +}]); diff --git a/app/controllers/ansible_credential_controller.rb b/app/controllers/ansible_credential_controller.rb index f6fafde672f..78d8de70f95 100644 --- a/app/controllers/ansible_credential_controller.rb +++ b/app/controllers/ansible_credential_controller.rb @@ -10,6 +10,7 @@ class AnsibleCredentialController < ApplicationController include Mixins::GenericShowMixin menu_section :ansible + toolbar :ansible_credential def self.display_methods %w(repositories) @@ -23,10 +24,51 @@ def display_repositories nested_list("repository", ManageIQ::Providers::EmbeddedAutomationManager::ConfigurationScriptSource) end + def button + if params[:pressed] == 'embedded_automation_manager_credentials_add' + javascript_redirect :action => 'new' + elsif params[:pressed] == 'embedded_automation_manager_credentials_edit' + javascript_redirect :action => 'edit', :id => from_cid(params[:miq_grid_checks]) + elsif params[:pressed] == 'embedded_automation_manager_credentials_delete' + delete_credentials + end + end + + def new + assert_privileges('embedded_automation_manager_credentials_add') + drop_breadcrumb(:name => _("Add a new Credential"), :url => "/ansible_credential/new") + @in_a_form = true + @id = 'new' + end + + def edit + assert_privileges('embedded_automation_manager_credentials_edit') + auth = ManageIQ::Providers::EmbeddedAutomationManager::Authentication.find(params[:id].to_i) + drop_breadcrumb(:name => _("Edit a Credential \"%{name}\"") % {:name => auth.name}, + :url => "/ansible_credential/edit/#{params[:id]}") + @in_a_form = true + @id = params[:id] + end + private def textual_group_list [%i(properties relationships options)] end helper_method :textual_group_list + + def delete_credentials + checked = find_checked_items + checked[0] = params[:id] if checked.blank? && params[:id] + ManageIQ::Providers::EmbeddedAutomationManager::Authentication.where(:id => checked).each do |auth| + begin + auth.delete_in_provider_queue + add_flash(_("Deletion of Credential \"%{name}\" was successfully initiated.") % {:name => auth.name}) + rescue => ex + add_flash(_("Unable to delete Credential \"%{name}\": %{details}") % {:name => auth.name, :details => ex}, :error) + end + end + session[:flash_msgs] = @flash_array + javascript_redirect :action => 'show_list' + end end diff --git a/app/helpers/application_helper/toolbar/ansible_credential_center.rb b/app/helpers/application_helper/toolbar/ansible_credential_center.rb new file mode 100644 index 00000000000..4319786bb11 --- /dev/null +++ b/app/helpers/application_helper/toolbar/ansible_credential_center.rb @@ -0,0 +1,25 @@ +class ApplicationHelper::Toolbar::AnsibleCredentialCenter < ApplicationHelper::Toolbar::Basic + button_group('ansible_repository', [ + select( + :ansible_credential_configuration, + 'fa fa-cog fa-lg', + t = N_('Configuration'), + t, + :items => [ + button( + :embedded_automation_manager_credentials_edit, + 'pficon pficon-edit fa-lg', + t = N_('Edit this Credential'), + t, + :url => "/edit"), + button( + :embedded_automation_manager_credentials_delete, + 'pficon pficon-delete fa-lg', + t = N_('Remove this Credential'), + t, + :url_parms => "&refresh=y", + :confirm => N_("Warning: The selected Credential will be permanently removed!")), + ] + ), + ]) +end diff --git a/app/helpers/application_helper/toolbar/ansible_credentials_center.rb b/app/helpers/application_helper/toolbar/ansible_credentials_center.rb new file mode 100644 index 00000000000..8b45f8c711d --- /dev/null +++ b/app/helpers/application_helper/toolbar/ansible_credentials_center.rb @@ -0,0 +1,35 @@ +class ApplicationHelper::Toolbar::AnsibleCredentialsCenter < ApplicationHelper::Toolbar::Basic + button_group('embedded_ansible_credentials', [ + select( + :embedded_ansible_credentials_configuration, + 'fa fa-cog fa-lg', + t = N_('Configuration'), + t, + :items => [ + button( + :embedded_automation_manager_credentials_add, + 'pficon pficon-edit fa-lg', + t = N_('Add New Credential'), + t, + :url_parms => "new_div"), + button( + :embedded_automation_manager_credentials_edit, + 'pficon pficon-edit fa-lg', + t = N_('Edit this Credential'), + t, + :enabled => false, + :onwhen => "1", + :url_parms => "edit_div"), + button( + :embedded_automation_manager_credentials_delete, + 'pficon pficon-delete fa-lg', + t = N_('Remove selected Credentials'), + t, + :url_parms => "delete_div", + :enabled => false, + :onwhen => "1+", + :confirm => N_("Warning: The selected Credentials will be permanently removed!")), + ] + ) + ]) +end diff --git a/app/views/ansible_credential/_credential_form.html.haml b/app/views/ansible_credential/_credential_form.html.haml new file mode 100644 index 00000000000..83eb78fe86e --- /dev/null +++ b/app/views/ansible_credential/_credential_form.html.haml @@ -0,0 +1,47 @@ +%br +.form-horizontal + %form#form_div{'name' => 'angularForm', + 'ng-controller' => 'ansibleCredentialsFormController as vm', + 'ng-show' => 'vm.afterGet', + 'ng-cloak' => '', + 'miq-form' => true, + 'model' => 'vm.credentialModel', + 'model-copy' => 'vm.modelCopy', + 'novalidate' => true} + = render :partial => "layouts/flash_msg" + .form-group{"ng-class" => "{'has-error': angularForm.name.$invalid}"} + %label.col-md-2.control-label + = _('Name') + .col-md-8 + %input.form-control{:type => "text", + :name => "name", + "id" => "name", + 'ng-model' => "vm.credentialModel.name", + :maxlength => MAX_NAME_LEN, + :required => true, + :checkchange => true, + "auto-focus" => ""} + %span.help-block{"ng-show" => "angularForm.name.$error.required"} + = _("Required") + .form-group + %label.col-md-2.control-label + = _('Credential type') + - if @id == 'new' # we don't allow changing auth. type when editing a resource + .col-md-8 + %select{'ng-model' => 'vm.credentialModel.type', + 'ng-options' => 'cred.value as cred.label for cred in vm.select_options', + 'required' => 'true', + 'pf-select' => 'true'} + - else + .col-md-8 + {{ vm.credential_options[vm.credentialModel.type].label }} + + %ansible-credential-options{:model => 'vm.credentialModel', + :options => 'vm.credential_options', + :type => 'vm.credentialModel.type'} + + = render :partial => 'layouts/angular/generic_form_buttons' + +:javascript + ManageIQ.angular.app.value('credentialId', '#{@id}'); + miq_bootstrap('#form_div'); diff --git a/app/views/ansible_credential/edit.html.haml b/app/views/ansible_credential/edit.html.haml new file mode 100644 index 00000000000..29d735189cb --- /dev/null +++ b/app/views/ansible_credential/edit.html.haml @@ -0,0 +1,2 @@ +#main_div + = render :partial => 'credential_form', :locals => {:newRecord => false} diff --git a/app/views/ansible_credential/new.html.haml b/app/views/ansible_credential/new.html.haml new file mode 100644 index 00000000000..c88f19c289f --- /dev/null +++ b/app/views/ansible_credential/new.html.haml @@ -0,0 +1,2 @@ +#main_div + = render :partial => 'credential_form', :locals => {:newRecord => true} diff --git a/config/routes.rb b/config/routes.rb index 1cfcda86f9b..6f63eb9c051 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2010,11 +2010,15 @@ :get => %w( download_data download_summary_pdf + edit + new show show_list ), :post => %w( - show_list) + button + show_list + ) }, :ansible_playbook => {