mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core): Node hints(warnings) system (#8954)
This commit is contained in:
@@ -392,7 +392,7 @@ export interface IGetExecuteTriggerFunctions {
|
||||
}
|
||||
|
||||
export interface IRunNodeResponse {
|
||||
data: INodeExecutionData[][] | null | undefined;
|
||||
data: INodeExecutionData[][] | NodeExecutionOutput | null | undefined;
|
||||
closeFunction?: CloseFunction;
|
||||
}
|
||||
export interface IGetExecuteFunctions {
|
||||
@@ -1423,6 +1423,20 @@ export interface SupplyData {
|
||||
closeFunction?: CloseFunction;
|
||||
}
|
||||
|
||||
export class NodeExecutionOutput extends Array {
|
||||
private hints: NodeExecutionHint[];
|
||||
|
||||
constructor(data: INodeExecutionData[][], hints: NodeExecutionHint[] = []) {
|
||||
super();
|
||||
this.push(...data);
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
public getHints(): NodeExecutionHint[] {
|
||||
return this.hints;
|
||||
}
|
||||
}
|
||||
|
||||
export interface INodeType {
|
||||
description: INodeTypeDescription;
|
||||
supplyData?(this: IAllExecuteFunctions, itemIndex: number): Promise<SupplyData>;
|
||||
@@ -1745,9 +1759,20 @@ export interface INodeTypeDescription extends INodeTypeBaseDescription {
|
||||
}
|
||||
| boolean;
|
||||
extendsCredential?: string;
|
||||
hints?: NodeHint[];
|
||||
__loadOptionsMethods?: string[]; // only for validation during build
|
||||
}
|
||||
|
||||
export type NodeHint = {
|
||||
message: string;
|
||||
type?: 'info' | 'warning' | 'danger';
|
||||
location?: 'outputPane' | 'inputPane' | 'ndv';
|
||||
displayCondition?: string;
|
||||
whenToDisplay?: 'always' | 'beforeExecution' | 'afterExecution';
|
||||
};
|
||||
|
||||
export type NodeExecutionHint = Omit<NodeHint, 'whenToDisplay' | 'displayCondition'>;
|
||||
|
||||
export interface INodeHookDescription {
|
||||
method: string;
|
||||
}
|
||||
@@ -1929,6 +1954,7 @@ export interface ITaskData {
|
||||
data?: ITaskDataConnections;
|
||||
inputOverride?: ITaskDataConnections;
|
||||
error?: ExecutionError;
|
||||
hints?: NodeExecutionHint[];
|
||||
source: Array<ISourceData | null>; // Is an array as nodes have multiple inputs
|
||||
metadata?: ITaskMetadata;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import type {
|
||||
INodeInputConfiguration,
|
||||
GenericValue,
|
||||
DisplayCondition,
|
||||
NodeHint,
|
||||
} from './Interfaces';
|
||||
import {
|
||||
isFilterValue,
|
||||
@@ -1120,6 +1121,50 @@ export function getNodeInputs(
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodeHints(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
nodeTypeData: INodeTypeDescription,
|
||||
): NodeHint[] {
|
||||
const hints: NodeHint[] = [];
|
||||
|
||||
if (nodeTypeData?.hints?.length) {
|
||||
for (const hint of nodeTypeData.hints) {
|
||||
if (hint.displayCondition) {
|
||||
try {
|
||||
const display = (workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
hint.displayCondition,
|
||||
'internal',
|
||||
{},
|
||||
) || false) as boolean;
|
||||
|
||||
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,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { INodeParameters, INodeProperties } from '@/Interfaces';
|
||||
import { getNodeParameters } from '@/NodeHelpers';
|
||||
import type { INode, INodeParameters, INodeProperties, INodeTypeDescription } from '@/Interfaces';
|
||||
import type { Workflow } from '../src';
|
||||
|
||||
import { getNodeParameters, getNodeHints } from '@/NodeHelpers';
|
||||
|
||||
describe('NodeHelpers', () => {
|
||||
describe('getNodeParameters', () => {
|
||||
@@ -3437,4 +3439,93 @@ 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user