From 78cec19e789f48f832c8a46cd9c829ab82f1e672 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Tue, 15 Jul 2014 13:46:01 -0400 Subject: [PATCH] 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. --- awx/ui/static/js/controllers/JobDetail.js | 2 +- awx/ui/static/js/forms/EventsViewer.js | 8 +-- awx/ui/static/js/helpers/EventViewer.js | 25 +++++++- awx/ui/static/js/helpers/HostEventsViewer.js | 10 ++-- awx/ui/static/js/helpers/JobDetail.js | 42 +++++++++----- awx/ui/static/less/event-viewer.less | 27 +++++++++ awx/ui/static/less/job-details.less | 60 -------------------- awx/ui/static/partials/job_detail.html | 10 +--- 8 files changed, 89 insertions(+), 95 deletions(-) diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js index a5d0b70a90..b6e7dc4531 100644 --- a/awx/ui/static/js/controllers/JobDetail.js +++ b/awx/ui/static/js/controllers/JobDetail.js @@ -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' }); }; diff --git a/awx/ui/static/js/forms/EventsViewer.js b/awx/ui/static/js/forms/EventsViewer.js index 10292f6c4c..c97eaf2362 100644 --- a/awx/ui/static/js/forms/EventsViewer.js +++ b/awx/ui/static/js/forms/EventsViewer.js @@ -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' diff --git a/awx/ui/static/js/helpers/EventViewer.js b/awx/ui/static/js/helpers/EventViewer.js index 8d4f82f3d6..6afa3804d6 100644 --- a/awx/ui/static/js/helpers/EventViewer.js +++ b/awx/ui/static/js/helpers/EventViewer.js @@ -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 += "" + key + ":" + obj[key] + ""; + } + else if (typeof obj[key] === "object" && Array.isArray(obj[key])) { + html += "" + key + ":"; + obj[key].forEach(function(row) { + html += "[" + row + "],"; + }); + html = html.replace(/,$/,''); + html += "\n"; + } + else if (typeof obj[key] === "object") { + html += "" + key + ":\n\n" + parseObject(obj[key]) + "\n
\n\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 += "" + label + ":\n" + parseJSON(obj[key]) + "\n"; + html += "" + label + ":\n\n" + parseObject(obj[key]) + "\n
\n\n"; } - //} }); html += "\n"; html += "\n"; diff --git a/awx/ui/static/js/helpers/HostEventsViewer.js b/awx/ui/static/js/helpers/HostEventsViewer.js index f49f244653..2294f7ab5d 100644 --- a/awx/ui/static/js/helpers/HostEventsViewer.js +++ b/awx/ui/static/js/helpers/HostEventsViewer.js @@ -114,11 +114,11 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities', 'EventView buildRow = function(res) { var html = ''; - html += "\n"; - html += " " + res.status_text + "\n"; - html += "" + res.play + "\n"; - html += "" + res.task + "\n"; - html += "" + res.msg + ""; + html += "\n"; + html += " " + res.status_text + "\n"; + html += "" + res.host_name + "\n"; + html += "" + res.play + "\n"; + html += "" + res.task + "\n"; html += ""; return html; }; diff --git a/awx/ui/static/js/helpers/JobDetail.js b/awx/ui/static/js/helpers/JobDetail.js index 453c355a14..32ee13ac0f 100644 --- a/awx/ui/static/js/helpers/JobDetail.js +++ b/awx/ui/static/js/helpers/JobDetail.js @@ -295,7 +295,7 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge status_tip: "Event ID: " + event.id + "
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) { diff --git a/awx/ui/static/less/event-viewer.less b/awx/ui/static/less/event-viewer.less index ef980ce2f5..2a4fc4d0ff 100644 --- a/awx/ui/static/less/event-viewer.less +++ b/awx/ui/static/less/event-viewer.less @@ -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; + } + } } \ No newline at end of file diff --git a/awx/ui/static/less/job-details.less b/awx/ui/static/less/job-details.less index 422602924a..c8ceb5e05e 100644 --- a/awx/ui/static/less/job-details.less +++ b/awx/ui/static/less/job-details.less @@ -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; } diff --git a/awx/ui/static/partials/job_detail.html b/awx/ui/static/partials/job_detail.html index 05cd69c0b4..7825c3046a 100644 --- a/awx/ui/static/partials/job_detail.html +++ b/awx/ui/static/partials/job_detail.html @@ -81,7 +81,6 @@
-
@@ -92,7 +91,6 @@
-
@@ -141,7 +139,6 @@
-
@@ -152,7 +149,6 @@
-
@@ -204,7 +200,6 @@
-
@@ -215,7 +210,6 @@
-
@@ -277,7 +271,6 @@
-
@@ -288,7 +281,6 @@
-
@@ -385,9 +377,9 @@ + -
StatusHost Play TaskResult