Merge pull request #1081 from jaredevantabor/job-detail-details

Job Details--details panel and events summary
This commit is contained in:
Jared Tabor
2016-03-02 11:58:39 -08:00
7 changed files with 384 additions and 386 deletions

View File

@@ -166,9 +166,6 @@
.unreachable-hosts-color { .unreachable-hosts-color {
color: @unreachable-hosts-color; color: @unreachable-hosts-color;
} }
.missing-hosts {
color: transparent;
}
.job_well { .job_well {
padding: 8px; padding: 8px;
@@ -197,9 +194,6 @@
margin-bottom: 0; margin-bottom: 0;
} }
#job-detail-tables {
margin-top: 20px;
}
#job_options { #job_options {
height: 100px; height: 100px;
@@ -208,7 +202,6 @@
} }
#job_plays, #job_tasks { #job_plays, #job_tasks {
height: 150px;
overflow-y: auto; overflow-y: auto;
overflow-x: none; overflow-x: none;
} }
@@ -224,7 +217,6 @@
position: relative; position: relative;
padding-left: 15px; padding-left: 15px;
padding-right: 7px; padding-right: 7px;
width: 58.33333333%;
.well { .well {
overflow: hidden; overflow: hidden;
} }
@@ -292,9 +284,6 @@
.row:first-child { .row:first-child {
border: none; border: none;
} }
.active {
background-color: @active-color;
}
.loading-info { .loading-info {
padding-top: 5px; padding-top: 5px;
padding-left: 3px; padding-left: 3px;
@@ -329,10 +318,6 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#tasks-table-detail {
height: 150px;
}
#play-section { #play-section {
.table-detail { .table-detail {
height: 150px; height: 150px;

View File

@@ -32,6 +32,7 @@ table, tbody {
background-color: @list-header-bg; background-color: @list-header-bg;
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
border-bottom-width:0px!important;
} }
.List-tableHeader:first-of-type { .List-tableHeader:first-of-type {
@@ -69,6 +70,7 @@ table, tbody {
.List-tableCell { .List-tableCell {
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
border-top:0px!important;
} }
.List-actionButtonCell { .List-actionButtonCell {

View File

@@ -235,7 +235,7 @@ export default
} }
if (newActivePlay) { if (newActivePlay) {
scope.activePlay = newActivePlay; scope.activePlay = newActivePlay;
scope.jobData.plays[scope.activePlay].playActiveClass = 'active'; scope.jobData.plays[scope.activePlay].playActiveClass = 'List-tableRow--selected';
} }
} }
}; };
@@ -265,7 +265,7 @@ export default
} }
if (newActiveTask) { if (newActiveTask) {
scope.activeTask = newActiveTask; scope.activeTask = newActiveTask;
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'active'; scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'List-tableRow--selected';
} }
} }
}; };
@@ -700,12 +700,12 @@ export default
task.missingPct = task.missingPct - diff; task.missingPct = task.missingPct - diff;
} }
} }
task.successfulStyle = (task.successfulPct > 0) ? { 'display': 'inline-block', 'width': task.successfulPct + "%" } : { 'display': 'none' }; task.successfulStyle = (task.successfulPct > 0) ? { 'display': 'inline-block' }: { 'display': 'none' };
task.changedStyle = (task.changedPct > 0) ? { 'display': 'inline-block', 'width': task.changedPct + "%" } : { 'display': 'none' }; task.changedStyle = (task.changedPct > 0) ? { 'display': 'inline-block'} : { 'display': 'none' };
task.skippedStyle = (task.skippedPct > 0) ? { 'display': 'inline-block', 'width': task.skippedPct + "%" } : { 'display': 'none' }; task.skippedStyle = (task.skippedPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' };
task.failedStyle = (task.failedPct > 0) ? { 'display': 'inline-block', 'width': task.failedPct + "%" } : { 'display': 'none' }; task.failedStyle = (task.failedPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' };
task.unreachableStyle = (task.unreachablePct > 0) ? { 'display': 'inline-block', 'width': task.unreachablePct + "%" } : { 'display': 'none' }; task.unreachableStyle = (task.unreachablePct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' };
task.missingStyle = (task.missingPct > 0) ? { 'display': 'inline-block', 'width': task.missingPct + "%" } : { 'display': 'none' }; task.missingStyle = (task.missingPct > 0) ? { 'display': 'inline-block' } : { 'display': 'none' };
}; };
}]) }])
@@ -793,7 +793,7 @@ export default
scope.selectedPlay = id; scope.selectedPlay = id;
scope.plays.forEach(function(play, idx) { scope.plays.forEach(function(play, idx) {
if (play.id === scope.selectedPlay) { if (play.id === scope.selectedPlay) {
scope.plays[idx].playActiveClass = 'active'; scope.plays[idx].playActiveClass = 'List-tableRow--selected';
} }
else { else {
scope.plays[idx].playActiveClass = ''; scope.plays[idx].playActiveClass = '';
@@ -940,7 +940,7 @@ export default
scope.selectedTask = id; scope.selectedTask = id;
scope.tasks.forEach(function(task, idx) { scope.tasks.forEach(function(task, idx) {
if (task.id === scope.selectedTask) { if (task.id === scope.selectedTask) {
scope.tasks[idx].taskActiveClass = 'active'; scope.tasks[idx].taskActiveClass = 'List-tableRow--selected';
} }
else { else {
scope.tasks[idx].taskActiveClass = ''; scope.tasks[idx].taskActiveClass = '';
@@ -1155,21 +1155,21 @@ export default
} }
if (scope.host_summary.changed) { if (scope.host_summary.changed) {
graph_data.push({ graph_data.push({
label: 'Changed', label: 'CHANGED',
value: scope.host_summary.changed, value: scope.host_summary.changed,
color: '#FF9900' color: '#FF9900'
}); });
} }
if (scope.host_summary.unreachable) { if (scope.host_summary.unreachable) {
graph_data.push({ graph_data.push({
label: 'Unreachable', label: 'UNREACHABLE',
value: scope.host_summary.unreachable, value: scope.host_summary.unreachable,
color: '#FF0000' color: '#FF0000'
}); });
} }
if (scope.host_summary.failed) { if (scope.host_summary.failed) {
graph_data.push({ graph_data.push({
label: 'Failed', label: 'FAILED',
value: scope.host_summary.failed, value: scope.host_summary.failed,
color: '#ff5850' color: '#ff5850'
}); });
@@ -1180,148 +1180,88 @@ export default
total_count += graph_data[gd_obj].value; total_count += graph_data[gd_obj].value;
} }
scope.total_count_for_graph = total_count; scope.total_count_for_graph = total_count;
// Adjust the size DonutChart({
width = $('#job-summary-container .job_well').width(); data: graph_data
height = $('#job-summary-container .job_well').height() - $('#summary-well-top-section').height() - $('#graph-section .header').outerHeight() - 80; });
svg_radius = Math.min(width, height);
svg_width = width;
svg_height = height;
if (svg_height > 0 && svg_width > 0) {
if (!resize && $('#graph-section svg').length > 0) {
// Donut3D.transition("completedHostsDonut", graph_data, Math.floor(svg_radius * 0.50), Math.floor(svg_radius * 0.25), 18, 0.4);
DonutChart({
target: '#graph-section',
height: height,
width: width,
data: graph_data,
radius: svg_radius
});
}
else {
if ($('#graph-section svg').length > 0) {
$('#graph-section svg').remove();
}
// svg = d3.select("#graph-section").append("svg").attr("width", svg_width).attr("height", svg_height);
// svg.append("g").attr("id","completedHostsDonut");
// Donut3D.draw("completedHostsDonut", graph_data, Math.floor(svg_width / 2), Math.floor(svg_height / 2) - 35, Math.floor(svg_radius * 0.50), Math.floor(svg_radius * 0.25), 18, 0.4);
DonutChart({
target: '#graph-section',
height: height,
width: width,
data: graph_data,
radius: svg_radius
});
$('#graph-section .header .legend').show();
}
}
}; };
}]) }])
.factory('DonutChart', [function() { .factory('DonutChart', [function() {
return function(params) { return function(params) {
var target = params.target, var dataset = params.data,
height = Math.max(params.height, 250), element = $("#graph-section"),
width = Math.max(params.width, 250), colors, total,job_detail_chart;
dataset = params.data,
outerRadius = Math.min(width, height) / 2,
innerRadius = (outerRadius/3),
svg, arc, pie, legend,
tooltip, path,
legendRectSize = 18,
legendSpacing = 4;
svg = d3.select(target) colors = ['#60D66F', '#FF9900','#FF0000','#ff5850'];
.append('svg') total = d3.sum(dataset.map(function(d) {
.data([dataset])
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
arc = d3.svg.arc()
.innerRadius(outerRadius - innerRadius)
.outerRadius(outerRadius);
pie = d3.layout.pie()
.value(function(d) { return d.value; })
.sort(function() {return null; });
tooltip = d3.select(target)
.append('div')
.attr('class', 'donut-tooltip');
tooltip.append('div')
.attr('class', 'donut-tooltip-inner');
path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d) {
return d.data.color;
});
path.on('mouseenter', function(d) {
var total = d3.sum(dataset.map(function(d) {
return d.value; return d.value;
})); }));
job_detail_chart = nv.models.pieChart()
.margin({bottom: 15})
.x(function(d) {
return d.label +': '+ Math.round((d.value/total)*100) + "%";
})
.y(function(d) { return d.value; })
.showLabels(true)
.showLegend(false)
.growOnHover(false)
.labelThreshold(0.01)
.tooltipContent(function(x, y) {
return '<p>'+x+'</p>'+ '<p>' + Math.floor(y.replace(',','')) + ' HOSTS ' + '</p>';
})
.color(colors);
var label; d3.select(element.find('svg')[0])
if (d.data.value === 1) { .datum(dataset)
label = " host "; .transition().duration(350)
} else { .call(job_detail_chart)
label = " hosts "; .style({
} "font-family": 'Open Sans',
var percent = Math.round(1000 * d.data.value / total) / 10; "font-style": "normal",
tooltip.select('.donut-tooltip-inner').html(d.data.value + label + " (" + "font-weight":400,
percent + "%) " + d.data.label + "."); "src": "url(/static/assets/OpenSans-Regular.ttf)"
//.attr('style', 'color:white;font-family:'); });
tooltip.style('display', 'block'); d3.select(element.find(".nv-label text")[0])
}); .attr("class", "DashboardGraphs-hostStatusLabel--successful")
.style({
path.on('mouseleave', function() { "font-family": 'Open Sans',
tooltip.style('display', 'none'); "text-anchor": "start",
}); "font-size": "16px",
"text-transform" : "uppercase",
path.on('mousemove', function() { "fill" : '#3CB878',
// d3.mouse() gives the coordinates of hte mouse, then add "src": "url(/static/assets/OpenSans-Regular.ttf)"
// some offset to provide breathing room for hte tooltip });
// based on the dimensions of the donut d3.select(element.find(".nv-label text")[1])
tooltip.style('top', (d3.mouse(this)[1] + (height/5) + 'px')) .attr("class", "DashboardGraphs-hostStatusLabel--failed")
.style('left', (d3.mouse(this)[0] + (width/3) + 'px')); .style({
}); "font-family": 'Open Sans',
"text-anchor" : "end !imporant",
legend = svg.selectAll('.legend') "font-size": "16px",
.data(pie(dataset)) "text-transform" : "uppercase",
.enter() "fill" : "#FF9900",
.append('g') "src": "url(/static/assets/OpenSans-Regular.ttf)"
.attr('class', 'legend') });
.attr('transform', function(d, i) { d3.select(element.find(".nv-label text")[2])
var height = legendRectSize + legendSpacing; .attr("class", "DashboardGraphs-hostStatusLabel--successful")
var offset = height * dataset.length / 2; .style({
var horz = -2 * legendRectSize; "font-family": 'Open Sans',
var vert = i * height - offset; "text-anchor" : "end !imporant",
return 'translate(' + horz + ',' + vert + ')'; "font-size": "16px",
}); "text-transform" : "uppercase",
"fill" : "#FF0000",
legend.append('rect') "src": "url(/static/assets/OpenSans-Regular.ttf)"
.attr('width', legendRectSize) });
.attr('height', legendRectSize) d3.select(element.find(".nv-label text")[3])
.attr('fill', function(d) { .attr("class", "DashboardGraphs-hostStatusLabel--failed")
return d.data.color; .style({
}) "font-family": 'Open Sans',
.attr('stroke', function(d) { "text-anchor" : "end !imporant",
return d.data.color; "font-size": "16px",
}); "text-transform" : "uppercase",
"fill" : "#ff5850",
legend.append('text') "src": "url(/static/assets/OpenSans-Regular.ttf)"
.attr('x', legendRectSize + legendSpacing) });
.attr('y', legendRectSize - legendSpacing) return job_detail_chart;
.text(function(d) {
return d.data.label;
});
}; };
}]) }])

View File

@@ -3,9 +3,20 @@
@import '../shared/branding/colors.less'; @import '../shared/branding/colors.less';
@import '../shared/branding/colors.default.less'; @import '../shared/branding/colors.default.less';
.JobDetail-leftSide{
width: 50%;
}
.JobDetail-panelHeader{ .JobDetail-panelHeader{
height: 50px;
display: flex; display: flex;
height: 30px;
}
.JobDetail-expandContainer{
flex: 1;
margin: 0px;
line-height: 30px;
white-space: nowrap;
} }
.JobDetail-panelHeaderText{ .JobDetail-panelHeaderText{
@@ -52,7 +63,71 @@
flex: 1 0 auto; flex: 1 0 auto;
} }
.JobDetail-resultRow--variables{
width: 90%;
display: block;
}
.JobDetail-resultRowText{ .JobDetail-resultRowText{
width: 40%; width: 40%;
flex: 1 0 auto; flex: 1 0 auto;
padding:0px;
}
.JobDetail-searchHeaderRow{
display: flex;
flex-wrap: wrap;
flex-direction: row;
height: 50px;
margin-top: 25px;
}
.JobDetail-searchContainer{
flex: 1 0 auto;
}
.JobDetail-tableToggleContainer{
flex: 1 0 auto;
display: flex;
justify-content: flex-end;
}
.JobDetail-tableToggle{
padding-left:10px;
padding-right: 10px;
border: 1px solid @default-second-border;
}
.JobDetail-tableToggle.active{
background-color: @default-link;
border: 1px solid @default-link;
color: @toggle-selected-text;
}
.JobDetail-tableToggle--left{
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.JobDetail-tableToggle--right{
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.JobDetail-searchInput{
border-radius: 5px !important;
}
.JobDetail-tableHeader:last-of-type{
text-align:justify;
}
.JobDetail-statusIcon{
padding-right: 10px;
padding-left: 10px;
}
.JobDetail-graphSection{
height: 320px;
width:100%;
} }

View File

@@ -19,7 +19,7 @@ export default
'EventViewer', 'DeleteJob', 'PlaybookRun', 'HostEventsViewer', 'EventViewer', 'DeleteJob', 'PlaybookRun', 'HostEventsViewer',
'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit', 'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit',
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
'EditSchedule', 'EditSchedule', 'ParseTypeChange',
function( function(
$location, $rootScope, $filter, $scope, $compile, $stateParams, $location, $rootScope, $filter, $scope, $compile, $stateParams,
$log, ClearScope, GetBasePath, Wait, Rest, ProcessErrors, $log, ClearScope, GetBasePath, Wait, Rest, ProcessErrors,
@@ -28,7 +28,7 @@ export default
SetTaskStyles, DigestEvent, UpdateDOM, EventViewer, DeleteJob, SetTaskStyles, DigestEvent, UpdateDOM, EventViewer, DeleteJob,
PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts,
HostsEdit, ParseVariableString, GetChoices, fieldChoices, HostsEdit, ParseVariableString, GetChoices, fieldChoices,
fieldLabels, EditSchedule fieldLabels, EditSchedule, ParseTypeChange
) { ) {
ClearScope(); ClearScope();
@@ -41,7 +41,7 @@ export default
job_type_options; job_type_options;
scope.plays = []; scope.plays = [];
scope.parseType = 'yaml';
scope.previousTaskFailed = false; scope.previousTaskFailed = false;
scope.$watch('job_status', function(job_status) { scope.$watch('job_status', function(job_status) {
@@ -201,6 +201,8 @@ export default
scope.haltEventQueue = false; scope.haltEventQueue = false;
scope.processing = false; scope.processing = false;
scope.lessStatus = false; scope.lessStatus = false;
scope.lessDetail = false;
scope.lessEvents = false;
scope.host_summary = {}; scope.host_summary = {};
scope.host_summary.ok = 0; scope.host_summary.ok = 0;
@@ -555,7 +557,7 @@ export default
}); });
}); });
if (scope.activeTask && scope.jobData.plays[scope.activePlay] && scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) { if (scope.activeTask && scope.jobData.plays[scope.activePlay] && scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) {
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'active'; scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'List-tableRow--selected';
} }
scope.$emit('LoadHosts'); scope.$emit('LoadHosts');
}) })
@@ -675,7 +677,7 @@ export default
scope.host_summary.failed; scope.host_summary.failed;
}); });
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) { if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
scope.jobData.plays[scope.activePlay].playActiveClass = 'active'; scope.jobData.plays[scope.activePlay].playActiveClass = 'List-tableRow--selected';
} }
scope.$emit('LoadTasks', events_url); scope.$emit('LoadTasks', events_url);
}) })
@@ -804,6 +806,7 @@ export default
return true; return true;
}); });
//scope.setSearchAll('host'); //scope.setSearchAll('host');
ParseTypeChange({ scope: scope, field_id: 'pre-formatted-variables' });
scope.$emit('LoadPlays', data.related.job_events); scope.$emit('LoadPlays', data.related.job_events);
}) })
.error(function(data, status) { .error(function(data, status) {
@@ -839,7 +842,6 @@ export default
$('.overlay').hide(); $('.overlay').hide();
$('#summary-button').hide(); $('#summary-button').hide();
$('#hide-summary-button').hide(); $('#hide-summary-button').hide();
$('#job-detail-container').css({ "width": "58.33333333%", "padding-right": "7px" });
$('#job-summary-container .job_well').css({ $('#job-summary-container .job_well').css({
'box-shadow': 'none', 'box-shadow': 'none',
'height': 'auto' 'height': 'auto'
@@ -859,12 +861,12 @@ export default
// Detail table height adjusting. First, put page height back to 'normal'. // Detail table height adjusting. First, put page height back to 'normal'.
$('#plays-table-detail').height(80); $('#plays-table-detail').height(80);
//$('#plays-table-detail').mCustomScrollbar("update"); //$('#plays-table-detail').mCustomScrollbar("update");
$('#tasks-table-detail').height(120); // $('#tasks-table-detail').height(120);
//$('#tasks-table-detail').mCustomScrollbar("update"); //$('#tasks-table-detail').mCustomScrollbar("update");
$('#hosts-table-detail').height(150); $('#hosts-table-detail').height(150);
//$('#hosts-table-detail').mCustomScrollbar("update"); //$('#hosts-table-detail').mCustomScrollbar("update");
height = $(window).height() - $('#main-menu-container .navbar').outerHeight() - height = $(window).height() - $('#main-menu-container .navbar').outerHeight() -
$('#job-detail-container').outerHeight() - $('#job-detail-footer').outerHeight() - 20; $('#job-detail-container').outerHeight() - 20;
if (height > 15) { if (height > 15) {
// there's a bunch of white space at the bottom, let's use it // there's a bunch of white space at the bottom, let's use it
$('#plays-table-detail').height(80 + (height * 0.10)); $('#plays-table-detail').height(80 + (height * 0.10));
@@ -872,10 +874,9 @@ export default
$('#hosts-table-detail').height(150 + (height * 0.70)); $('#hosts-table-detail').height(150 + (height * 0.70));
} }
// Summary table height adjusting. // Summary table height adjusting.
height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .header').outerHeight() - height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .JobDetail-searchHeaderRow').outerHeight() -
$('#hosts-summary-section .table-header').outerHeight() - $('#hosts-summary-section .table-header').outerHeight() - 20;
$('#summary-search-section').outerHeight() - 20; // $('#hosts-summary-table').height(height);
$('#hosts-summary-table').height(height);
//$('#hosts-summary-table').mCustomScrollbar("update"); //$('#hosts-summary-table').mCustomScrollbar("update");
scope.$emit('RefreshCompleted'); scope.$emit('RefreshCompleted');
}; };
@@ -989,6 +990,28 @@ export default
} }
}; };
scope.toggleLessDetail = function() {
if (!scope.lessDetail) {
$('#job-detail-details').slideUp(200);
scope.lessDetail = true;
}
else {
$('#job-detail-details').slideDown(200);
scope.lessDetail = false;
}
};
scope.toggleLessEvents = function() {
if (!scope.lessEvents) {
$('#events-summary').slideUp(200);
scope.lessEvents = true;
}
else {
$('#events-summary').slideDown(200);
scope.lessEvents = false;
}
};
scope.filterPlayStatus = function() { scope.filterPlayStatus = function() {
scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all'; scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing || scope.pauseLiveEvents) { if (!scope.liveEventProcessing || scope.pauseLiveEvents) {

View File

@@ -1,17 +1,21 @@
<div class="tab-pane" id="jobs-detail"> <div class="tab-pane" id="jobs-detail">
<div ng-cloak id="htmlTemplate"> <div ng-cloak id="htmlTemplate">
<div class="row" style="position: relative;"> <div class="row" style="position: relative;">
<div id="job-detail-container"> <div id="job-detail-container" class="JobDetail-leftSide">
<div class="JobDetail-resultsContainer Panel"> <div id="job-results-panel" class="JobDetail-resultsContainer Panel">
<div class="JobDetail-panelHeader"> <div class="JobDetail-panelHeader">
<a class="JobDetail-panelHeaderText" ng-show="lessStatus" href="" ng-click="toggleLessStatus()"> <div class="JobDetail-expandContainer">
RESULTS<i class="JobDetail-expandArrow fa fa-caret-left"></i> <a class="JobDetail-panelHeaderText" ng-show="lessStatus" href="" ng-click="toggleLessStatus()">
</a> RESULTS<i class="JobDetail-expandArrow fa fa-caret-left"></i>
<a class="JobDetail-panelHeaderText" ng-show="!lessStatus" href="" ng-click="toggleLessStatus()"> </a>
RESULTS<i class="JobDetail-expandArrow fa fa-caret-down"></i> <a class="JobDetail-panelHeaderText" ng-show="!lessStatus" href="" ng-click="toggleLessStatus()">
</a> RESULTS<i class="JobDetail-expandArrow fa fa-caret-down"></i>
<button id="submit-action" class="List-actionButton JobDetail-launchButton" data-placement="top" mode="all" ng-click="relaunchJob()" aw-tool-tip="Start a job using this template" data-original-title="" title=""><i class="fa fa-rocket"></i> </button> </a>
<button id="delete-action" class="List-actionButton List-actionButton--delete JobDetail-launchButton" data-placement="top" ng-click="deleteJobTemplate(job_template.id, job_template.name)" aw-tool-tip="Delete template" data-original-title="" title=""><i class="fa fa-trash-o"></i> </button> </div>
<div class="JobDetail-actions">
<button id="submit-action" class="List-actionButton JobDetail-launchButton" data-placement="top" mode="all" ng-click="relaunchJob()" aw-tool-tip="Start a job using this template" data-original-title="" title=""><i class="fa fa-rocket"></i> </button>
<button id="delete-action" class="List-actionButton List-actionButton--delete JobDetail-launchButton" data-placement="top" ng-click="deleteJobTemplate(job_template.id, job_template.name)" aw-tool-tip="Delete template" data-original-title="" title=""><i class="fa fa-trash-o"></i> </button>
</div>
</div> </div>
<div class="form-horizontal JobDetail-resultsDetails" role="form" id="job-status-form"> <div class="form-horizontal JobDetail-resultsDetails" role="form" id="job-status-form">
@@ -21,9 +25,9 @@
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.explanation"> <div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.explanation">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 col-xs-12">Explanation</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 col-xs-12">Explanation</label>
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation" <div class="JobDetail-resultRowText col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation"
ng-show="!previousTaskFailed" ng-bind-html="job_status.explanation"></div> ng-show="!previousTaskFailed" ng-bind-html="job_status.explanation"></div>
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation" <div class="JobDetail-resultRowText col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation"
ng-show="previousTaskFailed">Previous Task Failed ng-show="previousTaskFailed">Previous Task Failed
<a <a
href="" href=""
@@ -45,22 +49,6 @@
<div class="JobDetail-resultRowText col-lg-10 col-md-12 col-sm-12 col-xs-12 job_status_traceback" ng-bind-html="job_status.traceback"></div> <div class="JobDetail-resultRowText col-lg-10 col-md-12 col-sm-12 col-xs-12 job_status_traceback" ng-bind-html="job_status.traceback"></div>
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Started</label>
<div class="JobDetail-resultRowText">{{ job_status.started | date:'MM/dd/yy HH:mm:ss' }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Finished</label>
<div class="JobDetail-resultRowText">{{ job_status.finished | date:'MM/dd/yy HH:mm:ss' }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Elapsed</label>
<div class="JobDetail-resultRowText">{{ job_status.elapsed }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_template_name"> <div class="form-group JobDetail-resultRow toggle-show" ng-show="job_template_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Template</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Template</label>
<div class="JobDetail-resultRowText"> <div class="JobDetail-resultRowText">
@@ -68,11 +56,21 @@
</div> </div>
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Started</label>
<div class="JobDetail-resultRowText">{{ job_status.started | date:'MM/dd/yy HH:mm:ss' }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_type"> <div class="form-group JobDetail-resultRow toggle-show" ng-show="job_type">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Job Type</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Job Type</label>
<div class="JobDetail-resultRowText">{{ job_type }}</div> <div class="JobDetail-resultRowText">{{ job_type }}</div>
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Finished</label>
<div class="JobDetail-resultRowText">{{ job_status.finished | date:'MM/dd/yy HH:mm:ss' }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="created_by"> <div class="form-group JobDetail-resultRow toggle-show" ng-show="created_by">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText"> <div class="JobDetail-resultRowText">
@@ -80,6 +78,11 @@
</div> </div>
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Elapsed</label>
<div class="JobDetail-resultRowText">{{ job_status.elapsed }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="scheduled_by"> <div class="form-group JobDetail-resultRow toggle-show" ng-show="scheduled_by">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText"> <div class="JobDetail-resultRowText">
@@ -140,66 +143,67 @@
<div class="JobDetail-resultRowText">{{ job.job_tags }}</div> <div class="JobDetail-resultRowText">{{ job.job_tags }}</div>
</div> </div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="variables"> <div class="form-group JobDetail-resultRow JobDetail-resultRow--variables toggle-show" ng-show="variables">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Extra Variables</label> <label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Extra Variables</label>
<div class="JobDetail-resultRowText"> <textarea rows="6" ng-model="variables" name="variables" id="pre-formatted-variables"></textarea>
<div id="pre-formatted-variables">{{ variables }}</div>
<!-- <pre>{{ variables }}</pre> -->
</div>
</div> </div>
</div> </div>
</div> </div>
<!--- JobDetail-results----------------------------------------------> <!--- JobDetail-results---------------------------------------------->
<div id="job-detail-tables"> <div id="job-detail-panel" class="JobDetail-resultsContainer Panel">
<div id="play-section" class="section"> <div class="JobDetail-panelHeader">
<div class="JobDetail-expandContainer">
<a class="JobDetail-panelHeaderText" ng-show="lessDetail" href="" ng-click="toggleLessDetail()">
DETAILS<i class="JobDetail-expandArrow fa fa-caret-left"></i>
</a>
<a class="JobDetail-panelHeaderText" ng-show="!lessDetail" href="" ng-click="toggleLessDetail()">
DETAILS<i class="JobDetail-expandArrow fa fa-caret-down"></i>
</a>
</div>
</div>
<div class="row title-row"> <div id="job-detail-details">
<div class="col-lg-1 col-md-2 col-sm-2 col-xs-1 title">Plays</div> <div id="play-section">
<div class="col-lg-11 col-md-10 col-sm-10 col-xs-11" style="text-align:right;"> <div class="JobDetail-searchHeaderRow">
<div id="play-search-form" class="search-form form-inline"> <div class="JobDetail-searchContainer form-group">
<div class="form-group"> <div class="search-name">
<div class="search-name" style="display:inline-block; position:relative;"> <input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_play_name" ng-model="search_play_name" placeholder="Play Name" ng-keypress="searchPlaysKeyPress($event)" >
<input type="text" class="input-xs form-control" id="search_play_name" ng-model="search_play_name" <a class="List-searchInputIcon search-icon" ng-show="searchPlaysEnabled" ng-click="searchPlays()"><i class="fa fa-search"></i></a>
placeholder="Play Name" ng-keypress="searchPlaysKeyPress($event)" > <a class="List-searchInputIcon search-icon" ng-show="!searchPlaysEnabled" ng-click="search_play_name=''; searchPlays()"><i class="fa fa-times"></i></a>
<div id="search-all-input-icons">
<a class="search-icon" ng-show="searchPlaysEnabled" ng-click="searchPlays()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchPlaysEnabled" ng-click="search_play_name=''; searchPlays()"><i class="fa fa-times"></i></a>
</div>
</div>
</div> </div>
<div class="form-group"> </div>
<div class="btn-group" aw-toggle-button data-after-toggle="filterPlayStatus"> <div class="JobDetail-tableToggleContainer form-group">
<button class="btn btn-xs btn-primary active">All</button> <div class="btn-group" aw-toggle-button data-after-toggle="filterPlayStatus">
<button class="btn btn-xs btn-default">Failed</button> <button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
</div> <button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div> </div>
</div> </div>
</div> </div>
</div>
<div id="plays-table-header" class="table-header"> <div id="plays-table-header" class="table-header">
<table class="table table-condensed"> <table class="table table-condensed">
<thead> <thead>
<tr> <tr>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th> <th class="List-tableHeader col-lg-7 col-md-6 col-sm-6 col-xs-4">Plays</th>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th> <th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column">Status</th> <th class="List-tableHeader JobDetail-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
<th class="col-lg-7 col-md-6 col-sm-6 col-xs-4">Name</th>
</tr> </tr>
</thead> </thead>
</table> </table>
</div> </div>
<div id="plays-table-detail" class="table-detail" lr-infinite-scroll="playsScrollDown" <div id="plays-table-detail" class="table-detail" lr-infinite-scroll="playsScrollDown"
scroll-threshold="10" time-threshold="500"> scroll-threshold="10" time-threshold="500">
<table class="table table-condensed"> <table class="table">
<tbody> <tbody>
<tr class="cursor-pointer" ng-repeat="play in plays" ng-class="play.playActiveClass" ng-click="selectPlay(play.id, $event)"> <tr class="List-tableRow cursor-pointer" ng-repeat="play in plays" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-class="play.playActiveClass" ng-click="selectPlay(play.id, $event)">
<td class="col-lg-2 col-md-2 col-sm-2 col-xs-3">{{ play.created | date: 'HH:mm:ss' }}</td> <td class="List-tableCell col-lg-7 col-md-6 col-sm-6 col-xs-4 status-column" aw-tool-tip="{{ play.status_tip }}" data-tip-watch="play.status_tip" data-placement="top"><i class="JobDetail-statusIcon fa icon-job-{{ play.status }}"></i>{{ play.name }}</td>
<td class="col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ play.finishedTip }}" data-tip-watch="play.finishedTip" <td class="List-tableCell col-lg-2 col-md-2 col-sm-2 col-xs-3">{{ play.created | date: 'HH:mm:ss' }}</td>
<td class="List-tableCell col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ play.finishedTip }}" data-tip-watch="play.finishedTip"
data-placement="top">{{ play.elapsed }}</td> data-placement="top">{{ play.elapsed }}</td>
<td class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column" aw-tool-tip="{{ play.status_tip }}" data-tip-watch="play.status_tip" data-placement="top"><i class="fa icon-job-{{ play.status }}"></i></td>
<td class="col-lg-7 col-md-6 col-sm-6 col-xs-4">{{ play.name }}</td>
</tr> </tr>
<tr ng-show="plays.length === 0 && waiting"> <tr ng-show="plays.length === 0 && waiting">
<td colspan="4" class="col-lg-12 loading-info">Waiting...</td> <td colspan="4" class="col-lg-12 loading-info">Waiting...</td>
@@ -213,31 +217,24 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="scroll-spinner" id="playsMoreRows"><i class="fa fa-cog fa-spin"></i></div> <div class="scroll-spinner" id="playsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section --> </div>
<!-- end of plays section-->
<div id="task-section" class="section" tasks=> <div id="task-section" class="section" >
<div class="row title-row"> <div class="JobDetail-searchHeaderRow">
<div class="col-lg-1 col-md-2 col-sm-2 title">Tasks</div> <div class="JobDetail-searchContainer form-group">
<div class="col-lg-11 col-md-10 col-sm-10" style="text-align:right;"> <div class="search-name">
<div id="task-search-form" class="search-form form-inline"> <input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_task_name" ng-model="search_task_name" placeholder="Task Name" ng-keypress="searchTasksKeyPress($event)" >
<div class="form-group"> <a class="List-searchInputIcon search-icon" ng-show="searchTasksEnabled" ng-click="searchTasks()"><i class="fa fa-search"></i></a>
<div class="search-name" style="display:inline-block; position:relative;"> <a class="List-searchInputIcon search-icon" ng-show="!searchTasksEnabled" ng-click="search_task_name=''; searchTasks()"><i class="fa fa-times"></i></a>
<input type="text" class="input-xs form-control" id="search_task_name" ng-model="search_task_name" </div>
placeholder="Task Name" ng-keypress="searchTasksKeyPress($event)" > </div>
<div id="search-all-input-icons"> <div class="JobDetail-tableToggleContainer form-group">
<a class="search-icon" ng-show="searchTasksEnabled" ng-click="searchTasks()"><i class="fa fa-search"></i></a> <div class="btn-group" aw-toggle-button data-after-toggle="filterTaskStatus">
<a class="search-icon" ng-show="!searchTasksEnabled" ng-click="search_task_name=''; searchTasks()"><i class="fa fa-times"></i></a> <button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
</div> <button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div>
</div>
<div class="form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterTaskStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -246,46 +243,46 @@
<table id="tasks-table-header" class="table table-condensed"> <table id="tasks-table-header" class="table table-condensed">
<thead> <thead>
<tr> <tr>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th> <th class="List-tableHeader col-lg-3 col-md-3 col-sm-6 col-xs-4">Tasks</div>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th> <th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column">Status</th> <th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
<th class="col-lg-3 col-md-3 col-sm-6 col-xs-4">Name</div> <th class="List-tableHeader JobDetail-tableHeader col-lg-4 col-md-3 hidden-xs hidden-sm">Host Status</th>
<th class="col-lg-4 col-md-3 hidden-xs hidden-sm">Host Status</th>
</tr> </tr>
</thead> </thead>
</table> </table>
</div> </div>
<div id="tasks-table-detail" class="table-detail" lr-infinite-scroll="tasksScrollDown" <div id="tasks-table-detail" class="table-detail" lr-infinite-scroll="tasksScrollDown"
scroll-threshold="10" time-threshold="500"> scroll-threshold="10" time-threshold="500">
<table class="table table-condensed"> <table class="table">
<tbody> <tbody>
<tr class="cursor-pointer" ng-repeat="task in taskList = (tasks) track by $index" ng-class="task.taskActiveClass" ng-click="selectTask(task.id)"> <tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="task in taskList = (tasks) track by $index" ng-class="task.taskActiveClass" ng-click="selectTask(task.id)">
<td class="col-lg-2 col-md-2 col-sm-2 col-xs-3">{{ task.created | date: 'HH:mm:ss' }}</td> <td class="List-tableCell col-lg-3 col-md-3 col-sm-6 col-xs-4 status-column" aw-tool-tip="{{ task.status_tip }}"
<td class="col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ task.finishedTip }}" data-tip-watch="task.finishedTip" data-tip-watch="task.status_tip" data-placement="top"><i class="JobDetail-statusIcon fa icon-job-{{ task.status }}"></i>{{ task.name }}</td>
<td class="List-tableCell col-lg-2 col-md-2 col-sm-2 col-xs-3">{{ task.created | date: 'HH:mm:ss' }}</td>
<td class="List-tableCell col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ task.finishedTip }}" data-tip-watch="task.finishedTip"
data-placement="top">{{ task.elapsed }}</td> data-placement="top">{{ task.elapsed }}</td>
<td class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column" aw-tool-tip="{{ task.status_tip }}"
data-tip-watch="task.status_tip" data-placement="top"><i class="fa icon-job-{{ task.status }}"></i></td> <td class="List-tableCell col-lg-4 col-md-3 hidden-sm hidden-xs">
<td class="col-lg-3 col-md-3 col-sm-6 col-xs-4" id="">{{ task.name }}</td> <div>
<td class="col-lg-4 col-md-3 hidden-sm hidden-xs">
<div class="status-bar"> <a href="" id="{{ task.id }}-successful-bar" aw-tool-tip="{{ task.successfulCountTip }}" data-tip-watch="task.successfulCountTip" data-placement="top" ng-style="task.successfulStyle">
<div class="successful-hosts inner-bar" id="{{ task.id }}-successful-bar" aw-tool-tip="{{ task.successfulCountTip }}" data-tip-watch="task.successfulCountTip" data-placement="top" ng-style="task.successfulStyle"> <span class="badge successful-hosts">{{ task.successfulCount }}</span>
{{ task.successfulCount }} </a>
</div> <a href="" id="{{ task.id }}-changed-bar" aw-tool-tip="{{ task.changedCountTip }}" data-tip-watch="task.changedCountTip" data-placement="top" ng-style="task.changedStyle">
<div class="changed-hosts inner-bar" id="{{ task.id }}-changed-bar" aw-tool-tip="{{ task.changedCountTip }}" data-tip-watch="task.changedCountTip" data-placement="top" ng-style="task.changedStyle"> <span class="badge changed-hosts">{{ task.changedCount }}</span>
{{ task.changedCount }} </a>
</div> <a href="" id="{{ task.id }}-skipped-bar" aw-tool-tip="{{ task.skippedCountTip }}" data-tip-watch="task.skippedCountTip" data-placement="top" ng-style="task.skippedStyle">
<div class="skipped-hosts inner-bar" id="{{ task.id }}-skipped-bar" aw-tool-tip="{{ task.skippedCountTip }}" data-tip-watch="task.skippedCountTip" data-placement="top" ng-style="task.skippedStyle"> <span class="badge skipped-hosts">{{ task.skippedCount }}</span>
{{ task.skippedCount }} </a>
</div> <a href="" id="{{ task.id }}-failed-bar" aw-tool-tip="{{ task.failedCountTip }}" data-tip-watch="task.failedCountTip" data-placement="top" ng-style="task.failedStyle">
<div class="failed-hosts inner-bar" id="{{ task.id }}-failed-bar" aw-tool-tip="{{ task.failedCountTip }}" data-tip-watch="task.failedCountTip" data-placement="top" ng-style="task.failedStyle"> <span class="badge failed-hosts">{{ task.failedCount }}</span>
{{ task.failedCount }} </a>
</div> <a href="" id="{{ task.id }}-unreachable-bar" aw-tool-tip="{{ task.unreachableCountTip }}" data-tip-watch="task.unreachableCountTip" data-placement="top" ng-style="task.unreachableStyle">
<div class="unreachable-hosts inner-bar" id="{{ task.id }}-unreachable-hosts-bar" aw-tool-tip="{{ task.unreachableCountTip }}" data-tip-watch="task.unreachableCountTip" data-placement="top" ng-style="task.unreachableStyle"> <span class="badge unreachable-hosts">{{ task.unreachableCount }}</span>
{{ task.unreachableCount }} </a>
</div> <a href="" id="{{ task.id }}-missing-bar" aw-tool-tip="{{ task.missingCountTip }}" data-tip-watch="task.missingCountTip" data-placement="top" ng-style="task.missingStyle">
<div class="missing-hosts inner-bar" id="{{ task.id }}-misssing-hosts-bar" aw-tool-tip="{{ task.missingCountTip }}" data-tip-watch="task.missingCountTip" data-placement="top" ng-style="task.missingStyle"> <span class="badge missing-hosts">{{ task.missingCount }}</span>
{{ task.missingCount }} </a>
</div>
<div class="no-matching-hosts inner-bar" id="{{ task.id }}-{{ task.play_id }}-no-matching-hosts-bar" aw-tool-tip="No matching hosts were found." data-placement="top" style="width: 100%;" ng-show="task.status === 'no-matching-hosts'"> <div class="no-matching-hosts inner-bar" id="{{ task.id }}-{{ task.play_id }}-no-matching-hosts-bar" aw-tool-tip="No matching hosts were found." data-placement="top" style="width: 100%;" ng-show="task.status === 'no-matching-hosts'">
No matching hosts. No matching hosts.
</div> </div>
@@ -308,54 +305,44 @@
</div><!-- section --> </div><!-- section -->
<div id="task-hosts-section" class="section"> <div id="task-hosts-section" class="section">
<div class="JobDetail-searchHeaderRow">
<div class="row title-row"> <div class="JobDetail-searchContainer form-group">
<div class="col-lg-2 col-md-2 col-sm-2 title">Host Events</div> <div class="search-name">
<div class="col-lg-10 col-md-10 col-sm-10" style="text-align:right;"> <input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_host_name" ng-model="search_host_name" placeholder="Host Name" ng-keypress="searchHostsKeyPress($event)" >
<div id="host-search-form" class="search-form form-inline"> <a class="List-searchInputIcon search-icon" ng-show="searchHostsEnabled" ng-click="searchHosts()"><i class="fa fa-search"></i></a>
<div class="form-group"> <a class="List-searchInputIcon search-icon" ng-show="!searchHostsEnabled" ng-click="search_host_name=''; searchHosts()"><i class="fa fa-times"></i></a>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_host_name" ng-model="search_host_name"
placeholder="Host Name" ng-keypress="searchHostsKeyPress($event)" >
<div id="search-all-input-icons">
<a class="search-icon" ng-show="searchHostsEnabled" ng-click="searchHosts()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchHostsEnabled" ng-click="search_host_name=''; searchHosts()"><i class="fa fa-times"></i></a>
</div>
</div>
</div> </div>
<div class="form-group"> </div>
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostStatus"> <div class="JobDetail-tableToggleContainer form-group">
<button class="btn btn-xs btn-primary active">All</button> <div class="btn-group" aw-toggle-button data-after-toggle="filterHostStatus">
<button class="btn btn-xs btn-default">Failed</button> <button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
</div> <button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="table-header" id="hosts-table-header"> <div class="table-header" id="hosts-table-header">
<table class="table table-condensed"> <table class="table table-condensed">
<thead> <thead>
<tr> <tr>
<th class="col-lg-1 col-md-1 col-sm-2 col-xs-2 status-column">Status</th> <th class="List-tableHeader col-lg-3 col-md-3 col-sm-3 col-xs-3">Hosts</th>
<th class="col-lg-3 col-md-3 col-sm-3 col-xs-3">Host</th> <th class="List-tableHeader col-lg-3 col-md-4 col-sm-3 col-xs-3">Item</th>
<th class="col-lg-4 col-md-4 col-sm-3 col-xs-3">Item</th> <th class="List-tableHeader col-lg-3 col-md-4 col-sm-3 col-xs-3">Message</th>
<th class="col-lg-4 col-md-4 col-sm-3 col-xs-3">Message</th> <th class="List-tableHeader col-lg-2 col-md-1 col-sm-1 col-xs-1">Actions</th>
<th class="col-lg-1 col-md-1 col-sm-1 col-xs-1"></th>
</tr> </tr>
</thead> </thead>
</table> </table>
</div> </div>
<div id="hosts-table-detail" class="table-detail" lr-infinite-scroll="hostResultsScrollDown" scroll-threshold="10" time-threshold="500"> <div id="hosts-table-detail" class="table-detail" lr-infinite-scroll="hostResultsScrollDown" scroll-threshold="10" time-threshold="500">
<table class="table table-condensed"> <table class="table">
<tbody> <tbody>
<tr ng-repeat="result in results = (hostResults) track by $index"> <tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="result in results = (hostResults) track by $index">
<td class="col-lg-1 col-md-1 col-sm-2 col-xs-2 status-column"><a href="" ng-click="viewHostResults(result.id)" aw-tool-tip="Event ID: {{ result.id }}<br \>Status: {{ result.status_text }}. Click for details" data-placement="top"><i ng-show="result.status_text != 'Unreachable'" class="fa icon-job-{{ result.status }}"></i><i ng-show="result.status_text == 'Unreachable'" class="fa icon-job-unreachable"></i></a></td> <td class="List-tableCell col-lg-3 col-md-3 col-sm-3 col-xs-3 status-column"><a href="" ng-click="viewHostResults(result.id)" aw-tool-tip="Event ID: {{ result.id }}<br \>Status: {{ result.status_text }}. Click for details" data-placement="top"><i ng-show="result.status_text != 'Unreachable'" class="JobDetail-statusIcon fa icon-job-{{ result.status }}"></i><span ng-show="result.status_text != 'Unreachable'">{{ result.name }}</span><i ng-show="result.status_text == 'Unreachable'" class="JobDetail-statusIcon fa icon-job-unreachable"></i><span ng-show="result.status_text == 'Unreachable'">{{ result.name }}</span></a></td>
<td class="col-lg-3 col-md-3 col-sm-3 col-xs-3"><a href="" ng-click="viewHostResults(result.id)" aw-tool-tip="Event ID: {{ result.id }}<br \>Status: {{ result.status_text }}. Click for details" data-placement="top">{{ result.name }}</a></td> <td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3 item-column">{{ result.item }}</td>
<td class="col-lg-4 col-md-4 col-sm-3 col-xs-3 item-column">{{ result.item }}</td> <td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3">{{ result.msg }}</td>
<td class="col-lg-4 col-md-4 col-sm-3 col-xs-3">{{ result.msg }}</td> <td class="List-actionButtonCell List-tableCell col-lg-1 col-md-1 col-sm-1 col-xs-1">
<td class="col-lg-1 col-md-1 col-sm-1 col-xs-1"><a ng-show="result.host_id" href="" ng-click="editHost(result.host_id)" aw-tool-tip="Edit host" data-placement="top"><i class="fa fa-pencil"></i></a></td> <button class="List-actionButton " ng-show="result.host_id" data-placement="top" ng-click="editHost(result.host_id)" aw-tool-tip="Edit host" data-original-title="" title=""><i class="fa fa-pencil"></i> </button>
</td>
</tr> </tr>
<tr ng-show="results.length === 0 && waiting"> <tr ng-show="results.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td> <td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
@@ -370,75 +357,69 @@
</table> </table>
</div> </div>
<div class="scroll-spinner" id="hostResultsMoreRows"><i class="fa fa-cog fa-spin"></i></div> <div class="scroll-spinner" id="hostResultsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section --> </div>
</div><!-- job-detail-tables --> </div>
</div>
<div id="events-summary-panel" class="JobDetail-resultsContainer Panel">
</div><!-- job-detail-container -->
<!-- <div id="job-summary-container"> -->
<div class="job_well">
<div id="summary-well-top-section"> <div id="summary-well-top-section">
<div id="hide-summary-button" style="display: hidden;"> <div id="hide-summary-button" style="display: hidden;">
<a href="" class="btn btn-xs btn-primary" ng-click="toggleSummary('hide')" aw-tool-tip="Hide summary" data-placement="top"><i class="fa fa-arrow-circle-right"></i></a> <a href="" class="btn btn-xs btn-primary" ng-click="toggleSummary('hide')" aw-tool-tip="Hide summary" data-placement="top"><i class="fa fa-arrow-circle-right"></i></a>
</div> </div>
<div class="JobDetail-panelHeader">
<div class="JobDetail-expandContainer">
<a class="JobDetail-panelHeaderText" ng-show="lessEvents" href="" ng-click="toggleLessEvents()">
EVENT SUMMARY<i class="JobDetail-expandArrow fa fa-caret-left"></i>
</a>
<a class="JobDetail-panelHeaderText" ng-show="!lessEvents" href="" ng-click="toggleLessEvents()">
EVENT SUMMARY<i class="JobDetail-expandArrow fa fa-caret-down"></i>
</a>
</div>
</div>
<div id="events-summary">
<div id="hosts-summary-section" class="section"> <div id="hosts-summary-section" class="section">
<div class="JobDetail-searchHeaderRow">
<div class="row title-row"> <div class="JobDetail-searchContainer form-group">
<div class="col-lg-4 col-md-4 col-sm-4 title">Events Summary</div> <div class="search-name">
<div class="col-lg-8 col-md-8 col-sm-8" style="text-align:right;"> <input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_host_summary_name" ng-model="search_host_summary_name" placeholder="Host Name" ng-keypress="searchHostSummaryKeyPress($event)" >
<div id="task-search-form" class="search-form form-inline"> <a class="List-searchInputIcon search-icon" ng-show="searchHostSummaryEnabled" ng-click="searchHostSummary()"><i class="fa fa-search"></i></a>
<div class="form-group"> <a class="List-searchInputIcon search-icon" ng-show="!searchHostSummaryEnabled" ng-click="search_host_summary_name=''; searchHostSummary()"><i class="fa fa-times"></i></a>
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_host_summary_name" ng-model="search_host_summary_name"
placeholder="Host Name" ng-keypress="searchHostSummaryKeyPress($event)" >
<div id="search-all-input-icons">
<a class="search-icon" ng-show="searchHostSummaryEnabled" ng-click="searchHostSummary()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchHostSummaryEnabled" ng-click="search_host_summary_name=''; searchHostSummary()"><i class="fa fa-times"></i></a>
</div>
</div>
</div> </div>
<div class="form-group"> </div>
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus"> <div class="JobDetail-tableToggleContainer form-group">
<button class="btn btn-xs btn-primary active">All</button> <div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus">
<button class="btn btn-xs btn-default">Failed</button> <button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
</div> <button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="row legend-row">
<div class="col-md-12">
<div class="legend"><i class="fa fa-circle successful-hosts-color"></i> OK <i class="fa fa-circle changed-hosts-color"></i> Changed
<i class="fa fa-circle unreachable-hosts-color"></i> Unreachable <i class="fa fa-circle failed-hosts-color"></i> Failed</div>
</div>
</div>
<div class="table-header"> <div class="table-header">
<table class="table table-condensed"> <table class="table table-condensed">
<thead> <thead>
<tr> <tr>
<th class="col-lg-6 col-md-6 col-sm-6 col-xs-6">Host</th> <th class="List-tableHeader col-lg-5 col-md-6 col-sm-6 col-xs-6">Hosts</th>
<th class="col-lg-5 col-md-5 col-sm-5 col-xs-5">Completed Tasks</th> <th class="List-tableHeader col-lg-5 col-md-5 col-sm-5 col-xs-5">Completed Tasks</th>
<th class="col-lg-1 col-md-1 col-sm-1 col-xs-1"></th> <th class="List-tableHeader col-lg-2 col-md-1 col-sm-1 col-xs-1">Actions</th>
</tr> </tr>
</thead> </thead>
</table> </table>
</div> </div>
<div id="hosts-summary-table" class="table-detail" lr-infinite-scroll="hostSummariesScrollDown" scroll-threshold="10" time-threshold="500"> <div id="hosts-summary-table" class="table-detail" lr-infinite-scroll="hostSummariesScrollDown" scroll-threshold="10" time-threshold="500">
<table class="table table-condensed"> <table class="table">
<tbody> <tbody>
<tr ng-repeat="host in summaryList = (hosts) track by $index" id="{{ host.id }}"> <tr class="List-tableRow" ng-repeat="host in summaryList = (hosts) track by $index" id="{{ host.id }}" ng-class-even="'List-tableRow--evenRow'" ng-class-odd="'List-tableRow--oddRow'">
<td class="name col-lg-6 col-md-6 col-sm-6 col-xs-6"><a href="" ng-click="hostEventsViewer(host.id, host.name)" aw-tool-tip="View all events" data-placement="top">{{ host.name }}</a></td> <td class="List-tableCell name col-lg-6 col-md-6 col-sm-6 col-xs-6"><a href="" ng-click="hostEventsViewer(host.id, host.name)" aw-tool-tip="View events" data-placement="top">{{ host.name }}</a></td>
<td class="col-lg-5 col-md-5 col-sm-5 col-xs-5 badge-column"> <td class="List-tableCell col-lg-5 col-md-5 col-sm-5 col-xs-5 badge-column">
<a href="" ng-click="hostEventsViewer(host.id, host.name, 'ok')" aw-tool-tip="{{ host.okTip }}" data-tip-watch="host.okTip" data-placement="top" ng-hide="host.ok == 0"><span class="badge successful-hosts">{{ host.ok }}</span></a> <a href="" ng-click="hostEventsViewer(host.id, host.name, 'ok')" aw-tool-tip="{{ host.okTip }}" data-tip-watch="host.okTip" data-placement="top" ng-hide="host.ok == 0"><span class="badge successful-hosts">{{ host.ok }}</span></a>
<a href="" ng-click="hostEventsViewer(host.id, host.name, 'changed')" aw-tool-tip="{{ host.changedTip }}" data-tip-watch="host.changedTip" data-placement="top" ng-hide="host.changed == 0"><span class="badge changed-hosts">{{ host.changed }}</span></a> <a href="" ng-click="hostEventsViewer(host.id, host.name, 'changed')" aw-tool-tip="{{ host.changedTip }}" data-tip-watch="host.changedTip" data-placement="top" ng-hide="host.changed == 0"><span class="badge changed-hosts">{{ host.changed }}</span></a>
<a href="" ng-click="hostEventsViewer(host.id, host.name, 'unreachable')" aw-tool-tip="{{ host.unreachableTip }}" data-tip-watch="host.unreachableTip" data-placement="top" ng-hide="host.unreachable == 0"><span class="badge unreachable-hosts">{{ host.unreachable }}</span></a> <a href="" ng-click="hostEventsViewer(host.id, host.name, 'unreachable')" aw-tool-tip="{{ host.unreachableTip }}" data-tip-watch="host.unreachableTip" data-placement="top" ng-hide="host.unreachable == 0"><span class="badge unreachable-hosts">{{ host.unreachable }}</span></a>
<a href="" ng-click="hostEventsViewer(host.id, host.name, 'failed')" aw-tool-tip="{{ host.failedTip }}" data-tip-watch="host.failedTip" data-placement="top" ng-hide="host.failed == 0"><span class="badge failed-hosts">{{ host.failed }}</span></a></td> <a href="" ng-click="hostEventsViewer(host.id, host.name, 'failed')" aw-tool-tip="{{ host.failedTip }}" data-tip-watch="host.failedTip" data-placement="top" ng-hide="host.failed == 0"><span class="badge failed-hosts">{{ host.failed }}</span></a></td>
<td class="col-lg-1 col-md-1 col-sm-1 col-xs-1"><a ng-show="host.id" href="" ng-click="editHost(host.id)" aw-tool-tip="Edit host" data-placement="top"><i class="fa fa-pencil"></i></a></td> <td class="List-actionButtonCell List-tableCell col-lg-2 col-md-1 col-sm-1 col-xs-1">
<button class="List-actionButton " ng-show="host.id" data-placement="top" ng-click="editHost(host.id)" aw-tool-tip="Edit host" data-original-title="" title=""><i class="fa fa-pencil"></i></button>
</td>
</tr> </tr>
<tr ng-show="summaryList.length === 0 && waiting"> <tr ng-show="summaryList.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td> <td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
@@ -454,27 +435,16 @@
</div> </div>
<div class="scroll-spinner" id="hostSummariesMoreRows"><i class="fa fa-cog fa-spin"></i></div> <div class="scroll-spinner" id="hostSummariesMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section --> </div><!-- section -->
</div><!-- summary-well-top-section --> <div id="graph-section" class="JobDetail-graphSection">
<svg width="100%" height="100%"></svg>
<div class="row host_summary_row">
<div class="title">Host Summary</div>
<!-- <div ng-repeat="graph_data_object in graph_data">
<span>{{ (graph_data_object.value/total_count_for_graph) * 100 | number : 1 }}% of hosts <span style="color: {{ graph_data_object.color }}">{{ graph_data_object.label }}</span>.<br /></span>
</div> -->
</div> </div>
<div id="graph-section" >
<!-- <div class="header">
<div class="legend" style="display: none;"><i class="fa fa-circle successful-hosts-color"></i> OK <i class="fa fa-circle changed-hosts-color"></i> Changed
<i class="fa fa-circle unreachable-hosts-color"></i> Unreachable <i class="fa fa-circle failed-hosts-color"></i> Failed</div>
</div> -->
</div><!-- graph section -->
</div> </div>
</div>
</div> <!--end of job-detail-container-->
</div><!-- col-md-5 --> </div><!-- col-md-5 -->
</div> </div>
<div id="job-detail-footer" class="footer-row"></div>
</div> </div>
<div ng-include="'/static/partials/eventviewer.html'"></div> <div ng-include="'/static/partials/eventviewer.html'"></div>

View File

@@ -161,6 +161,9 @@
@db-graph-axis: @default-border; @db-graph-axis: @default-border;
@db-graph-axis-label: @default-interface-txt; @db-graph-axis-label: @default-interface-txt;
//job detail
@toggle-selected-text: #eeeeee;
// panel // panel
@panel-bg: @default-bg; @panel-bg: @default-bg;
@panel-border: @default-border; @panel-border: @default-border;