diff --git a/awx/ui/client/legacy-styles/lists.less b/awx/ui/client/legacy-styles/lists.less index 7e36f610cc..5580df4119 100644 --- a/awx/ui/client/legacy-styles/lists.less +++ b/awx/ui/client/legacy-styles/lists.less @@ -162,10 +162,16 @@ table, tbody { // float: right; } +.List-actionHolder--leftAlign { + width: 50%; + margin-left: 50%; + justify-content: flex-start; +} + .List-actions { display: flex; - margin-bottom: -32px; margin-top: 18px; + margin-bottom: -34px; } .List-auxAction { diff --git a/awx/ui/client/src/inventories/hosts/host.list.js b/awx/ui/client/src/inventories/hosts/host.list.js index ef6c19212e..34d5056d42 100644 --- a/awx/ui/client/src/inventories/hosts/host.list.js +++ b/awx/ui/client/src/inventories/hosts/host.list.js @@ -19,6 +19,7 @@ export default ['i18n', function(i18n) { trackBy: 'host.id', basePath: 'hosts', title: false, + actionHolderClass: 'List-actionHolder List-actionHolder--leftAlign', fields: { toggleHost: { @@ -108,7 +109,7 @@ export default ['i18n', function(i18n) { buttonContent: 'SMART INVENTORY', ngShow: 'canAdd', dataPlacement: "top", - ngDisabled: '!activeHostSearch' + ngDisabled: '!enableSmartInventoryButton' } } }; diff --git a/awx/ui/client/src/inventories/hosts/list/host-list.controller.js b/awx/ui/client/src/inventories/hosts/list/host-list.controller.js index 398a18a549..4f0b6f0b6a 100644 --- a/awx/ui/client/src/inventories/hosts/list/host-list.controller.js +++ b/awx/ui/client/src/inventories/hosts/list/host-list.controller.js @@ -15,7 +15,7 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath, function init(){ $scope.canAdd = false; - $scope.activeHostSearch = false; + $scope.enableSmartInventoryButton = false; rbacUiControlService.canAdd('hosts') .then(function(canAdd) { @@ -39,17 +39,22 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath, }); $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) { - if(toParams && toParams.host_search) { - let hasMoreThanDefaultKeys = false; - angular.forEach(toParams.host_search, function(value, key) { - if(key !== 'order_by' && key !== 'page_size') { - hasMoreThanDefaultKeys = true; - } - }); - $scope.activeHostSearch = hasMoreThanDefaultKeys ? true : false; + if(toState.name === 'hosts.addSmartInventory') { + $scope.enableSmartInventoryButton = false; } else { - $scope.activeHostSearch = false; + if(toParams && toParams.host_search) { + let hasMoreThanDefaultKeys = false; + angular.forEach(toParams.host_search, function(value, key) { + if(key !== 'order_by' && key !== 'page_size') { + hasMoreThanDefaultKeys = true; + } + }); + $scope.enableSmartInventoryButton = hasMoreThanDefaultKeys ? true : false; + } + else { + $scope.enableSmartInventoryButton = false; + } } }); @@ -110,7 +115,7 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath, }; $scope.smartInventory = function() { - $state.go('hosts.addSmartInventory'); + $state.go('inventories.addSmartInventory'); }; } diff --git a/awx/ui/client/src/inventories/hosts/smart-inventory/smart-inventory.form.js b/awx/ui/client/src/inventories/hosts/smart-inventory/smart-inventory.form.js index 4ba3d7e6d7..9404bb575c 100644 --- a/awx/ui/client/src/inventories/hosts/smart-inventory/smart-inventory.form.js +++ b/awx/ui/client/src/inventories/hosts/smart-inventory/smart-inventory.form.js @@ -78,6 +78,117 @@ export default ['i18n', function(i18n) { ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' } }, - related: {} + related: { + permissions: { + name: 'permissions', + awToolTip: i18n._('Please save before assigning permissions'), + dataPlacement: 'top', + basePath: 'api/v1/inventories/{{$stateParams.inventory_id}}/access_list/', + type: 'collection', + title: i18n._('Permissions'), + iterator: 'permission', + index: false, + open: false, + search: { + order_by: 'username' + }, + actions: { + add: { + label: i18n._('Add'), + ngClick: "$state.go('.add')", + awToolTip: i18n._('Add a permission'), + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ADD', + ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + + } + }, + fields: { + username: { + key: true, + label: i18n._('User'), + linkBase: 'users', + class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' + }, + role: { + label: i18n._('Role'), + type: 'role', + nosort: true, + class: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', + }, + team_roles: { + label: i18n._('Team Roles'), + type: 'team_roles', + nosort: true, + class: 'col-lg-5 col-md-5 col-sm-5 col-xs-4', + } + } + }, + hosts: { + name: 'hosts', + // awToolTip: i18n._('Please save before assigning permissions'), + // dataPlacement: 'top', + basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/hosts/', + type: 'collection', + title: i18n._('Hosts'), + iterator: 'host', + index: false, + open: false, + // search: { + // order_by: 'username' + // }, + actions: { + add: { + label: i18n._('Add'), + ngClick: "$state.go('.add')", + awToolTip: i18n._('Add a permission'), + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ADD', + // ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + + } + }, + fields: { + name: { + label: i18n._('Name'), + // linkBase: 'users', + class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' + } + } + }, + //this is a placeholder for when we're ready for completed jobs + completed_jobs: { + name: 'completed_jobs', + // awToolTip: i18n._('Please save before assigning permissions'), + // dataPlacement: 'top', + basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/completed_jobs/', + type: 'collection', + title: i18n._('Completed Jobs'), + iterator: 'completed_job', + index: false, + open: false, + // search: { + // order_by: 'username' + // }, + actions: { + add: { + label: i18n._('Add'), + ngClick: "$state.go('.add')", + awToolTip: i18n._('Add a permission'), + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ADD', + // ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' + + } + }, + fields: { + name: { + label: i18n._('Name'), + // linkBase: 'users', + class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' + } + } + } + } };}]; diff --git a/awx/ui/client/src/inventories/inventory.list.js b/awx/ui/client/src/inventories/inventory.list.js index 38c6f91874..fb6bac2a68 100644 --- a/awx/ui/client/src/inventories/inventory.list.js +++ b/awx/ui/client/src/inventories/inventory.list.js @@ -63,11 +63,31 @@ export default ['i18n', function(i18n) { actions: { add: { mode: 'all', // One of: edit, select, all - ngClick: 'addInventory()', + type: 'buttonDropdown', + basePaths: ['inventories'], awToolTip: i18n._('Create a new inventory'), - actionClass: 'btn List-buttonSubmit', + actionClass: 'btn List-dropdownSuccess', buttonContent: '+ ' + i18n._('ADD'), - ngShow: 'canAdd' + options: [ + { + optionContent: i18n._('Inventory'), + optionSref: 'inventories.add', + ngShow: 'canAddInventory' + }, + { + optionContent: i18n._('Smart Inventory'), + optionSref: 'inventories.addSmartInventory', + //TODO: this should have its own permission + ngShow: 'canAddInventory' + }, + { + optionContent: i18n._('SCM Inventory'), + optionSref: 'inventories.addSCMInventory', + //TODO: this should have its own permission + ngShow: 'canAddInventory' + } + ], + ngShow: 'canAddInventory || canAddSmartInventory || canAddSCMInventory' } }, diff --git a/awx/ui/client/src/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories/list/inventory-list.controller.js index 2f43f48100..0063b94fa4 100644 --- a/awx/ui/client/src/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories/list/inventory-list.controller.js @@ -23,8 +23,8 @@ function InventoriesList($scope, $rootScope, $location, $scope.canAdd = false; rbacUiControlService.canAdd('inventory') - .then(function(params) { - $scope.canAdd = params.canAdd; + .then(function(canAdd) { + $scope.canAddInventory = canAdd; }); $scope.$watchCollection(list.name, function(){ diff --git a/awx/ui/client/src/inventories/main.js b/awx/ui/client/src/inventories/main.js index be59ca6b4e..4f0f3b44fd 100644 --- a/awx/ui/client/src/inventories/main.js +++ b/awx/ui/client/src/inventories/main.js @@ -32,17 +32,17 @@ angular.module('inventory', [ let stateDefinitions = stateDefinitionsProvider.$get(), stateExtender = $stateExtenderProvider.$get(); - function generateHostStates() { + function generateInventoryStates() { let smartInventoryAdd = { - name: 'hosts.addSmartInventory', + name: 'inventories.addSmartInventory', url: '/smartinventory', form: 'SmartInventoryForm', ncyBreadcrumb: { label: "CREATE SMART INVENTORY" }, views: { - 'form@hosts': { + 'form@inventories': { templateProvider: function(SmartInventoryForm, GenerateForm) { return GenerateForm.buildHTML(SmartInventoryForm, { mode: 'add', @@ -56,7 +56,7 @@ angular.module('inventory', [ let smartInventoryAddOrgLookup = { searchPrefix: 'organization', - name: 'hosts.addSmartInventory.organization', + name: 'inventories.addSmartInventory.organization', url: '/organization', data: { formChildState: true @@ -108,7 +108,61 @@ angular.module('inventory', [ }, }; - let hosts = stateDefinitions.generateTree({ + let inventories = stateDefinitions.generateTree({ + parent: 'inventories', // top-most node in the generated tree (will replace this state definition) + modes: ['add', 'edit'], + list: 'InventoryList', + form: 'InventoryForm', + controllers: { + list: 'InventoryListController', + add: 'InventoryAddController', + edit: 'InventoryEditController', + related: { + groups: 'GroupsListController' + } + }, + urls: { + list: '/inventories' + }, + ncyBreadcrumb: { + label: N_('INVENTORIES') + }, + views: { + '@': { + templateUrl: templateUrl('inventories/inventories') + }, + 'list@inventories': { + templateProvider: function(InventoryList, generateList) { + let html = generateList.build({ + list: InventoryList, + mode: 'edit' + }); + return html; + }, + controller: 'InventoryListController' + } + } + }); + + return Promise.all([ + inventories + ]).then((generated) => { + return { + states: _.reduce(generated, (result, definition) => { + return result.concat(definition.states); + }, [ + stateExtender.buildDefinition(smartInventoryAdd), + stateExtender.buildDefinition(smartInventoryAddOrgLookup) + ]) + }; + }); + + } + + $stateProvider.state({ + name: 'hosts', + url: '/hosts', + lazyLoad: () => stateDefinitions.generateTree({ parent: 'hosts', // top-most node in the generated tree (will replace this state definition) modes: ['edit'], list: 'HostsList', @@ -149,67 +203,13 @@ angular.module('inventory', [ controller: 'HostListController' } } - }); - - return Promise.all([ - hosts - ]).then((generated) => { - return { - states: _.reduce(generated, (result, definition) => { - return result.concat(definition.states); - }, [ - stateExtender.buildDefinition(smartInventoryAdd), - stateExtender.buildDefinition(smartInventoryAddOrgLookup) - ]) - }; - }); - - } - - $stateProvider.state({ - name: 'inventories', - url: '/inventories', - lazyLoad: () => stateDefinitions.generateTree({ - parent: 'inventories', // top-most node in the generated tree (will replace this state definition) - modes: ['add', 'edit'], - list: 'InventoryList', - form: 'InventoryForm', - controllers: { - list: 'InventoryListController', - add: 'InventoryAddController', - edit: 'InventoryEditController', - related: { - groups: 'GroupsListController' - } - }, - urls: { - list: '/inventories' - }, - ncyBreadcrumb: { - label: N_('INVENTORIES') - }, - views: { - '@': { - templateUrl: templateUrl('inventories/inventories') - }, - 'list@inventories': { - templateProvider: function(InventoryList, generateList) { - let html = generateList.build({ - list: InventoryList, - mode: 'edit' - }); - return html; - }, - controller: 'InventoryListController' - } - } }) }); $stateProvider.state({ - name: 'hosts', - url: '/hosts', - lazyLoad: () => generateHostStates() + name: 'inventories', + url: '/inventories', + lazyLoad: () => generateInventoryStates() }); } ]); 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 14797c26b3..ac2802d6f9 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 @@ -174,7 +174,9 @@ export default ['$compile', 'Attr', 'Icon', html += (!list.wellOverride) ? "List-well" : ""; html += `">`; // List actions - html += "