From 67f282f64d315717a293c2613df306e36d5139b2 Mon Sep 17 00:00:00 2001 From: Chris Meyers Date: Fri, 6 Jan 2017 14:36:00 -0500 Subject: [PATCH 1/6] begin re-implementation of auto-populate feature --- awx/ui/client/src/shared/directives.js | 42 +++++++++++++++++++++- awx/ui/client/src/shared/form-generator.js | 5 +++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index f2e2b1d58d..d0435e1fc0 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -463,11 +463,51 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) return { require: 'ngModel', link: function(scope, elm, attrs, fieldCtrl) { - let query, basePath, defer = $q.defer(); + // Auto-populating related fields when there is only 1 relatable entry isn't mission critical. + // Therefore, don't display an error message if the get request fails. + function _doAutoPopulate() { + let modelKey = attrs.ngModel; + let modelName = attrs.source; + let query = ''; + + // TODO: We can't fully rely on basePath. For example, the "Add Credentials" form sets the basePath + // to something like admin_of_organizations. Instead, we should probably just use the model name. + // At the time, we need to account for admin_of_organizations to determine if we auto-populate org + // on the cred add page. + basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); + + switch(modelName) { + case 'credential': + query = '?kind=ssh'; + break; + case 'network_credential': + query = '?kind=net'; + break; + } + + Rest.setUrl(`${basePath}` + query); + Rest.get() + .success(function (data) { + // TODO: Obviously, add back in the data count + /* + if (data.count == 1) { + } + */ + scope[modelKey] = data.results[0].name; + scope[modelName] = data.results[0].id; + }); + } + + // TODO: Add more logic checks to see if this field needs to be auto-populated. Checks similar to the below linked code. + // https://github.com/ansible/ansible-tower/blob/release_3.0.3/awx/ui/client/src/lookup/lookup.factory.js#L94 + if (scope.mode === 'add') { + _doAutoPopulate(); + } + // query the API to see if field value corresponds to a valid resource // .ng-pending will be applied to the directive element while the request is outstanding // form.$pending will contain object reference to any ngModelControllers with outstanding requests diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 7c0804d499..b257197030 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -376,6 +376,11 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat }, applyDefaults: function (form, scope) { + // Note: This is a hack. Ideally, mode should be set in each -.controller.js + // The mode is needed by the awlookup directive to auto-populate form fields when there is a + // single related resource. + scope.mode = this.mode; + for (var fld in form.fields) { if (form.fields[fld]['default'] || form.fields[fld]['default'] === 0) { if (form.fields[fld].type === 'select' && scope[fld + '_options']) { From 61ad4e3793e4d72346ad81b4c5ef28cd3fcffb03 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Wed, 18 Jan 2017 20:49:12 -0800 Subject: [PATCH 2/6] fix for autopopulation --- awx/ui/client/src/forms/Credentials.js | 1 + awx/ui/client/src/shared/directives.js | 71 ++++++++++++++++------ awx/ui/client/src/shared/form-generator.js | 3 +- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/awx/ui/client/src/forms/Credentials.js b/awx/ui/client/src/forms/Credentials.js index 1ec2628cfd..4ebfa20170 100644 --- a/awx/ui/client/src/forms/Credentials.js +++ b/awx/ui/client/src/forms/Credentials.js @@ -48,6 +48,7 @@ export default ngShow: 'canShareCredential', label: i18n._('Organization'), type: 'lookup', + autopopulateLookup: false, list: 'OrganizationList', sourceModel: 'organization', sourceField: 'name', diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index d0435e1fc0..ade342c479 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -465,19 +465,21 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) link: function(scope, elm, attrs, fieldCtrl) { let query, basePath, - defer = $q.defer(); + defer = $q.defer(), + autopopulateLookup, + modelKey = attrs.ngModel, + modelName = attrs.source, + watcher = attrs.awRequiredWhen || undefined; + + if (attrs.autopopulateLookup !== undefined) { + autopopulateLookup = attrs.autopopulateLookup; + } else { + autopopulateLookup = true; + } - // Auto-populating related fields when there is only 1 relatable entry isn't mission critical. - // Therefore, don't display an error message if the get request fails. function _doAutoPopulate() { - let modelKey = attrs.ngModel; - let modelName = attrs.source; let query = ''; - // TODO: We can't fully rely on basePath. For example, the "Add Credentials" form sets the basePath - // to something like admin_of_organizations. Instead, we should probably just use the model name. - // At the time, we need to account for admin_of_organizations to determine if we auto-populate org - // on the cred add page. basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); switch(modelName) { @@ -492,22 +494,55 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) Rest.setUrl(`${basePath}` + query); Rest.get() .success(function (data) { - // TODO: Obviously, add back in the data count - /* - if (data.count == 1) { + if (data.count === 1) { + scope[modelKey] = data.results[0].name; + scope[modelName] = data.results[0].id; } - */ - scope[modelKey] = data.results[0].name; - scope[modelName] = data.results[0].id; }); } - // TODO: Add more logic checks to see if this field needs to be auto-populated. Checks similar to the below linked code. - // https://github.com/ansible/ansible-tower/blob/release_3.0.3/awx/ui/client/src/lookup/lookup.factory.js#L94 - if (scope.mode === 'add') { + if (fieldIsAutopopulatable()) { _doAutoPopulate(); } + // This checks to see if the field meets the criteria to + // autopopulate: + // Population rules: + // - add form only + // - lookup is required + // - lookup is not promptable + // - user must only have access to 1 item the lookup is for + function fieldIsAutopopulatable() { + if (autopopulateLookup === false) { + return false; + } + if (scope.mode === "add") { + if(watcher){ + scope.$watch(watcher, (newValue, oldValue, scope2) => { + console.log('success', watcher, newValue , oldValue, scope2); + + if(Boolean(scope.$eval(watcher)) === true){ + + // if we get here then the field is required + // by way of awRequiredWhen + // and is a candidate for autopopulation + + _doAutoPopulate(); + } + }); + } + else if (attrs.required === true) { + return true; + } + else { + return false; + } + } + else { + return false; + } + } + // query the API to see if field value corresponds to a valid resource // .ng-pending will be applied to the directive element while the request is outstanding // form.$pending will contain object reference to any ngModelControllers with outstanding requests diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index b257197030..52e0eccfc4 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -377,7 +377,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat applyDefaults: function (form, scope) { // Note: This is a hack. Ideally, mode should be set in each -.controller.js - // The mode is needed by the awlookup directive to auto-populate form fields when there is a + // The mode is needed by the awlookup directive to auto-populate form fields when there is a // single related resource. scope.mode = this.mode; @@ -1368,6 +1368,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += `data-basePath="${field.basePath}"`; html += `data-source="${field.sourceModel}"`; html += `data-query="?${field.sourceField}__iexact=:value"`; + html += (field.autopopulateLookup) ? `autopopulateLookup=${field.autopopulateLookup}` : ""; html += `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 300, 'blur': 0 } }"`; html += " awlookup >\n"; html += "\n"; From fc45603c3b1dc76304478cf7e8a62aca0c8e1bbf Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Thu, 19 Jan 2017 15:53:16 -0800 Subject: [PATCH 3/6] adding three fixes: 1. adding a watcher for the basePath to use for lookups that might have dynamic lookups. Ex: The groups form -> cred depends on "source.type" 2. adding a fix for RBAC based autopopulation. Basically, if you don't have permission to "use" something, then you shouldn't be able to see it auto-fill 3. adding a fix for the promptable fields on the job template form. The inventory and credential are both promptable, and therefore should not auto populate --- awx/ui/client/src/forms/Groups.js | 3 +- awx/ui/client/src/forms/JobTemplates.js | 2 + .../manage/groups/groups-add.controller.js | 8 +++ awx/ui/client/src/shared/directives.js | 55 +++++++++++++------ awx/ui/client/src/shared/form-generator.js | 3 +- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/awx/ui/client/src/forms/Groups.js b/awx/ui/client/src/forms/Groups.js index c5bf595ca2..5b6cb20b31 100644 --- a/awx/ui/client/src/forms/Groups.js +++ b/awx/ui/client/src/forms/Groups.js @@ -86,7 +86,8 @@ export default reqExpression: "cloudCredentialRequired", init: "false" }, - ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)' + ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)', + watchBasePath: "credentialBasePath" }, source_regions: { label: 'Regions', diff --git a/awx/ui/client/src/forms/JobTemplates.js b/awx/ui/client/src/forms/JobTemplates.js index 07f7ddf7c2..28462577ae 100644 --- a/awx/ui/client/src/forms/JobTemplates.js +++ b/awx/ui/client/src/forms/JobTemplates.js @@ -76,6 +76,7 @@ export default list: 'InventoryList', sourceModel: 'inventory', sourceField: 'name', + autopopulateLookup: false, awRequiredWhen: { reqExpression: '!ask_inventory_on_launch', alwaysShowAsterisk: true @@ -138,6 +139,7 @@ export default type: 'lookup', list: 'CredentialList', basePath: 'credentials', + autopopulateLookup: false, search: { kind: 'ssh' }, diff --git a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js index 9229595d96..cc1283c582 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js @@ -112,6 +112,13 @@ export default ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList }; $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, @@ -120,6 +127,7 @@ export default ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList 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 diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index ade342c479..be7f14e5e5 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -469,34 +469,59 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) autopopulateLookup, modelKey = attrs.ngModel, modelName = attrs.source, - watcher = attrs.awRequiredWhen || undefined; + watcher = attrs.awRequiredWhen || undefined, + watchBasePath; - if (attrs.autopopulateLookup !== undefined) { - autopopulateLookup = attrs.autopopulateLookup; + if (attrs.autopopulatelookup !== undefined) { + autopopulateLookup = JSON.parse(attrs.autopopulatelookup); } else { autopopulateLookup = true; } + + // The following block of code is for instances where the + // lookup field is reused by varying sub-forms. Example: The groups + // form will change it's credential lookup based on the + // source type. The basepath the lookup should utilize is dynamic + // in this case. You'd configure the "watchBasePath" key on the + // field's configuration in the form configuration field. + if (attrs.watchbasepath !== undefined) { + watchBasePath = attrs.watchbasepath; + scope.$watch(watchBasePath, (newValue) => { + if(newValue !== undefined && fieldIsAutopopulatable()){ + _doAutoPopulate(); + } + }); + } + function _doAutoPopulate() { let query = ''; - basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); + if (attrs.watchbasepath !== undefined && scope[attrs.watchbasepath] !== undefined) { + basePath = scope[attrs.watchbasepath]; + } + else { + basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); + switch(modelName) { + case 'credential': + query = '?kind=ssh'; + break; + case 'network_credential': + query = '?kind=net'; + break; + } - switch(modelName) { - case 'credential': - query = '?kind=ssh'; - break; - case 'network_credential': - query = '?kind=net'; - break; } Rest.setUrl(`${basePath}` + query); Rest.get() .success(function (data) { if (data.count === 1) { - scope[modelKey] = data.results[0].name; - scope[modelName] = data.results[0].id; + if(data.results[0].summary_fields.user_capabilities.edit === true){ + scope[modelKey] = data.results[0].name; + scope[modelName] = data.results[0].id; + } + } }); } @@ -518,9 +543,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) } if (scope.mode === "add") { if(watcher){ - scope.$watch(watcher, (newValue, oldValue, scope2) => { - console.log('success', watcher, newValue , oldValue, scope2); - + scope.$watch(watcher, () => { if(Boolean(scope.$eval(watcher)) === true){ // if we get here then the field is required diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 52e0eccfc4..9b59e9db81 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1368,7 +1368,8 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += `data-basePath="${field.basePath}"`; html += `data-source="${field.sourceModel}"`; html += `data-query="?${field.sourceField}__iexact=:value"`; - html += (field.autopopulateLookup) ? `autopopulateLookup=${field.autopopulateLookup}` : ""; + html += (field.autopopulateLookup !== undefined) ? ` autopopulateLookup=${field.autopopulateLookup} ` : ""; + html += (field.watchBasePath !== undefined) ? ` watchBasePath=${field.watchBasePath} ` : ""; html += `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 300, 'blur': 0 } }"`; html += " awlookup >\n"; html += "\n"; From 862a2d3c49b8ea71dd22c41413cb7f51491d9192 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Fri, 20 Jan 2017 15:45:00 -0800 Subject: [PATCH 4/6] incorporating RBAC into auto-population and for lookup modal lists basically, you shouldn't be able to select a resource you don't have permission to use, either through autopopulation or selecting manually --- awx/ui/client/src/shared/directives.js | 20 +++++++++++-------- awx/ui/client/src/shared/form-generator.js | 4 ++-- .../src/shared/stateDefinitions.factory.js | 10 +++++++++- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index be7f14e5e5..d64ad4d091 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -495,19 +495,26 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) } function _doAutoPopulate() { - let query = ''; + let query = '?role_level=use_role'; if (attrs.watchbasepath !== undefined && scope[attrs.watchbasepath] !== undefined) { basePath = scope[attrs.watchbasepath]; + query = '&role_level=use_role'; } else { basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); switch(modelName) { case 'credential': - query = '?kind=ssh'; + query = '?kind=ssh&role_level=use_role'; break; case 'network_credential': - query = '?kind=net'; + query = '?kind=net&role_level=use_role'; + break; + case 'organization': + query = '?role_level=admin_role'; + break; + case 'inventory_script': + query = '?role_level=admin_role'; break; } @@ -517,11 +524,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) Rest.get() .success(function (data) { if (data.count === 1) { - if(data.results[0].summary_fields.user_capabilities.edit === true){ - scope[modelKey] = data.results[0].name; - scope[modelName] = data.results[0].id; - } - + scope[modelKey] = data.results[0].name; + scope[modelName] = data.results[0].id; } }); } diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 9b59e9db81..bfaa383ea4 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1368,8 +1368,8 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += `data-basePath="${field.basePath}"`; html += `data-source="${field.sourceModel}"`; html += `data-query="?${field.sourceField}__iexact=:value"`; - html += (field.autopopulateLookup !== undefined) ? ` autopopulateLookup=${field.autopopulateLookup} ` : ""; - html += (field.watchBasePath !== undefined) ? ` watchBasePath=${field.watchBasePath} ` : ""; + html += (field.autopopulateLookup !== undefined) ? ` autopopulateLookup=${field.autopopulateLookup} ` : ""; + html += (field.watchBasePath !== undefined) ? ` watchBasePath=${field.watchBasePath} ` : ""; html += `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 300, 'blur': 0 } }"`; html += " awlookup >\n"; html += "\n"; diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index 0d13e4ed7f..db3969d760 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -643,7 +643,10 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat }, params: { [field.sourceModel + '_search']: { - value: { page_size: '5' } + value: { + page_size: '5', + role_level: 'use_role' + } } }, ncyBreadcrumb: { @@ -683,6 +686,11 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat interpolator = $interpolate(list.basePath); path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); } + // Need to delete the role_level here b/c organizations and inventory scripts + // don't have a "use_role", only "admin_role" and "read_role" + if(list.iterator === "organization" || list.iterator === "inventory_script"){ + delete $stateParams[`${list.iterator}_search`].role_level; + } return qs.search(path, $stateParams[`${list.iterator}_search`]); } ] From 6c7c4061d17e6d5b14947e1842d94e4b0ad05788 Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Fri, 20 Jan 2017 16:33:50 -0800 Subject: [PATCH 5/6] When a user types into a lookup field, we now only match against objects the user has permission to access. I also included the type of thing it was. So for instance, if you're typing into cloud credentials, it should validate against cloud credentials, instead of validating against all credentials. --- awx/ui/client/src/shared/directives.js | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index d64ad4d091..35b9e8716b 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -587,6 +587,35 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) basePath = GetBasePath(elm.attr('data-basePath')) || elm.attr('data-basePath'); query = elm.attr('data-query'); query = query.replace(/\:value/, encodeURIComponent(viewValue)); + + let base = ctrl.$name.split('_name')[0]; + if (attrs.watchbasepath !== undefined && scope[attrs.watchbasepath] !== undefined) { + basePath = scope[attrs.watchbasepath]; + query += '&role_level=use_role'; + query = query.replace('?', '&'); + } + else { + switch(base) { + case 'credential': + query += '&kind=ssh&role_level=use_role'; + break; + case 'network_credential': + query += '&kind=net&role_level=use_role'; + break; + case 'cloud_credential': + query += '&cloud=true&role_level=use_role'; + break; + case 'organization': + query += '&role_level=admin_role'; + break; + case 'inventory_script': + query += '&role_level=admin_role'; + break; + default: + query += '&role_level=use_role'; + } + } + Rest.setUrl(`${basePath}${query}`); // https://github.com/ansible/ansible-tower/issues/3549 // capturing both success/failure conditions in .then() promise From 250340e0630a53a9765ddce174b6f0e8cfc2691f Mon Sep 17 00:00:00 2001 From: jaredevantabor Date: Fri, 20 Jan 2017 17:50:24 -0800 Subject: [PATCH 6/6] Fix for filtering organizations, and fixing the org lookup on credentials form --- awx/ui/client/src/forms/Credentials.js | 3 +-- awx/ui/client/src/shared/stateDefinitions.factory.js | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/forms/Credentials.js b/awx/ui/client/src/forms/Credentials.js index 4ebfa20170..1043327e84 100644 --- a/awx/ui/client/src/forms/Credentials.js +++ b/awx/ui/client/src/forms/Credentials.js @@ -43,8 +43,7 @@ export default ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)' }, organization: { - // interpolated with $rootScope - basePath: "{{$rootScope.current_user.is_superuser ? 'api/v1/organizations' : $rootScope.current_user.url + 'admin_of_organizations'}}", + basePath: 'organizations', ngShow: 'canShareCredential', label: i18n._('Organization'), type: 'lookup', diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index db3969d760..8279173dc9 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -686,10 +686,10 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat interpolator = $interpolate(list.basePath); path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); } - // Need to delete the role_level here b/c organizations and inventory scripts + // Need to change the role_level here b/c organizations and inventory scripts // don't have a "use_role", only "admin_role" and "read_role" if(list.iterator === "organization" || list.iterator === "inventory_script"){ - delete $stateParams[`${list.iterator}_search`].role_level; + $stateParams[`${list.iterator}_search`].role_level = "admin_role"; } return qs.search(path, $stateParams[`${list.iterator}_search`]); }