diff --git a/awx/ui/static/js/controllers/JobDetail.js b/awx/ui/static/js/controllers/JobDetail.js
index 8921e3ffc0..749c451b6d 100644
--- a/awx/ui/static/js/controllers/JobDetail.js
+++ b/awx/ui/static/js/controllers/JobDetail.js
@@ -1009,7 +1009,7 @@ function JobDetailController ($location, $rootScope, $scope, $compile, $routePar
scope: scope,
id: id,
name: name,
- url: scope.job.related.job_events + '?event__icontains=runner'
+ url: scope.job.related.job_events
});
};
diff --git a/awx/ui/static/js/helpers/HostEventsViewer.js b/awx/ui/static/js/helpers/HostEventsViewer.js
index cb734c22dc..4c617c7481 100644
--- a/awx/ui/static/js/helpers/HostEventsViewer.js
+++ b/awx/ui/static/js/helpers/HostEventsViewer.js
@@ -15,13 +15,15 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities'])
function($log, $compile, CreateDialog, Wait, GetBasePath, Empty, GetEvents) {
return function(params) {
var parent_scope = params.scope,
+ scope = parent_scope.$new(true),
url = params.url,
- host_id = params.id,
- host_name = params.name,
title = params.title, //optional
- scope = parent_scope.$new(true);
+ fixHeight, buildTable;
- $log.debug('host_id: ' + host_id + ' host_name: ' + host_name);
+ scope.host_events_search_name = params.name;
+ scope.host_events_search_status = 'all';
+
+ scope.eventsSearchActive = (scope.host_events_search_name) ? true : false;
if (scope.removeModalReady) {
scope.removeModalReady();
@@ -37,29 +39,52 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities'])
scope.removeEventReady = scope.$on('EventsReady', function(e, data) {
var elem, html;
- //scope.host_events = data.results;
- //$log.debug(scope.host_events);
+ html = buildTable(data);
+ $('#host-events').html(html);
+ elem = angular.element(document.getElementById('host-events-modal-dialog'));
+ $compile(elem)(scope);
- scope.host_events = data.results;
- scope.host_events_search_name = host_name;
- scope.host_events_search_status = 'all';
- scope.host_events = [];
- html = "
\n";
- html += "\n";
- html += "| Status | " +
- "Play | " +
- "Task | " +
- "Result |
\n";
- html += "\n";
+ CreateDialog({
+ scope: scope,
+ width: 675,
+ height: 600,
+ minWidth: 450,
+ callback: 'ModalReady',
+ id: 'host-events-modal-dialog',
+ onResizeStop: fixHeight,
+ title: ( (title) ? title : 'Host Events' ),
+ onOpen: function() {
+ fixHeight();
+ }
+ });
+ });
+
+ if (scope.removeRefreshHTML) {
+ scope.removeRefreshHTML();
+ }
+ scope.removeRefreshHTML = scope.$on('RefreshHTML', function(e, data) {
+ var elem, html = buildTable(data);
+ $('#host-events').html(html);
+ elem = angular.element(document.getElementById('host-events'));
+ $compile(elem)(scope);
+ Wait('stop');
+ });
+
+ buildTable = function(data) {
+ var html = "\n";
html += "\n";
data.results.forEach(function(result) {
var msg = '',
status = 'ok',
status_text = 'OK';
- if (result.event_data.res) {
+
+ if (result.event_data.res && result.event_data.res.msg) {
msg = result.event_data.res.msg;
}
- if (result.event === "runner_on_no_hoss") {
+ if (!result.task && result.event_data.res.ansible_facts) {
+ result.task = "Gathering Facts";
+ }
+ if (result.event === "runner_on_no_hosts") {
msg = "No hosts remaining";
}
if (result.event === 'runner_on_unreachable') {
@@ -75,54 +100,86 @@ angular.module('HostEventsViewerHelper', ['ModalDialog', 'Utilities'])
status_text = 'Changed';
}
html += "\n";
- html += "| " + status_text + " | \n";
- html += "" + result.play + " | \n";
- html += "" + result.task + " | \n";
- html += "" + msg + " | ";
- html += "
"
+ html += " " + status_text + " | \n";
+ html += "" + result.play + " | \n";
+ html += "" + result.task + " | \n";
+ html += "" + msg + " | ";
+ html += "";
});
html += "\n";
html += "
\n";
- $('#host-events').html(html);
+ return html;
+ };
- elem = angular.element(document.getElementById('host-events-modal-dialog'));
- $compile(elem)(scope);
-
- CreateDialog({
- scope: scope,
- width: 675,
- height: 600,
- minWidth: 450,
- callback: 'ModalReady',
- id: 'host-events-modal-dialog',
- // onResizeStop: resizeText,
- title: ( (title) ? title : 'Host Events' )
- //onOpen: function() {
- //}
- });
- });
+ fixHeight = function() {
+ var available_height = $('#host-events-modal-dialog').height() - $('#host-events-modal-dialog #search-form').height() - $('#host-events-modal-dialog #fixed-table-header').height();
+ $('#host-events').height(available_height);
+ $log.debug('set height to: ' + available_height);
+ };
GetEvents({
url: url,
- scope: scope
+ scope: scope,
+ callback: 'EventsReady'
});
scope.modalOK = function() {
$('#host-events-modal-dialog').dialog('close');
scope.$destroy();
};
+
+ scope.searchEvents = function() {
+ scope.eventsSearchActive = (scope.host_events_search_name) ? true : false;
+ GetEvents({
+ scope: scope,
+ url: url,
+ callback: 'RefreshHTML'
+ });
+ };
+
+ scope.searchEventKeyPress = function(e) {
+ if (e.keyCode === 13) {
+ scope.searchEvents();
+ }
+ };
+
};
}])
.factory('GetEvents', ['Wait', 'Rest', 'ProcessErrors', function(Wait, Rest, ProcessErrors) {
return function(params) {
var url = params.url,
- scope = params.scope;
+ scope = params.scope,
+ callback = params.callback;
+
+ if (scope.host_events_search_name) {
+ url += '?host_name=' + scope.host_events_search_name;
+ }
+ else {
+ url += '?host_name__isnull=false';
+ }
+
+ if (scope.host_events_search_status === 'changed') {
+ url += '&event__icontains=runner&changed=true';
+ }
+ else if (scope.host_events_search_status === 'failed') {
+ url += '&event__icontains=runner&failed=true';
+ }
+ else if (scope.host_events_search_status === 'ok') {
+ url += '&event=runner_on_ok&changed=false';
+ }
+ else if (scope.host_events_search_status === 'unreachable') {
+ url += '&event=runner_on_unreachable';
+ }
+ else if (!scope.host_events_search_status) {
+ url += '&event__icontains=runner¬__event=runner_on_skipped';
+ }
+
Wait('start');
Rest.setUrl(url);
Rest.get()
.success(function(data) {
- scope.$emit('EventsReady', data);
+ scope.$emit(callback, data);
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
diff --git a/awx/ui/static/js/lists/HostEvents.js b/awx/ui/static/js/lists/HostEvents.js
deleted file mode 100644
index 7e48630588..0000000000
--- a/awx/ui/static/js/lists/HostEvents.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/*********************************************
- * Copyright (c) 2014 AnsibleWorks, Inc.
- *
- * HostEvents.js
- * Host summary event viewer dialog.
- *
- */
-
-'use strict';
-
-angular.module('HostEventsListDefinition', [])
- .value('HostEventList', {
-
- name: 'host_events',
- iterator: 'host_event',
- editTitle: 'Host Events',
- index: false,
- hover: true,
-
- fields: {
- status: {
- label: 'Status',
- columnClass: 'col-md-2',
-
- },
- play: {
- label: 'Play',
- columnClass: 'col-md-3',
- key: true,
- nosort: true,
- searchable: false,
- noLink: true
- },
- status: {
- label: 'Status',
- showValue: false,
- columnClass: 'col-sm-1 col-xs-2 text-center',
- searchField: 'failed',
- searchType: 'boolean',
- searchOptions: [{
- name: 'success',
- value: 0
- }, {
- name: 'error',
- value: 1
- }],
- nosort: true,
- searchable: false,
- ngClick: 'viewJobEvent(jobevent.id)',
- awToolTip: '{{ jobevent.statusBadgeToolTip }}',
- dataPlacement: 'top',
- badgeIcon: 'fa icon-job-{{ jobevent.status }}',
- badgePlacement: 'left',
- badgeToolTip: '{{ jobevent.statusBadgeToolTip }}',
- badgeTipPlacement: 'top',
- badgeNgClick: 'viewJobEvent(jobevent.id)'
- },
- event_display: {
- label: 'Event',
- hasChildren: true,
- ngClick: 'toggleChildren(jobevent.id, jobevent.related.children)',
- nosort: true,
- searchable: false,
- ngClass: '{{ jobevent.class }}',
- appendHTML: 'jobevent.event_detail'
- },
- host: {
- label: 'Host',
- ngBind: 'jobevent.summary_fields.host.name',
- ngHref: '{{ jobevent.hostLink }}',
- searchField: 'hosts__name',
- nosort: true,
- searchOnly: false,
- id: 'job-event-host-header',
- 'class': 'break',
- columnClass: 'col-lg-2 hidden-sm hidden-xs'
- }
- },
-
- actions: { },
-
- });
\ 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 37759861a8..e3cd01ffb0 100644
--- a/awx/ui/static/less/job-details.less
+++ b/awx/ui/static/less/job-details.less
@@ -15,17 +15,22 @@
#host-events-modal-dialog {
+ overflow: hidden;
+ i {
+ font-size: 12px;
+ vertical-align: middle;
+ }
#search-form {
margin-left: 7px;
}
#host-events-search-name {
width: 200px;
+ padding-right: 15px;
}
#search-form-input-icons {
position: absolute;
- right: 3px;
top: 5px;
- z-index: 100;
+ left: 235px;
a {
color: #a9a9a9;
}
@@ -36,10 +41,38 @@
#status-field {
margin-left: 15px;
}
-
- table {
+ #host-events-table {
margin-top: 15px;
}
+ #host-events {
+ height: 200px;
+ overflow: scroll;
+ tr:first-of-type {
+ border-top-color: @white;
+ td {
+ border-top-color: @white;
+ }
+ }
+ }
+ #fixed-table-header {
+ margin-bottom: 0;
+ }
+}
+
+@media (max-width: 768px) {
+ #host-events-modal-dialog {
+ #search-form-input-icons {
+ position: absolute;
+ top: 30px;
+ left: 185px;
+ }
+ #status-field {
+ margin-left: 0;
+ }
+ .form-group {
+ margin-bottom: 15px;
+ }
+ }
}
#jobs-detail {
diff --git a/awx/ui/static/lib/angular-scheduler/package.json b/awx/ui/static/lib/angular-scheduler/package.json
new file mode 100644
index 0000000000..ed29e7c7f2
--- /dev/null
+++ b/awx/ui/static/lib/angular-scheduler/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-scheduler",
+ "version": "0.0.14",
+ "devDependencies": {
+ "grunt": "~0.4.2",
+ "grunt-contrib-jshint": "~0.6.3",
+ "grunt-contrib-uglify": "~0.2.2",
+ "grunt-contrib-less": "~0.9.0",
+ "karma-chrome-launcher": "~0.1.2",
+ "karma-script-launcher": "~0.1.0",
+ "karma-firefox-launcher": "~0.1.3",
+ "karma-html2js-preprocessor": "~0.1.0",
+ "requirejs": "~2.1.11",
+ "karma-requirejs": "~0.2.1",
+ "karma-coffee-preprocessor": "~0.1.3",
+ "karma-phantomjs-launcher": "~0.1.2",
+ "karma": "~0.10.9",
+ "karma-jasmine": "~0.2.1"
+ }
+}
diff --git a/awx/ui/static/lib/socket.io-client/package.json b/awx/ui/static/lib/socket.io-client/package.json
new file mode 100644
index 0000000000..2c8a8991e5
--- /dev/null
+++ b/awx/ui/static/lib/socket.io-client/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "socket.io-client"
+ , "description": "Socket.IO client for the browser and node.js"
+ , "version": "0.9.16"
+ , "main" : "./lib/io.js"
+ , "browserify": "./dist/socket.io.js"
+ , "homepage": "http://socket.io"
+ , "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"]
+ , "author": "Guillermo Rauch "
+ , "contributors": [
+ { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
+ , { "name": "Arnout Kazemier", "email": "info@3rd-eden.com" }
+ , { "name": "Vladimir Dronnikov", "email": "dronnikov@gmail.com" }
+ , { "name": "Einar Otto Stangvik", "email": "einaros@gmail.com" }
+ ]
+ , "repository": {
+ "type": "git"
+ , "url": "https://github.com/LearnBoost/socket.io-client.git"
+ }
+ , "dependencies": {
+ "uglify-js": "1.2.5"
+ , "ws": "0.4.x"
+ , "xmlhttprequest": "1.4.2"
+ , "active-x-obfuscator": "0.0.1"
+ }
+ , "devDependencies": {
+ "expresso": "*"
+ , "express": "2.5.x"
+ , "jade": "*"
+ , "stylus": "*"
+ , "socket.io": "0.9.16"
+ , "socket.io-client": "0.9.16"
+ , "should": "*"
+ }
+ , "engines": { "node": ">= 0.4.0" }
+}
diff --git a/awx/ui/static/partials/job_detail.html b/awx/ui/static/partials/job_detail.html
index 00a47bc384..2ba40d3578 100644
--- a/awx/ui/static/partials/job_detail.html
+++ b/awx/ui/static/partials/job_detail.html
@@ -268,7 +268,7 @@