Latest job detail page changes. Fixed lookup modal horizontal scroll.

This commit is contained in:
Chris Houseknecht
2014-04-14 00:32:34 -04:00
parent 06cf3a2aec
commit b6dc4047f7
5 changed files with 408 additions and 159 deletions

View File

@@ -23,6 +23,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
$scope.plays = []; $scope.plays = [];
$scope.tasks = []; $scope.tasks = [];
$scope.hosts = [];
$scope.hostResults = [];
// Apply each event to the view // Apply each event to the view
if ($scope.removeEventsReady) { if ($scope.removeEventsReady) {

View File

@@ -39,7 +39,8 @@
angular.module('JobDetailHelper', ['Utilities', 'RestServices']) angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
.factory('DigestEvents', ['UpdatePlayStatus', 'UpdatePlayNoHostsMatched', function(UpdatePlayStatus, UpdatePlayNoHostsMatched) { .factory('DigestEvents', ['UpdatePlayStatus', 'UpdatePlayNoHostsMatched', 'UpdateHostStatus', 'UpdatePlayChild', 'AddHostResult',
function(UpdatePlayStatus, UpdatePlayNoHostsMatched, UpdateHostStatus, UpdatePlayChild, AddHostResult) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
events = params.events; events = params.events;
@@ -48,8 +49,22 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
scope.plays.push({ scope.plays.push({
id: event.id, id: event.id,
name: event.play, name: event.play,
status: (event.failed) ? 'failed' : 'successful',
children: []
});
}
if (event.event === 'playbook_on_setup') {
scope.tasks.push({
id: event.id,
name: event.event_display,
play_id: event.parent,
status: (event.failed) ? 'failed' : 'successful' status: (event.failed) ? 'failed' : 'successful'
}); });
UpdatePlayStatus({
scope: scope,
play_id: event.parent,
failed: event.failed
});
} }
if (event.event === 'playbook_on_task_start') { if (event.event === 'playbook_on_task_start') {
scope.tasks.push({ scope.tasks.push({
@@ -58,18 +73,68 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
play_id: event.parent, play_id: event.parent,
status: (event.failed) ? 'failed' : 'successful' status: (event.failed) ? 'failed' : 'successful'
}); });
UpdatePlayStatus({ scope: scope, play_id: event.parent, status: event.status }); UpdatePlayStatus({
scope: scope,
play_id: event.parent,
failed: event.failed
});
} }
if (event.event === 'playbook_on_no_hosts_matched') { if (event.event === 'playbook_on_no_hosts_matched') {
UpdatePlayNoHostsMatched({ scope: scope, play_id: event.parent }); UpdatePlayNoHostsMatched({ scope: scope, play_id: event.parent });
} }
if (event.event === 'runner_on_failed') { if (event.event === 'runner_on_failed') {
}
if (event.event === 'runner_on_ok') {
UpdateHostStatus({
scope: scope,
name: event.event_data.host,
host_id: event.host_id,
task_id: event.parent,
status: (event.changed) ? 'changed' : 'ok',
results: (event.res && event.res.results) ? event.res.results : ''
});
AddHostResult({
scope: scope,
event: event
});
} }
if (event.event === 'playbook_on_stats') { if (event.event === 'playbook_on_stats') {
} }
});
};
}])
.factory('UpdatePlayChild', [ function() {
return function(params) {
var scope = params.scope,
id = params.id,
play_id = params.play_id,
failed = params.failed,
name = params.name,
found_child = false;
scope.plays.every(function(play, i) {
if (play.id === play_id) {
scope.plays[i].children.every(function(child, j) {
if (child.id === id) {
scope.plays[i].children[j].status = (failed) ? 'failed' : 'successful';
found_child = true;
return false;
}
return true;
});
if (!found_child) {
scope.plays[i].children.push({
id: id,
name: name,
status: (failed) ? 'failed' : 'successful'
});
}
scope.plays[i].status = (failed) ? 'failed' : 'successful';
return false;
}
return true;
}); });
}; };
}]) }])
@@ -78,11 +143,11 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
.factory('UpdatePlayStatus', [ function() { .factory('UpdatePlayStatus', [ function() {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
status = params.status, failed = params.failed,
id = params.play_id; id = params.play_id;
scope.plays.every(function(play,idx) { scope.plays.every(function(play,idx) {
if (play.id === id) { if (play.id === id) {
scope.plays[idx].status = (status) ? 'failed' : 'successful'; scope.plays[idx].status = (failed) ? 'failed' : 'successful';
return false; return false;
} }
return true; return true;
@@ -90,6 +155,19 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
}; };
}]) }])
.factory('UpdateTaskStatus', [ function() {
return function(params) {
var scope = params.scope,
task_id = params.task_id,
failed = params.failed;
scope.tasks.every(function (task, i) {
if (task.id === task_id) {
scope.tasks[i].status = (failed) ? 'failed' : 'successful';
}
});
};
}])
.factory('UpdatePlayNoHostsMatched', [ function() { .factory('UpdatePlayNoHostsMatched', [ function() {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
@@ -102,6 +180,90 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
return true; return true;
}); });
}; };
}])
// Update or add a new host
.factory('UpdateHostStatus', ['UpdateTaskStatus', function(UpdateTaskStatus) {
return function(params) {
var scope = params.scope,
status = params.status, // ok, changed, unreachable, failed
name = params.name,
host_id = params.host_id,
task_id = params.task_id,
host_found = false;
scope.hosts.every(function(host, i) {
if (host.id === host_id) {
scope.hosts[i].ok += (status === 'ok' || status === 'changed') ? 1 : 0;
scope.hosts[i].changed += (status === 'changed') ? 1 : 0;
scope.hosts[i].unreachable += (status === 'unreachable') ? 1 : 0;
scope.hosts[i].failed += (status === 'failed') ? 1 : 0;
host_found = true;
return false;
}
return true;
});
if (!host_found) {
scope.hosts.push({
id: host_id,
name: name,
ok: (status === 'ok' || status === 'changed') ? 1 : 0,
changed: (status === 'changed') ? 1 : 0,
unreachable: (status === 'unreachable') ? 1 : 0,
failed: (status === 'failed') ? 1 : 0
});
}
// Mark task failed
if (status === 'failed') {
UpdateTaskStatus({
scope: scope,
task_id: task_id,
failed: true
});
}
};
}])
// Add a new host result
.factory('AddHostResult', ['Empty', function(Empty) {
return function(params) {
var scope = params.scope,
event = params.event,
id, status, host_id, play_name, task_name, module_name, module_args,
results, rc;
id = event.id;
status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful';
host_id = event.host;
play_name = event.play;
task_name = event.task;
if (event.event_data.res && event.event_data.res.invocation) {
module_name = event.event_data.res.invocation.module_name;
module_args = event.event_data.res.invocation.module_args;
}
else {
module_name = '';
module_args = '';
}
if (event.event_data.res && event.event_data.res.results) {
results = '';
event.event_data.res.results.forEach(function(row) {
results += row;
});
}
rc = (event.event_data.res && !Empty(event.event_data.res.rc)) ? event.event_data.res.rc : '';
scope.hostResults.push({
id: id,
status: status,
host_id: host_id,
play_name: play_name,
task_name : task_name,
module_name: module_name,
module_args: module_args,
results: results,
rc: rc
});
};
}]); }]);

View File

@@ -658,9 +658,12 @@ legend {
} }
#lookup-modal-dialog .instructions { #lookup-modal-dialog
margin-top: 0; overflow-x: hidden;
margin-bottom: 20px; .instructions {
margin-top: 0;
margin-bottom: 20px;
}
} }
.related-footer { .related-footer {
@@ -1576,15 +1579,71 @@ tr td button i {
/* New job detail page */ /* New job detail page */
.job-detail-tables { .relative-position {
position: relative;
}
.job-detail-tables, .job_options {
.table {
margin-bottom: 0;
}
.table>tbody>tr>td { .table>tbody>tr>td {
border-top-color: #fff; border-top-color: #fff;
padding: 0;
} }
.table>thead>tr>th { .table>thead>tr>th {
border-bottom-color: #fff; border-bottom-color: #fff;
padding: 0;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li ul {
margin-left: 20px;
} }
} }
.job_well {
padding: 8px;
background-color: @well;
border: 1px solid @well-border;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
.job_options {
height: 100px;
overflow-y: auto;
overflow-x: none;
}
.scroll-up-indicator {
position: absolute;
right: 18px;
font-size: 14px;
bottom: -2px;
padding: 0;
}
.scroll-down-indicator {
position: absolute;
right: 18px;
bottom: -2px;
font-size: 14px;
padding: 0;
}
.scroll-up-indicator,
.scroll-up-indicator:hover,
.scroll-up-indicator:visited,
.scroll-down-indicator,
.scroll-down-indicator:hover,
.scroll-down-indicator:visited {
color: @grey;
}
/* ng-cloak directive */ /* ng-cloak directive */

View File

@@ -696,6 +696,51 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
} }
}); });
}; };
}])
.directive('awScrollDown', [ function() {
return function(scope, element, attrs) {
var element_to_scroll = attrs.awScrollDown, elem;
$(element).on('click', function() {
var height = document.getElementById(element_to_scroll).scrollHeight;
$(element).hide();
$('#' + element_to_scroll).animate({scrollTop:height}, 800);
});
elem = document.getElementById(element_to_scroll);
$('#' + element_to_scroll).on('scroll', function() {
if (elem.scrollTop > 0 && $(element).is(':visible')) {
$(element).hide();
}
else if (elem.scrollTop === 0 && !$(element).is(':visible')) {
$(element).fadeIn(2500);
}
});
if (elem.scrollTop > 0 && $(element).is(':visible')) {
$(element).hide();
}
};
}])
.directive('awScrollUp', [ function() {
return function(scope, element, attrs) {
var element_to_scroll = attrs.awScrollUp, elem;
$(element).on('click', function() {
$(element).hide();
$('#' + element_to_scroll).animate({scrollTop:0}, 'slow');
});
elem = document.getElementById(element_to_scroll);
$('#' + element_to_scroll).on('scroll', function() {
if (elem.scrollTop === 0 && $(element).is(':visible')) {
$(element).hide();
}
else if (elem.scrollTop > 0 && !$(element).is(':visible')) {
$(element).fadeIn(2500);
}
});
if (elem.scrollTop === 0) {
$(element).hide();
}
};
}]); }]);
/* /*

View File

@@ -5,8 +5,8 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h4>Job Options</h4> <h5>Options</h5>
<div class="job_options"> <div class="job_options job_well" id="job_options">
<table class="table table-condensed"> <table class="table table-condensed">
<tbody> <tbody>
<tr ng-show="job_template_url"> <tr ng-show="job_template_url">
@@ -52,29 +52,27 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<a id="job_options_scroll_down_indicator" href="" aw-scroll-down="job_options" class="scroll-down-indicator">more <i class="fa fa-chevron-circle-down"></i></a>
<a id="job_options_scroll_up_indicator" href="" aw-scroll-up="job_options" class="scroll-up-indicator">more <i class="fa fa-chevron-circle-up"></i></a>
</div> </div>
</div><!-- row --> </div><!-- row -->
<div class="row"> <div class="row">
<div class="col-md-6 job-detail-tables"> <div class="col-md-6 job-detail-tables">
<h4>Plays</h4> <h5>Plays</h5>
<div class="job_plays"> <div class="job_plays job_well">
<table class="table table-condensed job-detail-table"> <ul>
<thead> <li ng-repeat="play in plays">
<tr> <i class="fa icon-job-{{ play.status }}"></i> {{play.name }}
<th class="col-md-1">Status</th> <ul ng-show="play.children.length > 0">
<th>Name</th> <li ng-repeat="child in play.children">
</tr> <i class="fa icon-job-{{ child.status }}"></i> {{child.name }}
</thead> </li>
<tbody> </ul>
<tr ng-repeat="play in plays"> </li>
<td><i class="fa icon-job-{{ play.status }}"></i></td> </ul>
<td>{{ play.name }}</td>
<td>{{ play.state }}</td>
</tr>
</tbody>
</table>
</div> </div>
<h4>Tasks</h4> <h4>Tasks</h4>
@@ -90,7 +88,6 @@
<tr ng-repeat="task in tasks"> <tr ng-repeat="task in tasks">
<td><i class="fa icon-job-{{ task.status }}"></i></td> <td><i class="fa icon-job-{{ task.status }}"></i></td>
<td>{{ task.name }}</td> <td>{{ task.name }}</td>
<td>{{ task.state }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -101,22 +98,20 @@
<table class="table table-condensed job-detail-table"> <table class="table table-condensed job-detail-table">
<thead> <thead>
<tr> <tr>
<th class="col-md-1">Status</th>
<th>Name</th> <th>Name</th>
<th>OK</th> <th class="text-center">OK</th>
<th>Changed</th> <th class="text-center">Changed</th>
<th>Unreachable</th> <th class="text-center">Unreachable</th>
<th>Failed</th> <th class="text-center">Failed</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="host in hosts"> <tr ng-repeat="host in hosts">
<td><i class="fa icon-job-{{ task.status }}"></i></td>
<td>{{ host.name }}</td> <td>{{ host.name }}</td>
<td>{{ host.ok }}</td> <td class="text-center">{{ host.ok }}</td>
<td>{{ host.changed }}</td> <td class="text-center">{{ host.changed }}</td>
<td>{{ host.unreachable }}</td> <td class="text-center">{{ host.unreachable }}</td>
<td>{{ host.failed }}</td> <td class="text-center">{{ host.failed }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -127,17 +122,3 @@
</div> </div>
</div> </div>