diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js index e49f661884..96c04b7eac 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js @@ -122,14 +122,8 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network'; $scope.sourceChange = function(source) { - if (source) { - source = source.value; - } else { - source = ""; - } - + source = (source && source.value) ? source.value : ''; $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network'; - if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm') { $scope.envParseType = 'yaml'; @@ -161,10 +155,11 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions']; $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false; - $scope.group_by = null; $scope.source_regions = null; $scope.credential = null; $scope.credential_name = null; + $scope.group_by = null; + $scope.group_by_choices = []; initRegionSelect(); }; // region / source options callback @@ -178,9 +173,53 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', element: '#inventory_source_source_regions', multiple: true }); + + initGroupBySelect(); + } + + function initGroupBySelect(){ + let add_new = false; + if($scope && $scope.source && $scope.source === 'ec2' || $scope && $scope.source && $scope.source.value && $scope.source.value === 'ec2'){ + $scope.group_by_choices = $scope.ec2_group_by; + $scope.groupByPopOver = "

Select which groups to create automatically. " + + "Tower will create group names similar to the following examples based on the options selected:

If blank, all groups above are created except Instance ID.

"; + $scope.instanceFilterPopOver = "

Provide a comma-separated list of filter expressions. " + + "Hosts are imported to Tower when ANY of the filters match.

" + + "Limit to hosts having a tag:
\n" + + "
tag-key=TowerManaged
\n" + + "Limit to hosts using either key pair:
\n" + + "
key-name=staging, key-name=production
\n" + + "Limit to hosts where the Name tag begins with test:
\n" + + "
tag:Name=test*
\n" + + "

View the Describe Instances documentation " + + "for a complete list of supported filters.

"; + } + if($scope && $scope.source && $scope.source === 'vmware' || $scope && $scope.source && $scope.source.value && $scope.source.value === 'vmware'){ + add_new = true; + $scope.group_by_choices = []; + $scope.group_by = $scope.group_by_choices; + $scope.groupByPopOver = `Specify which groups to create automatically. + Group names will be created similar to the options selected. + If blank, all groups above are created. Refer to Ansible Tower documentation for more detail.`; + $scope.instanceFilterPopOver = `Provide a comma-separated list of filter expressions. + Hosts are imported when ANY of the filters match. + Refer to Ansible Tower documentation for more detail.`; + } CreateSelect2({ element: '#inventory_source_group_by', - multiple: true + multiple: true, + addNew: add_new }); } @@ -279,7 +318,7 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', verbosity: $scope.verbosity.value, update_cache_timeout: $scope.update_cache_timeout || 0, // comma-delimited strings - group_by: _.map($scope.group_by, 'value').join(','), + group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by), source_regions: _.map($scope.source_regions, 'value').join(',') }; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js index e9f953e4a0..f4a68679ed 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js @@ -211,11 +211,6 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', else { $scope.source_regions = _.map(regions, (region) => _.find($scope[source + '_regions'], (o) => o.value === region)); } - $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; - if (source === 'ec2') { - var group_by = inventorySourceData.group_by.split(','); - $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, { value: item })); - } initRegionSelect(); } @@ -268,9 +263,57 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', element: '#inventory_source_source_regions', multiple: true }); + + initGroupBySelect(); + } + + function initGroupBySelect(){ + let add_new = false; + if($scope && $scope.source && $scope.source === 'ec2' || $scope && $scope.source && $scope.source.value && $scope.source.value === 'ec2'){ + $scope.group_by_choices = $scope.ec2_group_by; + let group_by = inventorySourceData.group_by.split(','); + $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, { value: item })); + $scope.groupByPopOver = "

Select which groups to create automatically. " + + "Tower will create group names similar to the following examples based on the options selected:

If blank, all groups above are created except Instance ID.

"; + $scope.instanceFilterPopOver = "

Provide a comma-separated list of filter expressions. " + + "Hosts are imported to Tower when ANY of the filters match.

" + + "Limit to hosts having a tag:
\n" + + "
tag-key=TowerManaged
\n" + + "Limit to hosts using either key pair:
\n" + + "
key-name=staging, key-name=production
\n" + + "Limit to hosts where the Name tag begins with test:
\n" + + "
tag:Name=test*
\n" + + "

View the Describe Instances documentation " + + "for a complete list of supported filters.

"; + + } + if($scope && $scope.source && $scope.source === 'vmware' || $scope && $scope.source && $scope.source.value && $scope.source.value === 'vmware'){ + add_new = true; + $scope.group_by_choices = (inventorySourceData.group_by) ? inventorySourceData.group_by.split(',') + .map((i) => ({name: i, label: i, value: i})) : []; + $scope.group_by = $scope.group_by_choices; + $scope.groupByPopOver = `Specify which groups to create automatically. + Group names will be created similar to the options selected. + If blank, all groups above are created. Refer to Ansible Tower documentation for more detail.`; + $scope.instanceFilterPopOver = `Provide a comma-separated list of filter expressions. + Hosts are imported when ANY of the filters match. + Refer to Ansible Tower documentation for more detail.`; + } CreateSelect2({ element: '#inventory_source_group_by', - multiple: true + multiple: true, + addNew: add_new }); } @@ -314,7 +357,7 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', update_cache_timeout: $scope.update_cache_timeout || 0, verbosity: $scope.verbosity.value, // comma-delimited strings - group_by: _.map($scope.group_by, 'value').join(','), + group_by: SourcesService.encodeGroupBy($scope.source, $scope.group_by), source_regions: _.map($scope.source_regions, 'value').join(',') }; @@ -341,14 +384,8 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', }; $scope.sourceChange = function(source) { - if (source) { - source = source.value; - } else { - source = ""; - } - + source = (source && source.value) ? source.value : ''; $scope.credentialBasePath = GetBasePath('credentials') + '?credential_type__kind__in=cloud,network'; - if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm') { $scope.envParseType = 'yaml'; @@ -380,11 +417,14 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions']; $scope.cloudCredentialRequired = source !== '' && source !== 'scm' && source !== 'custom' && source !== 'ec2' ? true : false; - $scope.group_by = null; $scope.source_regions = null; $scope.credential = null; $scope.credential_name = null; + $scope.group_by = null; + $scope.group_by_choices = []; + initRegionSelect(); + }; init(); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js index 4463d8a5d5..de9f217dcf 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js @@ -71,7 +71,7 @@ return { type: 'lookup', list: 'CredentialList', basePath: 'credentials', - ngShow: "source && source.value !== ''", + ngShow: "source && source.value !== '' && source.value !== 'custom'", sourceModel: 'credential', sourceField: 'name', ngClick: 'lookupCredential()', @@ -134,43 +134,24 @@ return { instance_filters: { label: i18n._('Instance Filters'), type: 'text', - ngShow: "source && source.value == 'ec2'", + ngShow: "source && (source.value == 'ec2' || source.value == 'vmware')", dataTitle: 'Instance Filters', dataPlacement: 'right', - awPopOver: "

Provide a comma-separated list of filter expressions. " + - "Hosts are imported when ANY of the filters match.

" + - "Limit to hosts having a tag:
\n" + - "
tag-key=TowerManaged
\n" + - "Limit to hosts using either key pair:
\n" + - "
key-name=staging, key-name=production
\n" + - "Limit to hosts where the Name tag begins with test:
\n" + - "
tag:Name=test*
\n" + - "

View the Describe Instances documentation " + - "for a complete list of supported filters.

", + awPopOverWatch: 'instanceFilterPopOver', + awPopOver: '{{ instanceFilterPopOver }}', dataContainer: 'body', ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' }, group_by: { label: i18n._('Only Group By'), type: 'select', - ngShow: "source && source.value == 'ec2'", + ngShow: "source && (source.value == 'ec2' || source.value == 'vmware')", ngOptions: 'source.label for source in group_by_choices track by source.value', multiSelect: true, dataTitle: 'Only Group By', dataPlacement: 'right', - awPopOver: "

Select which groups to create automatically. " + - "Tower will create group names similar to the following examples based on the options selected:

If blank, all groups above are created except Instance ID.

", + awPopOverWatch: 'groupByPopOver', + awPopOver: '{{ groupByPopOver }}', dataContainer: 'body', ngDisabled: '!(inventory_source_obj.summary_fields.user_capabilities.edit || canAdd)' }, diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js index 7544de056f..8ae2d144b7 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.service.js @@ -115,6 +115,23 @@ export default .success(this.success.bind(this)) .error(this.error.bind(this)) .finally(Wait('stop')); + }, + encodeGroupBy(source, group_by){ + source = source && source.value ? source.value : ''; + if(source === 'ec2'){ + return _.map(group_by, 'value').join(','); + } + if(source === 'vmware'){ + group_by = _.map(group_by, (i) => {return i.value;}); + $("#inventory_source_group_by").siblings(".select2").first().find(".select2-selection__choice").each(function(optionIndex, option){ + group_by.push(option.title); + }); + group_by = (Array.isArray(group_by)) ? _.uniq(group_by).join() : ""; + return group_by; + } + else { + return; + } } }; }];