From ffdf03943e580b0adf0f58fb41e89517a82b2b80 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Mon, 5 May 2014 16:52:40 -0400 Subject: [PATCH] Implementing websocket connection on jobs page. Group delete fixes. --- awx/ui/static/js/controllers/Jobs.js | 108 ++++++++++++++++++++-- awx/ui/static/js/helpers/Groups.js | 8 +- awx/ui/static/js/helpers/JobSubmission.js | 7 +- awx/ui/static/js/helpers/Jobs.js | 3 +- awx/ui/static/js/helpers/Schedules.js | 2 +- awx/ui/static/less/jobs.less | 8 ++ awx/ui/static/lib/ansible/Utilities.js | 7 +- 7 files changed, 127 insertions(+), 16 deletions(-) diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 1ed5f4fd61..54db17b414 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -11,14 +11,105 @@ 'use strict'; function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBreadCrumbs, LoadSchedulesScope, LoadJobsScope, RunningJobsList, CompletedJobsList, QueuedJobsList, - ScheduledJobsList, GetChoices, GetBasePath, Wait) { + ScheduledJobsList, GetChoices, GetBasePath, Wait, Socket) { ClearScope(); var e, completed_scope, running_scope, queued_scope, scheduled_scope, choicesCount = 0, - listCount = 0; + listCount = 0, + api_complete = false, + event_socket, + event_queue = [{"status":"pending","endpoint":"/socket.io/jobs","unified_job_id":4129,"event":"status_changed"}], + expecting = 0; + + event_socket = Socket({ + scope: $scope, + endpoint: "jobs" + }); + + event_socket.init(); + + event_socket.on("status_changed", function(data) { + if (api_complete) { + processEvent(data); + } + else { + event_queue.push(data); + } + }); + + function processEvent(event) { + expecting = 0; + switch(event.status) { + case 'running': + if (!inList(running_scope[RunningJobsList.name], event.unified_job_id)) { + expecting = 2; + running_scope.search('running_job'); + queued_scope.search('queued_job'); + } + break; + case 'new': + case 'pending': + case 'waiting': + if (!inList(queued_scope[QueuedJobsList.name], event.unified_job_id)) { + expecting = 1; + queued_scope.search('queued_job'); + } + break; + case 'successful': + case 'failed': + case 'error': + case 'canceled': + if (!inList(completed_scope[CompletedJobsList.name], event.unified_job_id)) { + expecting = 2; + completed_scope.search('completed_job'); + running_scope.search('running_job'); + } + break; + } + } + + function inList(list, id) { + var found = false; + list.every( function(row) { + if (row.id === id) { + found = true; + return false; + } + return true; + }); + return found; + } + + + if ($scope.removeProcessQueue) { + $scope.removeProcessQueue(); + } + $scope.removeProcessQueue = $scope.$on('ProcessQueue', function() { + var event; + listCount=0; + if (event_queue.length > 0) { + //console.log('found queued events'); + event = event_queue[0]; + processEvent(event); + event_queue.splice(0,1); + if ($scope.removeListLoaded) { + $scope.removeListLoaded(); + } + $scope.removeListLoaded = $scope.$on('listLoaded', function() { + listCount++; + if (listCount === expecting) { + //console.log('checking for more events...'); + $scope.$emit('ProcessQueue'); + } + }); + } + //else { + //console.log('no more events'); + //} + }); LoadBreadCrumbs(); @@ -34,6 +125,8 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea listCount++; if (listCount === 4) { resizeContainers(); + api_complete = true; + $scope.$emit('ProcessQueue'); } }); @@ -58,7 +151,7 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea scope: completed_scope, list: CompletedJobsList, id: 'completed-jobs', - url: GetBasePath('unified_jobs') + '?or__status=successful&or__status=failed&or__status=error&or__status=canceled', + url: GetBasePath('unified_jobs') + '?or__status=successful&or__status=failed&or__status=error&or__status=canceled' }); running_scope = $scope.$new(true); LoadJobsScope({ @@ -85,12 +178,12 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea url: GetBasePath('schedules') + '?next_run__isnull=false' }); - $scope.refreshJobs = function() { + /*$scope.refreshJobs = function() { queued_scope.search('queued_job'); running_scope.search('running_job'); completed_scope.search('completed_job'); scheduled_scope.search('schedule'); - }; + };*/ $(window).resize(_.debounce(function() { resizeContainers(); @@ -125,6 +218,7 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea callback: 'choicesReady' }); + // Set container height and return the number of allowed rows function resizeContainers() { var docw = $(document).width(), available_height, @@ -160,8 +254,8 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea } } -JobsListController.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'LoadSchedulesScope', 'LoadJobsScope', 'RunningJobsList', 'CompletedJobsList', - 'QueuedJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait' ]; +JobsListController.$inject = [ '$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'LoadSchedulesScope', 'LoadJobsScope', 'RunningJobsList', 'CompletedJobsList', + 'QueuedJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', 'Socket' ]; function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index cd1ea2a6ea..d08e516a20 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -1414,11 +1414,13 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched scope.removeDeleteNextGroup(); } scope.removeDeleteNextGroup = scope.$on('DeleteNextGroup', function() { - var group; + var group, + url = GetBasePath('inventory') + scope.inventory_id + '/groups/'; if (groups && groups.length > 0) { group = groups.pop(); - Rest.setUrl(GetBasePath('groups') + group.group_id + '/'); - Rest.destroy() + // GetBasePath('groups') + group.id + '/' + Rest.setUrl(url); + Rest.post({ id: group.id, disassociate: 1 }) .success(function() { scope.$emit('DeleteNextGroup'); }) diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index c72a17975b..bcbafb3579 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -301,11 +301,12 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi } scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function() { var base = $location.path().replace(/^\//, '').split('/')[0]; - if (base === 'jobs') { - scope.refreshJobs(); - } else { + if (base !== 'jobs') { $location.path('/jobs'); } + else { + Wait('stop'); + } }); if (scope.removeStartPlaybookRun) { diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index 2afc102871..64e4d82dc5 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -355,6 +355,7 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job list = params.list, id = params.id, url = params.url, + pageSize = params.pageSize || 5, base = $location.path().replace(/^\//, '').split('/')[0], e, html; @@ -386,7 +387,7 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job scope: scope, list: list, url: url, - pageSize: 5 + pageSize: pageSize }); scope.iterator = list.iterator; diff --git a/awx/ui/static/js/helpers/Schedules.js b/awx/ui/static/js/helpers/Schedules.js index 677b63870c..6dccddf634 100644 --- a/awx/ui/static/js/helpers/Schedules.js +++ b/awx/ui/static/js/helpers/Schedules.js @@ -542,7 +542,7 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe * Called from a controller to setup the scope for a schedules list * */ - .factory('LoadSchedulesScope', ['$compile', '$location', '$routeParams','SearchInit', 'PaginateInit', 'GenerateList', 'SchedulesControllerInit', + .factory('LoadSchedulesScope', ['$compile', '$location', '$routeParams','SearchInit', 'PaginateInit', 'GenerateList', 'SchedulesControllerInit', 'SchedulesListInit', 'SearchWidget', function($compile, $location, $routeParams, SearchInit, PaginateInit, GenerateList, SchedulesControllerInit, SchedulesListInit, SearchWidget) { return function(params) { diff --git a/awx/ui/static/less/jobs.less b/awx/ui/static/less/jobs.less index 40e2f655ed..d317a1b7cb 100644 --- a/awx/ui/static/less/jobs.less +++ b/awx/ui/static/less/jobs.less @@ -39,6 +39,14 @@ margin-left: 3px; } + #breadcrumbs .nav-path { + background-color: @white; + } + + #breadcrumb-list.breadcrumb { + background-color: @white; + } + } @media (min-width: 1024px) { diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index 14406c75f1..76ad262b62 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -163,7 +163,12 @@ angular.module('Utilities', ['RestServices', 'Utilities']) } else if (data.detail) { Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); } else if (data.__all__) { - Alert('Error!', data.__all__); + if (typeof data.__all__ === 'object' && Array.isArray(data.__all__)) { + Alert('Error!', data.__all__[0]); + } + else { + Alert('Error!', data.__all__); + } } else if (form) { fieldErrors = false; for (field in form.fields) {