+ STATUS
+
+
+
+
+ {{event.status || "No result found"}}
+
+
+
+ ID
+ {{event.id || "No result found"}}
+
+
+ CREATED
+ {{event.created || "No result found"}}
+
+
+ PLAY
+ {{event.play || "No result found"}}
+
+
+ TASK
+ {{event.task || "No result found"}}
+
+
+ MODULE
+ {{event.event_data.res.invocation.module_name || "No result found"}}
+
+
+
+
RESULTS
+
+
+ {{key}}
+ {{value}}
+
+
+
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-json.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-json.partial.html
new file mode 100644
index 0000000000..a574043dbd
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event-json.partial.html
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html
new file mode 100644
index 0000000000..db106deb1b
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event-modal.partial.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ HOST EVENT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html
new file mode 100644
index 0000000000..436c25262a
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event-stdout.partial.html
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html b/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html
new file mode 100644
index 0000000000..06171bd1c5
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event-timing.partial.html
@@ -0,0 +1 @@
+
timing
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/host-event.block.less b/awx/ui/client/src/job-detail/host-event/host-event.block.less
new file mode 100644
index 0000000000..04b25f7419
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event.block.less
@@ -0,0 +1,69 @@
+@import "awx/ui/client/src/shared/branding/colors.less";
+@import "awx/ui/client/src/shared/branding/colors.default.less";
+@import "awx/ui/client/src/shared/layouts/one-plus-two.less";
+
+.HostEvent .modal-footer{
+ border: 0;
+ margin-top: 0px;
+ padding-top: 5px;
+}
+.HostEvent-controls{
+ float: right;
+ button {
+ margin-left: 10px;
+ }
+}
+.HostEvent-status--ok{
+ color: @green;
+}
+.HostEvent-status--unreachable{
+ color: @unreachable;
+}
+.HostEvent-status--changed{
+ color: @changed;
+}
+.HostEvent-status--failed{
+ color: @default-err;
+}
+.HostEvent-status--skipped{
+ color: @skipped;
+}
+.HostEvent-title{
+ color: @default-interface-txt;
+ font-weight: 600;
+}
+.HostEvent .modal-body{
+ max-height: 500px;
+ overflow-y: auto;
+ padding: 20px;
+}
+.HostEvent-nav{
+ padding-top: 12px;
+ padding-bottom: 12px;
+}
+.HostEvent-field{
+ margin-bottom: 8px;
+}
+.HostEvent-field--label{
+ .OnePlusTwo-left--detailsLabel;
+ width: 80px;
+ margin-right: 20px;
+ font-size: 12px;
+}
+.HostEvent-field{
+ .OnePlusTwo-left--detailsRow;
+}
+.HostEvent-field--content{
+ .OnePlusTwo-left--detailsContent;
+}
+.HostEvent-details--left, .HostEvent-details--right{
+ vertical-align:top;
+ width:270px;
+ display: inline-block;
+
+}
+.HostEvent-details--right{
+ .HostEvent-field--label{
+ width: 170px;
+ }
+}
diff --git a/awx/ui/client/src/job-detail/host-event/host-event.controller.js b/awx/ui/client/src/job-detail/host-event/host-event.controller.js
new file mode 100644
index 0000000000..ac46279d0f
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event.controller.js
@@ -0,0 +1,71 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event',
+ function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){
+ // Avoid rendering objects in the details fieldset
+ // ng-if="processResults(value)" via host-event-details.partial.html
+ $scope.processResults = function(value){
+ if (typeof value == 'object'){return false}
+ else {return true}
+ };
+
+ var codeMirror = function(){
+ var el = $('#HostEvent-json')[0];
+ var editor = CodeMirror.fromTextArea(el, {
+ lineNumbers: true,
+ mode: {name: "javascript", json: true}
+ });
+ editor.getDoc().setValue(JSON.stringify($scope.json, null, 4));
+ };
+
+ $scope.getActiveHostIndex = function(){
+ var result = $scope.hostResults.filter(function( obj ) {
+ return obj.id == $scope.event.id;
+ });
+ return $scope.hostResults.indexOf(result[0])
+ };
+
+ $scope.showPrev = function(){
+ return $scope.getActiveHostIndex() != 0
+ };
+
+ $scope.showNext = function(){
+ return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1])
+ };
+
+ $scope.goNext = function(){
+ var index = $scope.getActiveHostIndex() + 1;
+ var id = $scope.hostResults[index].id;
+ $state.go('jobDetail.host-event.details', {eventId: id})
+ };
+
+ $scope.goPrev = function(){
+ var index = $scope.getActiveHostIndex() - 1;
+ var id = $scope.hostResults[index].id;
+ $state.go('jobDetail.host-event.details', {eventId: id})
+ };
+
+ var init = function(){
+ $scope.event = event.data.results[0];
+ $scope.event.created = moment($scope.event.created).format();
+ $scope.processEventStatus = JobDetailService.processEventStatus($scope.event);
+ $scope.hostResults = $stateParams.hostResults;
+ $scope.json = JobDetailService.processJson($scope.event);
+ if ($state.current.name == 'jobDetail.host-event.json'){
+ codeMirror();
+ }
+ try {
+ $scope.stdout = $scope.event.event_data.res.stdout
+ }
+ catch(err){
+ $scope.sdout = null;
+ }
+ $('#HostEvent').modal('show');
+ };
+ init();
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/host-event.route.js b/awx/ui/client/src/job-detail/host-event/host-event.route.js
new file mode 100644
index 0000000000..7d4f1cc011
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/host-event.route.js
@@ -0,0 +1,86 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ import {templateUrl} from '../../shared/template-url/template-url.factory';
+
+var hostEventModal = {
+ name: 'jobDetail.host-event',
+ url: '/host-event/:eventId',
+ controller: 'HostEventController',
+ params:{
+ hostResults: {
+ value: null,
+ squash: false,
+ }
+ },
+ templateUrl: templateUrl('job-detail/host-event/host-event-modal'),
+ resolve: {
+ features: ['FeaturesService', function(FeaturesService){
+ return FeaturesService.get();
+ }],
+ event: ['JobDetailService','$stateParams', function(JobDetailService, $stateParams) {
+ return JobDetailService.getRelatedJobEvents($stateParams.id, {
+ id: $stateParams.eventId
+ }).success(function(res){ return res.results[0]})
+ }]
+ },
+ onExit: function($state){
+ // close the modal
+ // using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
+ $('#HostEvent').modal('hide');
+ // hacky way to handle user browsing away via URL bar
+ $('.modal-backdrop').remove();
+ $('body').removeClass('modal-open');
+ }
+ }
+
+ var hostEventDetails = {
+ name: 'jobDetail.host-event.details',
+ url: '/details',
+ controller: 'HostEventController',
+ templateUrl: templateUrl('job-detail/host-event/host-event-details'),
+ resolve: {
+ features: ['FeaturesService', function(FeaturesService){
+ return FeaturesService.get();
+ }]
+ }
+ }
+
+ var hostEventJson = {
+ name: 'jobDetail.host-event.json',
+ url: '/json',
+ controller: 'HostEventController',
+ templateUrl: templateUrl('job-detail/host-event/host-event-json'),
+ resolve: {
+ features: ['FeaturesService', function(FeaturesService){
+ return FeaturesService.get();
+ }]
+ }
+ };
+ var hostEventTiming = {
+ name: 'jobDetail.host-event.timing',
+ url: '/timing',
+ controller: 'HostEventController',
+ templateUrl: templateUrl('job-detail/host-event/host-event-timing'),
+ resolve: {
+ features: ['FeaturesService', function(FeaturesService){
+ return FeaturesService.get();
+ }]
+ }
+ };
+ var hostEventStdout = {
+ name: 'jobDetail.host-event.stdout',
+ url: '/stdout',
+ controller: 'HostEventController',
+ templateUrl: templateUrl('job-detail/host-event/host-event-stdout'),
+ resolve: {
+ features: ['FeaturesService', function(FeaturesService){
+ return FeaturesService.get();
+ }]
+ }
+ };
+
+ export {hostEventDetails, hostEventJson, hostEventTiming, hostEventStdout, hostEventModal}
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-event/main.js b/awx/ui/client/src/job-detail/host-event/main.js
new file mode 100644
index 0000000000..c2b82530a1
--- /dev/null
+++ b/awx/ui/client/src/job-detail/host-event/main.js
@@ -0,0 +1,21 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ import {hostEventModal, hostEventDetails, hostEventTiming,
+ hostEventJson, hostEventStdout} from './host-event.route';
+ import controller from './host-event.controller';
+
+ export default
+ angular.module('jobDetail.hostEvent', [])
+ .controller('HostEventController', controller)
+
+ .run(['$stateExtender', function($stateExtender){
+ $stateExtender.addState(hostEventModal);
+ $stateExtender.addState(hostEventDetails);
+ $stateExtender.addState(hostEventTiming);
+ $stateExtender.addState(hostEventJson);
+ $stateExtender.addState(hostEventStdout);
+ }]);
\ No newline at end of file
diff --git a/awx/ui/client/src/job-detail/host-events/host-events.block.less b/awx/ui/client/src/job-detail/host-events/host-events.block.less
index 17d318dc89..1a92e8933c 100644
--- a/awx/ui/client/src/job-detail/host-events/host-events.block.less
+++ b/awx/ui/client/src/job-detail/host-events/host-events.block.less
@@ -16,7 +16,7 @@
color: @changed;
}
.HostEvents-status--failed{
- color: @warning;
+ color: @default-err;
}
.HostEvents-status--skipped{
color: @skipped;
@@ -47,6 +47,7 @@
padding-bottom: 15px;
}
.HostEvents-title{
+ text-transform: uppercase;
color: @default-interface-txt;
font-weight: 600;
}
diff --git a/awx/ui/client/src/job-detail/host-events/host-events.controller.js b/awx/ui/client/src/job-detail/host-events/host-events.controller.js
index a3a1c8faaf..c97da5eb62 100644
--- a/awx/ui/client/src/job-detail/host-events/host-events.controller.js
+++ b/awx/ui/client/src/job-detail/host-events/host-events.controller.js
@@ -6,13 +6,14 @@
export default
['$stateParams', '$scope', '$rootScope', '$state', 'Wait',
- 'JobDetailService', 'CreateSelect2',
+ 'JobDetailService', 'CreateSelect2', 'hosts',
function($stateParams, $scope, $rootScope, $state, Wait,
- JobDetailService, CreateSelect2){
+ JobDetailService, CreateSelect2, hosts){
// pagination not implemented yet, but it'll depend on this
$scope.page_size = $stateParams.page_size;
+ $scope.processEventStatus = JobDetailService.processEventStatus;
$scope.activeFilter = $stateParams.filter || null;
$scope.search = function(){
@@ -39,6 +40,7 @@
var filter = function(filter){
Wait('start');
+
if (filter == 'all'){
return JobDetailService.getRelatedJobEvents($stateParams.id, {
host_name: $stateParams.hostName,
@@ -104,47 +106,17 @@
filter($('.HostEvents-select').val());
});
- $scope.processStatus = function(event, $index){
- // the stack for which status to display is
- // unreachable > failed > changed > ok
- // uses the API's runner events and convenience properties .failed .changed to determine status.
- // see: job_event_callback.py
- if (event.event == 'runner_on_unreachable'){
- $scope.results[$index].status = 'Unreachable';
- return 'HostEvents-status--unreachable'
- }
- // equiv to 'runner_on_error' && 'runner on failed'
- if (event.failed){
- $scope.results[$index].status = 'Failed';
- return 'HostEvents-status--failed'
- }
- // catch the changed case before ok, because both can be true
- if (event.changed){
- $scope.results[$index].status = 'Changed';
- return 'HostEvents-status--changed'
- }
- if (event.event == 'runner_on_ok'){
- $scope.results[$index].status = 'OK';
- return 'HostEvents-status--ok'
- }
- if (event.event == 'runner_on_skipped'){
- $scope.results[$index].status = 'Skipped';
- return 'HostEvents-status--skipped'
- }
- else{
- // study a case where none of these apply
- }
- };
-
-
var init = function(){
+ $scope.hostName = $stateParams.hostName;
// create filter dropdown
+ console.log($stateParams)
CreateSelect2({
element: '.HostEvents-select',
multiple: false
});
// process the filter if one was passed
if ($stateParams.filter){
+ Wait('start');
filter($stateParams.filter).success(function(res){
$scope.results = res.results;
Wait('stop');
@@ -152,25 +124,11 @@
});;
}
else{
- Wait('start');
- JobDetailService.getRelatedJobEvents($stateParams.id, {
- host_name: $stateParams.hostName,
- page_size: $stateParams.page_size})
- .success(function(res){
- $scope.pagination = res;
- $scope.results = res.results;
- Wait('stop');
- $('#HostEvents').modal('show');
-
- });
+ $scope.results = hosts.data.results;
+ $('#HostEvents').modal('show');
}
};
- $scope.goBack = function(){
- // go back to the job details state
- // we're leaning on $stateProvider's onExit to close the modal
- $state.go('jobDetail');
- };
init();
diff --git a/awx/ui/client/src/job-detail/host-events/host-events.partial.html b/awx/ui/client/src/job-detail/host-events/host-events.partial.html
index ff2d21714a..9d0ccca40f 100644
--- a/awx/ui/client/src/job-detail/host-events/host-events.partial.html
+++ b/awx/ui/client/src/job-detail/host-events/host-events.partial.html
@@ -3,9 +3,9 @@