From eff41000927ae5f5d179a649e8b33b9ae6908613 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Tue, 23 May 2017 17:37:49 -0400 Subject: [PATCH 1/2] Added sync button to inventory list. Added sync status icon back to inventory list (was there in previous releases. Added inventory source type to inventory source list. --- .../src/inventories/inventories.block.less | 3 ++ .../client/src/inventories/inventory.list.js | 17 +++++++- .../list/inventory-list.controller.js | 40 ++++++++++++------- .../sources/list/sources-list.controller.js | 28 ++++++++++++- .../sources/list/sources-list.route.js | 3 ++ .../src/inventories/sources/sources.list.js | 9 ++++- .../inventories/sources/sources.service.js | 7 ++++ .../inventory-update.factory.js | 36 ++++++++++++----- awx/ui/client/src/shared/generator-helpers.js | 3 ++ 9 files changed, 115 insertions(+), 31 deletions(-) create mode 100644 awx/ui/client/src/inventories/inventories.block.less diff --git a/awx/ui/client/src/inventories/inventories.block.less b/awx/ui/client/src/inventories/inventories.block.less new file mode 100644 index 0000000000..91727c2e7d --- /dev/null +++ b/awx/ui/client/src/inventories/inventories.block.less @@ -0,0 +1,3 @@ +.Inventories-hostStatus { + margin-left: 5px; +} diff --git a/awx/ui/client/src/inventories/inventory.list.js b/awx/ui/client/src/inventories/inventory.list.js index 201b9b9138..7535a31cce 100644 --- a/awx/ui/client/src/inventories/inventory.list.js +++ b/awx/ui/client/src/inventories/inventory.list.js @@ -22,16 +22,22 @@ export default ['i18n', function(i18n) { fields: { status: { label: '', - columnClass: 'col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus', + columnClass: 'List-staticColumn--mediumStatus', nosort: true, ngClick: "null", iconOnly: true, excludeModal: true, icons: [{ + icon: "{{ 'icon-cloud-' + inventory.syncStatus }}", + awToolTip: "{{ inventory.syncTip }}", + awTipPlacement: "right", + ngClick: "showSourceSummary($event, inventory.id)", + ngClass: "inventory.launch_class" + },{ icon: "{{ 'icon-job-' + inventory.hostsStatus }}", awToolTip: false, ngClick: "showHostSummary($event, inventory.id)", - ngClass: "" + ngClass: "inventory.host_status_class" }] }, name: { @@ -83,6 +89,13 @@ export default ['i18n', function(i18n) { columnClass: 'col-md-2 col-sm-4 col-xs-4', + inventory_update: { + mode: 'all', + ngClick: 'syncInventory(inventory)', + awToolTip: i18n._('Sync all inventory sources'), + ngShow: "inventory.kind === ''", + dataPlacement: "top", + }, edit: { label: i18n._('Edit'), ngClick: 'editInventory(inventory.id)', 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 0063b94fa4..baf410473e 100644 --- a/awx/ui/client/src/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories/list/inventory-list.controller.js @@ -12,7 +12,8 @@ function InventoriesList($scope, $rootScope, $location, $compile, $filter, Rest, InventoryList, Prompt, - ProcessErrors, GetBasePath, Wait, Find, Empty, $state, rbacUiControlService, Dataset) { + ProcessErrors, GetBasePath, Wait, Find, Empty, $state, + rbacUiControlService, Dataset, InventoryUpdate) { let list = InventoryList, defaultUrl = GetBasePath('inventory'); @@ -37,15 +38,16 @@ function InventoriesList($scope, $rootScope, $location, $scope[list.name] = $scope[`${list.iterator}_dataset`].results; $rootScope.flashMessage = null; - } 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 + ' groups with sync failures. Click for details'; + inventory.syncTip = inventory.inventory_sources_with_failures + ' sources with sync failures. Click for details'; } else { inventory.syncStatus = 'successful'; @@ -57,6 +59,7 @@ function InventoriesList($scope, $rootScope, $location, inventory.syncTip = 'Not configured for inventory sync.'; inventory.launch_class = "btn-disabled"; } + if (inventory.has_active_failures) { inventory.hostsStatus = 'error'; inventory.hostsTip = inventory.hosts_with_active_failures + ' hosts with failures. Click for details.'; @@ -139,10 +142,10 @@ function InventoriesList($scope, $rootScope, $location, attachElem(event, html, title); }); - if ($scope.removeGroupSummaryReady) { - $scope.removeGroupSummaryReady(); + if ($scope.removeSourceSummaryReady) { + $scope.removeSourceSummaryReady(); } - $scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) { + $scope.removeSourceSummaryReady = $scope.$on('SourceSummaryReady', function(e, event, inventory, data) { var html, title; Wait('stop'); @@ -153,7 +156,7 @@ function InventoriesList($scope, $rootScope, $location, html += ""; html += "Status"; html += "Last Sync"; - html += "Group"; + html += "Source"; html += ""; html += "\n"; html += "\n"; @@ -162,14 +165,14 @@ function InventoriesList($scope, $rootScope, $location, html += ""; html += ``; html += "" + ($filter('longDate')(row.last_updated)).replace(/ /,'
') + ""; - html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + ""; + html += "" + $filter('sanitize')(ellipsis(row.name)) + ""; html += "\n"; } else { html += ""; html += ""; html += "NA"; - html += "" + $filter('sanitize')(ellipsis(row.summary_fields.group.name)) + ""; + html += "" + $filter('sanitize')(ellipsis(row.name)) + ""; html += "\n"; } }); @@ -179,7 +182,7 @@ function InventoriesList($scope, $rootScope, $location, attachElem(event, html, title); }); - $scope.showGroupSummary = function(event, id) { + $scope.showSourceSummary = function(event, id) { try{ var elem = $(event.target).parent(); // if the popover is visible already, then exit the function here @@ -193,10 +196,10 @@ function InventoriesList($scope, $rootScope, $location, inventory = Find({ list: $scope.inventories, key: 'id', val: id }); if (inventory.syncStatus !== 'na') { Wait('start'); - Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5'); + Rest.setUrl(inventory.related.inventory_sources + '?order_by=-last_job_run&page_size=5'); Rest.get() .success(function(data) { - $scope.$emit('GroupSummaryReady', event, inventory, data); + $scope.$emit('SourceSummaryReady', event, inventory, data); }) .error(function(data, status) { ProcessErrors( $scope, data, status, null, { hdr: 'Error!', @@ -300,9 +303,18 @@ function InventoriesList($scope, $rootScope, $location, $scope.viewFailedJobs = function (id) { $location.url('/jobs/?inventory__int=' + id + '&status=failed'); }; + + $scope.syncInventory = function(inventory) { + InventoryUpdate({ + scope: $scope, + url: inventory.related.update_inventory_sources, + updateAllSources: true + }); + }; } export default ['$scope', '$rootScope', '$location', - '$compile', '$filter', 'Rest', 'InventoryList', - 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', 'Dataset', InventoriesList + '$compile', '$filter', 'Rest', 'InventoryList', 'Prompt', + 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', + '$state', 'rbacUiControlService', 'Dataset', 'InventoryUpdate', InventoriesList ]; 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 0e09051f16..09d3c3e4d1 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', + 'inventoryData', '$filter', 'Prompt', 'Wait', 'SourcesService', 'inventorySourceOptions', function($scope, $rootScope, $state, $stateParams, SourcesListDefinition, InventoryUpdate, GroupManageService, CancelSourceUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath, GetSyncStatusMsg, Dataset, Find, qs, inventoryData, $filter, Prompt, - Wait, SourcesService){ + Wait, SourcesService, inventorySourceOptions){ let list = SourcesListDefinition; @@ -36,6 +36,7 @@ $scope.inventory_id = $stateParams.inventory_id; _.forEach($scope[list.name], buildStatusIndicators); + optionsRequestDataProcessing(); $scope.$on(`ws-jobs`, function(e, data){ var inventory_source = Find({ list: $scope.inventory_sources, key: 'id', val: data.inventory_source_id }); @@ -52,6 +53,7 @@ $scope[`${list.iterator}_dataset`] = searchResponse.data; $scope[list.name] = $scope[`${list.iterator}_dataset`].results; _.forEach($scope[list.name], buildStatusIndicators); + optionsRequestDataProcessing(); }); } else { var status = GetSyncStatusMsg({ @@ -64,6 +66,28 @@ inventory_source.launch_class = status.launch_class; } }); + + $scope.$watchCollection(`${$scope.list.name}`, function() { + _.forEach($scope[list.name], buildStatusIndicators); + optionsRequestDataProcessing(); + }); + } + + function optionsRequestDataProcessing(){ + if ($scope[list.name] !== undefined) { + $scope[list.name].forEach(function(item, item_idx) { + var itm = $scope[list.name][item_idx]; + + // Set the item source label + if (list.fields.source && inventorySourceOptions && inventorySourceOptions.hasOwnProperty('source')) { + inventorySourceOptions.source.choices.forEach(function(choice) { + if (choice[0] === item.source) { + itm.source_label = choice[1]; + } + }); + } + }); + } } function buildStatusIndicators(inventory_source){ 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 73e7a1ffc9..b00085b824 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 @@ -42,6 +42,9 @@ export default { } }, resolve: { + inventorySourceOptions: ['SourcesService', (SourcesService) => { + return SourcesService.options().then(res => res.data.actions.GET); + }], Dataset: ['SourcesListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field diff --git a/awx/ui/client/src/inventories/sources/sources.list.js b/awx/ui/client/src/inventories/sources/sources.list.js index 38288bf04e..6e88931c65 100644 --- a/awx/ui/client/src/inventories/sources/sources.list.js +++ b/awx/ui/client/src/inventories/sources/sources.list.js @@ -33,8 +33,13 @@ export default { label: 'Sources', key: true, ngClick: "editSource(inventory_source.id)", - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6', + columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4', class: 'InventoryManage-breakWord', + }, + source: { + label: 'Type', + ngBind: 'inventory_source.source_label', + columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4' } }, @@ -60,7 +65,7 @@ export default { fieldActions: { - columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right', + columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-4 text-right', group_update: { //label: 'Sync', diff --git a/awx/ui/client/src/inventories/sources/sources.service.js b/awx/ui/client/src/inventories/sources/sources.service.js index a913951806..7544de056f 100644 --- a/awx/ui/client/src/inventories/sources/sources.service.js +++ b/awx/ui/client/src/inventories/sources/sources.service.js @@ -54,6 +54,13 @@ export default .error(this.error.bind(this)) .finally(Wait('stop')); }, + options: function(){ + this.url = GetBasePath('inventory_sources'); + Rest.setUrl(this.url); + return Rest.options() + .success(this.success.bind(this)) + .error(this.error.bind(this)); + }, getCredential: function(id){ Wait('start'); this.url = GetBasePath('credentials') + id; diff --git a/awx/ui/client/src/job-submission/job-submission-factories/inventory-update.factory.js b/awx/ui/client/src/job-submission/job-submission-factories/inventory-update.factory.js index 80e13c09d6..cb4c0bf983 100644 --- a/awx/ui/client/src/job-submission/job-submission-factories/inventory-update.factory.js +++ b/awx/ui/client/src/job-submission/job-submission-factories/inventory-update.factory.js @@ -43,19 +43,33 @@ export default Rest.setUrl(url); Rest.get() .success(function (data) { - inventory_source = data; - if (data.can_update) { - if (data.passwords_needed_to_update) { - Wait('stop'); - scope.$emit('PromptForPasswords'); - } - else { + if(params.updateAllSources) { + let userCanUpdateAllSources = true; + _.forEach(data, function(inventory_source){ + if (!inventory_source.can_update) { + userCanUpdateAllSources = false; + } + }); + + if(userCanUpdateAllSources) { scope.$emit('StartTheUpdate', {}); } - } else { - Wait('stop'); - Alert('Permission Denied', 'You do not have access to run the inventory sync. Please contact your system administrator.', - 'alert-danger'); + } + else { + inventory_source = data; + if (data.can_update) { + if (data.passwords_needed_to_update) { + Wait('stop'); + scope.$emit('PromptForPasswords'); + } + else { + scope.$emit('StartTheUpdate', {}); + } + } else { + Wait('stop'); + Alert('Permission Denied', 'You do not have access to run the inventory sync. Please contact your system administrator.', + 'alert-danger'); + } } }) .error(function (data, status) { diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js index d6c8f03c6d..eddb7214e3 100644 --- a/awx/ui/client/src/shared/generator-helpers.js +++ b/awx/ui/client/src/shared/generator-helpers.js @@ -134,6 +134,9 @@ angular.module('GeneratorHelpers', [systemStatus.name]) case 'group_update': icon = 'fa-refresh'; break; + case 'inventory_update': + icon = 'fa-refresh'; + break; case 'scm_update': icon = 'fa-cloud-download'; break; From 4a08ed333b2ca4a0f57685b5910f448b1840f2e0 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Wed, 24 May 2017 17:40:28 -0400 Subject: [PATCH 2/2] Only show sync button on inventories with sources --- awx/ui/client/src/inventories/inventory.list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/inventories/inventory.list.js b/awx/ui/client/src/inventories/inventory.list.js index 7535a31cce..52cf848d7b 100644 --- a/awx/ui/client/src/inventories/inventory.list.js +++ b/awx/ui/client/src/inventories/inventory.list.js @@ -93,7 +93,7 @@ export default ['i18n', function(i18n) { mode: 'all', ngClick: 'syncInventory(inventory)', awToolTip: i18n._('Sync all inventory sources'), - ngShow: "inventory.kind === ''", + ngShow: "inventory.kind === '' && inventory.has_inventory_sources", dataPlacement: "top", }, edit: {