Job details -play button

Pause live events by clicking on a task or play. Restart live events by clicking the play button. Fixed issues with event viewer and host viewer dialogs.
This commit is contained in:
Chris Houseknecht
2014-07-24 20:47:25 -04:00
parent 627c6f029e
commit 9af5cc3d6d
6 changed files with 75 additions and 42 deletions

View File

@@ -31,8 +31,8 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.tasksMaxRows = 200;
scope.playsMaxRows = 200;
scope.liveEventProcessing = true; // control play/pause state of event processing
scope.pauseLiveEvents = false;
scope.liveEventProcessing = true; // true while job is active and live events are arriving
scope.pauseLiveEvents = false; // control play/pause state of event processing
scope.job_status = {};
scope.job_id = job_id;
@@ -105,7 +105,9 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
if ($rootScope.jobDetailInterval) {
window.clearInterval($rootScope.jobDetailInterval);
}
$scope.$emit('LoadJob'); //this is what is used for the refresh
if (!scope.pauseLiveEvents) {
$scope.$emit('LoadJob'); //this is what is used for the refresh
}
}
}
});
@@ -118,8 +120,8 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
var url;
Wait('stop');
if (JobIsFinished(scope)) {
$scope.liveEventProcessing = false; // signal that event processing is over and endless scroll
// should be enabled
scope.liveEventProcessing = false; // signal that event processing is over and endless scroll
scope.pauseLiveEvents = false; // should be enabled
url = scope.job.related.job_events + '?event=playbook_on_stats';
Rest.setUrl(url);
Rest.get()
@@ -143,7 +145,6 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
api_complete = true; //trigger events to start processing
$rootScope.jobDetailInterval = setInterval(function() {
$log.debug('Updating the DOM...');
UpdateDOM({ scope: scope });
}, 2000);
}
@@ -291,6 +292,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.activeTask = data.results[0].id;
}
scope.selectedTask = scope.activeTask;
}
data.results.forEach(function(event, idx) {
var end, elapsed, status, status_text;
@@ -352,7 +354,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
task: play.tasks[event.id]
});
});
if (scope.activeTask) {
if (scope.activeTask && scope.jobData.plays[scope.activePlay] && scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) {
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'active';
}
scope.$emit('LoadHosts');
@@ -395,6 +397,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.activePlay = data.results[0].id;
}
scope.selectedPlay = scope.activePlay;
}
data.results.forEach(function(event, idx) {
var status, status_text, start, end, elapsed, ok, changed, failed, skipped;
@@ -457,7 +460,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + scope.host_summary.unreachable +
scope.host_summary.failed;
});
if (scope.activePlay) {
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
scope.jobData.plays[scope.activePlay].playActiveClass = 'active';
}
scope.$emit('LoadTasks', events_url);
@@ -507,6 +510,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
}
scope.removeLoadJobRow = scope.$on('LoadJob', function() {
Wait('start');
scope.job_status = {};
// Load the job record
Rest.setUrl(GetBasePath('jobs') + job_id + '/');
Rest.get()
@@ -552,6 +556,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
if (data.status === 'successful' || data.status === 'failed' || data.status === 'error' || data.status === 'canceled') {
scope.job_status.finished = data.finsished;
scope.liveEventProcessing = false;
scope.pauseLiveEvents = false;
}
else {
scope.job_status.finished = null;
@@ -653,9 +658,19 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.adjustSize();
}, 500));
function flashPlayTip() {
setTimeout(function(){
$('#play-help').popover('show');
},500);
setTimeout(function() {
$('#play-help').popover('hide');
}, 5000);
}
scope.selectPlay = function(id) {
if (scope.liveEventProcessing) {
if (scope.liveEventProcessing && !scope.pauseLiveEvents) {
scope.pauseLiveEvents = true;
flashPlayTip();
}
SelectPlay({
scope: scope,
@@ -664,8 +679,9 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
};
scope.selectTask = function(id) {
if (scope.liveEventProcessing) {
if (scope.liveEventProcessing && !scope.pauseLiveEvents) {
scope.pauseLiveEvents = true;
flashPlayTip();
}
SelectTask({
scope: scope,
@@ -673,6 +689,13 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
});
};
scope.togglePlayButton = function() {
if (scope.pauseLiveEvents) {
scope.pauseLiveEvents = false;
scope.$emit('LoadJob');
}
};
scope.toggleSummary = function(hide) {
var docw, doch, height = $('#job-detail-container').height(), slide_width;
if (!hide) {
@@ -739,7 +762,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.filterPlayStatus = function() {
scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadPlays({
scope: scope
});
@@ -753,7 +776,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.searchPlaysEnabled = true;
}
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadPlays({
scope: scope
});
@@ -774,7 +797,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.searchTasksEnabled = true;
}
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadTasks({
scope: scope
});
@@ -795,7 +818,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.searchHostsEnabled = true;
}
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadHosts({
scope: scope
});
@@ -816,7 +839,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
scope.searchHostSummaryEnabled = true;
}
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
ReloadHostSummaryList({
scope: scope
});
@@ -832,7 +855,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.filterTaskStatus = function() {
scope.search_task_status = (scope.search_task_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadTasks({
scope: scope
});
@@ -841,7 +864,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.filterHostStatus = function() {
scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadHosts({
scope: scope
});
@@ -850,7 +873,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.filterHostSummaryStatus = function() {
scope.search_host_summary_status = (scope.search_host_summary_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing) {
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
ReloadHostSummaryList({
scope: scope
});
@@ -861,7 +884,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
EventViewer({
scope: scope,
url: scope.job.related.job_events,
parent_id: scope.activeTask,
parent_id: scope.selectedTask,
event_id: id,
title: 'Host Events'
});
@@ -975,7 +998,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
else {
// no next event (task), get the end time of the play
scope.plays.every(function(p, j) {
if (p.id === scope.activePlay) {
if (p.id === scope.selectedPlay) {
end = scope.plays[j].finished;
return false;
}
@@ -997,7 +1020,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope.tasks.push({
id: event.id,
play_id: scope.activePlay,
play_id: scope.selectedPlay,
name: event.name,
status: status,
status_text: status_text,

View File

@@ -116,9 +116,9 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities', 'EventView
var html = '';
html += "<tr>\n";
html += "<td class=\"col-md-3\"><a href=\"\" ng-click=\"showDetails(" + res.id + ")\" aw-tool-tip=\"Click to view details\" data-placement=\"top\"><i class=\"fa icon-job-" + res.status + "\"></i> " + res.status_text + "</a></td>\n";
html += "<td class=\"col-md=3\">" + res.host_name + "</td>\n";
html += "<td class=\"col-md-3\">" + res.play + "</td>\n";
html += "<td class=\"col-md-3\">" + res.task + "</td>\n";
html += "<td class=\"col-md=3\" ng-non-bindable>" + res.host_name + "</td>\n";
html += "<td class=\"col-md-3\" ng-non-bindable>" + res.play + "</td>\n";
html += "<td class=\"col-md-3\" ng-non-bindable>" + res.task + "</td>\n";
html += "</tr>";
return html;
};

View File

@@ -725,16 +725,16 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
};
}])
// Call SelectPlay whenever the the activePlay needs to change
.factory('SelectPlay', ['SelectTask', 'LoadTasks', function(SelectTask, LoadTasks) {
// Call when the selected Play needs to change
.factory('SelectPlay', ['LoadTasks', function(LoadTasks) {
return function(params) {
var scope = params.scope,
id = params.id,
callback = params.callback;
scope.activePlay = id;
scope.selectedPlay = id;
scope.plays.forEach(function(play, idx) {
if (play.id === scope.activePlay) {
if (play.id === scope.selectedPlay) {
scope.plays[idx].playActiveClass = 'active';
}
else {
@@ -760,14 +760,14 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
scope.tasks = [];
scope.tasksMap = {};
if (scope.activePlay) {
url = scope.job.url + 'job_tasks/?event_id=' + scope.activePlay;
if (scope.selectedPlay) {
url = scope.job.url + 'job_tasks/?event_id=' + scope.selectedPlay;
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
url += (scope.search_task_status === 'failed') ? '&failed=true' : '';
url += '&page_size=' + scope.tasksMaxRows + '&order_by=id';
scope.plays.every(function(p, idx) {
if (p.id === scope.activePlay) {
if (p.id === scope.selectedPlay) {
play = scope.plays[idx];
return false;
}
@@ -793,7 +793,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
else {
// no next event (task), get the end time of the play
scope.plays.every(function(play) {
if (play.id === scope.activePlay) {
if (play.id === scope.selectedPlay) {
end = play.finished;
return false;
}
@@ -816,7 +816,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
scope.tasks.push({
id: event.id,
play_id: scope.activePlay,
play_id: scope.selectedPlay,
name: event.name,
status: status,
status_text: status_text,
@@ -859,7 +859,6 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
});
}
else {
//$('#tasks-table-detail').mCustomScrollbar("update");
SelectTask({
scope: scope,
id: null,
@@ -869,16 +868,16 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
};
}])
// Call SelectTask whenever the activeTask needs to change
// Call when the selected task needs to change
.factory('SelectTask', ['LoadHosts', function(LoadHosts) {
return function(params) {
var scope = params.scope,
id = params.id,
callback = params.callback;
scope.activeTask = id;
scope.selectedTask = id;
scope.tasks.forEach(function(task, idx) {
if (task.id === scope.activeTask) {
if (task.id === scope.selectedTask) {
scope.tasks[idx].taskActiveClass = 'active';
}
else {
@@ -904,9 +903,9 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
scope.hostResults = [];
scope.hostResultsMap = {};
if (scope.activeTask) {
if (scope.selectedTask) {
// If we have a selected task, then get the list of hosts
url = scope.job.related.job_events + '?parent=' + scope.activeTask + '&';
url = scope.job.related.job_events + '?parent=' + scope.selectedTask + '&';
url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : '';
url += (scope.search_host_status === 'failed') ? 'failed=true&' : '';
url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order_by=host__name';
@@ -1178,6 +1177,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
setTimeout( function() {
scope.$apply( function() {
scope.plays = result;
scope.selectedPlay = scope.activePlay;
if (scope.liveEventProcessing) {
$('#plays-table-detail').scrollTop($('#plays-table-detail').prop("scrollHeight"));
}
@@ -1203,7 +1203,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
return 0;
}
if (scope.activePlay) {
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
tasks = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks));
@@ -1253,6 +1253,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
setTimeout( function() {
scope.$apply( function() {
scope.tasks = result;
scope.selectedTask = scope.activeTask;
if (scope.liveEventProcessing) {
$('#tasks-table-detail').scrollTop($('#tasks-table-detail').prop("scrollHeight"));
}
@@ -1273,7 +1274,8 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
key,
keys;
if (scope.activePlay && scope.activeTask) {
if (scope.activePlay && scope.activeTask && scope.jobData.plays[scope.activePlay] &&
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) {
hostResults = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults));

View File

@@ -80,6 +80,12 @@
#jobs-detail {
#play-help {
width: 1px;
height: 1px;
color: #fff;
}
.job_summary {
.table {
margin-bottom: 0;

View File

@@ -229,7 +229,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
* aw-tool-tip="<< tooltip text here >>"
*
* Include the standard TB data-XXX attributes to controll a tooltip's appearance. We will
* default placement to the left and delay to 2 seconds.
* default placement to the left and delay to the config setting.
*/
.directive('awToolTip', function() {
return function(scope, element, attrs) {

View File

@@ -15,6 +15,8 @@
<div class="job_well">
<div class="row">
<div class="col-md-12 text-right">
<a href="" id="play-help" aw-pop-over="Live event processing is now paused. Click here to resume." id="play-button-help" data-placement="left" ng-show="pauseLiveEvents" ><i class="fa fa-question"></i></a>
<a href="" ng-click="togglePlayButton()" id="play-button" class="btn btn-primary btn-xs" aw-tool-tip="Resume viewing live events" data-placement="top" ng-show="pauseLiveEvents" style="margin-right:25px;"><i class="fa fa-play"></i></a>
<a href="/#/jobs/{{ job_id }}/stdout" id="view-stdout-button" target="_blank" type="button" class="btn btn-primary btn-xs" aw-tool-tip="View standard out. Opens in new tab or window." data-placement="top"><i class="fa fa-external-link"></i></a>
<button type="button" class="btn btn-xs btn-primary ng-hide" ng-click="refresh()" id="refresh_btn" aw-tool-tip="Refresh the page" data-placement="top" ng-show="socketStatus == 'error'"
data-original-title="" title=""><i class="fa fa-refresh"></i></button>