Job detail page refactoration

Handling play and task parallel arrival seems to be working now. Removed 'search' and 'status' labels from search dialogs. Job events viewer now displays JSON objects as nested tables. Re-ordered host event viewer fields, adding host name, and fixing links so that only the status column is clickable.
This commit is contained in:
Chris Houseknecht 2014-07-15 13:46:01 -04:00
parent a35cd2d85e
commit 78cec19e78
8 changed files with 89 additions and 95 deletions

View File

@ -828,7 +828,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
EventViewer({
scope: scope,
url: scope.job.related.job_events + '?id=' + id,
title: 'Host Result'
title: 'Host Event'
});
};

View File

@ -37,6 +37,10 @@ angular.module('EventsViewerFormDefinition', [])
label: 'Task',
section: 'Event'
},
item: {
label: 'Item',
section: 'Event'
},
module_name: {
label: 'Module',
section: 'Event'
@ -45,10 +49,6 @@ angular.module('EventsViewerFormDefinition', [])
label: 'Arguments',
section: 'Event'
},
item: {
label: 'Item',
section: 'Event'
},
rc: {
label: 'Return Code',
section: 'Results'

View File

@ -195,6 +195,28 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo
section = params.section,
html = '', e;
function parseObject(obj) {
// parse nested JSON objects. a mini version of parseJSON without references to the event form object.
var key, html = '';
for (key in obj) {
if (typeof obj[key] === "boolean" || typeof obj[key] === "number" || typeof obj[key] === "string") {
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"value\">" + obj[key] + "</td></tr>";
}
else if (typeof obj[key] === "object" && Array.isArray(obj[key])) {
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"value\">";
obj[key].forEach(function(row) {
html += "[" + row + "],";
});
html = html.replace(/,$/,'');
html += "</td></tr>\n";
}
else if (typeof obj[key] === "object") {
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"nested-table\"><table>\n<tbody>\n" + parseObject(obj[key]) + "</tbody>\n</table>\n</td></tr>\n";
}
}
return html;
}
function parseJSON(obj) {
var html = '', key, keys, found = false;
if (typeof obj === "object") {
@ -252,9 +274,8 @@ angular.module('EventViewerHelper', ['ModalDialog', 'Utilities', 'EventsViewerFo
}
else if (typeof obj[key] === "object") {
found = true;
html += "<tr><td class=\"key\">" + label + ":</td><td class=\"nested-table\">\n" + parseJSON(obj[key]) + "</td></tr>\n";
html += "<tr><td class=\"key\">" + label + ":</td><td class=\"nested-table\"><table>\n<tbody>\n" + parseObject(obj[key]) + "</tbody>\n</table>\n</td></tr>\n";
}
//}
});
html += "</tbody>\n";
html += "</table>\n";

View File

@ -114,11 +114,11 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities', 'EventView
buildRow = function(res) {
var html = '';
html += "<tr ng-click=\"showDetails(" + res.id + ")\" class=\"cursor-pointer\" aw-tool-tip=\"Click to view details\" data-placement=\"top\">\n";
html += "<td class=\"col-md-3\"><i class=\"fa icon-job-" + res.status + "\"></i> <a href=\"\">" + res.status_text + "</a></td>\n";
html += "<td class=\"col-md-3\"><a href=\"\">" + res.play + "</a></td>\n";
html += "<td class=\"col-md-3\"><a href=\"\">" + res.task + "</a></td>\n";
html += "<td class=\"col-md-3\"><a href=\"\">" + res.msg + "</a></td>";
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 += "</tr>";
return html;
};

View File

@ -295,7 +295,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
status_tip: "Event ID: " + event.id + "<br />Status: " + status_text,
created: event.created,
modified: event.modified,
hostCount: (scope.activePlay && scope.jobData.plays[scope.activePlay]) ? scope.jobData.plays[scope.activePlay].hostCount : 0,
hostCount: (scope.jobData.plays[event.parent]) ? scope.jobData.plays[event.parent].hostCount : 0,
reportedHosts: 0,
successfulCount: 0,
failedCount: 0,
@ -451,8 +451,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
}])
// Each time a runner event is received update host summary totals and the parent task
.factory('UpdateHostStatus', ['UpdateTaskStatus', 'AddHostResult',
function(UpdateTaskStatus, AddHostResult) {
.factory('UpdateHostStatus', ['UpdateTaskStatus', 'AddHostResult', function(UpdateTaskStatus, AddHostResult) {
return function(params) {
var scope = params.scope,
status = params.status, // successful, changed, unreachable, failed, skipped
@ -516,7 +515,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
}])
// Add a new host result
.factory('AddHostResult', ['SetTaskStyles', 'SetActiveTask', function(SetTaskStyles, SetActiveTask) {
.factory('AddHostResult', ['SetTaskStyles', 'SetActivePlay', 'SetActiveTask', function(SetTaskStyles, SetActivePlay, SetActiveTask) {
return function(params) {
var scope = params.scope,
task_id = params.task_id,
@ -528,7 +527,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
msg = params.message,
item = params.item,
status_text = '',
task;
task, play, play_id;
switch(status) {
case "successful":
@ -551,11 +550,16 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
item = JSON.stringify(item);
}
if (scope.jobData.plays[scope.activePlay].tasks[task_id].hostResults[event_id]) {
// host already exists. do nothing.
for (play in scope.jobData.plays) {
for (task in scope.jobData.plays[play].tasks) {
if (parseInt(task,10) === parseInt(task_id,10)) {
play_id = parseInt(play,10);
}
}
}
else {
scope.jobData.plays[scope.activePlay].tasks[task_id].hostResults[event_id] = {
if (play_id) {
scope.jobData.plays[play_id].tasks[task_id].hostResults[event_id] = {
id: event_id,
status: status,
status_text: status_text,
@ -568,15 +572,15 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
};
// increment the unreachable count on the play
if (status === 'unreachable' && scope.jobData.plays[scope.activePlay]) {
scope.jobData.plays[scope.activePlay].unreachableCount++;
if (status === 'unreachable') {
scope.jobData.plays[play_id].unreachableCount++;
}
// update the task status bar
task = scope.jobData.plays[scope.activePlay].tasks[task_id];
task = scope.jobData.plays[play_id].tasks[task_id];
if (task_id === scope.jobData.plays[scope.activePlay].firstTask) {
scope.jobData.plays[scope.activePlay].hostCount++;
if (task_id === scope.jobData.plays[play_id].firstTask) {
scope.jobData.plays[play_id].hostCount++;
task.hostCount++;
}
@ -591,6 +595,8 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
task: task
});
SetActivePlay({ scope: scope });
SetActiveTask({ scope: scope });
}
};
@ -609,6 +615,14 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
task.successfulPct = (task.hostCount > 0) ? Math.ceil((100 * (task.successfulCount / task.hostCount))) : 0;
task.unreachablePct = (task.hostCount > 0) ? Math.ceil((100 * (task.unreachableCount / task.hostCount))) : 0;
// cap % at 100
task.missingPct = (task.missingPct > 100) ? 100 : task.missingPct;
task.failedPct = (task.failedPct > 100) ? 100 : task.failedPct;
task.changedPct = (task.changedPct > 100) ? 100 : task.changedPct;
task.skippedPct = (task.skippedPct > 100) ? 100 : task.skippedPct;
task.successfulPct = ( task.successfulPct > 100) ? 100 : task.successfulPct;
task.unreachablePct = (task.unreachablePct > 100) ? 100 : task.unreachablePct;
diff = (task.failedPct + task.changedPct + task.skippedPct + task.successfulPct + task.unreachablePct + task.missingPct) - 100;
if (diff > 0) {
if (task.failedPct > diff) {

View File

@ -30,4 +30,31 @@ table.eventviewer-status {
.value i {
font-size: 12px;
}
}
.nested-table {
border: none;
padding: 0;
table {
border-top: none;
border-bottom: none;
width: auto;
td {
vertical-align: top;
padding: 0 3px 3px 3px;
}
tr {
border-top: none;
border-bottom: 1px solid #ddd;
}
/*tr td:first-of-type {
width: auto;
}*/
tr:last-of-type {
border-bottom: none;
}
.key {
font-weight: 400;
}
}
}

View File

@ -506,66 +506,6 @@
font-weight: bold;
}
#event-viewer-dialog {
padding-bottom: 5px;
padding-top: 10px;
padding-left: 5px;
padding-right: 5px;
overflow: hidden;
.results {
width: 100%;
height: 100%;
overflow: auto;
}
.spacer {
height: 60px;
}
table {
border-collapse: collapse;
width: 100%;
border-bottom: 1px solid @well-border;
}
tr {
border-top: 1px solid @well-border;
/*border-bottom: 1px solid @well-border;*/
}
tr:first-child {
border-top: none;
}
tr td:first-of-type {
width: 20%;
}
.key {
vertical-align: top;
padding: 3px;
font-weight: 600;
}
.value {
padding: 3px;
i {
font-size: 12px;
}
}
.nested-table {
border: none;
padding: 0;
table {
border-top: none;
border-bottom: none;
width: auto;
tr {
border-top: none;
}
tr td:first-of-type {
width: auto;
}
.key {
font-weight: 400;
}
}
}
}
.footer-row {
height: 20px;
}

View File

@ -81,7 +81,6 @@
<div class="col-lg-11 col-md-10 col-sm-10 col-xs-11" style="text-align:right;">
<div id="play-search-form" class="search-form form-inline">
<div class="form-group">
<label>Search</label>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_play_name" ng-model="search_play_name"
placeholder="Play Name" ng-keypress="searchPlaysKeyPress($event)" >
@ -92,7 +91,6 @@
</div>
</div>
<div class="form-group">
<label>Status</label>
<div class="btn-group" aw-toggle-button data-after-toggle="filterPlayStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
@ -141,7 +139,6 @@
<div class="col-lg-11 col-md-10 col-sm-10" style="text-align:right;">
<div id="task-search-form" class="search-form form-inline">
<div class="form-group">
<label>Search</label>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_task_name" ng-model="search_task_name"
placeholder="Task Name" ng-keypress="searchTasksKeyPress($event)" >
@ -152,7 +149,6 @@
</div>
</div>
<div class="form-group">
<label>Status</label>
<div class="btn-group" aw-toggle-button data-after-toggle="filterTaskStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
@ -204,7 +200,6 @@
<div class="col-lg-10 col-md-10 col-sm-10" style="text-align:right;">
<div id="host-search-form" class="search-form form-inline">
<div class="form-group">
<label>Search</label>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_host_name" ng-model="search_host_name"
placeholder="Host Name" ng-keypress="searchHostsKeyPress($event)" >
@ -215,7 +210,6 @@
</div>
</div>
<div class="form-group">
<label>Status</label>
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
@ -277,7 +271,6 @@
<div class="col-lg-10 col-md-10 col-sm-10" style="text-align:right;">
<div id="task-search-form" class="search-form form-inline">
<div class="form-group">
<label>Search</label>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_host_summary_name" ng-model="search_host_summary_name"
placeholder="Host Name" ng-keypress="searchHostSummaryKeyPress($event)" >
@ -288,7 +281,6 @@
</div>
</div>
<div class="form-group">
<label>Status</label>
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
@ -385,9 +377,9 @@
<table id="fixed-table-header" class="table">
<thead>
<tr><th class="col-md-3">Status</th>
<th class="col-md-3">Host</th>
<th class="col-md-3">Play</th>
<th class="col-md-3">Task</th>
<th class="col-md-3">Result</th>
</tr>
</thead>
</table>