. Seems to be a bug in TB3 RC1
- $(this).remove();
- });
- // Set the focust to the first form field
- $('input:first').focus();
- });
-
- // Disable all the group related buttons
- scope.grpBtnDisable = false;
- }
-
- scope.closeForm = function() {
- // Slide in the group properties form
- $('#tree-form').hide('slide',{ direction: 'right' }, 500, function() { $('#tree-form').empty(); });
- scope.grpBtnDisable = false;
- }
-
- scope.editInventory = function() {
- EditInventory({ scope: scope, inventory_id: id });
- }
-
- scope.deleteGroup = function() {
- GroupsDelete({ scope: scope, "inventory_id": id, group_id: scope.group_id });
- }
-
- scope.editHosts = function() {
- $location.path('/inventories/' + scope.inventory_id + '/hosts');
- }
-}
-
-InventoryGroups.$inject = [
- '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryGroupsForm',
- 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt',
- 'BuildTree', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory',
- 'GroupsDelete', 'EditInventory', 'InventoryStatus', 'Stream'
- ];
-
\ No newline at end of file
diff --git a/awx/ui/static/js/controllers/Hosts.js b/awx/ui/static/js/controllers/Hosts.js
deleted file mode 100644
index 4dba753e3d..0000000000
--- a/awx/ui/static/js/controllers/Hosts.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/************************************
- * Copyright (c) 2014 AnsibleWorks, Inc.
- *
- * Hosts.js
- *
- * Controller functions for the Hosts model.
- *
- */
-
-'use strict';
-
-function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryHostsForm,
- GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
- RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
- GetBasePath, HostsList, HostsAdd, HostsEdit, HostsDelete,
- HostsReload, BuildTree, EditHostGroups, InventoryHostsHelp, HelpDialog, Wait,
- ToggleHostEnabled, Stream)
-{
- ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
- //scope.
-
- var generator = GenerateForm;
- var form = InventoryHostsForm;
- var defaultUrl=GetBasePath('inventory');
- var scope = generator.inject(form, {mode: 'edit', related: true, buildTree: true});
- var base = $location.path().replace(/^\//,'').split('/')[0];
- var id = $routeParams.inventory_id;
-
- scope['inventory_id'] = id;
- scope['hostAddHide'] = true;
- scope['hostCreateHide'] = true;
- scope['hosts'] = null;
- scope['helpCount'] = 0;
-
- // buildAllGroups emits from TreeSelector.js after the inventory object is ready
- if (scope.loadBreadCrumbsRemove) {
- scope.loadBreadCrumbsRemove();
- }
- scope.loadBreadCrumbsRemove = scope.$on('buildAllGroups', function(e, inventory_name) {
- LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name });
- });
-
- scope.showActivity = function() { Stream(); }
-
- scope.filterHosts = function() {
- HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
- }
-
- scope.addHost = function() {
- HostsList({ scope: scope, "inventory_id": id, group_id: scope.group_id });
- }
-
- scope.createHost = function() {
- HostsAdd({ scope: scope, "inventory_id": id, group_id: scope.group_id });
- }
-
- scope.editHost = function(host_id, host_name) {
- HostsEdit({ scope: scope, "inventory_id": id, group_id: scope.group_id, host_id: host_id, host_name: host_name });
- }
-
- scope.editGroups = function() {
- $location.path('/inventories/' + scope.inventory_id + '/groups');
- }
-
- scope.editHostGroups = function(host_id) {
- EditHostGroups({ inventory_id: id, host_id: host_id });
- }
-
- scope.deleteHost = function(host_id, host_name) {
- HostsDelete({ scope: scope, "inventory_id": id, group_id: scope.group_id, host_id: host_id, host_name: host_name,
- request: 'delete' });
- }
-
- scope.viewJobs = function(last_job) {
- $location.url('/jobs/?id__int=' + last_job );
- }
-
- scope.allJobs = function(id) {
- $location.url('/jobs/?job_host_summaries__host=' + id);
- }
-
- scope.toggle_host_enabled = function(id, sources) { ToggleHostEnabled(id, sources, scope); }
-
- scope.allHostSummaries = function(id, name, inventory_id) {
- LoadBreadCrumbs({ path: '/hosts/' + id, title: name, altPath: '/inventories/' + inventory_id + '/hosts',
- inventory_id: inventory_id });
- $location.url('/hosts/' + id + '/job_host_summaries/?inventory=' + inventory_id);
- }
-
- scope.viewLastEvents = function(host_id, last_job, host_name, last_job_name) {
- // Choose View-> Latest job events
- LoadBreadCrumbs({ path: '/jobs/' + last_job, title: last_job_name });
- $location.url('/jobs/' + last_job + '/job_events/?host=' + escape(host_name));
- }
-
- scope.viewLastSummary = function(host_id, last_job, host_name, last_job_name) {
- // Choose View-> Latest job events
- LoadBreadCrumbs({ path: '/jobs/' + last_job, title: last_job_name });
- $location.url('/jobs/' + last_job + '/job_host_summaries/?host=' + escape(host_name));
- }
-
- if (scope.removeShowHelp) {
- scope.removeShowHelp();
- }
- scope.removeShowHelp = scope.$on('ShowHelp', function() {
- // Force display fo help tooltip when no groups exist
- $('#hosts-page-help').focus();
- });
-
- scope.showHelp = function() {
- // Display help dialog
- $('.btn').blur(); //remove focus from the help button and all buttons
- //this stops the tooltip from continually displaying
- HelpDialog({ defn: InventoryHostsHelp });
- }
-
- // Refresh host is emitted each time a group on the selector tree is clicked
- if (scope.refreshHostRemove) {
- scope.refreshHostRemove();
- }
- scope.refreshHostRemove = scope.$on('refreshHost', function(e, id, group, title) {
- scope.groupTitle = title;
- scope.group_id = group;
- scope.helpCount++;
- if (scope.group_id == null) {
- scope.groupTitle = 'All Hosts';
- scope.hostAddHide = true;
- scope.hostCreateHide = true;
- scope.hostDeleteHide = true;
- }
- else {
- scope.hostAddHide = false;
- scope.hostCreateHide = false;
- scope.hostDeleteHide = false;
- }
- scope['hostDeleteDisabled'] = true;
- scope['hostDeleteDisabledClass'] = 'disabled';
- HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: group });
- });
-
- // Load the tree. See TreeSelector.js
- var group_id = ($routeParams['group'] !== undefined) ? $routeParams['group'] : null;
- if (group_id !== null) {
- // group was passed as a search parameter. load the tree with the group selected.
- BuildTree({
- scope: scope,
- inventory_id: id,
- emit_on_select: 'refreshHost',
- target_id: 'search-tree-container',
- refresh: true,
- group_id: group_id
- });
- }
- else {
- BuildTree({
- scope: scope,
- inventory_id: id,
- emit_on_select: 'refreshHost',
- target_id: 'search-tree-container'
- });
- }
-}
-
-InventoryHosts.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryHostsForm',
- 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
- 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
- 'GetBasePath', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete',
- 'HostsReload', 'BuildTree', 'EditHostGroups', 'InventoryHostsHelp', 'HelpDialog', 'Wait',
- 'ToggleHostEnabled', 'Stream'
- ];
-
diff --git a/awx/ui/static/js/controllers/JobEvents.js b/awx/ui/static/js/controllers/JobEvents.js
index 281ae44a38..bca8c3a81b 100644
--- a/awx/ui/static/js/controllers/JobEvents.js
+++ b/awx/ui/static/js/controllers/JobEvents.js
@@ -239,7 +239,8 @@ JobEventsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routePa
];
function JobEventsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobEventForm, GenerateForm,
- Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, FormatDate, EventView)
+ Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, FormatDate, EventView,
+ Wait)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@@ -253,6 +254,7 @@ function JobEventsEdit ($scope, $rootScope, $compile, $location, $log, $routePar
var base = $location.path().replace(/^\//,'').split('/')[0];
// Retrieve detail record and prepopulate the form
+ Wait('start');
Rest.setUrl(defaultUrl);
Rest.get()
.success( function(data, status, headers, config) {
@@ -316,6 +318,7 @@ function JobEventsEdit ($scope, $rootScope, $compile, $location, $log, $routePar
break;
}
}
+ Wait('stop');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
@@ -338,5 +341,5 @@ function JobEventsEdit ($scope, $rootScope, $compile, $location, $log, $routePar
JobEventsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobEventForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath',
- 'FormatDate', 'EventView'
+ 'FormatDate', 'EventView', 'Wait'
];
diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js
index 498dcf4d3d..1c806bb825 100644
--- a/awx/ui/static/js/controllers/Jobs.js
+++ b/awx/ui/static/js/controllers/Jobs.js
@@ -273,8 +273,6 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
scope['callback_url'] = data.related['callback'];
})
.error( function(data, status, headers, config) {
- //ProcessErrors(scope, data, status, form,
- // { hdr: 'Error!', msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status });
scope['callback_url'] = '<< Job template not found >>';
});
@@ -291,6 +289,8 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
});
}
+ Wait('stop');
+
});
// Our job type options
@@ -308,8 +308,8 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
return (rows > 15) ? 15 : rows;
}
-
// Retrieve detail record and prepopulate the form
+ Wait('start');
Rest.setUrl(defaultUrl + ':id/');
Rest.get({ params: {id: id} })
.success( function(data, status, headers, config) {
@@ -437,77 +437,6 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
{ hdr: 'Error!', msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status });
});
- // Save changes to the parent
- scope.formSave = function() {
- generator.clearApiErrors();
- Rest.setUrl(defaultUrl + $routeParams.id + '/');
- var data = {}
- for (var fld in form.fields) {
- if (form.fields[fld].type == 'select' && fld != 'playbook') {
- data[fld] = scope[fld].value;
- }
- else {
- data[fld] = scope[fld];
- }
- }
- Rest.put(data)
- .success( function(data, status, headers, config) {
- var base = $location.path().replace(/^\//,'').split('/')[0];
- (base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1);
- })
- .error( function(data, status, headers, config) {
- ProcessErrors(scope, data, status, form,
- { hdr: 'Error!', msg: 'Failed to update job ' + $routeParams.id + '. PUT returned status: ' + status });
- });
- };
-
- // Cancel
- scope.formReset = function() {
- generator.reset();
- for (var fld in master) {
- scope[fld] = master[fld];
- }
- $('#forks-slider').slider("option", "value", scope.forks);
- };
-
- // Related set: Add button
- scope.add = function(set) {
- $rootScope.flashMessage = null;
- $location.path('/' + base + '/' + $routeParams.id + '/' + set);
- };
-
- // Related set: Edit button
- scope.edit = function(set, id, name) {
- $rootScope.flashMessage = null;
- $location.path('/' + base + '/' + $routeParams.id + '/' + set + '/' + id);
- };
-
- // Related set: Delete button
- scope['delete'] = function(set, itm_id, name, title) {
- $rootScope.flashMessage = null;
-
- var action = function() {
- var url = defaultUrl + id + '/' + set + '/';
- Rest.setUrl(url);
- Rest.post({ id: itm_id, disassociate: 1 })
- .success( function(data, status, headers, config) {
- $('#prompt-modal').modal('hide');
- scope.search(form.related[set].iterator);
- })
- .error( function(data, status, headers, config) {
- $('#prompt-modal').modal('hide');
- ProcessErrors(scope, data, status, null,
- { hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST returned status: ' + status });
- });
- };
-
- Prompt({ hdr: 'Delete',
- body: 'Are you sure you want to remove ' + name + ' from ' + scope.name + ' ' + title + '?',
- action: action
- });
-
- }
-
scope.refresh = function() {
Wait('start');
Rest.setUrl(defaultUrl + id + '/');
diff --git a/awx/ui/static/js/controllers/Organizations.js b/awx/ui/static/js/controllers/Organizations.js
index d9a9fa472b..13528e51ab 100644
--- a/awx/ui/static/js/controllers/Organizations.js
+++ b/awx/ui/static/js/controllers/Organizations.js
@@ -166,9 +166,11 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
for (var set in relatedSets) {
scope.search(relatedSets[set].iterator);
}
+ Wait('stop');
});
// Retrieve detail record and prepopulate the form
+ Wait('start');
Rest.setUrl(defaultUrl + id + '/');
Rest.get()
.success( function(data, status, headers, config) {
diff --git a/awx/ui/static/js/controllers/Permissions.js b/awx/ui/static/js/controllers/Permissions.js
index d326f2f449..5787fa1ab5 100644
--- a/awx/ui/static/js/controllers/Permissions.js
+++ b/awx/ui/static/js/controllers/Permissions.js
@@ -196,6 +196,7 @@ function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
PermissionCategoryChange({ scope: scope, reset: reset }); }
// Retrieve detail record and prepopulate the form
+ Wait('start');
Rest.setUrl(defaultUrl);
Rest.get()
.success( function(data, status, headers, config) {
@@ -251,6 +252,7 @@ function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
}
});
}
+ Wait('stop');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
diff --git a/awx/ui/static/js/controllers/Projects.js b/awx/ui/static/js/controllers/Projects.js
index 983cd6a032..ac5e99bc56 100644
--- a/awx/ui/static/js/controllers/Projects.js
+++ b/awx/ui/static/js/controllers/Projects.js
@@ -515,6 +515,7 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
scope.pathRequired = (scope.scm_type.value == '') ? true : false;
scope.scmRequired = (scope.scm_type.value !== '') ? true : false;
scope.scmBranchLabel = (scope.scm_type.value == 'svn') ? 'Revision #' : 'SCM Branch';
+ Wait('stop');
});
if (scope.removeChoicesReady) {
@@ -587,6 +588,7 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
});
// Load the list of options for Kind
+ Wait('start');
GetChoices({
url: GetBasePath('projects'),
scope: scope,
diff --git a/awx/ui/static/js/controllers/Teams.js b/awx/ui/static/js/controllers/Teams.js
index d0c51f8cb3..c81d04121c 100644
--- a/awx/ui/static/js/controllers/Teams.js
+++ b/awx/ui/static/js/controllers/Teams.js
@@ -188,6 +188,7 @@ function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
.success( function(data, status, headers, config) {
scope['organization_name'] = data.name;
master['organization_name'] = data.name;
+ Wait('stop');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
@@ -199,6 +200,7 @@ function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
});
// Retrieve detail record and prepopulate the form
+ Wait('stop');
Rest.setUrl(defaultUrl + ':id/');
Rest.get({ params: {id: id} })
.success( function(data, status, headers, config) {
diff --git a/awx/ui/static/js/controllers/Users.js b/awx/ui/static/js/controllers/Users.js
index 92308bf14b..8f37b1c07f 100644
--- a/awx/ui/static/js/controllers/Users.js
+++ b/awx/ui/static/js/controllers/Users.js
@@ -228,6 +228,7 @@ function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
scope.search(relatedSets[set].iterator);
}
CheckAccess({ scope: scope }); //Does the user have access to add/edit Permissions?
+ Wait('stop');
});
// Retrieve detail record and prepopulate the form
@@ -428,7 +429,8 @@ function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
{ hdr: 'Error!', msg: 'Failed to retrieve application config. GET status: ' + status });
});
});
-
+
+ Wait('start');
Rest.setUrl(defaultUrl + id + '/');
Rest.get()
.success( function(data, status, headers, config) {
diff --git a/awx/ui/static/js/helpers/Users.js b/awx/ui/static/js/helpers/Users.js
index fc825bd651..17cbbf351d 100644
--- a/awx/ui/static/js/helpers/Users.js
+++ b/awx/ui/static/js/helpers/Users.js
@@ -22,8 +22,6 @@ angular.module('UserHelper', [ 'UserFormDefinition' ])
UserForm.fields['organization'].readonly = false;
UserForm.fields['username'].awRequiredWhen = { variable: "not_ldap_user", init: true };
UserForm.fields['username'].readonly = false;
- //UserForm.fields['password'].awRequiredWhen = { variable: "not_ldap_user", init: true },
- //UserForm.fields['password'].readonly = false;
UserForm.fields['password'].editRequired = false;
UserForm.fields['password'].addRrequired = true;
}
diff --git a/awx/ui/static/js/lists/Organizations.js b/awx/ui/static/js/lists/Organizations.js
index 6d637b5e22..6eeaa7c55d 100644
--- a/awx/ui/static/js/lists/Organizations.js
+++ b/awx/ui/static/js/lists/Organizations.js
@@ -44,7 +44,7 @@ angular.module('OrganizationListDefinition', [])
fieldActions: {
edit: {
label: 'Edit',
- ngClick: "editOrganization(\{\{ organization.id \}\})",
+ ngClick: "editOrganization(organization.id)",
icon: 'icon-edit',
"class": 'btn-xs btn-default',
awToolTip: 'Edit organization',
@@ -53,7 +53,7 @@ angular.module('OrganizationListDefinition', [])
"delete": {
label: 'Delete',
- ngClick: "deleteOrganization(\{\{ organization.id \}\},'\{\{ organization.name \}\}')",
+ ngClick: "deleteOrganization(organization.id, organization.name)",
icon: 'icon-trash',
"class": 'btn-xs btn-danger',
awToolTip: 'Delete organization',
diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less
index 9db50f95f8..414a1ebeea 100644
--- a/awx/ui/static/less/ansible-ui.less
+++ b/awx/ui/static/less/ansible-ui.less
@@ -1329,6 +1329,12 @@ tr td button i {
}
*/
+/* ng-cloak directive */
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+ display: none !important;
+}
+
/* Large desktop */
diff --git a/awx/ui/static/lib/3.4.5 b/awx/ui/static/lib/3.4.5
deleted file mode 100644
index b1a5bca845..0000000000
Binary files a/awx/ui/static/lib/3.4.5 and /dev/null differ
diff --git a/awx/ui/static/lib/angular-1.2.9/angular-cookies.js b/awx/ui/static/lib/angular-1.2.9/angular-cookies.js
new file mode 100644
index 0000000000..13347e0564
--- /dev/null
+++ b/awx/ui/static/lib/angular-1.2.9/angular-cookies.js
@@ -0,0 +1,202 @@
+/**
+ * @license AngularJS v1.2.9
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {'use strict';
+
+/**
+ * @ngdoc overview
+ * @name ngCookies
+ * @description
+ *
+ * # ngCookies
+ *
+ * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
+ *
+ * {@installModule cookies}
+ *
+ *
+ *
+ * See {@link ngCookies.$cookies `$cookies`} and
+ * {@link ngCookies.$cookieStore `$cookieStore`} for usage.
+ */
+
+
+angular.module('ngCookies', ['ng']).
+ /**
+ * @ngdoc object
+ * @name ngCookies.$cookies
+ * @requires $browser
+ *
+ * @description
+ * Provides read/write access to browser's cookies.
+ *
+ * Only a simple Object is exposed and by adding or removing properties to/from
+ * this object, new cookies are created/deleted at the end of current $eval.
+ *
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
+ *
+ * @example
+
+
+
+
+
+ */
+ factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
+ var cookies = {},
+ lastCookies = {},
+ lastBrowserCookies,
+ runEval = false,
+ copy = angular.copy,
+ isUndefined = angular.isUndefined;
+
+ //creates a poller fn that copies all cookies from the $browser to service & inits the service
+ $browser.addPollFn(function() {
+ var currentCookies = $browser.cookies();
+ if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
+ lastBrowserCookies = currentCookies;
+ copy(currentCookies, lastCookies);
+ copy(currentCookies, cookies);
+ if (runEval) $rootScope.$apply();
+ }
+ })();
+
+ runEval = true;
+
+ //at the end of each eval, push cookies
+ //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
+ // strings or browser refuses to store some cookies, we update the model in the push fn.
+ $rootScope.$watch(push);
+
+ return cookies;
+
+
+ /**
+ * Pushes all the cookies from the service to the browser and verifies if all cookies were
+ * stored.
+ */
+ function push() {
+ var name,
+ value,
+ browserCookies,
+ updated;
+
+ //delete any cookies deleted in $cookies
+ for (name in lastCookies) {
+ if (isUndefined(cookies[name])) {
+ $browser.cookies(name, undefined);
+ }
+ }
+
+ //update all cookies updated in $cookies
+ for(name in cookies) {
+ value = cookies[name];
+ if (!angular.isString(value)) {
+ if (angular.isDefined(lastCookies[name])) {
+ cookies[name] = lastCookies[name];
+ } else {
+ delete cookies[name];
+ }
+ } else if (value !== lastCookies[name]) {
+ $browser.cookies(name, value);
+ updated = true;
+ }
+ }
+
+ //verify what was actually stored
+ if (updated){
+ updated = false;
+ browserCookies = $browser.cookies();
+
+ for (name in cookies) {
+ if (cookies[name] !== browserCookies[name]) {
+ //delete or reset all cookies that the browser dropped from $cookies
+ if (isUndefined(browserCookies[name])) {
+ delete cookies[name];
+ } else {
+ cookies[name] = browserCookies[name];
+ }
+ updated = true;
+ }
+ }
+ }
+ }
+ }]).
+
+
+ /**
+ * @ngdoc object
+ * @name ngCookies.$cookieStore
+ * @requires $cookies
+ *
+ * @description
+ * Provides a key-value (string-object) storage, that is backed by session cookies.
+ * Objects put or retrieved from this storage are automatically serialized or
+ * deserialized by angular's toJson/fromJson.
+ *
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
+ *
+ * @example
+ */
+ factory('$cookieStore', ['$cookies', function($cookies) {
+
+ return {
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#get
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Returns the value of given cookie key
+ *
+ * @param {string} key Id to use for lookup.
+ * @returns {Object} Deserialized cookie value.
+ */
+ get: function(key) {
+ var value = $cookies[key];
+ return value ? angular.fromJson(value) : value;
+ },
+
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#put
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Sets a value for given cookie key
+ *
+ * @param {string} key Id for the `value`.
+ * @param {Object} value Value to be stored.
+ */
+ put: function(key, value) {
+ $cookies[key] = angular.toJson(value);
+ },
+
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#remove
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Remove given cookie
+ *
+ * @param {string} key Id of the key-value pair to delete.
+ */
+ remove: function(key) {
+ delete $cookies[key];
+ }
+ };
+
+ }]);
+
+
+})(window, window.angular);
diff --git a/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js b/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js
new file mode 100644
index 0000000000..45b6114298
--- /dev/null
+++ b/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js
@@ -0,0 +1,8 @@
+/*
+ AngularJS v1.2.9
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&d.$apply())})();k=!0;d.$watch(function(){var a,e,d;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)(e=c[a],f.isString(e))?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(m(e[a])?delete c[a]:c[a]=e[a])});
+return c}]).factory("$cookieStore",["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular);
+//# sourceMappingURL=angular-cookies.min.js.map
diff --git a/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js.map b/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js.map
new file mode 100644
index 0000000000..a7fd1e9caa
--- /dev/null
+++ b/awx/ui/static/lib/angular-1.2.9/angular-cookies.min.js.map
@@ -0,0 +1,8 @@
+{
+"version":3,
+"file":"angular-cookies.min.js",
+"lineCount":7,
+"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAoBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA4BW,UA5BX,CA4BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CAEE,CADAY,CACK,CADGZ,CAAA,CAAQW,CAAR,CACH,CAAAjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAAL,EAMWA,CANX,GAMqBX,CAAA,CAAYU,CAAZ,CANrB,GAOEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CARZ,EACMnB,CAAAqB,UAAA,CAAkBd,CAAA,CAAYU,CAAZ,CAAlB,CAAJ,CACEX,CAAA,CAAQW,CAAR,CADF,CACkBV,CAAA,CAAYU,CAAZ,CADlB,CAGE,OAAOX,CAAA,CAAQW,CAAR,CASb,IAAIE,CAAJ,CAIE,IAAKF,CAAL,GAFAK,EAEahB,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBK,CAAA,CAAeL,CAAf,CAAtB,GAEMN,CAAA,CAAYW,CAAA,CAAeL,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBK,CAAA,CAAeL,CAAf,CALpB,CAlCU,CAThB,CAEA;MAAOX,EA1BqE,CAA3D,CA5BvB,CAAAH,QAAA,CA4HW,cA5HX,CA4H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAYAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAZd,KA4BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA5BrB,QA0CGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CA1CjB,CAF8C,CAAhC,CA5H3B,CApBsC,CAArC,CAAA,CAoME1B,MApMF,CAoMUA,MAAAC,QApMV;",
+"sources":["angular-cookies.js"],
+"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","isDefined","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"]
+}
diff --git a/awx/ui/static/lib/angular-1.2.9/angular-csp.css b/awx/ui/static/lib/angular-1.2.9/angular-csp.css
new file mode 100644
index 0000000000..763f7b9e01
--- /dev/null
+++ b/awx/ui/static/lib/angular-1.2.9/angular-csp.css
@@ -0,0 +1,13 @@
+/* Include this file in your html if you are using the CSP mode. */
+
+@charset "UTF-8";
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
+.ng-cloak, .x-ng-cloak,
+.ng-hide {
+ display: none !important;
+}
+
+ng\:form {
+ display: block;
+}
diff --git a/awx/ui/static/lib/angular-1.2.9/angular-resource.js b/awx/ui/static/lib/angular-1.2.9/angular-resource.js
new file mode 100644
index 0000000000..bb15b7e711
--- /dev/null
+++ b/awx/ui/static/lib/angular-1.2.9/angular-resource.js
@@ -0,0 +1,594 @@
+/**
+ * @license AngularJS v1.2.9
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {'use strict';
+
+var $resourceMinErr = angular.$$minErr('$resource');
+
+// Helper functions and regex to lookup a dotted path on an object
+// stopping at undefined/null. The path must be composed of ASCII
+// identifiers (just like $parse)
+var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
+
+function isValidDottedPath(path) {
+ return (path != null && path !== '' && path !== 'hasOwnProperty' &&
+ MEMBER_NAME_REGEX.test('.' + path));
+}
+
+function lookupDottedPath(obj, path) {
+ if (!isValidDottedPath(path)) {
+ throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
+ }
+ var keys = path.split('.');
+ for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
+ var key = keys[i];
+ obj = (obj !== null) ? obj[key] : undefined;
+ }
+ return obj;
+}
+
+/**
+ * Create a shallow copy of an object and clear other fields from the destination
+ */
+function shallowClearAndCopy(src, dst) {
+ dst = dst || {};
+
+ angular.forEach(dst, function(value, key){
+ delete dst[key];
+ });
+
+ for (var key in src) {
+ if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
+ dst[key] = src[key];
+ }
+ }
+
+ return dst;
+}
+
+/**
+ * @ngdoc overview
+ * @name ngResource
+ * @description
+ *
+ * # ngResource
+ *
+ * The `ngResource` module provides interaction support with RESTful services
+ * via the $resource service.
+ *
+ * {@installModule resource}
+ *
+ *
+ *
+ * See {@link ngResource.$resource `$resource`} for usage.
+ */
+
+/**
+ * @ngdoc object
+ * @name ngResource.$resource
+ * @requires $http
+ *
+ * @description
+ * A factory which creates a resource object that lets you interact with
+ * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
+ *
+ * The returned resource object has action methods which provide high-level behaviors without
+ * the need to interact with the low level {@link ng.$http $http} service.
+ *
+ * Requires the {@link ngResource `ngResource`} module to be installed.
+ *
+ * @param {string} url A parametrized URL template with parameters prefixed by `:` as in
+ * `/user/:username`. If you are using a URL with a port number (e.g.
+ * `http://example.com:8080/api`), it will be respected.
+ *
+ * If you are using a url with a suffix, just add the suffix, like this:
+ * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
+ * or even `$resource('http://example.com/resource/:resource_id.:format')`
+ * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
+ * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
+ * can escape it with `/\.`.
+ *
+ * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
+ * `actions` methods. If any of the parameter value is a function, it will be executed every time
+ * when a param value needs to be obtained for a request (unless the param was overridden).
+ *
+ * Each key value in the parameter object is first bound to url template if present and then any
+ * excess keys are appended to the url search query after the `?`.
+ *
+ * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
+ * URL `/path/greet?salutation=Hello`.
+ *
+ * If the parameter value is prefixed with `@` then the value of that parameter is extracted from
+ * the data object (useful for non-GET operations).
+ *
+ * @param {Object.
+ */
+ /* global -ngRouteModule */
+var ngRouteModule = angular.module('ngRoute', ['ng']).
+ provider('$route', $RouteProvider);
+
+/**
+ * @ngdoc object
+ * @name ngRoute.$routeProvider
+ * @function
+ *
+ * @description
+ *
+ * Used for configuring routes.
+ *
+ * ## Example
+ * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
+ *
+ * ## Dependencies
+ * Requires the {@link ngRoute `ngRoute`} module to be installed.
+ */
+function $RouteProvider(){
+ function inherit(parent, extra) {
+ return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
+ }
+
+ var routes = {};
+
+ /**
+ * @ngdoc method
+ * @name ngRoute.$routeProvider#when
+ * @methodOf ngRoute.$routeProvider
+ *
+ * @param {string} path Route path (matched against `$location.path`). If `$location.path`
+ * contains redundant trailing slash or is missing one, the route will still match and the
+ * `$location.path` will be updated to add or drop the trailing slash to exactly match the
+ * route definition.
+ *
+ * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
+ * to the next slash are matched and stored in `$routeParams` under the given `name`
+ * when the route matches.
+ * * `path` can contain named groups starting with a colon and ending with a star:
+ * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
+ * when the route matches.
+ * * `path` can contain optional named groups with a question mark: e.g.`:name?`.
+ *
+ * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
+ * `/color/brown/largecode/code/with/slashs/edit` and extract:
+ *
+ * * `color: brown`
+ * * `largecode: code/with/slashs`.
+ *
+ *
+ * @param {Object} route Mapping information to be assigned to `$route.current` on route
+ * match.
+ *
+ * Object properties:
+ *
+ * - `controller` – `{(string|function()=}` – Controller fn that should be associated with
+ * newly created scope or the name of a {@link angular.Module#controller registered
+ * controller} if passed as a string.
+ * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
+ * published to scope under the `controllerAs` name.
+ * - `template` – `{string=|function()=}` – html template as a string or a function that
+ * returns an html template as a string which should be used by {@link
+ * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
+ * This property takes precedence over `templateUrl`.
+ *
+ * If `template` is a function, it will be called with the following parameters:
+ *
+ * - `{Array.