mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(core): Add special @tool displayOption (#14318)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
@@ -371,6 +371,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
) as ICredentialDataDecryptedObject;
|
||||
|
||||
if (decryptedDataOriginal.oauthTokenData !== undefined) {
|
||||
|
||||
@@ -219,6 +219,7 @@ export abstract class NodeExecutionContext implements Omit<FunctionsBase, 'getCr
|
||||
additionalData.currentNodeParameters || node.parameters,
|
||||
nodeCredentialDescription,
|
||||
node,
|
||||
nodeType.description,
|
||||
node.parameters,
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -33,7 +33,13 @@ function findPropertyFromParameterName(
|
||||
return options.find(
|
||||
(i) =>
|
||||
i.name === name &&
|
||||
NodeHelpers.displayParameterPath(nodeParameters, i, currentParamPath, node),
|
||||
NodeHelpers.displayParameterPath(
|
||||
nodeParameters,
|
||||
i,
|
||||
currentParamPath,
|
||||
node,
|
||||
nodeType.description,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -160,7 +160,8 @@ export const validateValueAgainstSchema = (
|
||||
|
||||
const propertyDescription = nodeType.description.properties.find(
|
||||
(prop) =>
|
||||
parameterPath[0] === prop.name && NodeHelpers.displayParameter(node.parameters, prop, node),
|
||||
parameterPath[0] === prop.name &&
|
||||
NodeHelpers.displayParameter(node.parameters, prop, node, nodeType.description),
|
||||
);
|
||||
|
||||
if (!propertyDescription) {
|
||||
|
||||
@@ -829,8 +829,16 @@ export class RoutingNode {
|
||||
};
|
||||
let basePath = path ? `${path}.` : '';
|
||||
|
||||
const { node } = this.context;
|
||||
if (!NodeHelpers.displayParameter(node.parameters, nodeProperties, node, node.parameters)) {
|
||||
const { node, nodeType } = this.context;
|
||||
if (
|
||||
!NodeHelpers.displayParameter(
|
||||
node.parameters,
|
||||
nodeProperties,
|
||||
node,
|
||||
nodeType.description,
|
||||
node.parameters,
|
||||
)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
if (nodeProperties.routing) {
|
||||
|
||||
@@ -999,6 +999,7 @@ export class WorkflowExecute {
|
||||
nodeIssues = NodeHelpers.getNodeParametersIssues(
|
||||
nodeType.description.properties,
|
||||
node,
|
||||
nodeType.description,
|
||||
inputData.pinDataNodeNames,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -663,6 +663,7 @@ async function saveCredential(): Promise<ICredentialsResponse | null> {
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
assert(credentialTypeName.value);
|
||||
|
||||
@@ -337,7 +337,7 @@ const removeMismatchedOptionValues = (
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasValidOptions && displayParameter(nodeParameterValues, prop, node.value)) {
|
||||
if (!hasValidOptions && displayParameter(nodeParameterValues, prop, node.value, nodeType)) {
|
||||
unset(nodeParameterValues as object, prop.name);
|
||||
}
|
||||
});
|
||||
@@ -395,6 +395,7 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||
false,
|
||||
false,
|
||||
_node,
|
||||
nodeType,
|
||||
);
|
||||
|
||||
const oldNodeParameters = Object.assign({}, nodeParameters);
|
||||
@@ -453,6 +454,7 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||
true,
|
||||
false,
|
||||
_node,
|
||||
nodeType,
|
||||
);
|
||||
|
||||
for (const key of Object.keys(nodeParameters as object)) {
|
||||
@@ -487,6 +489,7 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||
false,
|
||||
false,
|
||||
_node,
|
||||
nodeType,
|
||||
);
|
||||
const oldNodeParameters = Object.assign({}, nodeParameters);
|
||||
|
||||
@@ -535,6 +538,7 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||
true,
|
||||
false,
|
||||
_node,
|
||||
nodeType,
|
||||
);
|
||||
|
||||
for (const key of Object.keys(nodeParameters as object)) {
|
||||
|
||||
@@ -81,6 +81,7 @@ describe('ParameterInput.vue', () => {
|
||||
};
|
||||
mockNodeTypesState = {
|
||||
allNodeTypes: [],
|
||||
getNodeType: vi.fn().mockReturnValue(null),
|
||||
};
|
||||
createAppModals();
|
||||
});
|
||||
|
||||
@@ -346,6 +346,7 @@ const getIssues = computed<string[]>(() => {
|
||||
node.value.parameters,
|
||||
newPath.join('.'),
|
||||
node.value,
|
||||
nodeTypesStore.getNodeType(node.value.type, node.value.typeVersion),
|
||||
);
|
||||
|
||||
if (props.parameter.type === 'credentialsSelect' && displayValue.value === '') {
|
||||
|
||||
@@ -466,7 +466,13 @@ function getParameterIssues(parameter: INodeProperties): string[] {
|
||||
if (!node.value || !showIssuesInLabelFor.includes(parameter.type)) {
|
||||
return [];
|
||||
}
|
||||
const issues = NodeHelpers.getParameterIssues(parameter, node.value.parameters, '', node.value);
|
||||
const issues = NodeHelpers.getParameterIssues(
|
||||
parameter,
|
||||
node.value.parameters,
|
||||
'',
|
||||
node.value,
|
||||
nodeType.value,
|
||||
);
|
||||
|
||||
return issues.parameters?.[parameter.name] ?? [];
|
||||
}
|
||||
|
||||
@@ -407,6 +407,7 @@ function updateNodeIssues(): void {
|
||||
const parameterIssues = NodeHelpers.getNodeParametersIssues(
|
||||
nodeType.value?.properties ?? [],
|
||||
props.node,
|
||||
nodeType.value,
|
||||
);
|
||||
if (parameterIssues) {
|
||||
ndvStore.updateNodeParameterIssues(parameterIssues);
|
||||
|
||||
@@ -874,6 +874,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
);
|
||||
|
||||
node.parameters = nodeParameters ?? {};
|
||||
|
||||
@@ -106,7 +106,17 @@ export function useNodeHelpers() {
|
||||
node: INodeUi | null,
|
||||
displayKey: 'displayOptions' | 'disabledOptions' = 'displayOptions',
|
||||
) {
|
||||
return NodeHelpers.displayParameterPath(nodeValues, parameter, path, node, displayKey);
|
||||
const nodeTypeDescription = node?.type
|
||||
? nodeTypesStore.getNodeType(node.type, node.typeVersion)
|
||||
: null;
|
||||
return NodeHelpers.displayParameterPath(
|
||||
nodeValues,
|
||||
parameter,
|
||||
path,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
displayKey,
|
||||
);
|
||||
}
|
||||
|
||||
function getNodeIssues(
|
||||
@@ -137,7 +147,7 @@ export function useNodeHelpers() {
|
||||
|
||||
// Add potential parameter issues
|
||||
if (!ignoreIssues.includes('parameters')) {
|
||||
nodeIssues = NodeHelpers.getNodeParametersIssues(nodeType.properties, node);
|
||||
nodeIssues = NodeHelpers.getNodeParametersIssues(nodeType.properties, node, nodeType);
|
||||
}
|
||||
|
||||
if (!ignoreIssues.includes('credentials')) {
|
||||
@@ -287,6 +297,7 @@ export function useNodeHelpers() {
|
||||
const fullNodeIssues: INodeIssues | null = NodeHelpers.getNodeParametersIssues(
|
||||
localNodeType.properties,
|
||||
node,
|
||||
nodeType ?? null,
|
||||
);
|
||||
|
||||
let newIssues: INodeIssueObjectProperty | null = null;
|
||||
|
||||
@@ -589,6 +589,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||
isCredentialOnly,
|
||||
false,
|
||||
node,
|
||||
nodeType,
|
||||
);
|
||||
nodeData.parameters = nodeParameters !== null ? nodeParameters : {};
|
||||
|
||||
|
||||
@@ -1331,6 +1331,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
true,
|
||||
false,
|
||||
latestNode,
|
||||
nodeType,
|
||||
);
|
||||
|
||||
if (latestNode) {
|
||||
|
||||
@@ -338,8 +338,7 @@ export function getGenericHints({
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
undefined,
|
||||
false,
|
||||
nodeType,
|
||||
);
|
||||
|
||||
const assignments =
|
||||
|
||||
@@ -22,11 +22,17 @@ export function getNodeTypeDisplayableCredentials(
|
||||
// credentials can have conditional requirements that depend on
|
||||
// node parameters.
|
||||
const nodeParameters =
|
||||
NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, false, node) ??
|
||||
node.parameters;
|
||||
NodeHelpers.getNodeParameters(
|
||||
nodeType.properties,
|
||||
node.parameters,
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
nodeType,
|
||||
) ?? node.parameters;
|
||||
|
||||
const displayableCredentials = nodeTypeCreds.filter((credentialTypeDescription) => {
|
||||
return NodeHelpers.displayParameter(nodeParameters, credentialTypeDescription, node);
|
||||
return NodeHelpers.displayParameter(nodeParameters, credentialTypeDescription, node, nodeType);
|
||||
});
|
||||
|
||||
return displayableCredentials;
|
||||
|
||||
@@ -1376,6 +1376,7 @@ export interface IDisplayOptions {
|
||||
};
|
||||
show?: {
|
||||
'@version'?: Array<number | DisplayCondition>;
|
||||
'@tool'?: [boolean];
|
||||
[key: string]: Array<NodeParameterValue | DisplayCondition> | undefined;
|
||||
};
|
||||
|
||||
|
||||
@@ -392,6 +392,7 @@ const getPropertyValues = (
|
||||
nodeValues: INodeParameters,
|
||||
propertyName: string,
|
||||
node: Pick<INode, 'typeVersion'> | null,
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
nodeValuesRoot: INodeParameters,
|
||||
) => {
|
||||
let value;
|
||||
@@ -400,6 +401,8 @@ const getPropertyValues = (
|
||||
value = get(nodeValuesRoot, propertyName.slice(1));
|
||||
} else if (propertyName === '@version') {
|
||||
value = node?.typeVersion || 0;
|
||||
} else if (propertyName === '@tool') {
|
||||
value = nodeTypeDescription?.name.endsWith('Tool') ?? false;
|
||||
} else {
|
||||
// Get the value from current level
|
||||
value = get(nodeValues, propertyName);
|
||||
@@ -487,6 +490,7 @@ export function displayParameter(
|
||||
nodeValues: INodeParameters,
|
||||
parameter: INodeProperties | INodeCredentialDescription,
|
||||
node: Pick<INode, 'typeVersion'> | null, // Allow null as it does also get used by credentials and they do not have versioning yet
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
nodeValuesRoot?: INodeParameters,
|
||||
displayKey: 'displayOptions' | 'disabledOptions' = 'displayOptions',
|
||||
) {
|
||||
@@ -501,7 +505,13 @@ export function displayParameter(
|
||||
if (show) {
|
||||
// All the defined rules have to match to display parameter
|
||||
for (const propertyName of Object.keys(show)) {
|
||||
const values = getPropertyValues(nodeValues, propertyName, node, nodeValuesRoot);
|
||||
const values = getPropertyValues(
|
||||
nodeValues,
|
||||
propertyName,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
nodeValuesRoot,
|
||||
);
|
||||
|
||||
if (values.some((v) => typeof v === 'string' && v.charAt(0) === '=')) {
|
||||
return true;
|
||||
@@ -516,7 +526,13 @@ export function displayParameter(
|
||||
if (hide) {
|
||||
// Any of the defined hide rules have to match to hide the parameter
|
||||
for (const propertyName of Object.keys(hide)) {
|
||||
const values = getPropertyValues(nodeValues, propertyName, node, nodeValuesRoot);
|
||||
const values = getPropertyValues(
|
||||
nodeValues,
|
||||
propertyName,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
nodeValuesRoot,
|
||||
);
|
||||
|
||||
if (values.length !== 0 && checkConditions(hide[propertyName]!, values)) {
|
||||
return false;
|
||||
@@ -541,6 +557,7 @@ export function displayParameterPath(
|
||||
parameter: INodeProperties | INodeCredentialDescription,
|
||||
path: string,
|
||||
node: Pick<INode, 'typeVersion'> | null,
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
displayKey: 'displayOptions' | 'disabledOptions' = 'displayOptions',
|
||||
) {
|
||||
let resolvedNodeValues = nodeValues;
|
||||
@@ -554,7 +571,14 @@ export function displayParameterPath(
|
||||
nodeValuesRoot = get(nodeValues, 'parameters') as INodeParameters;
|
||||
}
|
||||
|
||||
return displayParameter(resolvedNodeValues, parameter, node, nodeValuesRoot, displayKey);
|
||||
return displayParameter(
|
||||
resolvedNodeValues,
|
||||
parameter,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
nodeValuesRoot,
|
||||
displayKey,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,6 +722,14 @@ export function getParameterResolveOrder(
|
||||
return executionOrder;
|
||||
}
|
||||
|
||||
export type GetNodeParametersOptions = {
|
||||
onlySimpleTypes?: boolean;
|
||||
dataIsResolved?: boolean; // If nodeValues are already fully resolved (so that all default values got added already)
|
||||
nodeValuesRoot?: INodeParameters;
|
||||
parentType?: string;
|
||||
parameterDependencies?: IParameterDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the node parameter values. Depending on the settings it either just returns the none
|
||||
* default values or it applies all the default values.
|
||||
@@ -706,9 +738,7 @@ export function getParameterResolveOrder(
|
||||
* @param {INodeParameters} nodeValues The node parameter data
|
||||
* @param {boolean} returnDefaults If default values get added or only none default values returned
|
||||
* @param {boolean} returnNoneDisplayed If also values which should not be displayed should be returned
|
||||
* @param {boolean} [onlySimpleTypes=false] If only simple types should be resolved
|
||||
* @param {boolean} [dataIsResolved=false] If nodeValues are already fully resolved (so that all default values got added already)
|
||||
* @param {INodeParameters} [nodeValuesRoot] The root node-parameter-data
|
||||
* @param {GetNodeParametersOptions} options Optional properties
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
export function getNodeParameters(
|
||||
@@ -717,12 +747,11 @@ export function getNodeParameters(
|
||||
returnDefaults: boolean,
|
||||
returnNoneDisplayed: boolean,
|
||||
node: Pick<INode, 'typeVersion'> | null,
|
||||
onlySimpleTypes = false,
|
||||
dataIsResolved = false,
|
||||
nodeValuesRoot?: INodeParameters,
|
||||
parentType?: string,
|
||||
parameterDependencies?: IParameterDependencies,
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
options?: GetNodeParametersOptions,
|
||||
): INodeParameters | null {
|
||||
let { nodeValuesRoot, parameterDependencies } = options ?? {};
|
||||
const { onlySimpleTypes = false, dataIsResolved = false, parentType } = options ?? {};
|
||||
if (parameterDependencies === undefined) {
|
||||
parameterDependencies = getParameterDependencies(nodePropertiesArray);
|
||||
}
|
||||
@@ -752,11 +781,14 @@ export function getNodeParameters(
|
||||
true,
|
||||
true,
|
||||
node,
|
||||
true,
|
||||
true,
|
||||
nodeTypeDescription,
|
||||
{
|
||||
onlySimpleTypes: true,
|
||||
dataIsResolved: true,
|
||||
nodeValuesRoot,
|
||||
parentType,
|
||||
parameterDependencies,
|
||||
},
|
||||
) as INodeParameters;
|
||||
}
|
||||
|
||||
@@ -781,7 +813,13 @@ export function getNodeParameters(
|
||||
|
||||
if (
|
||||
!returnNoneDisplayed &&
|
||||
!displayParameter(nodeValuesDisplayCheck, nodeProperties, node, nodeValuesRoot)
|
||||
!displayParameter(
|
||||
nodeValuesDisplayCheck,
|
||||
nodeProperties,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
nodeValuesRoot,
|
||||
)
|
||||
) {
|
||||
if (!returnNoneDisplayed || !returnDefaults) {
|
||||
continue;
|
||||
@@ -792,7 +830,15 @@ export function getNodeParameters(
|
||||
// Is a simple property so can be set as it is
|
||||
|
||||
if (duplicateParameterNames.includes(nodeProperties.name)) {
|
||||
if (!displayParameter(nodeValuesDisplayCheck, nodeProperties, node, nodeValuesRoot)) {
|
||||
if (
|
||||
!displayParameter(
|
||||
nodeValuesDisplayCheck,
|
||||
nodeProperties,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
nodeValuesRoot,
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -871,10 +917,13 @@ export function getNodeParameters(
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
node,
|
||||
false,
|
||||
false,
|
||||
nodeTypeDescription,
|
||||
{
|
||||
onlySimpleTypes: false,
|
||||
dataIsResolved: false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
parentType: nodeProperties.type,
|
||||
},
|
||||
);
|
||||
|
||||
if (tempNodeParameters !== null) {
|
||||
@@ -944,10 +993,13 @@ export function getNodeParameters(
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
node,
|
||||
false,
|
||||
false,
|
||||
nodeTypeDescription,
|
||||
{
|
||||
onlySimpleTypes: false,
|
||||
dataIsResolved: false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
parentType: nodeProperties.type,
|
||||
},
|
||||
);
|
||||
if (tempValue !== null) {
|
||||
tempArrayValue.push(tempValue);
|
||||
@@ -972,10 +1024,13 @@ export function getNodeParameters(
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
node,
|
||||
false,
|
||||
false,
|
||||
nodeTypeDescription,
|
||||
{
|
||||
onlySimpleTypes: false,
|
||||
dataIsResolved: false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
parentType: nodeProperties.type,
|
||||
},
|
||||
);
|
||||
if (tempValue !== null) {
|
||||
Object.assign(tempNodeParameters, tempValue);
|
||||
@@ -1236,6 +1291,7 @@ export function getNodeOutputs(
|
||||
export function getNodeParametersIssues(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
node: INode,
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
pinDataNodeNames?: string[],
|
||||
): INodeIssues | null {
|
||||
const foundIssues: INodeIssues = {};
|
||||
@@ -1247,7 +1303,13 @@ export function getNodeParametersIssues(
|
||||
}
|
||||
|
||||
for (const nodeProperty of nodePropertiesArray) {
|
||||
propertyIssues = getParameterIssues(nodeProperty, node.parameters, '', node);
|
||||
propertyIssues = getParameterIssues(
|
||||
nodeProperty,
|
||||
node.parameters,
|
||||
'',
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
);
|
||||
mergeIssues(foundIssues, propertyIssues);
|
||||
}
|
||||
|
||||
@@ -1456,9 +1518,16 @@ export function getParameterIssues(
|
||||
nodeValues: INodeParameters,
|
||||
path: string,
|
||||
node: INode,
|
||||
nodeTypeDescription: INodeTypeDescription | null,
|
||||
): INodeIssues {
|
||||
const foundIssues: INodeIssues = {};
|
||||
const isDisplayed = displayParameterPath(nodeValues, nodeProperties, path, node);
|
||||
const isDisplayed = displayParameterPath(
|
||||
nodeValues,
|
||||
nodeProperties,
|
||||
path,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
);
|
||||
if (nodeProperties.required === true) {
|
||||
if (isDisplayed) {
|
||||
const value = getParameterValueByPath(nodeValues, nodeProperties.name, path);
|
||||
@@ -1636,7 +1705,13 @@ export function getParameterIssues(
|
||||
let propertyIssues;
|
||||
|
||||
for (const optionData of checkChildNodeProperties) {
|
||||
propertyIssues = getParameterIssues(optionData.data, nodeValues, optionData.basePath, node);
|
||||
propertyIssues = getParameterIssues(
|
||||
optionData.data,
|
||||
nodeValues,
|
||||
optionData.basePath,
|
||||
node,
|
||||
nodeTypeDescription,
|
||||
);
|
||||
mergeIssues(foundIssues, propertyIssues);
|
||||
}
|
||||
|
||||
|
||||
@@ -198,6 +198,7 @@ export function generateNodesGraph(
|
||||
true,
|
||||
false,
|
||||
stickyNote,
|
||||
stickyType.description,
|
||||
) ?? {};
|
||||
} catch {
|
||||
// prevent node param resolution from failing graph generation
|
||||
@@ -376,6 +377,7 @@ export function generateNodesGraph(
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
nodeType.description,
|
||||
);
|
||||
|
||||
if (nodeParameters) {
|
||||
|
||||
@@ -112,6 +112,7 @@ export class Workflow {
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
nodeType.description,
|
||||
);
|
||||
node.parameters = nodeParameters !== null ? nodeParameters : {};
|
||||
}
|
||||
|
||||
@@ -2166,6 +2166,7 @@ describe('NodeHelpers', () => {
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsFalse);
|
||||
|
||||
@@ -2176,6 +2177,7 @@ describe('NodeHelpers', () => {
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsTrue);
|
||||
|
||||
@@ -2186,6 +2188,7 @@ describe('NodeHelpers', () => {
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsFalse);
|
||||
|
||||
@@ -2196,6 +2199,7 @@ describe('NodeHelpers', () => {
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsTrue);
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
getParameterIssues,
|
||||
isTriggerNode,
|
||||
isExecutable,
|
||||
displayParameter,
|
||||
} from '@/NodeHelpers';
|
||||
import type { Workflow } from '@/Workflow';
|
||||
|
||||
@@ -3420,6 +3421,7 @@ describe('NodeHelpers', () => {
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsFalse);
|
||||
|
||||
@@ -3430,6 +3432,7 @@ describe('NodeHelpers', () => {
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsTrue);
|
||||
|
||||
@@ -3440,6 +3443,7 @@ describe('NodeHelpers', () => {
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsFalse);
|
||||
|
||||
@@ -3450,6 +3454,7 @@ describe('NodeHelpers', () => {
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsTrue);
|
||||
});
|
||||
@@ -4193,6 +4198,7 @@ describe('NodeHelpers', () => {
|
||||
testData.input.nodeValues,
|
||||
testData.input.path,
|
||||
testData.input.node,
|
||||
null,
|
||||
);
|
||||
expect(result).toEqual(testData.output);
|
||||
});
|
||||
@@ -4209,6 +4215,18 @@ describe('NodeHelpers', () => {
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
const testNodeType: INodeTypeDescription = {
|
||||
name: 'Test Node',
|
||||
version: 0,
|
||||
defaults: {},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
properties: [],
|
||||
displayName: '',
|
||||
group: [],
|
||||
description: '',
|
||||
};
|
||||
|
||||
it('Should validate required dateTime parameters if empty string', () => {
|
||||
const nodeProperties: INodeProperties = {
|
||||
displayName: 'Date Time',
|
||||
@@ -4221,7 +4239,7 @@ describe('NodeHelpers', () => {
|
||||
testDateTime: '',
|
||||
};
|
||||
|
||||
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);
|
||||
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode, null);
|
||||
|
||||
expect(result).toEqual({
|
||||
parameters: {
|
||||
@@ -4242,7 +4260,7 @@ describe('NodeHelpers', () => {
|
||||
testDateTime: undefined,
|
||||
};
|
||||
|
||||
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);
|
||||
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode, testNodeType);
|
||||
|
||||
expect(result).toEqual({
|
||||
parameters: {
|
||||
@@ -4513,4 +4531,393 @@ describe('NodeHelpers', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
describe('displayParameter', () => {
|
||||
const testNode: INode = {
|
||||
id: '12345',
|
||||
name: 'Test Node',
|
||||
typeVersion: 1,
|
||||
type: 'n8n-nodes-base.testNode',
|
||||
position: [1, 1],
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
const testNodeType: INodeTypeDescription = {
|
||||
name: 'Test Node',
|
||||
version: 0,
|
||||
defaults: {},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
properties: [],
|
||||
displayName: '',
|
||||
group: [],
|
||||
description: '',
|
||||
};
|
||||
|
||||
const defaultTestInput = {
|
||||
nodeValues: {},
|
||||
parameter: {
|
||||
displayName: 'Test Parameter',
|
||||
name: 'testParameter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
} as INodeProperties,
|
||||
node: testNode,
|
||||
nodeTypeDescription: testNodeType,
|
||||
nodeValuesRoot: undefined as undefined | INodeParameters,
|
||||
displayKey: 'displayOptions' as 'displayOptions' | 'disabledOptions',
|
||||
};
|
||||
|
||||
const tests: Array<[string, typeof defaultTestInput, boolean]> = [
|
||||
['Should return true if no displayOptions are defined', { ...defaultTestInput }, true],
|
||||
[
|
||||
'Should return true if displayOptions.show conditions are met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if displayOptions.show conditions are not met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value2' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return false if displayOptions.hide conditions are met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
hide: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if displayOptions.hide conditions are not met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value2' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
hide: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return true if displayOptions.show and hide conditions are both met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
hide: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false, // Hide takes precedence over show
|
||||
],
|
||||
[
|
||||
'Should return true if displayOptions.show conditions are met with multiple values',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value2' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
condition: ['value1', 'value2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if displayOptions.hide conditions are met with multiple values',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value2' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
hide: {
|
||||
condition: ['value1', 'value2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if @tool is true in nodeTypeDescription of tool',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeTypeDescription: {
|
||||
...testNodeType,
|
||||
name: testNodeType.name + 'Tool',
|
||||
},
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@tool': [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if @tool is true in nodeTypeDescription of non-tool',
|
||||
{
|
||||
...defaultTestInput,
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@tool': [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if @version condition is met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
node: {
|
||||
...testNode,
|
||||
typeVersion: 2,
|
||||
},
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@version': [
|
||||
{
|
||||
_cnd: {
|
||||
gte: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if @version condition is not met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
node: {
|
||||
...testNode,
|
||||
typeVersion: 1,
|
||||
},
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@version': [
|
||||
{
|
||||
_cnd: {
|
||||
gte: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if @tool and @version conditions are both met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
node: {
|
||||
...testNode,
|
||||
typeVersion: 2,
|
||||
},
|
||||
nodeTypeDescription: {
|
||||
...testNodeType,
|
||||
name: testNodeType.name + 'Tool',
|
||||
},
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@tool': [true],
|
||||
'@version': [
|
||||
{
|
||||
_cnd: {
|
||||
gte: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if @tool is true but @version condition is not met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
node: {
|
||||
...testNode,
|
||||
typeVersion: 1,
|
||||
},
|
||||
nodeTypeDescription: {
|
||||
...testNodeType,
|
||||
name: testNodeType.name + 'Tool',
|
||||
},
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@tool': [true],
|
||||
'@version': [
|
||||
{
|
||||
_cnd: {
|
||||
gte: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if no disabledOptions are defined',
|
||||
{
|
||||
...defaultTestInput,
|
||||
displayKey: 'disabledOptions',
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if disabledOptions.hide conditions are met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
disabledOptions: {
|
||||
hide: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
displayKey: 'disabledOptions',
|
||||
},
|
||||
false,
|
||||
],
|
||||
[
|
||||
'Should return true if disabledOptions.hide conditions are not met',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value2' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
disabledOptions: {
|
||||
hide: {
|
||||
condition: ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
displayKey: 'disabledOptions',
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return true if nodeValuesRoot contains a matching value for displayOptions.show',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: {},
|
||||
nodeValuesRoot: { condition: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/condition': ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
],
|
||||
[
|
||||
'Should return false if nodeValuesRoot does not contain a matching value for displayOptions.show',
|
||||
{
|
||||
...defaultTestInput,
|
||||
nodeValues: { condition: 'value1' },
|
||||
nodeValuesRoot: { anotherKey: 'value1' },
|
||||
parameter: {
|
||||
...defaultTestInput.parameter,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/condition': ['value1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
],
|
||||
];
|
||||
|
||||
for (const [description, input, expected] of tests) {
|
||||
test(description, () => {
|
||||
const result = displayParameter(
|
||||
input.nodeValues,
|
||||
input.parameter,
|
||||
input.node,
|
||||
input.nodeTypeDescription,
|
||||
input.nodeValuesRoot,
|
||||
input.displayKey,
|
||||
);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user