From b85614082e125ac6ad059cabff8c987913043549 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Wed, 12 Apr 2017 11:25:47 -0700 Subject: [PATCH] Adding group add and group edit routes back in --- .../add/build-groups-add-state.factory.js | 46 +++ .../groups/add/groups-add.controller.js | 225 ++++++++++++ .../client/src/inventories/groups/add/main.js | 13 + .../groups/edit/groups-edit.controller.js | 247 +++++++++++++ .../src/inventories/groups/edit/main.js | 13 + .../src/inventories/groups/groups.form.js | 339 ++++++++++++++++++ ...nventory-groups.list.js => groups.list.js} | 0 .../list/build-groups-list-state.factory.js | 31 +- .../groups/list/group-list.controller.js | 236 ------------ .../groups/list/groups-list.controller.js | 10 +- .../src/inventories/groups/list/main.js | 8 +- awx/ui/client/src/inventories/groups/main.js | 10 +- .../src/inventories/inventories.partial.html | 1 + .../client/src/inventories/inventory.form.js | 10 +- .../src/shared/stateDefinitions.factory.js | 9 +- 15 files changed, 917 insertions(+), 281 deletions(-) create mode 100644 awx/ui/client/src/inventories/groups/add/build-groups-add-state.factory.js create mode 100644 awx/ui/client/src/inventories/groups/add/groups-add.controller.js create mode 100644 awx/ui/client/src/inventories/groups/add/main.js create mode 100644 awx/ui/client/src/inventories/groups/edit/groups-edit.controller.js create mode 100644 awx/ui/client/src/inventories/groups/edit/main.js create mode 100644 awx/ui/client/src/inventories/groups/groups.form.js rename awx/ui/client/src/inventories/groups/{list/inventory-groups.list.js => groups.list.js} (100%) delete mode 100644 awx/ui/client/src/inventories/groups/list/group-list.controller.js diff --git a/awx/ui/client/src/inventories/groups/add/build-groups-add-state.factory.js b/awx/ui/client/src/inventories/groups/add/build-groups-add-state.factory.js new file mode 100644 index 0000000000..e44130ce22 --- /dev/null +++ b/awx/ui/client/src/inventories/groups/add/build-groups-add-state.factory.js @@ -0,0 +1,46 @@ +/************************************************* +* Copyright (c) 2017 Ansible, Inc. +* +* All Rights Reserved +*************************************************/ + +import GroupAddController from './groups-add.controller'; + +export default ['$stateExtender', 'templateUrl', '$injector', + function($stateExtender, templateUrl, $injector){ + var val = function(field, formStateDefinition, params) { + let state, + list = field.include ? $injector.get(field.include) : field, + breadcrumbLabel = (field.iterator.replace('_', ' ') + 's').toUpperCase(), + stateConfig = { + name: `${formStateDefinition.name}.${list.iterator}s.add`, + url: `/add`, + ncyBreadcrumb: { + parent: `${formStateDefinition.name}`, + label: `${breadcrumbLabel}` + }, + views: { + 'groupForm@inventories': { + templateProvider: function(GenerateForm, GroupForm) { + let form = GroupForm; + return GenerateForm.buildHTML(form, { + mode: 'add', + related: false + }); + }, + controller: GroupAddController + } + }, + resolve: { + 'FormDefinition': [params.form, function(definition) { + return definition; + }] + } + }; + + state = $stateExtender.buildDefinition(stateConfig); + return state; + }; + return val; + } +]; diff --git a/awx/ui/client/src/inventories/groups/add/groups-add.controller.js b/awx/ui/client/src/inventories/groups/add/groups-add.controller.js new file mode 100644 index 0000000000..818e1890d2 --- /dev/null +++ b/awx/ui/client/src/inventories/groups/add/groups-add.controller.js @@ -0,0 +1,225 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$state', '$stateParams', '$scope', 'GroupForm', + 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'GroupManageService', + 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', + 'rbacUiControlService', 'ToJSON', + function($state, $stateParams, $scope, GroupForm, ParseTypeChange, + GenerateForm, inventoryData, GroupManageService, GetChoices, + GetBasePath, CreateSelect2, GetSourceTypeOptions, rbacUiControlService, + ToJSON) { + + let form = GroupForm; + init(); + + 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.parseType = 'yaml'; + $scope.envParseType = 'yaml'; + ParseTypeChange({ + scope: $scope, + field_id: 'group_variables', + variable: 'variables', + }); + initSources(); + } + + $scope.lookupCredential = function(){ + let kind = ($scope.source.value === "ec2") ? "aws" : $scope.source.value; + $state.go('.credential', { + credential_search: { + kind: kind, + page_size: '5', + page: '1' + } + }); + }; + + $scope.formCancel = function() { + $state.go('^'); + }; + + $scope.formSave = function() { + var params, source, json_data; + json_data = ToJSON($scope.parseType, $scope.variables, true); + // group fields + var group = { + variables: json_data, + name: $scope.name, + description: $scope.description, + inventory: inventoryData.id + }; + if ($scope.source) { + // inventory_source fields + params = { + instance_filters: $scope.instance_filters, + source_vars: $scope[$scope.source.value + '_variables'] === '---' || $scope[$scope.source.value + '_variables'] === '{}' ? null : $scope[$scope.source.value + '_variables'], + source_script: $scope.inventory_script, + source: $scope.source.value, + credential: $scope.credential, + overwrite: $scope.overwrite, + overwrite_vars: $scope.overwrite_vars, + update_on_launch: $scope.update_on_launch, + update_cache_timeout: $scope.update_cache_timeout || 0, + // comma-delimited strings + group_by: _.map($scope.group_by, 'value').join(','), + source_regions: _.map($scope.source_regions, 'value').join(',') + }; + source = $scope.source.value; + } else { + source = null; + } + switch (source) { + // no inventory source set, just create a new group + // '' is the value supplied for Manual source type + case null || '': + GroupManageService.post(group).then(res => { + // associate + if ($stateParams.group) { + return GroupManageService.associateGroup(res.data, _.last($stateParams.group)) + .then(() => $state.go('^', null, { reload: true })); + } else { + $state.go('^', null, { reload: true }); + } + }); + break; + // create a new group and create/associate an inventory source + // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'satellite6' || 'cloudforms' || 'openstack' || 'custom' + default: + GroupManageService.post(group) + // associate to group + .then(res => { + if ($stateParams.group) { + GroupManageService.associateGroup(res.data, _.last($stateParams.group)); + return res; + } else { + return res; } + // pass the original POST response and not the association response + }) + .then(res => GroupManageService.putInventorySource( + // put the received group ID into inventory source payload + // and pass the related endpoint + _.assign(params, { group: res.data.id }), res.data.related.inventory_source)) + .then(res => $state.go('inventoryManage.editGroup', { group_id: res.data.group }, { reload: true })); + break; + } + }; + $scope.sourceChange = function(source) { + source = source.value; + if (source === 'custom'){ + $scope.credentialBasePath = GetBasePath('inventory_script'); + } + // equal to case 'ec2' || 'rax' || 'azure' || 'azure_rm' || 'vmware' || 'satellite6' || 'cloudforms' || 'openstack' + else{ + $scope.credentialBasePath = (source === 'ec2') ? GetBasePath('credentials') + '?kind=aws' : GetBasePath('credentials') + (source === '' ? '' : '?kind=' + (source)); + } + if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack') { + ParseTypeChange({ + scope: $scope, + field_id: source + '_variables', + variable: source + '_variables', + parse_variable: 'envParseType' + }); + } + + // reset fields + $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; + // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint + $scope.source_region_choices = source === 'azure_rm' ? $scope.azure_regions : $scope[source + '_regions']; + $scope.cloudCredentialRequired = source !== '' && source !== 'custom' && source !== 'ec2' ? true : false; + $scope.group_by = null; + $scope.source_regions = null; + $scope.credential = null; + $scope.credential_name = null; + initRegionSelect(); + }; + // region / source options callback + $scope.$on('choicesReadyGroup', function() { + initRegionSelect(); + }); + + $scope.$on('sourceTypeOptionsReady', function() { + initSourceSelect(); + }); + + function initRegionSelect(){ + CreateSelect2({ + element: '#group_source_regions', + multiple: true + }); + CreateSelect2({ + element: '#group_group_by', + multiple: true + }); + } + function initSourceSelect(){ + CreateSelect2({ + element: '#group_source', + multiple: false + }); + } + + function initSources(){ + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'rax_regions', + choice_name: 'rax_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'ec2_regions', + choice_name: 'ec2_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'gce_regions', + choice_name: 'gce_region_choices', + callback: 'choicesReadyGroup' + }); + + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'azure_regions', + choice_name: 'azure_region_choices', + callback: 'choicesReadyGroup' + }); + + // Load options for group_by + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'group_by', + variable: 'ec2_group_by', + choice_name: 'ec2_group_by_choices', + callback: 'choicesReadyGroup' + }); + GetSourceTypeOptions({ + scope: $scope, + variable: 'source_type_options', + //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref + }); + } + } +]; diff --git a/awx/ui/client/src/inventories/groups/add/main.js b/awx/ui/client/src/inventories/groups/add/main.js new file mode 100644 index 0000000000..4cbb4e5c66 --- /dev/null +++ b/awx/ui/client/src/inventories/groups/add/main.js @@ -0,0 +1,13 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import buildGroupAddState from './build-groups-add-state.factory'; +import controller from './groups-add.controller'; + +export default +angular.module('groupAdd', []) + .factory('buildGroupsAddState', buildGroupAddState) + .controller('GroupAddController', controller); diff --git a/awx/ui/client/src/inventories/groups/edit/groups-edit.controller.js b/awx/ui/client/src/inventories/groups/edit/groups-edit.controller.js new file mode 100644 index 0000000000..1355d5d33f --- /dev/null +++ b/awx/ui/client/src/inventories/groups/edit/groups-edit.controller.js @@ -0,0 +1,247 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$state', '$stateParams', '$scope', 'ParseVariableString', 'rbacUiControlService', 'ToJSON', + 'ParseTypeChange', 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'groupData', 'inventorySourceData', + function($state, $stateParams, $scope, ParseVariableString, rbacUiControlService, ToJSON, + ParseTypeChange, GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, groupData, inventorySourceData) { + + init(); + + function init() { + rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups") + .then(function(canAdd) { + $scope.canAdd = canAdd; + }); + // instantiate expected $scope values from inventorySourceData & groupData + _.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) { + $scope.credential_name = inventorySourceData.summary_fields.credential.name; + } + $scope = angular.extend($scope, groupData); + + // display custom inventory_script name + if (inventorySourceData.source === 'custom') { + $scope.inventory_script_name = inventorySourceData.summary_fields.source_script.name; + } + + $scope.$watch('summary_fields.user_capabilities.edit', function(val) { + $scope.canAdd = val; + }); + + // init codemirror(s) + $scope.variables = $scope.variables === null || $scope.variables === '' ? '---' : ParseVariableString($scope.variables); + $scope.parseType = 'yaml'; + $scope.envParseType = 'yaml'; + + ParseTypeChange({ + scope: $scope, + field_id: 'group_variables', + variable: 'variables', + }); + + initSources(); + } + + var initRegionSelect = function() { + CreateSelect2({ + element: '#group_source_regions', + multiple: true + }); + CreateSelect2({ + element: '#group_group_by', + multiple: true + }); + }; + + $scope.lookupCredential = function(){ + let kind = ($scope.source.value === "ec2") ? "aws" : $scope.source.value; + $state.go('.credential', { + credential_search: { + kind: kind, + page_size: '5', + page: '1' + } + }); + }; + + $scope.formCancel = function() { + $state.go('^'); + }; + $scope.formSave = function() { + var params, source, json_data; + json_data = ToJSON($scope.parseType, $scope.variables, true); + // group fields + var group = { + variables: json_data, + name: $scope.name, + description: $scope.description, + inventory: $scope.inventory, + id: groupData.id + }; + if ($scope.source) { + // inventory_source fields + params = { + group: groupData.id, + source: $scope.source.value, + credential: $scope.credential, + overwrite: $scope.overwrite, + overwrite_vars: $scope.overwrite_vars, + source_script: $scope.inventory_script, + update_on_launch: $scope.update_on_launch, + update_cache_timeout: $scope.update_cache_timeout || 0, + // comma-delimited strings + group_by: _.map($scope.group_by, 'value').join(','), + source_regions: _.map($scope.source_regions, 'value').join(','), + instance_filters: $scope.instance_filters, + source_vars: $scope[$scope.source.value + '_variables'] === '---' || $scope[$scope.source.value + '_variables'] === '{}' ? null : $scope[$scope.source.value + '_variables'] + }; + source = $scope.source.value; + } else { + source = null; + } + switch (source) { + // no inventory source set, just create a new group + // '' is the value supplied for Manual source type + case null || '': + GroupManageService.put(group).then(() => $state.go($state.current, null, { reload: true })); + break; + // create a new group and create/associate an inventory source + // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'satellite6' || 'cloudforms' || 'openstack' || 'custom' + default: + GroupManageService.put(group) + .then(() => GroupManageService.putInventorySource(params, groupData.related.inventory_source)) + .then(() => $state.go($state.current, null, { reload: true })); + break; + } + }; + + $scope.sourceChange = function(source) { + $scope.source = source; + if (source.value === 'ec2' || source.value === 'custom' || + source.value === 'vmware' || source.value === 'openstack') { + $scope[source.value + '_variables'] = $scope[source.value + '_variables'] === (null || undefined) ? '---' : $scope[source.value + '_variables']; + ParseTypeChange({ + scope: $scope, + field_id: source.value + '_variables', + variable: source.value + '_variables', + parse_variable: 'envParseType', + }); + } + // reset fields + // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint + $scope.source_region_choices = source.value === 'azure_rm' ? $scope.azure_regions : $scope[source.value + '_regions']; + $scope.cloudCredentialRequired = source.value !== '' && source.value !== 'custom' && source.value !== 'ec2' ? true : false; + $scope.group_by = null; + $scope.source_regions = null; + $scope.credential = null; + $scope.credential_name = null; + initRegionSelect(); + }; + + function initSourceSelect() { + $scope.source = _.find($scope.source_type_options, { value: inventorySourceData.source }); + CreateSelect2({ + element: '#group_source', + multiple: false + }); + // After the source is set, conditional fields will be visible + // CodeMirror is buggy if you instantiate it in a not-visible element + // So we initialize it here instead of the init() routine + if (inventorySourceData.source === 'ec2' || inventorySourceData.source === 'openstack' || + inventorySourceData.source === 'custom' || inventorySourceData.source === 'vmware') { + $scope[inventorySourceData.source + '_variables'] = inventorySourceData.source_vars === null || inventorySourceData.source_vars === '' ? '---' : ParseVariableString(inventorySourceData.source_vars); + ParseTypeChange({ + scope: $scope, + field_id: inventorySourceData.source + '_variables', + variable: inventorySourceData.source + '_variables', + parse_variable: 'envParseType', + }); + } + } + + function initRegionData() { + var source = $scope.source.value === 'azure_rm' ? 'azure' : $scope.source.value; + var regions = inventorySourceData.source_regions.split(','); + // azure_rm regions choices are keyed as "azure" in an OPTIONS request to the inventory_sources endpoint + $scope.source_region_choices = $scope[source + '_regions']; + + // the API stores azure regions as all-lowercase strings - but the azure regions received from OPTIONS are Snake_Cased + if (source === 'azure') { + $scope.source_regions = _.map(regions, (region) => _.find($scope[source + '_regions'], (o) => o.value.toLowerCase() === region)); + } + // all other regions are 1-1 + else { + $scope.source_regions = _.map(regions, (region) => _.find($scope[source + '_regions'], (o) => o.value === region)); + } + $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null; + if (source === 'ec2') { + var group_by = inventorySourceData.group_by.split(','); + $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, { value: item })); + } + initRegionSelect(); + } + + function initSources() { + GetSourceTypeOptions({ + scope: $scope, + variable: 'source_type_options', + //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'rax_regions', + choice_name: 'rax_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'ec2_regions', + choice_name: 'ec2_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'gce_regions', + choice_name: 'gce_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'source_regions', + variable: 'azure_regions', + choice_name: 'azure_region_choices', + callback: 'choicesReadyGroup' + }); + GetChoices({ + scope: $scope, + url: GetBasePath('inventory_sources'), + field: 'group_by', + variable: 'ec2_group_by', + choice_name: 'ec2_group_by_choices', + callback: 'choicesReadyGroup' + }); + } + + // region / source options callback + $scope.$on('choicesReadyGroup', function() { + if (angular.isObject($scope.source)) { + initRegionData(); + } + }); + + $scope.$on('sourceTypeOptionsReady', function() { + initSourceSelect(); + }); + } +]; diff --git a/awx/ui/client/src/inventories/groups/edit/main.js b/awx/ui/client/src/inventories/groups/edit/main.js new file mode 100644 index 0000000000..532d4b03ba --- /dev/null +++ b/awx/ui/client/src/inventories/groups/edit/main.js @@ -0,0 +1,13 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import buildGroupsEditState from './build-groups-edit-state.factory'; +import controller from './groups-edit.controller'; + +export default +angular.module('groupEdit', []) + .factory('buildGroupsEditState', buildGroupsEditState) + .controller('GroupEditController', controller); diff --git a/awx/ui/client/src/inventories/groups/groups.form.js b/awx/ui/client/src/inventories/groups/groups.form.js new file mode 100644 index 0000000000..bdf9df2353 --- /dev/null +++ b/awx/ui/client/src/inventories/groups/groups.form.js @@ -0,0 +1,339 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + /** + * @ngdoc function + * @name forms.function:Groups + * @description This form is for adding/editing a Group on the inventory page +*/ + +export default { + + + addTitle: 'CREATE GROUP', + editTitle: '{{ name }}', + showTitle: true, + name: 'group', + basePath: 'groups', + parent: 'inventories.edit.groups', + // the parent node this generated state definition tree expects to attach to + stateTree: 'inventories', + // form generator inspects the current state name to determine whether or not to set an active (.is-selected) class on a form tab + // this setting is optional on most forms, except where the form's edit state name is not parentStateName.edit + activeEditState: 'inventories.edit.groups.editGroup', + detailsClick: "$state.go('inventories.edit.groups.editGroup')", + well: false, + fields: { + name: { + label: 'Name', + type: 'text', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + required: true, + tab: 'properties' + }, + description: { + label: 'Description', + type: 'text', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + tab: 'properties' + }, + variables: { + label: 'Variables', + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + dataTitle: 'Group Variables', + dataPlacement: 'right', + parseTypeName: 'parseType', + awPopOver: "

Variables defined here apply to all child groups and hosts.

" + + "

Enter variables using either JSON or YAML syntax. Use the " + + "radio button to toggle between the two.

" + + "JSON:
\n" + + "
{
  \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

View JSON examples at www.json.org

' + + '

View YAML examples at docs.ansible.com

', + dataContainer: 'body', + tab: 'properties' + }, + source: { + label: 'Source', + type: 'select', + ngOptions: 'source.label for source in source_type_options track by source.value', + ngChange: 'sourceChange(source)', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + ngModel: 'source' + }, + credential: { + // initializes a default value for this search param + // search params with default values set will not generate user-interactable search tags + search: { + kind: null + }, + label: 'Cloud Credential', + type: 'lookup', + list: 'CredentialList', + basePath: 'credentials', + ngShow: "source && source.value !== '' && source.value !== 'custom'", + sourceModel: 'credential', + sourceField: 'name', + ngClick: 'lookupCredential()', + awRequiredWhen: { + reqExpression: "cloudCredentialRequired", + init: "false" + }, + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + watchBasePath: "credentialBasePath" + }, + source_regions: { + label: 'Regions', + type: 'select', + ngOptions: 'source.label for source in source_region_choices track by source.value', + multiSelect: true, + ngShow: "source && (source.value == 'rax' || source.value == 'ec2' || source.value == 'gce' || source.value == 'azure' || source.value == 'azure_rm')", + + + dataTitle: 'Source Regions', + dataPlacement: 'right', + awPopOver: "

Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " + + "or choose All to include all regions. Tower will only be updated with Hosts associated with the selected regions." + + "

", + dataContainer: 'body', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + instance_filters: { + label: 'Instance Filters', + type: 'text', + ngShow: "source && source.value == 'ec2'", + dataTitle: 'Instance Filters', + dataPlacement: 'right', + awPopOver: "

Provide a comma-separated list of filter expressions. " + + "Hosts are imported to Tower when ANY of the filters match.

" + + "Limit to hosts having a tag:
\n" + + "
tag-key=TowerManaged
\n" + + "Limit to hosts using either key pair:
\n" + + "
key-name=staging, key-name=production
\n" + + "Limit to hosts where the Name tag begins with test:
\n" + + "
tag:Name=test*
\n" + + "

View the Describe Instances documentation " + + "for a complete list of supported filters.

", + dataContainer: 'body', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + group_by: { + label: 'Only Group By', + type: 'select', + ngShow: "source && source.value == 'ec2'", + ngOptions: 'source.label for source in group_by_choices track by source.value', + multiSelect: true, + dataTitle: 'Only Group By', + dataPlacement: 'right', + awPopOver: "

Select which groups to create automatically. " + + "Tower will create group names similar to the following examples based on the options selected:

If blank, all groups above are created except Instance ID.

", + dataContainer: 'body', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + inventory_script: { + label : "Custom Inventory Script", + type: 'lookup', + basePath: 'inventory_scripts', + list: 'InventoryScriptsList', + ngShow: "source && source.value === 'custom'", + sourceModel: 'inventory_script', + sourceField: 'name', + awRequiredWhen: { + reqExpression: "source && source.value === 'custom'", + init: "false" + }, + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + }, + custom_variables: { + id: 'custom_variables', + label: 'Environment Variables', //"{{vars_label}}" , + ngShow: "source && source.value=='custom' ", + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + parseTypeName: 'envParseType', + dataTitle: "Environment Variables", + dataPlacement: 'right', + awPopOver: "

Provide environment variables to pass to the custom inventory script.

" + + "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

View JSON examples at www.json.org

' + + '

View YAML examples at docs.ansible.com

', + dataContainer: 'body' + }, + ec2_variables: { + id: 'ec2_variables', + label: 'Source Variables', //"{{vars_label}}" , + ngShow: "source && source.value == 'ec2'", + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + parseTypeName: 'envParseType', + dataTitle: "Source Variables", + dataPlacement: 'right', + awPopOver: "

Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables " + + "" + + "view ec2.ini in the Ansible github repo.

" + + "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

View JSON examples at www.json.org

' + + '

View YAML examples at docs.ansible.com

', + dataContainer: 'body' + }, + vmware_variables: { + id: 'vmware_variables', + label: 'Source Variables', //"{{vars_label}}" , + ngShow: "source && source.value == 'vmware'", + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + parseTypeName: 'envParseType', + dataTitle: "Source Variables", + dataPlacement: 'right', + awPopOver: "

Override variables found in vmware.ini and used by the inventory update script. For a detailed description of these variables " + + "" + + "view vmware_inventory.ini in the Ansible github repo.

" + + "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

View JSON examples at www.json.org

' + + '

View YAML examples at docs.ansible.com

', + dataContainer: 'body' + }, + openstack_variables: { + id: 'openstack_variables', + label: 'Source Variables', //"{{vars_label}}" , + ngShow: "source && source.value == 'openstack'", + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + parseTypeName: 'envParseType', + dataTitle: "Source Variables", + dataPlacement: 'right', + awPopOver: "

Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration " + + "" + + "view openstack.yml in the Ansible github repo.

" + + "

Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.

" + + "JSON:
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + "YAML:
\n" + + "
---
somevar: somevalue
password: magic
\n" + + '

View JSON examples at www.json.org

' + + '

View YAML examples at docs.ansible.com

', + dataContainer: 'body' + }, + checkbox_group: { + label: 'Update Options', + type: 'checkbox_group', + ngShow: "source && (source.value !== '' && source.value !== null)", + class: 'Form-checkbox--stacked', + fields: [{ + name: 'overwrite', + label: 'Overwrite', + type: 'checkbox', + ngShow: "source.value !== '' && source.value !== null", + + + awPopOver: '

If checked, all child groups and hosts not found on the external source will be deleted from ' + + 'the local inventory.

When not checked, local child hosts and groups not found on the external source will ' + + 'remain untouched by the inventory update process.

', + dataTitle: 'Overwrite', + dataContainer: 'body', + dataPlacement: 'right', + labelClass: 'checkbox-options', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, { + name: 'overwrite_vars', + label: 'Overwrite Variables', + type: 'checkbox', + ngShow: "source.value !== '' && source.value !== null", + + + awPopOver: '

If checked, all variables for child groups and hosts will be removed and replaced by those ' + + 'found on the external source.

When not checked, a merge will be performed, combining local variables with ' + + 'those found on the external source.

', + dataTitle: 'Overwrite Variables', + dataContainer: 'body', + dataPlacement: 'right', + labelClass: 'checkbox-options', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, { + name: 'update_on_launch', + label: 'Update on Launch', + type: 'checkbox', + ngShow: "source.value !== '' && source.value !== null", + awPopOver: '

Each time a job runs using this inventory, refresh the inventory from the selected source before ' + + 'executing job tasks.

', + dataTitle: 'Update on Launch', + dataContainer: 'body', + dataPlacement: 'right', + labelClass: 'checkbox-options', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }] + }, + update_cache_timeout: { + label: "Cache Timeout (seconds)", + id: 'source-cache-timeout', + type: 'number', + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + integer: true, + min: 0, + ngShow: "source && source.value !== '' && update_on_launch", + spinner: true, + "default": 0, + awPopOver: '

Time in seconds to consider an inventory sync to be current. During job runs and callbacks the task system will ' + + 'evaluate the timestamp of the latest sync. If it is older than Cache Timeout, it is not considered current, ' + + 'and a new inventory sync will be performed.

', + dataTitle: 'Cache Timeout', + dataPlacement: 'right', + dataContainer: "body" + } + }, + + buttons: { + cancel: { + ngClick: 'formCancel()', + ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + }, + save: { + ngClick: 'formSave()', + ngDisabled: true, + ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)' + } + } + }; diff --git a/awx/ui/client/src/inventories/groups/list/inventory-groups.list.js b/awx/ui/client/src/inventories/groups/groups.list.js similarity index 100% rename from awx/ui/client/src/inventories/groups/list/inventory-groups.list.js rename to awx/ui/client/src/inventories/groups/groups.list.js diff --git a/awx/ui/client/src/inventories/groups/list/build-groups-list-state.factory.js b/awx/ui/client/src/inventories/groups/list/build-groups-list-state.factory.js index f1af8925fd..db175bf3eb 100644 --- a/awx/ui/client/src/inventories/groups/list/build-groups-list-state.factory.js +++ b/awx/ui/client/src/inventories/groups/list/build-groups-list-state.factory.js @@ -3,10 +3,10 @@ * * All Rights Reserved *************************************************/ - -export default ['InventoryGroupsList', '$stateExtender', 'templateUrl', '$injector', - function(InventoryGroupsList, $stateExtender, templateUrl, $injector){ - var val = function(field, formStateDefinition, params) { +import GroupsListController from './groups-list.controller'; +export default ['GroupList', '$stateExtender', 'templateUrl', '$injector', + function(GroupList, $stateExtender, templateUrl, $injector){ + var val = function(field, formStateDefinition) { let state, list = field.include ? $injector.get(field.include) : field, breadcrumbLabel = (field.iterator.replace('_', ' ') + 's').toUpperCase(), @@ -25,8 +25,8 @@ export default ['InventoryGroupsList', '$stateExtender', 'templateUrl', '$inject }, views: { 'related': { - templateProvider: function(InventoryGroupsList, generateList, $templateRequest, $stateParams, GetBasePath) { - let list = _.cloneDeep(InventoryGroupsList); + templateProvider: function(GroupList, generateList, $templateRequest, $stateParams, GetBasePath) { + let list = _.cloneDeep(GroupList); if($stateParams && $stateParams.group) { list.basePath = GetBasePath('groups') + _.last($stateParams.group) + '/children'; } @@ -44,7 +44,7 @@ export default ['InventoryGroupsList', '$stateExtender', 'templateUrl', '$inject return html.concat(template); }); }, - // controller: GroupsListController + controller: GroupsListController } }, resolve: { @@ -70,23 +70,6 @@ export default ['InventoryGroupsList', '$stateExtender', 'templateUrl', '$inject } }; - if(params.controllers && params.controllers.related && params.controllers.related[field.name]) { - stateConfig.views.related.controller = params.controllers.related[field.name]; - } - else if(field.name === 'permissions') { - stateConfig.views.related.controller = 'PermissionsList'; - } - else { - // Generic controller - stateConfig.views.related.controller = ['$scope', 'ListDefinition', 'Dataset', - function($scope, list, Dataset) { - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[`${list.iterator}s`] = $scope[`${list.iterator}_dataset`].results; - } - ]; - } - state = $stateExtender.buildDefinition(stateConfig); // appy any default search parameters in form definition if (field.search) { diff --git a/awx/ui/client/src/inventories/groups/list/group-list.controller.js b/awx/ui/client/src/inventories/groups/list/group-list.controller.js deleted file mode 100644 index 8bc2bb8154..0000000000 --- a/awx/ui/client/src/inventories/groups/list/group-list.controller.js +++ /dev/null @@ -1,236 +0,0 @@ -/************************************************* - * Copyright (c) 2016 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - export default - ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroupsList', 'InventoryUpdate', - 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath', - 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', - function($scope, $rootScope, $state, $stateParams, InventoryGroupsList, InventoryUpdate, - GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath, - GetSyncStatusMsg, GetHostsStatusMsg, Dataset, Find, qs, inventoryData){ - - let list = InventoryGroupsList; - - init(); - - 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; - }); - - // Search init - $scope.list = list; - $scope[`${list.iterator}_dataset`] = Dataset.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - - // The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope. - // In this case, we don't want to incidentally bind to this scope when editing a host or a group. See: - // https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the - // problem that this solves. - $scope.ncyBreadcrumbIgnore = true; - if($state.current.name === "inventoryManage.editGroup") { - $scope.rowBeingEdited = $state.params.group_id; - $scope.listBeingEdited = "groups"; - } - - $scope.inventory_id = $stateParams.inventory_id; - _.forEach($scope[list.name], buildStatusIndicators); - - } - - function buildStatusIndicators(group){ - if (group === undefined || group === null) { - group = {}; - } - - let group_status, hosts_status; - - group_status = GetSyncStatusMsg({ - status: group.summary_fields.inventory_source.status, - has_inventory_sources: group.has_inventory_sources, - source: ( (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null ) - }); - hosts_status = GetHostsStatusMsg({ - active_failures: group.hosts_with_active_failures, - total_hosts: group.total_hosts, - inventory_id: $scope.inventory_id, - group_id: group.id - }); - _.assign(group, - {status_class: group_status.class}, - {status_tooltip: group_status.tooltip}, - {launch_tooltip: group_status.launch_tip}, - {launch_class: group_status.launch_class}, - {group_schedule_tooltip: group_status.schedule_tip}, - {hosts_status_tip: hosts_status.tooltip}, - {hosts_status_class: hosts_status.class}, - {source: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.source : null}, - {status: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.status : null}); - } - - $scope.groupSelect = function(id){ - var group = $stateParams.group === undefined ? [id] : _($stateParams.group).concat(id).value(); - $state.go('inventoryManage', { - inventory_id: $stateParams.inventory_id, - group: group, - group_search: { - page_size: '20', - page: '1', - order_by: 'name', - } - }, {reload: true}); - }; - $scope.createGroup = function(){ - $state.go('inventoryManage.addGroup'); - }; - $scope.editGroup = function(id){ - $state.go('inventoryManage.editGroup', {group_id: id}); - }; - $scope.deleteGroup = function(group){ - $scope.toDelete = {}; - angular.extend($scope.toDelete, group); - if($scope.toDelete.total_groups === 0 && $scope.toDelete.total_hosts === 0) { - // This group doesn't have any child groups or hosts - the user is just trying to delete - // the group - $scope.deleteOption = "delete"; - } - $('#group-delete-modal').modal('show'); - }; - $scope.confirmDelete = function(){ - - // Bind an even listener for the modal closing. Trying to $state.go() before the modal closes - // will mean that these two things are running async and the modal may not finish closing before - // the state finishes transitioning. - $('#group-delete-modal').off('hidden.bs.modal').on('hidden.bs.modal', function () { - // Remove the event handler so that we don't end up with multiple bindings - $('#group-delete-modal').off('hidden.bs.modal'); - // Reload the inventory manage page and show that the group has been removed - $state.go('inventoryManage', null, {reload: true}); - }); - - switch($scope.deleteOption){ - case 'promote': - GroupManageService.promote($scope.toDelete.id, $stateParams.inventory_id) - .then(() => { - if (parseInt($state.params.group_id) === $scope.toDelete.id) { - $state.go("inventoryManage", null, {reload: true}); - } else { - $state.go($state.current, null, {reload: true}); - } - $('#group-delete-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }); - break; - default: - GroupManageService.delete($scope.toDelete.id).then(() => { - if (parseInt($state.params.group_id) === $scope.toDelete.id) { - $state.go("inventoryManage", null, {reload: true}); - } else { - $state.go($state.current, null, {reload: true}); - } - $('#group-delete-modal').modal('hide'); - $('body').removeClass('modal-open'); - $('.modal-backdrop').remove(); - }); - } - }; - $scope.updateGroup = function(group) { - GroupManageService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({ - scope: $scope, - group_id: group.id, - url: res.data.results[0].related.update, - group_name: group.name, - group_source: res.data.results[0].source - })); - }; - - $scope.$on(`ws-jobs`, function(e, data){ - var group = Find({ list: $scope.groups, key: 'id', val: data.group_id }); - - if (group === undefined || group === null) { - group = {}; - } - - if(data.status === 'failed' || data.status === 'successful'){ - let path; - if($stateParams && $stateParams.group && $stateParams.group.length > 0) { - path = GetBasePath('groups') + _.last($stateParams.group) + '/children'; - } - else { - //reaches here if the user is on the root level group - path = GetBasePath('inventory') + $stateParams.inventory_id + '/root_groups'; - } - qs.search(path, $state.params[`${list.iterator}_search`]) - .then(function(searchResponse) { - $scope[`${list.iterator}_dataset`] = searchResponse.data; - $scope[list.name] = $scope[`${list.iterator}_dataset`].results; - _.forEach($scope[list.name], buildStatusIndicators); - }); - } else { - var status = GetSyncStatusMsg({ - status: data.status, - has_inventory_sources: group.has_inventory_sources, - source: group.source - }); - group.status = data.status; - group.status_class = status.class; - group.status_tooltip = status.tooltip; - group.launch_tooltip = status.launch_tip; - group.launch_class = status.launch_class; - } - }); - - $scope.cancelUpdate = function (id) { - GroupsCancelUpdate({ scope: $scope, id: id }); - }; - $scope.viewUpdateStatus = function (id) { - ViewUpdateStatus({ - scope: $scope, - group_id: id - }); - }; - $scope.showFailedHosts = function() { - $state.go('inventoryManage', {failed: true}, {reload: true}); - }; - $scope.scheduleGroup = function(id) { - // Add this group's id to the array of group id's so that it gets - // added to the breadcrumb trail - var groupsArr = $stateParams.group ? $stateParams.group : []; - groupsArr.push(id); - $state.go('inventoryManage.editGroup.schedules', {group_id: id, group: groupsArr}, {reload: true}); - }; - // $scope.$parent governed by InventoryManageController, for unified multiSelect options - $scope.$on('multiSelectList.selectionChanged', (event, selection) => { - $scope.$parent.groupsSelected = selection.length > 0 ? true : false; - $scope.$parent.groupsSelectedItems = selection.selectedItems; - }); - - $scope.copyMoveGroup = function(id){ - $state.go('inventoryManage.copyMoveGroup', {group_id: id, groups: $stateParams.groups}); - }; - - var cleanUpStateChangeListener = $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) { - if (toState.name === "inventoryManage.editGroup") { - $scope.rowBeingEdited = toParams.group_id; - $scope.listBeingEdited = "groups"; - } - else { - delete $scope.rowBeingEdited; - delete $scope.listBeingEdited; - } - }); - - // Remove the listener when the scope is destroyed to avoid a memory leak - $scope.$on('$destroy', function() { - cleanUpStateChangeListener(); - }); - - }]; 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 8bc2bb8154..a9db830841 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 @@ -4,14 +4,14 @@ * All Rights Reserved *************************************************/ export default - ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroupsList', 'InventoryUpdate', + ['$scope', '$rootScope', '$state', '$stateParams', 'GroupList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', - function($scope, $rootScope, $state, $stateParams, InventoryGroupsList, InventoryUpdate, + function($scope, $rootScope, $state, $stateParams, GroupList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath, GetSyncStatusMsg, GetHostsStatusMsg, Dataset, Find, qs, inventoryData){ - let list = InventoryGroupsList; + let list = GroupList; init(); @@ -88,10 +88,10 @@ }, {reload: true}); }; $scope.createGroup = function(){ - $state.go('inventoryManage.addGroup'); + $state.go('inventories.edit.groups.add'); }; $scope.editGroup = function(id){ - $state.go('inventoryManage.editGroup', {group_id: id}); + $state.go('inventories.edit.groups.edit', {group_id: id}); }; $scope.deleteGroup = function(group){ $scope.toDelete = {}; diff --git a/awx/ui/client/src/inventories/groups/list/main.js b/awx/ui/client/src/inventories/groups/list/main.js index b36162d4be..37e4c974fa 100644 --- a/awx/ui/client/src/inventories/groups/list/main.js +++ b/awx/ui/client/src/inventories/groups/list/main.js @@ -4,12 +4,10 @@ * All Rights Reserved *************************************************/ -import buildGroupListState from './build-groups-list-state.factory'; +import buildGroupsListState from './build-groups-list-state.factory'; import controller from './groups-list.controller'; -import InventoryGroupsList from './inventory-groups.list'; export default - angular.module('groupList', []) - .factory('buildGroupListState', buildGroupListState) - .value('InventoryGroupsList', InventoryGroupsList) + angular.module('groupsList', []) + .factory('buildGroupsListState', buildGroupsListState) .controller('GroupsListController', controller); diff --git a/awx/ui/client/src/inventories/groups/main.js b/awx/ui/client/src/inventories/groups/main.js index d8af95c6f2..9461571a71 100644 --- a/awx/ui/client/src/inventories/groups/main.js +++ b/awx/ui/client/src/inventories/groups/main.js @@ -5,6 +5,10 @@ *************************************************/ import groupList from './list/main'; +import groupAdd from './add/main'; +import groupEdit from './edit/main'; +import groupFormDefinition from './groups.form'; +import groupListDefinition from './groups.list'; import service from './groups.service'; import GetHostsStatusMsg from './factories/get-hosts-status-msg.factory'; import GetSourceTypeOptions from './factories/get-source-type-options.factory'; @@ -14,8 +18,12 @@ import ViewUpdateStatus from './factories/view-update-status.factory'; export default angular.module('group', [ - groupList.name + groupList.name, + groupAdd.name, + groupEdit.name ]) + .value('GroupForm', groupFormDefinition) + .value('GroupList', groupListDefinition) .factory('GetHostsStatusMsg', GetHostsStatusMsg) .factory('GetSourceTypeOptions', GetSourceTypeOptions) .factory('GetSyncStatusMsg', GetSyncStatusMsg) diff --git a/awx/ui/client/src/inventories/inventories.partial.html b/awx/ui/client/src/inventories/inventories.partial.html index 871367dcb9..26d66de7af 100644 --- a/awx/ui/client/src/inventories/inventories.partial.html +++ b/awx/ui/client/src/inventories/inventories.partial.html @@ -1,4 +1,5 @@
+
diff --git a/awx/ui/client/src/inventories/inventory.form.js b/awx/ui/client/src/inventories/inventory.form.js index 91c181a006..6755e72381 100644 --- a/awx/ui/client/src/inventories/inventory.form.js +++ b/awx/ui/client/src/inventories/inventory.form.js @@ -10,8 +10,8 @@ * @description This form is for adding/editing an inventory */ -export default ['i18n', 'buildGroupListState', -function(i18n,buildGroupListState) { +export default ['i18n', 'buildGroupsListState', 'buildGroupsAddState', 'buildGroupsEditState', +function(i18n, buildGroupsListState, buildGroupsAddState, buildGroupsEditState) { return { addTitle: i18n._('NEW INVENTORY'), @@ -134,10 +134,12 @@ function(i18n,buildGroupListState) { }, groups: { name: 'groups', - include: "InventoryGroupsList", + include: "GroupList", title: i18n._('Groups'), iterator: 'group', - stateGeneratorFunction: buildGroupListState + listState: buildGroupsListState, + addState: buildGroupsAddState, + editState: buildGroupsEditState }, hosts: { name: 'hosts', diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index 6e3a6ef426..107ea95b4e 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -246,7 +246,6 @@ function($injector, $stateExtender, $log, i18n) { * @returns {array} Array of state definitions [{...}, {...}, ...] */ generateFormListDefinitions: function(form, formStateDefinition, params) { - function buildRbacUserTeamDirective(){ let states = []; @@ -508,10 +507,6 @@ function($injector, $stateExtender, $log, i18n) { ] } }); - // // appy any default search parameters in form definition - // if (field.search) { - // state.params[`${field.iterator}_search`].value = _.merge(state.params[`${field.iterator}_search`].value, field.search); - // } return state; } @@ -559,7 +554,9 @@ function($injector, $stateExtender, $log, i18n) { function buildListNodes(field) { let states = []; if(field.iterator === 'group'){ - states.push(field.stateGeneratorFunction(field, formStateDefinition, params)); + states.push(field.listState(field, formStateDefinition)); + states.push(field.addState(field, formStateDefinition, params)); + states.push(field.editState(field, formStateDefinition, params)); states = _.flatten(states); } else if(field.iterator === 'notification'){