diff --git a/awx/ui/static/img/help/groups001.png b/awx/ui/static/img/help/groups001.png new file mode 100644 index 0000000000..9d202cbcac Binary files /dev/null and b/awx/ui/static/img/help/groups001.png differ diff --git a/awx/ui/static/img/help/groups002.png b/awx/ui/static/img/help/groups002.png new file mode 100644 index 0000000000..7476db1903 Binary files /dev/null and b/awx/ui/static/img/help/groups002.png differ diff --git a/awx/ui/static/img/help/groups003.png b/awx/ui/static/img/help/groups003.png new file mode 100644 index 0000000000..c29bc66d37 Binary files /dev/null and b/awx/ui/static/img/help/groups003.png differ diff --git a/awx/ui/static/img/help/groups004.png b/awx/ui/static/img/help/groups004.png new file mode 100644 index 0000000000..7d74e1a80e Binary files /dev/null and b/awx/ui/static/img/help/groups004.png differ diff --git a/awx/ui/static/img/help/groups005.png b/awx/ui/static/img/help/groups005.png new file mode 100644 index 0000000000..805881f84b Binary files /dev/null and b/awx/ui/static/img/help/groups005.png differ diff --git a/awx/ui/static/img/help/groups006.png b/awx/ui/static/img/help/groups006.png new file mode 100644 index 0000000000..b4dcac65d5 Binary files /dev/null and b/awx/ui/static/img/help/groups006.png differ diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 51937f7bca..a95a888464 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -76,7 +76,7 @@ angular.module('ansible', [ 'StreamWidget', 'JobsHelper', 'InventoryStatusDefinition', - 'InventorySummaryHelpDefinition', + 'InventoryGroupsHelpDefinition', 'InventoryHostsHelpDefinition', 'InventoryTree', 'CredentialsHelper', diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index e976465537..64de7d27ac 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -316,7 +316,8 @@ function InventoriesEdit ($scope, $location, $routeParams, $compile, GenerateLis GetSyncStatusMsg, InjectHosts, HostsReload, GroupsAdd, GroupsEdit, GroupsDelete, Breadcrumbs, LoadBreadCrumbs, Empty, Rest, ProcessErrors, InventoryUpdate, Alert, ToggleChildren, ViewUpdateStatus, GroupsCancelUpdate, Find, HostsCreate, EditInventoryProperties, HostsEdit, HostsDelete, ToggleHostEnabled, CopyMoveGroup, CopyMoveHost, - Stream, GetBasePath, ShowJobSummary, ApplyEllipsis, WatchInventoryWindowResize) + Stream, GetBasePath, ShowJobSummary, ApplyEllipsis, WatchInventoryWindowResize, HelpDialog, InventoryGroupsHelp, + Store) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -362,8 +363,25 @@ function InventoriesEdit ($scope, $location, $routeParams, $compile, GenerateLis InjectHosts({ scope: $scope, inventory_id: $scope.inventory_id, tree_id: $scope.selected_tree_id, group_id: $scope.selected_group_id }); // As the window shrinks and expands, apply ellipsis - setTimeout(function() { ApplyEllipsis('#groups_table .group-name a'); }, 2500); //give the window time to display + setTimeout(function() { + // Hack to keep group name from slipping to a new line + $('#groups_table .name-column').each( function() { + var td_width = $(this).width(); + var level_width = $(this).find('.level').width(); + var level_padding = parseInt($(this).find('.level').css('padding-left').replace(/px/,'')); + var level = level_width + level_padding; + var pct = ( 100 - Math.ceil((level / td_width)*100) ) + '%'; + $(this).find('.group-name').css({ width: pct }); + }); + ApplyEllipsis('#groups_table .group-name a'); + ApplyEllipsis('#hosts_table .host-name a'); + }, 2500); //give the window time to display WatchInventoryWindowResize(); + + var inventoryAutoHelp = Store('inventoryAutoHelp'); + if (inventoryAutoHelp !== 'off' && $scope.autoShowGroupHelp) { + $scope.showGroupHelp({ autoShow: true }); + } }); @@ -545,17 +563,24 @@ function InventoriesEdit ($scope, $location, $routeParams, $compile, GenerateLis ShowJobSummary({ job_id: job_id }); } + $scope.showGroupHelp = function(params) { + var opts = { defn: InventoryGroupsHelp }; + if (params) { + opts.autoShow = params.autoShow || false; + } + HelpDialog(opts); + } + //Load tree data for the first time BuildTree({ scope: $scope, inventory_id: $scope.inventory_id, refresh: false }); - -} + } InventoriesEdit.$inject = [ '$scope', '$location', '$routeParams', '$compile', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts', 'BuildTree', 'Wait', 'GetSyncStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsAdd', 'GroupsEdit', 'GroupsDelete', 'Breadcrumbs', 'LoadBreadCrumbs', 'Empty', 'Rest', 'ProcessErrors', 'InventoryUpdate', 'Alert', 'ToggleChildren', 'ViewUpdateStatus', 'GroupsCancelUpdate', 'Find', 'HostsCreate', 'EditInventoryProperties', 'HostsEdit', 'HostsDelete', 'ToggleHostEnabled', 'CopyMoveGroup', 'CopyMoveHost', 'Stream', 'GetBasePath', 'ShowJobSummary', - 'ApplyEllipsis', 'WatchInventoryWindowResize' + 'ApplyEllipsis', 'WatchInventoryWindowResize', 'HelpDialog', 'InventoryGroupsHelp', 'Store' ]; diff --git a/awx/ui/static/js/help/InventoryGroups.js b/awx/ui/static/js/help/InventoryGroups.js new file mode 100644 index 0000000000..29d3e030b2 --- /dev/null +++ b/awx/ui/static/js/help/InventoryGroups.js @@ -0,0 +1,52 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * InventoryGroups.js + * + * Help object for inventory groups/hosts page. + * + * @dict + */ +angular.module('InventoryGroupsHelpDefinition', []) + .value( + 'InventoryGroupsHelp', { + story: { + hdr: 'Building your inventory', + steps: { + step1: { + intro: 'Start by creating a group:', + img: { src: 'groups001.png', maxWidth: 338 , maxHeight: 222 }, + box: "Click the button to add a new group to the inventory.", + autoOffNotice: true, + height: 500 + }, + step2: { + img: { src: 'groups002.png', maxWidth: 443, maxHeight: 251 }, + box: "Provide a name, description and any variables.", + height: 460 + }, + step3: { + img: { src: 'groups003.png', maxWidth: 412, maxHeight: 215 }, + box: "If this a cloud inventory, choose a Source.", + height: 460 + }, + step4: { + img: { src: 'groups004.png', maxWidth: 261, maxHeight: 221 }, + box: "For a cloud inventory, start the sync process by clicking .", + height: 460 + }, + step5: { + intro: "Create subgroups by first clicking a group name to select it.", + img: { src: 'groups005.png', maxWidth: 430, maxHeight: 206 }, + box: "With a group selected, click the to create the new subgroup.", + height: 500 + }, + step6: { + intro: ' ', + img: { src: 'groups006.png', maxWidth: 263, maxHeight: 211 }, + box: "Copy or move a group by dragging and dropping the group name.", + height: 460 + } + } + } + }); diff --git a/awx/ui/static/js/help/InventorySummary.js b/awx/ui/static/js/help/InventorySummary.js deleted file mode 100644 index f7233a1b82..0000000000 --- a/awx/ui/static/js/help/InventorySummary.js +++ /dev/null @@ -1,29 +0,0 @@ -/********************************************* - * Copyright (c) 2014 AnsibleWorks, Inc. - * - * InventorySummary.js - * Help object for Inventory-> Groups page. - * - * @dict - */ -angular.module('InventorySummaryHelpDefinition', []) - .value( - 'InventorySummaryHelp', { - story: { - hdr: 'Building Your Inventory', - steps: { - step1: { - intro: 'Start by creating a group:', - img: { src: 'help002.png', maxWidth: 460 , maxHeight: 111 }, - box: "Click the Create New button and add a new group to the inventory.", - height: 400 - }, - step2: { - intro: 'After creating a group, add hosts:', - img: { src: 'help001.png', maxWidth: 467, maxHeight: 208 }, - box: "Navigate to Hosts using the drop-down menu, where you can add hosts to the new group", - height: 480 - } - } - } - }); \ No newline at end of file diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 073620cd2d..e2480d8820 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -12,8 +12,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'GroupsHelper', 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', - 'PromptDialog', 'InventorySummaryHelpDefinition', 'CredentialsListDefinition', - 'InventoryTree' + 'PromptDialog', 'CredentialsListDefinition','InventoryTree' ]) .factory('GetSourceTypeOptions', [ 'Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) { @@ -391,7 +390,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope.searchCleanup(); } scope.formModalActionDisabled = false; - scope.showGroupHelp = false; //get rid of the Hint BuildTree({ scope: parent_scope, inventory_id: inventory_id, refresh: true, new_group_id: group_id }); WatchInventoryWindowResize(); } @@ -848,7 +846,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } scope.formModalActionDisabled = false; - scope.showGroupHelp = false; //get rid of the Hint $('#form-modal').modal('hide'); @@ -892,7 +889,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } data['source_regions'] = r.join(); - if (scope['source'].value == 'ec2') { + if (scope['source'] && scope['source'].value == 'ec2') { // for ec2, validate variable data try { if (scope.envParseType == 'json') { diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index e53ec26a24..8e6915fcc9 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -91,7 +91,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H html += "\n"; html += "" + job.id + "\n"; html += "\n"; - html += "" + job.name + "\n"; + html += "" + "language_features/roletest.yml(limit:all:cloud)therealsuperlonglaskaname\n"; html += "\n"; } html += "\n"; diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 7c0b446015..3658629866 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -19,6 +19,15 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi $(window).resize(function() { clearTimeout(timeOut); timeOut = setTimeout(function() { + // Hack to stop group-name div slipping to a new line + $('#groups_table .name-column').each( function() { + var td_width = $(this).width(); + var level_width = $(this).find('.level').width(); + var level_padding = parseInt($(this).find('.level').css('padding-left').replace(/px/,'')); + var level = level_width + level_padding; + var pct = ( 100 - Math.ceil((level / td_width)*100) ) + '%'; + $(this).find('.group-name').css({ width: pct }); + }); ApplyEllipsis('#groups_table .group-name a'); ApplyEllipsis('#hosts_table .host-name a'); }, 100); diff --git a/awx/ui/static/js/lists/InventoryGroups.js b/awx/ui/static/js/lists/InventoryGroups.js index 79b8e9750f..c5a2c9e76f 100644 --- a/awx/ui/static/js/lists/InventoryGroups.js +++ b/awx/ui/static/js/lists/InventoryGroups.js @@ -1,9 +1,7 @@ /********************************************* * Copyright (c) 2014 AnsibleWorks, Inc. * - * InventorySummary.js - * - * Summary of groups contained within an inventory + * InventoryGroups.js * */ angular.module('InventoryGroupsDefinition', []) @@ -25,7 +23,7 @@ angular.module('InventoryGroupsDefinition', []) name: { label: 'Groups', key: true, - ngClick: "\{\{ 'showHosts(' + group.id + ',' + group.group_id + ', false)' \}\}", + ngClick: "showHosts(group.id,group.group_id, false)", ngClass: "group.selected_class", hasChildren: true, columnClass: 'col-lg-9 col-md-9 col-sm-7 col-xs-7', @@ -66,11 +64,8 @@ angular.module('InventoryGroupsDefinition', []) }, help: { mode: 'all', - awToolTip: - //"
" + - //"

Need help getting started creating your inventory?

Click here for help.

", - "

Need help getting started creating your inventory?

Click here for help.

", - ngClick: "showHelp()", + awToolTip: "Get help building your inventory", + ngClick: "showGroupHelp()", id: "inventory-summary-help" } }, @@ -128,4 +123,4 @@ angular.module('InventoryGroupsDefinition', []) } } }); - \ No newline at end of file + diff --git a/awx/ui/static/js/lists/InventoryHosts.js b/awx/ui/static/js/lists/InventoryHosts.js index c0f9ad40b0..0eeb7204b4 100644 --- a/awx/ui/static/js/lists/InventoryHosts.js +++ b/awx/ui/static/js/lists/InventoryHosts.js @@ -57,7 +57,6 @@ angular.module('InventoryHostsDefinition', []) fieldActions: { enabled_flag: { - //label: 'Enabled', iconClass: "{{ 'fa icon-enabled-' + host.enabled }}", dataPlacement: 'top', awToolTip: "{{ host.enabledToolTip }}", @@ -65,8 +64,6 @@ angular.module('InventoryHostsDefinition', []) ngClick: "toggleHostEnabled(host.id, host.has_inventory_sources)" }, active_failures: { - //label: 'Job Status', - //ngHref: "\{\{'/#/hosts/' + host.id + '/job_host_summaries/?inventory=' + inventory_id \}\}", awPopOver: "{{ host.job_status_html }}", dataTitle: "{{ host.job_status_title }}", awToolTip: "{{ host.badgeToolTip }}", @@ -105,15 +102,6 @@ angular.module('InventoryHostsDefinition', []) awToolTip: "View Activity Stream", mode: 'all', ngShow: "user_is_superuser" - }, - help: { - mode: 'all', - awToolTip: - //"
" + - //"

Need help getting started creating your inventory?

Click here for help.

", - "

Need help getting started creating your inventory?

Click here for help.

", - ngClick: "showHelp()", - id: "inventory-summary-help" } } diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 2b729b0765..9c582cea07 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -71,7 +71,7 @@ body.modal-open { .group-name { display: inline-block; - width: 90%; + width: 85%; } a { @@ -223,6 +223,14 @@ hr { display: inline-block; } +.help-auto-off { + margin-top: 15px; + margin-bottom: 15px; + label { + font-weight: normal; + } +} + /* help collapse */ h4.panel-title { font-size: 14px; @@ -315,7 +323,7 @@ dd { } .break { - word-wrap: break-word; + word-break: break-all; } .login-alert { @@ -1059,16 +1067,17 @@ input[type="checkbox"].checkbox-no-label { cursor: default; } /* Padding levels used on job events and inventory groups */ - .level-1 { padding-left: 20px; } - .level-2 { padding-left: 40px; } - .level-3 { padding-left: 60px; } - .level-4 { padding-left: 80px; } - .level-5 { padding-left: 100px; } - .level-6 { padding-left: 120px; } - .level-7 { padding-left: 140px; } - .level-8 { padding-left: 160px; } - .level-9 { padding-left: 180px; } - .level-10 { padding-left: 200px; } + .level { display: inline-block; } + .level-1 { padding-left: 15px; } + .level-2 { padding-left: 30px; } + .level-3 { padding-left: 45px; } + .level-4 { padding-left: 60px; } + .level-5 { padding-left: 75px; } + .level-6 { padding-left: 90px; } + .level-7 { padding-left: 105px; } + .level-8 { padding-left: 120px; } + .level-9 { padding-left: 135px; } + .level-10 { padding-left: 150px; } .level-3-detail { padding-left: 80px; @@ -1344,7 +1353,7 @@ tr td button i { text-align: center; border: 1px solid @info-border; border-radius: 6px; - margin-top: 0; + margin-top: 10px; margin-bottom: 10px; padding: 10px; background-color: @info; @@ -1440,6 +1449,20 @@ tr td button i { } @media (min-width: 768px) and (max-width: 1199px) { + + .level-1, + .level-2, + .level-3, + .level-4, + .level-5, + .level-6, + .level-7, + .level-8, + .level-9, + .level-10, + .level-3-detail { + padding-left: 0; + } .list-actions button, .list-actions .checkbox-inline { margin-top: 10px; @@ -1465,6 +1488,13 @@ tr td button i { .level-1, .level-2, .level-3, + .level-4, + .level-5, + .level-6, + .level-7, + .level-8, + .level-9, + .level-10, .level-3-detail { padding-left: 0; } diff --git a/awx/ui/static/lib/ansible/InventoryTree.js b/awx/ui/static/lib/ansible/InventoryTree.js index bafdb5f01a..ac4b13e68b 100644 --- a/awx/ui/static/lib/ansible/InventoryTree.js +++ b/awx/ui/static/lib/ansible/InventoryTree.js @@ -136,6 +136,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P .success( function(data, status, headers, config) { buildAllHosts(data); buildGroups(data, 0, 0); + scope.autoShowGroupHelp = (data.length == 0) ? true : false; if (refresh) { scope.groups = groups; scope.$emit('GroupTreeRefreshed', inventory_name, groups, emit); diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index 4d4ba92c40..02849cad4f 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -243,7 +243,7 @@ angular.module('Utilities',['RestServices', 'Utilities']) } }]) - .factory('HelpDialog', ['$rootScope', '$location', function($rootScope, $location) { + .factory('HelpDialog', ['$rootScope', '$location', 'Store', function($rootScope, $location, Store) { return function(params) { // Display a help dialog // @@ -257,6 +257,7 @@ angular.module('Utilities',['RestServices', 'Utilities']) var defn = params.defn; var nxtStory = { story: { steps: { } } }; var width, height; + var autoShow = params.autoShow || false; function buildHtml(step) { var html = ''; @@ -270,6 +271,8 @@ angular.module('Utilities',['RestServices', 'Utilities']) html += ">"; } html += (step.box) ? "
" + step.box + "
" : ""; + html += (autoShow && step.autoOffNotice) ? "
\n" : ""; return html; } @@ -291,7 +294,7 @@ angular.module('Utilities',['RestServices', 'Utilities']) } nxtStory.story.hdr = defn.story.hdr; - nxtStep = function() { + var nxtStep = function() { showHelp({ defn: nxtStory }); } @@ -312,8 +315,9 @@ angular.module('Utilities',['RestServices', 'Utilities']) hide: 500, close: function() { $('#help-modal').empty(); } }); - $('.ui-dialog-buttonset button').addClass('btn btn-primary').focus(); - $('.ui-dialog-titlebar-close').empty().removeClass('close').removeClass('ui-dialog-titlebar-close').addClass('close').append('x'); + $('.ui-dialog-buttonset button').attr({ 'class': 'btn btn-primary' }); + $('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button') + .empty().attr({ 'class': 'close' }).text('x'); } else { try { @@ -333,9 +337,19 @@ angular.module('Utilities',['RestServices', 'Utilities']) hide: 500, close: function() { $('#help-modal').empty(); } }); - $('.ui-dialog-buttonset button').addClass('btn btn-primary').focus(); - $('.ui-dialog-titlebar button').empty().removeClass('close').removeClass('ui-dialog-titlebar-close').addClass('close').append('x'); + $('.ui-dialog-buttonset button').attr({ 'class': 'btn btn-primary' }); + $('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button') + .empty().attr({ 'class': 'close' }).text('x'); } + + $('#auto-off-checkbox').click(function() { + if ($('input[name="auto-off-checkbox"]:checked').length) { + Store('inventoryAutoHelp','off'); + } + else { + Store('inventoryAutoHelp','on'); + } + }); } showHelp(params); diff --git a/awx/ui/static/lib/ansible/generator-helpers.js b/awx/ui/static/lib/ansible/generator-helpers.js index 2253508c2a..d49331a8a3 100644 --- a/awx/ui/static/lib/ansible/generator-helpers.js +++ b/awx/ui/static/lib/ansible/generator-helpers.js @@ -471,8 +471,8 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers']) // Add collapse/expand icon --used on job_events page if (list['hasChildren'] && field.hasChildren) { - html += " " + - " "; + html += "
" + + "
"; //ng-show=\"'\{\{ " + list.iterator + ".related.children \}\}' !== ''\" } @@ -548,9 +548,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers']) html += field.text; } - if (list['hasChildren'] && field.hasChildren) { - html += "
"; - } + //if (list['hasChildren'] && field.hasChildren) { + // html += ""; + //} // close the link if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref ) diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 43bdfc6ad6..4c4f2e18e9 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -122,7 +122,7 @@ - +