diff --git a/ansibleworks/ui/static/js/controllers/Inventories.js b/ansibleworks/ui/static/js/controllers/Inventories.js index b0978a445c..52bb8af3a0 100644 --- a/ansibleworks/ui/static/js/controllers/Inventories.js +++ b/ansibleworks/ui/static/js/controllers/Inventories.js @@ -380,9 +380,13 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP } scope.$on('NodeSelect', function(e, n) { + + // Respond to user clicking on a tree node + var node = $('li[id="' + n.attr.id + '"]'); var type = node.attr('type'); var url; + scope['selectedNode'] = node; $('#tree-view').jstree('open_node',node); if (type == 'group') { url = node.attr('all'); diff --git a/ansibleworks/ui/static/js/helpers/Groups.js b/ansibleworks/ui/static/js/helpers/Groups.js index fe2d01eeb3..8a570bc560 100644 --- a/ansibleworks/ui/static/js/helpers/Groups.js +++ b/ansibleworks/ui/static/js/helpers/Groups.js @@ -11,12 +11,12 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', 'InventoryHelper' - ]) + ]) .factory('GroupsList', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupList', 'GenerateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ProcessErrors', 'GetBasePath', 'GroupsAdd', 'RefreshTree', function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupList, GenerateList, LoadBreadCrumbs, SearchInit, - PaginateInit, ProcessErrors, GetBasePath, GroupsAdd, RefreshTree) { + PaginateInit, ProcessErrors, GetBasePath, GroupsAdd, RefreshTree) { return function(params) { var inventory_id = params.inventory_id; @@ -45,6 +45,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } scope.PostRefreshRemove = scope.$on('PostRefresh', function() { $("tr.success").each(function(index) { + // Make sure no rows have a green background var ngc = $(this).attr('ng-class'); scope[ngc] = ""; }); @@ -64,35 +65,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' PaginateInit({ scope: scope, list: list, url: defaultUrl }); scope.search(list.iterator); - /*LoadBreadCrumbs();*/ - - scope.editGroup = function(id) { - $location.path($location.path() + '/' + id); - } - - scope.deleteGroup = function(id, name) { - - var action = function() { - var url = defaultUrl; - Rest.setUrl(url); - Rest.post({ id: id, disassociate: 1 }) - .success( function(data, status, headers, config) { - $('#prompt-modal').modal('hide'); - scope.search(list.iterator); - }) - .error( function(data, status, headers, config) { - $('#prompt-modal').modal('hide'); - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - }; - - Prompt({ hdr: 'Delete', - body: 'Are you sure you want to remove group' + name + '?', - action: action - }); - } - scope.formModalAction = function() { var url = (group_id) ? GetBasePath('groups') + group_id + '/children/' : GetBasePath('inventory') + inventory_id + '/groups/'; @@ -120,6 +92,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } else { $('#form-modal').modal('hide'); + RefreshTree({ scope: scope }); } } }); @@ -173,16 +146,15 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' GroupsAdd({ inventory_id: inventory_id, group_id: group_id }); } - } }]) .factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshTree', function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath) { + GetBasePath, RefreshTree) { return function(params) { var inventory_id = params.inventory_id; @@ -197,7 +169,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope.formModalActionLabel = 'Save' scope.formModalHeader = 'Create Group' generator.reset(); - var master={}; + var master={}; // Save scope.formModalAction = function() { @@ -224,12 +196,17 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' Rest.put({data: scope.variables}) .success( function(data, status, headers, config) { $('#form-modal').modal('hide'); + RefreshTree({ scope: scope }); }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, { hdr: 'Error!', msg: 'Failed to add group varaibles. PUT returned status: ' + status }); }); } + else { + $('#form-modal').modal('hide'); + RefreshTree({ scope: scope }); + } }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, @@ -251,9 +228,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }]) .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshTree', function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath) { + GetBasePath, RefreshTree) { return function(params) { var group_id = params.group_id; @@ -343,13 +320,17 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' Rest.put({data: scope.variables}) .success( function(data, status, headers, config) { $('#form-modal').modal('hide'); - }) + RefreshTree({ scope: scope }); + }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, { hdr: 'Error!', msg: 'Failed to update group varaibles. PUT returned status: ' + status }); }); } - $('#form-modal').modal('hide'); + else { + $('#form-modal').modal('hide'); + RefreshTree({ scope: scope }); + } }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, @@ -389,6 +370,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }) .error( function(data, status, headers, config) { $('#prompt-modal').modal('hide'); + RefreshTree({ scope: scope }); ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status }); }); diff --git a/ansibleworks/ui/static/js/helpers/inventory.js b/ansibleworks/ui/static/js/helpers/inventory.js index b00bb58630..8ecf0a5370 100644 --- a/ansibleworks/ui/static/js/helpers/inventory.js +++ b/ansibleworks/ui/static/js/helpers/inventory.js @@ -163,6 +163,10 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi items: scope.treeController } }); + + $(tree_id).bind("loaded.jstree", function () { + scope.$emit('treeLoaded'); + }); // When user clicks on a group, display the related hosts in the list view $(tree_id).bind("select_node.jstree", function(e, data){ @@ -178,21 +182,9 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi }]) - .factory('RefreshTree', ['Alert', 'Rest', 'Authorization', '$http', 'TreeInit', - function(Alert, Rest, Authorization, $http, TreeInit) { - return function(params) { - - $('#tree-view').jstree('destroy'); - - TreeInit(params); - - } - }]) - - - .factory('LoadInventory', ['$routeParams', 'Alert', 'Rest', 'Authorization', '$http', 'RefreshTree', 'ProcessErrors', + .factory('LoadInventory', ['$routeParams', 'Alert', 'Rest', 'Authorization', '$http', 'ProcessErrors', 'RelatedSearchInit', 'RelatedPaginateInit', 'GetBasePath', 'LoadBreadCrumbs', 'InventoryForm', - function($routeParams, Alert, Rest, Authorization, $http, RefreshTree ,ProcessErrors, RelatedSearchInit, RelatedPaginateInit, + function($routeParams, Alert, Rest, Authorization, $http, ProcessErrors, RelatedSearchInit, RelatedPaginateInit, GetBasePath, LoadBreadCrumbs, InventoryForm) { return function(params) { @@ -240,6 +232,63 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi { hdr: 'Error!', msg: 'Failed to retrieve inventory: ' + $routeParams.id + '. GET status: ' + status }); }); + } + }]) + + + .factory('RefreshTree', ['Alert', 'Rest', 'Authorization', '$http', 'TreeInit', 'LoadInventory', + function(Alert, Rest, Authorization, $http, TreeInit, LoadInventory) { + return function(params) { + + // Call after an Edit or Add to refresh tree data + + var scope = params.scope; + var openId = []; + var selectedId; + + if (scope.treeLoadedRemove) { + scope.treeLoadedRemove(); + } + scope.treeLoadedRemove = scope.$on('treeLoaded', function() { + // Called recursively to pop the next openId node value and open it. + // Opens the list in reverse so that nodes open in parent then child order, + // drilling down to the last selected node. + var id, node; + if (openId.length > 0) { + id = openId.pop(); + node = $('#tree-view li[id="' + id + '"]'); + $.jstree._reference('#tree-view').open_node(node, function(){ scope.$emit('treeLoaded'); }, true); + } + else { + if (selectedId !== null && selectedId !== undefined) { + // Click on the previously selected node + $('#tree-view li[id="' + selectedId + '"] a').first().click(); + } + } + }); + + if (scope.inventoryLoadedRemove) { + scope.inventoryLoadedRemove(); + } + scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() { + // Get the list of open tree nodes starting with the current group and going up + // the tree until we hit the inventory or root node. + function findOpenNodes(node) { + if (node.attr('id') != 'inventory-node') { + if (node.prop('tagName') == 'LI' && (node.hasClass('jstree-open') || node.find('.jstree-clicked'))) { + openId.push(node.attr('id')); + } + findOpenNodes(node.parent()); + } + } + selectedId = scope.selectedNode.attr('id'); + findOpenNodes(scope.selectedNode); + $('#tree-view').jstree('destroy'); + TreeInit(scope.TreeParams); + }); + + LoadInventory({ scope: scope }); + } }]);