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..3723a676f9d 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,22 +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); - vm.afterGet = true; + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.formCloudCredentials(vm, null, null); vm.modelCopy = angular.copy(vm.catalogItemModel); } else { vm.newRecord = false; @@ -66,65 +64,20 @@ 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); }); } }; - 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 +102,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 +119,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 +134,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 +152,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 +249,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 +259,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); + playbookReusableCodeMixin.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 +292,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 +324,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 +373,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 +386,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 +401,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 +416,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 new file mode 100644 index 00000000000..da9b724ca3d --- /dev/null +++ b/app/assets/javascripts/controllers/miq_ae_class/ae_method_form_controller.js @@ -0,0 +1,263 @@ +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 = { + name: '', + display_name: '', + location: '', + namespace_path: '', + class_id: '', + language: '', + scope: '', + key: '', + key_value: '', + key_type: 'string', + available_datatypes: '', + provisioning_repository_id: '', + provisioning_playbook_id: '', + provisioning_machine_credential_id: '', + provisioning_network_credential_id: '', + provisioning_cloud_credential_id: '', + provisioning_key: '', + provisioning_value: '', + provisioning_type: 'string', + provisioning_inputs: [], + provisioning_verbosity: '0', + provisioning_editMode: false, + provisioning_become_enabled: false, + }; + vm.verbosity_types = playbookReusableCodeMixin.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); + vm.saveable = miqService.saveable; + vm.newRecord = aeMethodFormId === 'new'; + if (aeMethodFormId === 'new') { + playbookReusableCodeMixin.formOptions(vm); + } + }; + + 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.aeMethodModel.available_datatypes = data.available_datatypes; + playbookReusableCodeMixin.formOptions(vm); + playbookReusableCodeMixin.formCloudCredentials(vm, data.config_info.cloud_credential_id, null); + getConfigInfo(data.config_info); + vm.modelCopy = angular.copy(vm.aeMethodModel); + } + + 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_become_enabled = configData.become_enabled === 'true'; + vm.aeMethodModel.provisioning_key = ''; + vm.aeMethodModel.provisioning_value = ''; + + if (configData.verbosity === undefined || configData.verbosity === '') { + vm.aeMethodModel.provisioning_verbosity = '0'; + } else { + vm.aeMethodModel.provisioning_verbosity = configData.verbosity; + } + setExtraVars('provisioning_inputs', configData.extra_vars); + }; + + var setExtraVars = function(variableName, extraVars) { + if (extraVars !== 'undefined') { + vm.aeMethodModel[variableName] = []; + extraVars.forEach(function(arrayItem) { + var inputVars = [arrayItem.name, arrayItem.default_value, arrayItem.datatype, arrayItem.id]; + vm.aeMethodModel[variableName].push(inputVars); + }); + } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }; + + vm.resetClicked = function() { + vm.aeMethodModel = angular.copy(vm.modelCopy); + 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")); + }; + + var methodEditButtonClicked = function(buttonName) { + miqService.sparkleOn(); + var url = '/miq_ae_class/add_update_method/' + aeMethodFormId + '?button=' + buttonName; + miqService.miqAjaxButton(url, setConfigInfo(vm.aeMethodModel, vm.modelCopy)); + }; + + vm.cancelClicked = function() { + methodEditButtonClicked('cancel'); + $scope.angularForm.$setPristine(true); + }; + + vm.saveClicked = function() { + methodEditButtonClicked('save'); + $scope.angularForm.$setPristine(true); + }; + + vm.addClicked = function() { + methodEditButtonClicked('add'); + $scope.angularForm.$setPristine(true); + }; + + var setConfigInfo = function(configData) { + 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, + verbosity: configData.provisioning_verbosity, + become_enabled: configData.provisioning_become_enabled, + extra_vars: configData.provisioning_inputs, + }; + 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; + }; + + $scope.$watch('vm._provisioning_repository', function(value) { + if (value) { + playbookReusableCodeMixin.repositoryChanged(vm, 'provisioning', value.id); + } else { + vm.aeMethodModel.provisioning_repository_id = ''; + } + 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) { + vm.aeMethodModel.key_value = ''; + } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }); + + $scope.$watch('vm.aeMethodModel.provisioning_type', function(value) { + if (value) { + vm.aeMethodModel.provisioning_value = ''; + } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }); + + vm.fieldsRequired = function(prefix) { + return prefix === 'provisioning'; + }; + + $scope.$watch('vm._provisioning_cloud_type', function(value) { + playbookReusableCodeMixin.cloudTypeChanged(vm, 'provisioning', value); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }); + + vm.addKeyValue = function() { + var valid = validateInputName(vm.aeMethodModel.provisioning_key, 0, "add"); + if (! valid) { + return miqService.miqFlash("error", __("Inputs name must be unique")); + } + 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() { + return vm.aeMethodModel.provisioning_repository_id !== ''; + }; + + vm.removeKeyValue = function(index) { + vm.aeMethodModel.provisioning_inputs.splice(index, 1); + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }; + + 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 = keyValue; + vm.aeMethodModel.key_type = keyType; + vm.aeMethodModel.original_key = key; + 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][1] = vm.aeMethodModel.original_key_value; + vm.aeMethodModel.provisioning_inputs[index][2] = vm.aeMethodModel.original_key_type; + }; + + vm.saveKeyValue = function(index) { + var valid = validateInputName(vm.aeMethodModel.key, index, "edit"); + 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; + return true; + }; + + var validateInputName = function(inputName, index, type) { + var valid = true; + 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 ((type === "add" && input[0] === inputName) || (type === "edit" && index !== i && input[0] === inputName)) { + valid = false; + } + }); + return valid; + }; + + // 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) { + var fieldName = "vm._" + name; + $scope.$watch(fieldName, function(value) { + if (value) { + vm.aeMethodModel[name + '_id'] = value.id; + } + playbookReusableCodeMixin.checkFormPristine(vm.aeMethodModel, vm.modelCopy, $scope.angularForm); + }); + } + + init(); +} 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..af5ef2db659 --- /dev/null +++ b/app/assets/javascripts/controllers/playbook-reusable-code-mixin.js @@ -0,0 +1,236 @@ +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 = []; + + 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; + allApiPromises.push(API.get(url) + .then(function(data) { + vm[prefix + '_cloud_credentials'] = data.resources; + findObjectForDropDown(prefix, '_cloud_credential', '_cloud_credentials', vm); + }) + .catch(miqService.handleFailure) + ); + }; + + 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; + 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); + } + }) + .catch(miqService.handleFailure) + ); + }; + + // list of service catalogs + var formOptions = function(vm) { + miqService.sparkleOn(); + if (vm[vm.model].catalog_id !== undefined) { + 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}); + }) + .catch(miqService.handleFailure) + ); + } + + // list of service dialogs + if (vm[vm.model].provisioning_dialog_id !== undefined) { + 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}); + }) + .catch(miqService.handleFailure) + ); + } + + // list of repositories + 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}); + }) + .catch(miqService.handleFailure) + ); + + // list of machine credentials + 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}); + }) + .catch(miqService.handleFailure) + ); + + // list of network credentials + 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}); + }) + .catch(miqService.handleFailure) + ); + }; + + function retrievedFormData(vm) { + vm.afterGet = true; + miqService.sparkleOff(); + } + + // list of cloud credentials + var formCloudCredentials = function(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); + }) + .catch(miqService.handleFailure) + ); + $q.all(allApiPromises) + .then(retrievedFormData(vm)); + }; + + // 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); + } + }) + .catch(miqService.handleFailure); + }; + + 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 6064c9270d2..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 @@ -1794,6 +1795,35 @@ def build_created_audit(rec, eh) } end + 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} + 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) @@ -2275,7 +2305,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) @@ -2307,4 +2337,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/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 b4129e356c0..737f4723b68 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") @@ -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) @@ -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 @@ -497,8 +497,12 @@ def edit_method id = x_node.split('-') end @ae_method = find_record_with_rbac(MiqAeMethod, from_cid(id[1])) - set_method_form_vars - @in_a_form = true + 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 @@ -899,10 +903,17 @@ 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' - 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" + 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]) + page.replace_html(@refresh_div, :partial => @refresh_partial) + end + if params[:cls_field_datatype] if session[:field_data][:datatype] == "password" page << javascript_hide("cls_field_default_value") @@ -964,6 +975,40 @@ def form_method_field_changed end end + def method_form_fields + method = params[:id] == "new" ? MiqAeMethod.new : MiqAeMethod.find(params[:id]) + 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, + :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] || '', + :network_credential_id => data[:network_credential_id] || '', + :cloud_credential_id => data[:cloud_credential_id] || '', + :verbosity => data[:verbosity], + :become_enabled => data[:become_enabled] || false, + :extra_vars => method.inputs + } + } + 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 +1147,46 @@ 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 = YAML.dump(set_playbook_data) + begin + MiqAeMethod.transaction do + to_save, to_delete = 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 + 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_angular(old_method_attributes, method, params[:button] == "add")) + replace_right_cell(:replace_trees => [:ae]) + return + end + end + end + def update_method assert_privileges("miq_ae_method_edit") return unless load_edit("aemethod_edit__#{params[:id]}", "replace_cell__explorer") @@ -1628,6 +1713,43 @@ 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 + 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 + @record = @ae_method + @ae_class = ae_class_for_instance_or_method(@ae_method) + @current_region = MiqRegion.my_region.region + @angular_form = true + end + def validate_expression(task) if @edit[@expkey][:expression]["???"] == "???" add_flash(_("Error during '%{task}': Expression element is required") % {:task => _(task)}, :error) @@ -2195,7 +2317,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 @@ -2556,11 +2677,33 @@ 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 = {} + 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]) + @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 + end + def get_class_node_info(id) @sb[:active_tab] = "instances" if !@in_a_form && !params[:button] && !params[:pressed] begin 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/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/layouts/angular/_ansible_form_options_angular.html.haml b/app/views/layouts/angular/_ansible_form_options_angular.html.haml index a914cbc3969..b37aa33057b 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')}>" @@ -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 @@ -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 @@ -120,8 +119,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") @@ -138,9 +136,10 @@ %label.col-md-3.control-label = _('Verbosity') .col-md-9 - %select{"ng-model" => "vm.catalogItemModel.#{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" => "", 'pf-select' => true} - if prefix == "retirement" @@ -148,12 +147,13 @@ %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} - .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,13 +217,13 @@ %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"} - 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 @@ -259,3 +259,8 @@ "checkchange" => ""} %span.help-block{"ng-show" => "angularForm.#{prefix}_dialog_name.$error.$invalid"} = _("Required") + +.row{'ng-if' => "#{ng_model}.#{prefix}_inputs"} + = render :partial => "miq_ae_class/angular_inputs_form", + :locals => {:ng_model => "vm.aeMethodModel", + :prefix => "provisioning"} 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/_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"} 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..a848434c34b --- /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/generic_form_buttons" + +: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/_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_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..b1d797c4650 100644 --- a/app/views/miq_ae_class/_method_inputs.html.haml +++ b/app/views/miq_ae_class/_method_inputs.html.haml @@ -1,38 +1,24 @@ #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 .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" @@ -50,6 +36,20 @@ :read_only => true} - elsif @ae_method.location == 'expression' = @expression + - elsif @ae_method.location == 'playbook' + .form-horizontal.static + .form-group + = format_form_group(_('Repository'), @playbook_details[:repository]) + .form-group + = format_form_group(_('Playbook'), @playbook_details[:playbook]) + .form-group + = format_form_group(_('Machine Credential'), @playbook_details[:machine_credential]) + .form-group + = format_form_group(_('Cloud Credential'), @playbook_details[:cloud_credential]) + .form-group + = format_form_group(_('Escalate Privilege'), @playbook_details[:become_enabled]) + .form-group + = format_form_group(_('Verbosity'), verbosity_display(@playbook_details[:verbosity])) - else = @ae_method.data -# show inputs parameters grid if there are any inputs @@ -72,7 +72,3 @@ - else = record.default_value %td= record.datatype.blank? ? 'string' : record.datatype - - else - #method_form_div - = 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 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