diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index f18b0c69b2..0d64318f14 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -216,7 +216,6 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP LoadInventory({ scope: scope, doPostSteps: true }); $('#inventory-tabs a[href="#inventory-hosts"]').on('show.bs.tab', function() { LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] }); - HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] }); if (!scope.$$phase) { scope.$digest(); } @@ -382,10 +381,10 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP scope.inventoryEditHide = true; scope.groupDeleteHide = false; scope.createButtonShow = true; - scope.group_id = node.attr('group_id'); - scope.groupName = n.data; - scope.groupTitle = '

' + n.data + '

'; - scope.groupTitle += (node.attr('description')) ? '

' + node.attr('description') + '

' : ''; + //scope.group_id = node.attr('group_id'); + //scope.groupName = n.data; + //scope.groupTitle = '

' + n.data + '

'; + //scope.groupTitle += (node.attr('description')) ? '

' + node.attr('description') + '

' : ''; } else if (type == 'inventory') { url = node.attr('hosts'); @@ -395,9 +394,9 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP scope.inventoryEditHide=false; scope.groupDeleteHide = true; scope.createButtonShow = false; - scope.groupName = 'All Hosts'; - scope.groupTitle = '

All Hosts

'; - scope.group_id = null; + //scope.groupName = 'All Hosts'; + //scope.groupTitle = '

All Hosts

'; + //scope.group_id = null; } if (!scope.$$phase) { @@ -460,11 +459,12 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP }); } - scope.showHosts = function(e) { - console.log('here'); - var elm = angular.elment(e.srcElement); - console.log('Need to show hosts: ' + elm.attr('data-hosts')); - } + // Respond to the scope.$emit from awTree directive + scope.$on('refreshHost', function(e, group, title) { + scope.groupTitle = title; + scope.group_id = group; + HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: group }); + }); } diff --git a/awx/ui/static/js/controllers/Organizations.js b/awx/ui/static/js/controllers/Organizations.js index 8a11ff0927..0d5ed2e48c 100644 --- a/awx/ui/static/js/controllers/Organizations.js +++ b/awx/ui/static/js/controllers/Organizations.js @@ -12,7 +12,7 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, Rest, Alert, LoadBreadCrumbs, Prompt, GenerateList, OrganizationList, SearchInit, PaginateInit, ClearScope, ProcessErrors, - GetBasePath, SelectionInit) + GetBasePath, SelectionInit, Wait) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -70,7 +70,7 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, R OrganizationsList.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', '$log', 'Rest', 'Alert', 'LoadBreadCrumbs', 'Prompt', 'GenerateList', 'OrganizationList', 'SearchInit', 'PaginateInit', 'ClearScope', 'ProcessErrors', - 'GetBasePath', 'SelectionInit' ]; + 'GetBasePath', 'SelectionInit', 'Wait' ]; function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, OrganizationForm, diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 8d14bfd167..1c18acd691 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -410,10 +410,12 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H function(RelatedSearchInit, RelatedPaginateInit, InventoryForm, GetBasePath) { return function(params) { // Rerfresh the Hosts view on right side of page - scope = params.scope; + + var group_id = params.group_id; + var scope = params.scope; scope['hosts'] = null; - var url = (scope.group_id !== null && scope.group_id !== undefined) ? GetBasePath('groups') + scope.group_id + '/all_hosts/' : + var url = (group_id !== null && group_id !== undefined) ? GetBasePath('groups') + group_id + '/all_hosts/' : GetBasePath('inventory') + params.inventory_id + '/hosts/'; var relatedSets = { hosts: { url: url, iterator: 'host' } }; diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 2dd7864728..cb694f1909 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -100,8 +100,8 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi }]) - .factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', 'GetBasePath', 'ProcessErrors', - function(Alert, Rest, Authorization, $http, LoadTreeData, GetBasePath, ProcessErrors) { + .factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', 'GetBasePath', 'ProcessErrors', 'Wait', + function(Alert, Rest, Authorization, $http, LoadTreeData, GetBasePath, ProcessErrors, Wait) { return function(params) { var scope = params.scope; @@ -200,6 +200,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi $(tree_id).bind('move_node.jstree', function(e, data) { // When user drags-n-drops a node, update the API + Wait('start'); var node, target, url, parent, inv_id, variables; node = $('#tree-view li[id="' + data.rslt.o[0].id + '"]'); // node being moved parent = $('#tree-view li[id="' + data.args[0].op[0].id + '"]'); //node moving from @@ -214,9 +215,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi function showSuccessMsg() { var parent_descr = (parent.attr('type') == 'inventory') ? 'the inventory root' : parent.attr('name'); var target_descr = (target.attr('type') == 'inventory') ? 'the inventory root' : target.attr('name'); - Alert('Group Moved', 'Group ' + node.attr('name') + ' was successfully moved from ' + parent_descr + - ' to ' + target_descr + '.', 'alert-success'); - scope['treeLoading'] = false; + Wait('stop'); if (!scope.$$phase) { scope.$digest(); } @@ -302,7 +301,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi '. GET returned status: ' + status }); }); - scope['treeLoading'] = true; + //scope['treeLoading'] = true; if (!scope.$$phase) { scope.$digest(); diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 0c98e17475..7bf4f7fcac 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -24,6 +24,35 @@ body { color: @black; } +.spinny { + display: none; + position: absolute; + z-index: 2000; + width: 75px; + height: 75px; + text-align:center; + color: #eee; + background-color: @black; + border: 1px solid @grey; + border-radius: 6px; + padding-top: 10px; + + p { + padding-top: 10px; + font-size: 11px; + } +} + +.overlay { + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 1999; + background-color: @black; + opacity: .4; +} + .tooltip { z-index: 1050; } @@ -603,7 +632,7 @@ input[type="text"].job-successful { .search-tree { ul { list-style-type: none; - padding-left: 10px; + padding-left: 13px; } ul:first-child { padding-left: 0; @@ -611,10 +640,21 @@ input[type="text"].job-successful { } .search-tree .active { - background-color: #ddd; + /*background-color: #ddd; padding: 1px 1px 1px 0; border: 1px solid #ddd; - border-radius: 4px; + border-radius: 4px;*/ + font-weight: bold; + color: #000; + } + + .search-tree .expand { + padding: 3px; + } + + .search-tree .expand:hover { + background-color: #ddd; + border: 1px solid #ddd; } .parse-selection { diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js index d3f1a5740d..15fee8919e 100644 --- a/awx/ui/static/lib/ansible/directives.js +++ b/awx/ui/static/lib/ansible/directives.js @@ -317,8 +317,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos } }]) - .directive('awTree', ['Rest', 'ProcessErrors', 'Authorization', '$compile', '$rootScope', 'HostsReload', - function(Rest, ProcessErrors, Authorization, $compile, $rootScope, HostsReload) { + .directive('awTree', ['Rest', 'ProcessErrors', 'Authorization', '$compile', '$rootScope', + function(Rest, ProcessErrors, Authorization, $compile, $rootScope) { return { //require: 'ngModel', @@ -335,104 +335,143 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos template: "
\n" + "\n" + "
\n", link: function(scope, elm , attrs) { var idx=1000; - - function toggle(e) { - var id = (e.target.tagName == 'I') ? e.target.parentNode.attributes.id.value : e.target.attributes.id.value; - var elm = angular.element(document.getElementById(id)); - function activate() { - /* Set the clicked node as active */ - $('.search-tree .active').removeClass('active'); - elm.addClass('active'); - var group = (elm.attr('data-group-id')) ? elm.attr('data-group-id') : null; - var parentScope = angular.element(document.getElementById('htmlTemplate')).scope(); - console.log('calling for group: ' + group); - HostsReload({ scope: parentScope, inventory_id: parentScope['inventory_id'], group_id: group }); + function refresh(parent) { + var group, title; + if (parent.attr('data-group-id')) { + group = parent.attr('data-group-id'); + title = '

' + parent.attr('data-name') + '

'; + title += (parent.attr('data-description') !== "") ? '

' + parent.attr('data-description') + '

' : ''; } - + else { + group = null; + title = '

All Hosts

' + } + scope.$emit('refreshHost', group, title); + } + + function activate(e) { + /* Set the clicked node as active */ + var elm = angular.element(e.target); // + var parent = angular.element(e.target.parentNode); //
  • + $('.search-tree .active').removeClass('active'); + elm.addClass('active'); + refresh(parent); + } + + function toggle(e) { + + var id, parent, elm, icon; + + if (e.target.tagName == 'I') { + id = e.target.parentNode.parentNode.attributes.id.value; + parent = angular.element(e.target.parentNode.parentNode); //
  • + elm = angular.element(e.target.parentNode); // + } + else { + id = e.target.parentNode.attributes.id.value; + parent = angular.element(e.target.parentNode); + elm = angular.element(e.target); + } + + var sibling = angular.element(parent.children()[1]); // + var state = parent.attr('data-state'); + var icon = angular.element(elm.children()[0]); + /* Open/close the node and expand */ if (scope.childrenLoadedRemove) { scope.childrenLoadedRemove(); } scope.childrenLoadedRemove = scope.$on('childrenLoaded', function() { - childlists = elm.parent().find('ul'); //look for children + childlists = parent.find('ul'); //look for children if (childlists && childlists.length > 0) { // bind toggle() to click event of each link in the group we clicked on - var parent = angular.element(elm.parent()[0]); var links = parent.find('a'); for (var i=0; i < links.length; i++) { var link = angular.element(links[i]); - link.unbind('click', toggle); - link.bind('click', toggle); + if (link.hasClass('expand')) { + link.unbind('click', toggle); + link.bind('click', toggle); + } + if (link.hasClass('activate')) { + link.unbind('click', activate); + link.bind('click', activate); + } } toggle(e); } else { - var icon = angular.element(elm.children()[0]); - icon.removeClass('icon-caret-down').removeClass('icon-caret-right').addClass('icon-ellipsis-horizontal'); + icon.removeClass('icon-caret-right').addClass('icon-caret-down'); + //activate(e); } }); - - if (elm.attr('data-state') == 'closed') { + + + if (state == 'closed') { // expand the elment - var childlists = elm.parent().find('ul'); + var childlists = parent.find('ul'); if (childlists && childlists.length > 0) { // already has childen for (var i=0; i < childlists.length; i++) { var listChild = angular.element(childlists[i]); - var listParent = angular.element(listChild.parent().find('a')[0]); - if (listParent.attr('id') == elm.attr('id')) { + var listParent = angular.element(listChild.parent()); + if (listParent.attr('id') == id) { angular.element(childlists[i]).removeClass('hidden'); } // all the children should be in a closed state - var aList = listChild.find('a'); - for (var j=0; j < aList.length; j++) { - var thisList = angular.element(aList[j]); + var liList = listChild.find('li'); + for (var j=0; j < liList.length; j++) { + var thisList = angular.element(liList[j]); + var anchor = angular.element(thisList.find('a')[0]); + var thisIcon = angular.element(anchor.children()[0]); + thisIcon.removeClass('icon-caret-down').addClass('icon-caret-right'); thisList.attr('data-state', 'closed'); - var icon = angular.element(thisList.children()[0]); - icon.removeClass('icon-caret-down').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-right'); } } - elm.attr('data-state','open'); - var icon = angular.element(elm.children()[0]); - icon.removeClass('icon-caret-right').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-down'); - activate(); + parent.attr('data-state','open'); + icon.removeClass('icon-caret-right').addClass('icon-caret-down'); } else { - getChildren(elm); + getChildren(elm, parent, sibling); } } else { // close the element - elm.attr('data-state','closed'); + parent.attr('data-state','closed'); var icon = angular.element(elm.children()[0]); - icon.removeClass('icon-caret-down').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-right'); - var childlists = elm.parent().find('ul'); + icon.removeClass('icon-caret-down').addClass('icon-caret-right'); + var childlists = parent.find('ul'); if (childlists && childlists.length > 0) { // has childen for (var i=0; i < childlists.length; i++) { angular.element(childlists[i]).addClass('hidden'); } } - activate(); + /* When the active node's parent is closed, activate the parent*/ + if ($(parent).find('.active').length > 0) { + $(parent).find('.active').removeClass('active'); + sibling.addClass('active'); + refresh(parent); + } + } } - } - function getChildren(elm) { - var url = elm.attr('data-groups'); + function getChildren(elm, parent, sibling) { + var url = parent.attr('data-groups'); var html = ''; var token = Authorization.getToken(); /* For reasons unknown calling Rest fails. It just dies with no errors @@ -445,23 +484,21 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos // build html and append to parent of clicked link for (var i=0; i < data.results.length; i++) { idx++; - html += "
  • \n"; - html += " " + data.results[i].name; - html += "
  • \n"; + html += "data-group-id=\"" + data.results[i].id + "\">"; + html += " "; + html += "" + data.results[i].name + "\n"; } html = (html !== '') ? "\n" : ""; - var parent = angular.element(elm.parent()[0]); var compiled = $compile(html)(scope); parent.append(compiled); //append the new list to the parent
  • - console.log('childrenLoaded'); scope.$emit('childrenLoaded'); }, error: function(data, status) { @@ -474,7 +511,10 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos function initialize() { var root = angular.element(document.getElementById('search-node-1000')); - root.bind('click', toggle); + var toggleElm = angular.element(root.find('a')[0]); + var activateElm = angular.element(root.find('a')[1]) + toggleElm.bind('click', toggle); + activateElm.bind('click', activate); } if ($rootScope.hostTabInitRemove) { @@ -484,18 +524,23 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos var container = angular.element(document.getElementById('search-tree-container')); container.empty(); var html = "\n"; var compiled = $compile(html)(scope); container.append(compiled); initialize(); - //setTimeout(function() { $('.search-tree .active').click(); }, 1000); //click the root node, forcing level 1 nodes to appear + // Expand the root node and show All Hosts + setTimeout(function() { + $('#search-node-1000 .expand').click(); + $('#search-node-1000 .activate').click(); + }, 500); }); } diff --git a/awx/ui/static/lib/ansible/utilities.js b/awx/ui/static/lib/ansible/utilities.js index aab37f5fa9..f9e88965bb 100644 --- a/awx/ui/static/lib/ansible/utilities.js +++ b/awx/ui/static/lib/ansible/utilities.js @@ -8,206 +8,233 @@ angular.module('Utilities',[]) .factory('ClearScope', function() { - return function(id) { - var element = document.getElementById(id); - var scope = angular.element(element).scope(); - scope.$destroy(); - } + return function(id) { + var element = document.getElementById(id); + var scope = angular.element(element).scope(); + scope.$destroy(); + } }) .factory('ToggleClass', function() { - return function(selector, cssClass) { - // Toggles the existance of a css class on a given element - if ( $(selector) && $(selector).hasClass(cssClass) ) { - $(selector).removeClass(cssClass); - } - else if ($(selector)) { - $(selector).addClass(cssClass); - } - } + return function(selector, cssClass) { + // Toggles the existance of a css class on a given element + if ( $(selector) && $(selector).hasClass(cssClass) ) { + $(selector).removeClass(cssClass); + } + else if ($(selector)) { + $(selector).addClass(cssClass); + } + } }) .factory('Alert', ['$rootScope', '$location', function($rootScope, $location) { - return function(hdr, msg, cls, action, secondAlert, disableButtons) { - // Pass in the header and message you want displayed on TB modal dialog found in index.html. - // Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success, - // alert-info...). Pass an optional function(){}, if you want a specific action to occur when user - // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. - if (secondAlert) { - $rootScope.alertHeader2 = hdr; - $rootScope.alertBody2 = msg; - $rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); - $rootScope.disableButtons2 = (disableButtons) ? true : false; - if (action) { - $('#alert-modal2').on('hidden', function() { - action(); - }); - } - $(document).bind('keydown', function(e) { - if (e.keyCode === 27) { - $('#alert-modal2').modal('hide'); - if (action) { - action(); - } - } - }); - } - else { - $rootScope.alertHeader = hdr; - $rootScope.alertBody = msg; - $rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); + return function(hdr, msg, cls, action, secondAlert, disableButtons) { + // Pass in the header and message you want displayed on TB modal dialog found in index.html. + // Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success, + // alert-info...). Pass an optional function(){}, if you want a specific action to occur when user + // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. + if (secondAlert) { + $rootScope.alertHeader2 = hdr; + $rootScope.alertBody2 = msg; + $rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger + $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); + $rootScope.disableButtons2 = (disableButtons) ? true : false; + if (action) { + $('#alert-modal2').on('hidden', function() { + action(); + }); + } + $(document).bind('keydown', function(e) { + if (e.keyCode === 27) { + $('#alert-modal2').modal('hide'); + if (action) { + action(); + } + } + }); + } + else { + $rootScope.alertHeader = hdr; + $rootScope.alertBody = msg; + $rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger + $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); - $(document).bind('keydown', function(e) { - if (e.keyCode === 27) { - $('#alert-modal').modal('hide'); - if (action) { - action(); - } - } - }); + $(document).bind('keydown', function(e) { + if (e.keyCode === 27) { + $('#alert-modal').modal('hide'); + if (action) { + action(); + } + } + }); - $rootScope.disableButtons = (disableButtons) ? true : false; - if (action) { - $('#alert-modal').on('hidden', function() { - action(); - }); - } - } - } + $rootScope.disableButtons = (disableButtons) ? true : false; + if (action) { + $('#alert-modal').on('hidden', function() { + action(); + }); + } + } + } }]) .factory('ProcessErrors', ['$log', 'Alert', function($log, Alert) { - return function(scope, data, status, form, defaultMsg) { - if (status == 403) { - var msg = 'The API responded with a 403 Access Denied error. '; - if (data['detail']) { - msg += 'Detail: ' + data['detail']; - } - else { - msg += 'Please contact your system administrator.'; - } - Alert(defaultMsg.hdr, msg); - } - else if (data.non_field_errors) { - Alert('Error!', data.non_field_errors); - } - else if (data.detail) { - Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); - } - else if (data['__all__']) { - Alert('Error!', data['__all__']); - } - else if (form) { - var fieldErrors = false; - for (var field in form.fields ) { - if (form.fields[field].realName) { - if (data[form.fields[field].realName]) { - scope[field + '_api_error'] = data[form.fields[field]][0]; - fieldErrors = true; - } - } - if (form.fields[field].sourceModel) { - if (data[field]) { - scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = - data[field][0]; - fieldErrors = true; - } - } - else { - if (data[field]) { - scope[field + '_api_error'] = data[field][0]; - fieldErrors = true; - } - } - } - if ( (!fieldErrors) && defaultMsg) { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } - else { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } + return function(scope, data, status, form, defaultMsg) { + if (status == 403) { + var msg = 'The API responded with a 403 Access Denied error. '; + if (data['detail']) { + msg += 'Detail: ' + data['detail']; + } + else { + msg += 'Please contact your system administrator.'; + } + Alert(defaultMsg.hdr, msg); + } + else if (data.non_field_errors) { + Alert('Error!', data.non_field_errors); + } + else if (data.detail) { + Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); + } + else if (data['__all__']) { + Alert('Error!', data['__all__']); + } + else if (form) { + var fieldErrors = false; + for (var field in form.fields ) { + if (form.fields[field].realName) { + if (data[form.fields[field].realName]) { + scope[field + '_api_error'] = data[form.fields[field]][0]; + fieldErrors = true; + } + } + if (form.fields[field].sourceModel) { + if (data[field]) { + scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = + data[field][0]; + fieldErrors = true; + } + } + else { + if (data[field]) { + scope[field + '_api_error'] = data[field][0]; + fieldErrors = true; + } + } + } + if ( (!fieldErrors) && defaultMsg) { + Alert(defaultMsg.hdr, defaultMsg.msg); + } + } + else { + Alert(defaultMsg.hdr, defaultMsg.msg); + } + } }]) .factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', function($rootScope, $routeParams, $location, Rest) { - return function(crumb) { - - //Keep a list of path/title mappings. When we see /organizations/XX in the path, for example, - //we'll know the actual organization name it maps to. - if (crumb !== null && crumb !== undefined) { - var found = false; - for (var i=0; i < $rootScope.crumbCache.length; i++) { - if ($rootScope.crumbCache[i].path == crumb.path) { - found = true; - $rootScope.crumbCache[i] = crumb; - break; - } - } - if (found == false) { - $rootScope.crumbCache.push(crumb); - } - } + return function(crumb) { + //Keep a list of path/title mappings. When we see /organizations/XX in the path, for example, + //we'll know the actual organization name it maps to. + if (crumb !== null && crumb !== undefined) { + var found = false; + for (var i=0; i < $rootScope.crumbCache.length; i++) { + if ($rootScope.crumbCache[i].path == crumb.path) { + found = true; + $rootScope.crumbCache[i] = crumb; + break; + } + } + if (found == false) { + $rootScope.crumbCache.push(crumb); + } + } - var paths = $location.path().replace(/^\//,'').split('/'); - var ppath = ''; - $rootScope.breadcrumbs = []; - if (paths.length > 1) { - var parent, child; - for (var i=0; i < paths.length - 1; i++) { - if (i > 0 && paths[i].match(/\d+/)) { - parent = paths[i-1]; - if (parent == 'inventories') { + var paths = $location.path().replace(/^\//,'').split('/'); + var ppath = ''; + $rootScope.breadcrumbs = []; + if (paths.length > 1) { + var parent, child; + for (var i=0; i < paths.length - 1; i++) { + if (i > 0 && paths[i].match(/\d+/)) { + parent = paths[i-1]; + if (parent == 'inventories') { child = 'inventory'; - } - else { - child = parent.substring(0,parent.length - 1); //assumes parent ends with 's' - } - // find the correct title - for (var j=0; j < $rootScope.crumbCache.length; j++) { - if ($rootScope.crumbCache[j].path == '/' + parent + '/' + paths[i]) { - child = $rootScope.crumbCache[j].title; - break; - } - } - $rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] }); - } - else { - $rootScope.breadcrumbs.push({ title: paths[i], path: ppath + '/' + paths[i] }); - } - ppath += '/' + paths[i]; - } - } - } + } + else { + child = parent.substring(0,parent.length - 1); //assumes parent ends with 's' + } + // find the correct title + for (var j=0; j < $rootScope.crumbCache.length; j++) { + if ($rootScope.crumbCache[j].path == '/' + parent + '/' + paths[i]) { + child = $rootScope.crumbCache[j].title; + break; + } + } + $rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] }); + } + else { + $rootScope.breadcrumbs.push({ title: paths[i], path: ppath + '/' + paths[i] }); + } + ppath += '/' + paths[i]; + } + } + } }]) .factory('ReturnToCaller', ['$location', function($location) { - return function(idx) { - // Split the current path by '/' and use the array elements from 0 up to and - // including idx as the new path. If no idx value supplied, use 0 to length - 1. + return function(idx) { + // Split the current path by '/' and use the array elements from 0 up to and + // including idx as the new path. If no idx value supplied, use 0 to length - 1. - var paths = $location.path().replace(/^\//,'').split('/'); - var newpath = ''; - idx = (idx == null || idx == undefined) ? paths.length - 1 : idx + 1; - for (var i=0; i < idx; i++) { - newpath += '/' + paths[i] - } - $location.path(newpath); - } + var paths = $location.path().replace(/^\//,'').split('/'); + var newpath = ''; + idx = (idx == null || idx == undefined) ? paths.length - 1 : idx + 1; + for (var i=0; i < idx; i++) { + newpath += '/' + paths[i] + } + $location.path(newpath); + } }]) .factory('FormatDate', [ function() { - return function(dt) { - var result = ('0' + (dt.getMonth() + 1)).slice(-2) + '/'; - result += ('0' + dt.getDate()).slice(-2) + '/'; - result += ('0' + (dt.getFullYear() - 2000)).slice(-2) + ' '; - result += ('0' + dt.getHours()).slice(-2) + ':'; - result += ('0' + dt.getMinutes()).slice(-2) + ':'; - result += ('0' + dt.getSeconds()).slice(-2); - //result += ('000' + dt.getMilliseconds()).slice(-3); - return result; - } + return function(dt) { + var result = ('0' + (dt.getMonth() + 1)).slice(-2) + '/'; + result += ('0' + dt.getDate()).slice(-2) + '/'; + result += ('0' + (dt.getFullYear() - 2000)).slice(-2) + ' '; + result += ('0' + dt.getHours()).slice(-2) + ':'; + result += ('0' + dt.getMinutes()).slice(-2) + ':'; + result += ('0' + dt.getSeconds()).slice(-2); + //result += ('000' + dt.getMilliseconds()).slice(-3); + return result; + } + }]) + + .factory('Wait', [ function() { + return function(directive) { + // Display a spinning icon in the center of the screen to freeze the + // UI while waiting on async things to complete (i.e. API calls). + // Wait('start' | 'stop'); + if (directive == 'start') { + var docw = $(document).width(); + var doch = $(document).height(); + var spinnyw = $('.spinny').width(); + var spinnyh = $('.spinny').height(); + var x = (docw - spinnyw) / 2; + var y = (doch - spinnyh) / 2; + console.log($(document)); + $('.overlay').css({ + width: $('html').width(), + height: $(document).height() + 200 + }).fadeIn(500); + $('.spinny').css({ + top: y, + left: x, + }).fadeIn(500); + } + else { + $('.spinny, .overlay').fadeOut(2000); + } + } }]); \ No newline at end of file diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 364ca4fee1..1658eff0f3 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -320,6 +320,9 @@ + +
    +

    working...