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",
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" +
"\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 @@
+
+
+