refactor: Migrate NodeConnectionType to const object type (no-changelog) (#14078)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Alex Grozav
2025-03-21 14:01:26 +02:00
committed by GitHub
parent 7e8179b848
commit 8215e0b59f
703 changed files with 3104 additions and 3018 deletions

View File

@@ -5,7 +5,7 @@ import { userEvent } from '@testing-library/user-event';
import { createRouter, createWebHistory } from 'vue-router';
import { computed, ref } from 'vue';
import type { INodeTypeDescription } from 'n8n-workflow';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import CanvasChat from './CanvasChat.vue';
import { createComponentRenderer } from '@/__tests__/render';
@@ -77,8 +77,8 @@ const mockNodeTypes: INodeTypeDescription[] = [
defaults: {
name: 'AI Agent',
},
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
version: 0,
group: [],
description: '',
@@ -96,7 +96,7 @@ const mockConnections = {
[
{
node: 'AI Agent',
type: NodeConnectionType.Main,
type: NodeConnectionTypes.Main,
index: 0,
},
],

View File

@@ -2,7 +2,7 @@ import type { ComputedRef, Ref } from 'vue';
import { computed, ref } from 'vue';
import { v4 as uuid } from 'uuid';
import type { ChatMessage, ChatMessageText } from '@n8n/chat/types';
import { NodeConnectionType, CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow';
import { NodeConnectionTypes, CHAT_TRIGGER_NODE_TYPE } from 'n8n-workflow';
import type {
ITaskData,
INodeExecutionData,
@@ -252,7 +252,7 @@ export function useChatMessaging({
const connectedMemoryInputs =
workflow.value.connectionsByDestinationNode?.[connectedNode.value.name]?.[
NodeConnectionType.AiMemory
NodeConnectionTypes.AiMemory
];
if (!connectedMemoryInputs) return [];
@@ -263,7 +263,9 @@ export function useChatMessaging({
const nodeResultData = getWorkflowResultDataByNodeName(memoryConnection.node);
const memoryOutputData = (nodeResultData ?? [])
.map((data) => get(data, ['data', NodeConnectionType.AiMemory, 0, 0, 'json']) as MemoryOutput)
.map(
(data) => get(data, ['data', NodeConnectionTypes.AiMemory, 0, 0, 'json']) as MemoryOutput,
)
.find((data) => data && data.action === 'saveContext');
return (memoryOutputData?.chatHistory ?? []).map((message, index) => {

View File

@@ -2,7 +2,7 @@ import type { ComputedRef, MaybeRef } from 'vue';
import { ref, computed, unref } from 'vue';
import {
CHAIN_SUMMARIZATION_LANGCHAIN_NODE_TYPE,
NodeConnectionType,
NodeConnectionTypes,
NodeHelpers,
} from 'n8n-workflow';
import type { INodeTypeDescription, Workflow, INode, INodeParameters } from 'n8n-workflow';
@@ -103,9 +103,9 @@ export function useChatTrigger({
// Validate if node has required AI connection types
if (
inputTypes.includes(NodeConnectionType.AiLanguageModel) &&
inputTypes.includes(NodeConnectionType.Main) &&
outputTypes.includes(NodeConnectionType.Main)
inputTypes.includes(NodeConnectionTypes.AiLanguageModel) &&
inputTypes.includes(NodeConnectionTypes.Main) &&
outputTypes.includes(NodeConnectionTypes.Main)
) {
isCustomChainOrAgent = true;
}

View File

@@ -11,7 +11,7 @@ import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils';
import { useTelemetry } from '@/composables/useTelemetry';
import type { Segment } from '@/types/expressions';
import type { INodeProperties } from 'n8n-workflow';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { outputTheme } from './ExpressionEditorModal/theme';
import ExpressionOutput from './InlineExpressionEditor/ExpressionOutput.vue';
import VirtualSchema from '@/components/VirtualSchema.vue';
@@ -172,7 +172,7 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
:search="appliedSearch"
:nodes="parentNodes"
:mapping-enabled="!isReadOnly"
:connection-type="NodeConnectionType.Main"
:connection-type="NodeConnectionTypes.Main"
pane-type="input"
/>
</div>

View File

@@ -6,7 +6,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
import { createTestingPinia } from '@pinia/testing';
import { waitFor } from '@testing-library/vue';
import {
NodeConnectionType,
NodeConnectionTypes,
type IConnections,
type INodeExecutionData,
type IRunData,
@@ -32,18 +32,18 @@ const nodes = [
const render = (props: Partial<Props> = {}, pinData?: INodeExecutionData[], runData?: IRunData) => {
const connections: IConnections = {
[nodes[0].name]: {
[NodeConnectionType.Main]: [
[{ node: nodes[1].name, type: NodeConnectionType.Main, index: 0 }],
[NodeConnectionTypes.Main]: [
[{ node: nodes[1].name, type: NodeConnectionTypes.Main, index: 0 }],
],
},
[nodes[1].name]: {
[NodeConnectionType.Main]: [
[{ node: nodes[2].name, type: NodeConnectionType.Main, index: 0 }],
[NodeConnectionTypes.Main]: [
[{ node: nodes[2].name, type: NodeConnectionTypes.Main, index: 0 }],
],
},
[nodes[3].name]: {
[NodeConnectionType.AiMemory]: [
[{ node: nodes[2].name, type: NodeConnectionType.AiMemory, index: 0 }],
[NodeConnectionTypes.AiMemory]: [
[{ node: nodes[2].name, type: NodeConnectionTypes.AiMemory, index: 0 }],
],
},
};

View File

@@ -14,7 +14,7 @@ import { waitingNodeTooltip } from '@/utils/executionUtils';
import { uniqBy } from 'lodash-es';
import { N8nIcon, N8nRadioButtons, N8nText, N8nTooltip } from '@n8n/design-system';
import type { INodeInputConfiguration, INodeOutputConfiguration, Workflow } from 'n8n-workflow';
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
import { type NodeConnectionType, NodeConnectionTypes, NodeHelpers } from 'n8n-workflow';
import { storeToRefs } from 'pinia';
import { computed, ref, watch } from 'vue';
import { useNDVStore } from '../stores/ndv.store';
@@ -143,8 +143,8 @@ const isActiveNodeConfig = computed(() => {
return (
inputs.length === 0 ||
(inputs.every((input) => filterOutConnectionType(input, NodeConnectionType.Main)) &&
outputs.find((output) => filterOutConnectionType(output, NodeConnectionType.Main)))
(inputs.every((input) => filterOutConnectionType(input, NodeConnectionTypes.Main)) &&
outputs.find((output) => filterOutConnectionType(output, NodeConnectionTypes.Main)))
);
});

View File

@@ -4,7 +4,7 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { computed, onMounted, onBeforeUnmount } from 'vue';
import NodeIcon from '@/components/NodeIcon.vue';
import { NodeConnectionType, type INodeTypeDescription } from 'n8n-workflow';
import { NodeConnectionTypes, type INodeTypeDescription } from 'n8n-workflow';
interface Props {
rootNode: INodeUi;
@@ -72,10 +72,10 @@ const connectedNodes = computed<
workflow.getChildNodes(rootName, 'ALL_NON_MAIN'),
),
[FloatingNodePosition.right]: getINodesFromNames(
workflow.getChildNodes(rootName, NodeConnectionType.Main, 1),
workflow.getChildNodes(rootName, NodeConnectionTypes.Main, 1),
).reverse(),
[FloatingNodePosition.left]: getINodesFromNames(
workflow.getParentNodes(rootName, NodeConnectionType.Main, 1),
workflow.getParentNodes(rootName, NodeConnectionTypes.Main, 1),
),
};
});

View File

@@ -4,17 +4,17 @@ import { setActivePinia } from 'pinia';
import { createTestingPinia } from '@pinia/testing';
import type { INodeUi } from '@/Interface';
import type { INodeTypeDescription, WorkflowParameters } from 'n8n-workflow';
import { NodeConnectionType, Workflow } from 'n8n-workflow';
import { NodeConnectionTypes, Workflow } from 'n8n-workflow';
const nodeType: INodeTypeDescription = {
displayName: 'OpenAI',
name: '@n8n/n8n-nodes-langchain.openAi',
version: [1],
inputs: [
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiTool, displayName: 'Tools' },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiTool, displayName: 'Tools' },
],
outputs: [NodeConnectionType.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'openAiApi',

View File

@@ -1,7 +1,7 @@
import { computed } from 'vue';
import {
CHAIN_LLM_LANGCHAIN_NODE_TYPE,
NodeConnectionType,
NodeConnectionTypes,
type IDataObject,
type INodeParameters,
} from 'n8n-workflow';
@@ -249,7 +249,7 @@ export const useActions = () => {
if (shouldPrependLLMChain(addedNodes)) {
addedNodes.unshift({ type: CHAIN_LLM_LANGCHAIN_NODE_TYPE, isAutoAdd: true });
connections.push({
from: { nodeIndex: 2, type: NodeConnectionType.AiLanguageModel },
from: { nodeIndex: 2, type: NodeConnectionTypes.AiLanguageModel },
to: { nodeIndex: 1 },
});
}

View File

@@ -1,4 +1,4 @@
import { NodeConnectionType, type INodeProperties, type INodeTypeDescription } from 'n8n-workflow';
import { NodeConnectionTypes, type INodeProperties, type INodeTypeDescription } from 'n8n-workflow';
import { useActionsGenerator } from './composables/useActionsGeneration';
describe('useActionsGenerator', () => {
@@ -14,8 +14,8 @@ describe('useActionsGenerator', () => {
defaults: {
name: 'Test',
},
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
properties: [],
};

View File

@@ -62,7 +62,8 @@ import { useI18n } from '@/composables/useI18n';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import type { SimplifiedNodeType } from '@/Interface';
import type { INodeTypeDescription, Themed } from 'n8n-workflow';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import type { NodeConnectionType } from 'n8n-workflow';
import { useTemplatesStore } from '@/stores/templates.store';
import type { BaseTextKey } from '@/plugins/i18n';
import { camelCase } from 'lodash-es';
@@ -219,7 +220,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_DOCUMENT_LOADERS,
info: getSubcategoryInfo(AI_CATEGORY_DOCUMENT_LOADERS),
icon: 'file-import',
...getAISubcategoryProperties(NodeConnectionType.AiDocument),
...getAISubcategoryProperties(NodeConnectionTypes.AiDocument),
},
},
{
@@ -229,7 +230,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_LANGUAGE_MODELS,
info: getSubcategoryInfo(AI_CATEGORY_LANGUAGE_MODELS),
icon: 'language',
...getAISubcategoryProperties(NodeConnectionType.AiLanguageModel),
...getAISubcategoryProperties(NodeConnectionTypes.AiLanguageModel),
},
},
{
@@ -239,7 +240,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_MEMORY,
info: getSubcategoryInfo(AI_CATEGORY_MEMORY),
icon: 'brain',
...getAISubcategoryProperties(NodeConnectionType.AiMemory),
...getAISubcategoryProperties(NodeConnectionTypes.AiMemory),
},
},
{
@@ -249,7 +250,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_OUTPUTPARSER,
info: getSubcategoryInfo(AI_CATEGORY_OUTPUTPARSER),
icon: 'list',
...getAISubcategoryProperties(NodeConnectionType.AiOutputParser),
...getAISubcategoryProperties(NodeConnectionTypes.AiOutputParser),
},
},
{
@@ -259,7 +260,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_RETRIEVERS,
info: getSubcategoryInfo(AI_CATEGORY_RETRIEVERS),
icon: 'search',
...getAISubcategoryProperties(NodeConnectionType.AiRetriever),
...getAISubcategoryProperties(NodeConnectionTypes.AiRetriever),
},
},
{
@@ -269,7 +270,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_TEXT_SPLITTERS,
info: getSubcategoryInfo(AI_CATEGORY_TEXT_SPLITTERS),
icon: 'grip-lines-vertical',
...getAISubcategoryProperties(NodeConnectionType.AiTextSplitter),
...getAISubcategoryProperties(NodeConnectionTypes.AiTextSplitter),
},
},
{
@@ -280,7 +281,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_TOOLS,
info: getSubcategoryInfo(AI_CATEGORY_TOOLS),
icon: 'tools',
...getAISubcategoryProperties(NodeConnectionType.AiTool),
...getAISubcategoryProperties(NodeConnectionTypes.AiTool),
sections: [
{
key: 'popular',
@@ -297,7 +298,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_EMBEDDING,
info: getSubcategoryInfo(AI_CATEGORY_EMBEDDING),
icon: 'vector-square',
...getAISubcategoryProperties(NodeConnectionType.AiEmbedding),
...getAISubcategoryProperties(NodeConnectionTypes.AiEmbedding),
},
},
{
@@ -307,7 +308,7 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
title: AI_CATEGORY_VECTOR_STORES,
info: getSubcategoryInfo(AI_CATEGORY_VECTOR_STORES),
icon: 'project-diagram',
...getAISubcategoryProperties(NodeConnectionType.AiVectorStore),
...getAISubcategoryProperties(NodeConnectionTypes.AiVectorStore),
},
},
{

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue';
import { createEventBus } from '@n8n/utils/event-bus';
import type { IRunData, Workflow } from 'n8n-workflow';
import { jsonParse, NodeHelpers, NodeConnectionType } from 'n8n-workflow';
import type { IRunData, Workflow, NodeConnectionType } from 'n8n-workflow';
import { jsonParse, NodeHelpers, NodeConnectionTypes } from 'n8n-workflow';
import type { IUpdateInformation, TargetItem } from '@/Interface';
import NodeSettings from '@/components/NodeSettings.vue';
@@ -160,16 +160,16 @@ const inputNodeName = computed<string | undefined>(() => {
: [];
const nonMainOutputs = nodeOutputs.filter((output) => {
if (typeof output === 'string') return output !== NodeConnectionType.Main;
if (typeof output === 'string') return output !== NodeConnectionTypes.Main;
return output.type !== NodeConnectionType.Main;
return output.type !== NodeConnectionTypes.Main;
});
const isSubNode = nonMainOutputs.length > 0;
if (isSubNode && activeNode.value) {
// For sub-nodes, we need to get their connected output node to determine the input
// because sub-nodes use specialized outputs (e.g. NodeConnectionType.AiTool)
// because sub-nodes use specialized outputs (e.g. NodeConnectionTypes.AiTool)
// instead of the standard Main output type
const connectedOutputNode = props.workflowObject.getChildNodes(
activeNode.value.name,
@@ -275,7 +275,7 @@ const maxInputRun = computed(() => {
const runData: IRunData | null = workflowRunData.value;
if (outputs.some((output) => output !== NodeConnectionType.Main)) {
if (outputs.some((output) => output !== NodeConnectionTypes.Main)) {
node = activeNode.value;
}
@@ -413,7 +413,7 @@ const onFeatureRequestClick = () => {
node_type: activeNode.value.type,
workflow_id: workflowsStore.workflowId,
push_ref: pushRef.value,
pane: NodeConnectionType.Main,
pane: NodeConnectionTypes.Main,
type: 'i-wish-this-node-would',
});
}

View File

@@ -4,11 +4,12 @@ import type {
INodeTypeDescription,
INodeParameters,
INodeProperties,
NodeConnectionType,
NodeParameterValue,
} from 'n8n-workflow';
import {
NodeHelpers,
NodeConnectionType,
NodeConnectionTypes,
deepCopy,
isINodePropertyCollectionList,
isINodePropertiesList,
@@ -139,7 +140,7 @@ const isExecutable = computed(() => {
);
const inputNames = NodeHelpers.getConnectionTypes(inputs);
if (!inputNames.includes(NodeConnectionType.Main) && !isTriggerNode.value) {
if (!inputNames.includes(NodeConnectionTypes.Main) && !isTriggerNode.value) {
return false;
}
}

View File

@@ -8,7 +8,7 @@ import {
import { useNDVStore } from '@/stores/ndv.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import type { INodeTypeDescription } from 'n8n-workflow';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { computed } from 'vue';
import { useExternalHooks } from '@/composables/useExternalHooks';
@@ -130,7 +130,7 @@ function onTabSelect(tab: string) {
node_type: activeNode.value?.type,
workflow_id: workflowsStore.workflowId,
push_ref: props.pushRef,
pane: NodeConnectionType.Main,
pane: NodeConnectionTypes.Main,
type: 'docs',
});
}

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import {
NodeConnectionType,
NodeConnectionTypes,
type IRunData,
type IRunExecutionData,
type Workflow,
@@ -237,7 +237,7 @@ const allToolsWereUnusedNotice = computed(() => {
const toolsAvailable = props.workflow.getParentNodes(
node.value.name,
NodeConnectionType.AiTool,
NodeConnectionTypes.AiTool,
1,
);
const toolsUsedInLatestRun = toolsAvailable.filter(

View File

@@ -1,5 +1,5 @@
import {
NodeConnectionType,
NodeConnectionTypes,
type INode,
type INodeProperties,
type INodeTypeDescription,
@@ -91,8 +91,8 @@ export const EXECUTE_WORKFLOW_NODE_TYPE_TEST: INodeTypeDescription = {
subtitle: '={{"Workflow: " + $parameter["workflowId"]}}',
description: 'Execute another workflow',
defaults: { name: 'Execute Workflow', color: '#ff6d5a' },
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
properties: [
{
displayName: 'Operation',

View File

@@ -1,22 +1,26 @@
<script setup lang="ts">
import { useStorage } from '@/composables/useStorage';
import { saveAs } from 'file-saver';
import {
type IBinaryData,
type IConnectedNode,
type IDataObject,
type INodeExecutionData,
type INodeOutputConfiguration,
type IRunData,
type IRunExecutionData,
type ITaskMetadata,
type NodeError,
type NodeHint,
TRIMMED_TASK_DATA_CONNECTIONS_KEY,
type Workflow,
parseErrorMetadata,
import type {
IBinaryData,
IConnectedNode,
IDataObject,
INodeExecutionData,
INodeOutputConfiguration,
IRunData,
IRunExecutionData,
ITaskMetadata,
NodeError,
NodeHint,
Workflow,
NodeConnectionType,
} from 'n8n-workflow';
import {
parseErrorMetadata,
NodeConnectionTypes,
NodeHelpers,
TRIMMED_TASK_DATA_CONNECTIONS_KEY,
} from 'n8n-workflow';
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
import { computed, defineAsyncComponent, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue';
import type {
@@ -164,7 +168,7 @@ const emit = defineEmits<{
];
}>();
const connectionType = ref<NodeConnectionType>(NodeConnectionType.Main);
const connectionType = ref<NodeConnectionType>(NodeConnectionTypes.Main);
const dataSize = ref(0);
const showData = ref(false);
const userEnabledShowData = ref(false);
@@ -1082,7 +1086,7 @@ function getRunLabel(option: number) {
function getRawInputData(
runIndex: number,
outputIndex: number,
connectionType: NodeConnectionType = NodeConnectionType.Main,
connectionType: NodeConnectionType = NodeConnectionTypes.Main,
): INodeExecutionData[] {
let inputData: INodeExecutionData[] = [];
@@ -1130,7 +1134,7 @@ function getFilteredData(data: INodeExecutionData[]): INodeExecutionData[] {
function getDataCount(
runIndex: number,
outputIndex: number,
connectionType: NodeConnectionType = NodeConnectionType.Main,
connectionType: NodeConnectionType = NodeConnectionTypes.Main,
) {
if (!node.value) {
return 0;
@@ -1165,7 +1169,7 @@ function init() {
const outputs = getResolvedNodeOutputs();
outputTypes = NodeHelpers.getConnectionTypes(outputs);
}
connectionType.value = outputTypes.length === 0 ? NodeConnectionType.Main : outputTypes[0];
connectionType.value = outputTypes.length === 0 ? NodeConnectionTypes.Main : outputTypes[0];
if (binaryData.value.length > 0) {
ndvStore.setPanelDisplayMode({
pane: props.paneType,

View File

@@ -9,8 +9,8 @@ import hljs from 'highlight.js/lib/core';
import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@/composables/useI18n';
import { useToast } from '@/composables/useToast';
import { NodeConnectionType } from 'n8n-workflow';
import type { NodeError, IDataObject } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import type { NodeConnectionType, NodeError, IDataObject } from 'n8n-workflow';
const props = defineProps<{
runData: IAiDataContent;
@@ -29,13 +29,16 @@ const contentParsed = ref(false);
const parsedRun = ref(undefined as ParsedAiContent | undefined);
function getInitialExpandedState() {
const collapsedTypes = {
input: [NodeConnectionType.AiDocument, NodeConnectionType.AiTextSplitter],
input: [
NodeConnectionTypes.AiDocument,
NodeConnectionTypes.AiTextSplitter,
] as NodeConnectionType[],
output: [
NodeConnectionType.AiDocument,
NodeConnectionType.AiEmbedding,
NodeConnectionType.AiTextSplitter,
NodeConnectionType.AiVectorStore,
],
NodeConnectionTypes.AiDocument,
NodeConnectionTypes.AiEmbedding,
NodeConnectionTypes.AiTextSplitter,
NodeConnectionTypes.AiVectorStore,
] as NodeConnectionType[],
};
return !collapsedTypes[props.runData.inOut].includes(props.runData.type);

View File

@@ -1,5 +1,5 @@
import type { IDataObject, INodeExecutionData } from 'n8n-workflow';
import { isObjectEmpty, NodeConnectionType } from 'n8n-workflow';
import type { IDataObject, INodeExecutionData, NodeConnectionType } from 'n8n-workflow';
import { isObjectEmpty, NodeConnectionTypes } from 'n8n-workflow';
interface MemoryMessage {
lc: number;
@@ -15,7 +15,7 @@ interface LmGeneration {
message: MemoryMessage;
}
type ExcludedKeys = NodeConnectionType.Main | NodeConnectionType.AiChain;
type ExcludedKeys = typeof NodeConnectionTypes.Main | typeof NodeConnectionTypes.AiChain;
type AllowedEndpointType = Exclude<NodeConnectionType, ExcludedKeys>;
const fallbackParser = (execData: IDataObject) => ({
@@ -31,7 +31,7 @@ const outputTypeParsers: {
parsed: boolean;
};
} = {
[NodeConnectionType.AiLanguageModel](execData: IDataObject) {
[NodeConnectionTypes.AiLanguageModel](execData: IDataObject) {
const response = (execData.response as IDataObject) ?? execData;
if (!response) throw new Error('No response from Language Model');
@@ -50,7 +50,7 @@ const outputTypeParsers: {
// Use the memory parser if the response is a memory-like(chat) object
if (response.messages && Array.isArray(response.messages)) {
return outputTypeParsers[NodeConnectionType.AiMemory](execData);
return outputTypeParsers[NodeConnectionTypes.AiMemory](execData);
}
if (response.generations) {
@@ -82,9 +82,9 @@ const outputTypeParsers: {
parsed: true,
};
},
[NodeConnectionType.AiTool]: fallbackParser,
[NodeConnectionType.AiAgent]: fallbackParser,
[NodeConnectionType.AiMemory](execData: IDataObject) {
[NodeConnectionTypes.AiTool]: fallbackParser,
[NodeConnectionTypes.AiAgent]: fallbackParser,
[NodeConnectionTypes.AiMemory](execData: IDataObject) {
const chatHistory =
execData.chatHistory ??
execData.messages ??
@@ -153,9 +153,9 @@ const outputTypeParsers: {
return fallbackParser(execData);
},
[NodeConnectionType.AiOutputParser]: fallbackParser,
[NodeConnectionType.AiRetriever]: fallbackParser,
[NodeConnectionType.AiVectorStore](execData: IDataObject) {
[NodeConnectionTypes.AiOutputParser]: fallbackParser,
[NodeConnectionTypes.AiRetriever]: fallbackParser,
[NodeConnectionTypes.AiVectorStore](execData: IDataObject) {
if (execData.documents) {
return {
type: 'json',
@@ -166,7 +166,7 @@ const outputTypeParsers: {
return fallbackParser(execData);
},
[NodeConnectionType.AiEmbedding](execData: IDataObject) {
[NodeConnectionTypes.AiEmbedding](execData: IDataObject) {
if (execData.documents) {
return {
type: 'json',
@@ -177,7 +177,7 @@ const outputTypeParsers: {
return fallbackParser(execData);
},
[NodeConnectionType.AiDocument](execData: IDataObject) {
[NodeConnectionTypes.AiDocument](execData: IDataObject) {
if (execData.documents) {
return {
type: 'json',
@@ -188,7 +188,7 @@ const outputTypeParsers: {
return fallbackParser(execData);
},
[NodeConnectionType.AiTextSplitter](execData: IDataObject) {
[NodeConnectionTypes.AiTextSplitter](execData: IDataObject) {
const arrayData = Array.isArray(execData.response)
? execData.response
: [execData.textSplitter];
@@ -213,7 +213,11 @@ export const useAiContentParsers = () => {
executionData: INodeExecutionData[],
endpointType: NodeConnectionType,
): ParsedAiContent => {
if ([NodeConnectionType.AiChain, NodeConnectionType.Main].includes(endpointType)) {
if (
([NodeConnectionTypes.AiChain, NodeConnectionTypes.Main] as NodeConnectionType[]).includes(
endpointType,
)
) {
return executionData.map((data) => ({ raw: data.json, parsedContent: null }));
}

View File

@@ -1,6 +1,6 @@
import { createTestNode, createTestWorkflowObject } from '@/__tests__/mocks';
import { createAiData, getTreeNodeData } from '@/components/RunDataAi/utils';
import { type ITaskData, NodeConnectionType } from 'n8n-workflow';
import { type ITaskData, NodeConnectionTypes } from 'n8n-workflow';
describe(getTreeNodeData, () => {
function createTaskData(partialData: Partial<ITaskData>): ITaskData {
@@ -22,9 +22,9 @@ describe(getTreeNodeData, () => {
createTestNode({ name: 'C' }),
],
connections: {
B: { ai_tool: [[{ node: 'A', type: NodeConnectionType.AiTool, index: 0 }]] },
B: { ai_tool: [[{ node: 'A', type: NodeConnectionTypes.AiTool, index: 0 }]] },
C: {
ai_languageModel: [[{ node: 'B', type: NodeConnectionType.AiLanguageModel, index: 0 }]],
ai_languageModel: [[{ node: 'B', type: NodeConnectionTypes.AiLanguageModel, index: 0 }]],
},
},
});

View File

@@ -13,7 +13,7 @@ import {
mockNodeTypeDescription,
} from '@/__tests__/mocks';
import { mockedStore } from '@/__tests__/utils';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { SET_NODE_TYPE } from '@/constants';
vi.mock('vue-router', () => {
@@ -53,8 +53,8 @@ describe('NodesPinning', () => {
const nodeTypesStore = mockedStore(useNodeTypesStore);
const nodeTypeDescription = mockNodeTypeDescription({
name: SET_NODE_TYPE,
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
});
nodeTypesStore.nodeTypes = {
node: { 1: nodeTypeDescription },

View File

@@ -15,7 +15,7 @@ import { mock } from 'vitest-mock-extended';
import type { IWorkflowDb } from '@/Interface';
import {
createResultOk,
NodeConnectionType,
NodeConnectionTypes,
type IDataObject,
type INodeExecutionData,
} from 'n8n-workflow';
@@ -96,11 +96,11 @@ async function setupStore() {
...defaultNodeDescriptions,
mockNodeTypeDescription({
name: MANUAL_TRIGGER_NODE_TYPE,
outputs: [NodeConnectionType.Main],
outputs: [NodeConnectionTypes.Main],
}),
mockNodeTypeDescription({
name: IF_NODE_TYPE,
outputs: [NodeConnectionType.Main, NodeConnectionType.Main],
outputs: [NodeConnectionTypes.Main, NodeConnectionTypes.Main],
}),
]);
workflowsStore.workflow = workflow;

View File

@@ -22,7 +22,8 @@ import { executionDataToJson } from '@/utils/nodeTypesUtils';
import { N8nText } from '@n8n/design-system';
import {
createResultError,
NodeConnectionType,
type NodeConnectionType,
NodeConnectionTypes,
type IConnectedNode,
type IDataObject,
} from 'n8n-workflow';
@@ -70,7 +71,7 @@ const props = withDefaults(defineProps<Props>(), {
runIndex: 0,
outputIndex: 0,
totalRuns: 1,
connectionType: NodeConnectionType.Main,
connectionType: NodeConnectionTypes.Main,
search: '',
mappingEnabled: false,
});

View File

@@ -5,7 +5,7 @@ import Canvas from '@/components/canvas/Canvas.vue';
import { createPinia, setActivePinia } from 'pinia';
import type { CanvasConnection, CanvasNode } from '@/types';
import { createCanvasConnection, createCanvasNodeElement } from '@/__tests__/data';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import type { useDeviceSupport } from '@n8n/composables/useDeviceSupport';
import { useVueFlow } from '@vue-flow/core';
@@ -59,7 +59,7 @@ describe('Canvas', () => {
data: {
outputs: [
{
type: NodeConnectionType.Main,
type: NodeConnectionTypes.Main,
index: 0,
},
],
@@ -72,7 +72,7 @@ describe('Canvas', () => {
data: {
inputs: [
{
type: NodeConnectionType.Main,
type: NodeConnectionTypes.Main,
index: 0,
},
],

View File

@@ -36,7 +36,7 @@ import type {
import { MarkerType, PanelPosition, useVueFlow, VueFlow } from '@vue-flow/core';
import { MiniMap } from '@vue-flow/minimap';
import { onKeyDown, onKeyUp, useThrottleFn } from '@vueuse/core';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import {
computed,
nextTick,
@@ -460,7 +460,7 @@ onEdgeMouseEnter(({ edge }) => {
onEdgeMouseMove(
useThrottleFn(({ edge, event }) => {
const type = edge.data.source.type;
if (type !== NodeConnectionType.AiTool) {
if (type !== NodeConnectionTypes.AiTool) {
return;
}

View File

@@ -5,7 +5,7 @@ import { BaseEdge } from '@vue-flow/core';
import { computed, onMounted, ref, useCssModule } from 'vue';
import { getEdgeRenderData } from './utils';
import { useCanvas } from '@/composables/useCanvas';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { parseCanvasConnectionHandleString } from '@/utils/canvasUtils';
const props = defineProps<ConnectionLineProps>();
@@ -26,7 +26,7 @@ const classes = computed(() => {
});
const edgeColor = computed(() => {
if (connectionType.value !== NodeConnectionType.Main) {
if (connectionType.value !== NodeConnectionTypes.Main) {
return 'var(--node-type-supplemental-color)';
} else {
return 'var(--color-foreground-xdark)';
@@ -34,7 +34,7 @@ const edgeColor = computed(() => {
});
const edgeStyle = computed(() => ({
...(connectionType.value === NodeConnectionType.Main ? {} : { strokeDasharray: '8,8' }),
...(connectionType.value === NodeConnectionTypes.Main ? {} : { strokeDasharray: '8,8' }),
strokeWidth: 2,
stroke: edgeColor.value,
}));

View File

@@ -2,7 +2,7 @@ import { createComponentRenderer } from '@/__tests__/render';
import { createTestingPinia } from '@pinia/testing';
import userEvent from '@testing-library/user-event';
import { Position } from '@vue-flow/core';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { setActivePinia } from 'pinia';
import CanvasEdge, { type CanvasEdgeProps } from './CanvasEdge.vue';
@@ -15,8 +15,8 @@ const DEFAULT_PROPS = {
targetPosition: Position.Bottom,
data: {
status: undefined,
source: { index: 0, type: NodeConnectionType.Main },
target: { index: 0, type: NodeConnectionType.Main },
source: { index: 0, type: NodeConnectionTypes.Main },
target: { index: 0, type: NodeConnectionTypes.Main },
},
} satisfies Partial<CanvasEdgeProps>;
const renderComponent = createComponentRenderer(CanvasEdge, {
@@ -159,7 +159,7 @@ describe('CanvasEdge', () => {
data: {
...DEFAULT_PROPS.data,
source: {
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
},
},
sourceX: 0,

View File

@@ -4,7 +4,7 @@ import type { CanvasConnectionData } from '@/types';
import { isValidNodeConnectionType } from '@/utils/typeGuards';
import type { Connection, EdgeProps } from '@vue-flow/core';
import { BaseEdge, EdgeLabelRenderer } from '@vue-flow/core';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { computed, ref, toRef, useCssModule, watch } from 'vue';
import CanvasEdgeToolbar from './CanvasEdgeToolbar.vue';
import { getEdgeRenderData } from './utils';
@@ -30,7 +30,7 @@ const $style = useCssModule();
const connectionType = computed(() =>
isValidNodeConnectionType(props.data.source.type)
? props.data.source.type
: NodeConnectionType.Main,
: NodeConnectionTypes.Main,
);
const delayedHovered = ref(props.hovered);
@@ -54,7 +54,7 @@ watch(
const renderToolbar = computed(() => (props.selected || delayedHovered.value) && !props.readOnly);
const isMainConnection = computed(() => data.value.source.type === NodeConnectionType.Main);
const isMainConnection = computed(() => data.value.source.type === NodeConnectionTypes.Main);
const status = computed(() => props.data.status);

View File

@@ -1,7 +1,8 @@
<script lang="ts" setup>
import { useI18n } from '@/composables/useI18n';
import { computed, useCssModule } from 'vue';
import { NodeConnectionType } from 'n8n-workflow';
import type { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
const emit = defineEmits<{
add: [];
@@ -20,7 +21,7 @@ const classes = computed(() => ({
[$style.canvasEdgeToolbar]: true,
}));
const isAddButtonVisible = computed(() => props.type === NodeConnectionType.Main);
const isAddButtonVisible = computed(() => props.type === NodeConnectionTypes.Main);
function onAdd() {
emit('add');

View File

@@ -1,6 +1,7 @@
import type { EdgeProps } from '@vue-flow/core';
import { getBezierPath, getSmoothStepPath, Position } from '@vue-flow/core';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import type { NodeConnectionType } from 'n8n-workflow';
const EDGE_PADDING_BOTTOM = 130;
const EDGE_PADDING_X = 40;
@@ -15,7 +16,7 @@ export function getEdgeRenderData(
'sourceX' | 'sourceY' | 'sourcePosition' | 'targetX' | 'targetY' | 'targetPosition'
>,
{
connectionType = NodeConnectionType.Main,
connectionType = NodeConnectionTypes.Main,
}: {
connectionType?: NodeConnectionType;
} = {},
@@ -23,7 +24,7 @@ export function getEdgeRenderData(
const { targetX, targetY, sourceX, sourceY, sourcePosition, targetPosition } = props;
const isConnectorStraight = sourceY === targetY;
if (!isRightOfSourceHandle(sourceX, targetX) || connectionType !== NodeConnectionType.Main) {
if (!isRightOfSourceHandle(sourceX, targetX) || connectionType !== NodeConnectionTypes.Main) {
const segment = getBezierPath(props);
return {
segments: [segment],

View File

@@ -1,5 +1,5 @@
import CanvasHandleRenderer from '@/components/canvas/elements/handles/CanvasHandleRenderer.vue';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { createComponentRenderer } from '@/__tests__/render';
import { CanvasNodeHandleKey } from '@/constants';
import { ref } from 'vue';
@@ -16,7 +16,7 @@ describe('CanvasHandleRenderer', () => {
const { container } = renderComponent({
props: {
mode: CanvasConnectionMode.Input,
type: NodeConnectionType.Main,
type: NodeConnectionTypes.Main,
index: 0,
position: 'left',
offset: { left: '10px', top: '10px' },
@@ -37,7 +37,7 @@ describe('CanvasHandleRenderer', () => {
const { container } = renderComponent({
props: {
mode: CanvasConnectionMode.Output,
type: NodeConnectionType.Main,
type: NodeConnectionTypes.Main,
index: 0,
position: 'right',
offset: { right: '10px', bottom: '10px' },
@@ -58,7 +58,7 @@ describe('CanvasHandleRenderer', () => {
const { container } = renderComponent({
props: {
mode: CanvasConnectionMode.Input,
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
index: 0,
position: 'top',
offset: { top: '10px', left: '5px' },
@@ -80,7 +80,7 @@ describe('CanvasHandleRenderer', () => {
const { getByText } = renderComponent({
props: {
mode: 'input',
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
index: 0,
position: 'top',
offset: { top: '10px', left: '5px' },

View File

@@ -5,7 +5,7 @@ import type { CanvasConnectionPort, CanvasElementPortWithRenderData } from '@/ty
import { CanvasConnectionMode } from '@/types';
import type { ValidConnectionFunc } from '@vue-flow/core';
import { Handle } from '@vue-flow/core';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import CanvasHandleMainInput from '@/components/canvas/elements/handles/render-types/CanvasHandleMainInput.vue';
import CanvasHandleMainOutput from '@/components/canvas/elements/handles/render-types/CanvasHandleMainOutput.vue';
import CanvasHandleNonMainInput from '@/components/canvas/elements/handles/render-types/CanvasHandleNonMainInput.vue';
@@ -58,13 +58,13 @@ const connectionsLimitReached = computed(() => {
const isConnectableStart = computed(() => {
if (connectionsLimitReached.value) return false;
return props.mode === CanvasConnectionMode.Output || props.type !== NodeConnectionType.Main;
return props.mode === CanvasConnectionMode.Output || props.type !== NodeConnectionTypes.Main;
});
const isConnectableEnd = computed(() => {
if (connectionsLimitReached.value) return false;
return props.mode === CanvasConnectionMode.Input || props.type !== NodeConnectionType.Main;
return props.mode === CanvasConnectionMode.Input || props.type !== NodeConnectionTypes.Main;
});
const isConnected = computed(() => props.connectionsCount > 0);
@@ -91,13 +91,13 @@ const RenderType = () => {
let Component;
if (props.mode === CanvasConnectionMode.Output) {
if (props.type === NodeConnectionType.Main) {
if (props.type === NodeConnectionTypes.Main) {
Component = CanvasHandleMainOutput;
} else {
Component = CanvasHandleNonMainOutput;
}
} else {
if (props.type === NodeConnectionType.Main) {
if (props.type === NodeConnectionTypes.Main) {
Component = CanvasHandleMainInput;
} else {
Component = CanvasHandleNonMainInput;

View File

@@ -1,7 +1,7 @@
import CanvasNode from '@/components/canvas/elements/nodes/CanvasNode.vue';
import { createComponentRenderer } from '@/__tests__/render';
import { createPinia, setActivePinia } from 'pinia';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { fireEvent } from '@testing-library/vue';
import { createCanvasNodeData, createCanvasNodeProps, createCanvasProvide } from '@/__tests__/data';
import { CanvasNodeRenderType } from '@/types';
@@ -61,13 +61,13 @@ describe('CanvasNode', () => {
...createCanvasNodeProps({
data: {
inputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
],
outputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
],
},
}),
@@ -92,9 +92,9 @@ describe('CanvasNode', () => {
...createCanvasNodeProps({
data: {
inputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.AiAgent, index: 0, required: true },
{ type: NodeConnectionType.AiTool, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.AiAgent, index: 0, required: true },
{ type: NodeConnectionTypes.AiTool, index: 0 },
],
outputs: [],
},

View File

@@ -1,6 +1,6 @@
import CanvasNodeDefault from '@/components/canvas/elements/nodes/render-types/CanvasNodeDefault.vue';
import { createComponentRenderer } from '@/__tests__/render';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { createCanvasNodeProvide, createCanvasProvide } from '@/__tests__/data';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
@@ -40,7 +40,7 @@ describe('CanvasNodeDefault', () => {
provide: {
...createCanvasNodeProvide({
data: {
inputs: [{ type: NodeConnectionType.Main, index: 0 }],
inputs: [{ type: NodeConnectionTypes.Main, index: 0 }],
},
}),
},
@@ -58,9 +58,9 @@ describe('CanvasNodeDefault', () => {
...createCanvasNodeProvide({
data: {
inputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
],
},
}),
@@ -80,7 +80,7 @@ describe('CanvasNodeDefault', () => {
provide: {
...createCanvasNodeProvide({
data: {
outputs: [{ type: NodeConnectionType.Main, index: 0 }],
outputs: [{ type: NodeConnectionTypes.Main, index: 0 }],
},
}),
},
@@ -98,9 +98,9 @@ describe('CanvasNodeDefault', () => {
...createCanvasNodeProvide({
data: {
outputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.Main, index: 0 },
],
},
}),
@@ -173,17 +173,17 @@ describe('CanvasNodeDefault', () => {
...createCanvasNodeProvide({
data: {
disabled: true,
inputs: [{ type: NodeConnectionType.Main, index: 0 }],
outputs: [{ type: NodeConnectionType.Main, index: 0 }],
inputs: [{ type: NodeConnectionTypes.Main, index: 0 }],
outputs: [{ type: NodeConnectionTypes.Main, index: 0 }],
connections: {
[CanvasConnectionMode.Input]: {
[NodeConnectionType.Main]: [
[{ node: 'node', type: NodeConnectionType.Main, index: 0 }],
[NodeConnectionTypes.Main]: [
[{ node: 'node', type: NodeConnectionTypes.Main, index: 0 }],
],
},
[CanvasConnectionMode.Output]: {
[NodeConnectionType.Main]: [
[{ node: 'node', type: NodeConnectionType.Main, index: 0 }],
[NodeConnectionTypes.Main]: [
[{ node: 'node', type: NodeConnectionTypes.Main, index: 0 }],
],
},
},
@@ -251,10 +251,10 @@ describe('CanvasNodeDefault', () => {
...createCanvasNodeProvide({
data: {
inputs: [
{ type: NodeConnectionType.Main, index: 0 },
{ type: NodeConnectionType.AiTool, index: 0 },
{ type: NodeConnectionType.AiDocument, index: 0, required: true },
{ type: NodeConnectionType.AiMemory, index: 0, required: true },
{ type: NodeConnectionTypes.Main, index: 0 },
{ type: NodeConnectionTypes.AiTool, index: 0 },
{ type: NodeConnectionTypes.AiDocument, index: 0, required: true },
{ type: NodeConnectionTypes.AiMemory, index: 0, required: true },
],
render: {
type: CanvasNodeRenderType.Default,