mirror of
https://github.com/ansible/awx.git
synced 2026-03-13 23:17:32 -02:30
Merge pull request #4819 from jaredevantabor/autopopulate-lookups
Autopopulate lookups
This commit is contained in:
@@ -43,11 +43,11 @@ 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',
|
||||
autopopulateLookup: false,
|
||||
list: 'OrganizationList',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -463,10 +463,112 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper'])
|
||||
return {
|
||||
require: 'ngModel',
|
||||
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,
|
||||
watchBasePath;
|
||||
|
||||
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 = '?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&role_level=use_role';
|
||||
break;
|
||||
case 'network_credential':
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 (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, () => {
|
||||
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
|
||||
@@ -485,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
|
||||
|
||||
@@ -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 <resource>-<mode>.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']) {
|
||||
@@ -1370,6 +1375,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 += `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 300, 'blur': 0 } }"`;
|
||||
html += " awlookup >\n";
|
||||
html += "</div>\n";
|
||||
|
||||
@@ -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 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"){
|
||||
$stateParams[`${list.iterator}_search`].role_level = "admin_role";
|
||||
}
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user