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 += "| Status | ";
+ html += "Finished | ";
+ html += "Name | ";
+ html += "
\n";
+ html += "\n";
+ html += "\n";
+
+ data.results.forEach(function(row) {
+ html += "\n";
+ html += " | \n";
+ html += "" + ($filter('longDate')(row.finished)) + " | ";
+ html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
+ html += "
\n";
+ });
+ html += "\n";
+ html += "
\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 += "| Status | ";
- html += "Finished | ";
- html += "Name | ";
- html += "
\n";
- html += "\n";
- html += "\n";
-
- data.results.forEach(function(row) {
- html += "\n";
- html += " | \n";
- html += "" + ($filter('longDate')(row.finished)).replace(/ /,' ') + " | ";
- html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
- html += "
\n";
- });
- html += "\n";
- html += "
\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 += "| Status | ";
- html += "Last Sync | ";
- html += "Source | ";
- html += "
";
- html += "\n";
- html += "\n";
- data.results.forEach( function(row) {
- if (row.related.last_update) {
- html += "";
- html += ` | `;
- html += "" + ($filter('longDate')(row.last_updated)).replace(/ /,' ') + " | ";
- html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
- html += "
\n";
- }
- else {
- html += "";
- html += " | ";
- html += "NA | ";
- html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
- html += "
\n";
- }
- });
- html += "\n";
- html += "
\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 += "| Status | ";
+ html += "Last Sync | ";
+ html += "Source | ";
+ html += "
";
+ html += "\n";
+ html += "\n";
+ data.results.forEach( function(row) {
+ if (row.related.last_update) {
+ html += "";
+ html += ` | `;
+ html += "" + ($filter('longDate')(row.last_updated)) + " | ";
+ html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
+ html += "
\n";
+ }
+ else {
+ html += "";
+ html += " | ";
+ html += "NA | ";
+ html += "" + $filter('sanitize')(ellipsis(row.name)) + " | ";
+ html += "
\n";
+ }
+ });
+ html += "\n";
+ html += "
\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: