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.

This commit is contained in:
chouseknecht
2013-10-15 02:56:39 -04:00
parent c563f040ba
commit 4bcda34c3c
18 changed files with 257 additions and 106 deletions

View File

@@ -608,7 +608,7 @@ button.ui-button::-moz-focus-inner {
height: 100%; height: 100%;
} }
.ui-progressbar .ui-progressbar-overlay { .ui-progressbar .ui-progressbar-overlay {
background: url("images/animated-overlay.gif"); background: url("/static/css/custom-theme/images/animated-overlay.gif");
height: 100%; height: 100%;
filter: alpha(opacity=25); filter: alpha(opacity=25);
opacity: 0.25; opacity: 0.25;
@@ -806,7 +806,7 @@ body .ui-tooltip {
} }
.ui-widget-content { .ui-widget-content {
border: 1px solid #a6c9e2; 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; color: #36454F;
font-weight: normal; font-weight: normal;
} }
@@ -815,7 +815,7 @@ body .ui-tooltip {
} }
.ui-widget-header { .ui-widget-header {
border: 1px solid #a6c9e2; 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; color: #36454F;
font-weight: bold; font-weight: bold;
} }
@@ -829,7 +829,7 @@ body .ui-tooltip {
.ui-widget-content .ui-state-default, .ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default { .ui-widget-header .ui-state-default {
border: 1px solid #a6c9e2; 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; font-weight: bold;
color: #0088cc; color: #0088cc;
} }
@@ -846,7 +846,7 @@ body .ui-tooltip {
.ui-widget-content .ui-state-focus, .ui-widget-content .ui-state-focus,
.ui-widget-header .ui-state-focus { .ui-widget-header .ui-state-focus {
border: 1px solid #e3e3e3; 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; font-weight: bold;
color: #005580; color: #005580;
} }
@@ -861,7 +861,7 @@ body .ui-tooltip {
.ui-widget-content .ui-state-active, .ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active { .ui-widget-header .ui-state-active {
border: 1px solid #e3e3e3; 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; font-weight: bold;
color: #36454F; color: #36454F;
} }
@@ -878,7 +878,7 @@ body .ui-tooltip {
.ui-widget-content .ui-state-highlight, .ui-widget-content .ui-state-highlight,
.ui-widget-header .ui-state-highlight { .ui-widget-header .ui-state-highlight {
border: 1px solid #fad42e; 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; color: #363636;
} }
.ui-state-highlight a, .ui-state-highlight a,
@@ -890,7 +890,7 @@ body .ui-tooltip {
.ui-widget-content .ui-state-error, .ui-widget-content .ui-state-error,
.ui-widget-header .ui-state-error { .ui-widget-header .ui-state-error {
border: 1px solid #cd0a0a; 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; color: #cd0a0a;
} }
.ui-state-error a, .ui-state-error a,
@@ -936,27 +936,27 @@ body .ui-tooltip {
} }
.ui-icon, .ui-icon,
.ui-widget-content .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 { .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 { .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-hover .ui-icon,
.ui-state-focus .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 { .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 { .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 .ui-icon,
.ui-state-error-text .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 */ /* positioning */
@@ -1169,14 +1169,14 @@ body .ui-tooltip {
/* Overlays */ /* Overlays */
.ui-widget-overlay { .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; opacity: .3;
filter: Alpha(Opacity=30); filter: Alpha(Opacity=30);
} }
.ui-widget-shadow { .ui-widget-shadow {
margin: -8px 0 0 -8px; margin: -8px 0 0 -8px;
padding: 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; opacity: .3;
filter: Alpha(Opacity=30); filter: Alpha(Opacity=30);
border-radius: 8px; border-radius: 8px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -75,7 +75,8 @@ angular.module('ansible', [
'SCMSyncStatusWidget', 'SCMSyncStatusWidget',
'ObjectCountWidget', 'ObjectCountWidget',
'JobsHelper', 'JobsHelper',
'InventoryStatusDefinition' 'InventoryStatusDefinition',
'InventorySummaryHelpDefinition'
]) ])
.config(['$routeProvider', function($routeProvider) { .config(['$routeProvider', function($routeProvider) {
$routeProvider. $routeProvider.

View File

@@ -10,7 +10,7 @@
function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryGroupsForm, function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryGroupsForm,
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt,
TreeInit, GetBasePath, GroupsList, GroupsAdd, GroupsEdit, LoadInventory, 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 ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope. //scope.
@@ -34,7 +34,6 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeP
scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() { scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() {
LoadBreadCrumbs({ path: '/inventories/' + id, title: scope.inventory_name }); LoadBreadCrumbs({ path: '/inventories/' + id, title: scope.inventory_name });
TreeInit(scope.TreeParams); TreeInit(scope.TreeParams);
SetShowGroupHelp({ scope: scope });
if (!scope.$$phase) { if (!scope.$$phase) {
scope.$digest(); scope.$digest();
} }
@@ -242,6 +241,6 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeP
InventoryGroups.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryGroupsForm', InventoryGroups.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryGroupsForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt',
'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory', 'TreeInit', 'GetBasePath', 'GroupsList', 'GroupsAdd', 'GroupsEdit', 'LoadInventory',
'GroupsDelete', 'RefreshGroupName', 'EditInventory', 'SetShowGroupHelp', 'InventoryStatus' 'GroupsDelete', 'RefreshGroupName', 'EditInventory', 'InventoryStatus'
]; ];

View File

@@ -13,7 +13,7 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
GetBasePath, HostsList, HostsAdd, HostsEdit, HostsDelete, 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 ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope. //scope.
@@ -36,7 +36,6 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
} }
scope.loadBreadCrumbsRemove = scope.$on('buildAllGroups', function(e, inventory_name) { scope.loadBreadCrumbsRemove = scope.$on('buildAllGroups', function(e, inventory_name) {
LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name }); LoadBreadCrumbs({ path: '/inventories/' + id, title: inventory_name });
SetShowGroupHelp({ scope: scope });
}); });
// Sets up the search tree and loads All Hosts for the inventory // 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', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
'GetBasePath', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete', 'GetBasePath', 'HostsList', 'HostsAdd', 'HostsEdit', 'HostsDelete',
'HostsReload', 'LoadSearchTree', 'EditHostGroups', 'SetShowGroupHelp' 'HostsReload', 'LoadSearchTree', 'EditHostGroups'
]; ];

View File

@@ -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 <em>Create New</em> 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 <em>Hosts</em> using the drop-down menu, where you can add hosts to the new group",
height: 480
}
}
}
});

View File

@@ -9,7 +9,8 @@
angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition',
'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper',
'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper' 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper',
'PromptDialog', 'InventorySummaryHelpDefinition'
]) ])
.factory('GetSourceTypeOptions', [ function() { .factory('GetSourceTypeOptions', [ function() {
@@ -169,9 +170,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
.factory('InventoryStatus', [ '$rootScope', '$routeParams', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'InventorySummary', .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, 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) { return function(params) {
//Build a summary of a given inventory //Build a summary of a given inventory
@@ -268,6 +270,17 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
scope.search(list.iterator); 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) { scope.viewUpdateStatus = function(id) {
var found = false; var found = false;
var group; var group;
@@ -365,20 +378,29 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
break; break;
} }
} }
if (found && group.related.current_update) { if (group.summary_fields.inventory_source.source !== '' &&
Rest.setUrl(group.related.current_update); group.summary_fields.inventory_source.source !== null) {
Rest.get() // the group has a source
.success( function(data, status, headers, config) { if (group.related.current_update) {
scope.$emit('Check_Cancel', data); // there is an update currently running
}) Rest.setUrl(group.related.current_update);
.error( function(data, status, headers, config) { Rest.get()
ProcessErrors(scope, data, status, null, .success( function(data, status, headers, config) {
{ hdr: 'Error!', msg: 'Call to ' + group.related.current_update + ' failed. GET status: ' + status }); 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 <em>Refresh</em> ' +
'button to view the latet status.', 'alert-info');
}
} }
else { else {
Alert('Update Not Found', 'An Inventory update does not appear to be running for group: ' + name + '. Click the <em>Refresh</em> ' + Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group and provide external Source settings ' +
'button to view the latet status.', 'alert-info'); '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++) { for (var i=0; i < scope.groups.length; i++) {
if (scope.groups[i].id == id) { if (scope.groups[i].id == id) {
if (scope.groups[i].summary_fields.inventory_source.source == "" || scope.groups[i].summary_fields.inventory_source.source == null) { 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, ' + Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group and provide ' +
'and then run an update.', 'alert-info'); 'external Source settings before attempting an update.', 'alert-info');
} }
else if (scope.groups[i].summary_fields.inventory_source.status == 'updating') { else if (scope.groups[i].summary_fields.inventory_source.status == 'updating') {
Alert('Update in Progress', 'The inventory update process is currently running for group <em>' + Alert('Update in Progress', 'The inventory update process is currently running for group <em>' +
@@ -433,6 +455,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
} }
} }
} }
ShowGroupHelp({ scope: scope });
} }
}]) }])

View File

@@ -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) { return function(params) {
// Check if inventory has groups. If not, turn on hints to let user know groups are required // Check if inventory has groups. If not, turn on hints to let user know groups are required
// before hosts can be added // before hosts can be added
var scope = params.scope; 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.setUrl(url);
Rest.get() Rest.get()
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
if (data.results.length > 0) { scope.$emit('ShowHelp');
scope.showGroupHelp = false;
}
else {
scope.showGroupHelp = true;
}
}) })
.error( function(data, status, headers, config) { .error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form, 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 });
}); });
} }
}]) }])

View File

@@ -109,22 +109,13 @@ angular.module('InventorySummaryDefinition', [])
dataPlacement: 'top' dataPlacement: 'top'
}, },
help: { help: {
awPopOver:
"<dl>\n" +
"<dt>failed</dt><dd>Errors were encountered with the most recent inventory update.</dd>\n" +
"<dt>n/a</dt><dd>The group is not configured for inventory update.</dd>\n" +
"<dt>never</dt><dd>The inventory update has never run for the group.</dd>\n" +
"<dt>successful</dt><dd>The most recent inventory update ran to completion without incident.</dd>\n" +
"<dt>updating</dt><dd>The inventory update is currently running.</dd>\n" +
"</dl>\n",
dataPlacement: 'top', dataPlacement: 'top',
dataContainer: 'body',
icon: "icon-question-sign", icon: "icon-question-sign",
mode: 'all', mode: 'all',
'class': 'btn-xs btn-info btn-help', 'class': 'btn-xs btn-info btn-help',
awToolTip: 'Click for help', awToolTip: 'Click for help',
dataTitle: 'Update Status', iconSize: 'large',
iconSize: 'large' ngClick: "showHelp()"
}, },
refresh: { refresh: {
awRefresh: true, awRefresh: true,

View File

@@ -109,7 +109,7 @@ angular.module('JobHostDefinition', [])
"<dt>Unreachable</dt><dd>Times the ansible server could not reach the host.</dd>\n" + "<dt>Unreachable</dt><dd>Times the ansible server could not reach the host.</dd>\n" +
"<dt>Skipped</dt><dd>Tasks bypassed and not performed on the host due to prior task failure or the host being unreachable.</dd>\n" + "<dt>Skipped</dt><dd>Tasks bypassed and not performed on the host due to prior task failure or the host being unreachable.</dd>\n" +
"</dl>\n", "</dl>\n",
dataPlacement: 'top', dataPlacement: 'left',
dataContainer: "body", dataContainer: "body",
icon: "icon-question-sign", icon: "icon-question-sign",
mode: 'all', mode: 'all',

View File

@@ -60,7 +60,7 @@ angular.module('ProjectsListDefinition', [])
"<dt>Missing</dt><dd>The local project directory is missing.</dd>\n" + "<dt>Missing</dt><dd>The local project directory is missing.</dd>\n" +
"<dt>N/A</dt><dd>The project does not use SCM, so an update status is not available.</dd>\n" + "<dt>N/A</dt><dd>The project does not use SCM, so an update status is not available.</dd>\n" +
"</dl>\n", "</dl>\n",
dataPlacement: 'top', dataPlacement: 'left',
dataContainer: 'body', dataContainer: 'body',
icon: "icon-question-sign", icon: "icon-question-sign",
mode: 'all', mode: 'all',

View File

@@ -31,26 +31,6 @@ angular.module('ObjectCountWidget', ['RestServices', 'Utilities'])
cnt++; cnt++;
} }
if (cnt == expected) { 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 = "<div class=\"panel panel-default\">\n"; html = "<div class=\"panel panel-default\">\n";
html += "<div class=\"panel-heading\">System Summary</div>\n"; html += "<div class=\"panel-heading\">System Summary</div>\n";
html += "<div class=\"panel-body\">\n"; html += "<div class=\"panel-body\">\n";

View File

@@ -7,15 +7,18 @@
* *
*/ */
@black: #171717; @black: #171717;
@warning: #FF9900; @warning: #FF9900;
@red: #da4f49; @red: #da4f49;
@red-hover: #AE3F3A; @red-hover: #AE3F3A;
@green: #5bb75b; @green: #5bb75b;
@blue: #1778c3; /* logo blue */ @blue: #1778c3; /* logo blue */
@blue-link: #0088cc; @blue-link: #0088cc;
@grey: #A9A9A9; @grey: #A9A9A9;
@green: #5bb75b; @green: #5bb75b;
@info: #d9edf7; /* alert info background color */
@info-border: #bce8f1; /* alert info border color */
@info-color: #3a87ad;
html { html {
background-color: @black; background-color: @black;
@@ -1204,6 +1207,44 @@ tr td button i {
margin-bottom: 5px; 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 */ /* Large desktop */

View File

@@ -5,7 +5,7 @@
* Utility functions * Utility functions
* *
*/ */
angular.module('Utilities',['RestServices']) angular.module('Utilities',['RestServices', 'Utilities'])
.factory('ClearScope', function() { .factory('ClearScope', function() {
return function(id) { return function(id) {
@@ -220,6 +220,83 @@ angular.module('Utilities',['RestServices'])
} }
}]) }])
.factory('HelpDialog', ['$rootScope', '$location', function($rootScope, $location) {
return function(params) {
// Display a help dialog
//
// HelpDialog({ defn: <HelpDefinition> })
//
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) ? "<div class=\"help-intro\">" + step.intro + "</div>" : "";
html += (step.img) ? "<img src=\"" + $basePath + "img/help/" + step.img + "\" style=\"max-width:" + (width - 30) + "px\" >" : "";
html += (step.box) ? "<div class=\"help-box\">" + step.box + "</div>" : "";
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) { .factory('ReturnToCaller', ['$location', function($location) {
return function(idx) { return function(idx) {
// Split the current path by '/' and use the array elements from 0 up to and // Split the current path by '/' and use the array elements from 0 up to and

View File

@@ -106,10 +106,12 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
} }
}); });
// Remove leftover timer, if any try {
//if ((!options.modal) && this.scope.timer) { $('#help-modal').empty().dialog('destroy');
// clearInterval(this.scope.timer); }
//} catch(e) {
//ignore any errors should the dialog not be initialized
}
if (options.modal) { if (options.modal) {
this.scope.formModalActionDisabled = false; this.scope.formModalActionDisabled = false;
@@ -1198,12 +1200,12 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += this.breadCrumbs(options, navigation); html += this.breadCrumbs(options, navigation);
// build the groups page // build the groups page
html += "<div ng-show=\"showGroupHelp\" class=\"alert alert-dismissable alert-info\">\n"; //html += "<div ng-show=\"showGroupHelp\" class=\"alert alert-dismissable alert-info\">\n";
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">&times;</button>\n"; //html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">&times;</button>\n";
html += "<p><strong>Hint:</strong> Get started building your inventory by adding a group. After creating a group, " + //html += "<p><strong>Hint:</strong> Get started building your inventory by adding a group. After creating a group " +
"use the <a href=\"/#/inventories/\{\{ inventory_id \}\}/hosts\"><em>Inventories->Hosts</em></a> page to " + // "go to the <a href=\"/#/inventories/\{\{ inventory_id \}\}/hosts\"><em>Hosts</em></a> page to " +
"add hosts to the group.</p>"; // "add hosts to the group.</p>";
html += "</div>\n"; //html += "</div>\n";
/* /*
html += "<div class=\"row\">\n"; html += "<div class=\"row\">\n";

View File

@@ -73,6 +73,13 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
$(this).remove(); $(this).remove();
}); });
try {
$('#help-modal').empty().dialog('destroy');
}
catch(e) {
//ignore any errors should the dialog not be initialized
}
if (options.mode == 'lookup') { if (options.mode == 'lookup') {
// options should include {hdr: <dialog header>, action: <function...> } // options should include {hdr: <dialog header>, action: <function...> }
this.scope.formModalActionDisabled = false; this.scope.formModalActionDisabled = false;

View File

@@ -14,7 +14,9 @@
{% endif %} {% endif %}
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico" /> <link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico" />
<script>
var $basePath = "{{ STATIC_URL }}";
</script>
<script src="{{ STATIC_URL }}lib/jquery/jquery-1.10.2.min.js"></script> <script src="{{ STATIC_URL }}lib/jquery/jquery-1.10.2.min.js"></script>
<script src="{{ STATIC_URL }}js/config.js"></script> <script src="{{ STATIC_URL }}js/config.js"></script>
<script src="{{ STATIC_URL }}lib/angular/angular.js"></script> <script src="{{ STATIC_URL }}lib/angular/angular.js"></script>
@@ -112,6 +114,7 @@
<script src="{{ STATIC_URL }}js/widgets/InventorySyncStatus.js"></script> <script src="{{ STATIC_URL }}js/widgets/InventorySyncStatus.js"></script>
<script src="{{ STATIC_URL }}js/widgets/SCMSyncStatus.js"></script> <script src="{{ STATIC_URL }}js/widgets/SCMSyncStatus.js"></script>
<script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script> <script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script>
<script src="{{ STATIC_URL }}js/help/InventorySummary.js"></script>
<script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script> <script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script>
{% endif %} {% endif %}
@@ -337,6 +340,9 @@
</div><!-- modal-dialog --> </div><!-- modal-dialog -->
</div><!-- modal --> </div><!-- modal -->
<!-- Help dialog -->
<div id="help-modal"></div>
</div><!-- container --> </div><!-- container -->
<div class="overlay"></div> <div class="overlay"></div>