diff --git a/awx/ui/client/features/output/details.partial.html b/awx/ui/client/features/output/details.partial.html index b2faddea97..5ad6dde62e 100644 --- a/awx/ui/client/features/output/details.partial.html +++ b/awx/ui/client/features/output/details.partial.html @@ -350,7 +350,7 @@ { + $scope.variables = $scope[variablesName]; + }); } function expand () { vm.expanded = true; } - function close () { + function close (varsFromModal, parseTypeFromModal) { + $scope.variables = varsFromModal; + $scope[variablesName] = $scope.variables; + $scope.parseType = parseTypeFromModal; + // New set of variables from the modal, reinit codemirror + ParseTypeChange({ + scope: $scope, + variable: variablesName, + parse_variable: 'parseType', + field_id: `${$scope.name}_variables`, + readOnly: $scope.disabled + }); $(CodeMirrorModalID).off('hidden.bs.modal'); $(CodeMirrorModalID).modal('hide'); $('.popover').popover('hide'); vm.expanded = false; } - vm.variables = variables; + // Adding this function b/c sometimes extra vars are returned to the + // UI as yaml (ex: "foo: bar"), and other times as a + // json-object-string (ex: "{"foo": "bar"}"). The latter typically + // occurs when host vars were system generated and not user-input + // (such as adding a cloud host); + function sanitizeVars (str) { + // Quick function to test if the host vars are a json-object-string, + // by testing if they can be converted to a JSON object w/o error. + function IsJsonString (varStr) { + try { + JSON.parse(varStr); + } catch (e) { + return false; + } + return true; + } + + if (typeof str !== 'string') { + const yamlStr = jsyaml.safeDump(str); + // jsyaml.safeDump doesn't process an empty object correctly + if (yamlStr === '{}\n') { + return '---'; + } + return yamlStr; + } + if (str === '' || str === '{}') { + return '---'; + } else if (IsJsonString(str)) { + str = JSON.parse(str); + return jsyaml.safeDump(str); + } + return str; + } + vm.name = $scope.name; - vm.modalName = `${vm.name}_modal`; vm.strings = strings; vm.expanded = false; vm.close = close; vm.expand = expand; + vm.variablesName = variablesName; + vm.parseType = $scope.parseType; if ($scope.init) { $scope.init = init; } angular.element(document).ready(() => { - init($scope.variables, $scope.name); + init(); }); } atCodeMirrorController.$inject = [ '$scope', 'CodeMirrorStrings', - 'ParseTypeChange', - 'ParseVariableString' + 'ParseTypeChange' ]; function atCodeMirrorTextarea () { @@ -77,7 +125,7 @@ function atCodeMirrorTextarea () { labelClass: '@', tooltip: '@', tooltipPlacement: '@', - variables: '@', + variables: '=', name: '@', init: '=' } diff --git a/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html b/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html index 7d149af226..4253f29a21 100644 --- a/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html +++ b/awx/ui/client/lib/components/code-mirror/code-mirror.partial.html @@ -13,26 +13,27 @@ class="help-link" data-original-title="{{ label || vm.strings.get('code_mirror.label.VARIABLES') }}" title="{{ label || vm.strings.get('code_mirror.label.VARIABLES') }}" - tabindex="-1"> + tabindex="-1" + ng-if="tooltip">
-
diff --git a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js index 4d51a7b8c4..a4051084b0 100644 --- a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js +++ b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.directive.js @@ -1,8 +1,6 @@ const templateUrl = require('~components/code-mirror/modal/code-mirror-modal.partial.html'); const CodeMirrorModalID = '#CodeMirror-modal'; -const ParseVariable = 'parseType'; -const ParseType = 'yaml'; const ModalHeight = '#CodeMirror-modal .modal-dialog'; const ModalHeader = '.atCodeMirror-label'; const ModalFooter = '.CodeMirror-modalControls'; @@ -10,11 +8,9 @@ const ModalFooter = '.CodeMirror-modalControls'; function atCodeMirrorModalController ( $scope, strings, - ParseTypeChange, - ParseVariableString + ParseTypeChange ) { const vm = this; - const variables = `${$scope.name}_variables`; function resize () { if ($scope.disabled === 'true') { $scope.disabled = true; @@ -28,29 +24,33 @@ function atCodeMirrorModalController ( } function toggle () { - $scope.parseTypeChange('parseType', variables); + $scope.parseTypeChange('modalParseType', 'modalVars'); setTimeout(resize, 0); } - function init (vars, name) { + $scope.close = () => { + $scope.closeFn({ + values: $scope.modalVars, + parseType: $scope.modalParseType, + }); + }; + + function init () { if ($scope.disabled === 'true') { $scope.disabled = true; } else if ($scope.disabled === 'false') { $scope.disabled = false; } $(CodeMirrorModalID).modal('show'); - $scope[variables] = ParseVariableString(_.cloneDeep(vars)); - $scope.parseType = ParseType; - const options = { + ParseTypeChange({ scope: $scope, - variable: variables, - parse_variable: ParseVariable, - field_id: name, + variable: 'modalVars', + parse_variable: 'modalParseType', + field_id: 'variables_modal', readOnly: $scope.disabled - }; - ParseTypeChange(options); + }); resize(); - $(CodeMirrorModalID).on('hidden.bs.modal', $scope.closeFn); + $(CodeMirrorModalID).on('hidden.bs.modal', $scope.close); $(`${CodeMirrorModalID} .modal-dialog`).resizable({ minHeight: 523, minWidth: 600 @@ -58,15 +58,13 @@ function atCodeMirrorModalController ( $(`${CodeMirrorModalID} .modal-dialog`).on('resize', resize); } - vm.variables = variables; - vm.name = $scope.name; vm.strings = strings; vm.toggle = toggle; if ($scope.init) { $scope.init = init; } angular.element(document).ready(() => { - init($scope.variables, $scope.name); + init($scope.variablesName, $scope.name); }); } @@ -74,7 +72,6 @@ atCodeMirrorModalController.$inject = [ '$scope', 'CodeMirrorStrings', 'ParseTypeChange', - 'ParseVariableString', ]; function atCodeMirrorModal () { @@ -90,7 +87,8 @@ function atCodeMirrorModal () { label: '@', labelClass: '@', tooltip: '@', - variables: '@', + modalVars: '=', + modalParseType: '=', name: '@', closeFn: '&' } diff --git a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html index 9785f439f8..96d31dbd7d 100644 --- a/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html +++ b/awx/ui/client/lib/components/code-mirror/modal/code-mirror-modal.partial.html @@ -21,20 +21,20 @@
-
@@ -55,15 +55,15 @@
diff --git a/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js b/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js index 3cd6a00c28..219cee0b07 100644 --- a/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/hosts/edit/host-edit.controller.js @@ -42,43 +42,8 @@ $rootScope.breadcrumb.host_name = host.data.name; $scope.name = host.data.name; $scope.description = host.data.description; - $scope.variables = getVars(host.data.variables); - ParseTypeChange({ - scope: $scope, - field_id: 'host_variables', - variable: 'variables', - }); + $scope.variables = host.data.variables; }; - // Adding this function b/c sometimes extra vars are returned to the - // UI as a string (ex: "foo: bar"), and other times as a - // json-object-string (ex: "{"foo": "bar"}"). CodeMirror wouldn't know - // how to prettify the latter. The latter occurs when host vars were - // system generated and not user-input (such as adding a cloud host); - function getVars(str){ - - // Quick function to test if the host vars are a json-object-string, - // by testing if they can be converted to a JSON object w/o error. - function IsJsonString(str) { - try { - JSON.parse(str); - } catch (e) { - return false; - } - return true; - } - - if(str === ''){ - return '---'; - } - else if(IsJsonString(str)){ - str = JSON.parse(str); - return jsyaml.safeDump(str); - } - else if(!IsJsonString(str)){ - return str; - } - } - init(); }]; diff --git a/awx/ui/client/src/inventories-hosts/hosts/host.form.js b/awx/ui/client/src/inventories-hosts/hosts/host.form.js index f66f48b4df..64a1c88db9 100644 --- a/awx/ui/client/src/inventories-hosts/hosts/host.form.js +++ b/awx/ui/client/src/inventories-hosts/hosts/host.form.js @@ -66,20 +66,17 @@ function(i18n) { }, variables: { label: i18n._('Variables'), - type: 'textarea', - rows: 6, + type: 'code_mirror', + variables: 'variables', class: 'Form-formGroup--fullWidth', "default": "---", awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "
{
 "somevar": "somevalue",
 "password": "magic"
}
\n" + "YAML:
\n" + "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Host Variables'), - dataPlacement: 'right', - dataContainer: 'body' + '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + + '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', } }, diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js index 52661b4129..81755c1b17 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/edit/host-edit.controller.js @@ -39,43 +39,8 @@ $scope.name = host.name; $rootScope.breadcrumb.host_name = host.name; $scope.description = host.description; - $scope.host_variables = getVars(host.variables); - ParseTypeChange({ - scope: $scope, - field_id: 'host_host_variables', - variable: 'host_variables', - }); + $scope.host_variables = host.variables; }; - // Adding this function b/c sometimes extra vars are returned to the - // UI as a string (ex: "foo: bar"), and other times as a - // json-object-string (ex: "{"foo": "bar"}"). CodeMirror wouldn't know - // how to prettify the latter. The latter occurs when host vars were - // system generated and not user-input (such as adding a cloud host); - function getVars(str){ - - // Quick function to test if the host vars are a json-object-string, - // by testing if they can be converted to a JSON object w/o error. - function IsJsonString(str) { - try { - JSON.parse(str); - } catch (e) { - return false; - } - return true; - } - - if(str === ''){ - return '---'; - } - else if(IsJsonString(str)){ - str = JSON.parse(str); - return jsyaml.safeDump(str); - } - else if(!IsJsonString(str)){ - return str; - } - } - init(); }]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js index f368af8329..2d8616e87f 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js @@ -66,20 +66,26 @@ function(i18n) { }, host_variables: { label: i18n._('Variables'), - type: 'textarea', - rows: 6, + type: 'code_mirror', class: 'Form-formGroup--fullWidth', "default": "---", - awPopOver: "

" + i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + - "JSON:
\n" + - "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + - "YAML:
\n" + - "
---
somevar: somevalue
password: magic
\n" + - '

' + i18n.sprintf(i18n._('View JSON examples at %s'), 'www.json.org') + '

' + - '

' + i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com') + '

', - dataTitle: i18n._('Host Variables'), - dataPlacement: 'right', - dataContainer: 'body', + variables: 'host_variables', + awPopOver: `

${i18n._("Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two.")}

+ JSON:
+
+ {
 "somevar": "somevalue",
 "password": "magic"
} +
+ YAML:
+
+ ---
+ somevar: somevalue
+ password: magic
+
+

${i18n.sprintf(i18n._( + 'View JSON examples at %s'), + 'www.json.org' + )}

+

${i18n.sprintf(i18n._('View YAML examples at %s'), 'docs.ansible.com')}

`, ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd) || isSmartInvHost' } }, diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js index 8f96ae9f6f..ce2d8e7ea7 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js @@ -40,13 +40,6 @@ function InventoriesEdit($scope, $location, $scope.instance_groups = InstanceGroupsData; $scope.canRemediate = CanRemediate; - ParseTypeChange({ - scope: $scope, - variable: 'inventory_variables', - parse_variable: 'parseType', - field_id: 'inventory_inventory_variables' - }); - OrgAdminLookup.checkForRoleLevelAdminAccess(inventoryData.organization, 'inventory_admin_role') .then(function(canEditOrg){ $scope.canEditOrg = canEditOrg; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js index 7e8083bf48..3cf7629f1d 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js @@ -66,17 +66,12 @@ function(i18n) { dataContainer: 'body', control: '', }, - inventory_variables: { - realName: 'variables', + variables: { label: i18n._('Variables'), - type: 'textarea', + type: 'code_mirror', class: 'Form-formGroup--fullWidth', - rows: 6, - "default": "---", + variables: 'variables', awPopOver: i18n._('Enter inventory variables using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.'), - dataTitle: i18n._('Variables'), - dataPlacement: 'right', - dataContainer: 'body', ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working } }, diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js index 2f99c6a075..a4ab5f1024 100644 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js +++ b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.controller.js @@ -4,25 +4,17 @@ * All Rights Reserved *************************************************/ -function AnsibleFacts($scope, Facts, ParseTypeChange, ParseVariableString) { +function AnsibleFacts($scope, Facts) { function init() { - $scope.facts = ParseVariableString(Facts); + $scope.facts = Facts; let rows = (_.isEmpty(Facts)) ? 6 : 20; $("#host_facts").attr("rows", rows); $scope.parseType = 'yaml'; - ParseTypeChange({ - scope: $scope, - variable: 'facts', - parse_variable: 'parseType', - field_id: 'host_facts', - readOnly: true - }); } init(); } -export default ['$scope', 'Facts', 'ParseTypeChange', 'ParseVariableString', AnsibleFacts -]; +export default ['$scope', 'Facts', AnsibleFacts]; diff --git a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html index 5cb0ac2162..7976a5cb5d 100644 --- a/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html +++ b/awx/ui/client/src/inventories-hosts/shared/ansible-facts/ansible-facts.partial.html @@ -1,10 +1,12 @@
- -
- -
+
diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index c1b4d7f35f..5387fca4f5 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1364,6 +1364,18 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += "
\n"; } + if (field.type === 'code_mirror') { + html += '