AC-1197 callback workflow -dynamic help text. Fixed js lint issues.

This commit is contained in:
Chris Houseknecht 2014-04-16 13:47:20 -04:00
parent 9901658f02
commit 98c56827db
11 changed files with 140 additions and 55 deletions

View File

@ -48,6 +48,7 @@ angular.module('Tower', [
'LookUpHelper',
'JobTemplatesListDefinition',
'JobTemplateFormDefinition',
'JobTemplatesHelper',
'JobSubmissionHelper',
'ProjectsListDefinition',
'ProjectFormDefinition',

View File

@ -103,7 +103,7 @@ function Authenticate($cookieStore, $compile, $window, $scope, $rootScope, $loca
Wait('stop');
Alert('Error', 'Failed to access license information. GET returned status: ' + status, 'alert-danger', setLoginFocus);
});
});
});
if (scope.removeAuthorizationGetUser) {
scope.removeAuthorizationGetUser();
@ -131,7 +131,7 @@ function Authenticate($cookieStore, $compile, $window, $scope, $rootScope, $loca
} else {
Wait('start');
Authorization.retrieveToken(username, password)
.success(function (data, status) {
.success(function (data) {
$('#login-modal').modal('hide');
token = data.token;
Authorization.setToken(data.token, data.expires);

View File

@ -108,7 +108,8 @@ JobTemplatesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$route
function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm,
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GetBasePath,
InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait, Empty, ToJSON) {
InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait, Empty, ToJSON,
CallbackHelpInit) {
ClearScope();
@ -121,6 +122,8 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
selectPlaybook, checkSCMStatus,
callback;
CallbackHelpInit({ scope: $scope });
generator.inject(form, { mode: 'add', related: false, scope: $scope });
callback = function() {
@ -274,8 +277,9 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is: <strong>' + data.related.callback +
'</strong></p><p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is:</p>'+
'<p style="padding: 10px 0;"><strong>' + $scope.callback_server_path + data.related.callback + '</strong></p>'+
'<p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
}
else {
saveCompleted();
@ -330,7 +334,7 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
JobTemplatesAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope',
'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit',
'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON'
'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON', 'CallbackHelpInit'
];
@ -338,7 +342,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList,
CredentialList, ProjectList, LookUpInit, GetBasePath, md5Setup, ParseTypeChange, JobStatusToolTip, FormatDate,
Wait, Stream, Empty, Prompt, ParseVariableString, ToJSON, SchedulesControllerInit, JobsControllerInit, JobsListUpdate,
GetChoices, SchedulesListInit, SchedulesList) {
GetChoices, SchedulesListInit, SchedulesList, CallbackHelpInit) {
ClearScope();
@ -353,6 +357,8 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
checkSCMStatus, getPlaybooks, callback,
choicesCount = 0;
CallbackHelpInit({ scope: $scope });
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
$scope.parseType = 'yaml';
@ -610,7 +616,14 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
relatedSets = form.relatedSets(data.related);
$scope.callback_url = data.related.callback;
if (data.host_config_key) {
$scope.example_config_key = data.host_config_key;
}
$scope.example_template_id = id;
$scope.setCallbackHelp();
$scope.callback_url = $scope.callback_server_path + ((data.related.callback) ? data.related.callback :
GetBasePath('job_templates') + id + '/callback/');
master.callback_url = $scope.callback_url;
LookUpInit({
@ -695,9 +708,10 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (Empty(master.callback_url) && data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is: <strong>' + data.related.callback +
'</strong></p><p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
if (data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is:</p>'+
'<p style="padding: 10px 0;"><strong>' + $scope.callback_server_path + data.related.callback + '</strong></p>'+
'<p>The host configuration key is: <strong>' + data.host_config_key + '</strong></p>', 'alert-info', saveCompleted);
}
else {
saveCompleted();
@ -802,5 +816,5 @@ JobTemplatesEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$l
'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit',
'GetBasePath', 'md5Setup', 'ParseTypeChange', 'JobStatusToolTip', 'FormatDate', 'Wait', 'Stream', 'Empty', 'Prompt',
'ParseVariableString', 'ToJSON', 'SchedulesControllerInit', 'JobsControllerInit', 'JobsListUpdate', 'GetChoices',
'SchedulesListInit', 'SchedulesList'
'SchedulesListInit', 'SchedulesList', 'CallbackHelpInit'
];

View File

@ -1,26 +1,26 @@
/************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* Sockets.js
* SocketsController- simple test of socket connection
*
*/
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* Sockets.js
* SocketsController- simple test of socket connection
*
*/
'use strict';
'use strict';
function SocketsController ($scope, ClearScope, Socket) {
function SocketsController ($scope, ClearScope, Socket) {
ClearScope();
ClearScope();
var socket = Socket({ scope: $scope });
socket.init(); //make the connection
var socket = Socket({ scope: $scope });
socket.init(); //make the connection
$scope.messages = ['Stuff happened', 'message received', 'blah blah bob blah'];
$scope.messages = ['Stuff happened', 'message received', 'blah blah bob blah'];
socket.on('anything', function(data) {
socket.on('anything', function(data) {
$scope.messages.push(data);
});
});
}
}
SocketsController.$inject = [ '$scope', 'ClearScope', 'Socket'];
SocketsController.$inject = [ '$scope', 'ClearScope', 'Socket'];

View File

@ -226,17 +226,10 @@ angular.module('JobTemplateFormDefinition', ['SchedulesListDefinition', 'Complet
falseValue: 'false',
ngChange: "toggleCallback('host_config_key')",
column: 2,
awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
"using the job template. The URL will look like the following:</p>\n" +
"<pre>http://your.server.com:999/api/v1/job_templates/1/callback/</pre>" +
"<p>The request from the host must be a POST. Here is an example using curl:</p>\n" +
"<pre>curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</pre>\n" +
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
"in one of your defined inventories, the request will be denied.</p>" +
"<p>Successful requests will result in an entry on the Jobs tab, where the results and history can be viewed.</p>",
awPopOver: "<p>Enable creation of a callback URL. With a callback URL a host can contact Tower and request a configuration update " +
"using this job template.</p>",
dataPlacement: 'right',
dataTitle: 'Callback URL',
dataTitle: 'Allow Callbacks',
dataContainer: "body"
},
callback_url: {
@ -247,14 +240,8 @@ angular.module('JobTemplateFormDefinition', ['SchedulesListDefinition', 'Complet
readonly: true,
ngShow: "allow_callbacks",
column: 2,
required: false,
awPopOver: "<p>Using this URL a host can contact Tower and request a configuration update using the job " +
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
"<pre>curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</pre>\n" +
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
"in one of your defined inventories, the request will be denied.</p>" +
"<p>Successful requests will result in an entry on the Jobs tab, where the results and history can be viewed.</p>",
awPopOver: "callback_help",
awPopOverWatch: "callback_help",
dataPlacement: 'right',
dataTitle: 'Callback URL',
dataContainer: "body"
@ -263,12 +250,11 @@ angular.module('JobTemplateFormDefinition', ['SchedulesListDefinition', 'Complet
label: 'Host Config Key',
type: 'text',
ngShow: "allow_callbacks",
ngChange: "configKeyChange()",
genMD5: true,
column: 2,
awPopOver: "<p>When contacting the Tower server using the callback URL, the calling host must authenticate by including " +
"this key in the POST data of the request. Here's an example using curl:</p>\n" +
"<pre>curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</pre>\n",
awPopOver: "callback_help",
awPopOverWatch: "callback_help",
dataPlacement: 'right',
dataTitle: "Host Config Key",
dataContainer: "body"

View File

@ -0,0 +1,58 @@
/*********************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* JobTemplatesHelper
*
* Routines shared by job related controllers
*
*/
'use strict';
angular.module('JobTemplatesHelper', ['Utilities'])
/*
* Add bits to $scope for handling callback url help
*
*/
.factory('CallbackHelpInit', ['$location', 'GetBasePath', function($location, GetBasePath) {
return function(params) {
var scope = params.scope;
// The form uses awPopOverWatch directive to 'watch' scope.callback_help for changes. Each time the
// popover is activated, a function checks the value of scope.callback_help before constructing the content.
scope.setCallbackHelp = function() {
scope.callback_help = "<p>With a callback URL and a host config key a host can contact Tower and request a configuration update using this job " +
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
"<pre>curl --data \"host_config_key=\"" + scope.example_config_key + "\" " +
scope.callback_server_path + GetBasePath('job_templates') + scope.example_template_id + "/callback/</pre>\n" +
"<p>Note the requesting host must be defined in the inventory associated with the job template. If Tower fails to " +
"locate the host, the request will be denied.</p>" +
"<p>Successful requests create an entry on the Jobs page, where results and history can be viewed.</p>";
};
// The md5 helper emits NewMD5Generated whenever a new key is available
if (scope.removeNewMD5Generated) {
scope.removeNewMD5Generated();
}
scope.removeNewMD5Generated = scope.$on('NewMD5Generated', function() {
scope.configKeyChange();
});
// Fired when user enters a key value
scope.configKeyChange = function() {
scope.example_config_key = scope.host_config_key;
scope.setCallbackHelp();
};
// Set initial values and construct help text
scope.callback_server_path = $location.protocol() + '://' + $location.host() + (($location.port()) ? ':' + $location.port() : '');
scope.example_config_key = '5a8ec154832b780b9bdef1061764ae5a';
scope.example_template_id = 'N';
scope.setCallbackHelp();
};
}]);

View File

@ -25,6 +25,7 @@ angular.module('md5Helper', ['RestServices', 'Utilities', 'angular-md5'])
scope.genMD5 = function (fld) {
var now = new Date();
scope[fld] = md5.createHash('AnsibleWorks' + now.getTime());
scope.$emit('NewMD5Generated');
};
scope.toggleCallback = function (fld) {

View File

@ -6,6 +6,8 @@
* Wrapper for lib/socket.io-client/dist/socket.io.js.
*/
/* global io */
'use strict';
angular.module('SocketIO', ['AuthService', 'Utilities'])
@ -13,7 +15,6 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Alert', function ($rootScope, $location, $log, Authorization, Alert) {
return function(params) {
var scope = params.scope,
debug = params.debug,
host = $location.host(),
protocol = $location.protocol(),
url = protocol + '://' + host + ':8080';
@ -102,7 +103,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
}
},
on: function (eventName, callback) {
self = this;
var self = this;
self.socket.on(eventName, function () {
var args = arguments;
self.scope.$apply(function () {
@ -119,7 +120,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
callback.apply(self.socket, args);
}
});
})
});
}
};
};

View File

@ -288,8 +288,30 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
title = (attrs.title !== undefined && attrs.title !== null) ? attrs.title : 'Help',
container = (attrs.container !== undefined) ? attrs.container : false,
trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manual';
$(element).popover({ placement: placement, delay: 0, title: title,
content: attrs.awPopOver, trigger: trigger, html: true, container: container });
if (attrs.awPopOverWatch) {
$(element).popover({
placement: placement,
delay: 0,
title: title,
content: function() {
return scope[attrs.awPopOverWatch];
},
trigger: trigger,
html: true,
container: container
});
}
else {
$(element).popover({
placement: placement,
delay: 0,
title: title,
content: attrs.awPopOver,
trigger: trigger,
html: true,
container: container
});
}
$(element).click(function() {
var self = $(this);
try {

View File

@ -43,6 +43,7 @@ angular.module('GeneratorHelpers', [])
result += (obj.dataContainer) ? "data-container=\"" + obj.dataContainer + "\" " : "";
result += (obj.dataTitle) ? "data-title=\"" + obj.dataTitle + "\" " : "";
result += (obj.dataTrigger) ? "data-trigger=\"" + obj.dataTrigger + "\" " : "";
result += (obj.awPopOverWatch) ? "aw-pop-over-watch=\"" + obj.awPopOverWatch + "\" " : "";
result += "class=\"help-link\" ";
result += "><i class=\"fa fa-question-circle\"></i></a> ";
break;

View File

@ -154,6 +154,7 @@
<script src="{{ STATIC_URL }}js/helpers/Schedules.js"></script>
<script src="{{ STATIC_URL }}js/helpers/LogViewer.js"></script>
<script src="{{ STATIC_URL }}js/helpers/JobDetail.js"></script>
<script src="{{ STATIC_URL }}js/helpers/JobTemplates.js"></script>
<script src="{{ STATIC_URL }}js/widgets/JobStatus.js"></script>
<script src="{{ STATIC_URL }}js/widgets/InventorySyncStatus.js"></script>
<script src="{{ STATIC_URL }}js/widgets/SCMSyncStatus.js"></script>