1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-30 22:21:13 +03:00

AC-966,AC-967,AC-968,AC-973,AC-972: fixed links, titles, texts referencing AWX and ansibleworks. Fixed AC-941 issues also for Credentials and Projects tab. Upgraded projects status to use jquery dialog, allowing user to expand and move.

This commit is contained in:
chris Houseknecht 2014-01-23 16:38:39 -05:00
parent bb6c34f4a4
commit 44d9d12e4d
18 changed files with 220 additions and 112 deletions

View File

@ -14,9 +14,10 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices, Wait, Stream) ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices, Wait, Stream)
{ {
ClearScope('tree-form');
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope. //scope.
Wait('start');
var list = CredentialList; var list = CredentialList;
var defaultUrl = GetBasePath('credentials'); var defaultUrl = GetBasePath('credentials');
var view = GenerateList; var view = GenerateList;
@ -24,6 +25,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
var mode = (base == 'credentials') ? 'edit' : 'select'; // if base path 'credentials', we're here to add/edit var mode = (base == 'credentials') ? 'edit' : 'select'; // if base path 'credentials', we're here to add/edit
var scope = view.inject(list, { mode: mode }); // Inject our view var scope = view.inject(list, { mode: mode }); // Inject our view
scope.selected = []; scope.selected = [];
scope.credentialLoading = true;
var url = GetBasePath(base); var url = GetBasePath(base);
url += (base == 'users') ? $routeParams.user_id + '/credentials/' : $routeParams.team_id + '/credentials/'; url += (base == 'users') ? $routeParams.user_id + '/credentials/' : $routeParams.team_id + '/credentials/';

View File

@ -15,16 +15,19 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, ProjectStatus, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, ProjectStatus,
FormatDate, Refresh, Wait, Stream, GetChoices) FormatDate, Refresh, Wait, Stream, GetChoices)
{ {
ClearScope('tree-form');
ClearScope('htmlTemplate'); ClearScope('htmlTemplate');
Wait('start');
var list = ProjectList; var list = ProjectList;
var defaultUrl = GetBasePath('projects'); var defaultUrl = GetBasePath('projects');
var view = GenerateList; var view = GenerateList;
var base = $location.path().replace(/^\//,'').split('/')[0]; var base = $location.path().replace(/^\//,'').split('/')[0];
var mode = (base == 'projects') ? 'edit' : 'select'; var mode = (base == 'projects') ? 'edit' : 'select';
var scope = view.inject(list, { mode: mode }); var scope = view.inject(list, { mode: mode });
$rootScope.flashMessage = null; $rootScope.flashMessage = null;
scope.projectLoading = true;
var url = (base == 'teams') ? GetBasePath('teams') + $routeParams.team_id + '/projects/' : defaultUrl; var url = (base == 'teams') ? GetBasePath('teams') + $routeParams.team_id + '/projects/' : defaultUrl;
@ -179,9 +182,11 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
} }
if (project.scm_type !== null) { if (project.scm_type !== null) {
if (project.related.current_update) { if (project.related.current_update) {
Wait('start');
ProjectStatus({ project_id: id, last_update: project.related.current_update }); ProjectStatus({ project_id: id, last_update: project.related.current_update });
} }
else if (project.related.last_update) { else if (project.related.last_update) {
Wait('start');
ProjectStatus({ project_id: id, last_update: project.related.last_update }); ProjectStatus({ project_id: id, last_update: project.related.last_update });
} }
else { else {
@ -197,8 +202,7 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
}); });
// Refresh the project list so we're looking at the latest data // Refresh the project list so we're looking at the latest data
scope.search(list.iterator); scope.search(list.iterator, null, false, true);
} }
scope.deleteProject = function(id, name) { scope.deleteProject = function(id, name) {

View File

@ -56,7 +56,7 @@ angular.module('GroupFormDefinition', [])
"YAML:<br />\n" + "YAML:<br />\n" +
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" + "<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' + '<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
'<p>View YAML examples at <a href="http://www.ansibleworks.com/docs/YAMLSyntax.html" target="_blank">ansibleworks.com</a></p>', '<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
dataContainer: 'body', dataContainer: 'body',
tab: 'properties' tab: 'properties'
}, },
@ -98,7 +98,7 @@ angular.module('GroupFormDefinition', [])
dataTitle: 'Source Regions', dataTitle: 'Source Regions',
dataPlacement: 'right', dataPlacement: 'right',
awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " + awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " +
"or choose <em>All</em> to include all regions. AWX will only be updated with Hosts associated with the selected regions." + "or choose <em>All</em> to include all regions. Tower will only be updated with Hosts associated with the selected regions." +
"</p>", "</p>",
dataContainer: 'body', dataContainer: 'body',
tab: 'source' tab: 'source'
@ -123,7 +123,7 @@ angular.module('GroupFormDefinition', [])
"YAML:<br />\n" + "YAML:<br />\n" +
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" + "<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' + '<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
'<p>View YAML examples at <a href="http://www.ansibleworks.com/docs/YAMLSyntax.html" target="_blank">ansibleworks.com</a></p>', '<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
dataContainer: 'body', dataContainer: 'body',
tab: 'source' tab: 'source'
}, },
@ -137,7 +137,7 @@ angular.module('GroupFormDefinition', [])
'default': { label: 'none', value: 0 }, 'default': { label: 'none', value: 0 },
dataTitle: 'Update Interval', dataTitle: 'Update Interval',
dataPlacement: 'left', dataPlacement: 'left',
awPopOver: "<p>Instruct the AWX server to automatically run the inventory update process the selected number of minutes from " + awPopOver: "<p>Automatically run the inventory update process the selected number of minutes from " +
"the last run.</p><p>With a value set, task manager will periodically compare the amount of elapsed time from the last run. If enough time " + "the last run.</p><p>With a value set, task manager will periodically compare the amount of elapsed time from the last run. If enough time " +
"has elapsed, it will go ahead and start an inventory update process.</p>", "has elapsed, it will go ahead and start an inventory update process.</p>",
dataContainer: 'body' dataContainer: 'body'

View File

@ -66,7 +66,7 @@ angular.module('HostFormDefinition', [])
"YAML:<br />\n" + "YAML:<br />\n" +
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" + "<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' + '<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
'<p>View YAML examples at <a href="http://www.ansibleworks.com/docs/YAMLSyntax.html" target="_blank">ansibleworks.com</a></p>', '<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
dataTitle: 'Host Variables', dataTitle: 'Host Variables',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: '#form-modal .modal-content' dataContainer: '#form-modal .modal-content'

View File

@ -68,7 +68,7 @@ angular.module('InventoryFormDefinition', [])
"YAML:<br />\n" + "YAML:<br />\n" +
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" + "<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' + '<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
'<p>View YAML examples at <a href="http://www.ansibleworks.com/docs/YAMLSyntax.html" target="_blank">ansibleworks.com</a></p>', '<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
dataTitle: 'Inventory Variables', dataTitle: 'Inventory Variables',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: 'body' dataContainer: 'body'

View File

@ -139,7 +139,9 @@ angular.module('JobTemplateFormDefinition', [])
editRequired: false, editRequired: false,
'class': "input-small", 'class': "input-small",
column: 1, column: 1,
awPopOver: "<p>The number of parallel or simultaneous processes to use while executing the playbook.</p>", awPopOver: '<p>The number of parallel or simultaneous processes to use while executing the playbook. 0 signifies ' +
'the default value from the <a href=\"http://docs.ansible.com/intro_configuration.html#the-ansible-configuration-file\" ' +
' target=\"_blank\">ansible configuration file</a>.</p>',
dataTitle: 'Forks', dataTitle: 'Forks',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body" dataContainer: "body"
@ -151,9 +153,8 @@ angular.module('JobTemplateFormDefinition', [])
editRequired: false, editRequired: false,
column: 1, column: 1,
awPopOver: "<p>Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. " + awPopOver: "<p>Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. " +
"Multiple patterns can be separated by &#59; &#58; or &#44;</p><p>For more information and examples see the " + "Multiple patterns can be separated by &#59; &#58; or &#44;</p><p>For more information and examples see " +
"<a href=\"http://ansible.cc/docs/patterns.html#selecting-targets\" target=\"_blank\">Selecting Targets section</a> under Inventory and Patterns " + "<a href=\"http://docs.ansible.com/intro_patterns.html\" target=\"_blank\">the Patters top at docs.ansible.com</a>.</p>",
" in the Ansible documentation.</p>",
dataTitle: 'Limit', dataTitle: 'Limit',
dataPlacement: 'right', dataPlacement: 'right',
dataContainer: "body" dataContainer: "body"
@ -218,7 +219,7 @@ angular.module('JobTemplateFormDefinition', [])
falseValue: 'false', falseValue: 'false',
ngChange: "toggleCallback('host_config_key')", ngChange: "toggleCallback('host_config_key')",
column: 2, column: 2,
awPopOver: "<p>Create a callback URL a host can use to contact the AWX server and request a configuration update " + awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
"using the job template. The URL will look like the following:</p>\n" + "using the job template. The URL will look like the following:</p>\n" +
"<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" + "<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" +
"<p>The request from the host must be a POST. Here is an example using curl:</p>\n" + "<p>The request from the host must be a POST. Here is an example using curl:</p>\n" +
@ -240,7 +241,7 @@ angular.module('JobTemplateFormDefinition', [])
column: 2, column: 2,
required: false, required: false,
'class': 'span12', 'class': 'span12',
awPopOver: "<p>Using this URL a host can contact the AWX server and request a configuration update using the job " + awPopOver: "<p>Using this URL a host can contact Tower and request a configuration update using the job " +
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" + "template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" + "http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
@ -257,7 +258,7 @@ angular.module('JobTemplateFormDefinition', [])
ngShow: "allow_callbacks", ngShow: "allow_callbacks",
genMD5: true, genMD5: true,
column: 2, column: 2,
awPopOver: "<p>When contacting the AWX server using the callback URL, the calling host must authenticate by including " + awPopOver: "<p>When contacting the Tower server using the callback URL, the calling host must authenticate by including " +
"this key in the POST data of the request. Here's an example using curl:</p>\n" + "this key in the POST data of the request. Here's an example using curl:</p>\n" +
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n", "http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n",

View File

@ -233,7 +233,7 @@ angular.module('JobFormDefinition', [])
ngChange: "toggleCallback('host_config_key')", ngChange: "toggleCallback('host_config_key')",
"class": "span12", "class": "span12",
column: 2, column: 2,
awPopOver: "<p>Create a callback URL a host can use to contact the AWX server and request a configuration update " + awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
"using the job template. The URL will look like the following:</p>\n" + "using the job template. The URL will look like the following:</p>\n" +
"<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" + "<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" +
"<p>The request from the host must be a POST. Here is an example using curl:</p>\n" + "<p>The request from the host must be a POST. Here is an example using curl:</p>\n" +
@ -255,7 +255,7 @@ angular.module('JobFormDefinition', [])
column: 2, column: 2,
required: false, required: false,
'class': 'span12', 'class': 'span12',
awPopOver: "<p>Using this URL a host can contact the AWX server and request a configuration update using the job " + awPopOver: "<p>Using this URL a host can contact Tower and request a configuration update using the job " +
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" + "template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" + "http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
@ -272,7 +272,7 @@ angular.module('JobFormDefinition', [])
ngShow: "allow_callbacks", ngShow: "allow_callbacks",
genMD5: true, genMD5: true,
column: 2, column: 2,
awPopOver: "<p>When contacting the AWX server using the callback URL, the calling host must authenticate by including " + awPopOver: "<p>When contacting Tower using the callback URL, the calling host must authenticate by including " +
"this key in the POST data of the request. Here's an example using curl:</p>\n" + "this key in the POST data of the request. Here's an example using curl:</p>\n" +
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n", "http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n",

View File

@ -30,6 +30,7 @@ angular.module('ProjectStatusDefinition', [])
label: 'Std Out', label: 'Std Out',
type: 'textarea', type: 'textarea',
ngShow: "result_stdout", ngShow: "result_stdout",
'class': 'mono-space',
readonly: true, readonly: true,
rows: 15 rows: 15
}, },
@ -37,6 +38,7 @@ angular.module('ProjectStatusDefinition', [])
label: 'Traceback', label: 'Traceback',
type: 'textarea', type: 'textarea',
ngShow: "result_traceback", ngShow: "result_traceback",
'class': 'mono-space',
readonly: true, readonly: true,
rows: 15 rows: 15
} }

View File

@ -76,8 +76,8 @@ angular.module('ProjectFormDefinition', [])
ngShow: 'showMissingPlaybooksAlert && !scm_type', ngShow: 'showMissingPlaybooksAlert && !scm_type',
alertTxt: '<p class=\"text-justify\"><strong>WARNING:</strong> There are no unassigned playbook directories in the base project path {{ base_dir }}. Either the projects ' + alertTxt: '<p class=\"text-justify\"><strong>WARNING:</strong> There are no unassigned playbook directories in the base project path {{ base_dir }}. Either the projects ' +
'directory is empty, or all of the contents are already assigned to other projects. New projects can be checked out from source control by ' + 'directory is empty, or all of the contents are already assigned to other projects. New projects can be checked out from source control by ' +
'changing the SCM type option rather than specifying checkout paths manually. To continue with manual setup, log into the AWX server and ' + 'changing the SCM type option rather than specifying checkout paths manually. To continue with manual setup, log into the Tower host and ' +
'ensure content is present in a subdirectory under {{ base_dir }}. Run "chown -R awx" on the content directory to ensure awx can read the ' + 'ensure content is present in a subdirectory under {{ base_dir }}. Run "chown -R awx" on the content directory to ensure Tower can read the ' +
'playbooks.</p>' 'playbooks.</p>'
}, },
base_dir: { base_dir: {

View File

@ -48,6 +48,11 @@ angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies'])
var status = 'success'; var status = 'success';
var hdr, msg; var hdr, msg;
var license = $cookieStore.get('license'); var license = $cookieStore.get('license');
var purchase_msg = '<p>To purchase a license or extend an existing license ' +
'<a href="http://store.ansibleworks.com" target="_blank"><strong>visit the Ansible online store</strong></a>, ' +
'or visit <a href="https://support.ansible.com/anonymous_requests/new">support.ansible.com</a> for assistance.</p>';
if (license && !Authorization.licenseTested()) { if (license && !Authorization.licenseTested()) {
// This is our first time evaluating the license // This is our first time evaluating the license
license['tested'] = true; license['tested'] = true;
@ -58,47 +63,37 @@ angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies'])
// The license is invalid. Stop the user from logging in. // The license is invalid. Stop the user from logging in.
status = 'alert-danger'; status = 'alert-danger';
hdr = 'License Error'; hdr = 'License Error';
msg = 'Something is wrong with your /etc/awx/license file on this server. ' + msg = '<p>There is a problem with the /etc/awx/license file on your Tower server. Check to make sure Tower can access ' +
'Please contact <a href="mailto:info@ansibleworks.com">info@ansibleworks.com</a> for assistance.'; 'the file.<p>' + purchase_msg;
//action = function() { window.location = '#/logout'; };
Alert(hdr, msg, status, null, false, true); Alert(hdr, msg, status, null, false, true);
} }
else if (license['demo'] !== undefined && license['demo'] == true) { else if (license['demo'] !== undefined && license['demo'] == true) {
// demo // demo
status = 'alert-info'; status = 'alert-info';
hdr = 'AWX Demo'; hdr = 'Tower Demo';
msg = 'Thank you for trying AnsibleWorks AWX. You can use this edition to manage up to 10 hosts free. ' + msg = '<p>Thank you for trying Ansible Tower. You can use this edition to manage up to 10 hosts free.<p>' +
'Should you wish to acquire a license for additional servers, please ' + purchase_msg;
'<a href="http://store.ansibleworks.com" target="_blank"><strong>visit the AnsibleWorks online store</strong></a>, or ' +
'contact <a href="mailto:info@ansibleworks.com"><strong>info@ansibleworks.com</strong></a> for assistance.';
Alert(hdr, msg, status); Alert(hdr, msg, status);
} }
if (license['date_expired'] !== undefined && license['date_expired'] == true) { if (license['date_expired'] !== undefined && license['date_expired'] == true) {
// expired // expired
status = 'alert-info'; status = 'alert-info';
hdr = 'AWX License Expired'; hdr = 'License Expired';
msg = 'Your AnsibleWorks AWX License has expired and is no longer compliant. ' + msg = '<p>Your Ansible Tower License has expired and is no longer compliant. You can continue, but you will be ' +
'You can continue, but you will be unable to add any additional hosts. Please ' + 'unable to add any additional hosts.<p>' + purchase_msg;
'<a href="http://store.ansibleworks.com" target="_blank"><strong>visit the AnsibleWorks online store</strong></a> ' +
'for license and renewal information, or contact <a href="mailto:info@ansibleworks.com"><strong>info@ansibleworks.com</strong></a> ' +
'for assistance.';
Alert(hdr, msg, status); Alert(hdr, msg, status);
} }
else if (license['date_warning'] !== undefined && license['date_warning'] == true) { else if (license['date_warning'] !== undefined && license['date_warning'] == true) {
status = 'alert-info'; status = 'alert-info';
hdr = 'AWX License Warning'; hdr = 'License Warning';
msg = 'Your AnsibleWorks AWX License is about to expire. To extend your license, please ' + msg = '<p>Your Ansible Tower license is about to expire!</p>' + purchase_msg;
'<a href="http://store.ansibleworks.com" target="_blank"><strong>visit the AnsibleWorks online store</strong></a>, or ' +
'contact <a href="mailto:info@ansibleworks.com"><strong>info@ansibleworks.com</strong></a> for more information.';
Alert(hdr, msg, status); Alert(hdr, msg, status);
} }
if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) { if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) {
status = 'alert-info'; status = 'alert-info';
hdr = 'License Warning'; hdr = 'License Warning';
msg = 'Your AnsibleWorks AWX License has reached capacity for the number of managed ' + msg = '<p>Your Ansible Tower license has reached capacity for the number of managed ' +
'hosts allowed. You will not be able to add any additional hosts. To extend your license, please ' + 'hosts allowed. You will not be able to add any additional hosts.</p>' + purchase_msg;
'<a href="http://store.ansibleworks.com" target="_blank"><strong>visit the AnsibleWorks online store</strong></a>, or ' +
'contact <a href="mailto:info@ansibleworks.com"><strong>info@ansibleworks.com</strong></a> for more information.';
Alert(hdr, msg, status, null, true); Alert(hdr, msg, status, null, true);
} }
} }

View File

@ -238,6 +238,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
//$('#s2id_group_source_regions').select2('data', []); //$('#s2id_group_source_regions').select2('data', []);
$('#s2id_group_source_regions').select2('data', [{ id: 'all', text: 'All' }]); $('#s2id_group_source_regions').select2('data', [{ id: 'all', text: 'All' }]);
} }
else
var kind = (scope.source.value == 'rax') ? 'rax' : 'aws'; var kind = (scope.source.value == 'rax') ? 'rax' : 'aws';
var url = GetBasePath('credentials') + '?cloud=true&kind=' + kind; var url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
LookUpInit({ LookUpInit({
@ -1102,8 +1103,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
generator.reset(); generator.reset();
scope.formModalAction = function() { scope.formModalAction = function() {
console.log('tree_id: ' + tree_id);
console.log('selected_tree_id: ' + parent_scope.selected_tree_id);
$('#form-modal').modal("hide"); $('#form-modal').modal("hide");
if (parent_scope && parent_scope.showHosts && !Empty(tree_id)) { if (parent_scope && parent_scope.showHosts && !Empty(tree_id)) {
if (parent_scope.selected_tree_id !== tree_id) if (parent_scope.selected_tree_id !== tree_id)

View File

@ -51,7 +51,9 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
var form = JobSummary; var form = JobSummary;
// Using jquery dialog for its expandable property // Using jquery dialog for its expandable property
var html = "<div id=\"status-modal-dialog\" title=\"Job " + job_id + "\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n"; var html = "<div id=\"status-modal-dialog\" title=\"Job " + job_id + "\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n";
$('#inventory-modal-container').empty().append(html); $('#inventory-modal-container').empty().append(html);
var scope = generator.inject(form, { mode: 'edit', id: 'form-container', breadCrumbs: false, related: false }); var scope = generator.inject(form, { mode: 'edit', id: 'form-container', breadCrumbs: false, related: false });
@ -97,8 +99,19 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
}, },
close: function(e, ui) { close: function(e, ui) {
// Destroy on close // Destroy on close
$('.tooltip').each( function(index) {
// Remove any lingering tooltip <div> elements
$(this).remove();
});
$('.popover').each(function(index) {
// remove lingering popover <div> elements
$(this).remove();
});
$('#status-modal-dialog').dialog('destroy'); $('#status-modal-dialog').dialog('destroy');
$('#inventory-modal-container').empty(); $('#inventory-modal-container').empty();
},
open: function(e, ui) {
Wait('stop');
} }
}); });
@ -122,7 +135,6 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
scope['traceback_rows'] = calcRows(scope['result_traceback']); scope['traceback_rows'] = calcRows(scope['result_traceback']);
var cDate = new Date(data.created); var cDate = new Date(data.created);
scope.created = FormatDate(cDate); scope.created = FormatDate(cDate);
Wait('stop');
$('#status-modal-dialog').dialog('open'); $('#status-modal-dialog').dialog('open');
}) })
.error( function(data, status, headers, config) { .error( function(data, status, headers, config) {

View File

@ -12,24 +12,89 @@
angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDefinition', 'ProjectFormDefinition']) angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDefinition', 'ProjectFormDefinition'])
.factory('ProjectStatus', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm', .factory('ProjectStatus', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm',
'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'ProjectStatusForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'ProjectStatusForm', 'Wait',
function($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath, function($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath,
FormatDate, ProjectStatusForm) { FormatDate, ProjectStatusForm, Wait) {
return function(params) { return function(params) {
var project_id = params.project_id; var project_id = params.project_id;
var last_update = params.last_update; var last_update = params.last_update;
var generator = GenerateForm; var generator = GenerateForm;
var form = ProjectStatusForm; var form = ProjectStatusForm;
var scope;
Wait('start');
// Using jquery dialog for its expandable property
var html = "<div id=\"status-modal-dialog\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n";
$('#projects-modal-container').empty().append(html);
var scope = generator.inject(form, { mode: 'edit', id: 'form-container', related: false, breadCrumbs: false });
generator.reset();
// Set modal dimensions based on viewport width
var ww = $(document).width();
var wh = $('body').height();
var x, y, maxrows;
if (ww > 1199) {
// desktop
x = 675;
y = (750 > wh) ? wh - 20 : 750;
maxrows = 20;
}
else if (ww <= 1199 && ww >= 768) {
x = 550;
y = (620 > wh) ? wh - 15 : 620;
maxrows = 15;
}
else {
x = (ww - 20);
y = (500 > wh) ? wh : 500;
maxrows = 10;
}
// Create the modal
$('#status-modal-dialog').dialog({
buttons: { "OK": function() { $( this ).dialog( "close" ); } },
modal: true,
width: x,
height: y,
autoOpen: false,
create: function (e, ui) {
// fix the close button
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({ 'class': 'close' }).text('x');
// fix the OK button
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
.attr({ 'class': 'btn btn-primary' });
},
resizeStop: function(e, ui) {
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]');
var content = dialog.find('#status-modal-dialog');
content.width( dialog.width() - 28 );
},
close: function(e, ui) {
// Destroy on close
// Destroy on close
$('.tooltip').each( function(index) {
// Remove any lingering tooltip <div> elements
$(this).remove();
});
$('.popover').each(function(index) {
// remove lingering popover <div> elements
$(this).remove();
});
$('#status-modal-dialog').dialog('destroy');
$('#projects-modal-container').empty();
},
open: function(e, ui) {
Wait('stop');
}
});
// Retrieve detail record and prepopulate the form // Retrieve detail record and prepopulate the form
Rest.setUrl(last_update); Rest.setUrl(last_update);
Rest.get() Rest.get()
.success( function(data, status, headers, config) { .success( function(data, status, headers, config) {
// load up the form
scope = generator.inject(form, { mode: 'edit', modal: true, related: false});
generator.reset();
var results = data; var results = data;
for (var fld in form.fields) { for (var fld in form.fields) {
if (results[fld]) { if (results[fld]) {
@ -46,18 +111,10 @@ angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDef
} }
} }
} }
scope.formModalAction = function() { $('#status-modal-dialog')
$('#form-modal').modal("hide"); .dialog({ title: results.summary_fields.project.name + ' Status'})
} .dialog('open');
scope.formModalActionLabel = 'OK';
scope.formModalCancelShow = false;
scope.formModalInfo = false;
scope.formModalHeader = results.summary_fields.project.name + '<span class="subtitle"> - SCM Status</span>';
$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
$('#form-modal').addClass('skinny-modal');
if (!scope.$$phase) {
scope.$digest();
}
}) })
.error( function(data, status, headers, config) { .error( function(data, status, headers, config) {
$('#form-modal').modal("hide"); $('#form-modal').modal("hide");

View File

@ -84,7 +84,7 @@ angular.module('JobsListDefinition', [])
fieldActions: { fieldActions: {
submit: { submit: {
label: 'Launch', label: 'Relaunch',
icon: 'icon-rocket', icon: 'icon-rocket',
mode: 'all', mode: 'all',
ngClick: "submitJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}' )", ngClick: "submitJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}' )",

View File

@ -142,19 +142,39 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
} }
} }
if (options.modal_selector) { if (options.modal_selector) {
$(options.modal_selector).modal({ show: true, backdrop: 'static', keyboard: true }); $(options.modal_selector).modal({ show: true, backdrop: 'static', keyboard: true });
$(options.modal_selector).on('shown.bs.modal', function() { $(options.modal_selector).on('shown.bs.modal', function() {
$(options.modal_select + ' input:first').focus(); $(options.modal_select + ' input:first').focus();
}); });
$(options.modal_selector).unbind('hidden.bs.modal'); $(options.modal_selector).on('hidden.bs.modal', function() {
$('.tooltip').each( function(index) {
// Remove any lingering tooltip and popover <div> elements
$(this).remove();
});
$('.popover').each(function(index) {
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
$(this).remove();
});
});
} }
else { else {
var show = (options.show_modal == false) ? false : true; var show = (options.show_modal == false) ? false : true;
$('#form-modal').modal({ show: show, backdrop: 'static', keyboard: true }); $('#form-modal').modal({ show: show, backdrop: 'static', keyboard: true });
$('#form-modal').on('shown.bs.modal', function() { $('#form-modal').on('shown.bs.modal', function() {
$('#form-modal input:first').focus(); $('#form-modal input:first').focus();
}); });
$('#form-modal').off('hidden.bs.modal'); $('#form-modal').on('hidden.bs.modal', function() {
$('.tooltip').each( function(index) {
// Remove any lingering tooltip and popover <div> elements
$(this).remove();
});
$('.popover').each(function(index) {
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
$(this).remove();
});
});
} }
$(document).bind('keydown', function(e) { $(document).bind('keydown', function(e) {
if (e.keyCode === 27) { if (e.keyCode === 27) {
@ -195,37 +215,50 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
this.scope[this.form.name + '_form'].$setPristine(); this.scope[this.form.name + '_form'].$setPristine();
} }
for (var fld in this.form.fields) { var scope = this.scope;
if (this.form.fields[fld].type == 'checkbox_group') { var form = this.form;
for (var i=0; i < this.form.fields[fld].fields.length; i++) {
this.scope[this.form.fields[fld].fields[i].name] = ''; function resetField(f, fld) {
this.scope[this.form.fields[fld].fields[i].name + '_api_error'] = ''; // f is the field object, fld is the key
}
if (f.type == 'checkbox_group') {
for (var i=0; i < f.fields.length; i++) {
scope[f.name] = '';
scope[f.name + '_api_error'] = '';
}
} }
else { else {
this.scope[fld] = ''; scope[fld] = '';
this.scope[fld + '_api_error'] = ''; scope[fld + '_api_error'] = '';
} }
if (this.form.fields[fld].sourceModel) { if (f.sourceModel) {
this.scope[this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] = ''; scope[f.sourceModel + '_' + f.sourceField] = '';
this.scope[this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField + '_api_error'] = ''; scope[f.sourceModel + '_' + f.sourceField + '_api_error'] = '';
} }
if ( this.form.fields[fld].type == 'lookup' && if (f.type == 'lookup' && scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField]) {
this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] ) { scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setPristine();
this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField].$setPristine();
} }
if (this.scope[this.form.name + '_form'][fld]) { if (scope[form.name + '_form'][fld]) {
this.scope[this.form.name + '_form'][fld].$setPristine(); scope[form.name + '_form'][fld].$setPristine();
} }
if (this.form.fields[fld].chkPass && this.scope[this.form.name + '_form'][fld]) { if (f.chkPass && scope[form.name + '_form'][fld]) {
this.scope[this.form.name + '_form'][fld].$setValidity('complexity', true); scope[form.name + '_form'][fld].$setValidity('complexity', true);
$('#progbar').css({ width: 0 }); $('#progbar').css({ width: 0 });
} }
if (this.form.fields[fld].awPassMatch && this.scope[this.form.name + '_form'][fld]) { if (f.awPassMatch && scope[form.name + '_form'][fld]) {
this.scope[this.form.name + '_form'][fld].$setValidity('awpassmatch', true); scope[form.name + '_form'][fld].$setValidity('awpassmatch', true);
} }
if (this.form.fields[fld].ask) { if (f.ask) {
this.scope[fld + '_ask'] = false; scope[fld + '_ask'] = false;
}
}
for (var fld in form.fields) {
resetField(form.fields[fld], fld);
}
if (form.statusFields) {
for (var fld in form.statusFields) {
resetField(form.statusFields[fld], fld);
} }
} }
if (this.mode == 'add') { if (this.mode == 'add') {

View File

@ -1,7 +1,9 @@
/***************************************** /*********************************************
* Copyright (c) 2014 AnsibleWorks, Inc.
*
* License.js * License.js
* *
* View license info: /api/vi/config/ * View license info found in /api/vi/config/
* *
*****************************************/ *****************************************/
@ -118,7 +120,7 @@ angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'Prompt
scope.formModalActionLabel = 'OK'; scope.formModalActionLabel = 'OK';
scope.formModalCancelShow = false; scope.formModalCancelShow = false;
scope.formModalInfo = 'Purchase/Extend License'; scope.formModalInfo = 'Purchase/Extend License';
scope.formModalHeader = 'AWX License'; scope.formModalHeader = 'Tower License';
//$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none'); //$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
//$('#form-modal').addClass('skinny-modal'); //$('#form-modal').addClass('skinny-modal');
@ -127,10 +129,10 @@ angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'Prompt
// Respond to license button // Respond to license button
scope.formModalInfoAction = function() { scope.formModalInfoAction = function() {
Prompt({ Prompt({
hdr: 'AWX Licensing', hdr: 'Tower Licensing',
body: "<p>AWX licenses can be purchased or extended by visiting <a id=\"license-link\" " + body: "<p>Ansible Tower licenses can be purchased or extended by visiting <a id=\"license-link\" " +
"href=\"http://store.ansibleworks.com\" target=\"_blank\">" + "href=\"http://store.ansible.com\" target=\"_blank\">" +
"the AnsibleWorks online store</a>. Would you like to purchase or extend your license now?</p>", "the Ansible online store</a>. Would you like to purchase or extend your license now?</p>",
'class': 'btn-primary', 'class': 'btn-primary',
action: function() { action: function() {
var href = $('#license-link').attr('href'); var href = $('#license-link').attr('href');

View File

@ -1,3 +1,4 @@
<div class="tab-pane" id="projects"> <div class="tab-pane" id="projects">
<div ng-cloak id="htmlTemplate"></div> <div ng-cloak id="htmlTemplate"></div>
<div id="projects-modal-container"></div>
</div> </div>

View File

@ -369,14 +369,14 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-3 text-left help"> <div class="col-lg-3 text-left help">
<a href="https://ansibleworks.zendesk.com/anonymous_requests/new" target="_blank"><i class="fa fa-question-circle"></i> Contact Support</a> <a href="https://support.ansible.com/anonymous_requests/new" target="_blank"><i class="fa fa-question-circle"></i> Contact Support</a>
</div> </div>
<div class="col-lg-6 text-center copyright"> <div class="col-lg-6 text-center copyright">
<a href="http://www.ansibleworks.com">Copyright &copy; 2014 AnsibleWorks, Inc. All rights reserved.</a> <a href="http://www.ansible.com">Copyright &copy; 2014 AnsibleWorks, Inc. All rights reserved.</a>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<div class="logo"> <div class="logo">
<a href="http://www.ansibleworks.com" target="_blank"><img src="{{ STATIC_URL }}img/tower_console_bug.png" /></a> <a href="http://www.ansible.com" target="_blank"><img src="{{ STATIC_URL }}img/tower_console_bug.png" /></a>
</div> </div>
</div> </div>
</div> </div>