mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 02:50:02 -03:30
Job detail page re-refactor
Host events viewer. Search now wired up. HTML re-load working. Table scrolling works.
This commit is contained in:
parent
39a5366237
commit
fb9b5ae43c
@ -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
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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 = "<table class=\"table\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr><th class=\"col-md-3\">Status</th>" +
|
||||
"<th class=\"col-md-3\">Play</th>" +
|
||||
"<th class=\"col-md-3\">Task</th>" +
|
||||
"<th class=\"col-md-3\">Result</th></tr>\n";
|
||||
html += "</thead>\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 = "<table class=\"table\">\n";
|
||||
html += "<tbody>\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 += "<tr ng-click=\"showDetails()\" class=\"cursor-pointer\" aw-tool-tip=\"Click to view details\" data-placement=\"top\">\n";
|
||||
html += "<td><i class=\"fa icon-job-" + status + "\"></i> <a href=\"\">" + status_text + "</a></td>\n";
|
||||
html += "<td><a href=\"\">" + result.play + "</a></td>\n";
|
||||
html += "<td><a href=\"\">" + result.task + "</a></td>\n";
|
||||
html += "<td><a href=\"\">" + msg + "</a></td>";
|
||||
html += "</tr>"
|
||||
html += "<td class=\"col-md-3\"><i class=\"fa icon-job-" + status + "\"></i> <a href=\"\">" + status_text + "</a></td>\n";
|
||||
html += "<td class=\"col-md-3\"><a href=\"\">" + result.play + "</a></td>\n";
|
||||
html += "<td class=\"col-md-3\"><a href=\"\">" + result.task + "</a></td>\n";
|
||||
html += "<td class=\"col-md-3\"><a href=\"\">" + msg + "</a></td>";
|
||||
html += "</tr>";
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\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!',
|
||||
|
||||
@ -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: { },
|
||||
|
||||
});
|
||||
@ -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 {
|
||||
|
||||
20
awx/ui/static/lib/angular-scheduler/package.json
Normal file
20
awx/ui/static/lib/angular-scheduler/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
36
awx/ui/static/lib/socket.io-client/package.json
Normal file
36
awx/ui/static/lib/socket.io-client/package.json
Normal file
@ -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 <guillermo@learnboost.com>"
|
||||
, "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" }
|
||||
}
|
||||
@ -268,7 +268,7 @@
|
||||
<form id="search-form" class="form-inline">
|
||||
<div class="form-group" style="position:relative;">
|
||||
<label>Search</label>
|
||||
<input type="text" class="form-control input-sm" id="host-events-search-name" ng-model="host_events_search_name" placeholder="Host name" >
|
||||
<input type="text" class="form-control input-sm" id="host-events-search-name" ng-model="host_events_search_name" placeholder="Host name" ng-keypress="searchEventKeyPress($event)" >
|
||||
<div id="search-form-input-icons">
|
||||
<a class="search-icon" ng-show="!eventsSearchActive" ng-click="searchEvents()"><i class="fa fa-search"></i></a>
|
||||
<a class="search-icon" ng-show="eventsSearchActive" ng-click="host_events_search_name=''; searchEvents()"><i class="fa fa-times"></i></a>
|
||||
@ -276,7 +276,7 @@
|
||||
</div>
|
||||
<div class="form-group" id="status-field">
|
||||
<label>Status</label>
|
||||
<select id="host-events-search-status" class="form-control input-sm" ng-model="host_events_search_status" name="host-events-search-name">
|
||||
<select id="host-events-search-status" class="form-control input-sm" ng-model="host_events_search_status" name="host-events-search-name" ng-change="searchEvents()">
|
||||
<option value="all">All</option>
|
||||
<option value="changed">Changed</option>
|
||||
<option value="failed">Failed</option>
|
||||
@ -285,9 +285,19 @@
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
<div id="host-events-table" lr-infinite-scroll="hostEventsTable" scroll-threshold="10" time-threshold="500">
|
||||
<!-- lr-infinite-scroll="hostEventsTable" scroll-threshold="10" time-threshold="500" -->
|
||||
<div id="host-events-table">
|
||||
<table id="fixed-table-header" class="table">
|
||||
<thead>
|
||||
<tr><th class="col-md-3">Status</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>
|
||||
<div id="host-events"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user