diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index 299f785724..21404ec788 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -14,9 +14,10 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices, Wait, Stream) { - ClearScope('tree-form'); ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior - //scope. + //scope. + Wait('start'); + var list = CredentialList; var defaultUrl = GetBasePath('credentials'); 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 scope = view.inject(list, { mode: mode }); // Inject our view scope.selected = []; + scope.credentialLoading = true; var url = GetBasePath(base); url += (base == 'users') ? $routeParams.user_id + '/credentials/' : $routeParams.team_id + '/credentials/'; diff --git a/awx/ui/static/js/controllers/Projects.js b/awx/ui/static/js/controllers/Projects.js index ac5e99bc56..e23623d3f7 100644 --- a/awx/ui/static/js/controllers/Projects.js +++ b/awx/ui/static/js/controllers/Projects.js @@ -15,17 +15,20 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, ProjectStatus, FormatDate, Refresh, Wait, Stream, GetChoices) { - ClearScope('tree-form'); ClearScope('htmlTemplate'); + Wait('start'); + var list = ProjectList; var defaultUrl = GetBasePath('projects'); var view = GenerateList; var base = $location.path().replace(/^\//,'').split('/')[0]; var mode = (base == 'projects') ? 'edit' : 'select'; 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; if (mode == 'select') { @@ -179,9 +182,11 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, } if (project.scm_type !== null) { if (project.related.current_update) { + Wait('start'); ProjectStatus({ project_id: id, last_update: project.related.current_update }); } else if (project.related.last_update) { + Wait('start'); ProjectStatus({ project_id: id, last_update: project.related.last_update }); } 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 - scope.search(list.iterator); - + scope.search(list.iterator, null, false, true); } scope.deleteProject = function(id, name) { diff --git a/awx/ui/static/js/forms/Groups.js b/awx/ui/static/js/forms/Groups.js index a24b8f8933..1a9691dee9 100644 --- a/awx/ui/static/js/forms/Groups.js +++ b/awx/ui/static/js/forms/Groups.js @@ -56,7 +56,7 @@ angular.module('GroupFormDefinition', []) "YAML:
\n" + "
---
somevar: somevalue
password: magic
\n" + '

View JSON examples at www.json.org

' + - '

View YAML examples at ansibleworks.com

', + '

View YAML examples at docs.ansible.com

', dataContainer: 'body', tab: 'properties' }, @@ -98,7 +98,7 @@ angular.module('GroupFormDefinition', []) dataTitle: 'Source Regions', dataPlacement: 'right', awPopOver: "

Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " + - "or choose All to include all regions. AWX will only be updated with Hosts associated with the selected regions." + + "or choose All to include all regions. Tower will only be updated with Hosts associated with the selected regions." + "

", dataContainer: 'body', tab: 'source' @@ -123,7 +123,7 @@ angular.module('GroupFormDefinition', []) "YAML:
\n" + "
---
somevar: somevalue
password: magic
\n" + '

View JSON examples at www.json.org

' + - '

View YAML examples at ansibleworks.com

', + '

View YAML examples at docs.ansible.com

', dataContainer: 'body', tab: 'source' }, @@ -137,7 +137,7 @@ angular.module('GroupFormDefinition', []) 'default': { label: 'none', value: 0 }, dataTitle: 'Update Interval', dataPlacement: 'left', - awPopOver: "

Instruct the AWX server to automatically run the inventory update process the selected number of minutes from " + + awPopOver: "

Automatically run the inventory update process the selected number of minutes from " + "the last run.

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.

", dataContainer: 'body' diff --git a/awx/ui/static/js/forms/Hosts.js b/awx/ui/static/js/forms/Hosts.js index 391bd2ab0d..4431c992ed 100644 --- a/awx/ui/static/js/forms/Hosts.js +++ b/awx/ui/static/js/forms/Hosts.js @@ -66,7 +66,7 @@ angular.module('HostFormDefinition', []) "YAML:
\n" + "
---
somevar: somevalue
password: magic
\n" + '

View JSON examples at www.json.org

' + - '

View YAML examples at ansibleworks.com

', + '

View YAML examples at docs.ansible.com

', dataTitle: 'Host Variables', dataPlacement: 'right', dataContainer: '#form-modal .modal-content' diff --git a/awx/ui/static/js/forms/Inventories.js b/awx/ui/static/js/forms/Inventories.js index 11134facba..d30e52b9a6 100644 --- a/awx/ui/static/js/forms/Inventories.js +++ b/awx/ui/static/js/forms/Inventories.js @@ -68,7 +68,7 @@ angular.module('InventoryFormDefinition', []) "YAML:
\n" + "
---
somevar: somevalue
password: magic
\n" + '

View JSON examples at www.json.org

' + - '

View YAML examples at ansibleworks.com

', + '

View YAML examples at docs.ansible.com

', dataTitle: 'Inventory Variables', dataPlacement: 'right', dataContainer: 'body' diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index ef7776334c..274a4a0d13 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -139,7 +139,9 @@ angular.module('JobTemplateFormDefinition', []) editRequired: false, 'class': "input-small", column: 1, - awPopOver: "

The number of parallel or simultaneous processes to use while executing the playbook.

", + awPopOver: '

The number of parallel or simultaneous processes to use while executing the playbook. 0 signifies ' + + 'the default value from the ansible configuration file.

', dataTitle: 'Forks', dataPlacement: 'right', dataContainer: "body" @@ -151,9 +153,8 @@ angular.module('JobTemplateFormDefinition', []) editRequired: false, column: 1, awPopOver: "

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 ; : or ,

For more information and examples see the " + - "Selecting Targets section under Inventory and Patterns " + - " in the Ansible documentation.

", + "Multiple patterns can be separated by ; : or ,

For more information and examples see " + + "the Patters top at docs.ansible.com.

", dataTitle: 'Limit', dataPlacement: 'right', dataContainer: "body" @@ -218,7 +219,7 @@ angular.module('JobTemplateFormDefinition', []) falseValue: 'false', ngChange: "toggleCallback('host_config_key')", column: 2, - awPopOver: "

Create a callback URL a host can use to contact the AWX server and request a configuration update " + + awPopOver: "

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:

\n" + "

http://your.server.com:999/api/v1/job_templates/1/callback/

" + "

The request from the host must be a POST. Here is an example using curl:

\n" + @@ -240,7 +241,7 @@ angular.module('JobTemplateFormDefinition', []) column: 2, required: false, 'class': 'span12', - awPopOver: "

Using this URL a host can contact the AWX server and request a configuration update using the job " + + awPopOver: "

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:

\n" + "

curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "http://your.server.com:999/api/v1/job_templates/1/callback/

\n" + @@ -257,7 +258,7 @@ angular.module('JobTemplateFormDefinition', []) ngShow: "allow_callbacks", genMD5: true, column: 2, - awPopOver: "

When contacting the AWX server using the callback URL, the calling host must authenticate by including " + + awPopOver: "

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:

\n" + "

curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "http://your.server.com:999/api/v1/job_templates/1/callback/

\n", diff --git a/awx/ui/static/js/forms/Jobs.js b/awx/ui/static/js/forms/Jobs.js index b17f5bd402..6b60223d78 100644 --- a/awx/ui/static/js/forms/Jobs.js +++ b/awx/ui/static/js/forms/Jobs.js @@ -233,7 +233,7 @@ angular.module('JobFormDefinition', []) ngChange: "toggleCallback('host_config_key')", "class": "span12", column: 2, - awPopOver: "

Create a callback URL a host can use to contact the AWX server and request a configuration update " + + awPopOver: "

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:

\n" + "

http://your.server.com:999/api/v1/job_templates/1/callback/

" + "

The request from the host must be a POST. Here is an example using curl:

\n" + @@ -255,7 +255,7 @@ angular.module('JobFormDefinition', []) column: 2, required: false, 'class': 'span12', - awPopOver: "

Using this URL a host can contact the AWX server and request a configuration update using the job " + + awPopOver: "

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:

\n" + "

curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "http://your.server.com:999/api/v1/job_templates/1/callback/

\n" + @@ -272,7 +272,7 @@ angular.module('JobFormDefinition', []) ngShow: "allow_callbacks", genMD5: true, column: 2, - awPopOver: "

When contacting the AWX server using the callback URL, the calling host must authenticate by including " + + awPopOver: "

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:

\n" + "

curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " + "http://your.server.com:999/api/v1/job_templates/1/callback/

\n", diff --git a/awx/ui/static/js/forms/ProjectStatus.js b/awx/ui/static/js/forms/ProjectStatus.js index 3d965369bd..8de59fbcc4 100644 --- a/awx/ui/static/js/forms/ProjectStatus.js +++ b/awx/ui/static/js/forms/ProjectStatus.js @@ -30,6 +30,7 @@ angular.module('ProjectStatusDefinition', []) label: 'Std Out', type: 'textarea', ngShow: "result_stdout", + 'class': 'mono-space', readonly: true, rows: 15 }, @@ -37,6 +38,7 @@ angular.module('ProjectStatusDefinition', []) label: 'Traceback', type: 'textarea', ngShow: "result_traceback", + 'class': 'mono-space', readonly: true, rows: 15 } diff --git a/awx/ui/static/js/forms/Projects.js b/awx/ui/static/js/forms/Projects.js index fec21f36c5..3727c46ed6 100644 --- a/awx/ui/static/js/forms/Projects.js +++ b/awx/ui/static/js/forms/Projects.js @@ -76,8 +76,8 @@ angular.module('ProjectFormDefinition', []) ngShow: 'showMissingPlaybooksAlert && !scm_type', alertTxt: '

WARNING: 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 ' + - 'changing the SCM type option rather than specifying checkout paths manually. To continue with manual setup, log into the AWX server 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 ' + + '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 Tower can read the ' + 'playbooks.

' }, base_dir: { @@ -256,4 +256,4 @@ angular.module('ProjectFormDefinition', []) }); // Form - \ No newline at end of file + diff --git a/awx/ui/static/js/helpers/Access.js b/awx/ui/static/js/helpers/Access.js index 74a5a6ce8f..26202a48e9 100644 --- a/awx/ui/static/js/helpers/Access.js +++ b/awx/ui/static/js/helpers/Access.js @@ -48,6 +48,11 @@ angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies']) var status = 'success'; var hdr, msg; var license = $cookieStore.get('license'); + + var purchase_msg = '

To purchase a license or extend an existing license ' + + 'visit the Ansible online store, ' + + 'or visit support.ansible.com for assistance.

'; + if (license && !Authorization.licenseTested()) { // This is our first time evaluating the license license['tested'] = true; @@ -58,47 +63,37 @@ angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies']) // The license is invalid. Stop the user from logging in. status = 'alert-danger'; hdr = 'License Error'; - msg = 'Something is wrong with your /etc/awx/license file on this server. ' + - 'Please contact info@ansibleworks.com for assistance.'; - //action = function() { window.location = '#/logout'; }; + msg = '

There is a problem with the /etc/awx/license file on your Tower server. Check to make sure Tower can access ' + + 'the file.

' + purchase_msg; Alert(hdr, msg, status, null, false, true); } else if (license['demo'] !== undefined && license['demo'] == true) { // demo status = 'alert-info'; - hdr = 'AWX Demo'; - msg = 'Thank you for trying AnsibleWorks AWX. You can use this edition to manage up to 10 hosts free. ' + - 'Should you wish to acquire a license for additional servers, please ' + - 'visit the AnsibleWorks online store, or ' + - 'contact info@ansibleworks.com for assistance.'; + hdr = 'Tower Demo'; + msg = '

Thank you for trying Ansible Tower. You can use this edition to manage up to 10 hosts free.

' + + purchase_msg; Alert(hdr, msg, status); } if (license['date_expired'] !== undefined && license['date_expired'] == true) { // expired status = 'alert-info'; - hdr = 'AWX License Expired'; - msg = 'Your AnsibleWorks AWX License has expired and is no longer compliant. ' + - 'You can continue, but you will be unable to add any additional hosts. Please ' + - 'visit the AnsibleWorks online store ' + - 'for license and renewal information, or contact info@ansibleworks.com ' + - 'for assistance.'; + hdr = 'License Expired'; + msg = '

Your Ansible Tower License has expired and is no longer compliant. You can continue, but you will be ' + + 'unable to add any additional hosts.

' + purchase_msg; Alert(hdr, msg, status); } else if (license['date_warning'] !== undefined && license['date_warning'] == true) { status = 'alert-info'; - hdr = 'AWX License Warning'; - msg = 'Your AnsibleWorks AWX License is about to expire. To extend your license, please ' + - 'visit the AnsibleWorks online store, or ' + - 'contact info@ansibleworks.com for more information.'; + hdr = 'License Warning'; + msg = '

Your Ansible Tower license is about to expire!

' + purchase_msg; Alert(hdr, msg, status); } if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) { status = 'alert-info'; hdr = 'License Warning'; - msg = 'Your AnsibleWorks AWX 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 ' + - 'visit the AnsibleWorks online store, or ' + - 'contact info@ansibleworks.com for more information.'; + msg = '

Your Ansible Tower license has reached capacity for the number of managed ' + + 'hosts allowed. You will not be able to add any additional hosts.

' + purchase_msg; Alert(hdr, msg, status, null, true); } } diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index f62ea7398a..2da171e82a 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -238,6 +238,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' //$('#s2id_group_source_regions').select2('data', []); $('#s2id_group_source_regions').select2('data', [{ id: 'all', text: 'All' }]); } + else var kind = (scope.source.value == 'rax') ? 'rax' : 'aws'; var url = GetBasePath('credentials') + '?cloud=true&kind=' + kind; LookUpInit({ @@ -1102,8 +1103,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' generator.reset(); scope.formModalAction = function() { - console.log('tree_id: ' + tree_id); - console.log('selected_tree_id: ' + parent_scope.selected_tree_id); $('#form-modal').modal("hide"); if (parent_scope && parent_scope.showHosts && !Empty(tree_id)) { if (parent_scope.selected_tree_id !== tree_id) diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index ae89d1e45d..af723d1868 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -51,7 +51,9 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio var form = JobSummary; // Using jquery dialog for its expandable property + var html = "
\n"; + $('#inventory-modal-container').empty().append(html); 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) { // Destroy on close + $('.tooltip').each( function(index) { + // Remove any lingering tooltip
elements + $(this).remove(); + }); + $('.popover').each(function(index) { + // remove lingering popover
elements + $(this).remove(); + }); $('#status-modal-dialog').dialog('destroy'); $('#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']); var cDate = new Date(data.created); scope.created = FormatDate(cDate); - Wait('stop'); $('#status-modal-dialog').dialog('open'); }) .error( function(data, status, headers, config) { diff --git a/awx/ui/static/js/helpers/Projects.js b/awx/ui/static/js/helpers/Projects.js index afcb4562ff..a551ef2f90 100644 --- a/awx/ui/static/js/helpers/Projects.js +++ b/awx/ui/static/js/helpers/Projects.js @@ -12,24 +12,89 @@ angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDefinition', 'ProjectFormDefinition']) .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, - FormatDate, ProjectStatusForm) { + FormatDate, ProjectStatusForm, Wait) { return function(params) { var project_id = params.project_id; var last_update = params.last_update; + var generator = GenerateForm; var form = ProjectStatusForm; - var scope; + + Wait('start'); + + // Using jquery dialog for its expandable property + var html = "
\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
elements + $(this).remove(); + }); + $('.popover').each(function(index) { + // remove lingering popover
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 Rest.setUrl(last_update); Rest.get() .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; for (var fld in form.fields) { if (results[fld]) { @@ -46,18 +111,10 @@ angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDef } } } - scope.formModalAction = function() { - $('#form-modal').modal("hide"); - } - scope.formModalActionLabel = 'OK'; - scope.formModalCancelShow = false; - scope.formModalInfo = false; - scope.formModalHeader = results.summary_fields.project.name + ' - SCM Status'; - $('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none'); - $('#form-modal').addClass('skinny-modal'); - if (!scope.$$phase) { - scope.$digest(); - } + $('#status-modal-dialog') + .dialog({ title: results.summary_fields.project.name + ' Status'}) + .dialog('open'); + }) .error( function(data, status, headers, config) { $('#form-modal').modal("hide"); diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js index a56a2328b8..29a40309d0 100644 --- a/awx/ui/static/js/lists/Jobs.js +++ b/awx/ui/static/js/lists/Jobs.js @@ -84,7 +84,7 @@ angular.module('JobsListDefinition', []) fieldActions: { submit: { - label: 'Launch', + label: 'Relaunch', icon: 'icon-rocket', mode: 'all', ngClick: "submitJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}' )", diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index e87bfcf02c..3817f34686 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -142,19 +142,39 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities']) } } if (options.modal_selector) { - $(options.modal_selector).modal({ show: true, backdrop: 'static', keyboard: true }); - $(options.modal_selector).on('shown.bs.modal', function() { - $(options.modal_select + ' input:first').focus(); - }); - $(options.modal_selector).unbind('hidden.bs.modal'); + $(options.modal_selector).modal({ show: true, backdrop: 'static', keyboard: true }); + $(options.modal_selector).on('shown.bs.modal', function() { + $(options.modal_select + ' input:first').focus(); + }); + $(options.modal_selector).on('hidden.bs.modal', function() { + $('.tooltip').each( function(index) { + // Remove any lingering tooltip and popover
elements + $(this).remove(); + }); + + $('.popover').each(function(index) { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); + }); } else { - var show = (options.show_modal == false) ? false : true; - $('#form-modal').modal({ show: show, backdrop: 'static', keyboard: true }); - $('#form-modal').on('shown.bs.modal', function() { - $('#form-modal input:first').focus(); - }); - $('#form-modal').off('hidden.bs.modal'); + var show = (options.show_modal == false) ? false : true; + $('#form-modal').modal({ show: show, backdrop: 'static', keyboard: true }); + $('#form-modal').on('shown.bs.modal', function() { + $('#form-modal input:first').focus(); + }); + $('#form-modal').on('hidden.bs.modal', function() { + $('.tooltip').each( function(index) { + // Remove any lingering tooltip and popover
elements + $(this).remove(); + }); + + $('.popover').each(function(index) { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); + }); } $(document).bind('keydown', function(e) { if (e.keyCode === 27) { @@ -194,38 +214,51 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities']) if (this.scope[this.form.name + '_form']) { this.scope[this.form.name + '_form'].$setPristine(); } + + var scope = this.scope; + var form = this.form; - for (var fld in this.form.fields) { - if (this.form.fields[fld].type == 'checkbox_group') { - for (var i=0; i < this.form.fields[fld].fields.length; i++) { - this.scope[this.form.fields[fld].fields[i].name] = ''; - this.scope[this.form.fields[fld].fields[i].name + '_api_error'] = ''; - } + function resetField(f, fld) { + // 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 { - this.scope[fld] = ''; - this.scope[fld + '_api_error'] = ''; + scope[fld] = ''; + scope[fld + '_api_error'] = ''; } - if (this.form.fields[fld].sourceModel) { - this.scope[this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] = ''; - this.scope[this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField + '_api_error'] = ''; + if (f.sourceModel) { + scope[f.sourceModel + '_' + f.sourceField] = ''; + scope[f.sourceModel + '_' + f.sourceField + '_api_error'] = ''; } - if ( this.form.fields[fld].type == 'lookup' && - this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] ) { - this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField].$setPristine(); + if (f.type == 'lookup' && scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField]) { + scope[form.name + '_form'][f.sourceModel + '_' + f.sourceField].$setPristine(); } - if (this.scope[this.form.name + '_form'][fld]) { - this.scope[this.form.name + '_form'][fld].$setPristine(); + if (scope[form.name + '_form'][fld]) { + scope[form.name + '_form'][fld].$setPristine(); } - if (this.form.fields[fld].chkPass && this.scope[this.form.name + '_form'][fld]) { - this.scope[this.form.name + '_form'][fld].$setValidity('complexity', true); + if (f.chkPass && scope[form.name + '_form'][fld]) { + scope[form.name + '_form'][fld].$setValidity('complexity', true); $('#progbar').css({ width: 0 }); } - if (this.form.fields[fld].awPassMatch && this.scope[this.form.name + '_form'][fld]) { - this.scope[this.form.name + '_form'][fld].$setValidity('awpassmatch', true); + if (f.awPassMatch && scope[form.name + '_form'][fld]) { + scope[form.name + '_form'][fld].$setValidity('awpassmatch', true); } - if (this.form.fields[fld].ask) { - this.scope[fld + '_ask'] = false; + if (f.ask) { + 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') { diff --git a/awx/ui/static/lib/ansible/license.js b/awx/ui/static/lib/ansible/license.js index b247cf1ffa..cacba6b0ce 100644 --- a/awx/ui/static/lib/ansible/license.js +++ b/awx/ui/static/lib/ansible/license.js @@ -1,7 +1,9 @@ -/***************************************** +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * * 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.formModalCancelShow = false; 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').addClass('skinny-modal'); @@ -127,10 +129,10 @@ angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'Prompt // Respond to license button scope.formModalInfoAction = function() { Prompt({ - hdr: 'AWX Licensing', - body: "

AWX licenses can be purchased or extended by visiting " + - "the AnsibleWorks online store. Would you like to purchase or extend your license now?

", + hdr: 'Tower Licensing', + body: "

Ansible Tower licenses can be purchased or extended by visiting " + + "the Ansible online store. Would you like to purchase or extend your license now?

", 'class': 'btn-primary', action: function() { var href = $('#license-link').attr('href'); diff --git a/awx/ui/static/partials/projects.html b/awx/ui/static/partials/projects.html index 4b57efbd87..a034df92bc 100644 --- a/awx/ui/static/partials/projects.html +++ b/awx/ui/static/partials/projects.html @@ -1,3 +1,4 @@
+
\ No newline at end of file diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 51e5e3cc18..478f1e9c69 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -369,14 +369,14 @@