AC-1294 reworked standard out page to support custom scroll bar. Removed use of <pre> elment by parsing the inbound HTML and isolating the style sheet and the job output. Those are now inserted into styled <div> elements, giving the UI better control. The page now listens to the web socket server and refreshes whenver an event happens for the job. On an event the <div> element refreshes and automatically scrolls to the bottom.

This commit is contained in:
chouseknecht 2014-05-21 17:29:03 -04:00
parent 35521cbdc8
commit e5ee7e5383
12 changed files with 103 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/**********************************************************************
*
*
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* config.js
@ -11,20 +11,20 @@
/*jshint unused:false */
var $AnsibleConfig = {
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
debug_mode: true, // Enable console logging messages
password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong.
// This value controls progress bar colors:
// 0 to password_strength - 15 = red;
// password_strength - 15 to password_strength = yellow
// This value controls progress bar colors:
// 0 to password_strength - 15 = red;
// password_strength - 15 to password_strength = yellow
// > password_strength = green
// It also controls password validation. Passwords are rejected if the score is not > password_strength.
// It also controls password validation. Passwords are rejected if the score is not > password_strength.
session_timeout: 1800, // Number of seconds before an inactive session is automatically timed out and forced to log in again.
// Separate from time out value set in API.
// Separate from time out value set in API.
variable_edit_modes: { // Options we pass to ControlMirror for editing YAML/JSON variables
@ -46,6 +46,8 @@ var $AnsibleConfig = {
gutters: ["CodeMirror-lint-markers"],
lint: true
}
}
},
websocket_port: 8090
};

View File

@ -7,23 +7,44 @@
'use strict';
function JobStdoutController ($scope, $compile, $routeParams, ClearScope, GetBasePath, Wait, Rest, ProcessErrors) {
function JobStdoutController ($scope, $compile, $routeParams, ClearScope, GetBasePath, Wait, Rest, ProcessErrors, Socket) {
ClearScope();
var available_height, job_id = $routeParams.id;
var available_height, job_id = $routeParams.id,
api_complete = false,
stdout_url,
event_socket = Socket({
scope: $scope,
endpoint: "job_events"
});
Wait('start');
event_socket.init();
event_socket.on("job_events-" + job_id, function() {
if (api_complete) {
$scope.$emit('LoadStdout');
}
});
if ($scope.removeLoadStdout) {
$scope.removeLoadStdout();
}
$scope.removeLoadStdout = $scope.$on('LoadStdout', function(e, url) {
Rest.setUrl(url + '?format=html');
$scope.removeLoadStdout = $scope.$on('LoadStdout', function() {
Rest.setUrl(stdout_url + '?format=html');
Rest.get()
.success(function(data) {
api_complete = true;
Wait('stop');
$('#stdout-iframe').attr('srcdoc', data);
var doc, style, pre, parser = new DOMParser();
doc = parser.parseFromString(data, "text/html");
pre = doc.getElementsByTagName('pre');
style = doc.getElementsByTagName('style');
$('#style-sheet-container').empty().html(style[0]);
$('#pre-container-content').empty().html($(pre[0]).html());
setTimeout(function() { $('#pre-container').mCustomScrollbar("scrollTo", 'bottom'); }, 1000);
})
.error(function(data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
@ -33,15 +54,15 @@ function JobStdoutController ($scope, $compile, $routeParams, ClearScope, GetBas
function resizeToFit() {
available_height = $(window).height() - $('.main-menu').outerHeight() - $('#main_tabs').outerHeight() -
$('#breadcrumb-container').outerHeight() - $('.site-footer').outerHeight();
$('#breadcrumb-container').outerHeight() - $('.site-footer').outerHeight() * 2;
if ($(window).width() < 768) {
available_height += 55;
}
else {
else if ($(window).width() > 1240) {
available_height += 5;
}
$('#stdout-iframe').height(available_height);
//$('#stdout-container').mCustomScrollbar("update");
$('#pre-container').height(available_height);
$('#pre-container').mCustomScrollbar("update");
}
resizeToFit();
@ -53,7 +74,8 @@ function JobStdoutController ($scope, $compile, $routeParams, ClearScope, GetBas
Rest.get()
.success(function(data) {
$scope.job = data;
$scope.$emit('LoadStdout', data.related.stdout);
stdout_url = data.related.stdout;
$scope.$emit('LoadStdout');
})
.error(function(data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
@ -61,4 +83,4 @@ function JobStdoutController ($scope, $compile, $routeParams, ClearScope, GetBas
});
}
JobStdoutController.$inject = [ '$scope', '$compile', '$routeParams', 'ClearScope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors' ];
JobStdoutController.$inject = [ '$scope', '$compile', '$routeParams', 'ClearScope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors', 'Socket' ];

View File

@ -348,6 +348,12 @@ td.actions {
font-family: Fixed, monospace;
}
/* Make a div or any element behave like pre. Use in conjunction with .mono-space */
.pre {
white-space: pre;
}
dd {
margin-left: 15px;
}
@ -1658,7 +1664,8 @@ tr td button i {
/* job stdout */
#stdout-iframe {
#pre-container {
overflow: auto;
width: 100%;
border-radius: 4px;
margin: 0;

View File

@ -18,7 +18,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
host = $location.host(),
endpoint = params.endpoint,
protocol = $location.protocol(),
url = protocol + '://' + host + ':8080/socket.io/' + endpoint;
url = protocol + '://' + host + ':' + $AnsibleConfig.websocket_port + '/socket.io/' + endpoint;
function getSocketTip(status) {
var result = '';

View File

@ -722,6 +722,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
.directive('awCustomScroll', [ function() {
return function(scope, element, attrs) {
var theme = (attrs.scrollTheme) ? attrs.scrollTheme : 'dark-thin';
$(element).mCustomScrollbar({
advanced:{
updateOnContentResize: true
@ -729,7 +730,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
scrollButtons: {
enable: true
},
theme: 'dark-thin',
theme: theme,
mouseWheel: true,
scrollInertia: 300,
callbacks: {

View File

@ -1,6 +1,6 @@
{
"name": "malihu-custom-scrollbar-plugin",
"version": "2.8.3",
"version": "2.8.4",
"title": "malihu custom scrollbar plugin",
"description": "Custom scrollbar jQuery plugin that's fully customizable with CSS. Features vertical/horizontal scrolling, mouse-wheel support, scroll easing, adjustable scrollbar height/width, nested scrollbars, user defined callbacks etc.",
"main": "./jquery.mCustomScrollbar.js",
@ -37,13 +37,13 @@
"/source_files",
"/js"
],
"_release": "2.8.3",
"_release": "2.8.4",
"_resolution": {
"type": "version",
"tag": "2.8.3",
"commit": "179ced37ef972b2c44bb4b71d20a6310fa317867"
"tag": "2.8.4",
"commit": "7f5be74468063f39e5f9bf0a8e2db380486c6e0e"
},
"_source": "git://github.com/malihu/malihu-custom-scrollbar-plugin.git",
"_target": "2.8.3",
"_target": "2.8.4",
"_originalSource": "malihu-custom-scrollbar-plugin"
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/*
== malihu jquery custom scrollbars plugin ==
version: 2.8.3
version: 2.8.4
author: malihu (http://manos.malihu.gr)
plugin home: http://manos.malihu.gr/jquery-custom-content-scroller
*/
@ -176,8 +176,9 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
percentage=maxHeight,
maxHeight=$this.parent().height()*percentage/100;
}
var paddingY=($this.innerHeight()-$this.height());
$this.css("overflow","hidden");
mCustomScrollBox.css("max-height",maxHeight);
mCustomScrollBox.css("max-height",maxHeight-paddingY);
}
}
$this.mCustomScrollbar("update");
@ -192,8 +193,12 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
if(!$this.is(".mCS_disabled") && !$this.is(".mCS_destroyed")){
var winWidth=$(window).width(),winHeight=$(window).height();
if(currWinWidth!==winWidth || currWinHeight!==winHeight){ /*ie8 fix*/
if($this.css("max-height")!=="none" && percentage){
mCustomScrollBox.css("max-height",$this.parent().height()*percentage/100);
if($this.css("max-height")!=="none"){
if(percentage){
mCustomScrollBox.css("max-height",($this.parent().height()*percentage/100)-paddingY);
}else{
mCustomScrollBox.css("max-height",(parseInt($this.css("max-height"))-paddingY));
}
}
$this.mCustomScrollbar("update");
currWinWidth=winWidth; currWinHeight=winHeight;
@ -206,22 +211,23 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
if(options.advanced.updateOnContentResize){
var mCSB_onContentResize;
if(options.horizontalScroll){
var mCSB_containerOldSize=mCSB_container.outerWidth();
var mCSB_containerOldSize=mCSB_container.outerWidth(),mCSB_contentOldSize=mCSB_container.innerWidth();
}else{
var mCSB_containerOldSize=mCSB_container.outerHeight();
var mCSB_containerOldSize=mCSB_container.outerHeight(),mCSB_contentOldSize=mCSB_container.innerHeight();
}
mCSB_onContentResize=setInterval(function(){
if(options.horizontalScroll){
if(options.advanced.autoExpandHorizontalScroll){
mCSB_container.css({"position":"absolute","width":"auto"}).wrap("<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />").css({"width":mCSB_container.outerWidth(),"position":"relative"}).unwrap();
}
var mCSB_containerNewSize=mCSB_container.outerWidth();
var mCSB_containerNewSize=mCSB_container.outerWidth(),mCSB_contentNewSize=mCSB_container.innerWidth();
}else{
var mCSB_containerNewSize=mCSB_container.outerHeight();
var mCSB_containerNewSize=mCSB_container.outerHeight(),mCSB_contentNewSize=mCSB_container.innerHeight();
}
if(mCSB_containerNewSize!=mCSB_containerOldSize){
if(mCSB_containerNewSize!=mCSB_containerOldSize || mCSB_contentNewSize!=mCSB_contentOldSize){
$this.mCustomScrollbar("update");
mCSB_containerOldSize=mCSB_containerNewSize;
mCSB_contentOldSize=mCSB_contentNewSize;
}
},300);
}
@ -681,6 +687,18 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
}else{
draggerScrollTo=scrollTo=target;
}
}else if(typeof(scrollTo)==="object"){ /*if object, scroll by element position*/
var target=$(scrollTo);
if(target.length===1){ /*if such unique element exists, scroll to it*/
if($this.data("horizontalScroll")){
scrollTo=target.position().left;
}else{
scrollTo=target.position().top;
}
draggerScrollTo=scrollTo/$this.data("scrollAmount");
}else{
draggerScrollTo=scrollTo=target;
}
}
/*scroll to*/
if($this.data("horizontalScroll")){
@ -767,7 +785,7 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
}
/*callbacks*/
function callbacks(cb){
if ($this.data("mCustomScrollbarIndex")) {
if($this.data("mCustomScrollbarIndex")){
this.mcs = {
top: mCSB_container.position().top, left: mCSB_container.position().left,
draggerTop: mCSB_dragger.position().top, draggerLeft: mCSB_dragger.position().left,
@ -831,7 +849,9 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
functions={
/*hide/show scrollbar*/
showScrollbar:function(){
this.stop().animate({opacity:1},"fast");
if($(this).css("opacity")==0){
this.stop().animate({opacity:1},"fast");
}
},
hideScrollbar:function(){
this.stop().animate({opacity:0},"fast");
@ -955,7 +975,7 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
$.support.msPointer=window.navigator.msPointerEnabled; /*MSPointer support*/
/*plugin dependencies*/
var _dlp=("https:"==document.location.protocol) ? "https:" : "http:";
$.event.special.mousewheel || document.write('<script src="'+_dlp+'//cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.0.6/jquery.mousewheel.min.js"><\/script>');
$.event.special.mousewheel || $("<script>",{src:_dlp+"//cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.6/jquery.mousewheel.min.js"}).appendTo("body");
/*plugin fn*/
$.fn.mCustomScrollbar=function(method){
if(methods[method]){
@ -966,4 +986,4 @@ along with this program. If not, see http://www.gnu.org/licenses/lgpl.html.
$.error("Method "+method+" does not exist");
}
};
})(jQuery);
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
<div class="tab-pane" id="jobs-stdout">
<div ng-cloak id="htmlTemplate">
<div class="row">
<div id="breadcrumb-container" class="col-md-12" style="position: relative;">
<div class="nav-path">
@ -16,7 +16,10 @@
<div class="row">
<div class="col-md-12">
<iframe id="stdout-iframe"></iframe>
<div id="style-sheet-container"></div>
<div id="pre-container" class="body_background body_foreground pre mono-space" aw-custom-scroll data-scroll-theme="light-thin">
<div id="pre-container-content"></div>
</div>
</div>
</div>
</div>

View File

@ -402,7 +402,8 @@
<script src="{{ STATIC_URL }}lib/codemirror/addon/selection/active-line.js"></script>
<script src="{{ STATIC_URL }}lib/scrollto/lib/jquery-scrollto.js"></script>
<script src="{{ STATIC_URL }}lib/socket.io-client/dist/socket.io.min.js"></script>
<script src="{{ STATIC_URL }}lib/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js"></script>
<script src="{{ STATIC_URL }}lib/jquery-mousewheel/jquery.mousewheel.min.js"></script>
<script src="{{ STATIC_URL }}lib/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.min.js"></script>
<script scr="{{ STATIC_URL }}lib/lib/jQuery.dotdotdot/src/js/jquery.dotdotdot.min.js"></script>
<script src="{{ STATIC_URL }}lib/d3js/build/d3.v3.min.js"></script>
<script src="{{ STATIC_URL }}lib/d3Donut/d3Donut.js"></script>

View File

@ -23,7 +23,7 @@
"sizzle": "1.10.16",
"d3js": "*",
"angular-tz-extensions": "~0.3.10",
"malihu-custom-scrollbar-plugin": "2.8.3",
"malihu-custom-scrollbar-plugin": "2.8.4",
"jQuery.dotdotdot": "~1.6.14"
},
"resolutions": {