diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 20a1034dac..57c23472d5 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -789,6 +789,11 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched if (sources_scope.codeMirror) { sources_scope.codeMirror.destroy(); } + $('#properties-tab').empty(); + $('#sources-tab').empty(); + $('#schedules-list').empty(); + $('#schedules-form').empty(); + $('#schedules-detail').empty(); $('#group-modal-dialog').hide(); $('#group-modal-dialog').dialog('destroy'); modal_scope.cancelModal(); @@ -1265,45 +1270,149 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched .factory('GroupsDelete', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', 'BuildTree', 'Find', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', 'BuildTree', 'Find', 'CreateDialog', function ($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, Wait, BuildTree, Find) { + GetBasePath, Wait, BuildTree, Find, CreateDialog) { return function (params) { // Delete the selected group node. Disassociates it from its parent. var scope = params.scope, tree_id = params.tree_id, - inventory_id = params.inventory_id, node = Find({ list: scope.groups, key: 'id', val: tree_id }), - url = GetBasePath('inventory') + inventory_id + '/groups/', - action_to_take; + hosts = [], + groups = [], + childCount = 0, + buttonSet; - action_to_take = function () { - $('#prompt-modal').on('hidden.bs.modal', function () { - Wait('start'); + // action_to_take = function () { + // $('#prompt-modal').on('hidden.bs.modal', function () { + // Wait('start'); + // }); + // $('#prompt-modal').modal('hide'); + // Rest.setUrl(url); + // Rest.post({ id: node.group_id, disassociate: 1 }) + // .success(function () { + // $('#prompt-modal').modal('hide'); + // scope.$emit('GroupDeleteCompleted'); // Signal a group refresh to start + // }) + // .error(function (data, status) { + // Wait('stop'); + // ProcessErrors(scope, data, status, null, { + // hdr: 'Error!', + // msg: 'Call to ' + url + ' failed. POST returned status: ' + status + // }); + // }); + // }; + + scope.deleteOption = "preserve-all"; + + buttonSet = [{ + label: "Cancel", + onClick: function() { + scope.cancel(); + }, + icon: "fa-times", + "class": "btn btn-default", + "id": "group-delete-cancel-button" + },{ + label: "Continue", + onClick: function() { + scope.performDelete(); + }, + icon: "fa-check", + "class": "btn btn-primary", + "id": "group-delete-ok-button" + }]; + + if (scope.removeDeleteDialogReady) { + scope.removeDeleteDialogReady(); + } + scope.removeDeleteDialogReady = scope.$on('DeleteDialogReady', function() { + Wait('stop'); + $('#group-delete-dialog').dialog('open'); + }); + + if (scope.removeShowDeleteDialog) { + scope.removeShowDeleteDialog(); + } + scope.removeShowDeleteDialog = scope.$on('ShowDeleteDialog', function() { + scope.group_name = node.name; + scope.groupsCount = groups.length; + scope.hostsCount = hosts.length; + CreateDialog({ + id: 'group-delete-dialog', + scope: scope, + buttons: buttonSet, + width: 650, + height: 350, + minWidth: 500, + title: 'Delete Group', + callback: 'DeleteDialogReady' }); - $('#prompt-modal').modal('hide'); - Rest.setUrl(url); - Rest.post({ id: node.group_id, disassociate: 1 }) - .success(function () { - $('#prompt-modal').modal('hide'); - scope.$emit('GroupDeleteCompleted'); // Signal a group refresh to start + }); + + if (scope.removeChildrenReady) { + scope.removeChildrenReady(); + } + scope.removeChildrenReady = scope.$on('ChildrenReady', function() { + childCount++; + if (childCount === 2) { + scope.$emit('ShowDeleteDialog'); + } + }); + + Wait('start'); + + if (node.related.children) { + Rest.setUrl(node.related.children); + Rest.get() + .success(function(data) { + if (data.count) { + data.results.forEach(function(group) { + groups.push(group); + }); + } + scope.$emit('ChildrenReady'); }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, null, { - hdr: 'Error!', - msg: 'Call to ' + url + ' failed. POST returned status: ' + status + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve related groups. GET returned: ' + status }); }); + } + else { + scope.$emit('ChildrenReady'); + } + + if (node.related.all_hosts) { + Rest.setUrl(node.related.all_hosts); + Rest.get() + .success( function(data) { + if (data.count) { + data.results.forEach(function(host) { + hosts.push(host); + }); + } + scope.$emit('ChildrenReady'); + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve related hosts. GET returned: ' + status + }); + }); + } + else { + scope.$emit('ChildrenReady'); + } + + scope.cancel = function() { + $('#group-delete-dialog').dialog('close'); + }; + + scope.performDelete = function() { + $('#group-delete-dialog').dialog('close'); }; - Prompt({ - hdr: 'Delete Group', - body: '
Are you sure you want to delete group ' + node.name + '?
', - action: action_to_take, - 'class': 'btn-danger' - }); }; } ]) diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 7fdb7127f6..3c33eaa566 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -498,28 +498,35 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener formId: 'host_form' }); }, + beforeDestroy: function() { + if (scope.codeMirror) { + scope.codeMirror.destroy(); + } + $('#host-modal-dialog').empty(); + }, onOpen: function() { $('#host_name').focus(); - setTimeout(function() { - TextareaResize({ - scope: scope, - textareaId: 'host_variables', - modalId: 'host-modal-dialog', - formId: 'host_form' - }); - }, 300); - } + }, + callback: 'HostEditDialogReady' }); scope.parseType = 'yaml'; - + if (scope.hostVariablesLoadedRemove) { scope.hostVariablesLoadedRemove(); } scope.hostVariablesLoadedRemove = scope.$on('hostVariablesLoaded', function() { - var callback = function() { Wait('stop'); }; $('#host-modal-dialog').dialog('open'); - ParseTypeChange({ scope: scope, field_id: 'host_variables', onReady: callback }); + 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) { diff --git a/awx/ui/static/js/helpers/refresh.js b/awx/ui/static/js/helpers/refresh.js index 54339c5076..203e4bfe84 100644 --- a/awx/ui/static/js/helpers/refresh.js +++ b/awx/ui/static/js/helpers/refresh.js @@ -25,7 +25,8 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities', 'PaginationHelpers set = params.set, iterator = params.iterator, url = params.url; - + + scope[iterator + 'Loading'] = true; scope.current_url = url; Rest.setUrl(url); Rest.get() @@ -38,13 +39,12 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities', 'PaginationHelpers previous: data.previous, iterator: iterator }); - scope[iterator + 'Loading'] = false; for (i = 1; i <= 3; i++) { modifier = (i === 1) ? '' : i; scope[iterator + 'HoldInput' + modifier] = false; } scope[set] = data.results; - //window.scrollTo(0, 0); + scope[iterator + 'Loading'] = false; Wait('stop'); scope.$emit('PostRefresh'); }) diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index fb17e9d192..5c8313bf8a 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -942,9 +942,9 @@ input[type="checkbox"].checkbox-no-label { /* Table info rows */ .loading-info { - color: @grey-txt; - font-weight: bold; - padding: 15px 0; + color: @grey-txt; + font-weight: normal; + padding: 15px 0; } /* Jobs pages */ diff --git a/awx/ui/static/lib/ansible/InventoryTree.js b/awx/ui/static/lib/ansible/InventoryTree.js index ac9a8173e8..7da0fa6675 100644 --- a/awx/ui/static/lib/ansible/InventoryTree.js +++ b/awx/ui/static/lib/ansible/InventoryTree.js @@ -116,10 +116,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P event_level: level, children: children, ngicon: (sorted[i].children.length > 0) ? 'fa fa-minus-square-o node-toggle' : 'fa fa-square-o node-no-toggle', - related: { - children: (sorted[i].children.length > 0) ? sorted[i].related.children : '', - inventory_source: sorted[i].related.inventory_source - }, + related: sorted[i].related, status: sorted[i].summary_fields.inventory_source.status, status_class: stat['class'], status_tooltip: stat.tooltip, diff --git a/awx/ui/static/lib/ansible/Modal.js b/awx/ui/static/lib/ansible/Modal.js index 66f680e445..80eed2950e 100644 --- a/awx/ui/static/lib/ansible/Modal.js +++ b/awx/ui/static/lib/ansible/Modal.js @@ -26,6 +26,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) * onResizeStop: - Function to call when user stops resizing the dialog, optional * onClose: - Function to call after window closes, optional * onOpen: - Function to call after window opens, optional + * beforeDestroy: - Function to call during onClose and prior to destroying the window * callback: - String to pass to scope.$emit() after dialog is created, optional * }) * @@ -46,6 +47,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) onClose = params.onClose, onOpen = params.onOpen, callback = params.callback, + beforeDestroy = params.beforeDestroy, closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape, buttons, id = params.id, @@ -132,6 +134,9 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) // remove lingering popover
elements $(this).remove(); }); + if (beforeDestroy) { + beforeDestroy(); + } $('#' + id).dialog('destroy'); $('#' + id).hide(); if (onClose) { @@ -161,6 +166,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) * textareaId: - id attribute value of the textarea * modalId: - id attribute of the
element used to create the modal * formId: - id attribute of the textarea's parent form + * parse: - if true, call ParseTypeChange and replace textarea with codemirror editor * }) * * Use to resize a textarea field contained on a modal. Has only been tested where the diff --git a/awx/ui/static/partials/inventory-edit.html b/awx/ui/static/partials/inventory-edit.html index 1fa1b2205c..3737b77693 100644 --- a/awx/ui/static/partials/inventory-edit.html +++ b/awx/ui/static/partials/inventory-edit.html @@ -49,6 +49,59 @@
+ + +
+
\ No newline at end of file