From 152ddc4f4f2d43b19db68d506d96fec64729302a Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Tue, 20 Oct 2015 21:32:45 -0400 Subject: [PATCH 01/65] Rename task_ to job_ for pre-task fail error --- awx/main/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 8b83383737..b18df63b92 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -191,7 +191,7 @@ def handle_work_error(self, task_id, subtasks=None): if instance.celery_task_id != task_id: instance.status = 'failed' instance.failed = True - instance.job_explanation = 'Previous Task Failed: {"task_type": "%s", "task_name": "%s", "task_id": "%s"}' % \ + instance.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % \ (first_task_type, first_task_name, first_task_id) instance.save() instance.socketio_emit_status("failed") From 8dfc9e482e4fc03bbad2f7fb9dc60e4e32659bf2 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 21 Oct 2015 20:31:21 -0700 Subject: [PATCH 02/65] Revamp options request helper to work for other choice fields This moves the get-choices and get-labels services to the rest module The get-choices service is also revamped so that a field name can be passed to check the options request json All uses of get choices were revamped to utilize the new naming convention --- awx/ui/client/src/controllers/Teams.js | 11 ++++++----- awx/ui/client/src/controllers/Users.js | 11 ++++++----- .../client/src/permissions/add/add.controller.js | 11 ++++++----- .../src/permissions/edit/edit.controller.js | 11 ++++++----- .../src/permissions/list/list.controller.js | 11 ++++++----- awx/ui/client/src/permissions/main.js | 4 ---- .../shared => rest}/get-choices.factory.js | 16 ++++++++++------ .../shared => rest}/get-labels.factory.js | 0 awx/ui/client/src/rest/main.js | 6 +++++- 9 files changed, 45 insertions(+), 36 deletions(-) rename awx/ui/client/src/{permissions/shared => rest}/get-choices.factory.js (66%) rename awx/ui/client/src/{permissions/shared => rest}/get-labels.factory.js (100%) diff --git a/awx/ui/client/src/controllers/Teams.js b/awx/ui/client/src/controllers/Teams.js index ab5dc9298f..6fe42bc955 100644 --- a/awx/ui/client/src/controllers/Teams.js +++ b/awx/ui/client/src/controllers/Teams.js @@ -176,7 +176,7 @@ TeamsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$r export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, GetBasePath, CheckAccess, - OrganizationList, Wait, Stream, permissionsChoices, permissionsLabel, permissionsSearchSelect) { + OrganizationList, Wait, Stream, fieldChoices, fieldLabels, permissionsSearchSelect) { ClearScope(); @@ -192,16 +192,17 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP $scope.permission_search_select = []; // return a promise from the options request with the permission type choices (including adhoc) as a param - var permissionsChoice = permissionsChoices({ + var permissionsChoice = fieldChoices({ scope: $scope, - url: 'api/v1/' + base + '/' + id + '/permissions/' + url: 'api/v1/' + base + '/' + id + '/permissions/', + field: 'permission_type' }); // manipulate the choices from the options request to be set on // scope and be usable by the list form permissionsChoice.then(function (choices) { choices = - permissionsLabel({ + fieldLabels({ choices: choices }); _.map(choices, function(n, key) { @@ -431,5 +432,5 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP TeamsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', - 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect' + 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect' ]; diff --git a/awx/ui/client/src/controllers/Users.js b/awx/ui/client/src/controllers/Users.js index 2a37115a16..3aa0b98662 100644 --- a/awx/ui/client/src/controllers/Users.js +++ b/awx/ui/client/src/controllers/Users.js @@ -208,7 +208,7 @@ UsersAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$r export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeParams, UserForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, GetBasePath, - Prompt, CheckAccess, ResetForm, Wait, Stream, permissionsChoices, permissionsLabel, permissionsSearchSelect) { + Prompt, CheckAccess, ResetForm, Wait, Stream, fieldChoices, fieldLabels, permissionsSearchSelect) { ClearScope(); @@ -224,16 +224,17 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP $scope.permission_search_select = []; // return a promise from the options request with the permission type choices (including adhoc) as a param - var permissionsChoice = permissionsChoices({ + var permissionsChoice = fieldChoices({ scope: $scope, - url: 'api/v1/' + base + '/' + id + '/permissions/' + url: 'api/v1/' + base + '/' + id + '/permissions/', + field: 'permission_type' }); // manipulate the choices from the options request to be set on // scope and be usable by the list form permissionsChoice.then(function (choices) { choices = - permissionsLabel({ + fieldLabels({ choices: choices }); _.map(choices, function(n, key) { @@ -519,5 +520,5 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP UsersEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'UserForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', - 'GetBasePath', 'Prompt', 'CheckAccess', 'ResetForm', 'Wait', 'Stream', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect' + 'GetBasePath', 'Prompt', 'CheckAccess', 'ResetForm', 'Wait', 'Stream', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect' ]; diff --git a/awx/ui/client/src/permissions/add/add.controller.js b/awx/ui/client/src/permissions/add/add.controller.js index 0dad88f9db..f90e9120a7 100644 --- a/awx/ui/client/src/permissions/add/add.controller.js +++ b/awx/ui/client/src/permissions/add/add.controller.js @@ -10,8 +10,8 @@ * @description This controller for permissions add */ export default - ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'permissionsChoices', 'permissionsLabel', - function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, permissionsChoices, permissionsLabel) { + ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'fieldChoices', 'fieldLabels', + function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, fieldChoices, fieldLabels) { ClearScope(); @@ -22,13 +22,14 @@ export default base = $location.path().replace(/^\//, '').split('/')[0], master = {}; - var permissionsChoice = permissionsChoices({ + var permissionsChoice = fieldChoices({ scope: $scope, - url: 'api/v1/' + base + '/' + id + '/permissions/' + url: 'api/v1/' + base + '/' + id + '/permissions/', + field: 'permission_type' }); permissionsChoice.then(function (choices) { - return permissionsLabel({ + return fieldLabels({ choices: choices }); }).then(function (choices) { diff --git a/awx/ui/client/src/permissions/edit/edit.controller.js b/awx/ui/client/src/permissions/edit/edit.controller.js index 1b1c6a552b..e209a309e2 100644 --- a/awx/ui/client/src/permissions/edit/edit.controller.js +++ b/awx/ui/client/src/permissions/edit/edit.controller.js @@ -10,8 +10,8 @@ * @description This controller for permissions edit */ export default - ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'permissionsChoices', 'permissionsLabel', - function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, permissionsChoices, permissionsLabel) { + ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'fieldChoices', 'fieldLabels', + function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, fieldChoices, fieldLabels) { ClearScope(); @@ -25,13 +25,14 @@ export default $scope.permission_label = {}; - var permissionsChoice = permissionsChoices({ + var permissionsChoice = fieldChoices({ scope: $scope, - url: 'api/v1/' + base + '/' + base_id + '/permissions/' + url: 'api/v1/' + base + '/' + base_id + '/permissions/', + field: 'permission_type' }); permissionsChoice.then(function (choices) { - return permissionsLabel({ + return fieldLabels({ choices: choices }); }).then(function (choices) { diff --git a/awx/ui/client/src/permissions/list/list.controller.js b/awx/ui/client/src/permissions/list/list.controller.js index 4e9ea4c716..341150b71b 100644 --- a/awx/ui/client/src/permissions/list/list.controller.js +++ b/awx/ui/client/src/permissions/list/list.controller.js @@ -12,8 +12,8 @@ export default - ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'permissionsList', 'generateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess', 'Wait', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect', - function ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, permissionsList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, CheckAccess, Wait, permissionsChoices, permissionsLabel, permissionsSearchSelect) { + ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'permissionsList', 'generateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess', 'Wait', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect', + function ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, permissionsList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, CheckAccess, Wait, fieldChoices, fieldLabels, permissionsSearchSelect) { ClearScope(); @@ -27,16 +27,17 @@ export default $scope.permission_search_select = []; // return a promise from the options request with the permission type choices (including adhoc) as a param - var permissionsChoice = permissionsChoices({ + var permissionsChoice = fieldChoices({ scope: $scope, - url: 'api/v1/' + base + '/' + base_id + '/permissions/' + url: 'api/v1/' + base + '/' + base_id + '/permissions/', + field: 'permission_type' }); // manipulate the choices from the options request to be set on // scope and be usable by the list form permissionsChoice.then(function (choices) { choices = - permissionsLabel({ + fieldLabels({ choices: choices }); _.map(choices, function(n, key) { diff --git a/awx/ui/client/src/permissions/main.js b/awx/ui/client/src/permissions/main.js index fef273cfa6..0bb913370d 100644 --- a/awx/ui/client/src/permissions/main.js +++ b/awx/ui/client/src/permissions/main.js @@ -12,8 +12,6 @@ import list from './shared/permissions.list'; import form from './shared/permissions.form'; import permissionsCategoryChange from './shared/category-change.factory'; -import permissionsChoices from './shared/get-choices.factory'; -import permissionsLabel from './shared/get-labels.factory'; import permissionsSearchSelect from './shared/get-search-select.factory'; export default @@ -25,6 +23,4 @@ export default .factory('permissionsList', list) .factory('permissionsForm', form) .factory('permissionsCategoryChange', permissionsCategoryChange) - .factory('permissionsChoices', permissionsChoices) - .factory('permissionsLabel', permissionsLabel) .factory('permissionsSearchSelect', permissionsSearchSelect); diff --git a/awx/ui/client/src/permissions/shared/get-choices.factory.js b/awx/ui/client/src/rest/get-choices.factory.js similarity index 66% rename from awx/ui/client/src/permissions/shared/get-choices.factory.js rename to awx/ui/client/src/rest/get-choices.factory.js index 8ad55907a5..33537d5ab4 100644 --- a/awx/ui/client/src/permissions/shared/get-choices.factory.js +++ b/awx/ui/client/src/rest/get-choices.factory.js @@ -16,24 +16,28 @@ ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { return function (params) { var scope = params.scope, - url = params.url; + url = params.url, + field = params.field; // Auto populate the field if there is only one result Rest.setUrl(url); return Rest.options() .then(function (data) { data = data.data; - var choices = data.actions.GET.permission_type.choices; + var choices = data.actions.GET[field].choices; - // manually add the adhoc label to the choices object - choices.push(["adhoc", - data.actions.GET.run_ad_hoc_commands.help_text]); + // manually add the adhoc label to the choices object if + // the permission_type field + if (field === "permission_type") { + choices.push(["adhoc", + data.actions.GET.run_ad_hoc_commands.help_text]); + } return choices; }) .catch(function (data, status) { ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get permission type labels. Options requrest returned status: ' + status }); + msg: 'Failed to get ' + field + ' labels. Options requrest returned status: ' + status }); }); }; }]; diff --git a/awx/ui/client/src/permissions/shared/get-labels.factory.js b/awx/ui/client/src/rest/get-labels.factory.js similarity index 100% rename from awx/ui/client/src/permissions/shared/get-labels.factory.js rename to awx/ui/client/src/rest/get-labels.factory.js diff --git a/awx/ui/client/src/rest/main.js b/awx/ui/client/src/rest/main.js index 335106af5d..5466355a12 100644 --- a/awx/ui/client/src/rest/main.js +++ b/awx/ui/client/src/rest/main.js @@ -6,6 +6,8 @@ import restServicesFactory from './restServices.factory'; import interceptors from './interceptors.service'; +import fieldChoices from './get-choices.factory'; +import fieldLabels from './get-labels.factory'; export default angular.module('RestServices', []) @@ -13,4 +15,6 @@ export default $httpProvider.interceptors.push('RestInterceptor'); }]) .factory('Rest', restServicesFactory) - .service('RestInterceptor', interceptors); + .service('RestInterceptor', interceptors) + .factory('fieldChoices', fieldChoices) + .factory('fieldLabels', fieldLabels); From 891c9c0889dd960c3b256fe19bb651ac36dca7c3 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 21 Oct 2015 20:35:28 -0700 Subject: [PATCH 03/65] Updated the job details failure explanation Uses a help popover set up in the partial Also pulls labels for the job types from the unified_jobs option request using the helper services --- awx/ui/client/src/controllers/JobDetail.js | 30 +++++++++++++++++++--- awx/ui/client/src/partials/job_detail.html | 17 +++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/awx/ui/client/src/controllers/JobDetail.js b/awx/ui/client/src/controllers/JobDetail.js index cd31c73707..b50b2015b1 100644 --- a/awx/ui/client/src/controllers/JobDetail.js +++ b/awx/ui/client/src/controllers/JobDetail.js @@ -13,7 +13,7 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $compile, $routeParams, $log, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest, ProcessErrors, SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, LoadHostSummary, ReloadHostSummaryList, JobIsFinished, SetTaskStyles, DigestEvent, - UpdateDOM, EventViewer, DeleteJob, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices) { + UpdateDOM, EventViewer, DeleteJob, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices, fieldChoices, fieldLabels) { ClearScope(); @@ -27,11 +27,33 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co scope.plays = []; + scope.previousTaskFailed = false; + scope.$watch('job_status', function(job_status) { if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") { + scope.previousTaskFailed = true; var taskObj = JSON.parse(job_status.explanation.substring(job_status.explanation.split(":")[0].length + 1)); - job_status.explanation = job_status.explanation.split(":")[0] + ". "; - job_status.explanation += "" + taskObj.task_type + "-" + taskObj.task_id + " failed for " + taskObj.task_name + "" + // return a promise from the options request with the permission type choices (including adhoc) as a param + var fieldChoice = fieldChoices({ + scope: $scope, + url: 'api/v1/unified_jobs/', + field: 'type' + }); + + // manipulate the choices from the options request to be set on + // scope and be usable by the list form + fieldChoice.then(function (choices) { + choices = + fieldLabels({ + choices: choices + }); + scope.explanation_fail_type = choices[taskObj.job_type]; + scope.explanation_fail_name = taskObj.job_name; + scope.explanation_fail_id = taskObj.job_id; + scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with id " + scope.explanation_fail_id + "."; + }); + } else { + scope.previousTaskFailed = false; } }, true); @@ -1415,5 +1437,5 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co JobDetailController.$inject = [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$routeParams', '$log', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'EventViewer', 'DeleteJob', 'PlaybookRun', 'HostEventsViewer', 'LoadPlays', 'LoadTasks', - 'LoadHosts', 'HostsEdit', 'ParseVariableString', 'GetChoices' + 'LoadHosts', 'HostsEdit', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels' ]; diff --git a/awx/ui/client/src/partials/job_detail.html b/awx/ui/client/src/partials/job_detail.html index 25164ff4bc..fb17ecd7b0 100644 --- a/awx/ui/client/src/partials/job_detail.html +++ b/awx/ui/client/src/partials/job_detail.html @@ -34,7 +34,22 @@
-
+
+
Previous Task Failed + + + + +
From 4603ac5d1c1d948d8b805fae3f9c18c689b145c0 Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Thu, 22 Oct 2015 10:49:42 -0400 Subject: [PATCH 04/65] Change dependent job failure message entity ref. Originally we were looking at the underlying project/inventory update but we are now populating the name of project updates and inventory updates a lot better so we'll just take their names --- awx/main/tasks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index b18df63b92..0df4c195ad 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -170,10 +170,10 @@ def handle_work_error(self, task_id, subtasks=None): instance_name = '' if each_task['type'] == 'project_update': instance = ProjectUpdate.objects.get(id=each_task['id']) - instance_name = instance.project.name + instance_name = instance.name elif each_task['type'] == 'inventory_update': instance = InventoryUpdate.objects.get(id=each_task['id']) - instance_name = instance.inventory_source.inventory.name + instance_name = instance.name elif each_task['type'] == 'job': instance = Job.objects.get(id=each_task['id']) instance_name = instance.job_template.name From 98e66d87629a0379e6c50dca26ca45a351762a53 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Fri, 23 Oct 2015 08:45:50 -0700 Subject: [PATCH 05/65] fixed conditional of management jobs not showing up for non-superuser --- awx/ui/client/src/setup-menu/setup-menu.partial.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/ui/client/src/setup-menu/setup-menu.partial.html b/awx/ui/client/src/setup-menu/setup-menu.partial.html index a07d50a3e8..630ce5f570 100644 --- a/awx/ui/client/src/setup-menu/setup-menu.partial.html +++ b/awx/ui/client/src/setup-menu/setup-menu.partial.html @@ -53,8 +53,8 @@

- - + +
From 58f0f9f6e9afdbd26a9a4b37ec66aca558cee77b Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Fri, 23 Oct 2015 09:06:49 -0700 Subject: [PATCH 06/65] fixed alert unnecessary escaping --- awx/ui/client/src/controllers/Projects.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index 281d6bb0ad..83920528c8 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -13,7 +13,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, ProjectList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, - Refresh, Wait, Stream, GetChoices, Empty, Find, LogViewer, GetProjectIcon, GetProjectToolTip) { + Refresh, Wait, Stream, GetChoices, Empty, Find, LogViewer, GetProjectIcon, GetProjectToolTip, $filter) { ClearScope(); @@ -329,8 +329,8 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, msg: 'Call to ' + project.related.current_update + ' failed. GET status: ' + status }); }); } else { - Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + name + '. Click the Refresh ' + - 'button to view the latet status.', 'alert-info'); + Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the Refresh ' + + 'button to view the latet status.', 'alert-info',undefined,undefined,undefined,undefined,true); } }; @@ -384,7 +384,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, ProjectsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'ProjectList', 'generateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'Refresh', 'Wait', 'Stream', 'GetChoices', 'Empty', 'Find', - 'LogViewer', 'GetProjectIcon', 'GetProjectToolTip' + 'LogViewer', 'GetProjectIcon', 'GetProjectToolTip', '$filter' ]; From f8e4fdf2011d84d09dd10b329073d5e0869a269d Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Fri, 23 Oct 2015 12:23:37 -0700 Subject: [PATCH 07/65] change async loading order for form --- awx/ui/client/src/controllers/Teams.js | 113 +++++++++++++------------ awx/ui/client/src/controllers/Users.js | 101 ++++++++++++---------- 2 files changed, 114 insertions(+), 100 deletions(-) diff --git a/awx/ui/client/src/controllers/Teams.js b/awx/ui/client/src/controllers/Teams.js index 6fe42bc955..1cc8408bd1 100644 --- a/awx/ui/client/src/controllers/Teams.js +++ b/awx/ui/client/src/controllers/Teams.js @@ -210,8 +210,6 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP }); }); - $scope.team_id = id; - // manipulate the choices from the options request to be usable // by the search option for permission_type, you can't inject the // list until this is done! @@ -222,8 +220,11 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP }); generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); + $scope.$emit('loadTeam'); }); + $scope.team_id = id; + $scope.PermissionAddAllowed = false; // Retrieve each related set and any lookups @@ -254,59 +255,65 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP } }); - // Retrieve detail record and prepopulate the form - Wait('start'); - Rest.setUrl(defaultUrl + ':id/'); - Rest.get({ - params: { - id: id - } - }) - .success(function (data) { - var fld, related, set; - $scope.team_name = data.name; - for (fld in form.fields) { - if (data[fld]) { - $scope[fld] = data[fld]; - master[fld] = $scope[fld]; - } + // Retrieve each related set and any lookups + if ($scope.loadTeamRemove) { + $scope.loadTeamRemove(); + } + $scope.loadTeamRemove = $scope.$on('loadTeam', function () { + // Retrieve detail record and prepopulate the form + Wait('start'); + Rest.setUrl(defaultUrl + ':id/'); + Rest.get({ + params: { + id: id } - related = data.related; - for (set in form.related) { - if (related[set]) { - relatedSets[set] = { - url: related[set], - iterator: form.related[set].iterator - }; - } - } - // Initialize related search functions. Doing it here to make sure relatedSets object is populated. - RelatedSearchInit({ - scope: $scope, - form: form, - relatedSets: relatedSets - }); - RelatedPaginateInit({ - scope: $scope, - relatedSets: relatedSets - }); - - LookUpInit({ - scope: $scope, - form: form, - current_item: data.organization, - list: OrganizationList, - field: 'organization', - input_type: 'radio' - }); - - $scope.organization_url = data.related.organization; - $scope.$emit('teamLoaded'); }) - .error(function (data, status) { - ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id + - '. GET status: ' + status }); - }); + .success(function (data) { + var fld, related, set; + $scope.team_name = data.name; + for (fld in form.fields) { + if (data[fld]) { + $scope[fld] = data[fld]; + master[fld] = $scope[fld]; + } + } + related = data.related; + for (set in form.related) { + if (related[set]) { + relatedSets[set] = { + url: related[set], + iterator: form.related[set].iterator + }; + } + } + // Initialize related search functions. Doing it here to make sure relatedSets object is populated. + RelatedSearchInit({ + scope: $scope, + form: form, + relatedSets: relatedSets + }); + RelatedPaginateInit({ + scope: $scope, + relatedSets: relatedSets + }); + + LookUpInit({ + scope: $scope, + form: form, + current_item: data.organization, + list: OrganizationList, + field: 'organization', + input_type: 'radio' + }); + + $scope.organization_url = data.related.organization; + $scope.$emit('teamLoaded'); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id + + '. GET status: ' + status }); + }); + }); $scope.getPermissionText = function () { if (this.permission.permission_type !== "admin" && this.permission.run_ad_hoc_commands) { diff --git a/awx/ui/client/src/controllers/Users.js b/awx/ui/client/src/controllers/Users.js index 3aa0b98662..9cd0d2d161 100644 --- a/awx/ui/client/src/controllers/Users.js +++ b/awx/ui/client/src/controllers/Users.js @@ -242,22 +242,23 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP }); }); + // manipulate the choices from the options request to be usable + // by the search option for permission_type, you can't inject the + // list until this is done! + permissionsChoice.then(function (choices) { + form.related.permissions.fields.permission_type.searchOptions = + permissionsSearchSelect({ + choices: choices + }); + generator.inject(form, { mode: 'edit', related: true, scope: $scope }); + generator.reset(); + $scope.$emit("loadForm"); + }); + if ($scope.removeFormReady) { $scope.removeFormReady(); } $scope.removeFormReady = $scope.$on('formReady', function () { - // manipulate the choices from the options request to be usable - // by the search option for permission_type, you can't inject the - // list until this is done! - permissionsChoice.then(function (choices) { - form.related.permissions.fields.permission_type.searchOptions = - permissionsSearchSelect({ - choices: choices - }); - generator.inject(form, { mode: 'edit', related: true, scope: $scope }); - generator.reset(); - }); - if ($scope.removePostRefresh) { $scope.removePostRefresh(); } @@ -471,51 +472,57 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP // Put form back to its original state ResetForm(); - - if ($scope.removeModifyForm) { - $scope.removeModifyForm(); + if ($scope.removeLoadForm) { + $scope.removeLoadForm(); } - $scope.removeModifyForm = $scope.$on('modifyForm', function () { - // Modify form based on LDAP settings - Rest.setUrl(GetBasePath('config')); - Rest.get() - .success(function (data) { - var i, fld; - if (data.user_ldap_fields) { - for (i = 0; i < data.user_ldap_fields.length; i++) { - fld = data.user_ldap_fields[i]; - if (form.fields[fld]) { - form.fields[fld].readonly = true; - form.fields[fld].editRequired = false; - if (form.fields[fld].awRequiredWhen) { - delete form.fields[fld].awRequiredWhen; + $scope.removeLoadForm = $scope.$on('loadForm', function () { + + + if ($scope.removeModifyForm) { + $scope.removeModifyForm(); + } + $scope.removeModifyForm = $scope.$on('modifyForm', function () { + // Modify form based on LDAP settings + Rest.setUrl(GetBasePath('config')); + Rest.get() + .success(function (data) { + var i, fld; + if (data.user_ldap_fields) { + for (i = 0; i < data.user_ldap_fields.length; i++) { + fld = data.user_ldap_fields[i]; + if (form.fields[fld]) { + form.fields[fld].readonly = true; + form.fields[fld].editRequired = false; + if (form.fields[fld].awRequiredWhen) { + delete form.fields[fld].awRequiredWhen; + } } } } + $scope.$emit('formReady'); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve application config. GET status: ' + status }); + }); + }); + + Wait('start'); + Rest.setUrl(defaultUrl + id + '/'); + Rest.get() + .success(function (data) { + if (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') { + //this is an LDAP user + $scope.$emit('modifyForm'); + } else { + $scope.$emit('formReady'); } - $scope.$emit('formReady'); }) .error(function (data, status) { ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve application config. GET status: ' + status }); + msg: 'Failed to retrieve user: ' + id + '. GET status: ' + status }); }); }); - - Wait('start'); - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success(function (data) { - if (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') { - //this is an LDAP user - $scope.$emit('modifyForm'); - } else { - $scope.$emit('formReady'); - } - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve user: ' + id + '. GET status: ' + status }); - }); } UsersEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'UserForm', 'GenerateForm', From f73e56439aedf7500a0a9aab7888653662395e61 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Fri, 23 Oct 2015 17:08:44 -0700 Subject: [PATCH 08/65] On logout, log the user out of the UI on all open tabs I've also reworked the logic around storing the user session idle time in localStorage --- .../authentication.service.js | 8 ++++-- .../authenticationServices/timer.factory.js | 26 ++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/awx/ui/client/src/login/authenticationServices/authentication.service.js b/awx/ui/client/src/login/authenticationServices/authentication.service.js index 37426620a3..5ab9aced88 100644 --- a/awx/ui/client/src/login/authenticationServices/authentication.service.js +++ b/awx/ui/client/src/login/authenticationServices/authentication.service.js @@ -60,7 +60,8 @@ export default logout: function () { // the following puts our primary scope up for garbage collection, which // should prevent content flash from the prior user. - var scope = angular.element(document.getElementById('main-view')).scope(); + + var x, scope = angular.element(document.getElementById('main-view')).scope(); scope.$destroy(); //$rootScope.$destroy(); @@ -78,7 +79,10 @@ export default $cookieStore.remove('lastPath'); $rootScope.lastPath = '/home'; } - + x = Store('sessionTime'); + x[$rootScope.current_user.id].loggedIn = false; + Store('sessionTime', x); + $rootScope.lastUser = $cookieStore.get('current_user').id; $cookieStore.remove('token_expires'); $cookieStore.remove('current_user'); diff --git a/awx/ui/client/src/login/authenticationServices/timer.factory.js b/awx/ui/client/src/login/authenticationServices/timer.factory.js index 13ead3af02..d315ee50aa 100644 --- a/awx/ui/client/src/login/authenticationServices/timer.factory.js +++ b/awx/ui/client/src/login/authenticationServices/timer.factory.js @@ -32,13 +32,12 @@ export default timeout: null, getSessionTime: function () { - if(Store('sessionTime_'+$rootScope.current_user.id)){ - return Store('sessionTime_'+$rootScope.current_user.id); + if(Store('sessionTime')){ + return Store('sessionTime')[$rootScope.current_user.id].time; } else { - return 0; + return 0; } - }, isExpired: function (increase) { @@ -72,6 +71,7 @@ export default }, expireSession: function (reason) { + var x; if(reason === 'session_limit'){ $rootScope.sessionLimitExpired = true; $rootScope.sessionExpired = false; @@ -87,10 +87,21 @@ export default }, moveForward: function () { - var tm, t; + var tm, t, x, y; tm = ($AnsibleConfig.session_timeout) ? $AnsibleConfig.session_timeout : 1800; t = new Date().getTime() + (tm * 1000); - Store('sessionTime_'+$rootScope.current_user.id, t); + x = new Object({ + time: t, + loggedIn: true + }); + if(Store('sessionTime')){ + y = Store('sessionTime'); + } + else { + y = new Object(); + } + y[$rootScope.current_user.id] = x; + Store('sessionTime' , y); $rootScope.sessionExpired = false; $cookieStore.put('sessionExpired', false); this.startTimers(); @@ -149,6 +160,9 @@ export default } that.expireSession('idle'); } + if(Store('sessionTime')[$rootScope.current_user.id].loggedIn === false){ + that.expireSession(); + } }, 1000); From 8e4adfb88737686821d46bb6eaa8a4a09cfc6d03 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Sun, 25 Oct 2015 00:15:24 -0400 Subject: [PATCH 09/65] fixed typo in cancel message --- awx/ui/client/src/controllers/Projects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index 83920528c8..e0a5ce9956 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -330,7 +330,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, }); } else { Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the Refresh ' + - 'button to view the latet status.', 'alert-info',undefined,undefined,undefined,undefined,true); + 'button to view the latest status.', 'alert-info',undefined,undefined,undefined,undefined,true); } }; From e18791a65764a8d8093e4f4464968ff850656a48 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Sun, 25 Oct 2015 14:43:22 -0700 Subject: [PATCH 10/65] Integer Directive was returning false for a blank string this was causing the integer directive to throw an error if the user entered something in the field, then erased it. --- awx/ui/client/src/shared/directives.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index 2b005b06d0..c97f40b5ca 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -275,7 +275,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) if (/^\-?\d*$/.test(viewValue)) { // it is valid ctrl.$setValidity('integer', true); - if ( viewValue === '-' || viewValue === '-0' || viewValue === '' || viewValue === null) { + if ( viewValue === '-' || viewValue === '-0' || viewValue === null) { ctrl.$setValidity('integer', false); return viewValue; } From b83dfda92cdb85b4c05e941a0c65c2f09c70fb4d Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Sun, 25 Oct 2015 17:29:29 -0700 Subject: [PATCH 11/65] fixing a null pointer exception if services are down and user attempts to login --- awx/ui/client/src/login/loginModal/loginModal.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/login/loginModal/loginModal.controller.js b/awx/ui/client/src/login/loginModal/loginModal.controller.js index ce451834b4..48cf162f88 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.controller.js +++ b/awx/ui/client/src/login/loginModal/loginModal.controller.js @@ -193,7 +193,7 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l function (data) { var key; Wait('stop'); - if (data.data.non_field_errors && data.data.non_field_errors.length === 0) { + if (data && data.data && data.data.non_field_errors && data.data.non_field_errors.length === 0) { // show field specific errors returned by the API for (key in data.data) { scope[key + 'Error'] = data.data[key][0]; From 80eeda1c8c52b4c5ad07666260657007f62f2fc3 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Sun, 25 Oct 2015 18:32:54 -0700 Subject: [PATCH 12/65] removing stale code to make atom happy :) --- .../src/login/authenticationServices/timer.factory.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/login/authenticationServices/timer.factory.js b/awx/ui/client/src/login/authenticationServices/timer.factory.js index d315ee50aa..7e39c93502 100644 --- a/awx/ui/client/src/login/authenticationServices/timer.factory.js +++ b/awx/ui/client/src/login/authenticationServices/timer.factory.js @@ -71,7 +71,6 @@ export default }, expireSession: function (reason) { - var x; if(reason === 'session_limit'){ $rootScope.sessionLimitExpired = true; $rootScope.sessionExpired = false; @@ -90,15 +89,15 @@ export default var tm, t, x, y; tm = ($AnsibleConfig.session_timeout) ? $AnsibleConfig.session_timeout : 1800; t = new Date().getTime() + (tm * 1000); - x = new Object({ + x = { time: t, loggedIn: true - }); + }; if(Store('sessionTime')){ y = Store('sessionTime'); } else { - y = new Object(); + y = {}; } y[$rootScope.current_user.id] = x; Store('sessionTime' , y); From eddb2e01b000846fb8e5cff9298d34e2632f84c9 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Mon, 26 Oct 2015 17:40:39 -0400 Subject: [PATCH 13/65] fixed prepopulation of custom script lookups --- awx/ui/client/src/forms/Source.js | 4 ++-- awx/ui/client/src/helpers/Groups.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/forms/Source.js b/awx/ui/client/src/forms/Source.js index 9feb8e7f28..19780c3df0 100644 --- a/awx/ui/client/src/forms/Source.js +++ b/awx/ui/client/src/forms/Source.js @@ -118,8 +118,8 @@ export default sourceModel: 'inventory_script', sourceField: 'name', ngClick: 'lookUpInventory_script()' , - addRequired: false, - editRequired: false, + addRequired: true, + editRequired: true, ngRequired: "source && source.value === 'custom'", }, extra_vars: { diff --git a/awx/ui/client/src/helpers/Groups.js b/awx/ui/client/src/helpers/Groups.js index 63fe00cff1..0e0eef4636 100644 --- a/awx/ui/client/src/helpers/Groups.js +++ b/awx/ui/client/src/helpers/Groups.js @@ -751,9 +751,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name $compile(elem)(modal_scope); var form_scope = - generator.inject(GroupForm, { mode: 'edit', id: 'properties-tab', breadCrumbs: false, related: false, scope: properties_scope }); + generator.inject(GroupForm, { mode: mode, id: 'properties-tab', breadCrumbs: false, related: false, scope: properties_scope }); var source_form_scope = - generator.inject(SourceForm, { mode: 'edit', id: 'sources-tab', breadCrumbs: false, related: false, scope: sources_scope }); + generator.inject(SourceForm, { mode: mode, id: 'sources-tab', breadCrumbs: false, related: false, scope: sources_scope }); //generator.reset(); From f6f5bdd39674caa425be49be9ec897ab398fa01f Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 27 Oct 2015 13:47:13 -0400 Subject: [PATCH 14/65] fixed styling issues for job detail explanation --- awx/ui/client/src/controllers/JobDetail.js | 2 +- awx/ui/client/src/partials/job_detail.html | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/awx/ui/client/src/controllers/JobDetail.js b/awx/ui/client/src/controllers/JobDetail.js index b50b2015b1..6491b0aa43 100644 --- a/awx/ui/client/src/controllers/JobDetail.js +++ b/awx/ui/client/src/controllers/JobDetail.js @@ -50,7 +50,7 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co scope.explanation_fail_type = choices[taskObj.job_type]; scope.explanation_fail_name = taskObj.job_name; scope.explanation_fail_id = taskObj.job_id; - scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with id " + scope.explanation_fail_id + "."; + scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with ID " + scope.explanation_fail_id + "."; }); } else { scope.previousTaskFailed = false; diff --git a/awx/ui/client/src/partials/job_detail.html b/awx/ui/client/src/partials/job_detail.html index fb17ecd7b0..fd45b93891 100644 --- a/awx/ui/client/src/partials/job_detail.html +++ b/awx/ui/client/src/partials/job_detail.html @@ -33,16 +33,17 @@
- -
Explanation +
-
Previous Task Failed From 0f68ead0b37aa3e994176b4c03eaf15ee4fdff24 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 27 Oct 2015 13:58:27 -0400 Subject: [PATCH 15/65] fixed fields not clearing out between source changes --- awx/ui/client/src/helpers/Groups.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/awx/ui/client/src/helpers/Groups.js b/awx/ui/client/src/helpers/Groups.js index 0e0eef4636..4d7fb0487c 100644 --- a/awx/ui/client/src/helpers/Groups.js +++ b/awx/ui/client/src/helpers/Groups.js @@ -1465,6 +1465,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name // Change the lookup and regions when the source changes sources_scope.sourceChange = function () { + sources_scope.credential_name = ""; + sources_scope.credential = ""; + if (sources_scope.credential_name_api_error) { + delete sources_scope.credential_name_api_error; + } parent_scope.showSchedulesTab = (mode === 'edit' && sources_scope.source && sources_scope.source.value!=="manual") ? true : false; SourceChange({ scope: sources_scope, form: SourceForm }); }; From 32962bcadc9a1d1ee67d3989802f8a9bea056531 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 27 Oct 2015 14:42:10 -0400 Subject: [PATCH 16/65] fixed project update canceling --- awx/ui/client/src/controllers/Projects.js | 54 +++++++++++++---------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index e0a5ce9956..4083dbe2d4 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -309,29 +309,37 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, }); $scope.cancelUpdate = function (id, name) { - // Start the cancel process - var i, project, found = false; - for (i = 0; i < $scope.projects.length; i++) { - if ($scope.projects[i].id === id) { - project = $scope.projects[i]; - found = true; - break; - } - } - if (found && project.related.current_update) { - Rest.setUrl(project.related.current_update); - Rest.get() - .success(function (data) { - $scope.$emit('Check_Cancel', data); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + project.related.current_update + ' failed. GET status: ' + status }); - }); - } else { - Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the Refresh ' + - 'button to view the latest status.', 'alert-info',undefined,undefined,undefined,undefined,true); - } + // // Start the cancel process + // var i, project, found = false; + // for (i = 0; i < $scope.projects.length; i++) { + // if ($scope.projects[i].id === id) { + // project = $scope.projects[i]; + // found = true; + // break; + // } + // } + Rest.setUrl(GetBasePath("projects") + id); + Rest.get() + .success(function (data) { + if (data.related.current_update) { + Rest.setUrl(data.related.current_update); + Rest.get() + .success(function (data) { + $scope.$emit('Check_Cancel', data); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + data.related.current_update + ' failed. GET status: ' + status }); + }); + } else { + Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the Refresh ' + + 'button to view the latest status.', 'alert-info',undefined,undefined,undefined,undefined,true); + } + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Call to get project failed. GET status: ' + status }); + }) }; $scope.refresh = function () { From 6c8597cf95e288a07905aca90b95ca90067eb195 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 27 Oct 2015 13:51:54 -0700 Subject: [PATCH 17/65] Wrapping timer init in promise to ensure that timer is started before initializing websockets. This was leading to instances where the websocket thought that the session hadn't been started yet. Also fixed an issue where the session wasn't tearing down the $interval when AUTH_TOKEN_PER_USER had been exceeded. --- awx/ui/client/src/app.js | 11 +++++++---- .../authentication.service.js | 5 ++--- .../login/authenticationServices/timer.factory.js | 14 ++++++++++---- .../src/login/loginModal/loginModal.controller.js | 9 ++++++--- awx/ui/client/src/rest/interceptors.service.js | 6 ++++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index b07df48373..9e56c7af35 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -947,7 +947,8 @@ var tower = angular.module('Tower', [ control_socket.init(); control_socket.on("limit_reached", function(data) { $log.debug(data.reason); - Timer.expireSession('session_limit'); + $rootScope.sessionTimer.expireSession('session_limit'); + $location.url('/login'); }); } openSocket(); @@ -1023,9 +1024,11 @@ var tower = angular.module('Tower', [ $rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser'); // when the user refreshes we want to open the socket, except if the user is on the login page, which should happen after the user logs in (see the AuthService module for that call to OpenSocket) if(!_.contains($location.$$url, '/login')){ - $rootScope.sessionTimer = Timer.init(); - $rootScope.$emit('OpenSocket'); - pendoService.issuePendoIdentity(); + Timer.init().then(function(timer){ + $rootScope.sessionTimer = timer; + $rootScope.$emit('OpenSocket'); + pendoService.issuePendoIdentity(); + }); } } diff --git a/awx/ui/client/src/login/authenticationServices/authentication.service.js b/awx/ui/client/src/login/authenticationServices/authentication.service.js index 5ab9aced88..511cb4ab83 100644 --- a/awx/ui/client/src/login/authenticationServices/authentication.service.js +++ b/awx/ui/client/src/login/authenticationServices/authentication.service.js @@ -82,7 +82,7 @@ export default x = Store('sessionTime'); x[$rootScope.current_user.id].loggedIn = false; Store('sessionTime', x); - + $rootScope.lastUser = $cookieStore.get('current_user').id; $cookieStore.remove('token_expires'); $cookieStore.remove('current_user'); @@ -98,7 +98,7 @@ export default $rootScope.token_expires = null; $rootScope.login_username = null; $rootScope.login_password = null; - $rootScope.sessionTimer.expireSession(); + $rootScope.sessionTimer.clearTimers(); }, getLicense: function () { @@ -153,7 +153,6 @@ export default // store the response values in $rootScope so we can get to them later $rootScope.current_user = response.results[0]; $cookieStore.put('current_user', response.results[0]); //keep in session cookie in the event of browser refresh - $rootScope.$emit('OpenSocket'); }, restoreUserInfo: function () { diff --git a/awx/ui/client/src/login/authenticationServices/timer.factory.js b/awx/ui/client/src/login/authenticationServices/timer.factory.js index 7e39c93502..04478309e3 100644 --- a/awx/ui/client/src/login/authenticationServices/timer.factory.js +++ b/awx/ui/client/src/login/authenticationServices/timer.factory.js @@ -23,9 +23,9 @@ */ export default ['$rootScope', '$cookieStore', 'transitionTo', 'CreateDialog', 'Authorization', - 'Store', '$interval', + 'Store', '$interval', '$location', '$q', function ($rootScope, $cookieStore, transitionTo, CreateDialog, Authorization, - Store, $interval) { + Store, $interval, $location, $q) { return { sessionTime: null, @@ -82,7 +82,6 @@ export default this.sessionTime = 0; this.clearTimers(); $cookieStore.put('sessionExpired', true); - transitionTo('signOut'); }, moveForward: function () { @@ -158,9 +157,12 @@ export default $('#idle-modal').dialog('close'); } that.expireSession('idle'); + $location.url('/login'); } if(Store('sessionTime')[$rootScope.current_user.id].loggedIn === false){ that.expireSession(); + $location.url('/login'); + } }, 1000); @@ -169,11 +171,15 @@ export default clearTimers: function(){ $interval.cancel($rootScope.expireTimer); + delete $rootScope.expireTimer; }, init: function () { + var deferred = $q.defer(); this.moveForward(); - return this; + deferred.resolve(this); + return deferred.promise; + } }; } diff --git a/awx/ui/client/src/login/loginModal/loginModal.controller.js b/awx/ui/client/src/login/loginModal/loginModal.controller.js index 48cf162f88..6b2bbb9f03 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.controller.js +++ b/awx/ui/client/src/login/loginModal/loginModal.controller.js @@ -165,9 +165,12 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l Authorization.getUser() .success(function (data) { Authorization.setUserInfo(data); - $rootScope.sessionTimer = Timer.init(); - $rootScope.user_is_superuser = data.results[0].is_superuser; - scope.$emit('AuthorizationGetLicense'); + Timer.init().then(function(timer){ + $rootScope.sessionTimer = timer; + $rootScope.$emit('OpenSocket'); + $rootScope.user_is_superuser = data.results[0].is_superuser; + scope.$emit('AuthorizationGetLicense'); + }); }) .error(function (data, status) { Authorization.logout(); diff --git a/awx/ui/client/src/rest/interceptors.service.js b/awx/ui/client/src/rest/interceptors.service.js index 5ef77a40f4..def62c1560 100644 --- a/awx/ui/client/src/rest/interceptors.service.js +++ b/awx/ui/client/src/rest/interceptors.service.js @@ -11,8 +11,8 @@ *************************************************/ export default - [ '$rootScope', '$q', - function ($rootScope, $q) { + [ '$rootScope', '$q', '$injector', + function ($rootScope, $q, $injector) { return { response: function(config) { if(config.headers('auth-token-timeout') !== null){ @@ -23,6 +23,8 @@ responseError: function(rejection){ if( rejection.data && !_.isEmpty(rejection.data.detail) && rejection.data.detail === "Maximum per-user sessions reached"){ $rootScope.sessionTimer.expireSession('session_limit'); + var location = $injector.get('$location'); + location.url('/login'); return $q.reject(rejection); } return $q.reject(rejection); From 12d31c50999f591061531a1a2ad34b180247f5df Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 27 Oct 2015 20:49:37 -0700 Subject: [PATCH 18/65] promise function was outdated for $http request of config.js using .catch instead of .error --- awx/ui/client/src/helpers/LoadConfig.js | 9 +++++---- .../thirdPartySignOn.service.js | 2 +- awx/ui/client/src/shared/Utilities.js | 17 +++++++++++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/awx/ui/client/src/helpers/LoadConfig.js b/awx/ui/client/src/helpers/LoadConfig.js index 8c4245697e..4b7cb26cc6 100644 --- a/awx/ui/client/src/helpers/LoadConfig.js +++ b/awx/ui/client/src/helpers/LoadConfig.js @@ -57,15 +57,16 @@ angular.module('LoadConfigHelper', ['Utilities']) // load config.js $log.info('attempting to load config.js'); $http({ method:'GET', url: $basePath + 'config.js' }) - .success(function(data) { + .then(function(data) { $log.info('loaded config.js'); $AnsibleConfig = eval(data); Store('AnsibleConfig', $AnsibleConfig); $rootScope.$emit('LoadConfig'); }) - .error(function(data, status) { - ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', - msg: 'Failed to load ' + $basePath + '/config.js. GET status: ' + status + .catch(function(response) { + response.data = 'Failed to load ' + $basePath + '/config.js'; + ProcessErrors($rootScope, response, response.status, null, { hdr: 'Error!', + msg: 'Failed to load ' + $basePath + '/config.js.' }); }); }; diff --git a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js index 4129b9b758..6b55f34881 100644 --- a/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js +++ b/awx/ui/client/src/login/loginModal/thirdPartySignOn/thirdPartySignOn.service.js @@ -25,7 +25,7 @@ var options = [], error = ""; - function parseGoogle(option, key) { + function parseGoogle(option) { var newOption = {}; newOption.type = "google"; diff --git a/awx/ui/client/src/shared/Utilities.js b/awx/ui/client/src/shared/Utilities.js index de9bbf67b2..cff6227215 100644 --- a/awx/ui/client/src/shared/Utilities.js +++ b/awx/ui/client/src/shared/Utilities.js @@ -252,15 +252,20 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter']) if ((!fieldErrors) && defaultMsg) { Alert(defaultMsg.hdr, defaultMsg.msg); } - } else if (typeof data === 'object' && Object.keys(data).length > 0) { - keys = Object.keys(data); - if (Array.isArray(data[keys[0]])) { - msg = data[keys[0]][0]; + } else if (typeof data === 'object'){ + if(Object.keys(data).length > 0) { + keys = Object.keys(data); + if (Array.isArray(data[keys[0]])) { + msg = data[keys[0]][0]; + } + else { + msg = data[keys[0]]; + } + Alert(defaultMsg.hdr, msg); } else { - msg = data[keys[0]]; + Alert(defaultMsg.hdr, defaultMsg.msg); } - Alert(defaultMsg.hdr, msg); } else { Alert(defaultMsg.hdr, defaultMsg.msg); } From 65d44287df9bef017a4ace3c48656cce8223923a Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 27 Oct 2015 21:09:12 -0700 Subject: [PATCH 19/65] fix console error with rest interceptor null pointer exception fixed --- awx/ui/client/src/rest/interceptors.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/rest/interceptors.service.js b/awx/ui/client/src/rest/interceptors.service.js index 5ef77a40f4..81bf24a658 100644 --- a/awx/ui/client/src/rest/interceptors.service.js +++ b/awx/ui/client/src/rest/interceptors.service.js @@ -21,7 +21,7 @@ return config; }, responseError: function(rejection){ - if( rejection.data && !_.isEmpty(rejection.data.detail) && rejection.data.detail === "Maximum per-user sessions reached"){ + if(rejection && rejection.data && rejection.data.detail && rejection.data.detail === "Maximum per-user sessions reached"){ $rootScope.sessionTimer.expireSession('session_limit'); return $q.reject(rejection); } From d2cefe6018c057dc9a7247f7bd0271f2945f6751 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Wed, 28 Oct 2015 08:47:09 -0700 Subject: [PATCH 20/65] adding null pointer check for timer factory when a user logs out from another tab --- .../src/login/authenticationServices/timer.factory.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/awx/ui/client/src/login/authenticationServices/timer.factory.js b/awx/ui/client/src/login/authenticationServices/timer.factory.js index 04478309e3..7bbc3356c4 100644 --- a/awx/ui/client/src/login/authenticationServices/timer.factory.js +++ b/awx/ui/client/src/login/authenticationServices/timer.factory.js @@ -159,9 +159,11 @@ export default that.expireSession('idle'); $location.url('/login'); } - if(Store('sessionTime')[$rootScope.current_user.id].loggedIn === false){ - that.expireSession(); - $location.url('/login'); + if(Store('sessionTime') && + Store('sessionTime')[$rootScope.current_user.id] && + Store('sessionTime')[$rootScope.current_user.id].loggedIn === false){ + that.expireSession(); + $location.url('/login'); } From 3892b3db1ce4854d39c4ac8e886105764a8abe04 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Wed, 28 Oct 2015 10:08:46 -0700 Subject: [PATCH 21/65] Forgot to update object reference for upgraded $http service from angular 1.4 --- awx/ui/client/src/helpers/LoadConfig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/ui/client/src/helpers/LoadConfig.js b/awx/ui/client/src/helpers/LoadConfig.js index 4b7cb26cc6..0a55b55fd7 100644 --- a/awx/ui/client/src/helpers/LoadConfig.js +++ b/awx/ui/client/src/helpers/LoadConfig.js @@ -57,9 +57,9 @@ angular.module('LoadConfigHelper', ['Utilities']) // load config.js $log.info('attempting to load config.js'); $http({ method:'GET', url: $basePath + 'config.js' }) - .then(function(data) { + .then(function(response) { $log.info('loaded config.js'); - $AnsibleConfig = eval(data); + $AnsibleConfig = eval(response.data); Store('AnsibleConfig', $AnsibleConfig); $rootScope.$emit('LoadConfig'); }) From 5b20e8767a8e6bafb3a64b2a61631ff4b75ee1e7 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 28 Oct 2015 17:37:12 -0400 Subject: [PATCH 22/65] fix logo on about modal --- awx/ui/client/assets/cowsay-about.html | 7 ++++--- awx/ui/client/src/about/about.block.less | 14 ++++++++++++++ awx/ui/client/src/helpers/AboutAnsible.js | 2 +- awx/ui/client/src/partials/about.html | 14 -------------- awx/ui/templates/ui/index.html | 2 +- 5 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 awx/ui/client/src/about/about.block.less delete mode 100644 awx/ui/client/src/partials/about.html diff --git a/awx/ui/client/assets/cowsay-about.html b/awx/ui/client/assets/cowsay-about.html index ad38bb572d..b1cbcf9d24 100644 --- a/awx/ui/client/assets/cowsay-about.html +++ b/awx/ui/client/assets/cowsay-about.html @@ -1,7 +1,7 @@
-
+
diff --git a/awx/ui/client/src/about/about.block.less b/awx/ui/client/src/about/about.block.less new file mode 100644 index 0000000000..4e46b24b50 --- /dev/null +++ b/awx/ui/client/src/about/about.block.less @@ -0,0 +1,14 @@ +/** @define About */ +.About { + height: 309px !important; +} + +.About-cowsay { + margin-top: 30px; +} + +.About-redhat { + max-width: 100%; + margin-top: -61px; + margin-bottom: -33px; +} diff --git a/awx/ui/client/src/helpers/AboutAnsible.js b/awx/ui/client/src/helpers/AboutAnsible.js index 68fda8fc92..69fef1236c 100644 --- a/awx/ui/client/src/helpers/AboutAnsible.js +++ b/awx/ui/client/src/helpers/AboutAnsible.js @@ -75,7 +75,7 @@ export default scope: scope, // buttons: [], width: 710, - height: 400, + height: 450, minWidth: 300, resizable: false, callback: 'DialogReady', diff --git a/awx/ui/client/src/partials/about.html b/awx/ui/client/src/partials/about.html deleted file mode 100644 index fb1b4d1793..0000000000 --- a/awx/ui/client/src/partials/about.html +++ /dev/null @@ -1,14 +0,0 @@ - - diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 82ec76318a..27af8d6a1f 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -159,7 +159,7 @@ - +