diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index d59fcb639d..8fde480b73 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -15,6 +15,7 @@ aim_inputs = { 'id': 'url', 'label': _('CyberArk AIM URL'), 'type': 'string', + 'format': 'url', }, { 'id': 'app_id', 'label': _('Application ID'), diff --git a/awx/main/credential_plugins/azure_kv.py b/awx/main/credential_plugins/azure_kv.py index ee193974d0..77b7394b1f 100644 --- a/awx/main/credential_plugins/azure_kv.py +++ b/awx/main/credential_plugins/azure_kv.py @@ -10,6 +10,7 @@ azure_keyvault_inputs = { 'id': 'url', 'label': _('Vault URL (DNS Name)'), 'type': 'string', + 'format': 'url', }, { 'id': 'client', 'label': _('Client ID'), diff --git a/awx/main/credential_plugins/conjur.py b/awx/main/credential_plugins/conjur.py index e7bcf9c859..c2a60f72b6 100644 --- a/awx/main/credential_plugins/conjur.py +++ b/awx/main/credential_plugins/conjur.py @@ -16,6 +16,7 @@ conjur_inputs = { 'id': 'url', 'label': _('Conjur URL'), 'type': 'string', + 'format': 'url', }, { 'id': 'api_key', 'label': _('API Key'), diff --git a/awx/main/credential_plugins/hashivault.py b/awx/main/credential_plugins/hashivault.py index fefa46cbae..f82af720cf 100644 --- a/awx/main/credential_plugins/hashivault.py +++ b/awx/main/credential_plugins/hashivault.py @@ -14,6 +14,7 @@ base_inputs = { 'id': 'url', 'label': _('Server URL'), 'type': 'string', + 'format': 'url', 'help_text': _('The URL to the HashiCorp Vault'), }, { 'id': 'token', diff --git a/awx/main/fields.py b/awx/main/fields.py index f322691183..bc524b01c6 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -493,6 +493,23 @@ def format_ssh_private_key(value): return True +@JSONSchemaField.format_checker.checks('url') +def format_url(value): + try: + parsed = urllib.parse.urlparse(value) + except Exception as e: + raise jsonschema.exceptions.FormatError(str(e)) + if parsed.scheme == '': + raise jsonschema.exceptions.FormatError( + 'Invalid URL: Missing url scheme (http, https, etc.)' + ) + if parsed.netloc == '': + raise jsonschema.exceptions.FormatError( + 'Invalid URL: {}'.format(value) + ) + return True + + class DynamicCredentialInputField(JSONSchemaField): """ Used to validate JSON for @@ -725,7 +742,7 @@ class CredentialTypeInputField(JSONSchemaField): 'type': 'object', 'properties': { 'type': {'enum': ['string', 'boolean']}, - 'format': {'enum': ['ssh_private_key']}, + 'format': {'enum': ['ssh_private_key', 'url']}, 'choices': { 'type': 'array', 'minItems': 1, diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 52d176e146..f7e452cc99 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1042,7 +1042,7 @@ class BaseTask(object): AWX only saves the parent_uuid if the event is for a Job. ''' if event_data.get(self.event_data_key, None): - if event_data[self.event_data_key] != 'job_id': + if self.event_data_key != 'job_id': event_data.pop('parent_uuid', None) should_write_event = False event_data.setdefault(self.event_data_key, self.instance.id) diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index 2cb287b044..879a3e4de6 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -1942,3 +1942,39 @@ def test_create_credential_missing_user_team_org_xfail(post, admin, credentialty admin ) assert response.status_code == 400 + + +@pytest.mark.parametrize('url, status, msg', [ + ('foo.com', 400, 'Invalid URL: Missing url scheme (http, https, etc.)'), + ('https://[dead:beef', 400, 'Invalid IPv6 URL'), + ('http:domain:8080', 400, 'Invalid URL: http:domain:8080'), + ('http:/domain:8080', 400, 'Invalid URL: http:/domain:8080'), + ('http://foo.com', 201, None) +]) +@pytest.mark.django_db +def test_create_credential_with_invalid_url_xfail(post, organization, admin, url, status, msg): + credential_type = CredentialType( + kind='test', + name='MyTestCredentialType', + inputs = { + 'fields': [{ + 'id': 'server_url', + 'label': 'Server Url', + 'type': 'string', + 'format': 'url' + }] + } + ) + credential_type.save() + + params = { + 'name': 'Second Best Credential Ever', + 'organization': organization.pk, + 'credential_type': credential_type.pk, + 'inputs': {'server_url': url} + } + endpoint = reverse('api:credential_list', kwargs={'version': 'v2'}) + response = post(endpoint, params, admin) + assert response.status_code == status + if status != 201: + assert response.data['inputs']['server_url'] == [msg] diff --git a/awx/ui/client/features/applications/applications.strings.js b/awx/ui/client/features/applications/applications.strings.js index 4c907acbfc..f6fb73f56a 100644 --- a/awx/ui/client/features/applications/applications.strings.js +++ b/awx/ui/client/features/applications/applications.strings.js @@ -38,13 +38,6 @@ function ApplicationsStrings (BaseString) { ns.inputs = { ORGANIZATION_PLACEHOLDER: t.s('SELECT AN ORGANIZATION') }; - - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)'), - USERNAME_ASCENDING: t.s('Username (Ascending)'), - USERNAME_DESCENDING: t.s('Username (Descending)') - }; } ApplicationsStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/features/applications/list-applications-users.controller.js b/awx/ui/client/features/applications/list-applications-users.controller.js index 83b33b8251..bb7dc70edd 100644 --- a/awx/ui/client/features/applications/list-applications-users.controller.js +++ b/awx/ui/client/features/applications/list-applications-users.controller.js @@ -41,10 +41,13 @@ function ListApplicationsUsersController ( vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.USERNAME_DESCENDING')}`, - value: '-user__username' - } + { label: `${strings.get('sort.USERNAME_DESCENDING')}`, value: '-user__username' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.EXPIRES_ASCENDING')}`, value: 'expires' }, + { label: `${strings.get('sort.EXPIRES_DESCENDING')}`, value: '-expires' } ]; function setToolbarSort () { diff --git a/awx/ui/client/features/applications/list-applications.controller.js b/awx/ui/client/features/applications/list-applications.controller.js index df824ac52f..254b31930b 100644 --- a/awx/ui/client/features/applications/list-applications.controller.js +++ b/awx/ui/client/features/applications/list-applications.controller.js @@ -54,7 +54,9 @@ function ListApplicationsController ( vm.toolbarSortOptions = [ toolbarSortDefault, - { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' } ]; vm.toolbarSortValue = toolbarSortDefault; diff --git a/awx/ui/client/features/credentials/external-test-modal.component.js b/awx/ui/client/features/credentials/external-test-modal.component.js index 8600cc45f1..7b8ac82685 100644 --- a/awx/ui/client/features/credentials/external-test-modal.component.js +++ b/awx/ui/client/features/credentials/external-test-modal.component.js @@ -5,6 +5,10 @@ function ExternalTestModalController (strings) { vm.strings = strings; vm.title = strings.get('externalTest.TITLE'); + + vm.$onInit = () => { + vm.form.save = () => vm.onSubmit(); + }; } ExternalTestModalController.$inject = [ diff --git a/awx/ui/client/features/credentials/input-source-lookup.component.js b/awx/ui/client/features/credentials/input-source-lookup.component.js index 6d6d8841de..b76baf043b 100644 --- a/awx/ui/client/features/credentials/input-source-lookup.component.js +++ b/awx/ui/client/features/credentials/input-source-lookup.component.js @@ -6,7 +6,10 @@ function InputSourceLookupController (strings, wait) { vm.strings = strings; vm.title = strings.get('inputSources.TITLE'); - vm.$onInit = () => wait('start'); + vm.$onInit = () => { + wait('start'); + vm.form.save = () => vm.onTest(); + }; vm.onReady = () => { vm.isReady = true; diff --git a/awx/ui/client/features/jobs/jobs.strings.js b/awx/ui/client/features/jobs/jobs.strings.js index 6bc6225760..a5b69df13f 100644 --- a/awx/ui/client/features/jobs/jobs.strings.js +++ b/awx/ui/client/features/jobs/jobs.strings.js @@ -4,13 +4,6 @@ function JobsStrings (BaseString) { const { t } = this; const ns = this.jobs; - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)'), - START_TIME: t.s('Start Time'), - FINISH_TIME: t.s('Finish Time') - }; - ns.list = { PANEL_TITLE: t.s('JOBS'), ROW_ITEM_LABEL_STARTED: t.s('Started'), diff --git a/awx/ui/client/features/jobs/jobsList.controller.js b/awx/ui/client/features/jobs/jobsList.controller.js index 48bedb049e..3881a4071c 100644 --- a/awx/ui/client/features/jobs/jobsList.controller.js +++ b/awx/ui/client/features/jobs/jobsList.controller.js @@ -46,7 +46,7 @@ function ListJobsController ( }, true); const toolbarSortDefault = { - label: `${strings.get('sort.FINISH_TIME')}`, + label: `${strings.get('sort.FINISH_TIME_DESCENDING')}`, value: '-finished' }; @@ -63,7 +63,13 @@ function ListJobsController ( vm.toolbarSortOptions = [ { label: `${strings.get('sort.NAME_ASCENDING')}`, value: 'name' }, { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' }, - { label: `${strings.get('sort.START_TIME')}`, value: 'finished' }, + { label: `${strings.get('sort.FINISH_TIME_ASCENDING')}`, value: 'finished' }, + { label: `${strings.get('sort.START_TIME_ASCENDING')}`, value: 'started' }, + { label: `${strings.get('sort.START_TIME_DESCENDING')}`, value: '-started' }, + { label: `${strings.get('sort.LAUNCHED_BY_ASCENDING')}`, value: 'created_by__id' }, + { label: `${strings.get('sort.LAUNCHED_BY_DESCENDING')}`, value: '-created_by__id' }, + { label: `${strings.get('sort.PROJECT_ASCENDING')}`, value: 'unified_job_template__project__id' }, + { label: `${strings.get('sort.PROJECT_DESCENDING')}`, value: '-unified_job_template__project__id' }, toolbarSortDefault ]; diff --git a/awx/ui/client/features/output/_index.less b/awx/ui/client/features/output/_index.less index 8d5ac05b31..a4bef87569 100644 --- a/awx/ui/client/features/output/_index.less +++ b/awx/ui/client/features/output/_index.less @@ -79,6 +79,10 @@ &:hover div { background-color: white; } + + &--hidden { + display: none; + } } &-row--clickable { diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js index 2f4a3e2575..b9e81caac7 100644 --- a/awx/ui/client/features/output/index.controller.js +++ b/awx/ui/client/features/output/index.controller.js @@ -439,7 +439,7 @@ function togglePanelExpand () { const iconCollapsed = 'fa-angle-right'; const iconExpanded = 'fa-angle-down'; const iconSelector = '.at-Stdout-toggle > i'; -const lineCollapsed = 'hidden'; +const lineCollapsed = 'at-Stdout-row--hidden'; function toggleCollapseAll () { if (scroll.isPaused()) return; @@ -524,11 +524,15 @@ function togglePlayCollapse (uuid) { taskIcons.addClass(iconCollapsed); lines.addClass(lineCollapsed); + + descendants + .map(item => $(`.child-of-${item}`)) + .forEach(line => line.addClass(lineCollapsed)); } descendants .map(item => render.records[item]) - .filter(({ name }) => name === EVENT_START_TASK) + .filter((descRecord) => descRecord && descRecord.name === EVENT_START_TASK) .forEach(rec => { render.records[rec.uuid].isCollapsed = true; }); render.records[uuid].isCollapsed = !isCollapsed; diff --git a/awx/ui/client/features/output/render.service.js b/awx/ui/client/features/output/render.service.js index 0655dd0c71..f50bc27b40 100644 --- a/awx/ui/client/features/output/render.service.js +++ b/awx/ui/client/features/output/render.service.js @@ -204,7 +204,7 @@ function JobRenderService ($q, $compile, $sce, $window, strings) { return { html: '', count: 0 }; } - if (event.uuid && this.records[event.uuid]) { + if (event.uuid && this.records[event.uuid] && !this.records[event.uuid]._isIncomplete) { return { html: '', count: 0 }; } @@ -272,6 +272,9 @@ function JobRenderService ($q, $compile, $sce, $window, strings) { isClickable = true; } + const children = (this.records[event.uuid] && this.records[event.uuid].children) + ? this.records[event.uuid].children : []; + const record = { isClickable, id: event.id, @@ -285,6 +288,7 @@ function JobRenderService ($q, $compile, $sce, $window, strings) { lineCount: lines.length, isCollapsed: this.state.collapseAll, counters: [event.counter], + children }; if (event.parent_uuid) { @@ -307,12 +311,18 @@ function JobRenderService ($q, $compile, $sce, $window, strings) { if (event.parent_uuid) { if (this.records[event.parent_uuid]) { - if (this.records[event.parent_uuid].children && - !this.records[event.parent_uuid].children.includes(event.uuid)) { - this.records[event.parent_uuid].children.push(event.uuid); + if (this.records[event.parent_uuid].children) { + if (!this.records[event.parent_uuid].children.includes(event.uuid)) { + this.records[event.parent_uuid].children.push(event.uuid); + } } else { this.records[event.parent_uuid].children = [event.uuid]; } + } else { + this.records[event.parent_uuid] = { + _isIncomplete: true, + children: [event.uuid] + }; } } } @@ -397,7 +407,7 @@ function JobRenderService ($q, $compile, $sce, $window, strings) { if (record && record.isCollapsed) { if (record.level === 3 || record.level === 0) { - classList += ' hidden'; + classList += ' at-Stdout-row--hidden'; } } diff --git a/awx/ui/client/features/projects/projects.strings.js b/awx/ui/client/features/projects/projects.strings.js index 7512f0f339..c09f3104d9 100644 --- a/awx/ui/client/features/projects/projects.strings.js +++ b/awx/ui/client/features/projects/projects.strings.js @@ -46,11 +46,6 @@ function ProjectsStrings (BaseString) { HEADER: this.error.HEADER, CALL: this.error.CALL, }; - - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)') - }; } ProjectsStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/features/projects/projectsList.controller.js b/awx/ui/client/features/projects/projectsList.controller.js index b3557d7d00..a295d6e52b 100644 --- a/awx/ui/client/features/projects/projectsList.controller.js +++ b/awx/ui/client/features/projects/projectsList.controller.js @@ -68,10 +68,13 @@ function projectsListController ( vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.NAME_DESCENDING')}`, - value: '-name' - } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.LAST_USED_ASCENDING')}`, value: 'last_job_run' }, + { label: `${strings.get('sort.LAST_USED_DESCENDING')}`, value: '-last_job_run' }, + { label: `${strings.get('sort.ORGANIZATION_ASCENDING')}`, value: 'organization' }, + { label: `${strings.get('sort.ORGANIZATION_DESCENDING')}`, value: '-organization' } ]; vm.toolbarSortValue = toolbarSortDefault; diff --git a/awx/ui/client/features/templates/templates.strings.js b/awx/ui/client/features/templates/templates.strings.js index b536f665b3..d294988d01 100644 --- a/awx/ui/client/features/templates/templates.strings.js +++ b/awx/ui/client/features/templates/templates.strings.js @@ -143,11 +143,6 @@ function TemplatesStrings (BaseString) { CANCEL: t.s('CANCEL'), SAVE_AND_EXIT: t.s('SAVE & EXIT') }; - - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)') - }; } TemplatesStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/features/templates/templatesList.controller.js b/awx/ui/client/features/templates/templatesList.controller.js index b072029752..8c95aa745a 100644 --- a/awx/ui/client/features/templates/templatesList.controller.js +++ b/awx/ui/client/features/templates/templatesList.controller.js @@ -71,7 +71,15 @@ function ListTemplatesController( vm.toolbarSortOptions = [ toolbarSortDefault, - { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.LAST_JOB_RUN_ASCENDING')}`, value: 'last_job_run' }, + { label: `${strings.get('sort.LAST_JOB_RUN_DESCENDING')}`, value: '-last_job_run' }, + { label: `${strings.get('sort.INVENTORY_ASCENDING')}`, value: 'job_template__inventory__id' }, + { label: `${strings.get('sort.INVENTORY_DESCENDING')}`, value: '-job_template__inventory__id' }, + { label: `${strings.get('sort.PROJECT_ASCENDING')}`, value: 'jobtemplate__project__id' }, + { label: `${strings.get('sort.PROJECT_DESCENDING')}`, value: '-jobtemplate__project__id' }, ]; vm.toolbarSortValue = toolbarSortDefault; diff --git a/awx/ui/client/features/users/tokens/tokens.strings.js b/awx/ui/client/features/users/tokens/tokens.strings.js index 13487e9ede..2f84642eae 100644 --- a/awx/ui/client/features/users/tokens/tokens.strings.js +++ b/awx/ui/client/features/users/tokens/tokens.strings.js @@ -41,11 +41,6 @@ function TokensStrings (BaseString) { PERSONAL_ACCESS_TOKEN: t.s('Personal Access Token'), HEADER: appName => t.s('{{ appName }} Token', { appName }), }; - - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)') - }; } TokensStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/features/users/tokens/users-tokens-list.controller.js b/awx/ui/client/features/users/tokens/users-tokens-list.controller.js index aedac69bcb..008f30fda7 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-list.controller.js +++ b/awx/ui/client/features/users/tokens/users-tokens-list.controller.js @@ -50,10 +50,13 @@ function ListTokensController ( vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.NAME_DESCENDING')}`, - value: '-application__name' - } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-application__name' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.EXPIRES_ASCENDING')}`, value: 'expires' }, + { label: `${strings.get('sort.EXPIRES_DESCENDING')}`, value: '-expires' } ]; function setToolbarSort () { diff --git a/awx/ui/client/lib/services/base-string.service.js b/awx/ui/client/lib/services/base-string.service.js index 6db4249b49..3e7b3b7cd7 100644 --- a/awx/ui/client/lib/services/base-string.service.js +++ b/awx/ui/client/lib/services/base-string.service.js @@ -103,6 +103,39 @@ function BaseStringService (namespace) { CANCEL: resourceType => t.s('Cancel the {{resourceType}}', { resourceType }) }; + this.sort = { + NAME_ASCENDING: t.s('Name (Ascending)'), + NAME_DESCENDING: t.s('Name (Descending)'), + CREATED_ASCENDING: t.s('Created (Ascending)'), + CREATED_DESCENDING: t.s('Created (Descending)'), + MODIFIED_ASCENDING: t.s('Modified (Ascending)'), + MODIFIED_DESCENDING: t.s('Modified (Descending)'), + EXPIRES_ASCENDING: t.s('Expires (Ascending)'), + EXPIRES_DESCENDING: t.s('Expires (Descending)'), + LAST_JOB_RUN_ASCENDING: t.s('Last Run (Ascending)'), + LAST_JOB_RUN_DESCENDING: t.s('Last Run (Descending)'), + LAST_USED_ASCENDING: t.s('Last Used (Ascending)'), + LAST_USED_DESCENDING: t.s('Last Used (Descending)'), + USERNAME_ASCENDING: t.s('Username (Ascending)'), + USERNAME_DESCENDING: t.s('Username (Descending)'), + START_TIME_ASCENDING: t.s('Start Time (Ascending)'), + START_TIME_DESCENDING: t.s('Start Time (Descending)'), + FINISH_TIME_ASCENDING: t.s('Finish Time (Ascending)'), + FINISH_TIME_DESCENDING: t.s('Finish Time (Descending)'), + UUID_ASCENDING: t.s('UUID (Ascending)'), + UUID_DESCENDING: t.s('UUID (Descending)'), + LAUNCHED_BY_ASCENDING: t.s('Launched By (Ascending)'), + LAUNCHED_BY_DESCENDING: t.s('Launched By (Descending)'), + INVENTORY_ASCENDING: t.s('Inventory (Ascending)'), + INVENTORY_DESCENDING: t.s('Inventory (Descending)'), + PROJECT_ASCENDING: t.s('Project (Ascending)'), + PROJECT_DESCENDING: t.s('Project (Descending)'), + ORGANIZATION_ASCENDING: t.s('Organization (Ascending)'), + ORGANIZATION_DESCENDING: t.s('Organization (Descending)'), + CAPACITY_ASCENDING: t.s('Capacity (Ascending)'), + CAPACITY_DESCENDING: t.s('Capacity (Descending)') + }; + this.ALERT = ({ header, body }) => t.s('{{ header }} {{ body }}', { header, body }); /** diff --git a/awx/ui/client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js b/awx/ui/client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js index 6fd48cf8cd..96e0b81786 100644 --- a/awx/ui/client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js +++ b/awx/ui/client/src/home/dashboard/graphs/job-status/job-status-graph.directive.js @@ -96,6 +96,11 @@ function JobStatusGraph($window, adjustGraphSize, templateUrl, i18n, moment, gra job_status_chart.interactiveLayer.tooltip.fixedTop(-10); //distance from the top of the chart to tooltip job_status_chart.interactiveLayer.tooltip.distance(-1); //distance from interactive line to tooltip + scope.$on('$destroy', function() { + job_status_chart.tooltip.hidden(true); + job_status_chart.interactiveLayer.tooltip.hidden(true); + }); + job_status_chart.xAxis .axisLabel(i18n._("TIME"))//.showMaxMin(true) .tickFormat(function(d) { diff --git a/awx/ui/client/src/instance-groups/instance-groups.strings.js b/awx/ui/client/src/instance-groups/instance-groups.strings.js index ca93c23140..0becb671f7 100644 --- a/awx/ui/client/src/instance-groups/instance-groups.strings.js +++ b/awx/ui/client/src/instance-groups/instance-groups.strings.js @@ -62,11 +62,6 @@ function InstanceGroupsStrings (BaseString) { ns.alert = { MISSING_PARAMETER: t.s('Instance Group parameter is missing.'), }; - - ns.sort = { - NAME_ASCENDING: t.s('Name (Ascending)'), - NAME_DESCENDING: t.s('Name (Descending)') - }; } InstanceGroupsStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js b/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js index 474e3712bf..7ca555d81e 100644 --- a/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js +++ b/awx/ui/client/src/instance-groups/instances/instance-modal.controller.js @@ -42,10 +42,15 @@ function InstanceModalController ($scope, $state, Dataset, models, strings, Proc vm.toolbarSortValue = toolbarSortDefault; vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.NAME_DESCENDING')}`, - value: '-hostname' - } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-hostname' }, + { label: `${strings.get('sort.UUID_ASCENDING')}`, value: 'uuid' }, + { label: `${strings.get('sort.UUID_DESCENDING')}`, value: '-uuid' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.CAPACITY_ASCENDING')}`, value: 'capacity' }, + { label: `${strings.get('sort.CAPACITY_DESCENDING')}`, value: '-capacity' } ]; const removeStateParamsListener = $scope.$watchCollection('$state.params', () => { diff --git a/awx/ui/client/src/instance-groups/instances/instances.controller.js b/awx/ui/client/src/instance-groups/instances/instances.controller.js index 329ee1ad19..dbd5645d0a 100644 --- a/awx/ui/client/src/instance-groups/instances/instances.controller.js +++ b/awx/ui/client/src/instance-groups/instances/instances.controller.js @@ -24,10 +24,15 @@ function InstancesController ($scope, $state, $http, $transitions, models, strin vm.toolbarSortValue = toolbarSortDefault; vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.NAME_DESCENDING')}`, - value: '-hostname' - } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-hostname' }, + { label: `${strings.get('sort.UUID_ASCENDING')}`, value: 'uuid' }, + { label: `${strings.get('sort.UUID_DESCENDING')}`, value: '-uuid' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' }, + { label: `${strings.get('sort.CAPACITY_ASCENDING')}`, value: 'capacity' }, + { label: `${strings.get('sort.CAPACITY_DESCENDING')}`, value: '-capacity' } ]; const removeStateParamsListener = $scope.$watchCollection('$state.params', () => { diff --git a/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js b/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js index 25888a18f7..af7653cc37 100644 --- a/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js +++ b/awx/ui/client/src/instance-groups/list/instance-groups-list.controller.js @@ -43,10 +43,11 @@ export default ['$scope', '$filter', '$state', 'Alert', 'resolvedModels', 'Datas vm.toolbarSortOptions = [ toolbarSortDefault, - { - label: `${strings.get('sort.NAME_DESCENDING')}`, - value: '-name' - } + { label: `${strings.get('sort.NAME_DESCENDING')}`, value: '-name' }, + { label: `${strings.get('sort.CREATED_ASCENDING')}`, value: 'created' }, + { label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }, + { label: `${strings.get('sort.MODIFIED_ASCENDING')}`, value: 'modified' }, + { label: `${strings.get('sort.MODIFIED_DESCENDING')}`, value: '-modified' } ]; vm.toolbarSortValue = toolbarSortDefault; diff --git a/awx/ui/client/src/templates/prompt/prompt.controller.js b/awx/ui/client/src/templates/prompt/prompt.controller.js index 5bf6cee2df..d23dce9a54 100644 --- a/awx/ui/client/src/templates/prompt/prompt.controller.js +++ b/awx/ui/client/src/templates/prompt/prompt.controller.js @@ -154,7 +154,7 @@ export default [ 'ProcessErrors', 'CredentialTypeModel', 'TemplatesStrings', '$f _disabled: (order === 1 || vm.readOnlyPrompts) ? false : true, order: order }; - activeTab = activeTab || vm.steps.credentials.tab; + activeTab = activeTab || vm.steps.credential.tab; order++; } if(vm.promptDataClone.launchConf.ask_verbosity_on_launch || vm.promptDataClone.launchConf.ask_job_type_on_launch || vm.promptDataClone.launchConf.ask_limit_on_launch || vm.promptDataClone.launchConf.ask_tags_on_launch || vm.promptDataClone.launchConf.ask_skip_tags_on_launch || (vm.promptDataClone.launchConf.ask_variables_on_launch && !vm.promptDataClone.launchConf.ignore_ask_variables) || vm.promptDataClone.launchConf.ask_diff_mode_on_launch) { diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 6d9c19694a..cf2bb212a1 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -112,7 +112,7 @@ twilio==6.10.4 twisted==18.9.0 # via daphne txaio==18.8.1 # via autobahn typing==3.6.6 # via django-extensions -urllib3==1.24.1 # via requests +urllib3==1.24.3 # via requests uwsgi==2.0.17 uwsgitop==0.10.0 vine==1.2.0 # via amqp diff --git a/requirements/requirements_ansible.txt b/requirements/requirements_ansible.txt index 0be2c2861f..f3c638aa60 100644 --- a/requirements/requirements_ansible.txt +++ b/requirements/requirements_ansible.txt @@ -115,7 +115,7 @@ selectors2==2.0.1 # via ncclient six==1.11.0 # via azure-cli-core, bcrypt, cryptography, google-auth, isodate, keystoneauth1, knack, munch, ncclient, ntlm-auth, openstacksdk, ovirt-engine-sdk-python, packaging, pynacl, pyopenssl, python-dateutil, pyvmomi, pywinrm, stevedore stevedore==1.28.0 # via keystoneauth1 tabulate==0.7.7 # via azure-cli-core, knack -urllib3==1.24 # via requests +urllib3==1.24.3 # via requests wheel==0.30.0 # via azure-cli-core xmltodict==0.11.0 # via pywinrm diff --git a/tools/scripts/failure-event-handler b/tools/scripts/failure-event-handler index 9838696f1c..da5008f4ac 100755 --- a/tools/scripts/failure-event-handler +++ b/tools/scripts/failure-event-handler @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/awx-python import sys import os import signal