diff --git a/awx/ui/client/legacy-styles/lists.less b/awx/ui/client/legacy-styles/lists.less index bbaf12fe7b..3011995ea3 100644 --- a/awx/ui/client/legacy-styles/lists.less +++ b/awx/ui/client/legacy-styles/lists.less @@ -474,6 +474,10 @@ table, tbody { color: @default-interface-txt; } +.List-actionsInner { + display: flex; +} + @media (max-width: 991px) { .List-searchWidget + .List-searchWidget { margin-top: 20px; diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js index cbfc11a083..468c38273f 100644 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js +++ b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups.list.js @@ -62,7 +62,8 @@ export default ['i18n', function(i18n) { //label: 'Delete', mode: 'all', ngClick: "disassociateHost(group)", - awToolTip: i18n._('Disassociate host'), + awToolTip: i18n._('Disassociate group'), + iconClass: 'fa fa-times', dataPlacement: "top", ngShow: "group.summary_fields.user_capabilities.delete" } diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js index 6fd81ad00c..7caaa49f41 100644 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js +++ b/awx/ui/client/src/inventories-hosts/hosts/related/groups/main.js @@ -10,5 +10,5 @@ import hostGroupsDefinition from './hosts-related-groups.list'; export default angular.module('hostGroups', []) - .value('HostsRelatedGroupsList', hostGroupsDefinition) + .factory('HostsRelatedGroupsList', hostGroupsDefinition) .controller('HostsRelatedGroupsController', controller); diff --git a/awx/ui/client/src/inventories-hosts/inventories/main.js b/awx/ui/client/src/inventories-hosts/inventories/main.js index 0a11f575b1..22c8c773e5 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/main.js +++ b/awx/ui/client/src/inventories-hosts/inventories/main.js @@ -165,6 +165,28 @@ angular.module('inventory', [ data: { activityStream: true, activityStreamTarget: 'inventory' + }, + resolve: { + edit: { + InstanceGroupsData: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', + function($stateParams, Rest, GetBasePath, ProcessErrors){ + let path = `${GetBasePath('inventory')}${$stateParams.smartinventory_id}/instance_groups/`; + Rest.setUrl(path); + return Rest.get() + .then(({data}) => { + if (data.results.length > 0) { + return data.results; + } + }) + .catch(({data, status}) => { + ProcessErrors(null, data, status, null, { + hdr: 'Error!', + msg: 'Failed to get instance groups. GET returned ' + + 'status: ' + status + }); + }); + }] + } } }); diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js index 091f18e31d..2183cea7db 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js @@ -98,7 +98,7 @@ //label: 'Delete', mode: 'all', ngClick: "deleteGroup(group)", - awToolTip: i18n._('Disassociate group'), + awToolTip: i18n._('Delete group'), dataPlacement: "top", ngShow: "group.summary_fields.user_capabilities.delete" } diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js index b1c4ce0717..2f8b315f68 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups.list.js @@ -108,6 +108,7 @@ mode: 'all', ngClick: "disassociateGroup(nested_group)", awToolTip: i18n._('Disassociate group'), + iconClass: 'fa fa-times', dataPlacement: "top", ngShow: "nested_group.summary_fields.user_capabilities.delete" } diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js index 9231c9c8d8..10cbcb48bd 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts.list.js @@ -83,7 +83,7 @@ export default ['i18n', function(i18n) { "delete": { //label: 'Delete', ngClick: "disassociateHost(nested_host)", - icon: 'icon-trash', + iconClass: 'fa fa-times', awToolTip: i18n._('Disassociate host'), dataPlacement: 'top', ngShow: 'nested_host.summary_fields.user_capabilities.delete' diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js index 465395f5f8..a8a1e89499 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related-host.form.js @@ -78,11 +78,6 @@ function(i18n) { dataTitle: i18n._('Host Variables'), dataPlacement: 'right', dataContainer: 'body' - }, - inventory: { - type: 'hidden', - includeOnEdit: true, - includeOnAdd: true } }, diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js index a2da2035a3..161ed64e03 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups.list.js @@ -96,6 +96,7 @@ mode: 'all', ngClick: "disassociateGroup(nested_group)", awToolTip: i18n._('Disassociate group'), + iconClass: 'fa fa-times', dataPlacement: "top", ngShow: "nested_group.summary_fields.user_capabilities.delete" } 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 de9f217dcf..2159fb4ddb 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 @@ -19,7 +19,7 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n){ include: "NotificationsList", title: i18n._('Notifications'), iterator: 'notification', - disabled: "source === undefined || source.value === ''", + ngIf: "!(inventory_source_obj.source === undefined || inventory_source_obj.source === '')", generateList: true, ngClick: "$state.go('inventories.edit.inventory_sources.edit.notifications')" // search: { diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js index 4d916c5b99..ff0e6f6aad 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/add/smart-inventory-add.controller.js @@ -13,7 +13,7 @@ function SmartInventoryAdd($scope, $location, GenerateForm, smartInventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, GetBasePath, ParseTypeChange, Wait, ToJSON, - $state, canAdd) { + $state, canAdd, InstanceGroupsService) { $scope.canAdd = canAdd; @@ -64,9 +64,21 @@ function SmartInventoryAdd($scope, $location, Rest.setUrl(defaultUrl); Rest.post(data) .success(function(data) { - var inventory_id = data.id; - Wait('stop'); - $state.go('inventories.editSmartInventory', {smartinventory_id: inventory_id}, {reload: true}); + const inventory_id = data.id, + instance_group_url = data.related.instance_groups; + + InstanceGroupsService.addInstanceGroups(instance_group_url, $scope.instance_groups) + .then(() => { + Wait('stop'); + $state.go('inventories.editSmartInventory', {smartinventory_id: inventory_id}, {reload: true}); + }) + .catch(({data, status}) => { + ProcessErrors($scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to post instance groups. POST returned ' + + 'status: ' + status + }); + }); }) .error(function(data, status) { ProcessErrors($scope, data, status, form, { @@ -89,5 +101,5 @@ function SmartInventoryAdd($scope, $location, export default ['$scope', '$location', 'GenerateForm', 'smartInventoryForm', 'rbacUiControlService', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', - 'Wait', 'ToJSON', '$state', 'canAdd', SmartInventoryAdd + 'Wait', 'ToJSON', '$state', 'canAdd', 'InstanceGroupsService', SmartInventoryAdd ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js index 885556e6bd..fe7328a43d 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/edit/smart-inventory-edit.controller.js @@ -7,13 +7,15 @@ function SmartInventoryEdit($scope, $location, $stateParams, InventoryForm, Rest, ProcessErrors, GetBasePath, ParseTypeChange, Wait, ToJSON, - ParseVariableString, $state, OrgAdminLookup, resourceData, $rootScope) { + ParseVariableString, $state, OrgAdminLookup, resourceData, + $rootScope, InstanceGroupsService, InstanceGroupsData) { // Inject dynamic view var defaultUrl = GetBasePath('inventory'), form = InventoryForm, inventory_id = $stateParams.smartinventory_id, - inventoryData = resourceData.data; + inventoryData = resourceData.data, + instance_group_url = inventoryData.related.instance_groups; init(); function init() { @@ -25,6 +27,7 @@ function SmartInventoryEdit($scope, $location, $scope.smartinventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables); $scope.organization_name = inventoryData.summary_fields.organization.name; + $scope.instance_groups = InstanceGroupsData; $scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) { if (val === false) { @@ -75,8 +78,17 @@ function SmartInventoryEdit($scope, $location, Rest.setUrl(defaultUrl + inventory_id + '/'); Rest.put(data) .success(function() { - Wait('stop'); - $state.go($state.current, {}, { reload: true }); + InstanceGroupsService.editInstanceGroups(instance_group_url, $scope.instance_groups) + .then(() => { + Wait('stop'); + $state.go($state.current, {}, { reload: true }); + }) + .catch(({data, status}) => { + ProcessErrors($scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to update instance groups. POST returned status: ' + status + }); + }); }) .error(function(data, status) { ProcessErrors($scope, data, status, form, { @@ -96,5 +108,6 @@ export default [ '$scope', '$location', '$stateParams', 'InventoryForm', 'Rest', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'Wait', 'ToJSON', 'ParseVariableString', - '$state', 'OrgAdminLookup', 'resourceData', '$rootScope', SmartInventoryEdit + '$state', 'OrgAdminLookup', 'resourceData', + '$rootScope', 'InstanceGroupsService', 'InstanceGroupsData', SmartInventoryEdit ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js index 9d71393069..9265ca2501 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/main.js @@ -4,11 +4,12 @@ * All Rights Reserved *************************************************/ - import smartInventoryAdd from './add/main'; - import smartInventoryEdit from './edit/main'; - import smartInventoryForm from './smart-inventory.form'; - import smartInventoryHostFilter from './smart-inventory-host-filter/smart-inventory-host-filter.directive'; - import hostFilterModal from './smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive'; +import smartInventoryAdd from './add/main'; +import smartInventoryEdit from './edit/main'; +import smartInventoryForm from './smart-inventory.form'; +import smartInventoryHostFilter from './smart-inventory-host-filter/smart-inventory-host-filter.directive'; +import hostFilterModal from './smart-inventory-host-filter/host-filter-modal/host-filter-modal.directive'; +import SmartInventoryStrings from './smart-inventory.strings'; export default angular.module('smartInventory', [ @@ -17,4 +18,5 @@ angular.module('smartInventory', [ ]) .factory('smartInventoryForm', smartInventoryForm) .directive('smartInventoryHostFilter', smartInventoryHostFilter) - .directive('hostFilterModal', hostFilterModal); + .directive('hostFilterModal', hostFilterModal) + .service('SmartInventoryStrings', SmartInventoryStrings); diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js index 73b20ada75..198e398b66 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.controller.js @@ -4,10 +4,12 @@ * All Rights Reserved *************************************************/ -export default ['$scope', 'QuerySet', - function($scope, qs) { +export default ['$scope', 'QuerySet', 'SmartInventoryStrings', + function($scope, qs, SmartInventoryStrings) { $scope.hostFilterTags = []; + $scope.filterTooltip = SmartInventoryStrings.get('filter.TOOLTIP'); + $scope.$watch('hostFilter', function(){ $scope.hostFilterTags = []; diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html index 5a033a4000..6c3248b2de 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory-host-filter/smart-inventory-host-filter.partial.html @@ -4,7 +4,7 @@ - + {{tag}} diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js index 229d7bb294..07cf7db25c 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js @@ -65,8 +65,20 @@ export default ['i18n', 'InventoryCompletedJobsList', function(i18n, InventoryCo label: i18n._('Smart Host Filter'), type: 'custom', control: '', - required: true, - class: 'Form-formGroup--fullWidth' + awPopOver: "

" + i18n._("Filter that will be applied to the hosts of this inventory.") + "

", + dataTitle: i18n._('Smart Host Filter'), + dataPlacement: 'right', + dataContainer: 'body', + required: true + }, + instance_groups: { + label: i18n._('Instance Groups'), + type: 'custom', + awPopOver: "

" + i18n._("Select the Instance Groups for this Inventory to run on.") + "

", + dataTitle: i18n._('Instance Groups'), + dataPlacement: 'right', + dataContainer: 'body', + control: '', }, smartinventory_variables: { label: i18n._('Variables'), diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.strings.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.strings.js new file mode 100644 index 0000000000..e84d4d38f0 --- /dev/null +++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.strings.js @@ -0,0 +1,14 @@ +function SmartInventoryStrings (BaseString) { + BaseString.call(this, 'smartinventories'); + + let t = this.t; + let ns = this.smartinventories; + + ns.filter = { + TOOLTIP: t('Please click the icon to edit the host filter.') + }; +} + +SmartInventoryStrings.$inject = ['BaseStringService']; + +export default SmartInventoryStrings; diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js index a32c5ab49e..a709d5a919 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/edit/inventory-edit.controller.js @@ -55,6 +55,7 @@ function InventoriesEdit($scope, $location, }); $scope.inventory_obj = inventoryData; + $scope.inventory_name = inventoryData.name; $rootScope.breadcrumb.inventory_name = inventoryData.name; $scope.$watch('inventory_obj.summary_fields.user_capabilities.edit', function(val) { diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less index 77612ebf3b..befe6c1061 100644 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less +++ b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.block.less @@ -1,10 +1,5 @@ @import "../../shared/branding/colors.default.less"; -#InstanceGroups { - display: flex; - padding: 0 12px; -} - #instance-groups-panel { table { overflow: hidden; diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html index cc4b689308..46eaf47b8c 100644 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html +++ b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups.partial.html @@ -4,7 +4,7 @@
- +
@@ -15,4 +15,4 @@
- \ No newline at end of file + diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js index 01d5d4ea83..39ffcef1fb 100644 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ b/awx/ui/client/src/shared/list-generator/list-generator.factory.js @@ -182,7 +182,7 @@ export default ['$compile', 'Attr', 'Icon', html += (list.actionHolderClass) ? list.actionHolderClass : "List-actionHolder"; html += "\">"; html += "
"; - html += `
`; + html += `
`; for (action in list.actions) { list.actions[action] = _.defaults(list.actions[action], { dataPlacement: "top" }); diff --git a/awx/ui/client/src/templates/labels/labelsList.block.less b/awx/ui/client/src/templates/labels/labelsList.block.less index 649f1cd9a4..d0d0c07c2f 100644 --- a/awx/ui/client/src/templates/labels/labelsList.block.less +++ b/awx/ui/client/src/templates/labels/labelsList.block.less @@ -17,7 +17,7 @@ .LabelList-tag, .JobSubmission-previewTag { border-radius: 5px; padding: 2px 10px; - margin: 4px 0px; + margin: 3px 0px; font-size: 12px; color: @default-interface-txt; background-color: @default-list-header-bg; @@ -57,7 +57,7 @@ border-bottom-left-radius: 5px; color: @default-bg; padding: 0 5px; - margin: 4px 0px; + margin: 3px 0px; align-items: center; display: flex; cursor: pointer; @@ -86,6 +86,20 @@ color: @default-bg; } +.LabelList-lookupTags { + display: flex; + padding: 0 12px; +} + +.LabelList-lookupTags--disabled { + cursor: not-allowed; + background-color: @default-list-header-bg; + .LabelList-tag { + color: @default-bg; + background-color: @default-icon; + } +} + .JobSubmission-previewTagContainer--vault{ flex: 1 0 auto; }