diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 1f68ff75ae..6e817d1a5c 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -738,7 +738,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' elem = document.getElementById('group-modal-dialog'); $compile(elem)(modal_scope); + var form_scope = generator.inject(GroupForm, { mode: 'edit', id: 'properties-tab', breadCrumbs: false, related: false, scope: properties_scope }); + var source_form_scope = generator.inject(SourceForm, { mode: 'edit', id: 'sources-tab', breadCrumbs: false, related: false, scope: sources_scope }); //generator.reset(); @@ -881,6 +883,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' modal_scope.cancelModal(); }, open: function () { + function updateButtonStatus(isValid) { + $('.ui-dialog[aria-describedby="group-modal-dialog"]').find('.btn-primary').prop('disabled', !isValid); + } + form_scope.$watch('group_form.$valid', updateButtonStatus); + source_form_scope.$watch('source_form.$valid', updateButtonStatus); $('#group_name').focus(); Wait('stop'); } diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 280e398599..df9e045bf7 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -231,543 +231,545 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H }; }]) - .factory('InjectHosts', ['GenerateList', 'InventoryHosts', 'HostsReload', - function(GenerateList, InventoryHosts, HostsReload) { - return function(params) { - - var group_scope = params.group_scope, - host_scope = params.host_scope, - inventory_id = params.inventory_id, - group_id = params.group_id, - pageSize = params.pageSize, - generator = GenerateList; - - // Inject the list html - generator.inject(InventoryHosts, { scope: host_scope, mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-6 col-md-6 col-sm-6' }); - - // Load data - HostsReload({ scope: host_scope, group_id: group_id, inventory_id: inventory_id, parent_scope: group_scope, pageSize: pageSize }); - }; - }]) - - .factory('ToggleHostEnabled', [ 'GetBasePath', 'Rest', 'Wait', 'ProcessErrors', 'Alert', 'Find', 'SetEnabledMsg', - function(GetBasePath, Rest, Wait, ProcessErrors, Alert, Find, SetEnabledMsg) { - return function(params) { - - var id = params.host_id, - external_source = params.external_source, - parent_scope = params.parent_scope, - host_scope = params.host_scope, - host; - - function setMsg(host) { - host.enabled = (host.enabled) ? false : true; - host.enabled_flag = host.enabled; - SetEnabledMsg(host); - } - - if (!external_source) { - // Host is not managed by an external source - Wait('start'); - host = Find({ list: host_scope.hosts, key: 'id', val: id }); - setMsg(host); - - Rest.setUrl(GetBasePath('hosts') + id + '/'); - Rest.put(host) - .success( function() { - Wait('stop'); - }) - .error( function(data, status) { - // Flip the enabled flag back - setMsg(host); - ProcessErrors(parent_scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to update host. PUT returned status: ' + status }); - }); - } - else { - Alert('Action Not Allowed', 'This host is managed by an external cloud source. Disable it at the external source, ' + - 'then run an inventory sync to update Tower with the new status.', 'alert-info'); - } - }; - }]) - - .factory('HostsList', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostList', 'GenerateList', - 'Prompt', 'SearchInit', 'PaginateInit', 'ProcessErrors', 'GetBasePath', 'HostsAdd', 'HostsReload', 'SelectionInit', - function($rootScope, $location, $log, $routeParams, Rest, Alert, HostList, GenerateList, Prompt, SearchInit, - PaginateInit, ProcessErrors, GetBasePath, HostsAdd, HostsReload, SelectionInit) { - return function(params) { - - var inventory_id = params.inventory_id, - group_id = params.group_id, - list = HostList, - generator = GenerateList, - defaultUrl, scope; - - list.iterator = 'subhost'; //Override the iterator and name so the scope of the modal dialog - list.name = 'subhosts'; //will not conflict with the parent scope - - - - scope = generator.inject(list, { - id: 'form-modal-body', - mode: 'select', - breadCrumbs: false, - selectButton: false - }); - - defaultUrl = GetBasePath('inventory') + inventory_id + '/hosts/?not__groups__id=' + scope.group_id; - - scope.formModalActionLabel = 'Select'; - scope.formModalHeader = 'Add Existing Hosts'; - scope.formModalCancelShow = true; - - SelectionInit({ scope: scope, list: list, url: GetBasePath('groups') + group_id + '/hosts/' }); - - if (scope.removeModalClosed) { - scope.removeModalClosed(); - } - scope.removeModalClosed = scope.$on('modalClosed', function() { - // if the modal closed, assume something got changed and reload the host list - HostsReload(params); - }); - - $('.popover').popover('hide'); //remove any lingering pop-overs - $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); - $('#form-modal').modal({ backdrop: 'static', keyboard: false }); - - SearchInit({ scope: scope, set: 'subhosts', list: list, url: defaultUrl }); - PaginateInit({ scope: scope, list: list, url: defaultUrl, mode: 'lookup' }); - scope.search(list.iterator); - - if (!scope.$$phase) { - scope.$digest(); - } - - scope.createHost = function() { - $('#form-modal').modal('hide'); - HostsAdd({ scope: params.scope, inventory_id: inventory_id, group_id: group_id }); - }; - - }; - }]) - - - .factory('HostsCreate', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'ToJSON', - function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, HostsReload, ParseTypeChange, Wait, ToJSON) { - return function(params) { - - var parent_scope = params.scope, - inventory_id = parent_scope.inventory_id, - group_id = parent_scope.selected_group_id, - defaultUrl = GetBasePath('groups') + group_id + '/hosts/', - form = HostForm, - generator = GenerateForm, - scope = generator.inject(form, {mode: 'add', modal: true, related: false}), - master={}; - - scope.formModalActionLabel = 'Save'; - scope.formModalHeader = 'Create New Host'; - scope.formModalCancelShow = true; - - scope.parseType = 'yaml'; - ParseTypeChange({ scope: scope, field_id: 'host_variables' }); - - if (scope.removeHostsReload) { - scope.removeHostsReload(); - } - scope.removeHostsReload = scope.$on('hostsReload', function() { - HostsReload(params); - }); - - $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); - //$('#form-modal').unbind('hidden'); - //$('#form-modal').on('hidden', function () { scope.$emit('hostsReload'); }); - - generator.reset(); - master={}; - - if (!scope.$$phase) { - scope.$digest(); - } - - if (scope.removeHostSaveComplete) { - scope.removeHostSaveComplete(); - } - scope.removeHostSaveComplete = scope.$on('HostSaveComplete', function() { - Wait('stop'); - $('#form-modal').modal('hide'); - - HostsReload({ - scope: parent_scope, - group_id: parent_scope.selected_group_id, - tree_id: parent_scope.selected_tree_id, - inventory_id: parent_scope.inventory_id - }); - - //WatchInventoryWindowResize(); - }); - - // Save - scope.formModalAction = function() { - - Wait('start'); - - var fld, data={}; - scope.formModalActionDisabled = true; - data.variables = ToJSON(scope.parseType, scope.variables, true); - for (fld in form.fields) { - if (fld !== 'variables') { - data[fld] = scope[fld]; - } - } - data.inventory = inventory_id; - - Rest.setUrl(defaultUrl); - Rest.post(data) - .success( function() { - scope.$emit('HostSaveComplete'); - }) - .error( function(data, status) { - Wait('stop'); - scope.formModalActionDisabled = false; - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status }); - }); - }; - - // Cancel - scope.formReset = function() { - // Defaults - generator.reset(); - }; - - scope.cancelModal = function() { - // WatchInventoryWindowResize(); - }; - - }; - }]) - - - .factory('HostsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetStatus', 'ApplyEllipsis', - 'ToJSON', 'ParseVariableString', 'CreateDialog', 'TextareaResize', - function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus, ApplyEllipsis, ToJSON, - ParseVariableString, CreateDialog, TextareaResize) { - return function(params) { - - var parent_scope = params.host_scope, - group_scope = params.group_scope, - host_id = params.host_id, - inventory_id = params.inventory_id, - mode = params.mode, // 'add' or 'edit' - selected_group_id = params.selected_group_id, - generator = GenerateForm, - form = HostForm, - defaultUrl, - scope = parent_scope.$new(), - master = {}, - relatedSets = {}, - buttons, url; - - generator.inject(HostForm, { mode: 'edit', id: 'host-modal-dialog', breadCrumbs: false, related: false, scope: scope }); - generator.reset(); - - buttons = [{ - label: "Cancel", - onClick: function() { - scope.cancelModal(); - }, - icon: "fa-times", - "class": "btn btn-default", - "id": "host-cancel-button" - },{ - label: "Save", - onClick: function() { - scope.saveModal(); - }, - icon: "fa-check", - "class": "btn btn-primary", - "id": "host-save-button" - }]; - - CreateDialog({ - scope: scope, - buttons: buttons, - width: 675, - height: 750, - minWidth: 400, - title: 'Host Properties', - id: 'host-modal-dialog', - clonseOnEscape: false, - onClose: function() { - Wait('stop'); - scope.codeMirror.destroy(); - $('#host-modal-dialog').empty(); - }, - onResizeStop: function() { - TextareaResize({ - scope: scope, - textareaId: 'host_variables', - modalId: 'host-modal-dialog', - formId: 'host_form' - }); - }, - beforeDestroy: function() { - if (scope.codeMirror) { - scope.codeMirror.destroy(); - } - $('#host-modal-dialog').empty(); - }, - onOpen: function() { - $('#host_name').focus(); - }, - callback: 'HostEditDialogReady' - }); - - scope.parseType = 'yaml'; - - if (scope.hostVariablesLoadedRemove) { - scope.hostVariablesLoadedRemove(); - } - scope.hostVariablesLoadedRemove = scope.$on('hostVariablesLoaded', function() { - $('#host-modal-dialog').dialog('open'); - setTimeout(function() { - TextareaResize({ - scope: scope, - textareaId: 'host_variables', - modalId: 'host-modal-dialog', - formId: 'host_form', - parse: true - }); - }, 300); - //ParseTypeChange({ scope: scope, field_id: 'host_variables', onReady: callback }); - }); - - if (scope.hostLoadedRemove) { - scope.hostLoadedRemove(); - } - scope.hostLoadedRemove = scope.$on('hostLoaded', function() { - // Retrieve host variables - if (scope.variable_url) { - Rest.setUrl(scope.variable_url); - Rest.get() - .success( function(data) { - scope.variables = ParseVariableString(data); - scope.$emit('hostVariablesLoaded'); - }) - .error( function(data, status) { - scope.variables = null; - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to retrieve host variables. GET returned status: ' + status }); - }); - } - else { - scope.variables = "---"; - scope.$emit('hostVariablesLoaded'); - } - master.variables = scope.variables; - }); - - Wait('start'); - - // Retrieve detail record and prepopulate the form - if (mode === 'edit') { - defaultUrl = GetBasePath('hosts') + host_id + '/'; - Rest.setUrl(defaultUrl); - Rest.get() - .success( function(data) { - var set, fld, related; - for (fld in form.fields) { - if (data[fld]) { - scope[fld] = data[fld]; - master[fld] = scope[fld]; - } - } - related = data.related; - for (set in form.related) { - if (related[set]) { - relatedSets[set] = { url: related[set], iterator: form.related[set].iterator }; - } - } - scope.variable_url = data.related.variable_data; - scope.has_inventory_sources = data.has_inventory_sources; - scope.$emit('hostLoaded'); - }) - .error( function(data, status) { - ProcessErrors(parent_scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to retrieve host: ' + host_id + '. GET returned status: ' + status }); - }); - } - else { - // Add mode - url = GetBasePath('groups') + selected_group_id + '/'; - Rest.setUrl(url); - Rest.get() - .success( function(data) { - scope.has_inventory_sources = data.has_inventory_sources; - scope.enabled = true; - scope.variables = '---'; - defaultUrl = data.related.hosts; - scope.$emit('hostVariablesLoaded'); - }) - .error( function(data, status) { - ProcessErrors(parent_scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to retrieve group: ' + selected_group_id + '. GET returned status: ' + status }); - }); - } - - if (scope.removeSaveCompleted) { - scope.removeSaveCompleted(); - } - scope.removeSaveCompleted = scope.$on('saveCompleted', function() { - try { - $('#host-modal-dialog').dialog('close'); - } - catch(err) { - // ignore - } - if (group_scope && group_scope.refreshHosts) { - group_scope.refreshHosts(); - } - if (parent_scope.refreshHosts) { - parent_scope.refreshHosts(); - } - scope.$destroy(); - }); - - // Save changes to the parent - scope.saveModal = function() { - - Wait('start'); - var fld, data={}; - - try { - data.variables = ToJSON(scope.parseType, scope.variables, true); - for (fld in form.fields) { - data[fld] = scope[fld]; - } - data.inventory = inventory_id; - Rest.setUrl(defaultUrl); - if (mode === 'edit') { - Rest.put(data) - .success( function() { - scope.$emit('saveCompleted'); - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status }); - }); - } - else { - Rest.post(data) - .success( function() { - scope.$emit('saveCompleted'); - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to create host. POST returned status: ' + status }); - }); - } - } - catch(e) { - // ignore. ToJSON will have already alerted the user - } - }; - - // Cancel - scope.formReset = function() { - generator.reset(); - for (var fld in master) { - scope[fld] = master[fld]; - } - scope.parseType = 'yaml'; - }; - - scope.cancelModal = function() { - try { - $('#host-modal-dialog').dialog('close'); - } - catch(err) { - // ignore - } - scope.$destroy(); - }; - - }; - }]) - - - .factory('HostsDelete', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'Wait', - function($rootScope, $location, $log, $routeParams, Rest, Alert, Prompt, ProcessErrors, GetBasePath, HostsReload, Wait) { - return function(params) { - // Remove the selected host from the current group by disassociating - - var action_to_take, body, - scope = params.parent_scope, - host_id = params.host_id, - host_name = params.host_name, - group, - url_list = []; - - if (scope.selected_group_id) { - //group = Find({ list: parent_scope.groups, key: 'id', val: parent_scope.selected_group_id }); - //getChildren(group.id); - url_list.push(GetBasePath('groups') + scope.selected_group_id + '/hosts/'); - } - else { - url_list.push(GetBasePath('inventory') + scope.inventory.id + '/hosts/'); - } - - if (scope.removeHostsReload) { - scope.removeHostsReload(); - } - scope.removeHostsReload = scope.$on('hostsReload', function() { - $('#prompt-modal').modal('hide'); - scope.refreshHosts(); - }); - - $('#prompt-modal').on('hidden.bs.modal', function(){ Wait('stop'); }); - - action_to_take = function() { - var count=0, i; - - Wait('start'); - - if (scope.removeHostRemoved) { - scope.removeHostRemoved(); - } - scope.removeHostRemoved = scope.$on('hostRemoved', function(){ - count++; - if (count === url_list.length) { - Wait('start'); - scope.$emit('hostsReload'); - } - }); - - for(i=0; i < url_list.length; i++) { - Rest.setUrl(url_list[i]); - Rest.post({ id: host_id, disassociate: 1 }) - .success( function() { - scope.$emit('hostRemoved'); - }) - .error( function(data, status) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Attempt to delete ' + host_name + ' failed. DELETE returned status: ' + status }); - }); - } - }; - - body = (group) ? '

Are you sure you want to remove host ' + host_name + ' from group ' + group.name + '?' + - ' It will still be part of the inventory and available in All Hosts.

' : - '

Are you sure you want to permanently delete host ' + host_name + ' from the inventory?

'; - Prompt({ hdr: 'Delete Host', body: body, action: action_to_take, 'class': 'btn-danger' }); - - }; - }]) +.factory('InjectHosts', ['GenerateList', 'InventoryHosts', 'HostsReload', + function(GenerateList, InventoryHosts, HostsReload) { + return function(params) { + + var group_scope = params.group_scope, + host_scope = params.host_scope, + inventory_id = params.inventory_id, + group_id = params.group_id, + pageSize = params.pageSize, + generator = GenerateList; + + // Inject the list html + generator.inject(InventoryHosts, { scope: host_scope, mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-6 col-md-6 col-sm-6' }); + + // Load data + HostsReload({ scope: host_scope, group_id: group_id, inventory_id: inventory_id, parent_scope: group_scope, pageSize: pageSize }); + }; + }]) + +.factory('ToggleHostEnabled', [ 'GetBasePath', 'Rest', 'Wait', 'ProcessErrors', 'Alert', 'Find', 'SetEnabledMsg', + function(GetBasePath, Rest, Wait, ProcessErrors, Alert, Find, SetEnabledMsg) { + return function(params) { + + var id = params.host_id, + external_source = params.external_source, + parent_scope = params.parent_scope, + host_scope = params.host_scope, + host; + + function setMsg(host) { + host.enabled = (host.enabled) ? false : true; + host.enabled_flag = host.enabled; + SetEnabledMsg(host); + } + + if (!external_source) { + // Host is not managed by an external source + Wait('start'); + host = Find({ list: host_scope.hosts, key: 'id', val: id }); + setMsg(host); + + Rest.setUrl(GetBasePath('hosts') + id + '/'); + Rest.put(host) + .success( function() { + Wait('stop'); + }) + .error( function(data, status) { + // Flip the enabled flag back + setMsg(host); + ProcessErrors(parent_scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to update host. PUT returned status: ' + status }); + }); + } + else { + Alert('Action Not Allowed', 'This host is managed by an external cloud source. Disable it at the external source, ' + + 'then run an inventory sync to update Tower with the new status.', 'alert-info'); + } + }; + }]) + +.factory('HostsList', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostList', 'GenerateList', + 'Prompt', 'SearchInit', 'PaginateInit', 'ProcessErrors', 'GetBasePath', 'HostsAdd', 'HostsReload', 'SelectionInit', + function($rootScope, $location, $log, $routeParams, Rest, Alert, HostList, GenerateList, Prompt, SearchInit, + PaginateInit, ProcessErrors, GetBasePath, HostsAdd, HostsReload, SelectionInit) { + return function(params) { + + var inventory_id = params.inventory_id, + group_id = params.group_id, + list = HostList, + generator = GenerateList, + defaultUrl, scope; + + list.iterator = 'subhost'; //Override the iterator and name so the scope of the modal dialog + list.name = 'subhosts'; //will not conflict with the parent scope + + + + scope = generator.inject(list, { + id: 'form-modal-body', + mode: 'select', + breadCrumbs: false, + selectButton: false + }); + + defaultUrl = GetBasePath('inventory') + inventory_id + '/hosts/?not__groups__id=' + scope.group_id; + + scope.formModalActionLabel = 'Select'; + scope.formModalHeader = 'Add Existing Hosts'; + scope.formModalCancelShow = true; + + SelectionInit({ scope: scope, list: list, url: GetBasePath('groups') + group_id + '/hosts/' }); + + if (scope.removeModalClosed) { + scope.removeModalClosed(); + } + scope.removeModalClosed = scope.$on('modalClosed', function() { + // if the modal closed, assume something got changed and reload the host list + HostsReload(params); + }); + + $('.popover').popover('hide'); //remove any lingering pop-overs + $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); + $('#form-modal').modal({ backdrop: 'static', keyboard: false }); + + SearchInit({ scope: scope, set: 'subhosts', list: list, url: defaultUrl }); + PaginateInit({ scope: scope, list: list, url: defaultUrl, mode: 'lookup' }); + scope.search(list.iterator); + + if (!scope.$$phase) { + scope.$digest(); + } + + scope.createHost = function() { + $('#form-modal').modal('hide'); + HostsAdd({ scope: params.scope, inventory_id: inventory_id, group_id: group_id }); + }; + + }; + }]) + + +.factory('HostsCreate', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'ToJSON', + function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, + GetBasePath, HostsReload, ParseTypeChange, Wait, ToJSON) { + return function(params) { + + var parent_scope = params.scope, + inventory_id = parent_scope.inventory_id, + group_id = parent_scope.selected_group_id, + defaultUrl = GetBasePath('groups') + group_id + '/hosts/', + form = HostForm, + generator = GenerateForm, + scope = generator.inject(form, {mode: 'add', modal: true, related: false}), + master={}; + + scope.formModalActionLabel = 'Save'; + scope.formModalHeader = 'Create New Host'; + scope.formModalCancelShow = true; + + scope.parseType = 'yaml'; + ParseTypeChange({ scope: scope, field_id: 'host_variables' }); + + if (scope.removeHostsReload) { + scope.removeHostsReload(); + } + scope.removeHostsReload = scope.$on('hostsReload', function() { + HostsReload(params); + }); + + $('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success'); + //$('#form-modal').unbind('hidden'); + //$('#form-modal').on('hidden', function () { scope.$emit('hostsReload'); }); + + generator.reset(); + master={}; + + if (!scope.$$phase) { + scope.$digest(); + } + + if (scope.removeHostSaveComplete) { + scope.removeHostSaveComplete(); + } + scope.removeHostSaveComplete = scope.$on('HostSaveComplete', function() { + Wait('stop'); + $('#form-modal').modal('hide'); + + HostsReload({ + scope: parent_scope, + group_id: parent_scope.selected_group_id, + tree_id: parent_scope.selected_tree_id, + inventory_id: parent_scope.inventory_id + }); + + //WatchInventoryWindowResize(); + }); + + // Save + scope.formModalAction = function() { + + Wait('start'); + + var fld, data={}; + scope.formModalActionDisabled = true; + data.variables = ToJSON(scope.parseType, scope.variables, true); + for (fld in form.fields) { + if (fld !== 'variables') { + data[fld] = scope[fld]; + } + } + data.inventory = inventory_id; + + Rest.setUrl(defaultUrl); + Rest.post(data) + .success( function() { + scope.$emit('HostSaveComplete'); + }) + .error( function(data, status) { + Wait('stop'); + scope.formModalActionDisabled = false; + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status }); + }); + }; + + // Cancel + scope.formReset = function() { + // Defaults + generator.reset(); + }; + + scope.cancelModal = function() { + // WatchInventoryWindowResize(); + }; + + }; + }]) + + +.factory('HostsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetStatus', 'ApplyEllipsis', + 'ToJSON', 'ParseVariableString', 'CreateDialog', 'TextareaResize', + function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, + GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus, ApplyEllipsis, ToJSON, + ParseVariableString, CreateDialog, TextareaResize) { + return function(params) { + + var parent_scope = params.host_scope, + group_scope = params.group_scope, + host_id = params.host_id, + inventory_id = params.inventory_id, + mode = params.mode, // 'add' or 'edit' + selected_group_id = params.selected_group_id, + generator = GenerateForm, + form = HostForm, + defaultUrl, + scope = parent_scope.$new(), + master = {}, + relatedSets = {}, + buttons, url, form_scope; + + var form_scope = + generator.inject(HostForm, { mode: 'edit', id: 'host-modal-dialog', breadCrumbs: false, related: false, scope: scope }); + generator.reset(); + + buttons = [{ + label: "Cancel", + onClick: function() { + scope.cancelModal(); + }, + icon: "fa-times", + "class": "btn btn-default", + "id": "host-cancel-button" + },{ + label: "Save", + onClick: function() { + scope.saveModal(); + }, + icon: "fa-check", + "class": "btn btn-primary", + "id": "host-save-button" + }]; + + CreateDialog({ + scope: scope, + buttons: buttons, + width: 675, + height: 750, + minWidth: 400, + title: 'Host Properties', + id: 'host-modal-dialog', + clonseOnEscape: false, + form: form_scope.host_form, + onClose: function() { + Wait('stop'); + scope.codeMirror.destroy(); + $('#host-modal-dialog').empty(); + }, + onResizeStop: function() { + TextareaResize({ + scope: scope, + textareaId: 'host_variables', + modalId: 'host-modal-dialog', + formId: 'host_form' + }); + }, + beforeDestroy: function() { + if (scope.codeMirror) { + scope.codeMirror.destroy(); + } + $('#host-modal-dialog').empty(); + }, + onOpen: function() { + $('#host_name').focus(); + }, + callback: 'HostEditDialogReady' + }); + + scope.parseType = 'yaml'; + + if (scope.hostVariablesLoadedRemove) { + scope.hostVariablesLoadedRemove(); + } + scope.hostVariablesLoadedRemove = scope.$on('hostVariablesLoaded', function() { + $('#host-modal-dialog').dialog('open'); + setTimeout(function() { + TextareaResize({ + scope: scope, + textareaId: 'host_variables', + modalId: 'host-modal-dialog', + formId: 'host_form', + parse: true + }); + }, 300); + //ParseTypeChange({ scope: scope, field_id: 'host_variables', onReady: callback }); + }); + + if (scope.hostLoadedRemove) { + scope.hostLoadedRemove(); + } + scope.hostLoadedRemove = scope.$on('hostLoaded', function() { + // Retrieve host variables + if (scope.variable_url) { + Rest.setUrl(scope.variable_url); + Rest.get() + .success( function(data) { + scope.variables = ParseVariableString(data); + scope.$emit('hostVariablesLoaded'); + }) + .error( function(data, status) { + scope.variables = null; + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to retrieve host variables. GET returned status: ' + status }); + }); + } + else { + scope.variables = "---"; + scope.$emit('hostVariablesLoaded'); + } + master.variables = scope.variables; + }); + + Wait('start'); + + // Retrieve detail record and prepopulate the form + if (mode === 'edit') { + defaultUrl = GetBasePath('hosts') + host_id + '/'; + Rest.setUrl(defaultUrl); + Rest.get() + .success( function(data) { + var set, fld, related; + for (fld in form.fields) { + if (data[fld]) { + scope[fld] = data[fld]; + master[fld] = scope[fld]; + } + } + related = data.related; + for (set in form.related) { + if (related[set]) { + relatedSets[set] = { url: related[set], iterator: form.related[set].iterator }; + } + } + scope.variable_url = data.related.variable_data; + scope.has_inventory_sources = data.has_inventory_sources; + scope.$emit('hostLoaded'); + }) + .error( function(data, status) { + ProcessErrors(parent_scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to retrieve host: ' + host_id + '. GET returned status: ' + status }); + }); + } + else { + // Add mode + url = GetBasePath('groups') + selected_group_id + '/'; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + scope.has_inventory_sources = data.has_inventory_sources; + scope.enabled = true; + scope.variables = '---'; + defaultUrl = data.related.hosts; + scope.$emit('hostVariablesLoaded'); + }) + .error( function(data, status) { + ProcessErrors(parent_scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to retrieve group: ' + selected_group_id + '. GET returned status: ' + status }); + }); + } + + if (scope.removeSaveCompleted) { + scope.removeSaveCompleted(); + } + scope.removeSaveCompleted = scope.$on('saveCompleted', function() { + try { + $('#host-modal-dialog').dialog('close'); + } + catch(err) { + // ignore + } + if (group_scope && group_scope.refreshHosts) { + group_scope.refreshHosts(); + } + if (parent_scope.refreshHosts) { + parent_scope.refreshHosts(); + } + scope.$destroy(); + }); + + // Save changes to the parent + scope.saveModal = function() { + + Wait('start'); + var fld, data={}; + + try { + data.variables = ToJSON(scope.parseType, scope.variables, true); + for (fld in form.fields) { + data[fld] = scope[fld]; + } + data.inventory = inventory_id; + Rest.setUrl(defaultUrl); + if (mode === 'edit') { + Rest.put(data) + .success( function() { + scope.$emit('saveCompleted'); + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status }); + }); + } + else { + Rest.post(data) + .success( function() { + scope.$emit('saveCompleted'); + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to create host. POST returned status: ' + status }); + }); + } + } + catch(e) { + // ignore. ToJSON will have already alerted the user + } + }; + + // Cancel + scope.formReset = function() { + generator.reset(); + for (var fld in master) { + scope[fld] = master[fld]; + } + scope.parseType = 'yaml'; + }; + + scope.cancelModal = function() { + try { + $('#host-modal-dialog').dialog('close'); + } + catch(err) { + // ignore + } + scope.$destroy(); + }; + + }; + }]) + + +.factory('HostsDelete', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'Wait', + function($rootScope, $location, $log, $routeParams, Rest, Alert, Prompt, ProcessErrors, GetBasePath, HostsReload, Wait) { + return function(params) { + // Remove the selected host from the current group by disassociating + + var action_to_take, body, + scope = params.parent_scope, + host_id = params.host_id, + host_name = params.host_name, + group, + url_list = []; + + if (scope.selected_group_id) { + //group = Find({ list: parent_scope.groups, key: 'id', val: parent_scope.selected_group_id }); + //getChildren(group.id); + url_list.push(GetBasePath('groups') + scope.selected_group_id + '/hosts/'); + } + else { + url_list.push(GetBasePath('inventory') + scope.inventory.id + '/hosts/'); + } + + if (scope.removeHostsReload) { + scope.removeHostsReload(); + } + scope.removeHostsReload = scope.$on('hostsReload', function() { + $('#prompt-modal').modal('hide'); + scope.refreshHosts(); + }); + + $('#prompt-modal').on('hidden.bs.modal', function(){ Wait('stop'); }); + + action_to_take = function() { + var count=0, i; + + Wait('start'); + + if (scope.removeHostRemoved) { + scope.removeHostRemoved(); + } + scope.removeHostRemoved = scope.$on('hostRemoved', function(){ + count++; + if (count === url_list.length) { + Wait('start'); + scope.$emit('hostsReload'); + } + }); + + for(i=0; i < url_list.length; i++) { + Rest.setUrl(url_list[i]); + Rest.post({ id: host_id, disassociate: 1 }) + .success( function() { + scope.$emit('hostRemoved'); + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Attempt to delete ' + host_name + ' failed. DELETE returned status: ' + status }); + }); + } + }; + + body = (group) ? '

Are you sure you want to remove host ' + host_name + ' from group ' + group.name + '?' + + ' It will still be part of the inventory and available in All Hosts.

' : + '

Are you sure you want to permanently delete host ' + host_name + ' from the inventory?

'; + Prompt({ hdr: 'Delete Host', body: body, action: action_to_take, 'class': 'btn-danger' }); + + }; + }]) .factory('HostsCopy', ['$compile', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'GenerateList', 'GroupList', 'SearchInit', 'PaginateInit', diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 67ca22c3e1..f6c44525fc 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -201,15 +201,16 @@ export default form.well = false; - generator.inject(form, { - mode: 'edit', - showButtons: false, - showActions: false, - id: 'inventory-edit-modal-dialog', - breadCrumbs: false, - related: false, - scope: scope - }); + var form_scope = + generator.inject(form, { + mode: 'edit', + showButtons: false, + showActions: false, + id: 'inventory-edit-modal-dialog', + breadCrumbs: false, + related: false, + scope: scope + }); /* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */ form.well = true; @@ -241,6 +242,7 @@ export default title: 'Inventory Properties', id: 'inventory-edit-modal-dialog', clonseOnEscape: false, + form: form_scope.inventory_form, onClose: function() { Wait('stop'); scope.codeMirror.destroy(); diff --git a/awx/ui/static/lib/ansible/Modal.js b/awx/ui/static/lib/ansible/Modal.js index 8754d989c0..c34ef22971 100644 --- a/awx/ui/static/lib/ansible/Modal.js +++ b/awx/ui/static/lib/ansible/Modal.js @@ -57,10 +57,15 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) beforeDestroy = params.beforeDestroy, closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape, resizable = (params.resizable === undefined) ? true : params.resizable, + forms = _.chain([params.form]).flatten().compact().value(), buttons, id = params.id, x, y, wh, ww; + function updateButtonStatus(isValid) { + $('.ui-dialog[aria-describedby="' + id + '"]').find('.btn-primary').prop('disabled', !isValid); + } + if (Empty(buttonSet)) { // Default button object buttonSet = [{ @@ -115,6 +120,12 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) }); }, 300); + if (forms.length > 0) { + forms.map(function(form_ctrl) { + scope.$watch(form_ctrl.$name + '.$valid', updateButtonStatus); + }); + } + setTimeout(function() { scope.$apply(function() { scope.$emit(callback); @@ -226,4 +237,4 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) ParseTypeChange({ scope: scope, field_id: textareaId, onReady: waitStop, variable: fld, onChange: onChange }); } }; - }]); \ No newline at end of file + }]);