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
commit d6bd2abbd0
7 changed files with 384 additions and 386 deletions

View File

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

View File

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

View File

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

View File

@ -3,9 +3,20 @@
@import '../shared/branding/colors.less';
@import '../shared/branding/colors.default.less';
.JobDetail-leftSide{
width: 50%;
}
.JobDetail-panelHeader{
height: 50px;
display: flex;
height: 30px;
}
.JobDetail-expandContainer{
flex: 1;
margin: 0px;
line-height: 30px;
white-space: nowrap;
}
.JobDetail-panelHeaderText{
@ -52,7 +63,71 @@
flex: 1 0 auto;
}
.JobDetail-resultRow--variables{
width: 90%;
display: block;
}
.JobDetail-resultRowText{
width: 40%;
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',
'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit',
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
'EditSchedule',
'EditSchedule', 'ParseTypeChange',
function(
$location, $rootScope, $filter, $scope, $compile, $stateParams,
$log, ClearScope, GetBasePath, Wait, Rest, ProcessErrors,
@ -28,7 +28,7 @@ export default
SetTaskStyles, DigestEvent, UpdateDOM, EventViewer, DeleteJob,
PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts,
HostsEdit, ParseVariableString, GetChoices, fieldChoices,
fieldLabels, EditSchedule
fieldLabels, EditSchedule, ParseTypeChange
) {
ClearScope();
@ -41,7 +41,7 @@ export default
job_type_options;
scope.plays = [];
scope.parseType = 'yaml';
scope.previousTaskFailed = false;
scope.$watch('job_status', function(job_status) {
@ -201,6 +201,8 @@ export default
scope.haltEventQueue = false;
scope.processing = false;
scope.lessStatus = false;
scope.lessDetail = false;
scope.lessEvents = false;
scope.host_summary = {};
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]) {
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');
})
@ -675,7 +677,7 @@ export default
scope.host_summary.failed;
});
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);
})
@ -804,6 +806,7 @@ export default
return true;
});
//scope.setSearchAll('host');
ParseTypeChange({ scope: scope, field_id: 'pre-formatted-variables' });
scope.$emit('LoadPlays', data.related.job_events);
})
.error(function(data, status) {
@ -839,7 +842,6 @@ export default
$('.overlay').hide();
$('#summary-button').hide();
$('#hide-summary-button').hide();
$('#job-detail-container').css({ "width": "58.33333333%", "padding-right": "7px" });
$('#job-summary-container .job_well').css({
'box-shadow': 'none',
'height': 'auto'
@ -859,12 +861,12 @@ export default
// Detail table height adjusting. First, put page height back to 'normal'.
$('#plays-table-detail').height(80);
//$('#plays-table-detail').mCustomScrollbar("update");
$('#tasks-table-detail').height(120);
// $('#tasks-table-detail').height(120);
//$('#tasks-table-detail').mCustomScrollbar("update");
$('#hosts-table-detail').height(150);
//$('#hosts-table-detail').mCustomScrollbar("update");
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) {
// there's a bunch of white space at the bottom, let's use it
$('#plays-table-detail').height(80 + (height * 0.10));
@ -872,10 +874,9 @@ export default
$('#hosts-table-detail').height(150 + (height * 0.70));
}
// Summary table height adjusting.
height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .header').outerHeight() -
$('#hosts-summary-section .table-header').outerHeight() -
$('#summary-search-section').outerHeight() - 20;
$('#hosts-summary-table').height(height);
height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .JobDetail-searchHeaderRow').outerHeight() -
$('#hosts-summary-section .table-header').outerHeight() - 20;
// $('#hosts-summary-table').height(height);
//$('#hosts-summary-table').mCustomScrollbar("update");
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.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {

View File

@ -1,17 +1,21 @@
<div class="tab-pane" id="jobs-detail">
<div ng-cloak id="htmlTemplate">
<div class="row" style="position: relative;">
<div id="job-detail-container">
<div class="JobDetail-resultsContainer Panel">
<div id="job-detail-container" class="JobDetail-leftSide">
<div id="job-results-panel" class="JobDetail-resultsContainer Panel">
<div class="JobDetail-panelHeader">
<a class="JobDetail-panelHeaderText" ng-show="lessStatus" href="" ng-click="toggleLessStatus()">
RESULTS<i class="JobDetail-expandArrow fa fa-caret-left"></i>
</a>
<a class="JobDetail-panelHeaderText" ng-show="!lessStatus" href="" ng-click="toggleLessStatus()">
RESULTS<i class="JobDetail-expandArrow fa fa-caret-down"></i>
</a>
<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 class="JobDetail-expandContainer">
<a class="JobDetail-panelHeaderText" ng-show="lessStatus" href="" ng-click="toggleLessStatus()">
RESULTS<i class="JobDetail-expandArrow fa fa-caret-left"></i>
</a>
<a class="JobDetail-panelHeaderText" ng-show="!lessStatus" href="" ng-click="toggleLessStatus()">
RESULTS<i class="JobDetail-expandArrow fa fa-caret-down"></i>
</a>
</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 class="form-horizontal JobDetail-resultsDetails" role="form" id="job-status-form">
@ -21,9 +25,9 @@
</div>
<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>
<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>
<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
<a
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>
<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">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Template</label>
<div class="JobDetail-resultRowText">
@ -68,11 +56,21 @@
</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">
<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>
<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">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText">
@ -80,6 +78,11 @@
</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">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText">
@ -140,66 +143,67 @@
<div class="JobDetail-resultRowText">{{ job.job_tags }}</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>
<div class="JobDetail-resultRowText">
<div id="pre-formatted-variables">{{ variables }}</div>
<!-- <pre>{{ variables }}</pre> -->
</div>
<textarea rows="6" ng-model="variables" name="variables" id="pre-formatted-variables"></textarea>
</div>
</div>
</div>
<!--- JobDetail-results---------------------------------------------->
<div id="job-detail-tables">
<div id="play-section" class="section">
<div id="job-detail-panel" class="JobDetail-resultsContainer Panel">
<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 class="col-lg-1 col-md-2 col-sm-2 col-xs-1 title">Plays</div>
<div class="col-lg-11 col-md-10 col-sm-10 col-xs-11" style="text-align:right;">
<div id="play-search-form" class="search-form form-inline">
<div class="form-group">
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_play_name" ng-model="search_play_name"
placeholder="Play Name" ng-keypress="searchPlaysKeyPress($event)" >
<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 id="job-detail-details">
<div id="play-section">
<div class="JobDetail-searchHeaderRow">
<div class="JobDetail-searchContainer form-group">
<div class="search-name">
<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)" >
<a class="List-searchInputIcon search-icon" ng-show="searchPlaysEnabled" ng-click="searchPlays()"><i class="fa fa-search"></i></a>
<a class="List-searchInputIcon search-icon" ng-show="!searchPlaysEnabled" ng-click="search_play_name=''; searchPlays()"><i class="fa fa-times"></i></a>
</div>
<div class="form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterPlayStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
</div>
</div>
<div class="JobDetail-tableToggleContainer form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterPlayStatus">
<button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
<button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div>
</div>
</div>
</div>
<div id="plays-table-header" class="table-header">
<table class="table table-condensed">
<thead>
<tr>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
<th class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column">Status</th>
<th class="col-lg-7 col-md-6 col-sm-6 col-xs-4">Name</th>
<th class="List-tableHeader col-lg-7 col-md-6 col-sm-6 col-xs-4">Plays</th>
<th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="List-tableHeader JobDetail-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
</tr>
</thead>
</table>
</div>
<div id="plays-table-detail" class="table-detail" lr-infinite-scroll="playsScrollDown"
scroll-threshold="10" time-threshold="500">
<table class="table table-condensed">
<table class="table">
<tbody>
<tr class="cursor-pointer" ng-repeat="play in plays" 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="col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ play.finishedTip }}" data-tip-watch="play.finishedTip"
<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="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="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>
<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 ng-show="plays.length === 0 && waiting">
<td colspan="4" class="col-lg-12 loading-info">Waiting...</td>
@ -213,31 +217,24 @@
</tbody>
</table>
</div>
<div class="scroll-spinner" id="playsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section -->
<div class="scroll-spinner" id="playsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</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="col-lg-1 col-md-2 col-sm-2 title">Tasks</div>
<div class="col-lg-11 col-md-10 col-sm-10" style="text-align:right;">
<div id="task-search-form" class="search-form form-inline">
<div class="form-group">
<div class="search-name" style="display:inline-block; position:relative;">
<input type="text" class="input-xs form-control" id="search_task_name" ng-model="search_task_name"
placeholder="Task Name" ng-keypress="searchTasksKeyPress($event)" >
<div id="search-all-input-icons">
<a class="search-icon" ng-show="searchTasksEnabled" ng-click="searchTasks()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchTasksEnabled" ng-click="search_task_name=''; searchTasks()"><i class="fa fa-times"></i></a>
</div>
</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 class="JobDetail-searchHeaderRow">
<div class="JobDetail-searchContainer form-group">
<div class="search-name">
<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)" >
<a class="List-searchInputIcon search-icon" ng-show="searchTasksEnabled" ng-click="searchTasks()"><i class="fa fa-search"></i></a>
<a class="List-searchInputIcon search-icon" ng-show="!searchTasksEnabled" ng-click="search_task_name=''; searchTasks()"><i class="fa fa-times"></i></a>
</div>
</div>
<div class="JobDetail-tableToggleContainer form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterTaskStatus">
<button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
<button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div>
</div>
</div>
@ -246,46 +243,46 @@
<table id="tasks-table-header" class="table table-condensed">
<thead>
<tr>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
<th class="col-lg-1 col-md-2 col-sm-2 col-xs-2 status-column">Status</th>
<th class="col-lg-3 col-md-3 col-sm-6 col-xs-4">Name</div>
<th class="col-lg-4 col-md-3 hidden-xs hidden-sm">Host Status</th>
<th class="List-tableHeader col-lg-3 col-md-3 col-sm-6 col-xs-4">Tasks</div>
<th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Started</th>
<th class="List-tableHeader col-lg-2 col-md-2 col-sm-2 col-xs-3">Elapsed</th>
<th class="List-tableHeader JobDetail-tableHeader col-lg-4 col-md-3 hidden-xs hidden-sm">Host Status</th>
</tr>
</thead>
</table>
</div>
<div id="tasks-table-detail" class="table-detail" lr-infinite-scroll="tasksScrollDown"
scroll-threshold="10" time-threshold="500">
<table class="table table-condensed">
<table class="table">
<tbody>
<tr class="cursor-pointer" 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="col-lg-2 col-md-2 col-sm-2 col-xs-3" aw-tool-tip="{{ task.finishedTip }}" data-tip-watch="task.finishedTip"
<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="List-tableCell col-lg-3 col-md-3 col-sm-6 col-xs-4 status-column" aw-tool-tip="{{ task.status_tip }}"
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>
<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="col-lg-3 col-md-3 col-sm-6 col-xs-4" id="">{{ task.name }}</td>
<td class="col-lg-4 col-md-3 hidden-sm hidden-xs">
<div class="status-bar">
<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">
{{ task.successfulCount }}
</div>
<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">
{{ task.changedCount }}
</div>
<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">
{{ task.skippedCount }}
</div>
<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">
{{ task.failedCount }}
</div>
<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">
{{ task.unreachableCount }}
</div>
<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">
{{ task.missingCount }}
</div>
<td class="List-tableCell col-lg-4 col-md-3 hidden-sm hidden-xs">
<div>
<a href="" 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>
</a>
<a href="" 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>
</a>
<a href="" 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>
</a>
<a href="" 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>
</a>
<a href="" id="{{ task.id }}-unreachable-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>
</a>
<a href="" id="{{ task.id }}-missing-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>
</a>
<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.
</div>
@ -308,54 +305,44 @@
</div><!-- section -->
<div id="task-hosts-section" class="section">
<div class="row title-row">
<div class="col-lg-2 col-md-2 col-sm-2 title">Host Events</div>
<div class="col-lg-10 col-md-10 col-sm-10" style="text-align:right;">
<div id="host-search-form" class="search-form form-inline">
<div class="form-group">
<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 class="JobDetail-searchHeaderRow">
<div class="JobDetail-searchContainer form-group">
<div class="search-name">
<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)" >
<a class="List-searchInputIcon search-icon" ng-show="searchHostsEnabled" ng-click="searchHosts()"><i class="fa fa-search"></i></a>
<a class="List-searchInputIcon search-icon" ng-show="!searchHostsEnabled" ng-click="search_host_name=''; searchHosts()"><i class="fa fa-times"></i></a>
</div>
<div class="form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
</div>
</div>
<div class="JobDetail-tableToggleContainer form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostStatus">
<button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
<button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</div>
</div>
</div>
</div>
<div class="table-header" id="hosts-table-header">
<table class="table table-condensed">
<thead>
<tr>
<th class="col-lg-1 col-md-1 col-sm-2 col-xs-2 status-column">Status</th>
<th class="col-lg-3 col-md-3 col-sm-3 col-xs-3">Host</th>
<th class="col-lg-4 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">Message</th>
<th class="col-lg-1 col-md-1 col-sm-1 col-xs-1"></th>
<th class="List-tableHeader col-lg-3 col-md-3 col-sm-3 col-xs-3">Hosts</th>
<th class="List-tableHeader col-lg-3 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="List-tableHeader col-lg-2 col-md-1 col-sm-1 col-xs-1">Actions</th>
</tr>
</thead>
</table>
</div>
<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>
<tr 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="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="col-lg-4 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">{{ result.msg }}</td>
<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>
<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="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="List-tableCell col-lg-3 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="List-actionButtonCell List-tableCell col-lg-1 col-md-1 col-sm-1 col-xs-1">
<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 ng-show="results.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
@ -370,75 +357,69 @@
</table>
</div>
<div class="scroll-spinner" id="hostResultsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section -->
</div><!-- job-detail-tables -->
</div>
</div>
</div>
</div><!-- job-detail-container -->
<!-- <div id="job-summary-container"> -->
<div class="job_well">
<div id="events-summary-panel" class="JobDetail-resultsContainer Panel">
<div id="summary-well-top-section">
<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>
</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 class="row title-row">
<div class="col-lg-4 col-md-4 col-sm-4 title">Events Summary</div>
<div class="col-lg-8 col-md-8 col-sm-8" style="text-align:right;">
<div id="task-search-form" class="search-form form-inline">
<div class="form-group">
<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 class="JobDetail-searchHeaderRow">
<div class="JobDetail-searchContainer form-group">
<div class="search-name">
<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)" >
<a class="List-searchInputIcon search-icon" ng-show="searchHostSummaryEnabled" ng-click="searchHostSummary()"><i class="fa fa-search"></i></a>
<a class="List-searchInputIcon search-icon" ng-show="!searchHostSummaryEnabled" ng-click="search_host_summary_name=''; searchHostSummary()"><i class="fa fa-times"></i></a>
</div>
<div class="form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus">
<button class="btn btn-xs btn-primary active">All</button>
<button class="btn btn-xs btn-default">Failed</button>
</div>
</div>
<div class="JobDetail-tableToggleContainer form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus">
<button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
<button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
</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">
<table class="table table-condensed">
<thead>
<tr>
<th class="col-lg-6 col-md-6 col-sm-6 col-xs-6">Host</th>
<th class="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-5 col-md-6 col-sm-6 col-xs-6">Hosts</th>
<th class="List-tableHeader col-lg-5 col-md-5 col-sm-5 col-xs-5">Completed Tasks</th>
<th class="List-tableHeader col-lg-2 col-md-1 col-sm-1 col-xs-1">Actions</th>
</tr>
</thead>
</table>
</div>
<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>
<tr ng-repeat="host in summaryList = (hosts) track by $index" id="{{ host.id }}">
<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="col-lg-5 col-md-5 col-sm-5 col-xs-5 badge-column">
<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="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="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, '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, '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 ng-show="summaryList.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
@ -454,27 +435,16 @@
</div>
<div class="scroll-spinner" id="hostSummariesMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section -->
</div><!-- summary-well-top-section -->
<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 id="graph-section" class="JobDetail-graphSection">
<svg width="100%" height="100%"></svg>
</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> <!--end of job-detail-container-->
</div><!-- col-md-5 -->
</div>
<div id="job-detail-footer" class="footer-row"></div>
</div>
<div ng-include="'/static/partials/eventviewer.html'"></div>

View File

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