Latest job detail page changes. Fixed lookup modal horizontal scroll.

This commit is contained in:
Chris Houseknecht 2014-04-14 00:32:34 -04:00
parent 06cf3a2aec
commit b6dc4047f7
5 changed files with 408 additions and 159 deletions

View File

@ -23,6 +23,8 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
$scope.plays = [];
$scope.tasks = [];
$scope.hosts = [];
$scope.hostResults = [];
// Apply each event to the view
if ($scope.removeEventsReady) {

View File

@ -39,7 +39,8 @@
angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
.factory('DigestEvents', ['UpdatePlayStatus', 'UpdatePlayNoHostsMatched', function(UpdatePlayStatus, UpdatePlayNoHostsMatched) {
.factory('DigestEvents', ['UpdatePlayStatus', 'UpdatePlayNoHostsMatched', 'UpdateHostStatus', 'UpdatePlayChild', 'AddHostResult',
function(UpdatePlayStatus, UpdatePlayNoHostsMatched, UpdateHostStatus, UpdatePlayChild, AddHostResult) {
return function(params) {
var scope = params.scope,
events = params.events;
@ -48,8 +49,22 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
scope.plays.push({
id: event.id,
name: event.play,
status: (event.failed) ? 'failed' : 'successful',
children: []
});
}
if (event.event === 'playbook_on_setup') {
scope.tasks.push({
id: event.id,
name: event.event_display,
play_id: event.parent,
status: (event.failed) ? 'failed' : 'successful'
});
UpdatePlayStatus({
scope: scope,
play_id: event.parent,
failed: event.failed
});
}
if (event.event === 'playbook_on_task_start') {
scope.tasks.push({
@ -58,18 +73,68 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
play_id: event.parent,
status: (event.failed) ? 'failed' : 'successful'
});
UpdatePlayStatus({ scope: scope, play_id: event.parent, status: event.status });
UpdatePlayStatus({
scope: scope,
play_id: event.parent,
failed: event.failed
});
}
if (event.event === 'playbook_on_no_hosts_matched') {
UpdatePlayNoHostsMatched({ scope: scope, play_id: event.parent });
}
if (event.event === 'runner_on_failed') {
}
if (event.event === 'runner_on_ok') {
UpdateHostStatus({
scope: scope,
name: event.event_data.host,
host_id: event.host_id,
task_id: event.parent,
status: (event.changed) ? 'changed' : 'ok',
results: (event.res && event.res.results) ? event.res.results : ''
});
AddHostResult({
scope: scope,
event: event
});
}
if (event.event === 'playbook_on_stats') {
}
});
};
}])
.factory('UpdatePlayChild', [ function() {
return function(params) {
var scope = params.scope,
id = params.id,
play_id = params.play_id,
failed = params.failed,
name = params.name,
found_child = false;
scope.plays.every(function(play, i) {
if (play.id === play_id) {
scope.plays[i].children.every(function(child, j) {
if (child.id === id) {
scope.plays[i].children[j].status = (failed) ? 'failed' : 'successful';
found_child = true;
return false;
}
return true;
});
if (!found_child) {
scope.plays[i].children.push({
id: id,
name: name,
status: (failed) ? 'failed' : 'successful'
});
}
scope.plays[i].status = (failed) ? 'failed' : 'successful';
return false;
}
return true;
});
};
}])
@ -78,11 +143,11 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
.factory('UpdatePlayStatus', [ function() {
return function(params) {
var scope = params.scope,
status = params.status,
failed = params.failed,
id = params.play_id;
scope.plays.every(function(play,idx) {
if (play.id === id) {
scope.plays[idx].status = (status) ? 'failed' : 'successful';
scope.plays[idx].status = (failed) ? 'failed' : 'successful';
return false;
}
return true;
@ -90,6 +155,19 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
};
}])
.factory('UpdateTaskStatus', [ function() {
return function(params) {
var scope = params.scope,
task_id = params.task_id,
failed = params.failed;
scope.tasks.every(function (task, i) {
if (task.id === task_id) {
scope.tasks[i].status = (failed) ? 'failed' : 'successful';
}
});
};
}])
.factory('UpdatePlayNoHostsMatched', [ function() {
return function(params) {
var scope = params.scope,
@ -102,6 +180,90 @@ angular.module('JobDetailHelper', ['Utilities', 'RestServices'])
return true;
});
};
}])
// Update or add a new host
.factory('UpdateHostStatus', ['UpdateTaskStatus', function(UpdateTaskStatus) {
return function(params) {
var scope = params.scope,
status = params.status, // ok, changed, unreachable, failed
name = params.name,
host_id = params.host_id,
task_id = params.task_id,
host_found = false;
scope.hosts.every(function(host, i) {
if (host.id === host_id) {
scope.hosts[i].ok += (status === 'ok' || status === 'changed') ? 1 : 0;
scope.hosts[i].changed += (status === 'changed') ? 1 : 0;
scope.hosts[i].unreachable += (status === 'unreachable') ? 1 : 0;
scope.hosts[i].failed += (status === 'failed') ? 1 : 0;
host_found = true;
return false;
}
return true;
});
if (!host_found) {
scope.hosts.push({
id: host_id,
name: name,
ok: (status === 'ok' || status === 'changed') ? 1 : 0,
changed: (status === 'changed') ? 1 : 0,
unreachable: (status === 'unreachable') ? 1 : 0,
failed: (status === 'failed') ? 1 : 0
});
}
// Mark task failed
if (status === 'failed') {
UpdateTaskStatus({
scope: scope,
task_id: task_id,
failed: true
});
}
};
}])
// Add a new host result
.factory('AddHostResult', ['Empty', function(Empty) {
return function(params) {
var scope = params.scope,
event = params.event,
id, status, host_id, play_name, task_name, module_name, module_args,
results, rc;
id = event.id;
status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful';
host_id = event.host;
play_name = event.play;
task_name = event.task;
if (event.event_data.res && event.event_data.res.invocation) {
module_name = event.event_data.res.invocation.module_name;
module_args = event.event_data.res.invocation.module_args;
}
else {
module_name = '';
module_args = '';
}
if (event.event_data.res && event.event_data.res.results) {
results = '';
event.event_data.res.results.forEach(function(row) {
results += row;
});
}
rc = (event.event_data.res && !Empty(event.event_data.res.rc)) ? event.event_data.res.rc : '';
scope.hostResults.push({
id: id,
status: status,
host_id: host_id,
play_name: play_name,
task_name : task_name,
module_name: module_name,
module_args: module_args,
results: results,
rc: rc
});
};
}]);

View File

@ -1,8 +1,8 @@
/*********************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
*
* ansible-ui.css
*
*
* custom styles for ansible-ui
*
*/
@ -120,7 +120,7 @@ a:focus {
}
.btn-disabled {
cursor: not-allowed;
cursor: not-allowed;
}
/* Bring primary (blue) buttons in line with link colors */
@ -151,12 +151,12 @@ a:focus {
#home_groups_table .actions .cancel { padding-right: 3px; }
.success-badge {
.success-badge {
color: #ffffff;
background-color: #5cb85c;
}
.bold-text .checkbox-inline {
.bold-text .checkbox-inline {
font-weight: bold;
}
@ -176,9 +176,9 @@ textarea.allowresize {
z-index: 2000;
width: 75px;
height: 75px;
text-align:center;
text-align:center;
color: #eee;
background-color: @black;
background-color: @black;
border: 1px solid @grey;
border-radius: 6px;
padding-top: 10px;
@ -199,7 +199,7 @@ textarea.allowresize {
}
.license-version {
font-size: 18px;
font-size: 18px;
color: @grey-txt;
}
@ -212,9 +212,9 @@ textarea.allowresize {
position: absolute;
top: 0;
left: 0;
z-index: 1999;
z-index: 1999;
background-color: @black;
opacity: 0;
opacity: 0;
}
/* TB tooltip overrides */
@ -225,7 +225,7 @@ textarea.allowresize {
font-size: 12px;
}
.flyout thead> tr> th, .flyout tbody> tr> td, .flyout tbody> tr> td> a {
font-size: 12px;
font-size: 12px;
}
.popover-title {
padding-top: 5px;
@ -272,7 +272,7 @@ hr {
.help-auto-off {
margin-top: 15px;
margin-bottom: 15px;
margin-left: 10px;
margin-left: 10px;
label {
font-weight: normal;
}
@ -284,7 +284,7 @@ hr {
}
.panel-heading:hover {
cursor: pointer;
cursor: pointer;
}
.panel-default>.panel-heading .collapse-help-icon {
@ -296,10 +296,10 @@ hr {
margin-bottom: 20px;
dl {
margin-left: 15px;
}
}
dt {
margin-top: 15px;
}
}
}
th.actions-column,
@ -341,7 +341,7 @@ td.actions {
}
.ssh-key-field, .mono-space {
font-family: Fixed, monospace;
font-family: Fixed, monospace;
}
dd {
@ -423,7 +423,7 @@ dd {
}
.navbar-collapse {
padding-right: 0;
padding-right: 0;
}
.main-menu .nav >li >a:last-child {
@ -437,7 +437,7 @@ dd {
margin-top: 11px;
}
/* Using inline-block rather than block keeps
/* Using inline-block rather than block keeps
brand img from right aligning into the collapse button
on mobile screens */
.main-menu .navbar-brand {
@ -480,7 +480,7 @@ dd {
padding-top: 10px;
padding-bottom: 10px;
font-size: 12px;
a,
a:active,
a:visited {
@ -501,7 +501,7 @@ dd {
}
.logo img {
max-width: 46px;
max-width: 46px;
}
.copyright {
@ -526,7 +526,7 @@ dd {
width: 327px;
}
.form-title {
.form-title {
display: inline-block;
width: 100%;
vertical-align: middle;
@ -536,7 +536,7 @@ dd {
}
.form-group {
margin-bottom: 25px;
margin-bottom: 25px;
}
.form-cancel {
@ -549,7 +549,7 @@ dd {
}
.form-horizontal .buttons {
margin-top: 25px;
margin-top: 25px;
}
.label-text {
@ -615,7 +615,7 @@ legend {
}
/* Pagination */
.page-label {
.page-label {
font-size: 12px;
margin-top: 0;
text-align: right;
@ -630,7 +630,7 @@ legend {
padding: 3px 6px;
}
.modal-body {
.modal-body {
.pagination {
margin-top: 15px;
margin-bottom: 0;
@ -658,9 +658,12 @@ legend {
}
#lookup-modal-dialog .instructions {
margin-top: 0;
margin-bottom: 20px;
#lookup-modal-dialog
overflow-x: hidden;
.instructions {
margin-top: 0;
margin-bottom: 20px;
}
}
.related-footer {
@ -701,27 +704,27 @@ select.page-size {
}
/* Search Widget */
.search-widget label {
display: inline-block;
padding-right: 15px;
vertical-align: middle;
vertical-align: middle;
}
#search_value_input {
#search_value_input {
padding-right: 25px;
}
.search-reset-start {
color: @grey;
float: right;
position: relative;
position: relative;
top: -25px;
left: -10px;
z-index: 10;
}
.search-reset-start:hover {
.search-reset-start:hover {
cursor: pointer;
color: @black;
}
@ -777,9 +780,9 @@ select.page-size {
}
/* Display drop-down menus on hover. Remove margin between toggle link
and menu, allowing smooth mouse movement between toggle and menu
http://stackoverflow.com/questions/8878033/how-to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click
and menu, allowing smooth mouse movement between toggle and menu
http://stackoverflow.com/questions/8878033/how-to-make-twitter-bootstrap-menu-dropdown-on-hover-rather-than-click
*/
.dropdown-toggle:hover .dropdown-menu, .dropdown:hover .dropdown-menu {
display: block;
@ -787,7 +790,7 @@ select.page-size {
.dropdown-menu li:hover {
visibility: visible;
}
}
.dropdown-menu {
margin-top: 0;
@ -866,15 +869,15 @@ input[type="checkbox"].checkbox-no-label {
}
/*.list-wrapper {
background-color: @well;
padding: 10px;
padding: 10px;
border-radius: 4px;
border: 1px solid @well-border;
}*/
.ui-accordion-content {
padding-left: 15px;
padding-left: 15px;
padding-right: 15px;
}
.page-label {
.page-label {
margin-top: 5px;
}
}
@ -891,7 +894,7 @@ input[type="checkbox"].checkbox-no-label {
.table-hover tbody tr:hover > td,
.table-hover tbody tr:hover > th {
background-color: #fff;
border-top: 1px solid #ddd;
border-top: 1px solid #ddd;
}
.table-hover-inverse tbody tr:hover > td,
@ -947,7 +950,7 @@ input[type="checkbox"].checkbox-no-label {
/* Table info rows */
.loading-info {
color: @grey-txt;
color: @grey-txt;
font-weight: normal;
padding: 15px 0;
}
@ -978,7 +981,7 @@ input[type="checkbox"].checkbox-no-label {
padding-top: 5px;
}
.job-new,
.license-valid,
.job-success,
@ -1014,11 +1017,11 @@ input[type="checkbox"].checkbox-no-label {
.icon-job-successful {
color: @green;
}
.icon-job-running {
.pulsate();
}
.icon-job-changed,
.job-changed {
color: @warning;
@ -1053,7 +1056,7 @@ input[type="checkbox"].checkbox-no-label {
font-weight: normal;
line-height: 1;
}
.job-list.ui-accordion-content {
padding: 25px 15px 25px 15px;
}
@ -1088,7 +1091,7 @@ input[type="checkbox"].checkbox-no-label {
margin-top: 0;
margin-bottom: 25px;
}
/* Inventory job status badge */
.failures-true {
background-color: @red;
@ -1101,7 +1104,7 @@ input[type="checkbox"].checkbox-no-label {
}
/* Cloud inventory status. i.e. inventory_source.status values */
.icon-cloud-na:before,
.icon-cloud-never:before,
.icon-cloud-updating:before,
@ -1118,7 +1121,7 @@ input[type="checkbox"].checkbox-no-label {
}*/
.icon-cloud-na,
.icon-cloud-never,
.icon-cloud-never,
a.icon-cloud-na:hover,
a.icon-cloud-never:hover {
color: @grey;
@ -1160,14 +1163,14 @@ input[type="checkbox"].checkbox-no-label {
color: @red;
width: 14px;
}
/* Inventory cloud sourced? indicator */
.icon-cloud-true:before {
content: "\f111";
}
.icon-cloud-false:before {
content: "\f111";
content: "\f111";
}
.icon-cloud-true {
@ -1176,7 +1179,7 @@ input[type="checkbox"].checkbox-no-label {
.icon-cloud-false {
color: @grey;
}
}
/* end */
.field-success {
@ -1255,13 +1258,13 @@ input[type="checkbox"].checkbox-no-label {
overflow: hidden;
}
/* Inventory nav links */
/* Inventory nav links */
.navigation-links {
padding: 0;
margin-top: -10px;
a {
a {
margin-right: 15px;
}
@ -1280,12 +1283,12 @@ input[type="checkbox"].checkbox-no-label {
.selected {
font-weight: bold;
color: @blue-dark;
color: @blue-dark;
}
.inventory-title {
font-size: 16px;
font-weight: bold;
font-size: 16px;
font-weight: bold;
}
.active-row {
@ -1339,11 +1342,11 @@ input[type="checkbox"].checkbox-no-label {
}
a.disabled:hover {
color: @grey;
cursor: not-allowed;
color: @grey;
cursor: not-allowed;
}
a.btn-disabled:hover {
cursor: not-allowed;
cursor: not-allowed;
}
/* Variable Editing */
@ -1366,7 +1369,7 @@ a.btn-disabled:hover {
display: inline-block;
margin-left: 20px;
}
.slider {
display: inline-block;
width: 100px;
@ -1497,7 +1500,7 @@ tr td button i {
li {
line-height: normal;
margin-bottom: 10px;
}
}
ul:last-child {
margin-top: 10px;
}
@ -1526,7 +1529,7 @@ tr td button i {
overflow: hidden;
padding: 10px;
img {
img {
max-width: 450px;
margin-top: 15px;
margin-bottom: 15px;
@ -1550,7 +1553,7 @@ tr td button i {
}
/* Activity Stream Widget */
/* Activity Stream Widget */
#stream-container {
display: none;
@ -1573,18 +1576,74 @@ tr td button i {
margin-bottom: 20px;
}
}
/* New job detail page */
.job-detail-tables {
.relative-position {
position: relative;
}
.job-detail-tables, .job_options {
.table {
margin-bottom: 0;
}
.table>tbody>tr>td {
border-top-color: #fff;
padding: 0;
}
.table>thead>tr>th {
border-bottom-color: #fff;
padding: 0;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li ul {
margin-left: 20px;
}
}
.job_well {
padding: 8px;
background-color: @well;
border: 1px solid @well-border;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
.job_options {
height: 100px;
overflow-y: auto;
overflow-x: none;
}
.scroll-up-indicator {
position: absolute;
right: 18px;
font-size: 14px;
bottom: -2px;
padding: 0;
}
.scroll-down-indicator {
position: absolute;
right: 18px;
bottom: -2px;
font-size: 14px;
padding: 0;
}
.scroll-up-indicator,
.scroll-up-indicator:hover,
.scroll-up-indicator:visited,
.scroll-down-indicator,
.scroll-down-indicator:hover,
.scroll-down-indicator:visited {
color: @grey;
}
/* ng-cloak directive */
@ -1621,7 +1680,7 @@ tr td button i {
}*/
@media (min-width: 768px) and (max-width: 1199px) {
.level-1,
.level-2,
.level-3,
@ -1637,7 +1696,7 @@ tr td button i {
}
.list-actions button, .list-actions .checkbox-inline {
margin-top: 10px;
margin-top: 10px;
}
.label-text {
@ -1647,16 +1706,16 @@ tr td button i {
.group-name {
width: 80%;
}
}
/* Landscape phone to portrait tablet */
@media (max-width: 767px) {
/* Job events */
.level-1,
.level-2,
.level-3,
@ -1687,7 +1746,7 @@ tr td button i {
}
.list-actions button, .list-actions .checkbox-inline {
margin-top: 10px;
margin-top: 10px;
}
.group-name {

View File

@ -1,7 +1,7 @@
/*********************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* Custom directives for form validation
* Custom directives for form validation
*
*/
@ -10,7 +10,7 @@
/* global chkPass:false */
angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'JobsHelper'])
// awpassmatch: Add to password_confirm field. Will test if value
// matches that of 'input[name="password"]'
.directive('awpassmatch', function() {
@ -32,11 +32,11 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
})
// caplitalize Add to any input field where the first letter of each
// word should be capitalized. Use in place of css test-transform.
// For some reason "text-transform: capitalize" in breadcrumbs
// causes a break at each blank space. And of course,
// causes a break at each blank space. And of course,
// "autocapitalize='word'" only works in iOS. Use this as a fix.
.directive('capitalize', function() {
return {
@ -93,18 +93,18 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
})
//
// awRequiredWhen: { variable: "<variable to watch for true|false>", init:"true|false" }
//
// Make a field required conditionally using a scope variable. If the scope variable is true, the
// field will be required. Otherwise, the required attribute will be removed.
//
// field will be required. Otherwise, the required attribute will be removed.
//
.directive('awRequiredWhen', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
function checkIt () {
var viewValue = elm.val(), label, validity = true;
if ( scope[attrs.awRequiredWhen] && (elm.attr('required') === null || elm.attr('required') === undefined) ) {
@ -131,12 +131,12 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
ctrl.$setValidity('required', validity);
}
if (attrs.awrequiredInit !== undefined && attrs.awrequiredInit !== null) {
scope[attrs.awRequiredWhen] = attrs.awrequiredInit;
checkIt();
}
scope.$watch(attrs.awRequiredWhen, function() {
// watch for the aw-required-when expression to change value
checkIt();
@ -149,7 +149,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
})
// awPlaceholder: Dynamic placeholder set to a scope variable you want watched.
// Value will be place in field placeholder attribute.
.directive('awPlaceholder', [ function() {
@ -165,7 +165,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}])
// lookup Validate lookup value against API
//
//
.directive('awlookup', ['Rest', function(Rest) {
return {
require: 'ngModel',
@ -198,10 +198,10 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
}])
//
// awValidUrl
//
//
.directive('awValidUrl', [ function() {
return {
require: 'ngModel',
@ -222,13 +222,13 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
};
}])
/*
/*
* Enable TB tooltips. To add a tooltip to an element, include the following directive in
* the element's attributes:
*
* aw-tool-tip="<< tooltip text here >>"
*
* Include the standard TB data-XXX attributes to controll a tooltip's appearance. We will
* Include the standard TB data-XXX attributes to controll a tooltip's appearance. We will
* default placement to the left and delay to 2 seconds.
*/
.directive('awToolTip', function() {
@ -241,11 +241,11 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
else {
placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left';
}
$(element).on('hidden.bs.tooltip', function( ) {
// TB3RC1 is leaving behind tooltip <div> elements. This will remove them
// after a tooltip fades away. If not, they lay overtop of other elements and
// honk up the page.
// after a tooltip fades away. If not, they lay overtop of other elements and
// honk up the page.
$('.tooltip').each(function() {
$(this).remove();
});
@ -272,7 +272,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
})
/*
* Enable TB pop-overs. To add a pop-over to an element, include the following directive in
* the element's attributes:
@ -470,7 +470,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
}])
//
// awRefresh
//
@ -507,8 +507,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
};
}])
/*
/*
awMultiSelect
Relies on select2.js to create a multi-select with tags.
*/
@ -543,8 +543,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
};
}])
/*
/*
* Make an element draggable. Used on inventory groups tree.
*
* awDraggable: boolean || {{ expression }}
@ -552,7 +552,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
*/
.directive('awDraggable', [ function() {
return function(scope, element, attrs) {
if (attrs.awDraggable === "true") {
var containment = attrs.containment; //provide dataContainment:"#id"
$(element).draggable({
@ -569,8 +569,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
}])
/*
/*
* Make an element droppable- it can receive draggable elements
*
* awDroppable: boolean || {{ expression }}
@ -581,7 +581,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
var node;
if (attrs.awDroppable === "true") {
$(element).droppable({
// the following is inventory specific accept checking and
// the following is inventory specific accept checking and
// drop processing.
accept: function(draggable) {
if (draggable.attr('data-type') === 'group') {
@ -643,7 +643,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
var active,
list = Store('accordions'),
id, base;
if (!Empty(attrs.openFirst)) {
active = 0;
}
@ -696,6 +696,51 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
});
};
}])
.directive('awScrollDown', [ function() {
return function(scope, element, attrs) {
var element_to_scroll = attrs.awScrollDown, elem;
$(element).on('click', function() {
var height = document.getElementById(element_to_scroll).scrollHeight;
$(element).hide();
$('#' + element_to_scroll).animate({scrollTop:height}, 800);
});
elem = document.getElementById(element_to_scroll);
$('#' + element_to_scroll).on('scroll', function() {
if (elem.scrollTop > 0 && $(element).is(':visible')) {
$(element).hide();
}
else if (elem.scrollTop === 0 && !$(element).is(':visible')) {
$(element).fadeIn(2500);
}
});
if (elem.scrollTop > 0 && $(element).is(':visible')) {
$(element).hide();
}
};
}])
.directive('awScrollUp', [ function() {
return function(scope, element, attrs) {
var element_to_scroll = attrs.awScrollUp, elem;
$(element).on('click', function() {
$(element).hide();
$('#' + element_to_scroll).animate({scrollTop:0}, 'slow');
});
elem = document.getElementById(element_to_scroll);
$('#' + element_to_scroll).on('scroll', function() {
if (elem.scrollTop === 0 && $(element).is(':visible')) {
$(element).hide();
}
else if (elem.scrollTop > 0 && !$(element).is(':visible')) {
$(element).fadeIn(2500);
}
});
if (elem.scrollTop === 0) {
$(element).hide();
}
};
}]);
/*
@ -714,4 +759,4 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
}
};
}]);
*/
*/

View File

@ -2,13 +2,13 @@
<div ng-cloak id="htmlTemplate">
<div class="row">
<div class="col-md-12" id="breadcrumbs"></div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4>Job Options</h4>
<div class="job_options">
<h5>Options</h5>
<div class="job_options job_well" id="job_options">
<table class="table table-condensed">
<tbody>
<tbody>
<tr ng-show="job_template_url">
<td class="col-md-3 col-sm-2">Job Template</td>
<td><a ng-href="{{ job_template_url }}">{{ job_template_name }}</a></td>
@ -16,11 +16,11 @@
<tr ng-show="project_url">
<td class="col-md-3 col-sm-2">Project</td>
<td><a ng-href="{{ project_url }}">{{ project_name }}</a></td>
</tr>
</tr>
<tr ng-show="inventory_url">
<td class="col-md-3 col-sm-2">Inventory</td>
<td><a ng-href="{{ inventory_url }}">{{ inventory_name }}</a></td>
</tr>
</tr>
<tr ng-show="playbook">
<td class="col-md-3 col-sm-2">Playbook</td>
<td>{{ playbook }}</td>
@ -52,29 +52,27 @@
</tbody>
</table>
</div>
<a id="job_options_scroll_down_indicator" href="" aw-scroll-down="job_options" class="scroll-down-indicator">more <i class="fa fa-chevron-circle-down"></i></a>
<a id="job_options_scroll_up_indicator" href="" aw-scroll-up="job_options" class="scroll-up-indicator">more <i class="fa fa-chevron-circle-up"></i></a>
</div>
</div><!-- row -->
<div class="row">
<div class="col-md-6 job-detail-tables">
<h4>Plays</h4>
<div class="job_plays">
<table class="table table-condensed job-detail-table">
<thead>
<tr>
<th class="col-md-1">Status</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="play in plays">
<td><i class="fa icon-job-{{ play.status }}"></i></td>
<td>{{ play.name }}</td>
<td>{{ play.state }}</td>
</tr>
</tbody>
</table>
<h5>Plays</h5>
<div class="job_plays job_well">
<ul>
<li ng-repeat="play in plays">
<i class="fa icon-job-{{ play.status }}"></i> {{play.name }}
<ul ng-show="play.children.length > 0">
<li ng-repeat="child in play.children">
<i class="fa icon-job-{{ child.status }}"></i> {{child.name }}
</li>
</ul>
</li>
</ul>
</div>
<h4>Tasks</h4>
@ -90,10 +88,9 @@
<tr ng-repeat="task in tasks">
<td><i class="fa icon-job-{{ task.status }}"></i></td>
<td>{{ task.name }}</td>
<td>{{ task.state }}</td>
</tr>
</tbody>
</table>
</table>
</div>
<h4>Hosts</h4>
@ -101,22 +98,20 @@
<table class="table table-condensed job-detail-table">
<thead>
<tr>
<th class="col-md-1">Status</th>
<th>Name</th>
<th>OK</th>
<th>Changed</th>
<th>Unreachable</th>
<th>Failed</th>
<th class="text-center">OK</th>
<th class="text-center">Changed</th>
<th class="text-center">Unreachable</th>
<th class="text-center">Failed</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="host in hosts">
<td><i class="fa icon-job-{{ task.status }}"></i></td>
<td>{{ host.name }}</td>
<td>{{ host.ok }}</td>
<td>{{ host.changed }}</td>
<td>{{ host.unreachable }}</td>
<td>{{ host.failed }}</td>
<td class="text-center">{{ host.ok }}</td>
<td class="text-center">{{ host.changed }}</td>
<td class="text-center">{{ host.unreachable }}</td>
<td class="text-center">{{ host.failed }}</td>
</tr>
</tbody>
</table>
@ -127,17 +122,3 @@
</div>
</div>