diff --git a/awx/ui/client/legacy/styles/lists.less b/awx/ui/client/legacy/styles/lists.less
index 84514339de..4ca8c0a12a 100644
--- a/awx/ui/client/legacy/styles/lists.less
+++ b/awx/ui/client/legacy/styles/lists.less
@@ -219,7 +219,7 @@ table, tbody {
}
.List-actionHolder--leftAlign {
- margin-left: 52%;
+ margin-left: 50%;
justify-content: flex-start;
button {
height: 34px;
@@ -230,6 +230,15 @@ table, tbody {
align-items: center;
display: flex;
margin-bottom: -34px;
+
+ .List-buttonDefault {
+ margin-left: 20px;
+ }
+
+ .List-toggleButton {
+ height: 30px;
+ line-height: 14px;
+ }
}
.List-auxAction {
@@ -272,6 +281,10 @@ table, tbody {
opacity: 0.65;
}
+.List-actionButton {
+ margin-left: 20px;
+}
+
.List-searchDropdown {
border-top-left-radius: 5px!important;
border-bottom-left-radius: 5px!important;
diff --git a/awx/ui/client/src/inventories-hosts/inventories/main.js b/awx/ui/client/src/inventories-hosts/inventories/main.js
index 923d3ef1fe..a3160d7b1f 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/main.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/main.js
@@ -3,6 +3,7 @@
*
* All Rights Reserved
*************************************************/
+import { N_ } from '../../i18n';
import adhoc from './adhoc/main';
import group from './related/groups/main';
@@ -294,6 +295,78 @@ angular.module('inventory', [
let relatedHostCompletedJobs = _.cloneDeep(hostCompletedJobsRoute);
relatedHostCompletedJobs.name = 'inventories.edit.hosts.edit.completed_jobs';
+ let inventoryRootGroupsList = _.cloneDeep(inventoryGroupsList);
+ inventoryRootGroupsList.name = "inventories.edit.rootGroups";
+ inventoryRootGroupsList.url = "/root_groups?{group_search:queryset}",
+ inventoryRootGroupsList.ncyBreadcrumb.label = N_("ROOT GROUPS");// jshint ignore:line
+ inventoryRootGroupsList.resolve.listDefinition = ['GroupList', (list) => {
+ const rootGroupList = _.cloneDeep(list);
+ rootGroupList.basePath = 'api/v2/inventories/{{$stateParams.inventory_id}}/root_groups/';
+ rootGroupList.fields.name.uiSref = "inventories.edit.rootGroups.edit({group_id:group.id})";
+ return rootGroupList;
+ }];
+
+ let inventoryRootGroupsAdd = _.cloneDeep(inventoryGroupsAdd);
+ inventoryRootGroupsAdd.name = "inventories.edit.rootGroups.add";
+ inventoryRootGroupsAdd.ncyBreadcrumb.parent = "inventories.edit.rootGroups";
+
+ let inventoryRootGroupsEdit = _.cloneDeep(inventoryGroupsEdit);
+ inventoryRootGroupsEdit.name = "inventories.edit.rootGroups.edit";
+ inventoryRootGroupsEdit.ncyBreadcrumb.parent = "inventories.edit.rootGroups";
+ inventoryRootGroupsEdit.views = {
+ 'groupForm@inventories': {
+ templateProvider: function(GenerateForm, GroupForm) {
+ let form = _.cloneDeep(GroupForm);
+ form.activeEditState = 'inventories.edit.rootGroups.edit';
+ form.detailsClick = "$state.go('inventories.edit.rootGroups.edit')";
+ form.parent = 'inventories.edit.rootGroups';
+ form.related.nested_groups.ngClick = "$state.go('inventories.edit.rootGroups.edit.nested_groups')";
+ form.related.nested_hosts.ngClick = "$state.go('inventories.edit.rootGroups.edit.nested_hosts')";
+
+ return GenerateForm.buildHTML(form, {
+ mode: 'edit',
+ related: false
+ });
+ },
+ controller: 'GroupEditController'
+ }
+ };
+ inventoryGroupsEdit.views = {
+ 'groupForm@inventories': {
+ templateProvider: function(GenerateForm, GroupForm) {
+ let form = GroupForm;
+
+ return GenerateForm.buildHTML(form, {
+ mode: 'edit',
+ related: false
+ });
+ },
+ controller: 'GroupEditController'
+ }
+ };
+
+ let rootGroupNestedGroupsRoute = _.cloneDeep(groupNestedGroupsRoute);
+ rootGroupNestedGroupsRoute.name = 'inventories.edit.rootGroups.edit.nested_groups';
+ rootGroupNestedGroupsRoute.ncyBreadcrumb.parent = "inventories.edit.rootGroups.edit";
+
+ let rootNestedGroupsAdd = _.cloneDeep(nestedGroupsAdd);
+ rootNestedGroupsAdd.name = "inventories.edit.rootGroups.edit.nested_groups.add";
+ rootNestedGroupsAdd.ncyBreadcrumb.parent = "inventories.edit.groups.edit.nested_groups";
+
+ let rootGroupNestedGroupsAssociateRoute = _.cloneDeep(groupNestedGroupsAssociateRoute);
+ rootGroupNestedGroupsAssociateRoute.name = 'inventories.edit.rootGroups.edit.nested_groups.associate';
+
+ let rootGroupNestedHostsRoute = _.cloneDeep(nestedHostsRoute);
+ rootGroupNestedHostsRoute.name = 'inventories.edit.rootGroups.edit.nested_hosts';
+ rootGroupNestedHostsRoute.ncyBreadcrumb.parent = "inventories.edit.rootGroups.edit";
+
+ let rootNestedHostsAdd = _.cloneDeep(nestedHostsAddRoute);
+ rootNestedHostsAdd.name = "inventories.edit.rootGroups.edit.nested_hosts.add";
+ rootNestedHostsAdd.ncyBreadcrumb.parent = "inventories.edit.rootGroups.edit.nested_hosts";
+
+ let rootGroupNestedHostsAssociateRoute = _.cloneDeep(nestedHostsAssociateRoute);
+ rootGroupNestedHostsAssociateRoute.name = 'inventories.edit.rootGroups.edit.nested_hosts.associate';
+
return Promise.all([
standardInventoryAdd,
standardInventoryEdit,
@@ -315,10 +388,16 @@ angular.module('inventory', [
stateExtender.buildDefinition(relatedHostsAnsibleFacts),
stateExtender.buildDefinition(relatedHostsInsights),
stateExtender.buildDefinition(inventoryGroupsList),
+ stateExtender.buildDefinition(inventoryRootGroupsList),
stateExtender.buildDefinition(inventoryGroupsAdd),
+ stateExtender.buildDefinition(rootNestedGroupsAdd),
+ stateExtender.buildDefinition(inventoryRootGroupsAdd),
stateExtender.buildDefinition(inventoryGroupsEdit),
+ stateExtender.buildDefinition(inventoryRootGroupsEdit),
stateExtender.buildDefinition(groupNestedGroupsRoute),
+ stateExtender.buildDefinition(rootGroupNestedGroupsRoute),
stateExtender.buildDefinition(nestedHostsRoute),
+ stateExtender.buildDefinition(rootGroupNestedHostsRoute),
stateExtender.buildDefinition(inventoryHosts),
stateExtender.buildDefinition(smartInventoryHosts),
stateExtender.buildDefinition(inventoryHostsAdd),
@@ -338,10 +417,13 @@ angular.module('inventory', [
stateExtender.buildDefinition(addSourceProject),
stateExtender.buildDefinition(editSourceProject),
stateExtender.buildDefinition(groupNestedGroupsAssociateRoute),
+ stateExtender.buildDefinition(rootGroupNestedGroupsAssociateRoute),
stateExtender.buildDefinition(hostNestedGroupsAssociateRoute),
stateExtender.buildDefinition(nestedHostsAssociateRoute),
+ stateExtender.buildDefinition(rootGroupNestedHostsAssociateRoute),
stateExtender.buildDefinition(nestedGroupsAdd),
stateExtender.buildDefinition(nestedHostsAddRoute),
+ stateExtender.buildDefinition(rootNestedHostsAdd),
stateExtender.buildDefinition(relatedHostCompletedJobs)
])
};
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js
index 0fbdd763c7..6d1a670168 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/edit/groups-edit.route.js
@@ -5,18 +5,6 @@ export default {
parent: "inventories.edit.groups",
label: "{{breadcrumb.group_name}}"
},
- views: {
- 'groupForm@inventories': {
- templateProvider: function(GenerateForm, GroupForm) {
- let form = GroupForm;
- return GenerateForm.buildHTML(form, {
- mode: 'edit',
- related: false
- });
- },
- controller: 'GroupEditController'
- }
- },
resolve: {
groupData: ['$stateParams', 'GroupsService', function($stateParams, GroupsService) {
return GroupsService.get({ id: $stateParams.group_id }).then(response => response.data.results[0]);
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js
index 1e4c055741..74448958b0 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.form.js
@@ -98,7 +98,6 @@ function(i18n){
title: i18n._('Hosts'),
iterator: 'nested_hosts'
},
-
}
};
}];
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js
index cc316a16aa..895bfe5687 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/groups.list.js
@@ -52,6 +52,22 @@
actionClass: 'btn List-buttonDefault',
buttonContent: i18n._('REFRESH')
},
+ groupsToggle: {
+ mode: 'all',
+ type: 'toggle',
+ buttons: [
+ {
+ text: i18n._('ALL GROUPS'),
+ ngClick: "$state.go('inventories.edit.groups')",
+ ngClass: "{'btn-primary': $state.includes('inventories.edit.groups'), 'Button-primary--hollow': $state.includes('inventories.edit.rootGroups')}"
+ },
+ {
+ text: i18n._('ROOT GROUPS'),
+ ngClick: "$state.go('inventories.edit.rootGroups')",
+ ngClass: "{'btn-primary': $state.includes('inventories.edit.rootGroups'), 'Button-primary--hollow': $state.includes('inventories.edit.groups')}"
+ }
+ ]
+ },
launch: {
mode: 'all',
ngDisabled: '!groupsSelected',
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js
index daf0ab3e81..e439fab391 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.controller.js
@@ -4,20 +4,21 @@
* All Rights Reserved
*************************************************/
export default
- ['$scope', '$rootScope', '$state', '$stateParams', 'GroupList', 'InventoryUpdate',
- 'GroupsService', 'CancelSourceUpdate', 'rbacUiControlService', 'GetBasePath',
- 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', 'canAdd',
+ ['$scope', '$state', '$stateParams', 'listDefinition', 'InventoryUpdate',
+ 'GroupsService', 'CancelSourceUpdate',
+ 'GetHostsStatusMsg', 'Dataset', 'inventoryData', 'canAdd',
'InventoryHostsStrings', '$transitions',
- function($scope, $rootScope, $state, $stateParams, GroupList, InventoryUpdate,
- GroupsService, CancelSourceUpdate, rbacUiControlService, GetBasePath,
- GetHostsStatusMsg, Dataset, Find, qs, inventoryData, canAdd,
+ function($scope, $state, $stateParams, listDefinition, InventoryUpdate,
+ GroupsService, CancelSourceUpdate,
+ GetHostsStatusMsg, Dataset, inventoryData, canAdd,
InventoryHostsStrings, $transitions){
- let list = GroupList;
+ let list = listDefinition;
init();
function init(){
+ $scope.showOnlyRootGroups = true;
$scope.inventory_id = $stateParams.inventory_id;
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
$scope.canAdd = canAdd;
@@ -85,10 +86,18 @@
}
$scope.createGroup = function(){
- $state.go('inventories.edit.groups.add');
+ if ($state.includes('inventories.edit.groups')) {
+ $state.go('inventories.edit.groups.add');
+ } else if ($state.includes('inventories.edit.rootGroups')) {
+ $state.go('inventories.edit.rootGroups.add');
+ }
};
$scope.editGroup = function(id){
- $state.go('inventories.edit.groups.edit', {group_id: id});
+ if ($state.includes('inventories.edit.groups')) {
+ $state.go('inventories.edit.groups.edit', {group_id: id});
+ } else if ($state.includes('inventories.edit.rootGroups')) {
+ $state.go('inventories.edit.rootGroups.edit', {group_id: id});
+ }
};
$scope.goToGroupGroups = function(id){
$state.go('inventories.edit.groups.edit.nested_groups', {group_id: id});
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js
index c16e9ba2a1..2ad7a90a0a 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/list/groups-list.route.js
@@ -5,7 +5,8 @@ export default {
name: "inventories.edit.groups",
url: "/groups?{group_search:queryset}",
resolve: {
- Dataset: ['GroupList', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
+ listDefinition: ['GroupList', (list) => list],
+ Dataset: ['listDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope',
(list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => {
// allow related list definitions to use interpolated $rootScope / $stateParams in basePath field
let path, interpolator;
@@ -43,12 +44,12 @@ export default {
},
ncyBreadcrumb: {
parent: "inventories.edit",
- label: N_("GROUPS")
+ label: N_("ALL GROUPS")
},
views: {
'related': {
- templateProvider: function(GroupList, generateList, $templateRequest, $stateParams, GetBasePath) {
- let list = _.cloneDeep(GroupList);
+ templateProvider: function(listDefinition, generateList, $templateRequest, $stateParams, GetBasePath) {
+ let list = _.cloneDeep(listDefinition);
if($stateParams && $stateParams.group) {
list.basePath = GetBasePath('groups') + _.last($stateParams.group) + '/children';
}
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js
index 6f8f86e860..0df6fdc481 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js
@@ -6,7 +6,7 @@ export default {
skip:true
},
views: {
- 'modal@inventories.edit.groups.edit': {
+ 'modal@^.^': {
templateProvider: function() {
return ``;
},
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js
index 88d8eb04ed..65961998d6 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-list.controller.js
@@ -127,7 +127,11 @@
};
$scope.editGroup = function(id){
- $state.go('inventories.edit.groups.edit', {group_id: id});
+ if ($state.includes('inventories.edit.groups')) {
+ $state.go('inventories.edit.groups.edit', {group_id: id});
+ } else if ($state.includes('inventories.edit.rootGroups')) {
+ $state.go('inventories.edit.rootGroups.edit', {group_id: id});
+ }
};
$scope.goToGroupGroups = function(id){
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js
index 1d1ad65388..220a5a4285 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js
@@ -6,7 +6,7 @@ export default {
skip:true
},
views: {
- 'modal@inventories.edit.groups.edit': {
+ 'modal@^.^': {
templateProvider: function() {
return ``;
},
diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
index d78dae4e49..7e8083bf48 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
@@ -149,6 +149,7 @@ function(i18n) {
include: "GroupList",
title: i18n._('Groups'),
iterator: 'group',
+ tabSelected: `$state.includes('inventories.edit.groups') || $state.includes('inventories.edit.rootGroups')`,
skipGenerator: true
},
hosts: {
diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js
index 0e484f5f00..c1b4d7f35f 100644
--- a/awx/ui/client/src/shared/form-generator.js
+++ b/awx/ui/client/src/shared/form-generator.js
@@ -1469,7 +1469,13 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
`aw-tip-placement="${collection.dataPlacement}" ` +
`data-tip-watch="${collection.dataTipWatch}" `;
}
- let relatedTabSelected = this.form.activeEditState ? `$state.includes('${this.form.activeEditState}.${itm}') || $state.includes('${this.form.stateTree}.edit.${itm}')` : `$state.includes('${this.form.stateTree}.edit.${itm}')`;
+ let relatedTabSelected;
+ if (this.form.related[itm].tabSelected) {
+ relatedTabSelected = this.form.related[itm].tabSelected;
+ } else {
+ relatedTabSelected = this.form.activeEditState ? `$state.includes('${this.form.activeEditState}.${itm}') || $state.includes('${this.form.stateTree}.edit.${itm}')` : `$state.includes('${this.form.stateTree}.edit.${itm}')`;
+ }
+
html += `ng-class="{'is-selected' : ${relatedTabSelected}` ;
if(this.form.related[itm].disabled){
html += `, 'Form-tab--disabled' : ${this.form.related[itm].disabled }`;
diff --git a/awx/ui/client/src/shared/list-generator/list-actions.partial.html b/awx/ui/client/src/shared/list-generator/list-actions.partial.html
index d2552b7b2c..88b2ab5b01 100644
--- a/awx/ui/client/src/shared/list-generator/list-actions.partial.html
+++ b/awx/ui/client/src/shared/list-generator/list-actions.partial.html
@@ -1,6 +1,9 @@
-
+
+
+
+