mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix: Fix node graph telemetry with default values (#8297)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { getNodeParameters } from './NodeHelpers';
|
||||
import type {
|
||||
IConnection,
|
||||
INode,
|
||||
@@ -7,7 +8,6 @@ import type {
|
||||
INodesGraphResult,
|
||||
IWorkflowBase,
|
||||
INodeTypes,
|
||||
INodeType,
|
||||
} from './Interfaces';
|
||||
import { ApplicationError } from './errors/application.error';
|
||||
|
||||
@@ -21,28 +21,6 @@ export function isNumber(value: unknown): value is number {
|
||||
return typeof value === 'number';
|
||||
}
|
||||
|
||||
function getStickyDimensions(note: INode, stickyType: INodeType | undefined) {
|
||||
const heightProperty = stickyType?.description?.properties.find(
|
||||
(property) => property.name === 'height',
|
||||
);
|
||||
const widthProperty = stickyType?.description?.properties.find(
|
||||
(property) => property.name === 'width',
|
||||
);
|
||||
|
||||
const defaultHeight =
|
||||
heightProperty && isNumber(heightProperty?.default) ? heightProperty.default : 0;
|
||||
const defaultWidth =
|
||||
widthProperty && isNumber(widthProperty?.default) ? widthProperty.default : 0;
|
||||
|
||||
const height: number = isNumber(note.parameters.height) ? note.parameters.height : defaultHeight;
|
||||
const width: number = isNumber(note.parameters.width) ? note.parameters.width : defaultWidth;
|
||||
|
||||
return {
|
||||
height,
|
||||
width,
|
||||
};
|
||||
}
|
||||
|
||||
type XYPosition = [number, number];
|
||||
|
||||
function areOverlapping(
|
||||
@@ -112,123 +90,152 @@ export function getDomainPath(raw: string, urlParts = URL_PARTS_REGEX): string {
|
||||
}
|
||||
|
||||
export function generateNodesGraph(
|
||||
workflow: IWorkflowBase,
|
||||
workflow: Partial<IWorkflowBase>,
|
||||
nodeTypes: INodeTypes,
|
||||
options?: {
|
||||
sourceInstanceId?: string;
|
||||
nodeIdMap?: { [curr: string]: string };
|
||||
},
|
||||
): INodesGraphResult {
|
||||
const nodesGraph: INodesGraph = {
|
||||
const nodeGraph: INodesGraph = {
|
||||
node_types: [],
|
||||
node_connections: [],
|
||||
nodes: {},
|
||||
notes: {},
|
||||
is_pinned: Object.keys(workflow.pinData ?? {}).length > 0,
|
||||
};
|
||||
const nodeNameAndIndex: INodeNameIndex = {};
|
||||
const nameIndices: INodeNameIndex = {};
|
||||
const webhookNodeNames: string[] = [];
|
||||
|
||||
try {
|
||||
const notes = workflow.nodes.filter((node) => node.type === STICKY_NODE_TYPE);
|
||||
const otherNodes = workflow.nodes.filter((node) => node.type !== STICKY_NODE_TYPE);
|
||||
const notes = (workflow.nodes ?? []).filter((node) => node.type === STICKY_NODE_TYPE);
|
||||
const otherNodes = (workflow.nodes ?? []).filter((node) => node.type !== STICKY_NODE_TYPE);
|
||||
|
||||
notes.forEach((stickyNote: INode, index: number) => {
|
||||
const stickyType = nodeTypes.getByNameAndVersion(STICKY_NODE_TYPE, stickyNote.typeVersion);
|
||||
const { height, width } = getStickyDimensions(stickyNote, stickyType);
|
||||
notes.forEach((stickyNote: INode, index: number) => {
|
||||
const stickyType = nodeTypes.getByNameAndVersion(STICKY_NODE_TYPE, stickyNote.typeVersion);
|
||||
if (!stickyType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const topLeft = stickyNote.position;
|
||||
const bottomRight: [number, number] = [topLeft[0] + width, topLeft[1] + height];
|
||||
const overlapping = Boolean(
|
||||
otherNodes.find((node) => areOverlapping(topLeft, bottomRight, node.position)),
|
||||
);
|
||||
nodesGraph.notes[index] = {
|
||||
overlapping,
|
||||
position: topLeft,
|
||||
height,
|
||||
width,
|
||||
};
|
||||
});
|
||||
const nodeParameters =
|
||||
getNodeParameters(
|
||||
stickyType.description.properties,
|
||||
stickyNote.parameters,
|
||||
true,
|
||||
false,
|
||||
stickyNote,
|
||||
) ?? {};
|
||||
|
||||
otherNodes.forEach((node: INode, index: number) => {
|
||||
nodesGraph.node_types.push(node.type);
|
||||
const nodeItem: INodeGraphItem = {
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
version: node.typeVersion,
|
||||
position: node.position,
|
||||
};
|
||||
const height: number = typeof nodeParameters.height === 'number' ? nodeParameters.height : 0;
|
||||
const width: number = typeof nodeParameters.width === 'number' ? nodeParameters.width : 0;
|
||||
|
||||
if (options?.sourceInstanceId) {
|
||||
nodeItem.src_instance_id = options.sourceInstanceId;
|
||||
}
|
||||
const topLeft = stickyNote.position;
|
||||
const bottomRight: [number, number] = [topLeft[0] + width, topLeft[1] + height];
|
||||
const overlapping = Boolean(
|
||||
otherNodes.find((node) => areOverlapping(topLeft, bottomRight, node.position)),
|
||||
);
|
||||
nodeGraph.notes[index] = {
|
||||
overlapping,
|
||||
position: topLeft,
|
||||
height,
|
||||
width,
|
||||
};
|
||||
});
|
||||
|
||||
if (node.id && options?.nodeIdMap?.[node.id]) {
|
||||
nodeItem.src_node_id = options.nodeIdMap[node.id];
|
||||
}
|
||||
|
||||
if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion === 1) {
|
||||
try {
|
||||
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
||||
} catch {
|
||||
nodeItem.domain = getDomainBase(node.parameters.url as string);
|
||||
}
|
||||
} else if (node.type === 'n8n-nodes-base.httpRequest' && [2, 3].includes(node.typeVersion)) {
|
||||
const { authentication } = node.parameters as { authentication: string };
|
||||
|
||||
nodeItem.credential_type = {
|
||||
none: 'none',
|
||||
genericCredentialType: node.parameters.genericAuthType as string,
|
||||
predefinedCredentialType: node.parameters.nodeCredentialType as string,
|
||||
}[authentication];
|
||||
|
||||
nodeItem.credential_set = node.credentials
|
||||
? Object.keys(node.credentials).length > 0
|
||||
: false;
|
||||
|
||||
const { url } = node.parameters as { url: string };
|
||||
|
||||
nodeItem.domain_base = getDomainBase(url);
|
||||
nodeItem.domain_path = getDomainPath(url);
|
||||
nodeItem.method = node.parameters.requestMethod as string;
|
||||
} else if (node.type === 'n8n-nodes-base.webhook') {
|
||||
webhookNodeNames.push(node.name);
|
||||
} else {
|
||||
const nodeType = nodeTypes.getByNameAndVersion(node.type);
|
||||
|
||||
nodeType?.description?.properties?.forEach((property) => {
|
||||
if (
|
||||
property.name === 'operation' ||
|
||||
property.name === 'resource' ||
|
||||
property.name === 'mode'
|
||||
) {
|
||||
nodeItem[property.name] = property.default ? property.default.toString() : undefined;
|
||||
}
|
||||
});
|
||||
|
||||
nodeItem.operation = node.parameters.operation?.toString() ?? nodeItem.operation;
|
||||
nodeItem.resource = node.parameters.resource?.toString() ?? nodeItem.resource;
|
||||
nodeItem.mode = node.parameters.mode?.toString() ?? nodeItem.mode;
|
||||
}
|
||||
nodesGraph.nodes[`${index}`] = nodeItem;
|
||||
nodeNameAndIndex[node.name] = index.toString();
|
||||
});
|
||||
|
||||
const getGraphConnectionItem = (startNode: string, connectionItem: IConnection) => {
|
||||
return { start: nodeNameAndIndex[startNode], end: nodeNameAndIndex[connectionItem.node] };
|
||||
otherNodes.forEach((node: INode, index: number) => {
|
||||
nodeGraph.node_types.push(node.type);
|
||||
const nodeItem: INodeGraphItem = {
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
version: node.typeVersion,
|
||||
position: node.position,
|
||||
};
|
||||
|
||||
Object.keys(workflow.connections).forEach((nodeName) => {
|
||||
const connections = workflow.connections[nodeName];
|
||||
connections.main.forEach((element) => {
|
||||
if (options?.sourceInstanceId) {
|
||||
nodeItem.src_instance_id = options.sourceInstanceId;
|
||||
}
|
||||
|
||||
if (node.id && options?.nodeIdMap?.[node.id]) {
|
||||
nodeItem.src_node_id = options.nodeIdMap[node.id];
|
||||
}
|
||||
|
||||
if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion === 1) {
|
||||
try {
|
||||
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
||||
} catch {
|
||||
nodeItem.domain = getDomainBase(node.parameters.url as string);
|
||||
}
|
||||
} else if (node.type === 'n8n-nodes-base.httpRequest' && node.typeVersion > 1) {
|
||||
const { authentication } = node.parameters as { authentication: string };
|
||||
|
||||
nodeItem.credential_type = {
|
||||
none: 'none',
|
||||
genericCredentialType: node.parameters.genericAuthType as string,
|
||||
predefinedCredentialType: node.parameters.nodeCredentialType as string,
|
||||
}[authentication];
|
||||
|
||||
nodeItem.credential_set = node.credentials ? Object.keys(node.credentials).length > 0 : false;
|
||||
|
||||
const { url } = node.parameters as { url: string };
|
||||
|
||||
nodeItem.domain_base = getDomainBase(url);
|
||||
nodeItem.domain_path = getDomainPath(url);
|
||||
nodeItem.method = node.parameters.requestMethod as string;
|
||||
} else if (node.type === 'n8n-nodes-base.webhook') {
|
||||
webhookNodeNames.push(node.name);
|
||||
} else {
|
||||
try {
|
||||
const nodeType = nodeTypes.getByNameAndVersion(node.type);
|
||||
if (nodeType) {
|
||||
const nodeParameters = getNodeParameters(
|
||||
nodeType.description.properties,
|
||||
node.parameters,
|
||||
true,
|
||||
false,
|
||||
node,
|
||||
);
|
||||
|
||||
if (nodeParameters) {
|
||||
const keys: Array<'operation' | 'resource' | 'mode'> = [
|
||||
'operation',
|
||||
'resource',
|
||||
'mode',
|
||||
];
|
||||
keys.forEach((key) => {
|
||||
if (nodeParameters.hasOwnProperty(key)) {
|
||||
nodeItem[key] = nodeParameters[key]?.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (!(e instanceof Error && e.message.includes('Unrecognized node type'))) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodeGraph.nodes[index.toString()] = nodeItem;
|
||||
nameIndices[node.name] = index.toString();
|
||||
});
|
||||
|
||||
const getGraphConnectionItem = (startNode: string, connectionItem: IConnection) => {
|
||||
return { start: nameIndices[startNode], end: nameIndices[connectionItem.node] };
|
||||
};
|
||||
|
||||
Object.keys(workflow.connections ?? []).forEach((nodeName) => {
|
||||
const connections = workflow.connections?.[nodeName];
|
||||
if (!connections) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(connections).forEach((key) => {
|
||||
connections[key].forEach((element) => {
|
||||
element.forEach((element2) => {
|
||||
nodesGraph.node_connections.push(getGraphConnectionItem(nodeName, element2));
|
||||
nodeGraph.node_connections.push(getGraphConnectionItem(nodeName, element2));
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
return { nodeGraph: nodesGraph, nameIndices: nodeNameAndIndex, webhookNodeNames };
|
||||
}
|
||||
});
|
||||
|
||||
return { nodeGraph: nodesGraph, nameIndices: nodeNameAndIndex, webhookNodeNames };
|
||||
return { nodeGraph, nameIndices, webhookNodeNames };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user