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 += "" + - "" + - "" + - "\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 = "
StatusPlayTaskResult
\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 += "\n"; - html += "\n"; - html += "\n"; - html += ""; - html += "" + html += "\n"; + html += "\n"; + html += "\n"; + html += ""; + html += ""; }); html += "\n"; html += "
" + status_text + "" + result.play + "" + result.task + "" + msg + "
" + status_text + "" + result.play + "" + result.task + "" + msg + "
\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 @@
- +
@@ -276,7 +276,7 @@
- @@ -285,9 +285,19 @@
-
+ +
+ + + + + + + + +
StatusPlayTaskResult
-
+