1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Merge pull request #1114 from jaredevantabor/job-detail-stdout

Adding Standard Out and other Job Detail things
This commit is contained in:
Jared Tabor 2016-03-04 07:43:33 -08:00
commit 75ecafb6ff
8 changed files with 510 additions and 425 deletions

View File

@ -214,9 +214,7 @@
}
#job-detail-container {
position: relative;
padding-left: 15px;
padding-right: 7px;
.well {
overflow: hidden;
}

View File

@ -975,7 +975,7 @@ var tower = angular.module('Tower', [
$log.debug("sending status to standard out");
$rootScope.$emit('JobStatusChange-jobStdout', data);
} else if ($state.is('jobDetail')) {
} if ($state.is('jobDetail')) {
$rootScope.$emit('JobStatusChange-jobDetails', data);
} else if ($state.is('dashboard')) {
$rootScope.$emit('JobStatusChange-home', data);

View File

@ -235,7 +235,7 @@ export default
}
if (newActivePlay) {
scope.activePlay = newActivePlay;
scope.jobData.plays[scope.activePlay].playActiveClass = 'List-tableRow--selected';
scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected';
}
}
};
@ -265,7 +265,7 @@ export default
}
if (newActiveTask) {
scope.activeTask = newActiveTask;
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'List-tableRow--selected';
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'JobDetail-tableRow--selected';
}
}
};
@ -793,7 +793,7 @@ export default
scope.selectedPlay = id;
scope.plays.forEach(function(play, idx) {
if (play.id === scope.selectedPlay) {
scope.plays[idx].playActiveClass = 'List-tableRow--selected';
scope.plays[idx].playActiveClass = 'JobDetail-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 = 'List-tableRow--selected';
scope.tasks[idx].taskActiveClass = 'JobDetail-tableRow--selected';
}
else {
scope.tasks[idx].taskActiveClass = '';
@ -1142,8 +1142,7 @@ export default
.factory('DrawGraph', ['DonutChart', function(DonutChart) {
return function(params) {
var scope = params.scope,
resize = params.resize,
width, height, svg_height, svg_width, svg_radius, graph_data = [];
graph_data = [];
// Ready the data
if (scope.host_summary.ok) {
@ -1192,7 +1191,9 @@ export default
element = $("#graph-section"),
colors, total,job_detail_chart;
colors = ['#60D66F', '#FF9900','#FF0000','#ff5850'];
colors = _.map(dataset, function(d){
return d.color;
});
total = d3.sum(dataset.map(function(d) {
return d.value;
}));
@ -1221,6 +1222,7 @@ export default
"font-weight":400,
"src": "url(/static/assets/OpenSans-Regular.ttf)"
});
d3.select(element.find(".nv-label text")[0])
.attr("class", "DashboardGraphs-hostStatusLabel--successful")
.style({
@ -1228,7 +1230,7 @@ export default
"text-anchor": "start",
"font-size": "16px",
"text-transform" : "uppercase",
"fill" : '#3CB878',
"fill" : colors[0],
"src": "url(/static/assets/OpenSans-Regular.ttf)"
});
d3.select(element.find(".nv-label text")[1])
@ -1238,7 +1240,7 @@ export default
"text-anchor" : "end !imporant",
"font-size": "16px",
"text-transform" : "uppercase",
"fill" : "#FF9900",
"fill" : colors[1],
"src": "url(/static/assets/OpenSans-Regular.ttf)"
});
d3.select(element.find(".nv-label text")[2])
@ -1248,7 +1250,7 @@ export default
"text-anchor" : "end !imporant",
"font-size": "16px",
"text-transform" : "uppercase",
"fill" : "#FF0000",
"fill" : colors[2],
"src": "url(/static/assets/OpenSans-Regular.ttf)"
});
d3.select(element.find(".nv-label text")[3])
@ -1258,7 +1260,7 @@ export default
"text-anchor" : "end !imporant",
"font-size": "16px",
"text-transform" : "uppercase",
"fill" : "#ff5850",
"fill" : colors[3],
"src": "url(/static/assets/OpenSans-Regular.ttf)"
});
return job_detail_chart;

View File

@ -3,7 +3,19 @@
@import '../shared/branding/colors.less';
@import '../shared/branding/colors.default.less';
.JobDetail{
display: flex;
flex-direction: row;
}
.JobDetail-leftSide{
flex: 1 0 auto;
width: 50%;
padding-right: 20px;
}
.JobDetail-rightSide{
flex: 1 0 auto;
width: 50%;
}
@ -49,6 +61,7 @@
display: flex;
flex-wrap: wrap;
flex-direction: row;
padding-top: 25px;
}
.JobDetail-resultRow{
@ -56,6 +69,10 @@
display: flex;
}
.JobDetail-resultRowLabel{
text-transform: uppercase;
}
.JobDetail-resultRow label{
color: @default-interface-txt;
font-size: 14px;
@ -64,14 +81,26 @@
}
.JobDetail-resultRow--variables{
width: 90%;
display: block;
width: 100%;
display: flex;
flex-direction: column;
padding-left:15px;
}
.JobDetail-extraVars{
text-transform: none;
}
.JobDetail-extraVarsLabel{
margin-left:-15px;
padding-bottom: 15px;
}
.JobDetail-resultRowText{
width: 40%;
flex: 1 0 auto;
padding:0px;
text-transform: none;
}
.JobDetail-searchHeaderRow{
@ -101,7 +130,7 @@
.JobDetail-tableToggle.active{
background-color: @default-link;
border: 1px solid @default-link;
color: @toggle-selected-text;
color: @default-bg;
}
.JobDetail-tableToggle--left{
@ -127,7 +156,27 @@
padding-left: 10px;
}
.JobDetail-tableRow--selected,
.JobDetail-tableRow--selected > :first-child{
border-left: 5px solid @list-row-select-bord;
}
.JobDetail-tableRow--selected > :first-child > .JobDetail-statusIcon{
margin-left: -5px;
}
.JobDetail-statusIcon--results{
padding-left: 0px;
padding-right: 10px;
}
.JobDetail-graphSection{
height: 320px;
width:100%;
}
.JobDetail-stdoutActionButton--active{
flex:none;
width:0px;
padding-right: 0px;
}

View File

@ -43,6 +43,7 @@ export default
scope.plays = [];
scope.parseType = 'yaml';
scope.previousTaskFailed = false;
$scope.stdoutFullScreen = false;
scope.$watch('job_status', function(job_status) {
if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") {
@ -202,7 +203,7 @@ export default
scope.processing = false;
scope.lessStatus = false;
scope.lessDetail = false;
scope.lessEvents = false;
scope.lessEvents = true;
scope.host_summary = {};
scope.host_summary.ok = 0;
@ -557,7 +558,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 = 'List-tableRow--selected';
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].taskActiveClass = 'JobDetail-tableRow--selected';
}
scope.$emit('LoadHosts');
})
@ -677,7 +678,7 @@ export default
scope.host_summary.failed;
});
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
scope.jobData.plays[scope.activePlay].playActiveClass = 'List-tableRow--selected';
scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected';
}
scope.$emit('LoadTasks', events_url);
})
@ -981,11 +982,11 @@ export default
scope.toggleLessStatus = function() {
if (!scope.lessStatus) {
$('#job-status-form .toggle-show').slideUp(200);
$('#job-status-form').slideUp(200);
scope.lessStatus = true;
}
else {
$('#job-status-form .toggle-show').slideDown(200);
$('#job-status-form').slideDown(200);
scope.lessStatus = false;
}
};
@ -1009,6 +1010,7 @@ export default
else {
$('#events-summary').slideDown(200);
scope.lessEvents = false;
DrawGraph({scope:scope});
}
};
@ -1432,16 +1434,10 @@ export default
$scope.$emit('LoadJob');
};
scope.editHost = function(id) {
HostsEdit({
host_scope: scope,
group_scope: null,
host_id: id,
inventory_id: scope.job.inventory,
mode: 'edit', // 'add' or 'edit'
selected_group_id: null
});
};
// Click binding for the expand/collapse button on the standard out log
$scope.toggleStdoutFullscreen = function() {
$scope.stdoutFullScreen = !$scope.stdoutFullScreen;
}
scope.editSchedule = function() {
// We need to get the schedule's ID out of the related links

View File

@ -1,238 +1,406 @@
<div class="tab-pane" id="jobs-detail">
<div ng-cloak id="htmlTemplate">
<div class="row" style="position: relative;">
<div id="job-detail-container" class="JobDetail-leftSide">
<div id="job-results-panel" class="JobDetail-resultsContainer Panel">
<div class="JobDetail-panelHeader">
<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 ng-cloak id="htmlTemplate" class="JobDetail">
<!--beginning of job-detail-container (left side) -->
<div id="job-detail-container" class="JobDetail-leftSide" ng-class="{'JobDetail-stdoutActionButton--active': stdoutFullScreen}">
<!--beginning of results-->
<div id="job-results-panel" class="JobDetail-resultsContainer Panel" ng-show="!stdoutFullScreen">
<div class="JobDetail-panelHeader">
<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="form-horizontal JobDetail-resultsDetails" role="form" id="job-status-form">
<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">Status</label>
<div class="JobDetail-resultRowText"><i class="fa icon-job-{{ job_status.status }}"></i> {{ job_status.status_label }}</div>
</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="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="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=""
id="explanation_help"
aw-pop-over="{{ task_detail }}"
aw-pop-over-watch="task_detail"
data-placement="bottom"
data-container="body" class="help-link" over-title="Failure Detail"
title=""
tabindex="-1">
<i class="fa fa-question-circle">
</i>
</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.traceback">
<label class="col-lg-2 col-md-12 col-sm-12 col-xs-12">Results Traceback</label>
<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_template_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Template</label>
<div class="JobDetail-resultRowText">
<a href="{{ job_template_url }}" aw-tool-tip="Edit the job template" data-placement="top">{{ job_template_name }}</a>
</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">
<a href="{{ users_url }}" aw-tool-tip="Edit the User" data-placement="top">{{ created_by }}</a>
</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">
<a href aw-tool-tip="Edit the Schedule" data-placement="top" ng-click="editSchedule()">{{scheduled_by}}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="inventory_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Inventory</label>
<div class="JobDetail-resultRowText">
<a href="{{ inventory_url }}" aw-tool-tip="Edit the inventory" data-placement="top">{{ inventory_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="project_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Project</label>
<div class="JobDetail-resultRowText">
<a href="{{ project_url }}" aw-tool-tip="Edit the project" data-placement="top">{{ project_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.playbook">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Playbook</label>
<div class="JobDetail-resultRowText">{{ job.playbook }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="credential_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Machine Credential</label>
<div class="JobDetail-resultRowText JobDetail-resultRowText">
<a href="{{ credential_url }}" aw-tool-tip="Edit the credential" data-placement="top">{{ credential_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="cloud_credential_name">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Cloud Credential</label>
<div class="JobDetail-resultRowText">
<a href="{{ cloud_credential_url }}" aw-tool-tip="Edit the credential" data-placement="top">{{ cloud_credential_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.forks">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Forks</label>
<div class="JobDetail-resultRowText">{{ job.forks }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.limit">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Limit</label>
<div class="JobDetail-resultRowText">{{ job.limit }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="verbosity">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Verbosity</label>
<div class="JobDetail-resultRowText">{{ verbosity }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.job_tags">
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Job Tags</label>
<div class="JobDetail-resultRowText">{{ job.job_tags }}</div>
</div>
<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>
<textarea rows="6" ng-model="variables" name="variables" id="pre-formatted-variables"></textarea>
</div>
<div class="JobDetail-actions">
<button id="relaunch-job-button" class="List-actionButton JobDetail-launchButton" data-placement="top" mode="all" ng-click="relaunchJob()" aw-tool-tip="Relaunch using the same parameters" data-original-title="" title=""><i class="fa fa-rocket"></i> </button>
<button id="cancel-job-button" class="List-actionButton List-actionButton--delete JobDetail-launchButton" data-placement="top" ng-click="deleteJob()" ng-show="job_status.status == 'running' || job_status.status=='pending' " aw-tool-tip="Cancel" data-original-title="" title=""><i class="fa fa-minus-circle"></i> </button>
<button id="delete-job-button" class="List-actionButton List-actionButton--delete JobDetail-launchButton" data-placement="top" ng-click="deleteJob()" ng-hide="job_status.status == 'running' || job_status.status == 'pending' " aw-tool-tip="Delete" data-original-title="" title=""><i class="fa fa-trash-o"></i> </button>
</div>
</div>
<!--- JobDetail-results---------------------------------------------->
<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>
<div class="form-horizontal JobDetail-resultsDetails" role="form" id="job-status-form">
<div class="form-group JobDetail-resultRow toggle-show">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Status</label>
<div class="JobDetail-resultRowText"><i class="JobDetail-statusIcon--results fa icon-job-{{ job_status.status }}"></i> {{ job_status.status_label }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.explanation">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 col-xs-12">Explanation</label>
<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="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=""
id="explanation_help"
aw-pop-over="{{ task_detail }}"
aw-pop-over-watch="task_detail"
data-placement="bottom"
data-container="body" class="help-link" over-title="Failure Detail"
title=""
tabindex="-1">
<i class="fa fa-question-circle">
</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>
<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 id="plays-table-header" class="table-header">
<table class="table table-condensed">
<thead>
<tr>
<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">
<tbody>
<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>
</tr>
<tr ng-show="plays.length === 0 && waiting">
<td colspan="4" class="col-lg-12 loading-info">Waiting...</td>
</tr>
<tr ng-show="plays.length === 0 && playsLoading && !waiting">
<td colspan="4" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="plays.length === 0 && !playsLoading && !waiting">
<td colspan="4" class="col-lg-12 loading-info">No matching plays</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="playsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.traceback">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-12 col-sm-12 col-xs-12">Results Traceback</label>
<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>
<!-- end of plays section-->
<div id="task-section" class="section" >
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_template_name">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Template</label>
<div class="JobDetail-resultRowText">
<a href="{{ job_template_url }}" aw-tool-tip="Edit the job template" data-placement="top">{{ job_template_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="JobDetail-resultRowLabel 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="JobDetail-resultRowLabel 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="JobDetail-resultRowLabel 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="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText">
<a href="{{ users_url }}" aw-tool-tip="Edit the User" data-placement="top">{{ created_by }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
<label class="JobDetail-resultRowLabel 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="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Launched By</label>
<div class="JobDetail-resultRowText">
<a href aw-tool-tip="Edit the Schedule" data-placement="top" ng-click="editSchedule()">{{scheduled_by}}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="inventory_name">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Inventory</label>
<div class="JobDetail-resultRowText">
<a href="{{ inventory_url }}" aw-tool-tip="Edit the inventory" data-placement="top">{{ inventory_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="project_name">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Project</label>
<div class="JobDetail-resultRowText">
<a href="{{ project_url }}" aw-tool-tip="Edit the project" data-placement="top">{{ project_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.playbook">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Playbook</label>
<div class="JobDetail-resultRowText">{{ job.playbook }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="credential_name">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Machine Credential</label>
<div class="JobDetail-resultRowText JobDetail-resultRowText">
<a href="{{ credential_url }}" aw-tool-tip="Edit the credential" data-placement="top">{{ credential_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="cloud_credential_name">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Cloud Credential</label>
<div class="JobDetail-resultRowText">
<a href="{{ cloud_credential_url }}" aw-tool-tip="Edit the credential" data-placement="top">{{ cloud_credential_name }}</a>
</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.forks">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Forks</label>
<div class="JobDetail-resultRowText">{{ job.forks }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.limit">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Limit</label>
<div class="JobDetail-resultRowText">{{ job.limit }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="verbosity">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Verbosity</label>
<div class="JobDetail-resultRowText">{{ verbosity }}</div>
</div>
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job.job_tags">
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Job Tags</label>
<div class="JobDetail-resultRowText">{{ job.job_tags }}</div>
</div>
<div class="form-group JobDetail-resultRow JobDetail-resultRow--variables toggle-show" ng-show="variables">
<label class="JobDetail-resultRowLabel JobDetail-extraVarsLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Extra Variables</label>
<textarea rows="6" ng-model="variables" name="variables" class="JobDetail-extraVars" id="pre-formatted-variables"></textarea>
</div>
</div>
</div>
<!--- end of results-->
<!--beginning of details-->
<div id="job-detail-panel" class="JobDetail-resultsContainer Panel" ng-show="!stdoutFullScreen">
<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 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>
<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 id="plays-table-header" class="table-header">
<table class="table table-condensed">
<thead>
<tr>
<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">
<tbody>
<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>
</tr>
<tr ng-show="plays.length === 0 && waiting">
<td colspan="4" class="col-lg-12 loading-info">Waiting...</td>
</tr>
<tr ng-show="plays.length === 0 && playsLoading && !waiting">
<td colspan="4" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="plays.length === 0 && !playsLoading && !waiting">
<td colspan="4" class="col-lg-12 loading-info">No matching plays</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="playsMoreRows">
<i class="fa fa-cog fa-spin"></i>
</div>
</div>
<!-- end of plays section of details-->
<div id="task-section" class="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_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>
<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>
<div class="table-header">
<table id="tasks-table-header" class="table table-condensed">
<thead>
<tr>
<th class="List-tableHeader col-lg-3 col-md-3 col-sm-6 col-xs-4">Tasks</th>
<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">
<tbody>
<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="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>
</div>
</td>
</tr>
<tr ng-show="taskList.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
</tr>
<tr ng-show="taskList.length === 0 && tasksLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="taskList.length === 0 && !tasksLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">No matching tasks</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="tasksMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section -->
<!--end of tasks section of details-->
<div id="task-hosts-section" class="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_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>
<div class="JobDetail-tableToggleContainer form-group">
<div class="btn-group" aw-toggle-button data-after-toggle="filterTaskStatus">
<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 class="table-header" id="hosts-table-header">
<table class="table table-condensed">
<thead>
<tr>
<th class="List-tableHeader col-lg-4 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 JobDetail-tableHeader col-lg-3 col-md-4 col-sm-3 col-xs-3">Message</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">
<tbody>
<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-4 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>
</tr>
<tr ng-show="results.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
</tr>
<tr ng-show="results.length === 0 && hostResultsLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="results.length === 0 && !hostResultsLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">No matching host events</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="hostResultsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div>
<!--end of hosts section of details-->
</div>
</div>
<!--end of details-->
</div>
<!--end of job-detail-container (left side)-->
<!--beginning of stdout-->
<div class="JobDetail-rightSide">
<!--beginning of events summary-->
<div id="events-summary-panel" class="JobDetail-resultsContainer Panel" ng-show="!stdoutFullScreen">
<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" style="display:none">
<div id="hosts-summary-section" class="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_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>
<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>
@ -240,186 +408,29 @@
</div>
<div class="table-header">
<table id="tasks-table-header" class="table table-condensed">
<thead>
<tr>
<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">
<tbody>
<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="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>
</div>
</td>
</tr>
<tr ng-show="taskList.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
</tr>
<tr ng-show="taskList.length === 0 && tasksLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="taskList.length === 0 && !tasksLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">No matching tasks</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="tasksMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div><!-- section -->
<div id="task-hosts-section" class="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_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>
<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 class="table-header" id="hosts-table-header">
<table class="table table-condensed">
<thead>
<tr>
<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>
<th class="List-tableHeader col-lg-6 col-md-6 col-sm-6 col-xs-6">Hosts</th>
<th class="List-tableHeader JobDetail-tableHeader col-lg-6 col-md-5 col-sm-5 col-xs-5">Completed Tasks</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">
<tbody>
<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>
</tr>
<tr ng-show="results.length === 0 && hostResultsLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">Loading...</td>
</tr>
<tr ng-show="results.length === 0 && !hostResultsLoading && !waiting">
<td colspan="5" class="col-lg-12 loading-info">No matching host events</td>
</tr>
</tbody>
</table>
</div>
<div class="scroll-spinner" id="hostResultsMoreRows"><i class="fa fa-cog fa-spin"></i></div>
</div>
</div>
</div>
<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="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>
<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 class="table-header">
<table class="table table-condensed">
<thead>
<tr>
<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">
<tbody>
<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">
<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-6 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="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>
<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>
</tr>
<tr ng-show="summaryList.length === 0 && waiting">
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
@ -433,19 +444,42 @@
</tbody>
</table>
</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 id="graph-section" class="JobDetail-graphSection">
<svg width="100%" height="100%"></svg>
<div id="graph-section" class="JobDetail-graphSection">
<svg width="100%" height="100%"></svg>
</div>
</div>
<!--end of events summary-->
</div>
<!-- end of events summary-->
<div class="JobDetail-stdoutPanel Panel">
<div class="StandardOut-panelHeader">
<div class="StandardOut-panelHeaderText">STANDARD OUT</div>
<div class="StandardOut-panelHeaderActions">
<button class="StandardOut-actionButton" aw-tool-tip="Toggle Output" data-placement="top" ng-class="{'StandardOut-actionButton--active': stdoutFullScreen}" ng-click="toggleStdoutFullscreen()">
<i class="fa fa-arrows-alt"></i>
</button>
<a href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}">
<button class="StandardOut-actionButton" aw-tool-tip="Download Output" data-placement="top">
<i class="fa fa-download"></i>
</button>
</a>
</div>
</div>
</div>
</div> <!--end of job-detail-container-->
</div><!-- col-md-5 -->
<standard-out-log stdout-endpoint="job.related.stdout"></standard-out-log>
</div>
</div>
<!--end of stdout-->
</div>
</div>
<div ng-include="'/static/partials/eventviewer.html'"></div>

View File

@ -161,9 +161,6 @@
@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;

View File

@ -21,6 +21,15 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
// Open up a socket for events depending on the type of job
function openSockets() {
if ($state.current.name == 'jobDetail') {
$log.debug("socket watching on job_events-" + job_id);
$rootScope.event_socket.on("job_events-" + job_id, function() {
$log.debug("socket fired on job_events-" + job_id);
if (api_complete) {
event_queue++;
}
});
}
if ($state.current.name == 'adHocJobStdout') {
$log.debug("socket watching on ad_hoc_command_events-" + job_id);
$rootScope.adhoc_event_socket.on("ad_hoc_command_events-" + job_id, function() {
@ -108,7 +117,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
function getNextSection() {
// get the next range of data from the API
var start = loaded_sections[loaded_sections.length - 1].end, url;
url = stdout_url + '?format=json&start_line=' + start + '&end_line=' + (start + page_size);
url = $scope.stdoutEndpoint + '?format=json&start_line=' + start + '&end_line=' + (start + page_size);
$('#stdoutMoreRowsBottom').fadeIn();
Rest.setUrl(url);
Rest.get()