diff --git a/awx/ui/client/legacy-styles/stdout.less b/awx/ui/client/legacy-styles/stdout.less index e8f764dee6..61a29dd706 100644 --- a/awx/ui/client/legacy-styles/stdout.less +++ b/awx/ui/client/legacy-styles/stdout.less @@ -32,6 +32,7 @@ #pre-container { overflow-x: scroll; overflow-y: auto; + padding: 10px; } } diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 8b0757f370..4586c80fe2 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -881,9 +881,9 @@ var tower = angular.module('Tower', [ }]); }]) - .run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'Socket', + .run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', '$state', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'Socket', 'LoadConfig', 'Store', 'ShowSocketHelp', 'AboutAnsibleHelp', 'pendoService', - function ($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, Socket, + function ($q, $compile, $cookieStore, $rootScope, $log, $state, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, Socket, LoadConfig, Store, ShowSocketHelp, AboutAnsibleHelp, pendoService) { @@ -959,32 +959,28 @@ var tower = angular.module('Tower', [ ' status changed to ' + data.status + ' send to ' + $location.$$url); - var urlToCheck = $location.$$url; - if (urlToCheck.indexOf("?") !== -1) { - urlToCheck = urlToCheck.substr(0, urlToCheck.indexOf("?")); - } - // this acts as a router...it emits the proper // value based on what URL the user is currently // accessing. - if (urlToCheck === '/jobs') { + if ($state.is('jobs')) { $rootScope.$emit('JobStatusChange-jobs', data); - } else if (/\/jobs\/(\d)+\/stdout/.test(urlToCheck) || - /\/ad_hoc_commands\/(\d)+/.test(urlToCheck)) { - - // TODO: something will need to change here for stdout + } else if ($state.is('jobDetail') || + $state.is('adHocJobStdout') || + $state.is('inventorySyncStdout') || + $state.is('managementJobStdout') || + $state.is('scmUpdateStdout')) { $log.debug("sending status to standard out"); $rootScope.$emit('JobStatusChange-jobStdout', data); - } else if (/\/jobs\/(\d)+/.test(urlToCheck)) { + } else if ($state.is('jobDetail')) { $rootScope.$emit('JobStatusChange-jobDetails', data); - } else if (urlToCheck === '/home') { + } else if ($state.is('dashboard')) { $rootScope.$emit('JobStatusChange-home', data); - } else if (urlToCheck === '/portal') { + } else if ($state.is('portal')) { $rootScope.$emit('JobStatusChange-portal', data); - } else if (urlToCheck === '/projects') { + } else if ($state.is('projects')) { $rootScope.$emit('JobStatusChange-projects', data); - } else if (/\/inventories\/(\d)+\/manage/.test(urlToCheck)) { + } else if ($state.is('inventoryManage')) { $rootScope.$emit('JobStatusChange-inventory', data); } }); diff --git a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html index 3b8b51fa97..92e4d5e762 100644 --- a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html +++ b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.partial.html @@ -1,7 +1,7 @@
-
+
RESULTS @@ -98,17 +98,19 @@
- STANDARD OUT -
-
-
-
-
-
- +
STANDARD OUT
+
+ + + +
+
diff --git a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js index d9d121b443..0b6f547359 100644 --- a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js +++ b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js @@ -23,18 +23,16 @@ export default { return FeaturesService.get(); }], adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - // if (!$rootScope.adhoc_event_socket) { - // $rootScope.adhoc_event_socket = Socket({ - // scope: $rootScope, - // endpoint: "ad_hoc_command_events" - // }); - // $rootScope.adhoc_event_socket.init(); - // return true; - // } else { - // return true; - // } - - return true; + if (!$rootScope.adhoc_event_socket) { + $rootScope.adhoc_event_socket = Socket({ + scope: $rootScope, + endpoint: "ad_hoc_command_events" + }); + $rootScope.adhoc_event_socket.init(); + return true; + } else { + return true; + } }] } }; diff --git a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html index 3a1152f0ec..d16efeb007 100644 --- a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html +++ b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.partial.html @@ -1,7 +1,7 @@
-
+
RESULTS @@ -112,17 +112,19 @@
- STANDARD OUT -
-
-
-
-
-
- +
STANDARD OUT
+
+ + + +
+
diff --git a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js index a357f39afc..3fa874fbda 100644 --- a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js +++ b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js @@ -24,18 +24,8 @@ export default { features: ['FeaturesService', function(FeaturesService) { return FeaturesService.get(); }], - adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - // if (!$rootScope.adhoc_event_socket) { - // $rootScope.adhoc_event_socket = Socket({ - // scope: $rootScope, - // endpoint: "ad_hoc_command_events" - // }); - // $rootScope.adhoc_event_socket.init(); - // return true; - // } else { - // return true; - // } - + inventorySyncSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { + // TODO: determine whether or not we have socket support for inventory sync standard out return true; }] } diff --git a/awx/ui/client/src/standard-out/log/main.js b/awx/ui/client/src/standard-out/log/main.js new file mode 100644 index 0000000000..bb97a737be --- /dev/null +++ b/awx/ui/client/src/standard-out/log/main.js @@ -0,0 +1,10 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import standardOutLog from './standard-out-log.directive'; +export default + angular.module('standardOutLogDirective', []) + .directive('standardOutLog', standardOutLog); diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js new file mode 100644 index 0000000000..3316d088a9 --- /dev/null +++ b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js @@ -0,0 +1,206 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'ProcessErrors', 'Rest', 'Wait', + function ($log, $rootScope, $scope, $state, $stateParams, ProcessErrors, Rest, Wait) { + + var api_complete = false, + stdout_url, + current_range, + loaded_sections = [], + event_queue = 0, + auto_scroll_down=true, // programmatic scroll to bottom + live_event_processing = true, + page_size = 500, + job_id = $stateParams.id; + + $scope.should_apply_live_events = true; + + // Open up a socket for events depending on the type of job + function openSockets() { + if ($state.current.name == 'adHocJobStdout') { + $log.debug("socket watching on ad_hoc_command_events-" + job_id); + $rootScope.adhoc_event_socket.on("ad_hoc_command_events-" + job_id, function() { + $log.debug("socket fired on ad_hoc_command_events-" + job_id); + if (api_complete) { + event_queue++; + } + }); + } + // TODO: do we need to add socket listeners for scmUpdateStdout, inventorySyncStdout, managementJobStdout? + } + + openSockets(); + + // This is a trigger for loading up the standard out + if ($scope.removeLoadStdout) { + $scope.removeLoadStdout(); + } + $scope.removeLoadStdout = $scope.$on('LoadStdout', function() { + if (loaded_sections.length === 0) { + loadStdout() + } + else if (live_event_processing) { + getNextSection(); + } + }); + + // This interval checks to see whether or not we've gotten a new + // event via sockets. If so, go out and update the standard out + // log. + $rootScope.jobStdOutInterval = setInterval( function() { + if (event_queue > 0) { + // events happened since the last check + $log.debug('checking for stdout...'); + if (loaded_sections.length === 0) { ////this if statement for refresh + $log.debug('calling LoadStdout'); + loadStdout(); + } + else if (live_event_processing) { + $log.debug('calling getNextSection'); + getNextSection(); + } + event_queue = 0; + } + }, 2000); + + // stdoutEndpoint gets passed through in the directive declaration. + // This watcher fires off loadStdout() when the endpoint becomes + // available. + $scope.$watch('stdoutEndpoint', function(newVal, oldVal) { + if(newVal && newVal != oldVal) { + // Fire off the server call + loadStdout(); + } + }); + + function loadStdout() { + Rest.setUrl($scope.stdoutEndpoint + '?format=json&start_line=-' + page_size); + Rest.get() + .success(function(data) { + Wait('stop'); + if (data.content) { + api_complete = true; + $('#pre-container-content').html(data.content); + current_range = data.range; + if (data.content !== "Waiting for results...") { + loaded_sections.push({ + start: (data.range.start < 0) ? 0 : data.range.start, + end: data.range.end + }); + } + + $('#pre-container').scrollTop($('#pre-container').prop("scrollHeight")); + } + else { + api_complete = true; + } + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); + }); + }; + + function getNextSection() { + // get the next range of data from the API + var start = loaded_sections[loaded_sections.length - 1].end, url; + url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + (start + page_size); + $('#stdoutMoreRowsBottom').fadeIn(); + Rest.setUrl(url); + Rest.get() + .success( function(data) { + if ($('#pre-container-content').html() === "Waiting for results...") { + $('#pre-container-content').html(data.content); + } else { + $('#pre-container-content').append(data.content); + } + loaded_sections.push({ + start: (data.range.start < 0) ? 0 : data.range.start, + end: data.range.end + }); + //console.log('loaded start: ' + data.range.start + ' end: ' + data.range.end); + //console.log(data.content); + if ($scope.should_apply_live_events) { + // if user has not disabled live event view by scrolling upward, then scroll down to the new content + current_range = data.range; + auto_scroll_down = true; // prevent auto load from happening + $('#pre-container').scrollTop($('#pre-container').prop("scrollHeight")); + } + $('#stdoutMoreRowsBottom').fadeOut(400); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); + }); + } + + $scope.stdOutScrollToTop = function() { + // scroll up or back in time toward the beginning of the file + var start, end, url; + if (loaded_sections.length > 0 && loaded_sections[0].start > 0) { + start = (loaded_sections[0].start - page_size > 0) ? loaded_sections[0].start - page_size : 0; + end = loaded_sections[0].start - 1; + } + else if (loaded_sections.length === 0) { + start = 0; + end = page_size; + } + if (start !== undefined && end !== undefined) { + $('#stdoutMoreRowsTop').fadeIn(); + url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + end; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + //var currentPos = $('#pre-container').scrollTop(); + var newSH, oldSH = $('#pre-container').prop('scrollHeight'), + st = $('#pre-container').scrollTop(); + + $('#pre-container-content').prepend(data.content); + + newSH = $('#pre-container').prop('scrollHeight'); + $('#pre-container').scrollTop(newSH - oldSH + st); + + loaded_sections.unshift({ + start: (data.range.start < 0) ? 0 : data.range.start, + end: data.range.end + }); + current_range = data.range; + $('#stdoutMoreRowsTop').fadeOut(400); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); + }); + } + }; + + // We watch for job status changes here. If the job completes we want to clear out the + // stdout interval and kill the live_event_processing flag. + if ($scope.removeJobStatusChange) { + $scope.removeJobStatusChange(); + } + $scope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobStdout', function(e, data) { + if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { + if (data.status === 'failed' || data.status === 'canceled' || + data.status === 'error' || data.status === 'successful') { + if ($rootScope.jobStdOutInterval) { + window.clearInterval($rootScope.jobStdOutInterval); + } + if (live_event_processing) { + if (loaded_sections.length === 0) { + loadStdout(); + } + else { + getNextSection(); + } + } + live_event_processing = false; + } + } + }); + +}]; diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.directive.js b/awx/ui/client/src/standard-out/log/standard-out-log.directive.js new file mode 100644 index 0000000000..a780a1f4d3 --- /dev/null +++ b/awx/ui/client/src/standard-out/log/standard-out-log.directive.js @@ -0,0 +1,46 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import standardOutLogController from './standard-out-log.controller'; +export default [ 'templateUrl', + function(templateUrl) { + return { + scope: { + stdoutEndpoint: '=', + jobId: '=' + }, + templateUrl: templateUrl('standard-out/log/standard-out-log'), + restrict: 'E', + controller: standardOutLogController, + link: function(scope) { + // All of our DOM related stuff will go in here + + var lastScrollTop, + direction; + + function detectDirection() { + var st = $('#pre-container').scrollTop(); + if (st > lastScrollTop) { + direction = "down"; + } else { + direction = "up"; + } + lastScrollTop = st; + return direction; + } + + $('#pre-container').bind('scroll', function() { + if (detectDirection() === "up") { + scope.should_apply_live_events = false; + } + + if ($(this).scrollTop() + $(this).height() === $(this).prop("scrollHeight")) { + scope.should_apply_live_events = true; + } + }); + } + }; +}]; diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.partial.html b/awx/ui/client/src/standard-out/log/standard-out-log.partial.html new file mode 100644 index 0000000000..247e58b165 --- /dev/null +++ b/awx/ui/client/src/standard-out/log/standard-out-log.partial.html @@ -0,0 +1,9 @@ +
+
+
+
+
+ +
+
diff --git a/awx/ui/client/src/standard-out/main.js b/awx/ui/client/src/standard-out/main.js index b0aafe40ad..1e0f451014 100644 --- a/awx/ui/client/src/standard-out/main.js +++ b/awx/ui/client/src/standard-out/main.js @@ -10,8 +10,9 @@ import stdoutInventorySyncRoute from './inventory-sync/standard-out-inventory-sy import stdoutScmUpdateRoute from './scm-update/standard-out-scm-update.route'; import {JobStdoutController} from './standard-out.controller'; import StandardOutHelper from './standard-out-factories/main'; +import standardOutLogDirective from './log/main'; -export default angular.module('standardOut', [StandardOutHelper.name]) +export default angular.module('standardOut', [StandardOutHelper.name, standardOutLogDirective.name]) .controller('JobStdoutController', JobStdoutController) .run(['$stateExtender', function($stateExtender) { $stateExtender.addState(stdoutAdhocRoute); diff --git a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html index 36a29fef55..3e035ddab5 100644 --- a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html +++ b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.partial.html @@ -1,7 +1,7 @@
-
+
RESULTS @@ -64,17 +64,14 @@
- STANDARD OUT -
-
-
-
-
-
- +
STANDARD OUT
+
+
+
diff --git a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js index 6eaa1aa184..3f3bf8a8dd 100644 --- a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js +++ b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js @@ -22,18 +22,8 @@ export default { features: ['FeaturesService', function(FeaturesService) { return FeaturesService.get(); }], - adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - // if (!$rootScope.adhoc_event_socket) { - // $rootScope.adhoc_event_socket = Socket({ - // scope: $rootScope, - // endpoint: "ad_hoc_command_events" - // }); - // $rootScope.adhoc_event_socket.init(); - // return true; - // } else { - // return true; - // } - + managementJobSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { + // TODO: determine whether or not we have socket support for management job standard out return true; }] } diff --git a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html index ec1378cad7..74e7e63925 100644 --- a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html +++ b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.partial.html @@ -1,7 +1,7 @@
-
+
RESULTS @@ -77,17 +77,19 @@
- STANDARD OUT -
-
-
-
-
-
- +
STANDARD OUT
+
+ + + +
+
diff --git a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js index 294518cd7b..15cddbb5b4 100644 --- a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js +++ b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js @@ -24,18 +24,8 @@ export default { features: ['FeaturesService', function(FeaturesService) { return FeaturesService.get(); }], - adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - // if (!$rootScope.adhoc_event_socket) { - // $rootScope.adhoc_event_socket = Socket({ - // scope: $rootScope, - // endpoint: "ad_hoc_command_events" - // }); - // $rootScope.adhoc_event_socket.init(); - // return true; - // } else { - // return true; - // } - + scmUpdateSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { + // TODO: determine whether or not we have socket support for scm update standard out return true; }] } diff --git a/awx/ui/client/src/standard-out/standard-out.block.less b/awx/ui/client/src/standard-out/standard-out.block.less index 654439b6ed..8d0e8a0219 100644 --- a/awx/ui/client/src/standard-out/standard-out.block.less +++ b/awx/ui/client/src/standard-out/standard-out.block.less @@ -10,19 +10,19 @@ .StandardOut-leftPanel { flex: 0 0 400px; + margin-right: 20px; } .StandardOut-rightPanel { flex: 1 0; - margin-left: 20px; } .StandardOut-panelHeader { color: @default-interface-txt; font-size: 14px; font-weight: bold; - margin-right: 10px; text-transform: uppercase; + display: flex; } .StandardOut-consoleOutput { @@ -30,6 +30,8 @@ min-height: 200px; background-color: @default-secondary-bg; border-radius: 5px; + height: 300px; + overflow: scroll; } .StandardOut-details { @@ -63,13 +65,54 @@ text-transform: capitalize; } +.StandardOut-preContainer { + height: 300px; +} + +.StandardOut-panelHeaderText { + align-items: center; + flex: 1 0 auto; + display: flex; +} + +.StandardOut-panelHeaderActions { + justify-content: flex-end; + display: flex; + margin-left: 10px; + font-size: 20px; +} + +.StandardOut-actionButton { + font-size: 16px; + height: 30px; + min-width: 30px; + color: #b7b7b7; + background-color: inherit; + border: none; + border-radius: 50%; +} + +.StandardOut-actionButton:hover { + background-color: @list-actn-bg-hov !important; + color: @list-actn-icn-hov; +} + +.StandardOut-actionButton--active { + background-color: @list-actn-bg-hov !important; + color: @list-actn-icn-hov; +} + +.StandardOut-actionButton + a { + margin-left: 15px; +} + @standardout-breakpoint: 900px; @media screen and (max-width: @standardout-breakpoint) { .StandardOut { flex-direction: column; } - .StandardOut-rightPanel { - margin-left: 0px; + .StandardOut-leftPanel { + margin-right: 0px; } } diff --git a/awx/ui/client/src/standard-out/standard-out.controller.js b/awx/ui/client/src/standard-out/standard-out.controller.js index 1b9233a248..152d2a8a5d 100644 --- a/awx/ui/client/src/standard-out/standard-out.controller.js +++ b/awx/ui/client/src/standard-out/standard-out.controller.js @@ -11,153 +11,34 @@ */ -export function JobStdoutController ($location, $log, $rootScope, $scope, $compile, $state, $stateParams, ClearScope, GetBasePath, Wait, Rest, ProcessErrors, ModelToBasePathKey, Empty, GetChoices, LookUpName) { +export function JobStdoutController ($rootScope, $scope, $state, $stateParams, ClearScope, GetBasePath, Rest, ProcessErrors, Empty, GetChoices, LookUpName) { ClearScope(); var job_id = $stateParams.id, - jobType = $state.current.data.jobType, - api_complete = false, - stdout_url, - current_range, - loaded_sections = [], - event_queue = 0, - auto_scroll_down=true, // programmatic scroll to bottom - live_event_processing = true, - should_apply_live_events = true, - page_size = 500, - lastScrollTop = 0, - st, - direction; + jobType = $state.current.data.jobType; - $scope.isClosed = true; + // This scope variable controls whether or not the left panel is shown and the right panel + // is expanded to take up the full screen + $scope.stdoutFullScreen = false; - - // function openSockets() { - // if (/\/jobs\/(\d)+\/stdout/.test($location.$$url)) { - // $log.debug("socket watching on job_events-" + job_id); - // $rootScope.event_socket.on("job_events-" + job_id, function() { - // $log.debug("socket fired on job_events-" + job_id); - // if (api_complete) { - // event_queue++; - // } - // }); - // } else if (/\/ad_hoc_commands\/(\d)+/.test($location.$$url)) { - // $log.debug("socket watching on ad_hoc_command_events-" + job_id); - // $rootScope.adhoc_event_socket.on("ad_hoc_command_events-" + job_id, function() { - // $log.debug("socket fired on ad_hoc_command_events-" + job_id); - // if (api_complete) { - // event_queue++; - // } - // }); - // } - // } - // - // openSockets(); - - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); + // Listen for job status updates that may come across via sockets. We need to check the payload + // to see whethere the updated job is the one that we're currently looking at. + if ($scope.removeJobStatusChange) { + $scope.removeJobStatusChange(); } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobStdout', function(e, data) { + $scope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobStdout', function(e, data) { if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10) && $scope.job) { $scope.job.status = data.status; - if (data.status === 'failed' || data.status === 'canceled' || - data.status === 'error' || data.status === 'successful') { - if ($rootScope.jobStdOutInterval) { - window.clearInterval($rootScope.jobStdOutInterval); - } - if (live_event_processing) { - if (loaded_sections.length === 0) { - $scope.$emit('LoadStdout'); - } - else { - getNextSection(); - } - } - live_event_processing = false; - } } + + // TODO: when the job completes we should refresh the job data so that we pull in the finish + // timestamp as well as the run time. }); - $rootScope.jobStdOutInterval = setInterval( function() { - if (event_queue > 0) { - // events happened since the last check - $log.debug('checking for stdout...'); - if (loaded_sections.length === 0) { ////this if statement for refresh - $log.debug('calling LoadStdout'); - $scope.$emit('LoadStdout'); - } - else if (live_event_processing) { - $log.debug('calling getNextSection'); - getNextSection(); - } - event_queue = 0; - } - }, 2000); - - if ($scope.removeLoadStdout) { - $scope.removeLoadStdout(); - } - $scope.removeLoadStdout = $scope.$on('LoadStdout', function() { - Rest.setUrl(stdout_url + '?format=json&start_line=-' + page_size); - Rest.get() - .success(function(data) { - Wait('stop'); - if (data.content) { - api_complete = true; - $('#pre-container-content').html(data.content); - current_range = data.range; - if (data.content !== "Waiting for results...") { - loaded_sections.push({ - start: (data.range.start < 0) ? 0 : data.range.start, - end: data.range.end - }); - } - - $('#pre-container').scrollTop($('#pre-container').prop("scrollHeight")); - } - else { - api_complete = true; - } - }) - .error(function(data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); - }); - }); - - function detectDirection() { - st = $('#pre-container').scrollTop(); - if (st > lastScrollTop) { - direction = "down"; - } else { - direction = "up"; - } - lastScrollTop = st; - return direction; - } - - $('#pre-container').bind('scroll', function() { - if (detectDirection() === "up") { - should_apply_live_events = false; - } - - if ($(this).scrollTop() + $(this).height() === $(this).prop("scrollHeight")) { - should_apply_live_events = true; - } - }); - - $scope.toggleClosedStatus = function() { - if (!$scope.isClosed) { - $('.StandardOutDetails-detailRow--closable').slideUp(200); - $scope.isClosed = true; - } - else { - $('.StandardOutDetails-detailRow--closable').slideDown(200); - $scope.isClosed = false; - } - }; - + // Go out and get the job details based on the job type. jobType gets defined + // in the data block of the route declaration for each of the different types + // of stdout jobs. Rest.setUrl(GetBasePath('base') + jobType + '/' + job_id + '/'); Rest.get() .success(function(data) { @@ -179,7 +60,6 @@ export function JobStdoutController ($location, $log, $rootScope, $scope, $compi $scope.limit = data.limit; $scope.verbosity = data.verbosity; $scope.job_tags = data.job_tags; - stdout_url = data.related.stdout; // If we have a source then we have to go get the source choices from the server if (!Empty(data.source)) { @@ -252,14 +132,12 @@ export function JobStdoutController ($location, $log, $rootScope, $scope, $compi }); } - // if (data.status === 'successful' || data.status === 'failed' || data.status === 'error' || data.status === 'canceled') { - // live_event_processing = false; - // if ($rootScope.jobStdOutInterval) { - // window.clearInterval($rootScope.jobStdOutInterval); - // } - // } - if(stdout_url) { - $scope.$emit('LoadStdout'); + // If the job isn't running we want to clear out the interval that goes out and checks for stdout updates. + // This interval is defined in the standard out log directive controller. + if (data.status === 'successful' || data.status === 'failed' || data.status === 'error' || data.status === 'canceled') { + if ($rootScope.jobStdOutInterval) { + window.clearInterval($rootScope.jobStdOutInterval); + } } }) .error(function(data, status) { @@ -267,88 +145,17 @@ export function JobStdoutController ($location, $log, $rootScope, $scope, $compi msg: 'Failed to retrieve job: ' + job_id + '. GET returned: ' + status }); }); + // TODO: this is currently not used but is necessary for cases where sockets + // are not available and a manual refresh trigger is needed. $scope.refresh = function(){ - if (loaded_sections.length === 0) { ////this if statement for refresh - $scope.$emit('LoadStdout'); - } - else if (live_event_processing) { - getNextSection(); - } + $scope.$emit('LoadStdout'); }; - $scope.stdOutScrollToTop = function() { - // scroll up or back in time toward the beginning of the file - var start, end, url; - if (loaded_sections.length > 0 && loaded_sections[0].start > 0) { - start = (loaded_sections[0].start - page_size > 0) ? loaded_sections[0].start - page_size : 0; - end = loaded_sections[0].start - 1; - } - else if (loaded_sections.length === 0) { - start = 0; - end = page_size; - } - if (start !== undefined && end !== undefined) { - $('#stdoutMoreRowsTop').fadeIn(); - url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + end; - Rest.setUrl(url); - Rest.get() - .success( function(data) { - //var currentPos = $('#pre-container').scrollTop(); - var newSH, oldSH = $('#pre-container').prop('scrollHeight'), - st = $('#pre-container').scrollTop(); - - $('#pre-container-content').prepend(data.content); - - newSH = $('#pre-container').prop('scrollHeight'); - $('#pre-container').scrollTop(newSH - oldSH + st); - - loaded_sections.unshift({ - start: (data.range.start < 0) ? 0 : data.range.start, - end: data.range.end - }); - current_range = data.range; - $('#stdoutMoreRowsTop').fadeOut(400); - }) - .error(function(data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); - }); - } - }; - - function getNextSection() { - // get the next range of data from the API - var start = loaded_sections[loaded_sections.length - 1].end, url; - url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + (start + page_size); - $('#stdoutMoreRowsBottom').fadeIn(); - Rest.setUrl(url); - Rest.get() - .success( function(data) { - if ($('#pre-container-content').html() === "Waiting for results...") { - $('#pre-container-content').html(data.content); - } else { - $('#pre-container-content').append(data.content); - } - loaded_sections.push({ - start: (data.range.start < 0) ? 0 : data.range.start, - end: data.range.end - }); - //console.log('loaded start: ' + data.range.start + ' end: ' + data.range.end); - //console.log(data.content); - if (should_apply_live_events) { - // if user has not disabled live event view by scrolling upward, then scroll down to the new content - current_range = data.range; - auto_scroll_down = true; // prevent auto load from happening - $('#pre-container').scrollTop($('#pre-container').prop("scrollHeight")); - } - $('#stdoutMoreRowsBottom').fadeOut(400); - }) - .error(function(data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve stdout for job: ' + job_id + '. GET returned: ' + status }); - }); + // Click binding for the expand/collapse button on the standard out log + $scope.toggleStdoutFullscreen = function() { + $scope.stdoutFullScreen = !$scope.stdoutFullScreen; } } -JobStdoutController.$inject = [ '$location', '$log', '$rootScope', '$scope', '$compile', '$state', '$stateParams', 'ClearScope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors', 'ModelToBasePathKey', 'Empty', 'GetChoices', 'LookUpName']; +JobStdoutController.$inject = [ '$rootScope', '$scope', '$state', '$stateParams', 'ClearScope', 'GetBasePath', 'Rest', 'ProcessErrors', 'Empty', 'GetChoices', 'LookUpName'];