NIFI-11287: detect dependent properties when the property it depends on references a parameter (UI) (#7117)

* NIFI-11287: detect dependent properties when the property it depends on references a parameter

* address review feedback

* address more review comments

* - loadProperties checks type before getting the parameter context
- retrieve the parameter context with ajax call from inside the class

* add type parameter to all places calling loadProperties

* get reference parameters by invoking provided callbacks from the client

* check for user permissions before requesting for referenced parameters

* address review feedback

This closes #7117
This commit is contained in:
M Tien 2023-05-11 14:00:57 -07:00 committed by GitHub
parent bfa93b2b9e
commit 09cef4ff99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 22 deletions

View File

@ -73,7 +73,7 @@
require('nf.ProcessGroup'),
require('nf.ProcessGroupConfiguration'),
require('nf.Settings'),
recuire('nf.ParameterContexts'),
require('nf.ParameterContexts'),
require('lodash'));
} else {
factory(root.$,
@ -107,6 +107,7 @@
var groupId = null;
var supportsSensitiveDynamicProperties = false;
var propertyVerificationCallback = null;
var currentParameters = null;
var COMBO_MIN_WIDTH = 212;
var EDITOR_MIN_WIDTH = 212;
var EDITOR_MIN_HEIGHT = 100;
@ -1466,7 +1467,8 @@
// sets the available parameters for the specified property descriptor
var loadParameters = function (propertyDescriptor, parameterDeferred, setParameters) {
parameterDeferred(propertyDescriptor, groupId).done(function (parameters) {
parameterDeferred(nfCommon.isSensitiveProperty(propertyDescriptor), groupId).done(function (parameters) {
currentParameters = parameters;
setParameters(parameters);
});
};
@ -1720,12 +1722,20 @@
// Get the current property value to compare with the dependent value
var propertyValue = property.value;
var referencingParameter = null;
// check if the property references a parameter
if (!_.isEmpty(currentParameters)) {
const paramReference = getExistingParametersReferenced(propertyValue);
if (paramReference.length > 0) {
referencingParameter = paramReference[0].value;
}
}
// Test the dependentValues array against the current value of the property
// If not, then mark the current property hidden attribute is true
if (propertyValue != null) {
if (dependency.hasOwnProperty("dependentValues")) {
hidden = !dependency.dependentValues.includes(propertyValue);
}
if (propertyValue != null && dependency.hasOwnProperty("dependentValues")) {
hidden = !dependency.dependentValues.includes(referencingParameter || propertyValue);
} else {
hidden = true;
}
@ -1867,14 +1877,30 @@
* @param {type} properties
* @param {type} descriptors
* @param {type} history
* @param {type} options
*/
var loadProperties = function (table, properties, descriptors, history) {
var loadProperties = function (table, properties, descriptors, history, options) {
// save the original descriptors and history
table.data({
'descriptors': descriptors,
'history': history
});
if (_.isFunction(options.parameterDeferred) && _.isFunction(options.getParameterContext)) {
var paramContext = options.getParameterContext(groupId);
var canReadParamContext = _.get(paramContext, 'permissions.canRead', false);
if (canReadParamContext) {
options.parameterDeferred(false, groupId).done(function (parameters) {
currentParameters = parameters;
processProperties(table, properties, descriptors);
});
return;
}
}
processProperties(table, properties, descriptors);
};
var processProperties = function (table, properties, descriptors) {
// get the grid
var propertyGrid = table.data('gridInstance');
var propertyData = propertyGrid.getData();
@ -1931,13 +1957,20 @@
if (property.hidden === false) {
// Get the property value by propertyName
var propertyValue = properties[dependency.propertyName];
var referencingParameter = null;
// check if the property references a parameter
if (!_.isEmpty(currentParameters)) {
const paramReference = getExistingParametersReferenced(propertyValue);
if (paramReference.length > 0) {
referencingParameter = paramReference[0].value;
}
}
// Test the dependentValues against the current value of the property
// If not, then mark the current property hidden attribute is true
if (propertyValue != null) {
if (dependency.hasOwnProperty("dependentValues")) {
hidden = !dependency.dependentValues.includes(propertyValue);
}
if (propertyValue != null && dependency.hasOwnProperty("dependentValues")) {
hidden = !dependency.dependentValues.includes(referencingParameter || propertyValue);
} else {
hidden = true;
}
@ -1978,6 +2011,7 @@
* @param {jQuery} propertyTableContainer
*/
var clear = function (propertyTableContainer) {
currentParameters = null;
var options = propertyTableContainer.data('options');
if (options.readOnly === true) {
nfUniversalCapture.removeAllPropertyDetailDialogs();
@ -2001,6 +2035,43 @@
propertyData.setItems([]);
};
/**
* Gets all the referenced parameters from the {currentParameters} based on the value of {parameterReference}
*
* @param {string} parameterReference
* @returns {ParameterEntity[]}
*/
var getExistingParametersReferenced = function (parameterReference) {
if (_.isEmpty(currentParameters)) {
return [];
}
var existingParametersReferenced = [];
if (!_.isNil(parameterReference)) {
// can't use from common/constants because we are modifying the lastIndex below
var paramRefsRegex = /#{(')?([a-zA-Z0-9-_. ]+)\1}/gm;
var possibleMatch;
while ((possibleMatch = paramRefsRegex.exec(parameterReference)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (possibleMatch.index === paramRefsRegex.lastIndex) {
paramRefsRegex.lastIndex++;
}
if (!_.isEmpty(possibleMatch) && possibleMatch.length === 3) {
const parameterName = possibleMatch[2];
var found = currentParameters.find(function (param) {
return param.name === parameterName;
});
if (!_.isNil(found)) {
existingParametersReferenced.push(found);
}
}
}
}
return existingParametersReferenced;
};
var methods = {
/**
* Create a property table. The options are specified in the following
@ -2263,9 +2334,14 @@
* @argument {map} history
*/
loadProperties: function (properties, descriptors, history) {
return this.each(function () {
var table = $(this).find('div.property-table');
loadProperties(table, properties, descriptors, history);
var self = this;
return self.each(function () {
var propertyTableContainer = $(this);
var options = propertyTableContainer.data('options');
var table = propertyTableContainer.find('div.property-table');
loadProperties(table, properties, descriptors, history, options);
});
},

View File

@ -2173,7 +2173,7 @@
/**
* Whether the current user can read from this group.
*
* @returns {boolean} can write
* @returns {boolean} can read
*/
canReadCurrentGroup: function () {
return nfCanvas.canRead();

View File

@ -1672,11 +1672,11 @@
/**
* Gets the parameters for the specified property descriptor and group.
*
* @param propertyDescriptor The property descriptor in question
* @param sensitive The sensitivity of property descriptor in question
* @param groupId The group in question
* @returns {deferred}
*/
var getParameters = function (propertyDescriptor, groupId) {
var getParameters = function (sensitive, groupId) {
return $.Deferred(function (deferred) {
if (nfCommon.isDefinedAndNotNull(groupId)) {
var parameterContext;
@ -1699,8 +1699,6 @@
},
dataType: 'json'
}).done(function (response) {
var sensitive = nfCommon.isSensitiveProperty(propertyDescriptor);
deferred.resolve(response.component.parameters.map(function (parameterEntity) {
return parameterEntity.parameter;
}).filter(function (parameter) {

View File

@ -714,7 +714,7 @@
dataType: 'json'
}).fail(nfErrorHandler.handleAjaxError);
},
parameterDeferred: function (propertyDescriptor, groupId) {
parameterDeferred: function (sensitive, groupId) {
return $.Deferred(function (deferred) {
if (nfCommon.isDefinedAndNotNull(groupId)) {
// processors being configured must be in the current group
@ -729,8 +729,6 @@
},
dataType: 'json'
}).done(function (response) {
var sensitive = nfCommon.isSensitiveProperty(propertyDescriptor);
deferred.resolve(response.component.parameters.map(function (parameterEntity) {
return parameterEntity.parameter;
}).filter(function (parameter) {