From 1e06e1d939b9617048d54bc92fd6c9ad67d89040 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Thu, 25 May 2017 17:06:43 -0400 Subject: [PATCH 1/3] Refactored a lot of the rbacUiControlService out of the controller and into the resolve block of the state --- awx/ui/client/legacy-styles/ansible-ui.less | 17 +- .../copy-move/copy-move-groups.controller.js | 33 ++- .../copy-move/copy-move-hosts.controller.js | 26 +- .../groups/list/groups-list.controller.js | 13 +- .../groups/list/groups-list.route.js | 9 + .../nested-groups-add.controller.js | 10 +- .../nested-groups/nested-groups-add.route.js | 11 + .../nested-groups-list.controller.js | 11 +- .../nested-groups/nested-groups.route.js | 9 + .../nested-hosts/nested-hosts-add.route.js | 11 + .../nested-hosts-list.controller.js | 11 +- .../groups/nested-hosts/nested-hosts.route.js | 9 + .../hosts/list/host-list.controller.js | 11 +- .../src/inventories/inventories.route.js | 11 +- .../client/src/inventories/inventory.list.js | 9 +- .../host-summary-popover.controller.js | 26 ++ .../host-summary-popover.directive.js | 94 ++++++ .../host-summary-popover.partial.html | 3 + .../list/host-summary-popover/main.js | 7 + .../list/inventory-list.controller.js | 274 +++--------------- awx/ui/client/src/inventories/list/main.js | 7 +- .../list/source-summary-popover/main.js | 7 + .../source-summary-popover.controller.js | 27 ++ .../source-summary-popover.directive.js | 98 +++++++ .../source-summary-popover.partial.html | 3 + awx/ui/client/src/inventories/main.js | 37 +++ .../related-hosts/add/host-add.controller.js | 11 +- .../list/host-list.controller.js | 11 +- .../related-hosts/related-host.route.js | 9 + .../add/smart-inventory-add.controller.js | 19 +- .../sources/add/sources-add.controller.js | 10 +- .../sources/add/sources-add.route.js | 11 + .../sources/edit/sources-edit.controller.js | 9 +- .../sources/edit/sources-edit.route.js | 9 + .../sources/list/sources-list.controller.js | 11 +- .../sources/list/sources-list.route.js | 9 + .../standard/add/inventory-add.controller.js | 19 +- .../organizations-inventories.controller.js | 4 - awx/ui/client/src/shared/generator-helpers.js | 192 ++++++------ .../src/smart-status/smart-status.block.less | 2 +- 40 files changed, 629 insertions(+), 481 deletions(-) create mode 100644 awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.controller.js create mode 100644 awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.directive.js create mode 100644 awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.partial.html create mode 100644 awx/ui/client/src/inventories/list/host-summary-popover/main.js create mode 100644 awx/ui/client/src/inventories/list/source-summary-popover/main.js create mode 100644 awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.controller.js create mode 100644 awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.directive.js create mode 100644 awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.partial.html diff --git a/awx/ui/client/legacy-styles/ansible-ui.less b/awx/ui/client/legacy-styles/ansible-ui.less index ad3cff4442..a3679b2142 100644 --- a/awx/ui/client/legacy-styles/ansible-ui.less +++ b/awx/ui/client/legacy-styles/ansible-ui.less @@ -1032,12 +1032,6 @@ input[type="checkbox"].checkbox-no-label { border-top: none; } -/* Less padding on .table-condensed */ -.table-condensed>tbody>tr>td, -.table-condensed>thead>tr>th { - padding: 0.5em 0.6em; -} - .table > tbody > tr > td{ padding: 0.5em 0.6em; &.actions{ @@ -1049,6 +1043,17 @@ input[type="checkbox"].checkbox-no-label { } } +/* Less padding on .table-condensed */ +.table-condensed>tbody>tr>td:not(:last-child), +.table-condensed>thead>tr>th:not(:last-child) { + padding: 0.5em 20px 0.5em 0px; +} + +.table-condensed>tbody>tr>td:last-child, +.table-condensed>thead>tr>th:last-child { + padding: 0.5em 0px; +} + .table.table-condensed.flyout { thead>tr>th { padding-left: 0; diff --git a/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js b/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js index d982560725..3dc0bc0a27 100644 --- a/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js +++ b/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js @@ -7,20 +7,34 @@ export default ['$scope', '$state', '$stateParams', 'GroupManageService', 'CopyMoveGroupList', 'group', 'Dataset', '$rootScope', function($scope, $state, $stateParams, GroupManageService, CopyMoveGroupList, group, Dataset, $rootScope){ - var list = CopyMoveGroupList; + let list = CopyMoveGroupList; + + function init(){ + $scope.atRootLevel = $stateParams.group ? false : true; + + // search init + $scope.list = list; + $scope[`${list.iterator}_dataset`] = Dataset.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + + $scope.item = group; + $rootScope.breadcrumb.copyMoveName = group.name; + $scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy'; + } + + init(); - $scope.item = group; - $rootScope.breadcrumb.copyMoveName = group.name; - $scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy'; $scope.toggle_row = function(id){ // toggle off anything else currently selected _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;}); // yoink the currently selected thing $scope.selected = _.find($scope.groups, (item) => {return item.id === id;}); }; + $scope.formCancel = function(){ $state.go('^'); }; + $scope.formSave = function(){ switch($scope.submitMode) { case 'copy': @@ -48,6 +62,7 @@ } } }; + $scope.toggleTargetRootGroup = function(){ $scope.selected = !$scope.selected; // cannot perform copy operations to root group level @@ -60,14 +75,4 @@ }); }; - function init(){ - $scope.atRootLevel = $stateParams.group ? false : true; - - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - } - - init(); }]; diff --git a/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js b/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js index 47120e472a..a31f51676a 100644 --- a/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js +++ b/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js @@ -7,11 +7,21 @@ export default ['$scope', '$state', '$stateParams', 'HostManageService', 'CopyMoveGroupList', 'host', 'Dataset', '$rootScope', function($scope, $state, $stateParams, HostManageService, CopyMoveGroupList, host, Dataset, $rootScope){ - var list = CopyMoveGroupList; + let list = CopyMoveGroupList; + + let init = function(){ + // search init + $scope.list = list; + $scope[`${list.iterator}_dataset`] = Dataset.data; + $scope[list.name] = $scope[`${list.iterator}_dataset`].results; + + $scope.item = host; + $rootScope.breadcrumb.copyMoveName = host.name; + $scope.submitMode = 'copy'; + }; + + init(); - $scope.item = host; - $rootScope.breadcrumb.copyMoveName = host.name; - $scope.submitMode = 'copy'; $scope.toggle_row = function(id){ // toggle off anything else currently selected _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;}); @@ -40,12 +50,4 @@ break; } }; - var init = function(){ - // search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - }; - init(); }]; diff --git a/awx/ui/client/src/inventories/groups/list/groups-list.controller.js b/awx/ui/client/src/inventories/groups/list/groups-list.controller.js index 35a6549289..c641419a98 100644 --- a/awx/ui/client/src/inventories/groups/list/groups-list.controller.js +++ b/awx/ui/client/src/inventories/groups/list/groups-list.controller.js @@ -6,10 +6,10 @@ export default ['$scope', '$rootScope', '$state', '$stateParams', 'GroupList', 'InventoryUpdate', 'GroupManageService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', + 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', function($scope, $rootScope, $state, $stateParams, GroupList, InventoryUpdate, GroupManageService, CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData){ + GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd){ let list = GroupList; @@ -18,12 +18,7 @@ function init(){ $scope.inventory_id = $stateParams.inventory_id; $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = false; - - rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; // Search init $scope.list = list; @@ -36,7 +31,7 @@ } $scope.inventory_id = $stateParams.inventory_id; - + $scope.$watchCollection(list.name, function(){ _.forEach($scope[list.name], buildStatusIndicators); }); diff --git a/awx/ui/client/src/inventories/groups/list/groups-list.route.js b/awx/ui/client/src/inventories/groups/list/groups-list.route.js index fb9ef19167..e03af1c325 100644 --- a/awx/ui/client/src/inventories/groups/list/groups-list.route.js +++ b/awx/ui/client/src/inventories/groups/list/groups-list.route.js @@ -20,6 +20,15 @@ export default { ], inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) { return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data); + }], + canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] }, params: { diff --git a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.controller.js b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.controller.js index 76e6d1329f..1d97263e82 100644 --- a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.controller.js +++ b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.controller.js @@ -7,11 +7,11 @@ export default ['$state', '$stateParams', '$scope', 'NestedGroupForm', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', - 'rbacUiControlService', 'ToJSON', + 'rbacUiControlService', 'ToJSON', 'canAdd', function($state, $stateParams, $scope, NestedGroupForm, ParseTypeChange, GenerateForm, inventoryData, GroupManageService, GetChoices, GetBasePath, CreateSelect2, rbacUiControlService, - ToJSON) { + ToJSON, canAdd) { let form = NestedGroupForm; init(); @@ -19,11 +19,7 @@ export default ['$state', '$stateParams', '$scope', 'NestedGroupForm', function init() { // apply form definition's default field values GenerateForm.applyDefaults(form, $scope); - - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; $scope.parseType = 'yaml'; $scope.envParseType = 'yaml'; ParseTypeChange({ diff --git a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.route.js b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.route.js index 78f866e2b9..90fe46817f 100644 --- a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.route.js +++ b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-add.route.js @@ -18,5 +18,16 @@ export default { }, controller: 'NestedGroupsAddController' } + }, + resolve: { + canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); + }] } }; diff --git a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-list.controller.js b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-list.controller.js index e5a72b9c2f..ee1a0cc2d3 100644 --- a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-list.controller.js +++ b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups-list.controller.js @@ -6,10 +6,10 @@ export default ['$scope', '$rootScope', '$state', '$stateParams', 'NestedGroupListDefinition', 'InventoryUpdate', 'GroupManageService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath', - 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', + 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd', function($scope, $rootScope, $state, $stateParams, NestedGroupListDefinition, InventoryUpdate, GroupManageService, CancelSourceUpdate, rbacUiControlService, GetBasePath, - GetHostsStatusMsg, Dataset, Find, qs, inventoryData){ + GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd){ let list = NestedGroupListDefinition; @@ -18,12 +18,7 @@ function init(){ $scope.inventory_id = $stateParams.inventory_id; $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = false; - - rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; // Search init $scope.list = list; diff --git a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups.route.js b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups.route.js index 433cabf0e9..a01c311f9c 100644 --- a/awx/ui/client/src/inventories/groups/nested-groups/nested-groups.route.js +++ b/awx/ui/client/src/inventories/groups/nested-groups/nested-groups.route.js @@ -59,6 +59,15 @@ export default { inventoryData: ['InventoryManageService', '$stateParams', 'host', function(InventoryManageService, $stateParams, host) { var id = ($stateParams.inventory_id) ? $stateParams.inventory_id : host.summary_fields.inventory.id; return InventoryManageService.getInventory(id).then(res => res.data); + }], + canAdd: ['rbacUiControlService', '$state', 'GetBasePath', '$stateParams', function(rbacUiControlService, $state, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] } }; diff --git a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-add.route.js b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-add.route.js index 2006735dde..3559192274 100644 --- a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-add.route.js +++ b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-add.route.js @@ -18,5 +18,16 @@ export default { }, controller: 'RelatedHostAddController' } + }, + resolve: { + canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/hosts") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); + }] } }; diff --git a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-list.controller.js b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-list.controller.js index ad3bc20b2b..813b99fee2 100644 --- a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-list.controller.js +++ b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts-list.controller.js @@ -6,24 +6,19 @@ export default ['$scope', 'NestedHostsListDefinition', '$rootScope', 'GetBasePath', 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostManageService', 'SetStatus', + 'HostManageService', 'SetStatus', 'canAdd', function($scope, NestedHostsListDefinition, $rootScope, GetBasePath, rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostManageService, SetStatus) { + HostManageService, SetStatus, canAdd) { let list = NestedHostsListDefinition; init(); function init(){ - $scope.canAdd = false; + $scope.canAdd = canAdd; $scope.enableSmartInventoryButton = false; - rbacUiControlService.canAdd('hosts') - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - // Search init $scope.list = list; $scope[`${list.iterator}_dataset`] = Dataset.data; diff --git a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts.route.js b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts.route.js index bbfa7d8a79..2182a522cf 100644 --- a/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts.route.js +++ b/awx/ui/client/src/inventories/groups/nested-hosts/nested-hosts.route.js @@ -53,6 +53,15 @@ export default { ], inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) { return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data); + }], + canAdd: ['rbacUiControlService', function(rbacUiControlService) { + return rbacUiControlService.canAdd('hosts') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] } }; 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 47c41f508d..e906052a79 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 @@ -7,21 +7,16 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath, rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostManageService, SetStatus) { + HostManageService, SetStatus, canAdd) { let list = HostsList; init(); function init(){ - $scope.canAdd = false; + $scope.canAdd = canAdd; $scope.enableSmartInventoryButton = false; - rbacUiControlService.canAdd('hosts') - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - // Search init $scope.list = list; $scope[`${list.iterator}_dataset`] = Dataset.data; @@ -141,5 +136,5 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath, export default ['$scope', 'HostsList', '$rootScope', 'GetBasePath', 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostManageService', 'SetStatus', HostsList + 'HostManageService', 'SetStatus', 'canAdd', HostsList ]; diff --git a/awx/ui/client/src/inventories/inventories.route.js b/awx/ui/client/src/inventories/inventories.route.js index 694f68e274..8b982100e7 100644 --- a/awx/ui/client/src/inventories/inventories.route.js +++ b/awx/ui/client/src/inventories/inventories.route.js @@ -29,6 +29,15 @@ export default { let path = GetBasePath(list.basePath) || GetBasePath(list.name); return qs.search(path, $stateParams[`${list.iterator}_search`]); } - ] + ], + canAdd: ['rbacUiControlService', function(rbacUiControlService) { + return rbacUiControlService.canAdd('inventory') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); + }] } }; diff --git a/awx/ui/client/src/inventories/inventory.list.js b/awx/ui/client/src/inventories/inventory.list.js index 9dfaa20a78..7399b02095 100644 --- a/awx/ui/client/src/inventories/inventory.list.js +++ b/awx/ui/client/src/inventories/inventory.list.js @@ -27,17 +27,20 @@ export default ['i18n', function(i18n) { ngClick: "null", iconOnly: true, excludeModal: true, + template: ``, icons: [{ icon: "{{ 'icon-cloud-' + inventory.syncStatus }}", awToolTip: "{{ inventory.syncTip }}", awTipPlacement: "right", ngClick: "showSourceSummary($event, inventory.id)", - ngClass: "inventory.launch_class" + ngClass: "inventory.launch_class", + extraTemplate: "" },{ icon: "{{ 'icon-job-' + inventory.hostsStatus }}", awToolTip: false, ngClick: "showHostSummary($event, inventory.id)", - ngClass: "inventory.host_status_class" + ngClass: "inventory.host_status_class", + extraTemplate: "" }] }, name: { @@ -85,7 +88,7 @@ export default ['i18n', function(i18n) { ngShow: 'canAddInventory' } ], - ngShow: 'canAddInventory || canAddSmartInventory || canAddSCMInventory' + ngShow: 'canAddInventory' } }, diff --git a/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.controller.js b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.controller.js new file mode 100644 index 0000000000..b48b91f0b5 --- /dev/null +++ b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.controller.js @@ -0,0 +1,26 @@ +export default [ '$scope', 'Empty', 'Wait', 'GetBasePath', 'Rest', 'ProcessErrors', + function($scope, Empty, Wait, GetBasePath, Rest, ProcessErrors) { + + $scope.gatherRecentJobs = function(event) { + if (!Empty($scope.inventory.id)) { + if ($scope.inventory.total_hosts > 0) { + Wait('start'); + let url = GetBasePath('jobs') + "?type=job&inventory=" + $scope.inventory.id + "&failed="; + url += ($scope.inventory.has_active_failures) ? "true" : "false"; + url += "&order_by=-finished&page_size=5"; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + $scope.generateTable(data, event); + }) + .error( function(data, status) { + ProcessErrors( $scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status + }); + }); + } + } + }; + + } +]; diff --git a/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.directive.js b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.directive.js new file mode 100644 index 0000000000..713d5041f2 --- /dev/null +++ b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.directive.js @@ -0,0 +1,94 @@ +export default ['templateUrl', 'Wait', '$filter', '$compile', + function(templateUrl, Wait, $filter, $compile) { + return { + restrict: 'E', + replace: false, + scope: { + inventory: '=' + }, + controller: 'HostSummaryPopoverController', + templateUrl: templateUrl('inventories/list/host-summary-popover/host-summary-popover'), + link: function(scope) { + + function ellipsis(a) { + if (a.length > 20) { + return a.substr(0,20) + '...'; + } + return a; + } + + function attachElem(event, html, title) { + var elem = $(event.target).parent(); + try { + elem.tooltip('hide'); + elem.popover('destroy'); + } + catch(err) { + //ignore + } + $('.popover').each(function() { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); + $('.tooltip').each( function() { + // close any lingering tool tipss + $(this).hide(); + }); + elem.attr({ + "aw-pop-over": html, + "data-popover-title": title, + "data-placement": "right" }); + elem.removeAttr('ng-click'); + $compile(elem)(scope); + scope.triggerPopover(event); + } + + scope.generateTable = function(data, event){ + var html, title = "Recent Jobs"; + Wait('stop'); + if (data.count > 0) { + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + html += "\n"; + + data.results.forEach(function(row) { + html += "\n"; + html += "\n"; + html += ""; + html += ""; + html += "\n"; + }); + html += "\n"; + html += "
StatusFinishedName
" + ($filter('longDate')(row.finished)) + "" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; + } + else { + html = "

No recent job data available for this inventory.

\n"; + } + attachElem(event, html, title); + }; + + scope.showHostSummary = function(event) { + try{ + var elem = $(event.target).parent(); + // if the popover is visible already, then exit the function here + if(elem.data()['bs.popover'].tip().hasClass('in')){ + return; + } + } + catch(err){ + scope.gatherRecentJobs(event); + } + }; + + } + }; + } +]; diff --git a/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.partial.html b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.partial.html new file mode 100644 index 0000000000..d990230dcb --- /dev/null +++ b/awx/ui/client/src/inventories/list/host-summary-popover/host-summary-popover.partial.html @@ -0,0 +1,3 @@ + + + diff --git a/awx/ui/client/src/inventories/list/host-summary-popover/main.js b/awx/ui/client/src/inventories/list/host-summary-popover/main.js new file mode 100644 index 0000000000..e2b88a1d06 --- /dev/null +++ b/awx/ui/client/src/inventories/list/host-summary-popover/main.js @@ -0,0 +1,7 @@ +import directive from './host-summary-popover.directive'; +import controller from './host-summary-popover.controller'; + +export default +angular.module('HostSummaryPopoverModule', []) + .directive('hostSummaryPopover', directive) + .controller('HostSummaryPopoverController', controller); 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 e853f13336..3bcfbb83a7 100644 --- a/awx/ui/client/src/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories/list/inventory-list.controller.js @@ -10,10 +10,10 @@ * @description This controller's for the Inventory page */ -function InventoriesList($scope, $rootScope, $location, - $compile, $filter, Rest, InventoryList, Prompt, - ProcessErrors, GetBasePath, Wait, Find, Empty, $state, - rbacUiControlService, Dataset, InventoryUpdate) { +function InventoriesList($scope, + $filter, Rest, InventoryList, Prompt, + ProcessErrors, GetBasePath, Wait, $state, + Dataset, InventoryUpdate, canAdd) { let list = InventoryList, defaultUrl = GetBasePath('inventory'); @@ -21,12 +21,7 @@ function InventoriesList($scope, $rootScope, $location, init(); function init(){ - $scope.canAdd = false; - - rbacUiControlService.canAdd('inventory') - .then(function(canAdd) { - $scope.canAddInventory = canAdd; - }); + $scope.canAddInventory = canAdd; $scope.$watchCollection(list.name, function(){ _.forEach($scope[list.name], processInventoryRow); @@ -36,230 +31,43 @@ function InventoriesList($scope, $rootScope, $location, $scope.list = list; $scope[`${list.iterator}_dataset`] = Dataset.data; $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - $rootScope.flashMessage = null; } function processInventoryRow(inventory) { - buildStatusIndicators(inventory); - buildInventoryTypeLabel(inventory); - } + inventory.launch_class = ""; + inventory.host_status_class = "Inventories-hostStatus"; - function buildStatusIndicators(inventory){ - inventory.launch_class = ""; - inventory.host_status_class = "Inventories-hostStatus"; - - if (inventory.has_inventory_sources) { - if (inventory.inventory_sources_with_failures > 0) { - inventory.syncStatus = 'error'; - inventory.syncTip = inventory.inventory_sources_with_failures + ' sources with sync failures. Click for details'; - } - else { - inventory.syncStatus = 'successful'; - inventory.syncTip = 'No inventory sync failures. Click for details.'; - } + if (inventory.has_inventory_sources) { + if (inventory.inventory_sources_with_failures > 0) { + inventory.syncStatus = 'error'; + inventory.syncTip = inventory.inventory_sources_with_failures + ' sources with sync failures. Click for details'; } else { - inventory.syncStatus = 'na'; - inventory.syncTip = 'Not configured for inventory sync.'; - inventory.launch_class = "btn-disabled"; + inventory.syncStatus = 'successful'; + inventory.syncTip = 'No inventory sync failures. Click for details.'; } - - if (inventory.has_active_failures) { - inventory.hostsStatus = 'error'; - inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.'; - } - else if (inventory.total_hosts) { - inventory.hostsStatus = 'successful'; - inventory.hostsTip = 'No hosts with failures. Click for details.'; - } - else { - inventory.hostsStatus = 'none'; - inventory.hostsTip = 'Inventory contains 0 hosts.'; - } - } - - function buildInventoryTypeLabel(inventory) { - inventory.kind_label = inventory.kind === '' ? 'Inventory' : (inventory.kind === 'smart' ? 'Smart Inventory': 'Inventory'); - } - - function ellipsis(a) { - if (a.length > 20) { - return a.substr(0,20) + '...'; - } - return a; - } - - function attachElem(event, html, title) { - var elem = $(event.target).parent(); - try { - elem.tooltip('hide'); - elem.popover('destroy'); - } - catch(err) { - //ignore - } - $('.popover').each(function() { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); - $('.tooltip').each( function() { - // close any lingering tool tipss - $(this).hide(); - }); - elem.attr({ - "aw-pop-over": html, - "data-popover-title": title, - "data-placement": "right" }); - elem.removeAttr('ng-click'); - $compile(elem)($scope); - $scope.triggerPopover(event); - } - if ($scope.removeHostSummaryReady) { - $scope.removeHostSummaryReady(); - } - $scope.removeHostSummaryReady = $scope.$on('HostSummaryReady', function(e, event, data) { - - var html, title = "Recent Jobs"; - Wait('stop'); - if (data.count > 0) { - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - html += "\n"; - - data.results.forEach(function(row) { - html += "\n"; - html += "\n"; - html += ""; - html += ""; - html += "\n"; - }); - html += "\n"; - html += "
StatusFinishedName
" + ($filter('longDate')(row.finished)).replace(/ /,'
') + "
" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; } else { - html = "

No recent job data available for this inventory.

\n"; + inventory.syncStatus = 'na'; + inventory.syncTip = 'Not configured for inventory sync.'; + inventory.launch_class = "btn-disabled"; } - attachElem(event, html, title); - }); - if ($scope.removeSourceSummaryReady) { - $scope.removeSourceSummaryReady(); + if (inventory.has_active_failures) { + inventory.hostsStatus = 'error'; + inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.'; + } + else if (inventory.total_hosts) { + inventory.hostsStatus = 'successful'; + inventory.hostsTip = 'No hosts with failures. Click for details.'; + } + else { + inventory.hostsStatus = 'none'; + inventory.hostsTip = 'Inventory contains 0 hosts.'; + } + + inventory.kind_label = inventory.kind === '' ? 'Inventory' : (inventory.kind === 'smart' ? 'Smart Inventory': 'Inventory'); } - $scope.removeSourceSummaryReady = $scope.$on('SourceSummaryReady', function(e, event, inventory, data) { - var html, title; - - Wait('stop'); - - // Build the html for our popover - html = "\n"; - html += "\n"; - html += ""; - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - html += "\n"; - data.results.forEach( function(row) { - if (row.related.last_update) { - html += ""; - html += ``; - html += ""; - html += ""; - html += "\n"; - } - else { - html += ""; - html += ""; - html += ""; - html += ""; - html += "\n"; - } - }); - html += "\n"; - html += "
StatusLast SyncSource
" + ($filter('longDate')(row.last_updated)).replace(/ /,'
') + "
" + $filter('sanitize')(ellipsis(row.name)) + "
NA" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; - title = "Sync Status"; - attachElem(event, html, title); - }); - - $scope.showSourceSummary = function(event, id) { - try{ - var elem = $(event.target).parent(); - // if the popover is visible already, then exit the function here - if(elem.data()['bs.popover'].tip().hasClass('in')){ - return; - } - } - catch(err){ - var inventory; - if (!Empty(id)) { - inventory = Find({ list: $scope.inventories, key: 'id', val: id }); - if (inventory.syncStatus !== 'na') { - Wait('start'); - Rest.setUrl(inventory.related.inventory_sources + '?order_by=-last_job_run&page_size=5'); - Rest.get() - .success(function(data) { - $scope.$emit('SourceSummaryReady', event, inventory, data); - }) - .error(function(data, status) { - ProcessErrors( $scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status - }); - }); - } - } - } - }; - - $scope.showHostSummary = function(event, id) { - try{ - var elem = $(event.target).parent(); - // if the popover is visible already, then exit the function here - if(elem.data()['bs.popover'].tip().hasClass('in')){ - return; - } - } - catch(err){ - var url, inventory; - if (!Empty(id)) { - inventory = Find({ list: $scope.inventories, key: 'id', val: id }); - if (inventory.total_hosts > 0) { - Wait('start'); - url = GetBasePath('jobs') + "?type=job&inventory=" + id + "&failed="; - url += (inventory.has_active_failures) ? 'true' : "false"; - url += "&order_by=-finished&page_size=5"; - Rest.setUrl(url); - Rest.get() - .success( function(data) { - $scope.$emit('HostSummaryReady', event, data); - }) - .error( function(data, status) { - ProcessErrors( $scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status - }); - }); - } - } - } - }; - - $scope.viewJob = function(url) { - - // Pull the id out of the URL - var id = url.replace(/^\//, '').split('/')[3]; - - $state.go('inventorySyncStdout', {id: id}); - - }; $scope.editInventory = function (inventory) { if(inventory.kind && inventory.kind === 'smart') { @@ -270,12 +78,7 @@ function InventoriesList($scope, $rootScope, $location, } }; - $scope.manageInventory = function(id){ - $location.path($location.path() + '/' + id + '/manage'); - }; - $scope.deleteInventory = function (id, name) { - var action = function () { var url = defaultUrl + id + '/'; Wait('start'); @@ -305,15 +108,6 @@ function InventoriesList($scope, $rootScope, $location, }); }; - // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status - $scope.viewJobs = function (id) { - $location.url('/jobs/?inventory__int=' + id); - }; - - $scope.viewFailedJobs = function (id) { - $location.url('/jobs/?inventory__int=' + id + '&status=failed'); - }; - $scope.syncInventory = function(inventory) { InventoryUpdate({ scope: $scope, @@ -323,8 +117,8 @@ function InventoriesList($scope, $rootScope, $location, }; } -export default ['$scope', '$rootScope', '$location', - '$compile', '$filter', 'Rest', 'InventoryList', 'Prompt', - 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', - '$state', 'rbacUiControlService', 'Dataset', 'InventoryUpdate', InventoriesList +export default ['$scope', + '$filter', 'Rest', 'InventoryList', 'Prompt', + 'ProcessErrors', 'GetBasePath', 'Wait', + '$state', 'Dataset', 'InventoryUpdate', 'canAdd', InventoriesList ]; diff --git a/awx/ui/client/src/inventories/list/main.js b/awx/ui/client/src/inventories/list/main.js index 11c6e4e694..4df9ff834f 100644 --- a/awx/ui/client/src/inventories/list/main.js +++ b/awx/ui/client/src/inventories/list/main.js @@ -5,7 +5,12 @@ *************************************************/ import controller from './inventory-list.controller'; +import hostSummaryPopover from './host-summary-popover/main'; +import sourceSummaryPopover from './source-summary-popover/main'; export default -angular.module('InventoryList', []) +angular.module('InventoryList', [ + hostSummaryPopover.name, + sourceSummaryPopover.name + ]) .controller('InventoryListController', controller); diff --git a/awx/ui/client/src/inventories/list/source-summary-popover/main.js b/awx/ui/client/src/inventories/list/source-summary-popover/main.js new file mode 100644 index 0000000000..4b6659f510 --- /dev/null +++ b/awx/ui/client/src/inventories/list/source-summary-popover/main.js @@ -0,0 +1,7 @@ +import directive from './source-summary-popover.directive'; +import controller from './source-summary-popover.controller'; + +export default +angular.module('SourceSummaryPopoverModule', []) + .directive('sourceSummaryPopover', directive) + .controller('SourceSummaryPopoverController', controller); diff --git a/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.controller.js b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.controller.js new file mode 100644 index 0000000000..0b32903df8 --- /dev/null +++ b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.controller.js @@ -0,0 +1,27 @@ +export default [ '$scope', 'Wait', 'Empty', 'Rest', 'ProcessErrors', '$state', + function($scope, Wait, Empty, Rest, ProcessErrors, $state) { + + $scope.gatherSourceJobs = function(event) { + if (!Empty($scope.inventory.id)) { + Wait('start'); + Rest.setUrl($scope.inventory.related.inventory_sources + '?order_by=-last_job_run&page_size=5'); + Rest.get() + .success(function(data) { + $scope.generateTable(data, event); + }) + .error(function(data, status) { + ProcessErrors( $scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + $scope.inventory.related.inventory_sources + ' failed. GET returned status: ' + status + }); + }); + } + }; + + $scope.viewJob = function(url) { + // Pull the id out of the URL + var id = url.replace(/^\//, '').split('/')[3]; + $state.go('inventorySyncStdout', {id: id}); + }; + + } +]; diff --git a/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.directive.js b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.directive.js new file mode 100644 index 0000000000..1d40d15593 --- /dev/null +++ b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.directive.js @@ -0,0 +1,98 @@ +export default ['templateUrl', '$compile', 'Wait', '$filter', + function(templateUrl, $compile, Wait, $filter) { + return { + restrict: 'E', + replace: false, + scope: { + inventory: '=' + }, + controller: 'SourceSummaryPopoverController', + templateUrl: templateUrl('inventories/list/source-summary-popover/source-summary-popover'), + link: function(scope) { + + function ellipsis(a) { + if (a.length > 20) { + return a.substr(0,20) + '...'; + } + return a; + } + + function attachElem(event, html, title) { + var elem = $(event.target).parent(); + try { + elem.tooltip('hide'); + elem.popover('destroy'); + } + catch(err) { + //ignore + } + $('.popover').each(function() { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); + $('.tooltip').each( function() { + // close any lingering tool tipss + $(this).hide(); + }); + elem.attr({ + "aw-pop-over": html, + "data-popover-title": title, + "data-placement": "right" }); + elem.removeAttr('ng-click'); + $compile(elem)(scope); + scope.triggerPopover(event); + } + + scope.generateTable = function(data, event) { + var html, title; + + Wait('stop'); + + // Build the html for our popover + html = "\n"; + html += "\n"; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + html += "\n"; + data.results.forEach( function(row) { + if (row.related.last_update) { + html += ""; + html += ``; + html += ""; + html += ""; + html += "\n"; + } + else { + html += ""; + html += ""; + html += ""; + html += ""; + html += "\n"; + } + }); + html += "\n"; + html += "
StatusLast SyncSource
" + ($filter('longDate')(row.last_updated)) + "" + $filter('sanitize')(ellipsis(row.name)) + "
NA" + $filter('sanitize')(ellipsis(row.name)) + "
\n"; + title = "Sync Status"; + attachElem(event, html, title); + }; + + scope.showSourceSummary = function(event) { + try{ + var elem = $(event.target).parent(); + // if the popover is visible already, then exit the function here + if(elem.data()['bs.popover'].tip().hasClass('in')){ + return; + } + } + catch(err){ + scope.gatherSourceJobs(event); + } + }; + } + }; + } +]; diff --git a/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.partial.html b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.partial.html new file mode 100644 index 0000000000..87fd35ef00 --- /dev/null +++ b/awx/ui/client/src/inventories/list/source-summary-popover/source-summary-popover.partial.html @@ -0,0 +1,3 @@ + + + diff --git a/awx/ui/client/src/inventories/main.js b/awx/ui/client/src/inventories/main.js index ae85f2fd54..5e361587d4 100644 --- a/awx/ui/client/src/inventories/main.js +++ b/awx/ui/client/src/inventories/main.js @@ -84,6 +84,19 @@ angular.module('inventory', [ form: 'InventoryForm', controllers: { add: 'InventoryAddController' + }, + resolve: { + add: { + canAdd: ['rbacUiControlService', '$state', function(rbacUiControlService, $state) { + return rbacUiControlService.canAdd('inventory') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + $state.go('inventories'); + }); + }] + } } }); @@ -107,6 +120,19 @@ angular.module('inventory', [ form: 'smartInventoryForm', controllers: { add: 'SmartInventoryAddController' + }, + resolve: { + add: { + canAdd: ['rbacUiControlService', '$state', function(rbacUiControlService, $state) { + return rbacUiControlService.canAdd('inventory') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + $state.go('inventories'); + }); + }] + } } }); @@ -268,6 +294,17 @@ angular.module('inventory', [ return Rest.get(); } ] + }, + list: { + canAdd: ['rbacUiControlService', function(rbacUiControlService) { + return rbacUiControlService.canAdd('hosts') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); + }] } }, views: { diff --git a/awx/ui/client/src/inventories/related-hosts/add/host-add.controller.js b/awx/ui/client/src/inventories/related-hosts/add/host-add.controller.js index 966d3c351b..1247d73979 100644 --- a/awx/ui/client/src/inventories/related-hosts/add/host-add.controller.js +++ b/awx/ui/client/src/inventories/related-hosts/add/host-add.controller.js @@ -5,19 +5,14 @@ *************************************************/ export default ['$state', '$stateParams', '$scope', 'RelatedHostsFormDefinition', 'ParseTypeChange', - 'GenerateForm', 'HostManageService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', + 'GenerateForm', 'HostManageService', 'rbacUiControlService', 'GetBasePath', 'ToJSON', 'canAdd', function($state, $stateParams, $scope, RelatedHostsFormDefinition, ParseTypeChange, - GenerateForm, HostManageService, rbacUiControlService, GetBasePath, ToJSON) { + GenerateForm, HostManageService, rbacUiControlService, GetBasePath, ToJSON, canAdd) { init(); function init() { - $scope.canAdd = false; - - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/hosts") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; $scope.parseType = 'yaml'; $scope.host = { enabled: true }; // apply form definition's default field values diff --git a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js index 6a9b41bbcb..b02c9cbf43 100644 --- a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js +++ b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js @@ -7,24 +7,19 @@ // import HostManageService from './../hosts/host.service'; export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath', 'rbacUiControlService', 'Dataset', '$state', '$filter', 'Prompt', 'Wait', - 'HostManageService', 'SetStatus', + 'HostManageService', 'SetStatus', 'canAdd', function($scope, ListDefinition, $rootScope, GetBasePath, rbacUiControlService, Dataset, $state, $filter, Prompt, Wait, - HostManageService, SetStatus) { + HostManageService, SetStatus, canAdd) { let list = ListDefinition; init(); function init(){ - $scope.canAdd = false; + $scope.canAdd = canAdd; $scope.enableSmartInventoryButton = false; - rbacUiControlService.canAdd('hosts') - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - // Search init $scope.list = list; $scope[`${list.iterator}_dataset`] = Dataset.data; diff --git a/awx/ui/client/src/inventories/related-hosts/related-host.route.js b/awx/ui/client/src/inventories/related-hosts/related-host.route.js index 9ffb1e5f5e..b3ea2da30c 100644 --- a/awx/ui/client/src/inventories/related-hosts/related-host.route.js +++ b/awx/ui/client/src/inventories/related-hosts/related-host.route.js @@ -69,6 +69,15 @@ export default { }], inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) { return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data); + }], + canAdd: ['rbacUiControlService', function(rbacUiControlService) { + return rbacUiControlService.canAdd('hosts') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] } }; diff --git a/awx/ui/client/src/inventories/smart-inventory/add/smart-inventory-add.controller.js b/awx/ui/client/src/inventories/smart-inventory/add/smart-inventory-add.controller.js index 9f044877c5..b390dbe606 100644 --- a/awx/ui/client/src/inventories/smart-inventory/add/smart-inventory-add.controller.js +++ b/awx/ui/client/src/inventories/smart-inventory/add/smart-inventory-add.controller.js @@ -13,22 +13,9 @@ function SmartInventoryAdd($scope, $location, GenerateForm, smartInventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON, - $state) { + $state, canAdd) { - $scope.canAdd = false; - rbacUiControlService.canAdd(GetBasePath('inventory')) - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); - - Rest.setUrl(GetBasePath('inventory')); - Rest.options() - .success(function(data) { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add an inventory.', 'alert-info'); - } - }); + $scope.canAdd = canAdd; ClearScope(); @@ -104,5 +91,5 @@ function SmartInventoryAdd($scope, $location, export default ['$scope', '$location', 'GenerateForm', 'smartInventoryForm', 'rbacUiControlService', 'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', - 'Wait', 'ToJSON', '$state', SmartInventoryAdd + 'Wait', 'ToJSON', '$state', 'canAdd', SmartInventoryAdd ]; diff --git a/awx/ui/client/src/inventories/sources/add/sources-add.controller.js b/awx/ui/client/src/inventories/sources/add/sources-add.controller.js index 806f850f4c..6f6430acf0 100644 --- a/awx/ui/client/src/inventories/sources/add/sources-add.controller.js +++ b/awx/ui/client/src/inventories/sources/add/sources-add.controller.js @@ -7,11 +7,11 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', - 'rbacUiControlService', 'ToJSON', 'SourcesService', + 'rbacUiControlService', 'ToJSON', 'SourcesService', 'canAdd', function($state, $stateParams, $scope, SourcesFormDefinition, ParseTypeChange, GenerateForm, inventoryData, GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, rbacUiControlService, - ToJSON, SourcesService) { + ToJSON, SourcesService, canAdd) { let form = SourcesFormDefinition; init(); @@ -19,11 +19,7 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', function init() { // apply form definition's default field values GenerateForm.applyDefaults(form, $scope); - - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; $scope.envParseType = 'yaml'; initSources(); } diff --git a/awx/ui/client/src/inventories/sources/add/sources-add.route.js b/awx/ui/client/src/inventories/sources/add/sources-add.route.js index 40b8bdcc75..bf5c878312 100644 --- a/awx/ui/client/src/inventories/sources/add/sources-add.route.js +++ b/awx/ui/client/src/inventories/sources/add/sources-add.route.js @@ -19,4 +19,15 @@ export default { controller: 'SourcesAddController' } }, + resolve: { + canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); + }] + } }; diff --git a/awx/ui/client/src/inventories/sources/edit/sources-edit.controller.js b/awx/ui/client/src/inventories/sources/edit/sources-edit.controller.js index 98517f9e56..af5e7a9f2d 100644 --- a/awx/ui/client/src/inventories/sources/edit/sources-edit.controller.js +++ b/awx/ui/client/src/inventories/sources/edit/sources-edit.controller.js @@ -7,19 +7,16 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', 'rbacUiControlService', 'ToJSON', 'ParseTypeChange', 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', - 'inventorySourceData', 'SourcesService', 'inventoryData', + 'inventorySourceData', 'SourcesService', 'inventoryData', 'canAdd', function($state, $stateParams, $scope, ParseVariableString, rbacUiControlService, ToJSON,ParseTypeChange, GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, - inventorySourceData, SourcesService, inventoryData) { + inventorySourceData, SourcesService, inventoryData, canAdd) { init(); function init() { - rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; // instantiate expected $scope values from inventorySourceData _.assign($scope, { credential: inventorySourceData.credential }, { overwrite: inventorySourceData.overwrite }, { overwrite_vars: inventorySourceData.overwrite_vars }, { update_on_launch: inventorySourceData.update_on_launch }, { update_cache_timeout: inventorySourceData.update_cache_timeout }, { instance_filters: inventorySourceData.instance_filters }, { inventory_script: inventorySourceData.source_script }); if (inventorySourceData.credential) { diff --git a/awx/ui/client/src/inventories/sources/edit/sources-edit.route.js b/awx/ui/client/src/inventories/sources/edit/sources-edit.route.js index 03904159da..21d289f1dc 100644 --- a/awx/ui/client/src/inventories/sources/edit/sources-edit.route.js +++ b/awx/ui/client/src/inventories/sources/edit/sources-edit.route.js @@ -22,6 +22,15 @@ export default { resolve: { inventorySourceData: ['$stateParams', 'SourcesService', function($stateParams, SourcesService) { return SourcesService.get({id: $stateParams.inventory_source_id }).then(res => res.data.results[0]); + }], + canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] } }; diff --git a/awx/ui/client/src/inventories/sources/list/sources-list.controller.js b/awx/ui/client/src/inventories/sources/list/sources-list.controller.js index 13a64a8305..94854187e7 100644 --- a/awx/ui/client/src/inventories/sources/list/sources-list.controller.js +++ b/awx/ui/client/src/inventories/sources/list/sources-list.controller.js @@ -8,12 +8,12 @@ 'InventoryUpdate', 'GroupManageService', 'CancelSourceUpdate', 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath', 'GetSyncStatusMsg', 'Dataset', 'Find', 'QuerySet', - 'inventoryData', '$filter', 'Prompt', 'Wait', 'SourcesService', 'inventorySourceOptions', + 'inventoryData', '$filter', 'Prompt', 'Wait', 'SourcesService', 'inventorySourceOptions', 'canAdd', function($scope, $rootScope, $state, $stateParams, SourcesListDefinition, InventoryUpdate, GroupManageService, CancelSourceUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath, GetSyncStatusMsg, Dataset, Find, qs, inventoryData, $filter, Prompt, - Wait, SourcesService, inventorySourceOptions){ + Wait, SourcesService, inventorySourceOptions, canAdd){ let list = SourcesListDefinition; @@ -22,12 +22,7 @@ function init(){ $scope.inventory_id = $stateParams.inventory_id; $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; - $scope.canAdd = false; - - rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups") - .then(function(canAdd) { - $scope.canAdd = canAdd; - }); + $scope.canAdd = canAdd; // Search init $scope.list = list; diff --git a/awx/ui/client/src/inventories/sources/list/sources-list.route.js b/awx/ui/client/src/inventories/sources/list/sources-list.route.js index b00085b824..1985469b0c 100644 --- a/awx/ui/client/src/inventories/sources/list/sources-list.route.js +++ b/awx/ui/client/src/inventories/sources/list/sources-list.route.js @@ -60,6 +60,15 @@ export default { ], inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams) { return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data); + }], + canAdd: ['rbacUiControlService', 'GetBasePath', '$stateParams', function(rbacUiControlService, GetBasePath, $stateParams) { + return rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/inventory_sources") + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + return false; + }); }] } }; diff --git a/awx/ui/client/src/inventories/standard/add/inventory-add.controller.js b/awx/ui/client/src/inventories/standard/add/inventory-add.controller.js index 7fb71a9edb..95748d99b7 100644 --- a/awx/ui/client/src/inventories/standard/add/inventory-add.controller.js +++ b/awx/ui/client/src/inventories/standard/add/inventory-add.controller.js @@ -13,22 +13,9 @@ function InventoriesAdd($scope, $location, GenerateForm, InventoryForm, rbacUiControlService, Rest, Alert, ProcessErrors, ClearScope, GetBasePath, ParseTypeChange, Wait, ToJSON, - $state) { + $state, canAdd) { - $scope.canAdd = false; - rbacUiControlService.canAdd(GetBasePath('inventory')) - .then(function(params) { - $scope.canAdd = params.canAdd; - }); - - Rest.setUrl(GetBasePath('inventory')); - Rest.options() - .success(function(data) { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add an inventory.', 'alert-info'); - } - }); + $scope.canAdd = canAdd; ClearScope(); @@ -98,5 +85,5 @@ function InventoriesAdd($scope, $location, export default ['$scope', '$location', 'GenerateForm', 'InventoryForm', 'rbacUiControlService', 'Rest', 'Alert', 'ProcessErrors', 'ClearScope', 'GetBasePath', 'ParseTypeChange', - 'Wait', 'ToJSON', '$state', InventoriesAdd + 'Wait', 'ToJSON', '$state', 'canAdd', InventoriesAdd ]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js index dba089c13b..cd2a8508df 100644 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js +++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-inventories.controller.js @@ -239,10 +239,6 @@ export default ['$scope', '$rootScope', '$location', $state.go('inventories.edit', { inventory_id: id }); }; - $scope.manageInventory = function(id) { - $location.path($location.path() + '/' + id + '/manage'); - }; - // Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status $scope.viewJobs = function(id) { $location.url('/jobs/?inventory__int=' + id); diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js index eddb7214e3..d88426422e 100644 --- a/awx/ui/client/src/shared/generator-helpers.js +++ b/awx/ui/client/src/shared/generator-helpers.js @@ -551,116 +551,128 @@ angular.module('GeneratorHelpers', [systemStatus.name]) html += (field.awEllipsis) ? "aw-ellipsis " : ""; html += ">\n"; - // Add ngShow - html += (field.ngShow) ? "" : ""; - - //Add ngHide - //html += (field.ngHide) ? "" : ""; - - // Badge - if (options.mode !== 'lookup' && (field.badges || (field.badgeIcon && field.badgePlacement && field.badgePlacement === 'left'))) { - html += Badge(field); + if(field.template) { + html += field.template; } + else { - // Add collapse/expand icon --used on job_events page - if (list.hasChildren && field.hasChildren) { - html += ""; - } + // Add ngShow + html += (field.ngShow) ? "" : ""; - if (list.name === 'groups') { - html += "
"; - } - if (list.name === 'hosts') { - html += "
"; - } + //Add ngHide + //html += (field.ngHide) ? "" : ""; - // Start the Link - if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref || field.awToolTip || field.awPopOver) && - options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) { - if(field.noLink === true){ - // provide an override here in case we want key=true for sorting purposes but don't want links -- see: portal mode, + // Badge + if (options.mode !== 'lookup' && (field.badges || (field.badgeIcon && field.badgePlacement && field.badgePlacement === 'left'))) { + html += Badge(field); } - else if (field.icons) { - field.icons.forEach(function(icon, idx) { - var key, i = field.icons[idx]; - for (key in i) { - field[key] = i[key]; - } + + // Add collapse/expand icon --used on job_events page + if (list.hasChildren && field.hasChildren) { + html += ""; + } + + if (list.name === 'groups') { + html += "
"; + } + if (list.name === 'hosts') { + html += "
"; + } + + // Start the Link + if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref || field.awToolTip || field.awPopOver) && + options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) { + if(field.noLink === true){ + // provide an override here in case we want key=true for sorting purposes but don't want links -- see: portal mode, + } + else if (field.icons) { + field.icons.forEach(function(icon, idx) { + var key, i = field.icons[idx]; + for (key in i) { + field[key] = i[key]; + }console.log(BuildLink({ + list: list, + field: field, + fld: fld, + base: field.linkBase || base + }) + ' '); + html += BuildLink({ + list: list, + field: field, + fld: fld, + base: field.linkBase || base + }) + ' '; + }); + } + else if(field.smartStatus){ + html += ''; + } + else { html += BuildLink({ list: list, field: field, fld: fld, base: field.linkBase || base - }) + ' '; - }); - } - else if(field.smartStatus){ - html += ''; + }); + } } else { - html += BuildLink({ - list: list, - field: field, - fld: fld, - base: field.linkBase || base - }); - } - } - else { - if(field.simpleTip) { - html += ``; - } - // Add icon: - if (field.ngShowIcon) { - html += " "; - } else if (field.icon) { - html += Icon(field.icon) + " "; - } - // Add data binds - if (!field.ngBindHtml && !field.iconOnly && (field.showValue === undefined || field.showValue === true)) { - if (field.ngBind) { - html += "{{ " + field.ngBind; - } else { - html += "{{ " + list.iterator + "." + fld; + if(field.simpleTip) { + html += ``; } - if (field.filter) { - html += " | " + field.filter + " }}"; + // Add icon: + if (field.ngShowIcon) { + html += " "; + } else if (field.icon) { + html += Icon(field.icon) + " "; } - else { - html += " }}"; + // Add data binds + if (!field.ngBindHtml && !field.iconOnly && (field.showValue === undefined || field.showValue === true)) { + if (field.ngBind) { + html += "{{ " + field.ngBind; + } else { + html += "{{ " + list.iterator + "." + fld; + } + if (field.filter) { + html += " | " + field.filter + " }}"; + } + else { + html += " }}"; + } + } + // Add additional text: + if (field.text) { + html += field.text; + } + if(field.simpleTip) { + html += ``; } } - // Add additional text: - if (field.text) { - html += field.text; + + if (list.name === 'hosts' || list.name === 'groups') { + html += "
"; } - if(field.simpleTip) { - html += ``; + + // close ngShow + html += (field.ngShow) ? "" : ""; + + //close ngHide + //html += (field.ngHide) ? "" : ""; + + // Specific to Job Events page -showing event detail/results + html += (field.appendHTML) ? "
\n" : ""; + + // Badge + if (options.mode !== 'lookup' && field.badgeIcon && field.badgePlacement && field.badgePlacement !== 'left') { + html += Badge(field); } } - if (list.name === 'hosts' || list.name === 'groups') { - html += "
"; - } - - // close ngShow - html += (field.ngShow) ? "
" : ""; - - //close ngHide - //html += (field.ngHide) ? "" : ""; - - // Specific to Job Events page -showing event detail/results - html += (field.appendHTML) ? "
\n" : ""; - - // Badge - if (options.mode !== 'lookup' && field.badgeIcon && field.badgePlacement && field.badgePlacement !== 'left') { - html += Badge(field); - } } return html += "\n"; }; diff --git a/awx/ui/client/src/smart-status/smart-status.block.less b/awx/ui/client/src/smart-status/smart-status.block.less index 233c4a839f..b09429243d 100644 --- a/awx/ui/client/src/smart-status/smart-status.block.less +++ b/awx/ui/client/src/smart-status/smart-status.block.less @@ -62,7 +62,7 @@ } -.SmartStatus-tooltip--failed{ +.SmartStatus-tooltip--error, .SmartStatus-tooltip--failed{ color: @default-err; padding-right: 0px; text-shadow: From e9f4c4f7b5ffdeb7868e21f9dac2736372cc9f6f Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Tue, 30 May 2017 13:43:43 -0400 Subject: [PATCH 2/3] Removed extraTemplate lines. They are not used --- awx/ui/client/src/inventories/inventory.list.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/inventories/inventory.list.js b/awx/ui/client/src/inventories/inventory.list.js index 7399b02095..c729768188 100644 --- a/awx/ui/client/src/inventories/inventory.list.js +++ b/awx/ui/client/src/inventories/inventory.list.js @@ -33,14 +33,12 @@ export default ['i18n', function(i18n) { awToolTip: "{{ inventory.syncTip }}", awTipPlacement: "right", ngClick: "showSourceSummary($event, inventory.id)", - ngClass: "inventory.launch_class", - extraTemplate: "" + ngClass: "inventory.launch_class" },{ icon: "{{ 'icon-job-' + inventory.hostsStatus }}", awToolTip: false, ngClick: "showHostSummary($event, inventory.id)", - ngClass: "inventory.host_status_class", - extraTemplate: "" + ngClass: "inventory.host_status_class" }] }, name: { From e8573179c5367b96811864551e4f9b0dfb040600 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Tue, 30 May 2017 14:12:57 -0400 Subject: [PATCH 3/3] Removed console.log --- awx/ui/client/src/shared/generator-helpers.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js index d88426422e..b2c2e2b30a 100644 --- a/awx/ui/client/src/shared/generator-helpers.js +++ b/awx/ui/client/src/shared/generator-helpers.js @@ -592,12 +592,7 @@ angular.module('GeneratorHelpers', [systemStatus.name]) var key, i = field.icons[idx]; for (key in i) { field[key] = i[key]; - }console.log(BuildLink({ - list: list, - field: field, - fld: fld, - base: field.linkBase || base - }) + ' '); + } html += BuildLink({ list: list, field: field,