diff --git a/awx/ui/static/img/help/add_exception.png b/awx/ui/static/img/help/add_exception.png new file mode 100644 index 0000000000..4ba7bac86f Binary files /dev/null and b/awx/ui/static/img/help/add_exception.png differ diff --git a/awx/ui/static/img/help/confirm_exception.png b/awx/ui/static/img/help/confirm_exception.png new file mode 100644 index 0000000000..93b1fef7fe Binary files /dev/null and b/awx/ui/static/img/help/confirm_exception.png differ diff --git a/awx/ui/static/img/help/help001.png b/awx/ui/static/img/help/help001.png deleted file mode 100644 index eb1d498396..0000000000 Binary files a/awx/ui/static/img/help/help001.png and /dev/null differ diff --git a/awx/ui/static/img/help/help002.png b/awx/ui/static/img/help/help002.png deleted file mode 100644 index 2bbb8374f7..0000000000 Binary files a/awx/ui/static/img/help/help002.png and /dev/null differ diff --git a/awx/ui/static/img/help/help003.png b/awx/ui/static/img/help/help003.png deleted file mode 100644 index 4036e34cc2..0000000000 Binary files a/awx/ui/static/img/help/help003.png and /dev/null differ diff --git a/awx/ui/static/img/help/refresh_firefox.png b/awx/ui/static/img/help/refresh_firefox.png new file mode 100644 index 0000000000..47c4016165 Binary files /dev/null and b/awx/ui/static/img/help/refresh_firefox.png differ diff --git a/awx/ui/static/img/help/socket_indicator.png b/awx/ui/static/img/help/socket_indicator.png new file mode 100644 index 0000000000..eb37a6bf8c Binary files /dev/null and b/awx/ui/static/img/help/socket_indicator.png differ diff --git a/awx/ui/static/img/help/understand_the_risk.png b/awx/ui/static/img/help/understand_the_risk.png new file mode 100644 index 0000000000..d668b2b99e Binary files /dev/null and b/awx/ui/static/img/help/understand_the_risk.png differ diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 91a3608742..0444a68a4b 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -101,7 +101,8 @@ angular.module('Tower', [ 'JobDetailHelper', 'SocketIO', 'lrInfiniteScroll', - 'LoadConfigHelper' + 'LoadConfigHelper', + 'SocketHelper' ]) .constant('AngularScheduler.partials', $basePath + 'lib/angular-scheduler/lib/') @@ -409,9 +410,9 @@ angular.module('Tower', [ }]) .run(['$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'ViewLicense', - 'Timer', 'ClearScope', 'HideStream', 'Socket', 'LoadConfig', 'Store', + 'Timer', 'ClearScope', 'HideStream', 'Socket', 'LoadConfig', 'Store', 'ShowSocketHelp', function ($compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense, - Timer, ClearScope, HideStream, Socket, LoadConfig, Store) { + Timer, ClearScope, HideStream, Socket, LoadConfig, Store, ShowSocketHelp) { var e, html, sock, checkCount = 0; @@ -421,16 +422,16 @@ angular.module('Tower', [ if (ua.search("MSIE") >= 0) { browser = "MSIE"; } - else if (navigator.userAgent.search("Chrome") >= 0) { + else if (navigator.userAgent.search("Chrome") >= 0 && navigator.userAgent.search("OPR") < 0) { browser = "CHROME"; } else if (navigator.userAgent.search("Firefox") >= 0) { browser = "FF"; } - else if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) { + else if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0 && navigator.userAgent.search("OPR") < 0) { browser = "SAFARI"; } - else if (navigator.userAgent.search("Opera") >= 0) { + else if (navigator.userAgent.search("OPR") >= 0) { browser = "OPERA"; } return browser; @@ -540,8 +541,12 @@ angular.module('Tower', [ $('#' + tabs + ' #' + tab).tab('show'); }; - html = ""; + $rootScope.socketHelp = function() { + ShowSocketHelp(); + }; + + html = ""; e = angular.element(document.getElementById('socket-beacon-div')); e.empty().append(html); $compile(e)($rootScope); diff --git a/awx/ui/static/js/help/ChromeSocketHelp.js b/awx/ui/static/js/help/ChromeSocketHelp.js new file mode 100644 index 0000000000..8134828c00 --- /dev/null +++ b/awx/ui/static/js/help/ChromeSocketHelp.js @@ -0,0 +1,39 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * ChromeSocketHelp.js + * + * Help object for socket connection troubleshooting + * + */ + +'use strict'; + +angular.module('ChromeSocketHelpDefinition', []) + .value('ChromeSocketHelp', { + story: { + hdr: 'Live Events', + width: 510, + height: 560, + steps: [{ + intro: 'Connection status indicator:', + img: { + src: 'socket_indicator.png', + maxWidth: 360 + }, + box: "

When live events are streaming the connection status indicator will be green. Red or orange indicates the " + + "browser is having difficulty connecting to the server, and live events are no longer being received.

If the indicator " + + "appears red or orange, click next for troubleshooting help.

" + }, { + intro: 'Live events connection:', + icon: { + "class": "fa fa-5x fa-rss {{ socketStatus }}-color", + style: "margin-top: 75px;", + containerHeight: 200 + }, + box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + + " {{ socketStatus }}.

If the connection status indicator is not green, have the " + + "system administrator verify this is the correct port and that access to the port is not blocked by a firewall." + }] + } + }); diff --git a/awx/ui/static/js/help/FirefoxSocketHelp.js b/awx/ui/static/js/help/FirefoxSocketHelp.js new file mode 100644 index 0000000000..88081ddc44 --- /dev/null +++ b/awx/ui/static/js/help/FirefoxSocketHelp.js @@ -0,0 +1,77 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * FireFoxSocketHelp.js + * + * Help object for socket connection troubleshooting + * + */ + +'use strict'; + +angular.module('FFSocketHelpDefinition', []) + .value('FFSocketHelp', { + story: { + hdr: 'Live Events', + width: 510, + height: 560, + steps: [{ + intro: 'Connection status indicator:', + img: { + src: 'socket_indicator.png', + maxWidth: 360 + }, + box: "

When live events are streaming the connection status indicator will be green. Red or orange indicates the " + + "browser is having difficulty connecting to the server, and live events are no longer being received.

If the indicator " + + "appears red or orange, click Next for troubleshooting help.

" + }, { + intro: 'Live events connection:', + icon: { + "class": "fa fa-5x fa-rss {{ socketStatus }}-color", + style: "margin-top: 75px;", + containerHeight: 200 + }, + box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + + " {{ socketStatus }}.

If the connection status indicator is not green, have the " + + "system administrator verify this is the correct port and that access to the port is not blocked by a firewall.

" + }, { + intro: 'Self signed certificate:', + icon: { + "class": "fa fa-5x fa-check ok-color", + style: "margin-top: 75px;", + containerHeight: 200 + }, + box: "

If the Tower web server is using a self signed security certificate, Firefox needs to accept the certificate and allow the " + + "connection.

Click Next for help accepting a self signed certificate.

" + }, { + intro: 'Accepting a self-signed certificate:', + img: { + src: 'understand_the_risk.png', + maxWidth: 440 + }, + box: "

Navigate to {{ socketURL }} The above warning will appear.

Click I Understand the Risks

" + }, { + intro: 'Accepting a self-signed certificate:', + img: { + src: 'add_exception.png', + maxWidth: 440 + }, + box: "

Click the Add Exception button." + }, { + intro: 'Accepting a self-signed certificate:', + img: { + src: 'confirm_exception.png', + maxWidth: 340 + }, + box: "

Click the Confirm the Security Exception button. This will add the self signed certificate from the Tower server to Firefox's list of trusted certificates.

" + }, { + intro: 'Accepting a self-signed certificate:', + img: { + src: 'refresh_firefox.png', + maxWidth: 480 + }, + box: "

Now that Firefox has accepted the security certificate the live event connection status indicator should turn green. If it does not, reload Tower by clicking the " + + "Firefox refresh button." + }] + } + }); diff --git a/awx/ui/static/js/help/SafariSocketHelp.js b/awx/ui/static/js/help/SafariSocketHelp.js new file mode 100644 index 0000000000..9cb5e644e8 --- /dev/null +++ b/awx/ui/static/js/help/SafariSocketHelp.js @@ -0,0 +1,49 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * SafairSocketHelp.js + * + * Help object for socket connection troubleshooting + * + */ + +'use strict'; + +angular.module('SafariSocketHelpDefinition', []) + .value('SafariSocketHelp', { + story: { + hdr: 'Live Events', + width: 510, + height: 560, + steps: [{ + intro: 'Connection status indicator:', + img: { + src: 'socket_indicator.png', + maxWidth: 360 + }, + box: "

When live events are streaming the connection status indicator will be green. Red or orange indicates the " + + "browser is having difficulty connecting to the server, and live events are no longer being received.

If the indicator " + + "appears red or orange, click next for troubleshooting help.

" + }, { + intro: 'Live events connection:', + icon: { + "class": "fa fa-5x fa-rss {{ socketStatus }}-color", + style: "margin-top: 75px;", + containerHeight: 200 + }, + box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + + " {{ socketStatus }}.

If the connection status indicator is not green, have the " + + "system administrator verify this is the correct port and that access to the port is not blocked by a firewall.

" + }, { + intro: 'Self signed certificate:', + icon: { + "class": "fa fa-5x fa-check ok-color", + style: "margin-top: 75px;", + containerHeight: 200 + }, + box: "

Safari will not connect to the live event port when the Tower web server is configured with a self signed certificate. Check with a system administrator to" + + "determine if Tower is using a self signed certificate. Installing a signed certificate will fix the problem.

" + + "

Switching browsers to either Chrome or Firefox will work as well.

" + }] + } + }); diff --git a/awx/ui/static/js/helpers/SocketHelper.js b/awx/ui/static/js/helpers/SocketHelper.js new file mode 100644 index 0000000000..68ebd52700 --- /dev/null +++ b/awx/ui/static/js/helpers/SocketHelper.js @@ -0,0 +1,41 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * SocketHelper.js + * + * Show web socket troubleshooting help + * + */ + +'use strict'; + +angular.module('SocketHelper', ['Utilities', 'FFSocketHelpDefinition', 'SafariSocketHelpDefinition' , 'ChromeSocketHelpDefinition']) + +.factory('ShowSocketHelp', ['$location', '$rootScope', 'FFSocketHelp', 'SafariSocketHelp', 'ChromeSocketHelp', 'HelpDialog', +function($location, $rootScope, FFSocketHelp, SafariSocketHelp, ChromeSocketHelp, HelpDialog) { + return function() { + var scope = $rootScope.$new(); + scope.socketPort = $AnsibleConfig.websocket_port; + scope.socketURL = 'https://' + $location.host() + ':' + scope.socketPort + '/'; + if ($rootScope.browser === "FF") { + scope.browserName = "Firefox"; + HelpDialog({ defn: FFSocketHelp, scope: scope }); + } + else if ($rootScope.browser === "SAFARI") { + scope.browserName = "Safari"; + HelpDialog({ defn: SafariSocketHelp, scope: scope }); + } + else { + if ($rootScope.browser === "MSIE") { + scope.browserName = "Internet Explorer"; + } + else if ($rootScope.browser === "CHROME") { + scope.browserName = "Chrome"; + } + else if ($rootScope.browser === "OPERA") { + scope.browserName = "Opera"; + } + HelpDialog({ defn: ChromeSocketHelp, scope: scope }); + } + }; +}]); \ No newline at end of file diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 3edc5c95ca..5c5e13c3d6 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -1125,8 +1125,17 @@ input[type="checkbox"].checkbox-no-label { content: "\f111"; } + .error-color { + color:@red; + } + + .connecting-color { + color: @warning; + } + + .ok-color, .icon-cloud-true { - color: @green; + color: @green; } .icon-cloud-false { @@ -1511,34 +1520,37 @@ tr td button i { /* Help modal dialog */ -#help-modal { +#help-modal-dialog { overflow: hidden; padding: 10px; img { - max-width: 450px; - margin-top: 15px; - margin-bottom: 15px; - border: 1px solid @grey; - box-shadow: 3px 3px 5px 0 @grey; - } + margin-top: 15px; + margin-bottom: 15px; + border: 1px solid @grey; + box-shadow: 3px 3px 5px 0 @grey; + } + + .img-container, + .icon-container { + width: 100%; + text-align: center; + } + + .icon-container { + margin-top: 15px; + margin-bottom: 15px; + } + + .help-box { + width: 100%; + margin-top: 15px; + border-radius: 6px; + color: @grey-txt; + font-size: 14px; + } } -#help-modal .img-container { - width: 100%; - text-align: center; -} - -.help-box { - width: 100%; - margin-top: 15px; - border-radius: 6px; - padding: 8px; - color: @grey-txt; - font-size: 14px; - } - - /* Activity Stream Widget */ #stream-container { diff --git a/awx/ui/static/lib/ansible/Socket.js b/awx/ui/static/lib/ansible/Socket.js index 963b5b80ae..58794f9f26 100644 --- a/awx/ui/static/lib/ansible/Socket.js +++ b/awx/ui/static/lib/ansible/Socket.js @@ -37,14 +37,13 @@ angular.module('SocketIO', ['AuthService', 'Utilities']) var result = ''; switch(status) { case 'error': - result = "There was an error connecting to the websocket server. Click for troubleshooting help."; + result = "Live events: error connecting to the Tower server. Click for troubleshooting help."; break; case 'connecting': - result = "Attempting to connect to the websocket server. Click for troubleshooting help."; + result = "Live events: attempting to connect to the Tower server. Click for troubleshooting help."; break; case "ok": - result = "Connected to the websocket server. Pages containing job status information for playbook runs, SCM updates and inventory " + - "sync processes will automatically update in real-time."; + result = "Live events: connected. Pages containing job status information will automatically update in real-time."; } return result; } diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index f21198850d..f89305fe73 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -312,26 +312,43 @@ angular.module('Utilities', ['RestServices', 'Utilities']) * HelpDialog({ defn: }) * */ -.factory('HelpDialog', ['$rootScope', '$location', 'Store', - function ($rootScope, $location, Store) { +.factory('HelpDialog', ['$rootScope', '$compile', '$location', 'Store', + function ($rootScope, $compile, $location, Store) { return function (params) { var defn = params.defn, current_step = params.step, - autoShow = params.autoShow || false; + autoShow = params.autoShow || false, + scope = (params.scope) ? params.scope : $rootScope.$new(); + + function setButtonMargin() { + var width = ($('.ui-dialog[aria-describedby="help-modal-dialog"] .ui-dialog-buttonpane').innerWidth() / 2) - $('#help-next-button').outerWidth() - 93; + $('#help-next-button').css({'margin-right': width + 'px'}); + } function showHelp(step) { - var btns, ww, width, height, isOpen = false; + var e, btns, ww, width, height, isOpen = false; current_step = step; function buildHtml(step) { var html = ''; - //html += (step.intro) ? "
" + step.intro + "
" : ""; html += "

" + step.intro + "

\n"; - html += "
\n"; - html += ""; - html += "
\n"; + if (step.img) { + html += "
\n"; + html += "\n" : ""; + html += "" + step.box + "
"; html += (autoShow && step.autoOffNotice) ? "
\n" : ""; @@ -346,14 +363,16 @@ angular.module('Utilities', ['RestServices', 'Utilities']) width = (width > ww) ? ww : width; try { - isOpen = $('#help-modal').dialog('isOpen'); - } catch (e) { + isOpen = $('#help-modal-dialog').dialog('isOpen'); + } catch (err) { // ignore } - if (isOpen) { - $('#help-modal').html(buildHtml(defn.story.steps[current_step])); - } else { + e = angular.element(document.getElementById('help-modal-dialog')); + e.empty().html(buildHtml(defn.story.steps[current_step])); + setTimeout(function() { scope.$apply(function() { $compile(e)(scope); }); }); + + if (!isOpen) { // Define buttons based on story length btns = []; if (defn.story.steps.length > 1) { @@ -386,11 +405,11 @@ angular.module('Utilities', ['RestServices', 'Utilities']) btns.push({ text: "Close", click: function () { - $('#help-modal').dialog('close'); + $('#help-modal-dialog').dialog('close'); } }); // Show the dialog - $('#help-modal').html(buildHtml(defn.story.steps[current_step])).dialog({ + $('#help-modal-dialog').dialog({ position: { my: "center top", at: "center top+150", @@ -405,7 +424,7 @@ angular.module('Utilities', ['RestServices', 'Utilities']) hide: 500, resizable: false, close: function () { - $('#help-modal').empty(); + $('#help-modal-dialog').empty(); } }); @@ -442,7 +461,7 @@ angular.module('Utilities', ['RestServices', 'Utilities']) } }); - $('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button') + $('.ui-dialog[aria-describedby="help-modal-dialog"]').find('.ui-dialog-titlebar button') .empty().attr({ 'class': 'close' }).text('x'); @@ -455,11 +474,12 @@ angular.module('Utilities', ['RestServices', 'Utilities']) Store('inventoryAutoHelp', 'on'); } }); + + setButtonMargin(); } } showHelp(0); - }; } ]) diff --git a/awx/ui/static/partials/home.html b/awx/ui/static/partials/home.html index 825103ded0..844d6b15fd 100644 --- a/awx/ui/static/partials/home.html +++ b/awx/ui/static/partials/home.html @@ -25,5 +25,3 @@
- - diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 70b091a4de..1980c85962 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -125,6 +125,7 @@ + @@ -163,6 +164,9 @@ + + + {% endif %} @@ -388,8 +392,7 @@ - - +