From 4bcda34c3c49647f252a739d5e9e7310167e7e89 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Tue, 15 Oct 2013 02:56:39 -0400 Subject: [PATCH] Created new help widget and applied to Inventory-> Groups. Help can now be a movable dialog with images and text. Help definitions (objects) can include many steps to tell a story or walk through a process. --- .../custom-theme/jquery-ui-1.10.3.custom.css | 34 ++++---- awx/ui/static/img/help/help001.png | Bin 0 -> 21113 bytes awx/ui/static/img/help/help002.png | Bin 0 -> 8062 bytes awx/ui/static/js/app.js | 3 +- awx/ui/static/js/controllers/Groups.js | 5 +- awx/ui/static/js/controllers/Hosts.js | 5 +- awx/ui/static/js/help/InventorySummary.js | 29 +++++++ awx/ui/static/js/helpers/Groups.js | 58 +++++++++---- awx/ui/static/js/helpers/inventory.js | 13 +-- awx/ui/static/js/lists/InventorySummary.js | 13 +-- awx/ui/static/js/lists/JobHosts.js | 2 +- awx/ui/static/js/lists/Projects.js | 2 +- awx/ui/static/js/widgets/ObjectCount.js | 20 ----- awx/ui/static/less/ansible-ui.less | 59 +++++++++++-- awx/ui/static/lib/ansible/Utilities.js | 79 +++++++++++++++++- awx/ui/static/lib/ansible/form-generator.js | 24 +++--- awx/ui/static/lib/ansible/list-generator.js | 7 ++ awx/ui/templates/ui/index.html | 10 ++- 18 files changed, 257 insertions(+), 106 deletions(-) create mode 100644 awx/ui/static/img/help/help001.png create mode 100644 awx/ui/static/img/help/help002.png create mode 100644 awx/ui/static/js/help/InventorySummary.js diff --git a/awx/ui/static/css/custom-theme/jquery-ui-1.10.3.custom.css b/awx/ui/static/css/custom-theme/jquery-ui-1.10.3.custom.css index a05b962cc1..a268ebf601 100644 --- a/awx/ui/static/css/custom-theme/jquery-ui-1.10.3.custom.css +++ b/awx/ui/static/css/custom-theme/jquery-ui-1.10.3.custom.css @@ -608,7 +608,7 @@ button.ui-button::-moz-focus-inner { height: 100%; } .ui-progressbar .ui-progressbar-overlay { - background: url("images/animated-overlay.gif"); + background: url("/static/css/custom-theme/images/animated-overlay.gif"); height: 100%; filter: alpha(opacity=25); opacity: 0.25; @@ -806,7 +806,7 @@ body .ui-tooltip { } .ui-widget-content { border: 1px solid #a6c9e2; - background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; + background: #fcfdfd url(/static/css/custom-theme/images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #36454F; font-weight: normal; } @@ -815,7 +815,7 @@ body .ui-tooltip { } .ui-widget-header { border: 1px solid #a6c9e2; - background: #ffffff url(images/ui-bg_flat_50_ffffff_40x100.png) 50% 50% repeat-x; + background: #ffffff url(/static/css/custom-theme/images/ui-bg_flat_50_ffffff_40x100.png) 50% 50% repeat-x; color: #36454F; font-weight: bold; } @@ -829,7 +829,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #a6c9e2; - background: #ffffff url(images/ui-bg_flat_100_ffffff_40x100.png) 50% 50% repeat-x; + background: #ffffff url(/static/css/custom-theme/images/ui-bg_flat_100_ffffff_40x100.png) 50% 50% repeat-x; font-weight: bold; color: #0088cc; } @@ -846,7 +846,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #e3e3e3; - background: #e5e3e3 url(images/ui-bg_flat_75_e5e3e3_40x100.png) 50% 50% repeat-x; + background: #e5e3e3 url(/static/css/images/ui-bg_flat_75_e5e3e3_40x100.png) 50% 50% repeat-x; font-weight: bold; color: #005580; } @@ -861,7 +861,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #e3e3e3; - background: #f5f5f5 url(images/ui-bg_inset-hard_100_f5f5f5_1x100.png) 50% 50% repeat-x; + background: #f5f5f5 url(/static/css/custom-theme/images/ui-bg_inset-hard_100_f5f5f5_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #36454F; } @@ -878,7 +878,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { border: 1px solid #fad42e; - background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; + background: #fbec88 url(/static/css/custom-theme/images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; } .ui-state-highlight a, @@ -890,7 +890,7 @@ body .ui-tooltip { .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { border: 1px solid #cd0a0a; - background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; + background: #fef1ec url(/static/css/custom-theme/images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } .ui-state-error a, @@ -936,27 +936,27 @@ body .ui-tooltip { } .ui-icon, .ui-widget-content .ui-icon { - background-image: url(images/ui-icons_469bdd_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_469bdd_256x240.png); } .ui-widget-header .ui-icon { - background-image: url(images/ui-icons_36454F_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_36454F_256x240.png); } .ui-state-default .ui-icon { - background-image: url(images/ui-icons_0088cc_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_0088cc_256x240.png); } .ui-state-hover .ui-icon, .ui-state-focus .ui-icon { - background-image: url(images/ui-icons_217bc0_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_217bc0_256x240.png); } .ui-state-active .ui-icon { - background-image: url(images/ui-icons_36454F_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_36454F_256x240.png); } .ui-state-highlight .ui-icon { - background-image: url(images/ui-icons_2e83ff_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_2e83ff_256x240.png); } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon { - background-image: url(images/ui-icons_cd0a0a_256x240.png); + background-image: url(/static/css/custom-theme/images/ui-icons_cd0a0a_256x240.png); } /* positioning */ @@ -1169,14 +1169,14 @@ body .ui-tooltip { /* Overlays */ .ui-widget-overlay { - background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + background: #aaaaaa url(/static/css/custom-theme/images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3; filter: Alpha(Opacity=30); } .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; - background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + background: #aaaaaa url(/static/css/custom-theme/images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3; filter: Alpha(Opacity=30); border-radius: 8px; diff --git a/awx/ui/static/img/help/help001.png b/awx/ui/static/img/help/help001.png new file mode 100644 index 0000000000000000000000000000000000000000..0455fa7f8b52bd6e01114386e905eacc5bb5a177 GIT binary patch literal 21113 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 Vv2Ew*069>Hl95mpuMss0`5&}@aHjwO literal 0 HcmV?d00001 diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 5af7f5541b..ae2831ac18 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -75,7 +75,8 @@ angular.module('ansible', [ 'SCMSyncStatusWidget', 'ObjectCountWidget', 'JobsHelper', - 'InventoryStatusDefinition' + 'InventoryStatusDefinition', + 'InventorySummaryHelpDefinition' ]) .config(['$routeProvider', function($routeProvider) { $routeProvider. diff --git a/awx/ui/static/js/controllers/Groups.js b/awx/ui/static/js/controllers/Groups.js index 42eb95f02a..18f293c461 100644 --- a/awx/ui/static/js/controllers/Groups.js +++ b/awx/ui/static/js/controllers/Groups.js @@ -10,7 +10,7 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryGroupsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, TreeInit, GetBasePath, GroupsList, GroupsAdd, GroupsEdit, LoadInventory, - GroupsDelete, RefreshGroupName, EditInventory, SetShowGroupHelp, InventoryStatus) + GroupsDelete, RefreshGroupName, EditInventory, InventoryStatus) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -34,7 +34,6 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeP scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() { LoadBreadCrumbs({ path: '/inventories/' + id, title: scope.inventory_name }); TreeInit(scope.TreeParams); - SetShowGroupHelp({ scope: scope }); if (!scope.$$phase) { scope.$digest(); } @@ -242,6 +241,6 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeP InventoryGroups.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryGroupsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory', - 'GroupsDelete', 'RefreshGroupName', 'EditInventory', 'SetShowGroupHelp', 'InventoryStatus' + 'GroupsDelete', 'RefreshGroupName', 'EditInventory', 'InventoryStatus' ]; \ No newline at end of file diff --git a/awx/ui/static/js/controllers/Hosts.js b/awx/ui/static/js/controllers/Hosts.js index 3c354fb151..1e49b9f966 100644 --- a/awx/ui/static/js/controllers/Hosts.js +++ b/awx/ui/static/js/controllers/Hosts.js @@ -13,7 +13,7 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, GetBasePath, HostsList, HostsAdd, HostsEdit, HostsDelete, - HostsReload, LoadSearchTree, EditHostGroups, SetShowGroupHelp) + HostsReload, LoadSearchTree, EditHostGroups) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -36,7 +36,6 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa } scope.loadBreadCrumbsRemove = scope.$on('buildAllGroups', function(e, inventory_name) { LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name }); - SetShowGroupHelp({ scope: scope }); }); // Sets up the search tree and loads All Hosts for the inventory @@ -138,6 +137,6 @@ InventoryHosts.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$lo 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete', - 'HostsReload', 'LoadSearchTree', 'EditHostGroups', 'SetShowGroupHelp' + 'HostsReload', 'LoadSearchTree', 'EditHostGroups' ]; diff --git a/awx/ui/static/js/help/InventorySummary.js b/awx/ui/static/js/help/InventorySummary.js new file mode 100644 index 0000000000..f58bc7382e --- /dev/null +++ b/awx/ui/static/js/help/InventorySummary.js @@ -0,0 +1,29 @@ +/********************************************* + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * InventorySummary.js + * Help object for Inventory-> Groups page. + * + * @dict + */ +angular.module('InventorySummaryHelpDefinition', []) + .value( + 'InventorySummaryHelp', { + story: { + hdr: 'Getting Started', + steps: { + step1: { + intro: 'Start by creating a group:', + img: 'help002.png', + 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: 'help001.png', + 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 2555f8f5ab..2dee159da2 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -9,7 +9,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', - 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper' + 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', + 'PromptDialog', 'InventorySummaryHelpDefinition' ]) .factory('GetSourceTypeOptions', [ function() { @@ -169,9 +170,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' .factory('InventoryStatus', [ '$rootScope', '$routeParams', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'InventorySummary', - 'GenerateList', 'ClearScope', 'SearchInit', 'PaginateInit', 'Refresh', 'InventoryUpdate', 'GroupsEdit', 'ShowUpdateStatus', + 'GenerateList', 'ClearScope', 'SearchInit', 'PaginateInit', 'Refresh', 'InventoryUpdate', 'GroupsEdit', 'ShowUpdateStatus', 'HelpDialog', + 'ShowGroupHelp', 'InventorySummaryHelp', function($rootScope, $routeParams, Rest, Alert, ProcessErrors, GetBasePath, FormatDate, InventorySummary, GenerateList, ClearScope, SearchInit, - PaginateInit, Refresh, InventoryUpdate, GroupsEdit, ShowUpdateStatus) { + PaginateInit, Refresh, InventoryUpdate, GroupsEdit, ShowUpdateStatus, HelpDialog, ShowGroupHelp, InventorySummaryHelp) { return function(params) { //Build a summary of a given inventory @@ -267,6 +269,17 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } scope.search(list.iterator); + + if (scope.removeShowHelp) { + scope.removeShowHelp(); + } + scope.removeShowHelp = scope.$on('ShowHelp', function() { + HelpDialog({ defn: InventorySummaryHelp }); + }); + + scope.showHelp = function() { + scope.$emit('ShowHelp'); + } scope.viewUpdateStatus = function(id) { var found = false; @@ -365,20 +378,29 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' break; } } - if (found && group.related.current_update) { - Rest.setUrl(group.related.current_update); - Rest.get() - .success( function(data, status, headers, config) { - scope.$emit('Check_Cancel', data); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Call to ' + group.related.current_update + ' failed. GET status: ' + status }); - }); + if (group.summary_fields.inventory_source.source !== '' && + group.summary_fields.inventory_source.source !== null) { + // the group has a source + if (group.related.current_update) { + // there is an update currently running + Rest.setUrl(group.related.current_update); + Rest.get() + .success( function(data, status, headers, config) { + scope.$emit('Check_Cancel', data); + }) + .error( function(data, status, headers, config) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Call to ' + group.related.current_update + ' failed. GET status: ' + status }); + }); + } + else { + Alert('Update Not Found', 'An Inventory update does not appear to be running for group: ' + name + '. Click the Refresh ' + + 'button to view the latet status.', 'alert-info'); + } } else { - Alert('Update Not Found', 'An Inventory update does not appear to be running for group: ' + name + '. Click the Refresh ' + - 'button to view the latet status.', 'alert-info'); + Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group and provide external Source settings ' + + 'before attempting an update.', 'alert-info'); } } @@ -394,8 +416,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' for (var i=0; i < scope.groups.length; i++) { if (scope.groups[i].id == id) { if (scope.groups[i].summary_fields.inventory_source.source == "" || scope.groups[i].summary_fields.inventory_source.source == null) { - Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group, provide Source settings, ' + - 'and then run an update.', 'alert-info'); + Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group and provide ' + + 'external Source settings before attempting an update.', 'alert-info'); } else if (scope.groups[i].summary_fields.inventory_source.status == 'updating') { Alert('Update in Progress', 'The inventory update process is currently running for group ' + @@ -433,6 +455,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' } } } + + ShowGroupHelp({ scope: scope }); } }]) diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 1106e17288..54c1e79fab 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -560,25 +560,20 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi } }]) - .factory('SetShowGroupHelp', ['Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) { + .factory('ShowGroupHelp', ['Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) { return function(params) { // Check if inventory has groups. If not, turn on hints to let user know groups are required // before hosts can be added var scope = params.scope; - var url = GetBasePath('inventory') + scope.inventory_id + '/groups/'; + var url = GetBasePath('inventory') + scope.inventory_id + '/groups/?page=1'; Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { - if (data.results.length > 0) { - scope.showGroupHelp = false; - } - else { - scope.showGroupHelp = true; - } + scope.$emit('ShowHelp'); }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to retrieve inventory groups. GET returned status: ' + status }); + { hdr: 'Error!', msg: 'Failed to retrieve inventory group count. ' + url + ' GET status: ' + status }); }); } }]) diff --git a/awx/ui/static/js/lists/InventorySummary.js b/awx/ui/static/js/lists/InventorySummary.js index 374245cd91..9146d238a0 100644 --- a/awx/ui/static/js/lists/InventorySummary.js +++ b/awx/ui/static/js/lists/InventorySummary.js @@ -109,22 +109,13 @@ angular.module('InventorySummaryDefinition', []) dataPlacement: 'top' }, help: { - awPopOver: - "
\n" + - "
failed
Errors were encountered with the most recent inventory update.
\n" + - "
n/a
The group is not configured for inventory update.
\n" + - "
never
The inventory update has never run for the group.
\n" + - "
successful
The most recent inventory update ran to completion without incident.
\n" + - "
updating
The inventory update is currently running.
\n" + - "
\n", dataPlacement: 'top', - dataContainer: 'body', icon: "icon-question-sign", mode: 'all', 'class': 'btn-xs btn-info btn-help', awToolTip: 'Click for help', - dataTitle: 'Update Status', - iconSize: 'large' + iconSize: 'large', + ngClick: "showHelp()" }, refresh: { awRefresh: true, diff --git a/awx/ui/static/js/lists/JobHosts.js b/awx/ui/static/js/lists/JobHosts.js index 5358879aad..38ed204d73 100644 --- a/awx/ui/static/js/lists/JobHosts.js +++ b/awx/ui/static/js/lists/JobHosts.js @@ -109,7 +109,7 @@ angular.module('JobHostDefinition', []) "
Unreachable
Times the ansible server could not reach the host.
\n" + "
Skipped
Tasks bypassed and not performed on the host due to prior task failure or the host being unreachable.
\n" + "\n", - dataPlacement: 'top', + dataPlacement: 'left', dataContainer: "body", icon: "icon-question-sign", mode: 'all', diff --git a/awx/ui/static/js/lists/Projects.js b/awx/ui/static/js/lists/Projects.js index ca74747ca9..d4a2937924 100644 --- a/awx/ui/static/js/lists/Projects.js +++ b/awx/ui/static/js/lists/Projects.js @@ -60,7 +60,7 @@ angular.module('ProjectsListDefinition', []) "
Missing
The local project directory is missing.
\n" + "
N/A
The project does not use SCM, so an update status is not available.
\n" + "\n", - dataPlacement: 'top', + dataPlacement: 'left', dataContainer: 'body', icon: "icon-question-sign", mode: 'all', diff --git a/awx/ui/static/js/widgets/ObjectCount.js b/awx/ui/static/js/widgets/ObjectCount.js index c61e11be49..e677e6b688 100644 --- a/awx/ui/static/js/widgets/ObjectCount.js +++ b/awx/ui/static/js/widgets/ObjectCount.js @@ -31,26 +31,6 @@ angular.module('ObjectCountWidget', ['RestServices', 'Utilities']) cnt++; } if (cnt == expected) { - // sort the list of objs - //for (var key in counts) { - // if (key !== 'hosts' && key !== 'groups') { - // keys.push(key); - // } - //} - // sort the keys, forcing groups and hosts to appear directlry after inventory - //keys.sort(); - //var new_keys = []; - //for (var i=0; i < keys.length; i++) { - // if (keys[i] == 'inventory') { - // new_keys.push('inventory'); - // new_keys.push('groups'); - // new_keys.push('hosts'); - // } - // else { - // new_keys.push(keys[i]); - // } - //} - //keys = new_keys; html = "
\n"; html += "
System Summary
\n"; html += "
\n"; diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 046bc5bf44..01279404b2 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -7,15 +7,18 @@ * */ -@black: #171717; -@warning: #FF9900; -@red: #da4f49; -@red-hover: #AE3F3A; -@green: #5bb75b; -@blue: #1778c3; /* logo blue */ -@blue-link: #0088cc; -@grey: #A9A9A9; -@green: #5bb75b; +@black: #171717; +@warning: #FF9900; +@red: #da4f49; +@red-hover: #AE3F3A; +@green: #5bb75b; +@blue: #1778c3; /* logo blue */ +@blue-link: #0088cc; +@grey: #A9A9A9; +@green: #5bb75b; +@info: #d9edf7; /* alert info background color */ +@info-border: #bce8f1; /* alert info border color */ +@info-color: #3a87ad; html { background-color: @black; @@ -1204,6 +1207,44 @@ tr td button i { margin-bottom: 5px; } +/* help dialog */ + +#help-modal { + overflow: hidden; + padding: 10px; + text-align: center; +} + +.help-box { + text-align: center; + border: 1px solid @info-border; + border-radius: 6px; + margin-top: 0; + margin-bottom: 10px; + padding: 10px; + background-color: @info; + color: @info-color; +} + +.help-intro { + width: 100; + text-align: left; + margin: 15px 0 30px 0; + font-weight: normal; + font-size: 16px; + color: #888; +} + +.step-no { + font-weight: bold; +} + +.ui-dialog-titlebar.ui-widget-header { + color: #0088cc; + background-color: #F0F0F0; + background-image: none; +} + /* Large desktop */ diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index 8240d3bef2..0f11e5d876 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -5,7 +5,7 @@ * Utility functions * */ -angular.module('Utilities',['RestServices']) +angular.module('Utilities',['RestServices', 'Utilities']) .factory('ClearScope', function() { return function(id) { @@ -219,6 +219,83 @@ angular.module('Utilities',['RestServices']) } } }]) + + .factory('HelpDialog', ['$rootScope', '$location', function($rootScope, $location) { + return function(params) { + // Display a help dialog + // + // HelpDialog({ defn: }) + // + + function showHelp(params) { + // Using a function inside a function so we can recurse + // over the steps in the help story + + var defn = params.defn; + var nxtStory = { story: { steps: { } } }; + var width, height; + + function buildHtml(step) { + var html = ''; + html += (step.intro) ? "
" + step.intro + "
" : ""; + html += (step.img) ? "" : ""; + html += (step.box) ? "
" + step.box + "
" : ""; + return html; + } + + var nxt; + for (var step in defn.story.steps) { + nxt = step; + break; + } + + width = (defn.story.steps[nxt].width !== undefined) ? defn.story.steps[nxt].width : 500; + height = (defn.story.steps[nxt].height !== undefined) ? defn.story.steps[nxt].height : 600; + + if (Object.keys(defn.story.steps).length > 1) { + // We have multiple steps + for (var step in defn.story.steps) { + if (step !== nxt) { + nxtStory.story.steps[step] = defn.story.steps[step]; + } + } + nxtStory.story.hdr = defn.story.hdr; + + nxtStep = function() { + showHelp({ defn: nxtStory }); + } + + $('#help-modal').html(buildHtml(defn.story.steps[nxt])).dialog({ + position: { my: "center top", at: "center top+150", of: 'body' }, + title: defn.story.hdr, + width: width, + height: height, + buttons: [{ text: "Next", click: nxtStep }], + closeOnEscape: true, + 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'); + } + else { + $('#help-modal').html(buildHtml(defn.story.steps[nxt])).dialog({ + position: { my: "center top", at: "center top+150", of: 'body' }, + title: defn.story.hdr, + width: width, + height: height, + buttons: [ { text: "OK", click: function() { $( this ).dialog( "close" ); } } ], + closeOnEscape: true, + 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'); + } + } + + showHelp(params); + + } + }]) .factory('ReturnToCaller', ['$location', function($location) { return function(idx) { diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index 75eb3705e2..7d7bc873fb 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -105,11 +105,13 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) label.addClass('prepend-asterisk'); } }); - - // Remove leftover timer, if any - //if ((!options.modal) && this.scope.timer) { - // clearInterval(this.scope.timer); - //} + + try { + $('#help-modal').empty().dialog('destroy'); + } + catch(e) { + //ignore any errors should the dialog not be initialized + } if (options.modal) { this.scope.formModalActionDisabled = false; @@ -1198,12 +1200,12 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) html += this.breadCrumbs(options, navigation); // build the groups page - html += "
\n"; - html += "\n"; - html += "

Hint: Get started building your inventory by adding a group. After creating a group, " + - "use the Inventories->Hosts page to " + - "add hosts to the group.

"; - html += "
\n"; + //html += "
\n"; + //html += "\n"; + //html += "

Hint: Get started building your inventory by adding a group. After creating a group " + + // "go to the Hosts page to " + + // "add hosts to the group.

"; + //html += "
\n"; /* html += "
\n"; diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js index de280e2fd9..a27902d933 100644 --- a/awx/ui/static/lib/ansible/list-generator.js +++ b/awx/ui/static/lib/ansible/list-generator.js @@ -72,6 +72,13 @@ angular.module('ListGenerator', ['GeneratorHelpers']) // remove lingering popover
. Seems to be a bug in TB3 RC1 $(this).remove(); }); + + try { + $('#help-modal').empty().dialog('destroy'); + } + catch(e) { + //ignore any errors should the dialog not be initialized + } if (options.mode == 'lookup') { // options should include {hdr: , action: } diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 1fb2bdf440..db1138495e 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -14,7 +14,9 @@ {% endif %} - + @@ -112,6 +114,7 @@ + {% endif %} @@ -336,7 +339,10 @@
- + + +
+