Upgraded AWX to Twitter Bootstrap 3 RC1

This commit is contained in:
chouseknecht 2013-08-02 18:26:34 -04:00
parent f3cbda4352
commit 94ae9ffd43
40 changed files with 5172 additions and 7977 deletions

View File

@ -13,7 +13,7 @@
body {
color: #171717;
padding-top: 60px;
padding-top: 100px;
}
.text-center {
@ -28,9 +28,18 @@
white-space: nowrap;
}
.tab-content {
padding-top: 20px;
}
.btn .caret {
border-top-color: #787878;
}
/* Attempt to make button heights consistent. For some reason success, info, etc. are
taller than plain .btn */
/*
.btn-success, .btn-danger, .btn-info, .btn-primary, .btn-warning {
padding-top: 1px;
padding-bottom: 2px;
@ -46,7 +55,9 @@
padding-top: 3px;
padding-bottom: 1px;
}
*/
/*
.btn-inventory-edit {
padding-top: 2px;
padding-bottom: 1px;
@ -64,11 +75,8 @@
padding-left: 10px;
padding-right: 10px;
}
.icon-plus {
font-size: 10px;
}
*/
/* End btn heights */
/* Use code-breakable in pop-over text to indent and wrap code segments */
@ -93,18 +101,16 @@
min-height: 15px;
}
.container-fluid {
.main-container {
min-height: 700px;
}
.navbar-fixed-top .container {
width: 100%;
.navbar {
background-color: #171717;
}
.navbar-inverse .navbar-inner {
background-color: #171717;
border-color: #171717;
padding-right: 15px;
.navbar .nav {
margin-top: 15px;
}
.navbar-inverse .nav > li > a {
@ -116,25 +122,30 @@
color: #2078be;
}
.navbar .brand {
margin-left: 15px;
/* Using inline-block rather than block keeps
brand img from right aligning into the collapse button
on mobile screens */
.navbar-brand {
display: inline-block;
padding: 0;
}
.navbar .brand img {
width: 260px;
.navbar-brand img {
max-width: 260px;
}
.navbar .nav {
margin-top: 15px;
}
ß
a:hover {
text-decoration: none;
}
.help-link, .help-link:active, .help-link:visited {
color: #49afcd;
text-decoration: none;
}
.help-link:hover {
text-decoration: none;
color: #1778c3;
}
.site-footer {
@ -185,7 +196,25 @@
max-width: 100px;
}
/* Outline required fields in Red when focused */
.form-control[required]:focus {
border-color: rgba(204, 0, 0, 0.8);
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px rgba(204, 0, 0, 0.6);
}
/* For some reason TB 3 RC1 does not provide an input-mini */
.input-mini {
height: 26px;
padding: 3px 8px;
font-size: 12px;
border-radius: 3px;
}
.error {
margin-top: 5px;
line-height: normal;
font-size: 12px;
color: #FF0000;
}
@ -339,6 +368,7 @@
display: inline-block;
vertical-align: bottom;
margin-bottom: 15px;
padding-left: 0;
}
.list-actions {
@ -450,6 +480,7 @@
margin-top:5px;
}
.form-items .search-widget {
margin-top: 15px;
}
@ -553,17 +584,18 @@
}
.parse-selection {
display: inline-block;
font-size: 12px;
line-height: normal;
margin: 5px 0 8px 0;
}
.parse-selection .radio.inline {
padding-top: 0;
font-size: 12px;
.parse-selection input {
margin-left: 5px;
}
.parse-selection label:first-child {
margin-left: 5px;
.parse-select .parse-label {
margin-left: 3px;
}
#tree-view {
@ -621,34 +653,6 @@
padding-bottom: 5px;
}
/* form displayed in modal window */
.horizontal-narrow .control-label {
float: left;
width: 100px;
padding-top: 5px;
text-align: right;
}
.horizontal-narrow .controls {
*display: inline-block;
*padding-left: 20px;
margin-left: 120px;
*margin-left: 0;
}
.horizontal-narrow .controls:first-child {
*padding-left: 120px;
}
.modal-input-xlarge {
width: 350px;
}
.modal-input-xxlarge {
width: 98%;
}
.form-section-title {
font-weight: bold;
width: 100%;
@ -723,23 +727,16 @@
/* Portrait tablet to landscape and desktop */
@media (min-width: 768px) and (max-width: 979px) {
body {
padding-top: 0px;
}
}
/* Landscape phone to portrait tablet */
@media (max-width: 767px) {
body {
padding-top: 0px;
}
}
/* Landscape phones and down */
@media (max-width: 480px) {
body {
padding-top: 0px;
}
/* Job events */
.level-1, .level-2, .level-3, .level-3-detail {
@ -750,21 +747,4 @@
table-layout: fixed;
word-wrap: break-word;
}
/* form displayed in modal window */
.horizontal-narrow .control-label {
width: 105px;
}
.horizontal-narrow .controls {
margin-left: 125px;
}
.horizontal-narrow .controls:first-child {
*padding-left: 125px;
}
.modal-input-xlarge {
width: 200px;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
*/
var urlPrefix = '/static/';
angular.module('ansible', [
'RestServices',
'AuthService',
@ -210,9 +210,9 @@ angular.module('ansible', [
when('/teams/:user_id/credentials/:credential_id', { templateUrl: urlPrefix + 'partials/teams.html',
controller: CredentialsEdit }).
when('/login', { templateUrl: urlPrefix + 'partials/login-dialog.html', controller: Authenticate }).
when('/login', { templateUrl: urlPrefix + 'partials/organizations.html', controller: Authenticate }).
when('/logout', { templateUrl: urlPrefix + 'partials/login-dialog.html', controller: Authenticate }).
when('/logout', { templateUrl: urlPrefix + 'partials/organizations.html', controller: Authenticate }).
otherwise({redirectTo: '/'});
}])

View File

@ -12,22 +12,30 @@
function Authenticate($window, $scope, $rootScope, $location, Authorization, ToggleClass, Alert)
{
// Authorization is injected from AuthService found in services.js
// Display the login dialog
$('#login-modal').modal({ show: true, keyboard: false, backdrop: 'static' });
var scope = angular.element(document.getElementById('login-modal')).scope();
// Reset the login form
scope['login_username'] = null;
scope['login_password'] = null;
scope['loginForm']['login_username'].$setPristine();
scope['loginForm']['login_password'].$setPristine();
if ($location.path() == '/logout') {
//if logout request, clear AuthToken and user session data
Authorization.logout();
}
$scope.sessionTimeout = ($AnsibleConfig.session_timeout / 60).toFixed(2);
$scope.AWXLoginLogo = $staticURL + 'img/AWX_logo.png';
scope.sessionTimeout = ($AnsibleConfig.session_timeout / 60).toFixed(2);
if ($rootScope.userLoggedIn) {
// If we're logged in, check for session timeout
$scope.sessionExpired = Authorization.didSessionExpire();
scope.sessionExpired = Authorization.didSessionExpire();
}
else {
$scope.sessionExpired = false;
scope.sessionExpired = false;
}
$rootScope.userLoggedIn = false; //hide the logout link. if you got here, you're logged out.
@ -39,71 +47,74 @@ function Authenticate($window, $scope, $rootScope, $location, Authorization, Tog
$('#login-button').click();
}
});
// Display the login dialog
$('#login-modal').modal({ show: true, keyboard: false, backdrop: 'static' });
$scope.reset = function() {
scope.reset = function() {
$('#login-form input').each( function(index) { $(this).val(''); });
};
// Call the API to get an auth token
$scope.systemLogin = function(username, password) {
scope.systemLogin = function(username, password) {
$('.api-error').empty();
var token;
Authorization.retrieveToken(username, password)
.success( function(data, status, headers, config) {
$('#login-modal').modal('hide');
token = data.token;
Authorization.setToken(data.token);
$scope.reset();
if (username == null || username == undefined || username == '' ||
password == null || password == undefined || password == '' ) {
Alert('Error!', 'Please provide a username and password before attempting to login.');
}
else {
Authorization.retrieveToken(username, password)
.success( function(data, status, headers, config) {
$('#login-modal').modal('hide');
token = data.token;
Authorization.setToken(data.token);
scope.reset();
// Force request to /organizations to query with the correct token -in the event a new user
// has logged in.
var today = new Date();
today.setTime(today.getTime() + ($AnsibleConfig.session_timeout * 1000));
$rootScope.token = token;
$rootScope.userLoggedIn = true;
$rootScope.token_expire = today.getTime();
// Force request to /organizations to query with the correct token -in the event a new user
// has logged in.
var today = new Date();
today.setTime(today.getTime() + ($AnsibleConfig.session_timeout * 1000));
$rootScope.token = token;
$rootScope.userLoggedIn = true;
$rootScope.token_expire = today.getTime();
// Get all the profile/access info regarding the logged in user
Authorization.getUser()
.success(function(data, status, headers, config) {
Authorization.setUserInfo(data);
Authorization.getLicense()
.success(function(data, status, headers, config) {
Authorization.setLicense(data['license_info']);
$location.path('/organizations');
})
.error(function(data, status, headers, config) {
Alert('Error', 'Failed to access user information. GET returned status: ' + status);
});
})
.error( function(data, status, headers, config) {
Alert('Error', 'Failed to access license information. GET returned status: ' + status);
});
})
.error( function(data, status, headers, config) {
if ( data.non_field_errors && data.non_field_errors.length == 0 ) {
// show field specific errors returned by the API
for (var key in data) {
$scope[key + 'Error'] = data[key][0];
}
}
else {
var hdr, msg;
if ( data.non_field_errors && data.non_field_errors.length > 0 ) {
hdr = 'Error';
msg = data.non_field_errors[0];
}
else {
hdr = 'Error';
msg = 'The login attempt failed with a status of: ' + status;
}
$scope.reset();
Alert(hdr, msg);
}
});
// Get all the profile/access info regarding the logged in user
Authorization.getUser()
.success(function(data, status, headers, config) {
Authorization.setUserInfo(data);
Authorization.getLicense()
.success(function(data, status, headers, config) {
Authorization.setLicense(data['license_info']);
$location.path('/organizations');
})
.error(function(data, status, headers, config) {
Alert('Error', 'Failed to access user information. GET returned status: ' + status);
});
})
.error( function(data, status, headers, config) {
Alert('Error', 'Failed to access license information. GET returned status: ' + status);
});
})
.error( function(data, status, headers, config) {
if ( data.non_field_errors && data.non_field_errors.length == 0 ) {
// show field specific errors returned by the API
for (var key in data) {
scope[key + 'Error'] = data[key][0];
}
}
else {
var hdr, msg;
if ( data.non_field_errors && data.non_field_errors.length > 0 ) {
hdr = 'Error';
msg = data.non_field_errors[0];
}
else {
hdr = 'Error';
msg = 'The login attempt failed with a status of: ' + status;
}
scope.reset();
Alert(hdr, msg);
}
});
}
}
}

View File

@ -43,13 +43,16 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
rows = (n) ? n.length : 1;
rows = (rows > 10) ? 10 : rows;
found = true;
html += "<div class=\"form-group\">\n";
html += "<label>Traceback:</label>\n";
html += "<textarea readonly class=\"input-xxlarge nowrap\" rows=\"" + rows + "\">" + eventData.res + "</textarea>\n";
html += "<textarea readonly class=\"form-control nowrap\" rows=\"" + rows + "\">" + eventData.res + "</textarea>\n";
html += "</div>\n";
}
else {
for (var fld in eventData.res) {
if ( (fld == 'msg' || fld == 'stdout' || fld == 'stderr') &&
(eventData.res[fld] !== null && eventData.res[fld] !== '') ) {
html += "<div class=\"form-group\">\n";
html += "<label>";
switch(fld) {
case 'msg':
@ -64,7 +67,8 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
n = eventData['res'][fld].match(/\n/g);
rows = (n) ? n.length : 1;
rows = (rows > 10) ? 10 : rows;
html += "<textarea readonly class=\"input-xxlarge nowrap\" rows=\"" + rows + "\">" + eventData.res[fld] + "</textarea>\n";
html += "<textarea readonly class=\"form-control nowrap\" rows=\"" + rows + "\">" + eventData.res[fld] + "</textarea>\n";
html += "</div>\n";
found = true;
}
if ( fld == "results" && Array.isArray(eventData.res[fld]) && eventData.res[fld].length > 0 ) {
@ -77,14 +81,18 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
rows = (n) ? n.length : 1;
rows = (rows > 10) ? 10 : rows;
if (txt !== '') {
html += "<div class=\"form-group\">\n";
html += "<label>Results:</label>\n";
html += "<textarea readonly class=\"input-xxlarge nowrap\" rows=\"" + rows + "\">" + txt + "</textarea>\n";
html += "<textarea readonly class=\"form-control nowrap\" rows=\"" + rows + "\">" + txt + "</textarea>\n";
html += "</div>\n";
found = true;
}
}
if (fld == "rc" && eventData.res[fld] != '') {
html += "<div class=\"form-group\">\n";
html += "<label>Return Code:</label>\n";
html += "<input type=\"text\" class=\"input-mini\" value=\"" + eventData.res[fld] + "\" readonly >\n";
html += "<input type=\"text\" class=\"form-control\" value=\"" + eventData.res[fld] + "\" readonly >\n";
html += "</div>\n";
found = true;
}
}
@ -92,7 +100,7 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
html = (found) ? "<form class=\"event-form\">\n" + html + "</form>\n" : '';
}
if (eventData['host']) {
html = "<span class=\"event-detail-host visible-phone visible-tablet\">" + eventData['host'] + "</span>\n" + html;
html = "<span class=\"event-detail-host visible-sm\">" + eventData['host'] + "</span>\n" + html;
}
else {
html = (html == '' ) ? null : html;

View File

@ -14,8 +14,9 @@ angular.module('GroupFormDefinition', [])
editTitle: '{{ name }}', //Legend in edit mode
name: 'group', //Form name attribute
well: false, //Wrap the form with TB well
"class": 'horizontal-narrow',
formLabelSize: 'col-lg-3',
formFieldSize: 'col-lg-9',
fields: {
name: {
label: 'Name',

View File

@ -13,8 +13,9 @@ angular.module('HostFormDefinition', [])
addTitle: 'Create Host', //Legend in add mode
editTitle: '{{ name }}', //Legend in edit mode
name: 'host', //Form name attribute
"class": 'horizontal-narrow',
well: false, //Wrap the form with TB well
well: false, //Wrap the form with TB well
formLabelSize: 'col-lg-3',
formFieldSize: 'col-lg-9',
fields: {
name: {

View File

@ -113,7 +113,7 @@ angular.module('InventoryFormDefinition', [])
select: {
ngClick: "selectHost()",
icon: 'icon-check',
label: 'Add Existing Host',
label: 'Add Existing',
awToolTip: 'Select existing host',
ngHide: 'createButtonShow == false',
"class": 'btn btn-pad'
@ -121,7 +121,7 @@ angular.module('InventoryFormDefinition', [])
create: {
ngClick: "createHost()",
icon: 'icon-plus',
label: 'Create New Host',
label: 'Create New',
awToolTip: 'Create a new host',
ngHide: 'createButtonShow == false',
"class": 'btn-success'

View File

@ -43,7 +43,8 @@ angular.module('JobTemplateFormDefinition', [])
" on the selected hosts.</p> <p>Setting the type to <em>check</em> will not execute the playbook. Instead, ansible will check playbook " +
" syntax, test environment setup and report problems.</p>",
dataTitle: 'Job Type',
dataPlacement: 'right'
dataPlacement: 'right',
dataContainer: "body"
},
inventory: {
label: 'Inventory',
@ -100,7 +101,8 @@ angular.module('JobTemplateFormDefinition', [])
awPopOver: "<p>The number of parallel or simultaneous processes to use while executing the playbook. Provide a value between 0 and 100. " +
"A value of zero will use the ansible default setting of 5 parallel processes.</p>",
dataTitle: 'Forks',
dataPlacement: 'right'
dataPlacement: 'right',
dataContainer: "body"
},
limit: {
label: 'Limit',
@ -113,7 +115,8 @@ angular.module('JobTemplateFormDefinition', [])
"<a href=\"http://ansible.cc/docs/patterns.html#selecting-targets\" target=\"_blank\">Selecting Targets section</a> under Inventory and Patterns " +
" in the Ansible documentation.</p>",
dataTitle: 'Limit',
dataPlacement: 'right'
dataPlacement: 'right',
dataContainer: "body"
},
verbosity: {
label: 'Verbosity',
@ -125,7 +128,8 @@ angular.module('JobTemplateFormDefinition', [])
column: 1,
awPopOver: "<p>Control the level of output ansible will produce as the playbook executes.</p>",
dataTitle: 'Verbosity',
dataPlacement: 'right'
dataPlacement: 'right',
dataContainer: "body"
},
variables: {
label: 'Extra Variables',
@ -143,7 +147,8 @@ angular.module('JobTemplateFormDefinition', [])
"YAML:<br />\n" +
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n",
dataTitle: 'Extra Variables',
dataPlacement: 'left'
dataPlacement: 'left',
dataContainer: "body"
},
job_tags: {
label: 'Job Tags',
@ -161,7 +166,8 @@ angular.module('JobTemplateFormDefinition', [])
"in the Job Tags field:<\p>\n" +
"<blockquote>configuration,packages</blockquote>\n",
dataTitle: "Job Tags",
dataPlacement: "left"
dataPlacement: "left",
dataContainer: "body"
},
allow_callbacks: {
label: 'Allow Callbacks',
@ -182,8 +188,8 @@ angular.module('JobTemplateFormDefinition', [])
"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>",
detailPlacement: 'left',
dataContainer: '#job_templates',
dataTitle: 'Callback URL'
dataTitle: 'Callback URL',
dataContainer: "body"
},
callback_url: {
label: 'Callback URL',
@ -202,8 +208,8 @@ angular.module('JobTemplateFormDefinition', [])
"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>",
detailPlacement: 'left',
dataContainer: '#job_templates',
dataTitle: 'Callback URL'
dataTitle: 'Callback URL',
dataContainer: "body"
},
host_config_key: {
label: 'Host Config Key',
@ -216,7 +222,7 @@ angular.module('JobTemplateFormDefinition', [])
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n",
detailPlacement: 'left',
dataContainer: '#job_templates'
dataContainer: "body"
}
},

View File

@ -253,16 +253,18 @@ angular.module('JobFormDefinition', [])
label: 'Standard Out',
type: 'textarea',
readonly: true,
xtraWide: true,
rows: "\{\{ stdout_rows \}\}",
"class": 'span12 nowrap',
"class": 'nowrap',
ngShow: "result_stdout != ''"
},
result_traceback: {
label: 'Traceback',
type: 'textarea',
type: 'textarea',
xtraWide: true,
readonly: true,
rows: "\{\{ traceback_rows \}\}",
"class": 'span12 nowrap',
"class": 'nowrap',
ngShow: "result_traceback != ''"
}
},
@ -292,10 +294,6 @@ angular.module('JobFormDefinition', [])
awToolTip: 'Edit job events',
mode: 'all'
}
},
related: { //related colletions (and maybe items?)
}
}); //Form

View File

@ -56,7 +56,7 @@ angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies'])
$rootScope.license_tested = true;
if (license['valid_key'] !== undefined && license['valid_key'] == false) {
// The license is invalid. Stop the user from logging in.
status = 'alert-error';
status = 'alert-danger';
hdr = 'License Error';
msg = 'Something is wrong with your /etc/awx/license file on this server. ' +
'Please contact <a href="mailto:info@ansibleworks.com">info@ansibleworks.com</a> for assistance.';

View File

@ -24,7 +24,6 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
name: 'job_events',
well: false,
forceListeners: true,
'class': 'horizontal-narrow',
fields: {
status: {
labelClass: 'job-\{\{ status \}\}',
@ -76,37 +75,38 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
ngShow: "rc !== ''"
},
msg: {
label: false,
label: 'Msg',
type: 'textarea',
readonly: true,
section: 'Results',
'class': 'modal-input-xxlarge nowrap',
'class': 'nowrap',
ngShow: "msg !== ''",
rows: 10
},
stdout: {
label: false,
label: 'Std Out',
type: 'textarea',
readonly: true,
section: 'Results',
'class': 'modal-input-xxlarge nowrap',
'class': 'nowrap',
ngShow: "stdout !== ''",
rows: 10
},
stderr: {
label: false,
label: 'Std Err',
type: 'textarea',
readonly: true,
section: 'Results',
'class': 'modal-input-xxlarge nowrap',
'class': 'nowrap',
ngShow: "stderr !== ''",
rows: 10
},
results: {
label: false,
label: 'Results',
type: 'textarea',
section: 'Results',
readonly: true,
'class': 'modal-input-xxlarge nowrap',
'class': 'nowrap',
ngShow: "results !== ''",
rows: 10
},
@ -122,7 +122,7 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
type: 'textarea',
readonly: true,
section: 'Traceback',
'class': 'modal-input-xxlarge nowrap',
'class': 'nowrap',
ngShow: "traceback !== ''",
rows: 10
},
@ -148,7 +148,7 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
ngShow: "module_name !== ''"
},
module_args: {
label: 'Arguments',
label: 'Args',
type: 'text',
readonly: true,
section: 'Module',

View File

@ -37,7 +37,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
scope.formModalCancelShow = true;
scope.formModalActionClass = 'btn btn-success';
$('.popover').remove(); //remove any lingering pop-overs
$('.popover').popover('hide'); //remove any lingering pop-overs
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
$('#form-modal').modal({ backdrop: 'static', keyboard: false });

View File

@ -52,7 +52,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
HostsReload(params);
});
$('.popover').remove(); //remove any lingering pop-overs
$('.popover').popover('hide'); //remove any lingering pop-overs
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
$('#form-modal').modal({ backdrop: 'static', keyboard: false });

View File

@ -49,7 +49,7 @@ angular.module('CredentialsListDefinition', [])
mode: 'all', // One of: edit, select, all
ngClick: 'addCredential()',
basePaths: ['teams','users'], // base path must be in list, or action not available
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Create a new credential'
}
},
@ -59,7 +59,7 @@ angular.module('CredentialsListDefinition', [])
ngClick: "editCredential(\{\{ credential.id \}\})",
icon: 'icon-edit',
label: 'Edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit credential'
},
@ -67,7 +67,7 @@ angular.module('CredentialsListDefinition', [])
ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')",
icon: 'icon-trash',
label: 'Delete',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete credential'
}
}

View File

@ -33,7 +33,7 @@ angular.module('GroupListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'createGroup()',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Create a new group'
},
help: {
@ -44,7 +44,7 @@ angular.module('GroupListDefinition', [])
dataContainer: "#form-modal",
icon: "icon-question-sign",
mode: 'all',
'class': 'btn-small btn-info',
'class': 'btn-mini btn-info',
awToolTip: 'Click for help',
dataTitle: 'Adding Groups',
id: 'group-help-button',
@ -57,7 +57,7 @@ angular.module('GroupListDefinition', [])
label: 'Edit',
ngClick: "editGroup(\{\{ group.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit group'
},
@ -65,7 +65,7 @@ angular.module('GroupListDefinition', [])
label: 'Delete',
ngClick: "deleteGroup(\{\{ group.id \}\},'\{\{ group.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete group'
}
}

View File

@ -35,7 +35,7 @@ angular.module('HostListDefinition', [])
dataContainer: "#form-modal",
icon: "icon-question-sign",
mode: 'all',
'class': 'btn-small btn-info',
'class': 'btn-mini btn-info',
awToolTip: 'Click for help',
dataTitle: 'Selecting Hosts',
iconSize: 'large',
@ -48,7 +48,7 @@ angular.module('HostListDefinition', [])
label: 'Edit',
ngClick: "editHost(\{\{ host.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit host'
},
@ -56,7 +56,7 @@ angular.module('HostListDefinition', [])
label: 'Delete',
ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete host'
}
}

View File

@ -54,7 +54,7 @@ angular.module('InventoriesListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'addInventory()',
"class": 'btn-small btn-success',
"class": 'btn-mini btn-success',
awToolTip: 'Create a new inventory'
}
},
@ -64,7 +64,7 @@ angular.module('InventoriesListDefinition', [])
label: 'Edit',
ngClick: "editInventory(\{\{ inventory.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit inventory'
},
@ -72,7 +72,7 @@ angular.module('InventoriesListDefinition', [])
label: 'Delete',
ngClick: "deleteInventory(\{\{ inventory.id \}\},'\{\{ inventory.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete inventory'
}
}

View File

@ -53,7 +53,7 @@ angular.module('JobEventsListDefinition', [])
nosort: true,
searchOnly: false,
id: 'job-event-host-header',
columnClass: 'hidden-phone hidden-tablet'
columnClass: 'hidden-sm'
}
},
@ -63,14 +63,14 @@ angular.module('JobEventsListDefinition', [])
icon: 'icon-refresh',
label: 'Refresh',
awToolTip: 'Refresh the page',
"class": 'btn-small btn-success',
"class": 'btn-mini btn-success',
mode: 'all'
},
edit: {
label: 'Details',
ngClick: "jobDetails()",
icon: 'icon-zoom-in',
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'Edit job details',
mode: 'all'
},
@ -78,7 +78,7 @@ angular.module('JobEventsListDefinition', [])
label: 'Hosts',
icon: 'icon-th-large',
ngClick: "jobSummary()",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'View host summary',
mode: 'all'
}
@ -89,7 +89,7 @@ angular.module('JobEventsListDefinition', [])
label: 'View',
ngClick: "viewJobEvent(\{\{ jobevent.id \}\})",
icon: 'icon-zoom-in',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View event details'
}
}

View File

@ -60,7 +60,7 @@ angular.module('JobHostDefinition', [])
label: 'Refresh',
icon: 'icon-refresh',
ngClick: "refresh()",
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Refresh the page',
mode: 'all'
},
@ -68,7 +68,7 @@ angular.module('JobHostDefinition', [])
label: 'Details',
icon: 'icon-edit',
ngClick: "jobDetails()",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'Edit job details',
mode: 'all'
},
@ -76,7 +76,7 @@ angular.module('JobHostDefinition', [])
label: 'Events',
icon: 'icon-list-ul',
ngClick: "jobEvents()",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'View job events',
mode: 'all'
},

View File

@ -34,7 +34,7 @@ angular.module('JobTemplatesListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'addJobTemplate()',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
basePaths: ['job_templates'],
awToolTip: 'Create a new template'
}
@ -46,13 +46,13 @@ angular.module('JobTemplatesListDefinition', [])
ngClick: "editJobTemplate(\{\{ job_template.id \}\})",
icon: 'icon-edit',
awToolTip: 'Edit template',
"class": 'btn-small'
"class": 'btn-mini'
},
submit: {
label: 'Launch',
icon: 'icon-rocket',
mode: 'all',
"class": 'btn-small btn-success',
"class": 'btn-mini btn-success',
ngClick: 'submitJob(\{\{ job_template.id \}\})',
awToolTip: 'Start a job using this template'
},
@ -60,7 +60,7 @@ angular.module('JobTemplatesListDefinition', [])
label: 'Delete',
ngClick: "deleteJobTemplate(\{\{ job_template.id \}\},'\{\{ job_template.name \}\}')",
icon: 'icon-trash',
"class": 'btn-danger btn-small',
"class": 'btn-danger btn-mini',
awToolTip: 'Delete template'
}
}

View File

@ -57,7 +57,7 @@ angular.module('JobsListDefinition', [])
actions: {
refresh: {
label: 'Refresh',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
ngClick: "refreshJob(\{\{ job.id \}\})",
icon: 'icon-refresh',
awToolTip: 'Refresh the page',
@ -70,7 +70,7 @@ angular.module('JobsListDefinition', [])
label: 'Hosts',
icon: 'icon-th-large',
ngClick: "viewSummary(\{{ job.id \}\}, '\{\{ job.name \}\}')",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'View host summary',
ngDisabled: "job.status == 'new'"
},
@ -79,7 +79,7 @@ angular.module('JobsListDefinition', [])
icon: 'icon-list-ul',
mode: 'all',
ngClick: "viewEvents(\{{ job.id \}\}, '\{\{ job.name \}\}')",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'View events',
ngDisabled: "job.status == 'new'"
},
@ -87,21 +87,21 @@ angular.module('JobsListDefinition', [])
label: 'Details',
icon: 'icon-zoom-in',
ngClick: "editJob(\{\{ job.id \}\}, '\{\{ job.name \}\}')",
"class": 'btn btn-small',
"class": 'btn btn-mini',
awToolTip: 'View job details'
},
rerun: {
icon: 'icon-retweet',
mode: 'all',
ngClick: "submitJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}' )",
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Re-run this job'
},
cancel: {
icon: 'icon-minus-sign',
mode: 'all',
ngClick: 'deleteJob(\{\{ job.id \}\})',
"class": 'btn-danger btn-small',
"class": 'btn-danger btn-mini',
awToolTip: 'Cancel job',
ngShow: "job.status == 'pending' || job.status == 'running'"
},
@ -109,7 +109,7 @@ angular.module('JobsListDefinition', [])
icon: 'icon-trash',
mode: 'all',
ngClick: 'deleteJob(\{\{ job.id \}\})',
"class": 'btn-danger btn-small',
"class": 'btn-danger btn-mini',
awToolTip: 'Delete this job',
ngShow: "job.status != 'pending' && job.status != 'running'"
}

View File

@ -33,7 +33,7 @@ angular.module('OrganizationListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'addOrganization()',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Create a new organization'
}
},
@ -43,7 +43,7 @@ angular.module('OrganizationListDefinition', [])
label: 'Edit',
ngClick: "editOrganization(\{\{ organization.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit organization'
},
@ -51,7 +51,7 @@ angular.module('OrganizationListDefinition', [])
label: 'Delete',
ngClick: "deleteOrganization(\{\{ organization.id \}\},'\{\{ organization.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete organization'
}
}

View File

@ -47,7 +47,7 @@ angular.module('PermissionListDefinition', [])
label: 'Create New',
mode: 'all', // One of: edit, select, all
ngClick: 'addPermission()',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Add a new permission'
}
},
@ -57,7 +57,7 @@ angular.module('PermissionListDefinition', [])
label: 'Edit',
ngClick: "editPermission(\{\{ permission.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit permission'
},
@ -65,7 +65,7 @@ angular.module('PermissionListDefinition', [])
label: 'Delete',
ngClick: "deletePermission(\{\{ permission.id \}\},'\{\{ permission.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete permission'
}
}

View File

@ -35,7 +35,7 @@ angular.module('ProjectsListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'addProject()',
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Create a new project'
}
},
@ -45,7 +45,7 @@ angular.module('ProjectsListDefinition', [])
label: 'Edit',
ngClick: "editProject(\{\{ project.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/edit project'
},
@ -53,7 +53,7 @@ angular.module('ProjectsListDefinition', [])
label: 'Delete',
ngClick: "deleteProject(\{\{ project.id \}\},'\{\{ project.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete project'
}
}

View File

@ -40,7 +40,7 @@ angular.module('TeamsListDefinition', [])
icon: 'icon-plus',
mode: 'all', // One of: edit, select, all
ngClick: 'addTeam()',
"class": 'btn-small btn-success',
"class": 'btn-mini btn-success',
awToolTip: 'Create a new team'
}
},
@ -50,7 +50,7 @@ angular.module('TeamsListDefinition', [])
label: 'Edit',
ngClick: "editTeam(\{\{ team.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit team'
},
@ -58,7 +58,7 @@ angular.module('TeamsListDefinition', [])
label: 'Delete',
ngClick: "deleteTeam(\{\{ team.id \}\},'\{\{ team.name \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete team'
}
}

View File

@ -40,7 +40,7 @@ angular.module('UserListDefinition', [])
mode: 'all', // One of: edit, select, all
ngClick: 'addUser()',
basePaths: ['organizations','users'], // base path must be in list, or action not available
"class": 'btn-success btn-small',
"class": 'btn-success btn-mini',
awToolTip: 'Create a new user'
}
},
@ -50,7 +50,7 @@ angular.module('UserListDefinition', [])
label: 'Edit',
ngClick: "editUser(\{\{ user.id \}\})",
icon: 'icon-edit',
"class": 'btn-small',
"class": 'btn-mini',
awToolTip: 'View/Edit user'
},
@ -58,7 +58,7 @@ angular.module('UserListDefinition', [])
label: 'Delete',
ngClick: "deleteUser(\{\{ user.id \}\},'\{\{ user.username \}\}')",
icon: 'icon-trash',
"class": 'btn-small btn-danger',
"class": 'btn-mini btn-danger',
awToolTip: 'Delete user'
}
}

View File

@ -209,18 +209,21 @@ angular.module('AWDirectives', ['RestServices'])
content: attrs.awPopOver, trigger: 'manual', html: true, container: container });
$(element).click(function() {
var me = $(this).attr('id');
var e = $(this);
$('.help-link, .help-link-white').each( function(index) {
if (me != $(this).attr('id')) {
$(this).popover('hide');
}
else {
$(this).popover('toggle');
}
});
$('.popover').each(function(index) {
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
$(this).remove();
});
$(this).popover('toggle');
});
$(document).bind('keydown', function(e) {
if (e.keyCode === 27) {
$(element).popover('hide');
$(element).popover('destroy');
}
});
}

View File

@ -72,14 +72,14 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
if (options.modal) {
this.scope.formHeader = (options.mode == 'add') ? form.addTitle : form.editTitle; //Default title for default modal
this.scope.formModalInfo = false //Disable info button for default modal
$('.popover').remove(); //remove any lingering pop-overs
$('.popover').popover('hide'); //remove any lingering pop-overs
if (options.modal_selector) {
$(options.modal_selector).removeClass('skinny-modal'); //Used in job_events to remove white space
$(options.modal_selector).modal({ backdrop: 'static', keyboard: false });
$(options.modal_selector).modal({ show: true, backdrop: 'static', keyboard: false });
}
else {
$('#form-modal').removeClass('skinny-modal'); //Used in job_events to remove white space
$('#form-modal').modal({ backdrop: 'static', keyboard: false });
//$('#form-modal').removeClass('skinny-modal'); //Used in job_events to remove white space
$('#form-modal').modal({ show: true, backdrop: 'static', keyboard: false });
}
}
return this.scope;
@ -212,7 +212,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
var html = '';
for (var i=0; i < btn.position.length; i++) {
if (btn.position[i].indexOf(topOrBottom) >= 0) {
html += "<button ";
html += "<button type=\"button\" ";
html += "class=\"btn";
html += (btn['class']) ? " " + btn['class'] : "";
if (btn.position[i] == 'top-right' || btn.position[i] == 'bottom-right') {
@ -228,22 +228,65 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
return html;
},
buildField: function(fld, field, options) {
var html='';
buildField: function(fld, field, options, form) {
//Assuming horizontal form for now. This will need to be more flexible later.
function getFieldWidth() {
var x;
if (form.formFieldSize) {
x = form.formFieldSize;
}
else if (field.xtraWide) {
x = "col-lg-10";
}
else if (field.column) {
x = "col-lg-8";
}
else if (!form.formFieldSize && options.modal) {
x = "col-lg-10";
}
else {
x = "col-lg-6";
}
return x;
}
//text fields
if (field.type == 'text' || field.type == 'password' || field.type == 'email') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += (field.ngHide) ? this.attr(field,'ngHide') : "";
html += ">\n";
function getLabelWidth() {
var x;
if (form.formLabelSize) {
x = form.formLabelSize;
}
else if (field.column) {
x = "col-lg-4";
}
else if (!form.formLabelSize && options.modal) {
x = "col-lg-2";
}
else {
x = "col-lg-2";
}
return x;
}
var html = '';
if (field.type == 'hidden') {
if ( (options.mode == 'edit' && field.includeOnEdit) ||
(options.mode == 'add' && field.includeOnAdd) ) {
html += "<input type=\"hidden\" ng-model=\"" + fld + "\" name=\"" + fld + "\" />";
}
}
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"form-group\" ";
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += (field.ngHide) ? this.attr(field,'ngHide') : "";
html += ">\n";
//text fields
if (field.type == 'text' || field.type == 'password' || field.type == 'email') {
html += "<label ";
html += (field.labelNGClass) ? "ng-class=\"" + field.labelNGClass + "\" " : "";
html += "class=\"control-label";
html += "class=\"control-label " + getLabelWidth();
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
@ -251,8 +294,9 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"controls\">\n";
html += (field.clear || field.genMD5) ? "<div class=\"input-append\">\n" : "";
html += "class=\"" + getFieldWidth() + "\">\n";
html += (field.clear || field.genMD5) ? "<div class=\"input-group\">\n" : "";
if (field.control === null || field.control === undefined || field.control) {
html += "<input ";
html += this.attr(field,'type');
@ -260,7 +304,9 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += 'name="' + fld + '" ';
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field['class']) ? this.attr(field, 'class') : "";
html += "class=\"form-control";
html += (field['class']) ? " " + this.attr(field, 'class') : "";
html += "\" ";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
@ -270,310 +316,288 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += (field.ask) ? "ng-disabled=\"" + fld + "_ask\" " : "";
html += (field.autocomplete !== undefined) ? this.attr(field, 'autocomplete') : "";
html += (field.awRequiredWhen) ? "data-awrequired-init=\"" + field.awRequiredWhen.init + "\" aw-required-when=\"" +
field.awRequiredWhen.variable + "\" " : "";
field.awRequiredWhen.variable + "\" " : "";
html += (field.associated && this.form.fields[field.associated].ask) ? "ng-disabled=\"" + field.associated + "_ask\" " : "";
html += "/>";
if (field.clear) {
html += " \n<button class=\"btn\" ng-click=\"clear('" + fld + "','" + field.associated + "')\" " +
"aw-tool-tip=\"Clear " + field.label + "\" id=\"" + fld + "-clear-btn\"><i class=\"icon-undo\"></i></button>\n";
html += "</div>\n";
}
if (field.genMD5) {
html += " \n<button class=\"btn\" ng-click=\"genMD5('" + fld + "')\" " +
"aw-tool-tip=\"Generate " + field.label + "\" data-placement=\"top\" id=\"" + fld + "-gen-btn\"><i class=\"icon-repeat\"></i></button>\n";
/*html += " \n<button style=\"margin-left: 10px;\" class=\"btn\" ng-click=\"selectAll('" + fld + "')\" " +
"aw-tool-tip=\"Select " + field.label + " for copy\" data-placement=\"top\" id=\"" + fld + "-copy-btn\"><i class=\"icon-copy\"></i></button>\n";*/
html += "</div>\n";
}
html += " >\n";
}
if (field.clear) {
html += "<span class=\"input-group-btn\"><button type=\"button\" class=\"btn\" ng-click=\"clear('" + fld + "','" + field.associated + "')\" " +
"aw-tool-tip=\"Clear " + field.label + "\" id=\"" + fld + "-clear-btn\"><i class=\"icon-undo\"></i></button>\n";
if (field.ask) {
html += " \n<label class=\"checkbox inline ask-checkbox\"><input type=\"checkbox\" ng-model=\"" +
fld + "_ask\" ng-change=\"ask('" + fld + "','" + field.associated + "')\" /> Ask at runtime?</label>";
html += "<label class=\"checkbox-inline ask-checkbox\"><input type=\"checkbox\" ng-model=\"" +
fld + "_ask\" ng-change=\"ask('" + fld + "','" + field.associated + "')\" > Ask at runtime?</label>";
}
html += "<br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ||
field.awRequiredWhen ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span>\n";
}
if (field.type == "email") {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.email\">A valid email address is required!</span>\n";
}
if (field.awPassMatch) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld +
".$error.awpassmatch\">Must match Password value</span>\n";
}
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
}
html += "</div>\n";
html += "</div>\n";
}
}
//textarea fields
if (field.type == 'textarea') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
if (field.label !== false) {
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
}
// Variable editing
if (fld == "variables" || fld == "extra_vars" || fld == 'inventory_variables') {
html += "<div class=\"parse-selection\">Parse as: " +
"<label class=\"radio inline\"><input type=\"radio\" ng-model=\"";
html += (this.form.parseTypeName) ? this.form.parseTypeName : 'parseType';
html += "\" value=\"yaml\"> YAML</label>\n";
html += "<label class=\"radio inline\"><input type=\"radio\" ng-model=\"";
html += (this.form.parseTypeName) ? this.form.parseTypeName : 'parseType';
html += "\" value=\"json\"> JSON</label></div>\n";
html += "</span>\n</div>\n";
}
if (field.genMD5) {
html += "<span class=\"input-group-btn\"><button type=\"button\" class=\"btn\" ng-click=\"genMD5('" + fld + "')\" " +
"aw-tool-tip=\"Generate " + field.label + "\" data-placement=\"top\" id=\"" + fld + "-gen-btn\"><i class=\"icon-repeat\">" +
"</i></button></span>\n</div>\n";
}
html += "<textarea ";
html += (field.rows) ? this.attr(field, 'rows') : "";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += (field['class']) ? this.attr(field,'class') : "";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly || field.showonly) ? "readonly " : "";
html += "></textarea><br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span>\n";
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ||
field.awRequiredWhen ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</div>\n";
}
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
if (field.label !== false) {
html += "</div>\n";
if (field.type == "email") {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.email\">A valid email address is required!</div>\n";
}
if (field.awPassMatch) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld +
".$error.awpassmatch\">Must match Password value</div>\n";
}
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
html += "</div>\n";
}
}
//textarea fields
if (field.type == 'textarea') {
if (field.label !== false) {
html += "<label class=\"control-label " + getLabelWidth() + "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
}
// Variable editing
if (fld == "variables" || fld == "extra_vars" || fld == 'inventory_variables') {
html += "<div class=\"parse-selection\">Parse as: " +
"<input type=\"radio\" ng-model=\"";
html += (this.form.parseTypeName) ? this.form.parseTypeName : 'parseType';
html += "\" value=\"yaml\"> <span class=\"parse-label\">YAML</span>\n";
html += "<input type=\"radio\" ng-model=\"";
html += (this.form.parseTypeName) ? this.form.parseTypeName : 'parseType';
html += "\" value=\"json\"> <span class=\"parse-label\">JSON</span>\n</div>\n";
}
html += "<textarea ";
html += (field.rows) ? this.attr(field, 'rows') : "";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += "class=\"form-control";
html += (field['class']) ? " " + field['class'] : "";
html += "\" ";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly || field.showonly) ? "readonly " : "";
html += "></textarea>\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</div>\n";
}
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
if (field.label !== false) {
html += "</div>\n";
}
}
//select field
if (field.type == 'select') {
html += "<label class=\"control-label " + getLabelWidth() + "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
html += "<select ";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += "class=\"form-control";
html += (field['class']) ? " " + field['class'] : "";
html += "\" ";
html += this.attr(field, 'ngOptions');
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += ">\n";
html += "<option value=\"\">Choose " + field.label + "</option>\n";
html += "</select>\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</div>\n";
}
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
html += "</div>\n";
}
//number field
if (field.type == 'number') {
html += "<label class=\"control-label " + getLabelWidth() + "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
// Use 'text' rather than 'number' so that our integer directive works correctly
html += (field.slider) ? "<div class=\"slider\" id=\"" + fld + "-slider\"></div>\n" : "";
html += "<input type=\"";
html += (field.spinner) ? "spinner" : "text";
html += "\" value=\"" + field['default'] + "\" ";
html += "class=\"form-control";
html += (field['class']) ? " " + field['class'] : "";
html += "\" ";
html += (field.slider) ? "ng-slider=\"" + fld + "\" " : "";
html += (field.spinner) ? "ng-spinner=\"" + fld + "\" " : "";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += (field.min || field.min == 0) ? this.attr(field, 'min') : "";
html += (field.max) ? this.attr(field, 'max') : "";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.slider) ? "id=\"" + fld + "-number\"" : (field.id) ? this.attr(field,'id') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += (field.integer) ? "integer " : "";
html += (field.disabled) ? "data-disabled=\"true\" " : "";
html += " >\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</div>\n";
}
if (field.integer) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$error.integer\">Must be an integer value</div>\n";
}
if (field.min || field.max) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$error.min || " +
this.form.name + '_form.' + fld + ".$error.max\">Must be in range " + field.min + " to " +
field.max + "</div>\n";
}
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
html += "</div>\n";
}
//checkbox
if (field.type == 'checkbox') {
html += "<label class=\"control-label " + getLabelWidth() + "\" > </label>\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
html += "<label class=\"checkbox-inline\">";
html += "<input type=\"checkbox\" ";
html += this.attr(field,'type');
html += "ng-model=\"" + fld + '" ';
html += "name=\"" + fld + '" ';
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += this.attr(field,'trueValue');
html += this.attr(field,'falseValue');
html += (field.checked) ? "checked " : "";
html += (field.readonly) ? "disabled " : "";
html += " > " + field.label + "\n";
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += "</label>\n";
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
html += "</div>\n";
}
//radio
if (field.type == 'radio') {
html += "<label class=\"control-label " + getLabelWidth() + "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
for (var i=0; i < field.options.length; i++) {
html += "<label class=\"radio-inline\" ";
html += (field.options[i].ngShow) ? this.attr(field.options[i],'ngShow') : "";
html += ">";
html += "<input type=\"radio\" ";
html += "name=\"" + fld + "\" ";
html += "value=\"" + field.options[i].value + "\" ";
html += "ng-model=\"" + fld + "\" ";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.readonly) ? "disabled " : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += " > " + field.options[i].label + "\n";
html += "</label>\n";
}
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</div>\n";
}
html += "<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>\n";
html += "</div>\n";
}
//lookup type fields
if (field.type == 'lookup' && (field.excludeMode == undefined || field.excludeMode != options.mode)) {
html += "<label class=\"control-label " + getLabelWidth() + "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
html += "<div class=\"input-group\">\n";
html += "<span class=\"input-group-btn\">\n";
html += "<button type=\"button\" class=\"lookup-btn btn\" " + this.attr(field,'ngClick') + "><i class=\"icon-search\"></i></button>\n";
html += "</span>\n";
html += "<input type=\"text\" class=\"form-control input-medium\" ";
html += "ng-model=\"" + field.sourceModel + '_' + field.sourceField + "\" ";
html += "name=\"" + field.sourceModel + '_' + field.sourceField + "\" ";
html += "class=\"form-control\" ";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (field.awRequiredWhen) ? "data-awrequired-init=\"" + field.awRequiredWhen.init + "\" aw-required-when=\"" +
field.awRequiredWhen.variable + "\" " : "";
html += " awlookup >\n";
html += "</div>\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ||
field.awRequiredWhen ) {
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' +
field.sourceModel + '_' + field.sourceField + ".$dirty && " +
this.form.name + '_form.' + field.sourceModel + '_' + field.sourceField +
".$error.required\">A value is required!</div>\n";
}
html += "<div class=\"error\" ng-show=\"" + this.form.name + '_form.' +
field.sourceModel + '_' + field.sourceField + ".$dirty && " +
this.form.name + '_form.' + field.sourceModel + '_' + field.sourceField +
".$error.awlookup\">Value not found</div>\n";
html += "<div class=\"error api-error\" ng-bind=\"" + field.sourceModel + '_' + field.sourceField +
"_api_error\"></div>\n";
html += "</div>\n";
}
//custom fields
if (field.type == 'custom') {
html += "<label class=\"control-label " + getLabelWidth();
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += (field.icon) ? this.icon(field.icon) : "";
html += (field.label) ? field.label : '';
html += '</label>' + "\n";
html += "<div ";
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"" + getFieldWidth() + "\">\n";
html += field.control;
html += "</div>\n";
}
html += "</div>\n";
}
//select field
if (field.type == 'select') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
html += "<select ";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
//html += "ng-options=\"item.label for item in " + fld + "_options\" ";
html += this.attr(field, 'ngOptions');
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += ">\n";
html += "<option value=\"\">Choose " + field.label + "</option>\n";
html += "</select><br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span>\n";
}
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n";
html += "</div>\n";
}
}
//number field
if (field.type == 'number') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
// Use 'text' rather than 'number' so that our integer directive works correctly
html += (field.slider) ? "<div class=\"slider\" id=\"" + fld + "-slider\"></div>\n" : "";
html += "<input type=\"";
html += (field.spinner) ? "spinner" : "text";
html += "\" value=\"" + field['default'] + "\" ";
html += (field['class']) ? this.attr(field, 'class') : "";
html += (field.slider) ? "ng-slider=\"" + fld + "\" " : "";
html += (field.spinner) ? "ng-spinner=\"" + fld + "\" " : "";
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += (field.min || field.min == 0) ? this.attr(field, 'min') : "";
html += (field.max) ? this.attr(field, 'max') : "";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.slider) ? "id=\"" + fld + "-number\"" : (field.id) ? this.attr(field,'id') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += (field.integer) ? "integer " : "";
html += (field.disabled) ? "data-disabled=\"true\" " : "";
html += "/>\n";
html += "<br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span>\n";
}
if (field.integer) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$error.integer\">Must be an integer value</span>\n";
}
if (field.min || field.max) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$error.min || " +
this.form.name + '_form.' + fld + ".$error.max\">Must be in range " + field.min + " to " +
field.max + "</span>\n";
}
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n";
html += "</div>\n";
}
}
//checkbox
if (field.type == 'checkbox') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\" "
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<div class=\"controls\">\n";
html += "<label class=\"checkbox inline\">";
html += "<input ";
html += this.attr(field,'type');
html += "ng-model=\"" + fld + '" ';
html += "name=\"" + fld + '" ';
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += this.attr(field,'trueValue');
html += this.attr(field,'falseValue');
html += (field.checked) ? "checked " : "";
html += (field.readonly) ? "disabled " : "";
html += " /> " + field.label + "\n";
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += "</label>\n";
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n";
html += "</div>\n";
}
}
//radio
if (field.type == 'radio') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\" "
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
for (var i=0; i < field.options.length; i++) {
html += "<label class=\"radio inline\" ";
html += (field.options[i].ngShow) ? this.attr(field.options[i],'ngShow') : "";
html += ">";
html += "<input type=\"radio\" ";
html += "name=\"" + fld + "\" ";
html += "value=\"" + field.options[i].value + "\" ";
html += "ng-model=\"" + fld + "\" ";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.readonly) ? "disabled " : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += " /> " + field.options[i].label + "\n";
html += "</label>\n";
}
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<p><span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span></p>\n";
}
html += "<p><span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span></p>\n";
html += "</div>\n";
html += "</div>\n";
}
}
if (field.type == 'hidden') {
if ( (options.mode == 'edit' && field.includeOnEdit) ||
(options.mode == 'add' && field.includeOnAdd) ) {
html += "<input type=\"hidden\" ng-model=\"" + fld + "\" name=\"" + fld + "\" />";
}
}
//lookup type fields
if (field.type == 'lookup' && (field.excludeMode == undefined || field.excludeMode != options.mode)) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
html += "<div class=\"input-prepend\">\n";
html += "<button class=\"lookup-btn btn\" " + this.attr(field,'ngClick') + "><i class=\"icon-search\"></i></button>\n";
html += "<input class=\"input-medium\" type=\"text\" ";
html += "ng-model=\"" + field.sourceModel + '_' + field.sourceField + "\" ";
html += "name=\"" + field.sourceModel + '_' + field.sourceField + "\" ";
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (field.awRequiredWhen) ? "data-awrequired-init=\"" + field.awRequiredWhen.init + "\" aw-required-when=\"" +
field.awRequiredWhen.variable + "\" " : "";
html += " awlookup />\n";
html += "</div><br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ||
field.awRequiredWhen ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' +
field.sourceModel + '_' + field.sourceField + ".$dirty && " +
this.form.name + '_form.' + field.sourceModel + '_' + field.sourceField +
".$error.required\">A value is required!</span>\n";
}
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' +
field.sourceModel + '_' + field.sourceField + ".$dirty && " +
this.form.name + '_form.' + field.sourceModel + '_' + field.sourceField +
".$error.awlookup\">Value not found</span>\n";
html += "<span class=\"error api-error\" ng-bind=\"" + field.sourceModel + '_' + field.sourceField +
"_api_error\"></span>\n";
html += "</div>\n";
html += "</div>\n";
}
//text fields
if (field.type == 'custom') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label";
html += (field.labelClass) ? " " + field.labelClass : "";
html += "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver', fld) : "";
html += (field.icon) ? this.icon(field.icon) : "";
html += (field.label) ? field.label : '';
html += '</label>' + "\n";
html += "<div class=\"controls\">\n";
html += field.control;
html += "</div>\n";
html += "</div>\n";
}
}
return html;
},
@ -588,8 +612,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
//Breadcrumbs
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a> " +
"<span class=\"divider\">/</span></li>\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li class=\"active\">";
if (options.mode == 'edit') {
html += this.form.editTitle;
@ -608,7 +631,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
var act;
for (action in this.form.statusActions) {
act = this.form.statusActions[action];
html += "<button " + this.attr(act, 'ngClick') + "class=\"btn btn-small";
html += "<button type=\"button\" " + this.attr(act, 'ngClick') + "class=\"btn btn-small";
html += (act['class']) ? " " + act['class'] : "";
html += "\" ";
html += (act.awToolTip) ? this.attr(act,'awToolTip') : "";
@ -623,7 +646,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<div class=\"form-horizontal status-fields\">\n";
for (var fld in this.form.statusFields) {
field = this.form.statusFields[fld];
html += this.buildField(fld, field, options);
html += this.buildField(fld, field, options, this.form);
}
html += "</div><!-- status fields -->\n";
html += "</div><!-- well -->\n";
@ -672,24 +695,24 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
var field;
if (this.form.twoColumns) {
html += "<div class=\"row-fluid\">\n";
html += "<div class=\"span6\">\n";
html += "<div class=\"row\">\n";
html += "<div class=\"col-lg-6\">\n";
for (var fld in this.form.fields) {
field = this.form.fields[fld];
if (field.column == 1) {
html += this.buildField(fld, field, options);
html += this.buildField(fld, field, options, this.form);
}
}
html += "</div><!-- column 1 -->\n";
html += "<div class=\"span6\">\n";
html += "<div class=\"col-lg-6\">\n";
for (var fld in this.form.fields) {
field = this.form.fields[fld];
if (field.column == 2) {
html += this.buildField(fld, field, options);
html += this.buildField(fld, field, options, this.form);
}
}
html += "</div><!-- column 2 -->\n";
html += "</div><!-- inner row -->\n";
html += "</div>\n";
}
else {
// original, single-column form
@ -697,7 +720,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
var group = '';
for (var fld in this.form.fields) {
var field = this.form.fields[fld];
if (field.group && field.group != group) {
if (group !== '') {
html += "</div>\n";
@ -720,8 +743,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<div" + sectionShow + ">\n";
section = field.section;
}
html += this.buildField(fld, field, options);
html += this.buildField(fld, field, options, this.form);
}
if (section !== '') {
html += "</div>\n</div>\n";
@ -734,47 +756,52 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
//buttons
if (!this.modal) {
if (this.has('buttons')) {
html += (this.form.twoColumns) ? "<hr />" : "";
html += "<div class=\"control-group\">\n";
html += "<div class=\"controls buttons\">\n";
}
for (var btn in this.form.buttons) {
var button = this.form.buttons[btn];
//button
html += "<button ";
html += "class=\"btn btn-small";
html += (button['class']) ? " " + button['class'] : "";
html += "\" ";
if (button.ngClick) {
html += this.attr(button,'ngClick');
}
if (button.ngDisabled) {
if (btn !== 'reset') {
html += "ng-disabled=\"" + this.form.name + "_form.$pristine || " + this.form.name + "_form.$invalid";
html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : "";
html += "\" ";
if (this.form.twoColumns) {
html += "<div class=\"row\">\n";
html += "<div class=\"col-lg-12\">\n";
html += "<hr />\n";
}
html += "<div class=\"form-group buttons\">\n";
html += "<label class=\"col-lg-2 control-label\"> </label>\n";
html += "<div class=\"controls col-lg-6\">\n";
for (var btn in this.form.buttons) {
var button = this.form.buttons[btn];
//button
html += "<button type=\"button\" ";
html += "class=\"btn btn-small";
html += (button['class']) ? " " + button['class'] : "";
html += "\" ";
if (button.ngClick) {
html += this.attr(button,'ngClick');
}
else {
html += "ng-disabled=\"" + this.form.name + "_form.$pristine";
html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : "";
html += "\" ";
if (button.ngDisabled) {
if (btn !== 'reset') {
html += "ng-disabled=\"" + this.form.name + "_form.$pristine || " + this.form.name + "_form.$invalid";
html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : "";
html += "\" ";
}
else {
html += "ng-disabled=\"" + this.form.name + "_form.$pristine";
html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : "";
html += "\" ";
}
}
}
html += ">";
if (button.icon) {
html += this.icon(button.icon);
}
html += button.label + "</button>\n";
}
if (this.has('buttons')) {
html += ">";
if (button.icon) {
html += this.icon(button.icon);
}
html += button.label + "</button>\n";
}
html += "</div>\n";
html += "</div>\n";
if (this.form.twoColumns) {
html += "</div>\n";
html += "</div>\n";
}
}
html += "</form>\n";
}
html += "</form>\n";
if ( this.has('well') ) {
html += "</div>\n";
}
@ -812,7 +839,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<form class=\"form-horizontal\" name=\"" + this.form.name + '_items_form" id="' + this.form.name + '_items_form" novalidate>' + "\n";
for (var fld in this.form.items[itm].fields) {
var field = this.form.items[itm].fields[fld];
html += this.buildField(fld, field, options);
html += this.buildField(fld, field, options, this.form);
}
html += "</form>\n";
html += "<ul class=\"pager\">\n";
@ -855,22 +882,22 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
*/
html = "<div id=\"" + this.form.name + "-collapse-2\" data-open=\"true\" class=\"jqui-accordion\">\n";
html += "<h3>Inventory Content<h3>\n";
html += "<div>\n";
html += "<div class=\"row\">\n";
for (var itm in form.related) {
if (form.related[itm].type == 'tree') {
html += "<div class=\"span5\">";
html += "<div class=\"col-lg-5\">";
html += "<div class=\"inventory-buttons\">";
html += "<button ng-click=\"editGroup()\" ng-hide=\"groupEditHide\" id=\"inv-group-edit\" class=\"btn btn-pad btn-mini\" " +
html += "<button ng-click=\"editGroup()\" ng-hide=\"groupEditHide\" id=\"inv-group-edit\" class=\"btn btn-mini\" " +
"aw-tool-tip=\"Edit the selected group\" data-placement=\"bottom\">" +
"<i class=\"icon-edit\"></i> Edit Group</button>";
"<i class=\"icon-edit\"></i> Edit</button>";
html += "<button ng-click=\"addGroup()\" ng-hide=\"groupAddHide\" id=\"inv-group-add\" " +
"class=\"btn btn-mini btn-success\" aw-tool-tip=\"Add a new group\" " +
"data-placement=\"bottom\"><i class=\"icon-plus\"></i> Add Group</button>";
"data-placement=\"bottom\"><i class=\"icon-plus\"></i> Add</button>";
html += "<button ng-click=\"deleteGroup()\" ng-hide=\"groupDeleteHide\" id=\"inv-group-delete\" " +
"aw-tool-tip=\"Delete the selected group\" data-placement=\"bottom\" " +
"class=\"btn btn-mini btn-danger\">" +
"<i class=\"icon-trash\"></i> Delete Group</button>";
"<i class=\"icon-trash\"></i> Delete</button>";
html += "</div>\n";
html += "<div id=\"tree-view\"></div>\n";
html += "<div class=\" inventory-filter\">";
@ -880,15 +907,15 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "</div>\n";
}
else {
html += "<div id=\"group-view\" class=\"span7\">\n";
html += "<div id=\"group-view\" class=\"col-lg-7\">\n";
html += "<div id=\"hosts-well\" class=\"well\">\n";
html += "<div id=\"hosts-title\" ng-bind-html-unsafe=\"" + form.related[itm].title + "\"></div>\n";
html += SearchWidget({ iterator: form.related[itm].iterator, template: form.related[itm], mini: true });
html += SearchWidget({ iterator: form.related[itm].iterator, template: form.related[itm], mini: true, size: 'col-lg-6'});
// Add actions(s)
html += "<div class=\"list-actions\">\n";
for (var action in form.related[itm].actions) {
html += "<button class=\"btn btn-mini ";
html += "<button type=\"button\" class=\"btn btn-mini ";
html += (form.related[itm].actions[action]['class']) ? form.related[itm].actions[action]['class'] : "btn-success";
html += "\" ";
html += (form.related[itm]['actions'][action].id) ? this.attr(form.related[itm]['actions'][action],'id') : "";
@ -1041,7 +1068,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<div class=\"list-actions\">\n";
for (var act in form.related[itm].actions) {
var action = form.related[itm].actions[act];
html += "<button class=\"btn btn-small ";
html += "<button type=\"button\" class=\"btn btn-mini ";
html += (form.related[itm].actions[act]['class']) ? form.related[itm].actions[act]['class'] : "btn-success";
html += "\" ";
html += this.attr(action,'ngClick');
@ -1102,7 +1129,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<td class=\"actions\">";
for (act in form.related[itm].fieldActions) {
var action = form.related[itm].fieldActions[act];
html += "<button class=\"btn btn-small";
html += "<button type=\"button\" class=\"btn btn-mini";
html += (action['class']) ? " " + action['class'] : "";
html += "\" " + this.attr(action,'ngClick');
html += (action.awToolTip) ? this.attr(action,'awToolTip') : "";

View File

@ -49,7 +49,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
break;
case 'awPopOver':
// construct the entire help link
result = "<a id=\"awp-" + fld + "\" href=\"\" aw-pop-over=\"" + value + "\" ";
result = "<a id=\"awp-" + fld + "\" href=\"\" aw-pop-over=\'" + value + "\' ";
result += (obj.dataTitle) ? "data-title=\"" + obj['dataTitle'].replace(/[\'\"]/g, '&quot;') + "\" " : "";
result += (obj.dataPlacement) ? "data-placement=\"" + obj['dataPlacement'].replace(/[\'\"]/g, '&quot;') + "\" " : "";
result += (obj.dataContainer) ? "data-container=\"" + obj['dataContainer'].replace(/[\'\"]/g, '&quot;') + "\" " : "";
@ -193,12 +193,14 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
var label = (params.label) ? params.label : null;
var html= '';
html += "<div class=\"search-widget\">\n";
html += "<div class=\"search-widget ";
html += (params.size) ? params.size : "col-lg-4";
html += "\">\n";
html += (label) ? "<label>" + label +"</label>" : "";
html += "<div class=\"input-prepend input-append\">\n";
html += "<div class=\"btn-group\">\n";
html += "<button class=\"btn ";
html += (useMini) ? "btn-mini " : "btn-small";
html += "<div class=\"input-group\">\n";
html += "<div class=\"input-group-btn\">\n";
html += "<button type=\"button\" class=\"btn ";
html += (useMini) ? "btn-mini " : "btn-small ";
html += "dropdown-toggle\" data-toggle=\"dropdown\">\n";
html += "<span ng-bind=\"" + iterator + "SearchFieldLabel\"></span>\n";
html += "<span class=\"caret\"></span>\n";
@ -214,20 +216,20 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
html += "</ul>\n";
html += "</div>\n";
html += "<select ng-show=\"" + iterator + "SelectShow\" ng-model=\""+ iterator + "SearchSelectValue\" ng-change=\"search('" + iterator + "')\" ";
html += "ng-options=\"c.name for c in " + iterator + "SearchSelectOpts\" class=\"search-select";
html += (useMini) ? " field-mini-height" : "";
html += (useMini) ? " input-mini" : " input-small";
html += "\"></select>\n";
html += "<input ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"input-medium";
html += (useMini) ? " field-mini-height" : "";
html += "<input type=\"text\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"form-control ";
html += (useMini) ? " input-mini" : " input-small";
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-change=\"search('" + iterator +
"')\" placeholder=\"Search\" type=\"text\" >\n";
html += "<div class=\"btn-group\">\n";
html += "<button ng-hide=\"" + iterator + "SelectShow || " + iterator + "HideSearchType || " + iterator + "InputHide\" class=\"btn ";
html += (useMini) ? "btn-mini " : "btn-small";
html += "<div class=\"input-group-btn\">\n";
html += "<button type=\"button\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "HideSearchType || " + iterator + "InputHide\" class=\"btn ";
html += (useMini) ? "btn-mini " : "btn-small ";
html += "dropdown-toggle\" data-toggle=\"dropdown\">\n";
html += "<span ng-bind=\"" + iterator + "SearchTypeLabel\"></span>\n";
html += "<span class=\"caret\"></span>\n";

View File

@ -20,7 +20,6 @@ angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'Prompt
name: 'license',
well: false,
forceListeners: true,
'class': 'horizontal-narrow',
fields: {
license_status: {
label: 'Status',

View File

@ -32,7 +32,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
button: function(btn) {
// pass in button object, get back html
var html = '';
html += "<button " + this.attr(btn, 'ngClick') + "class=\"btn";
html += "<button type=\"button\" " + this.attr(btn, 'ngClick') + "class=\"btn";
html += (btn['class']) ? " " + btn['class'] : " btn-small";
html += (btn['awPopOver']) ? " help-link-white" : "";
html += "\" ";
@ -88,7 +88,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
if (options.mode == 'lookup') {
// options should include {hdr: <dialog header>, action: <function...> }
this.scope.lookupHeader = options.hdr;
$('.popover').remove(); //remove any lingering pop-overs
$('.popover').popover('hide'); //remove any lingering pop-overs
$('#lookup-modal').modal({ backdrop: 'static', keyboard: false });
}
@ -107,8 +107,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
//Breadcrumbs
html += "<div class=\"nav-path\">\n";
html += "<ul class=\"breadcrumb\">\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a> " +
"<span class=\"divider\">/</span></li>\n";
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
html += "<li class=\"active\">";
if (options.mode == 'select') {
html += list.selectTitle;
@ -131,7 +130,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
}
if (options.mode == 'lookup' || options.id != undefined) {
html += SearchWidget({ iterator: list.iterator, template: list, mini: true });
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-7' });
}
else {
html += SearchWidget({ iterator: list.iterator, template: list, mini: false });

View File

@ -30,13 +30,13 @@ angular.module('Utilities',[])
.factory('Alert', ['$rootScope', '$location', function($rootScope, $location) {
return function(hdr, msg, cls, action, secondAlert, disableButtons) {
// Pass in the header and message you want displayed on TB modal dialog found in index.html.
// Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-error, alert-success,
// Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success,
// alert-info...). Pass an optional function(){}, if you want a specific action to occur when user
// clicks 'OK' button. Set secondAlert to true, when a second dialog is needed.
if (secondAlert) {
$rootScope.alertHeader2 = hdr;
$rootScope.alertBody2 = msg;
$rootScope.alertClass2 = (cls) ? cls : 'alert-error'; //default alert class is alert-error
$rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
$('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' });
$rootScope.disableButtons2 = (disableButtons) ? true : false;
if (action) {
@ -48,7 +48,7 @@ angular.module('Utilities',[])
else {
$rootScope.alertHeader = hdr;
$rootScope.alertBody = msg;
$rootScope.alertClass = (cls) ? cls : 'alert-error'; //default alert class is alert-error
$rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
$('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' });
$rootScope.disableButtons = (disableButtons) ? true : false;
if (action) {

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,36 +1,34 @@
<div class="row-fluid">
<div class="span12">
<div id="login-modal" class="modal hide">
<div class="modal-header login-header">
<img ng-src="{{ AWXLoginLogo }}" />
</div>
<div class="modal-body">
<div class="login-alert" ng-show="(sessionExpired == false)">Welcome to AnsibleWorks AWX! &nbsp;Please sign in.</div>
<div class="login-alert" ng-show="(sessionExpired == true)">Your session timed out due to inactivity. Please sign in.</div>
<form id="login-form" name="loginForm" class="form-horizontal" autocomplete="off" novalidate >
<div class="control-group">
<label class="control-label">Username:</label>
<div class="controls">
<input type="text" name="login_username" ng-model="login_username" id="login-username" autocomplete="off" required><br />
<span class="error" ng-show="loginForm.login_username.$dirty && loginForm.login_username.$error.required">A value is required!</span>
<span class="error api-error" ng-bind="usernameError"></span>
<div id="login-modal" class="modal hide">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header login-header">
<img ng-src="{{ AWXLoginLogo }}" />
</div>
<div class="modal-body">
<div class="login-alert" ng-show="(sessionExpired == false)">Welcome to AnsibleWorks AWX! &nbsp;Please sign in.</div>
<div class="login-alert" ng-show="(sessionExpired == true)">Your session timed out due to inactivity. Please sign in.</div>
<form id="login-form" name="loginForm" class="form-horizontal" autocomplete="off" novalidate >
<div class="control-group">
<label class="control-label">Username:</label>
<div class="controls">
<input type="text" name="login_username" ng-model="login_username" id="login-username" autocomplete="off" required><br />
<span class="error" ng-show="loginForm.login_username.$dirty && loginForm.login_username.$error.required">A value is required!</span>
<span class="error api-error" ng-bind="usernameError"></span>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">Password:</label>
<div class="controls">
<input type="password" name="login_password" id="login-password" ng-model="login_password" required autocomplete="off"><br />
<span class="error" ng-show="loginForm.login_password.$dirty && loginForm.login_password.$error.required">A value is required!</span>
<span class="error api-error" ng-bind="passwordError"></span>
<div class="control-group">
<label class="control-label">Password:</label>
<div class="controls">
<input type="password" name="login_password" id="login-password" ng-model="login_password" required autocomplete="off"><br />
<span class="error" ng-show="loginForm.login_password.$dirty && loginForm.login_password.$error.required">A value is required!</span>
<span class="error api-error" ng-bind="passwordError"></span>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button ng-click="systemLogin(login_username, login_password)" id="login-button" class="btn btn-primary"><i class="icon-signin"></i> Sign In</button>
</div>
</div><!-- modal -->
</div><!-- span -->
</div><!-- row -->
</form>
</div>
<div class="modal-footer">
<button ng-click="systemLogin(login_username, login_password)" id="login-button" class="btn btn-primary"><i class="icon-signin"></i> Sign In</button>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->

View File

@ -6,13 +6,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/custom-theme/jquery-ui-1.10.3.custom.css" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.min.css" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap-responsive.min.css" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/font-awesome.min.css" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/ansible-ui.css" />
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico" />
<script>
var $staticURL = "{{ STATIC_URL }}";
</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-resource.js"></script>
@ -98,30 +95,31 @@
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#organizations"><img class="logo" src="{{ STATIC_URL }}img/logo.png" /></a>
<ul class="nav pull-right">
<div class="container">
<a class="navbar-brand" href="#organizations"><img class="logo" src="{{ STATIC_URL }}img/logo.png" /></a>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="nav-collapse collapse navbar-responsive-collapse">
<ul class="nav navbar-nav pull-right">
<li ng-show="current_user.username != null && current_user.username != undefined">
<a href="" ng-click="viewCurrentUser()" ng-bind="'Hello! ' + current_user.username"></a></li>
<li ng-show="userLoggedIn == true"><a href="" ng-click="viewLicense()">View License</a></li>
<li ng-show="userLoggedIn == true"><a href="#/logout">Logout</a></li>
</ul>
</div><!-- container -->
</div><!-- navbar-inner -->
</div><!-- nav-collapse -->
</div><!-- container -->
</div><!-- navbar -->
<div class="container-fluid">
<div class="container main-container">
<div class="row-fluid">
<div class="span12">
</div><!-- span12 -->
</div><!-- row -->
<div class="row-fluid">
<div class="span12">
<div class="row">
<div class="col-lg-12">
<ul class="nav nav-tabs">
<li class="active"><a href="#organizations" data-toggle="tab">Organizations</a></li>
<li><a href="#users" data-toggle="tab">Users</a></li>
@ -133,113 +131,184 @@
<li><a href="#jobs" data-toggle="tab">Jobs</a></li>
</ul>
<div class="tab-content" ng-cloak>
<div class="tab-content">
<div ng-view id="main-view"></div>
</div>
</div>
</div>
<!-- login modal -->
<div id="login-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header login-header">
<img src="{{ STATIC_URL }}img/AWX_logo.png" />
</div>
<div class="modal-body">
<div class="login-alert" ng-show="(sessionExpired == false)">Welcome to AnsibleWorks AWX! &nbsp;Please sign in.</div>
<div class="login-alert" ng-show="(sessionExpired == true)">Your session timed out due to inactivity. Please sign in.</div>
<form id="login-form" name="loginForm" class="form-horizontal" autocomplete="off" novalidate >
<div class="form-group">
<label class="control-label col-lg-3">Username</label>
<div class="col-lg-8">
<input type="text" name="login_username" class="form-control" ng-model="login_username"
id="login-username" autocomplete="off" required>
<div class="error" ng-show="loginForm.login_username.$dirty && loginForm.login_username.$error.required">
A value is required!
</div>
<div class="error api-error" ng-bind="usernameError"></div>
</div>
</div>
<div class="form-group">
<label class="control-label col-lg-3">Password</label>
<div class="col-lg-8">
<input type="password" name="login_password" id="login-password" class="form-control"
ng-model="login_password" required autocomplete="off">
<div class="error" ng-show="loginForm.login_password.$dirty && loginForm.login_password.$error.required">
A value is required!
</div>
<div class="error api-error" ng-bind="passwordError"></div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button ng-click="systemLogin(login_username, login_password)" id="login-button" class="btn btn-primary"><i class="icon-signin"></i> Sign In</button>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Password Dialog -->
<div id="password-modal" class="modal hide">
<div class="modal-header">
<button type="button" class="close" ng-click="cancelJob()" aria-hidden="true">&times;</button>
<h3>Password Required</h3>
</div>
<div class="modal-body" id="password-body">
</div>
<div class="modal-footer">
<a href="#" ng-click="cancelJob()" class="btn">Cancel</a>
<a href="" ng-click="startJob()" class="btn btn-primary" ng-disabled="password_form.$pristine || password_form.$invalid">Continue</a>
</div>
</div>
<div id="password-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="cancelJob()" aria-hidden="true">&times;</button>
<h3>Password Required</h3>
</div>
<div class="modal-body" id="password-body">
</div>
<div class="modal-footer">
<a href="#" ng-click="cancelJob()" class="btn btn-default">Cancel</a>
<a href="" ng-click="startJob()" class="btn btn-primary" ng-disabled="password_form.$pristine || password_form.$invalid">Continue</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Lookup dialog. Use for attribute selection -->
<div id="lookup-modal" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-target="#lookup-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="lookupHeader"></h3>
</div>
<div class="modal-body" id="lookup-modal-body"></div>
<div class="modal-footer">
<a href="#" data-target="#lookup-modal" data-dismiss="modal" class="btn">Cancel</a>
<a href="" ng-click="selectAction()" class="btn btn-primary">Select</a>
</div>
</div>
<div id="lookup-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#lookup-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="lookupHeader"></h3>
</div>
<div class="modal-body" id="lookup-modal-body"></div>
<div class="modal-footer">
<a href="#" data-target="#lookup-modal" data-dismiss="modal" class="btn btn-default">Cancel</a>
<a href="" ng-click="selectAction()" class="btn btn-primary">Select</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Generic Form dialog -->
<div id="form-modal" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="formModalHeader"></h3>
</div>
<div class="modal-body" id="form-modal-body"></div>
<div class="modal-footer">
<a href="" ng-show="formModalInfo !== undefined && formModalInfo != ''" ng-click="formModalInfoAction()"
class="btn btn-small pull-left"><i class="icon-zoom-in"></i> <span ng-bind="formModalInfo"></span></a>
<a href="#" ng-show="formModalCancelShow" data-target="#form-modal" data-dismiss="modal" class="btn btn">Cancel</a>
<a href="" ng-bind="formModalActionLabel" ng-click="formModalAction()" class="btn btn-primary"></a>
</div>
</div>
<div id="form-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="formModalHeader"></h3>
</div>
<div class="modal-body" id="form-modal-body"></div>
<div class="modal-footer">
<button ng-show="formModalInfo !== undefined && formModalInfo != ''" ng-click="formModalInfoAction()"
class="btn btn-mini pull-left"><i class="icon-zoom-in"></i> <span ng-bind="formModalInfo"></span></button>
<a href="#" ng-show="formModalCancelShow" data-target="#form-modal" data-dismiss="modal" class="btn btn-default">Cancel</a>
<a href="" ng-bind="formModalActionLabel" ng-click="formModalAction()" class="btn btn-primary"></a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<div id="form-modal2" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="formModal2Header"></h3>
</div>
<div class="modal-body" id="form-modal2-body"></div>
<div class="modal-footer">
<a href="" ng-bind="formModal2Info" ng-show="formModal2Info !== undefined && formModal2Info != ''" ng-click="formModal2InfoAction()"
class="btn btn-small pull-left"><i class="icon-zoom-in"></i> <span ng-bind="formModal2Info"></span></a>
<a href="#" ng-show="formModal2CancelShow" data-target="#form-modal2" data-dismiss="modal" class="btn btn">Cancel</a>
<a href="" ng-bind="formModal2ActionLabel" ng-click="formModal2Action()" class="btn btn-primary"></a>
</div>
</div>
<div id="form-modal2" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="formModal2Header"></h3>
</div>
<div class="modal-body" id="form-modal2-body"></div>
<div class="modal-footer">
<a href="" ng-bind="formModal2Info" ng-show="formModal2Info !== undefined && formModal2Info != ''" ng-click="formModal2InfoAction()"
class="btn btn-small pull-left"><i class="icon-zoom-in"></i> <span ng-bind="formModal2Info"></span></a>
<a href="#" ng-show="formModal2CancelShow" data-target="#form-modal2" data-dismiss="modal" class="btn btn-default">Cancel</a>
<a href="" ng-bind="formModal2ActionLabel" ng-click="formModal2Action()" class="btn btn-primary"></a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Confirmation Dialog -->
<div id="prompt-modal" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-target="#prompt-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="promptHeader" id="prompt-header"></h3>
</div>
<div class="modal-body" ng-bind-html-unsafe="promptBody" id="prompt-body">
</div>
<div class="modal-footer">
<a href="#" data-target="#prompt-modal" data-dismiss="modal" class="btn">No</a>
<a href="" ng-class="promptActionBtnClass" ng-click="promptAction()" id="prompt-action-btn" class="btn">Yes</a>
</div>
</div>
<div id="prompt-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#prompt-modal"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="promptHeader" id="prompt-header"></h3>
</div>
<div class="modal-body" ng-bind-html-unsafe="promptBody" id="prompt-body">
</div>
<div class="modal-footer">
<a href="#" data-target="#prompt-modal" data-dismiss="modal" class="btn btn-default">No</a>
<a href="" ng-class="promptActionBtnClass" ng-click="promptAction()" id="prompt-action-btn" class="btn btn-primary">Yes</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<!-- Alerts/error handling dialogs -->
<div id="alert-modal" class="modal hide">
<div class="modal-header">
<button type="button" class="close" ng-hide="disableButtons" data-target="#alert-modal"
data-dismiss="modal" class="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="alertHeader"></h3>
</div>
<div class="modal-body">
<div class="alert" ng-class="alertClass" ng-bind-html-unsafe="alertBody"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" class="btn">OK</a>
</div>
</div>
<div id="alert-modal2" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal2"
data-dismiss="modal" ng-hide="disableButtons2" aria-hidden="true">&times;</button>
<h3 ng-bind="alertHeader2"></h3>
</div>
<div class="modal-body">
<div class="alert" ng-class="alertClass2" ng-bind-html-unsafe="alertBody2"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" class="btn">OK</a>
</div>
</div>
<div id="alert-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-hide="disableButtons" data-target="#alert-modal"
data-dismiss="modal" class="modal" aria-hidden="true">&times;</button>
<h3 ng-bind="alertHeader"></h3>
</div>
<div class="modal-body">
<div class="alert" ng-class="alertClass" ng-bind-html-unsafe="alertBody"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" class="btn btn-default">OK</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
<div id="alert-modal2" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal2"
data-dismiss="modal" ng-hide="disableButtons2" aria-hidden="true">&times;</button>
<h3 ng-bind="alertHeader2"></h3>
</div>
<div class="modal-body">
<div class="alert" ng-class="alertClass2" ng-bind-html-unsafe="alertBody2"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" class="btn btn-default">OK</a>
</div>
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- modal -->
</div><!-- container -->
@ -270,7 +339,7 @@
<script src="{{ STATIC_URL }}lib/md5/jquery.md5.js"></script>
<script>
$('a[data-toggle="tab"]').on('show', function (e) {
$('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
var url = $(e.target).text();
var regx = new RegExp('/\#\/' + url.toLowerCase().replace(/ /g,'_') + '/');
var loc = window.location.toString();