mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
refactor(core): Trim down NodeHelpers (no-changelog) (#14829)
This commit is contained in:
committed by
GitHub
parent
88bce7fd8b
commit
3e5e3a585c
@@ -34,8 +34,6 @@ import type {
|
||||
INodeInputConfiguration,
|
||||
GenericValue,
|
||||
DisplayCondition,
|
||||
NodeHint,
|
||||
INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
} from './Interfaces';
|
||||
import { validateFilterParameter } from './NodeParameters/FilterParameter';
|
||||
@@ -235,87 +233,6 @@ export const cronNodeOptions: INodePropertyCollection[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const declarativeNodeOptionParameters: INodeProperties = {
|
||||
displayName: 'Request Options',
|
||||
name: 'requestOptions',
|
||||
type: 'collection',
|
||||
isNodeSetting: true,
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Batching',
|
||||
name: 'batching',
|
||||
placeholder: 'Add Batching',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {
|
||||
batch: {},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Batching',
|
||||
name: 'batch',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Items per Batch',
|
||||
name: 'batchSize',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: -1,
|
||||
},
|
||||
default: 50,
|
||||
description:
|
||||
'Input will be split in batches to throttle requests. -1 for disabled. 0 will be treated as 1.',
|
||||
},
|
||||
{
|
||||
displayName: 'Batch Interval (ms)',
|
||||
name: 'batchInterval',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
default: 1000,
|
||||
description: 'Time (in milliseconds) between each batch of requests. 0 for disabled.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore SSL Issues (Insecure)',
|
||||
name: 'allowUnauthorizedCerts',
|
||||
type: 'boolean',
|
||||
noDataExpression: true,
|
||||
default: false,
|
||||
description:
|
||||
'Whether to accept the response even if SSL certificate validation is not possible',
|
||||
},
|
||||
{
|
||||
displayName: 'Proxy',
|
||||
name: 'proxy',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. http://myproxy:3128',
|
||||
description:
|
||||
'HTTP proxy to use. If authentication is required it can be defined as follow: http://username:password@myproxy:3128',
|
||||
},
|
||||
{
|
||||
displayName: 'Timeout',
|
||||
name: 'timeout',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 10000,
|
||||
description:
|
||||
'Time in ms to wait for the server to send response headers (and start the response body) before aborting the request',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the provided node type has any output types other than the main connection type.
|
||||
* @param typeDescription The node's type description to check.
|
||||
@@ -332,62 +249,6 @@ export function isSubNodeType(
|
||||
: false;
|
||||
}
|
||||
|
||||
/** Augments additional `Request Options` property on declarative node-type */
|
||||
export function applyDeclarativeNodeOptionParameters(nodeType: INodeType): void {
|
||||
if (
|
||||
nodeType.execute ||
|
||||
nodeType.trigger ||
|
||||
nodeType.webhook ||
|
||||
nodeType.description.polling ||
|
||||
isSubNodeType(nodeType.description)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parameters = nodeType.description.properties;
|
||||
|
||||
if (!parameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Was originally under "options" instead of "requestOptions" so the chance
|
||||
// that that existed was quite high. With this name the chance is actually
|
||||
// very low that it already exists but lets leave it in anyway to be sure.
|
||||
const existingRequestOptionsIndex = parameters.findIndex(
|
||||
(parameter) => parameter.name === 'requestOptions',
|
||||
);
|
||||
if (existingRequestOptionsIndex !== -1) {
|
||||
parameters[existingRequestOptionsIndex] = {
|
||||
...declarativeNodeOptionParameters,
|
||||
options: [
|
||||
...(declarativeNodeOptionParameters.options || []),
|
||||
...(parameters[existingRequestOptionsIndex]?.options || []),
|
||||
],
|
||||
};
|
||||
|
||||
const options = parameters[existingRequestOptionsIndex]?.options;
|
||||
|
||||
if (options) {
|
||||
options.sort((a, b) => {
|
||||
if ('displayName' in a && 'displayName' in b) {
|
||||
if (a.displayName < b.displayName) {
|
||||
return -1;
|
||||
}
|
||||
if (a.displayName > b.displayName) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
parameters.push(declarativeNodeOptionParameters);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const getPropertyValues = (
|
||||
nodeValues: INodeParameters,
|
||||
propertyName: string,
|
||||
@@ -660,7 +521,7 @@ function getParameterDependencies(nodePropertiesArray: INodeProperties[]): IPara
|
||||
* Returns in which order the parameters should be resolved
|
||||
* to have the parameters available they depend on
|
||||
*/
|
||||
export function getParameterResolveOrder(
|
||||
function getParameterResolveOrder(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
parameterDependencies: IParameterDependencies,
|
||||
): number[] {
|
||||
@@ -722,7 +583,7 @@ export function getParameterResolveOrder(
|
||||
return executionOrder;
|
||||
}
|
||||
|
||||
export type GetNodeParametersOptions = {
|
||||
type GetNodeParametersOptions = {
|
||||
onlySimpleTypes?: boolean;
|
||||
dataIsResolved?: boolean; // If nodeValues are already fully resolved (so that all default values got added already)
|
||||
nodeValuesRoot?: INodeParameters;
|
||||
@@ -1164,75 +1025,6 @@ export function getNodeInputs(
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodeHints(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
nodeTypeData: INodeTypeDescription,
|
||||
nodeInputData?: {
|
||||
runExecutionData: IRunExecutionData | null;
|
||||
runIndex: number;
|
||||
connectionInputData: INodeExecutionData[];
|
||||
},
|
||||
): NodeHint[] {
|
||||
const hints: NodeHint[] = [];
|
||||
|
||||
if (nodeTypeData?.hints?.length) {
|
||||
for (const hint of nodeTypeData.hints) {
|
||||
if (hint.displayCondition) {
|
||||
try {
|
||||
let display;
|
||||
|
||||
if (nodeInputData === undefined) {
|
||||
display = (workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
hint.displayCondition,
|
||||
'internal',
|
||||
{},
|
||||
) || false) as boolean;
|
||||
} else {
|
||||
const { runExecutionData, runIndex, connectionInputData } = nodeInputData;
|
||||
display = workflow.expression.getParameterValue(
|
||||
hint.displayCondition,
|
||||
runExecutionData ?? null,
|
||||
runIndex,
|
||||
0,
|
||||
node.name,
|
||||
connectionInputData,
|
||||
'manual',
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof display === 'string' && display.trim() === 'true') {
|
||||
display = true;
|
||||
}
|
||||
|
||||
if (typeof display !== 'boolean') {
|
||||
console.warn(
|
||||
`Condition was not resolved as boolean in '${node.name}' node for hint: `,
|
||||
hint.message,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (display) {
|
||||
hints.push(hint);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`Could not calculate display condition in '${node.name}' node for hint: `,
|
||||
hint.message,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
hints.push(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hints;
|
||||
}
|
||||
|
||||
export function getNodeOutputs(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
@@ -1320,44 +1112,6 @@ export function getNodeParametersIssues(
|
||||
return foundIssues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the issues of the node as string
|
||||
*
|
||||
* @param {INodeIssues} issues The issues of the node
|
||||
* @param {INode} node The node
|
||||
*/
|
||||
export function nodeIssuesToString(issues: INodeIssues, node?: INode): string[] {
|
||||
const nodeIssues = [];
|
||||
|
||||
if (issues.execution !== undefined) {
|
||||
nodeIssues.push('Execution Error.');
|
||||
}
|
||||
|
||||
const objectProperties = ['parameters', 'credentials', 'input'];
|
||||
|
||||
let issueText: string;
|
||||
let parameterName: string;
|
||||
for (const propertyName of objectProperties) {
|
||||
if (issues[propertyName] !== undefined) {
|
||||
for (parameterName of Object.keys(issues[propertyName] as object)) {
|
||||
for (issueText of (issues[propertyName] as INodeIssueObjectProperty)[parameterName]) {
|
||||
nodeIssues.push(issueText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (issues.typeUnknown !== undefined) {
|
||||
if (node !== undefined) {
|
||||
nodeIssues.push(`Node Type "${node.type}" is not known.`);
|
||||
} else {
|
||||
nodeIssues.push('Node Type is not known.');
|
||||
}
|
||||
}
|
||||
|
||||
return nodeIssues;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validates resource locator node parameters based on validation ruled defined in each parameter mode
|
||||
*/
|
||||
|
||||
@@ -5,14 +5,11 @@ import {
|
||||
type INode,
|
||||
type INodeParameters,
|
||||
type INodeProperties,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
} from '@/Interfaces';
|
||||
import {
|
||||
getNodeParameters,
|
||||
getNodeHints,
|
||||
isSubNodeType,
|
||||
applyDeclarativeNodeOptionParameters,
|
||||
getParameterIssues,
|
||||
isTriggerNode,
|
||||
isExecutable,
|
||||
@@ -3461,95 +3458,6 @@ describe('NodeHelpers', () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe('getNodeHints', () => {
|
||||
//TODO: Add more tests here when hints are added to some node types
|
||||
test('should return node hints if present in node type', () => {
|
||||
const testType = {
|
||||
hints: [
|
||||
{
|
||||
message: 'TEST HINT',
|
||||
},
|
||||
],
|
||||
} as INodeTypeDescription;
|
||||
|
||||
const workflow = {} as unknown as Workflow;
|
||||
|
||||
const node: INode = {
|
||||
name: 'Test Node Hints',
|
||||
} as INode;
|
||||
const nodeType = testType;
|
||||
|
||||
const hints = getNodeHints(workflow, node, nodeType);
|
||||
|
||||
expect(hints).toHaveLength(1);
|
||||
expect(hints[0].message).toEqual('TEST HINT');
|
||||
});
|
||||
test('should not include hint if displayCondition is false', () => {
|
||||
const testType = {
|
||||
hints: [
|
||||
{
|
||||
message: 'TEST HINT',
|
||||
displayCondition: 'FALSE DISPLAY CONDITION EXPESSION',
|
||||
},
|
||||
],
|
||||
} as INodeTypeDescription;
|
||||
|
||||
const workflow = {
|
||||
expression: {
|
||||
getSimpleParameterValue(
|
||||
_node: string,
|
||||
_parameter: string,
|
||||
_mode: string,
|
||||
_additionalData = {},
|
||||
) {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
} as unknown as Workflow;
|
||||
|
||||
const node: INode = {
|
||||
name: 'Test Node Hints',
|
||||
} as INode;
|
||||
const nodeType = testType;
|
||||
|
||||
const hints = getNodeHints(workflow, node, nodeType);
|
||||
|
||||
expect(hints).toHaveLength(0);
|
||||
});
|
||||
test('should include hint if displayCondition is true', () => {
|
||||
const testType = {
|
||||
hints: [
|
||||
{
|
||||
message: 'TEST HINT',
|
||||
displayCondition: 'TRUE DISPLAY CONDITION EXPESSION',
|
||||
},
|
||||
],
|
||||
} as INodeTypeDescription;
|
||||
|
||||
const workflow = {
|
||||
expression: {
|
||||
getSimpleParameterValue(
|
||||
_node: string,
|
||||
_parameter: string,
|
||||
_mode: string,
|
||||
_additionalData = {},
|
||||
) {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
} as unknown as Workflow;
|
||||
|
||||
const node: INode = {
|
||||
name: 'Test Node Hints',
|
||||
} as INode;
|
||||
const nodeType = testType;
|
||||
|
||||
const hints = getNodeHints(workflow, node, nodeType);
|
||||
|
||||
expect(hints).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSubNodeType', () => {
|
||||
const tests: Array<[boolean, Pick<INodeTypeDescription, 'outputs'> | null]> = [
|
||||
[false, null],
|
||||
@@ -3564,60 +3472,6 @@ describe('NodeHelpers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyDeclarativeNodeOptionParameters', () => {
|
||||
test.each([
|
||||
[
|
||||
'node with execute method',
|
||||
{
|
||||
execute: jest.fn(),
|
||||
description: {
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'node with trigger method',
|
||||
{
|
||||
trigger: jest.fn(),
|
||||
description: {
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'node with webhook method',
|
||||
{
|
||||
webhook: jest.fn(),
|
||||
description: {
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'a polling node-type',
|
||||
{
|
||||
description: {
|
||||
polling: true,
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'a node-type with a non-main output',
|
||||
{
|
||||
description: {
|
||||
outputs: ['main', 'ai_agent'],
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
])('should not modify properties on node with %s method', (_, nodeTypeName) => {
|
||||
const nodeType = nodeTypeName as unknown as INodeType;
|
||||
applyDeclarativeNodeOptionParameters(nodeType);
|
||||
expect(nodeType.description.properties).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getParameterIssues', () => {
|
||||
const tests: Array<{
|
||||
description: string;
|
||||
|
||||
Reference in New Issue
Block a user