From b57ec1d6abbae9e23ae5f473d70674aa14701bce Mon Sep 17 00:00:00 2001 From: OlegIvaniv Date: Thu, 9 Feb 2023 16:04:26 +0100 Subject: [PATCH 1/6] fix(editor): Prevent creation of input connections for nodes without input slot (#5425) * fix(editor): Prevent creation of input connections for nodes without input * WIP: Workflow checks service and controller * fix: Created SQLite migration to remove broken connections * Cleanup & add mysql/posgres migrations * Linter fixes * Unify the migration scripts * Escape migration workflow_entity * Wrap the migration in try/catch and do not parse nodes and connection if mysql/postgres * Do migration changes also fro mysql * refactor: Wrap only the necessary call in try catch block --------- Co-authored-by: Omar Ajoue --- packages/cli/src/commands/start.ts | 16 ++-- ...0580449-PurgeInvalidWorkflowConnections.ts | 91 +++++++++++++++++++ .../src/databases/migrations/mysqldb/index.ts | 2 + ...0580449-PurgeInvalidWorkflowConnections.ts | 90 ++++++++++++++++++ .../databases/migrations/postgresdb/index.ts | 2 + ...0580449-PurgeInvalidWorkflowConnections.ts | 91 +++++++++++++++++++ .../src/databases/migrations/sqlite/index.ts | 2 + packages/editor-ui/src/views/NodeView.vue | 33 +++---- 8 files changed, 301 insertions(+), 26 deletions(-) create mode 100644 packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts create mode 100644 packages/cli/src/databases/migrations/postgresdb/1675940580449-PurgeInvalidWorkflowConnections.ts create mode 100644 packages/cli/src/databases/migrations/sqlite/1675940580449-PurgeInvalidWorkflowConnections.ts diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index 590307c26f..90b495fe79 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -239,6 +239,14 @@ export class Start extends Command { const { flags } = this.parse(Start); try { + // Load all node and credential types + const loadNodesAndCredentials = LoadNodesAndCredentials(); + await loadNodesAndCredentials.init(); + + // Add the found types to an instance other parts of the application can use + const nodeTypes = NodeTypes(loadNodesAndCredentials); + const credentialTypes = CredentialTypes(loadNodesAndCredentials); + // Start directly with the init of the database to improve startup time await Db.init().catch(async (error: Error) => exitWithCrash('There was an error initializing DB', error), @@ -265,18 +273,10 @@ export class Start extends Command { await Start.generateStaticAssets(); } - // Load all node and credential types - const loadNodesAndCredentials = LoadNodesAndCredentials(); - await loadNodesAndCredentials.init(); - // Load all external hooks const externalHooks = ExternalHooks(); await externalHooks.init(); - // Add the found types to an instance other parts of the application can use - const nodeTypes = NodeTypes(loadNodesAndCredentials); - const credentialTypes = CredentialTypes(loadNodesAndCredentials); - // Load the credentials overwrites if any exist CredentialsOverwrites(credentialTypes); diff --git a/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts b/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts new file mode 100644 index 0000000000..654858b422 --- /dev/null +++ b/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts @@ -0,0 +1,91 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; +import { NodeTypes } from '@/NodeTypes'; +import { IConnections, INode } from 'n8n-workflow'; +import { getLogger } from '@/Logger'; + +export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface { + name = 'PurgeInvalidWorkflowConnections1675940580449'; + + async up(queryRunner: QueryRunner): Promise { + logMigrationStart(this.name); + + const tablePrefix = getTablePrefix(); + + const workflows: Array<{ id: number; nodes: INode[]; connections: IConnections }> = + await queryRunner.query(` + SELECT id, nodes, connections + FROM \`${tablePrefix}workflow_entity\` + `); + + const nodeTypes = NodeTypes(); + + workflows.forEach(async (workflow) => { + let connections: IConnections = workflow.connections; + const nodes: INode[] = workflow.nodes; + + const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { + try { + const nodeType = nodeTypes.getByNameAndVersion(node.type, node.typeVersion); + if ((nodeType.description.inputs?.length ?? []) === 0) { + acc.push(node.name); + } + } catch (error) { + getLogger().warn(`Migration ${this.name} failed with error: ${error.message}`); + } + return acc; + }, [] as string[]); + + Object.keys(connections).forEach((sourceNodeName) => { + const connection = connections[sourceNodeName]; + const outputs = Object.keys(connection); + + outputs.forEach((outputConnectionName /* Like `main` */, idx) => { + const outputConnection = connection[outputConnectionName]; + + // It filters out all connections that are connected to a node that cannot receive input + outputConnection.forEach((outputConnectionItem, outputConnectionItemIdx) => { + outputConnection[outputConnectionItemIdx] = outputConnectionItem.filter( + (outgoingConnections) => + !nodesThatCannotReceiveInput.includes(outgoingConnections.node), + ); + }); + + // Filter out output connection items that are empty + connection[outputConnectionName] = connection[outputConnectionName].filter( + (item) => item.length > 0, + ); + + // Delete the output connection container if it is empty + if (connection[outputConnectionName].length === 0) { + delete connection[outputConnectionName]; + } + }); + + // Finally delete the source node if it has no output connections + if (Object.keys(connection).length === 0) { + delete connections[sourceNodeName]; + } + }); + + // Update database with new connections + const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( + ` + UPDATE \`${tablePrefix}workflow_entity\` + SET connections = :connections + WHERE id = '${workflow.id}' + `, + { connections: JSON.stringify(connections) }, + {}, + ); + + await queryRunner.query(updateQuery, updateParams); + }); + + logMigrationEnd(this.name); + } + + async down(queryRunner: QueryRunner): Promise { + // No need to revert this migration + } +} diff --git a/packages/cli/src/databases/migrations/mysqldb/index.ts b/packages/cli/src/databases/migrations/mysqldb/index.ts index 8892ddcbe7..2c25db44b1 100644 --- a/packages/cli/src/databases/migrations/mysqldb/index.ts +++ b/packages/cli/src/databases/migrations/mysqldb/index.ts @@ -30,6 +30,7 @@ import { RemoveWorkflowDataLoadedFlag1671726148420 } from './1671726148420-Remov import { MessageEventBusDestinations1671535397530 } from './1671535397530-MessageEventBusDestinations'; import { DeleteExecutionsWithWorkflows1673268682475 } from './1673268682475-DeleteExecutionsWithWorkflows'; import { CreateLdapEntities1674509946020 } from './1674509946020-CreateLdapEntities'; +import { PurgeInvalidWorkflowConnections1675940580449 } from './1675940580449-PurgeInvalidWorkflowConnections'; export const mysqlMigrations = [ InitialMigration1588157391238, @@ -64,4 +65,5 @@ export const mysqlMigrations = [ MessageEventBusDestinations1671535397530, DeleteExecutionsWithWorkflows1673268682475, CreateLdapEntities1674509946020, + PurgeInvalidWorkflowConnections1675940580449 ]; diff --git a/packages/cli/src/databases/migrations/postgresdb/1675940580449-PurgeInvalidWorkflowConnections.ts b/packages/cli/src/databases/migrations/postgresdb/1675940580449-PurgeInvalidWorkflowConnections.ts new file mode 100644 index 0000000000..7534742ce4 --- /dev/null +++ b/packages/cli/src/databases/migrations/postgresdb/1675940580449-PurgeInvalidWorkflowConnections.ts @@ -0,0 +1,90 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; +import { NodeTypes } from '@/NodeTypes'; +import { IConnections, INode } from 'n8n-workflow'; +import { getLogger } from '@/Logger'; +export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface { + name = 'PurgeInvalidWorkflowConnections1675940580449'; + + async up(queryRunner: QueryRunner): Promise { + logMigrationStart(this.name); + + const tablePrefix = getTablePrefix(); + + const workflows: Array<{ id: number; nodes: INode[]; connections: IConnections }> = + await queryRunner.query(` + SELECT id, nodes, connections + FROM "${tablePrefix}workflow_entity" + `); + + const nodeTypes = NodeTypes(); + + workflows.forEach(async (workflow) => { + let connections: IConnections = workflow.connections; + const nodes: INode[] = workflow.nodes; + + const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { + try { + const nodeType = nodeTypes.getByNameAndVersion(node.type, node.typeVersion); + if ((nodeType.description.inputs?.length ?? []) === 0) { + acc.push(node.name); + } + } catch (error) { + getLogger().warn(`Migration ${this.name} failed with error: ${error.message}`); + } + return acc; + }, [] as string[]); + + Object.keys(connections).forEach((sourceNodeName) => { + const connection = connections[sourceNodeName]; + const outputs = Object.keys(connection); + + outputs.forEach((outputConnectionName /* Like `main` */, idx) => { + const outputConnection = connection[outputConnectionName]; + + // It filters out all connections that are connected to a node that cannot receive input + outputConnection.forEach((outputConnectionItem, outputConnectionItemIdx) => { + outputConnection[outputConnectionItemIdx] = outputConnectionItem.filter( + (outgoingConnections) => + !nodesThatCannotReceiveInput.includes(outgoingConnections.node), + ); + }); + + // Filter out output connection items that are empty + connection[outputConnectionName] = connection[outputConnectionName].filter( + (item) => item.length > 0, + ); + + // Delete the output connection container if it is empty + if (connection[outputConnectionName].length === 0) { + delete connection[outputConnectionName]; + } + }); + + // Finally delete the source node if it has no output connections + if (Object.keys(connection).length === 0) { + delete connections[sourceNodeName]; + } + }); + + // Update database with new connections + const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( + ` + UPDATE "${tablePrefix}workflow_entity" + SET connections = :connections + WHERE id = '${workflow.id}' + `, + { connections: JSON.stringify(connections) }, + {}, + ); + + await queryRunner.query(updateQuery, updateParams); + }); + + logMigrationEnd(this.name); + } + + async down(queryRunner: QueryRunner): Promise { + // No need to revert this migration + } +} diff --git a/packages/cli/src/databases/migrations/postgresdb/index.ts b/packages/cli/src/databases/migrations/postgresdb/index.ts index 6138f89d56..dde85c808b 100644 --- a/packages/cli/src/databases/migrations/postgresdb/index.ts +++ b/packages/cli/src/databases/migrations/postgresdb/index.ts @@ -28,6 +28,7 @@ import { RemoveWorkflowDataLoadedFlag1671726148421 } from './1671726148421-Remov import { MessageEventBusDestinations1671535397530 } from './1671535397530-MessageEventBusDestinations'; import { DeleteExecutionsWithWorkflows1673268682475 } from './1673268682475-DeleteExecutionsWithWorkflows'; import { CreateLdapEntities1674509946020 } from './1674509946020-CreateLdapEntities'; +import { PurgeInvalidWorkflowConnections1675940580449 } from './1675940580449-PurgeInvalidWorkflowConnections'; export const postgresMigrations = [ InitialMigration1587669153312, @@ -60,4 +61,5 @@ export const postgresMigrations = [ MessageEventBusDestinations1671535397530, DeleteExecutionsWithWorkflows1673268682475, CreateLdapEntities1674509946020, + PurgeInvalidWorkflowConnections1675940580449 ]; diff --git a/packages/cli/src/databases/migrations/sqlite/1675940580449-PurgeInvalidWorkflowConnections.ts b/packages/cli/src/databases/migrations/sqlite/1675940580449-PurgeInvalidWorkflowConnections.ts new file mode 100644 index 0000000000..459c478214 --- /dev/null +++ b/packages/cli/src/databases/migrations/sqlite/1675940580449-PurgeInvalidWorkflowConnections.ts @@ -0,0 +1,91 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; +import { NodeTypes } from '@/NodeTypes'; +import { IConnections, INode } from 'n8n-workflow'; +import { getLogger } from '@/Logger'; + +export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface { + name = 'PurgeInvalidWorkflowConnections1675940580449'; + + async up(queryRunner: QueryRunner): Promise { + logMigrationStart(this.name); + + const tablePrefix = getTablePrefix(); + + const workflows: Array<{ id: number; nodes: string; connections: string }> = + await queryRunner.query(` + SELECT id, nodes, connections + FROM "${tablePrefix}workflow_entity" + `); + + const nodeTypes = NodeTypes(); + + workflows.forEach(async (workflow) => { + let connections: IConnections = JSON.parse(workflow.connections); + const nodes: INode[] = JSON.parse(workflow.nodes); + + const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { + try { + const nodeType = nodeTypes.getByNameAndVersion(node.type, node.typeVersion); + if ((nodeType.description.inputs?.length ?? []) === 0) { + acc.push(node.name); + } + } catch (error) { + getLogger().warn(`Migration ${this.name} failed with error: ${error.message}`); + } + return acc; + }, [] as string[]); + + Object.keys(connections).forEach((sourceNodeName) => { + const connection = connections[sourceNodeName]; + const outputs = Object.keys(connection); + + outputs.forEach((outputConnectionName /* Like `main` */, idx) => { + const outputConnection = connection[outputConnectionName]; + + // It filters out all connections that are connected to a node that cannot receive input + outputConnection.forEach((outputConnectionItem, outputConnectionItemIdx) => { + outputConnection[outputConnectionItemIdx] = outputConnectionItem.filter( + (outgoingConnections) => + !nodesThatCannotReceiveInput.includes(outgoingConnections.node), + ); + }); + + // Filter out output connection items that are empty + connection[outputConnectionName] = connection[outputConnectionName].filter( + (item) => item.length > 0, + ); + + // Delete the output connection container if it is empty + if (connection[outputConnectionName].length === 0) { + delete connection[outputConnectionName]; + } + }); + + // Finally delete the source node if it has no output connections + if (Object.keys(connection).length === 0) { + delete connections[sourceNodeName]; + } + }); + + // Update database with new connections + const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( + ` + UPDATE "${tablePrefix}workflow_entity" + SET connections = :connections + WHERE id = '${workflow.id}' + `, + { connections: JSON.stringify(connections) }, + {}, + ); + + await queryRunner.query(updateQuery, updateParams); + }); + + logMigrationEnd(this.name); + } + + async down(queryRunner: QueryRunner): Promise { + // No need to revert this migration + } +} diff --git a/packages/cli/src/databases/migrations/sqlite/index.ts b/packages/cli/src/databases/migrations/sqlite/index.ts index 247daf1280..7325893d18 100644 --- a/packages/cli/src/databases/migrations/sqlite/index.ts +++ b/packages/cli/src/databases/migrations/sqlite/index.ts @@ -27,6 +27,7 @@ import { RemoveWorkflowDataLoadedFlag1671726148419 } from './1671726148419-Remov import { MessageEventBusDestinations1671535397530 } from './1671535397530-MessageEventBusDestinations'; import { DeleteExecutionsWithWorkflows1673268682475 } from './1673268682475-DeleteExecutionsWithWorkflows'; import { CreateLdapEntities1674509946020 } from './1674509946020-CreateLdapEntities'; +import { PurgeInvalidWorkflowConnections1675940580449 } from './1675940580449-PurgeInvalidWorkflowConnections'; const sqliteMigrations = [ InitialMigration1588102412422, @@ -58,6 +59,7 @@ const sqliteMigrations = [ MessageEventBusDestinations1671535397530, DeleteExecutionsWithWorkflows1673268682475, CreateLdapEntities1674509946020, + PurgeInvalidWorkflowConnections1675940580449, ]; export { sqliteMigrations }; diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 22ee4d3679..6d33c4d1e6 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -1995,7 +1995,7 @@ export default mixins( }, ] as [IConnection, IConnection]; - this.__addConnection(connectionData, true); + this.__addConnection(connectionData); }, async addNode( nodeTypeName: string, @@ -2558,22 +2558,19 @@ export default mixins( return NodeViewUtils.getInputEndpointUUID(node.id, index); }, - __addConnection(connection: [IConnection, IConnection], addVisualConnection = false) { - if (addVisualConnection) { - const outputUuid = this.getOutputEndpointUUID(connection[0].node, connection[0].index); - const inputUuid = this.getInputEndpointUUID(connection[1].node, connection[1].index); - if (!outputUuid || !inputUuid) { - return; - } - - const uuid: [string, string] = [outputUuid, inputUuid]; - // Create connections in DOM - this.instance?.connect({ - uuids: uuid, - detachable: !this.isReadOnly, - }); + __addConnection(connection: [IConnection, IConnection]) { + const outputUuid = this.getOutputEndpointUUID(connection[0].node, connection[0].index); + const inputUuid = this.getInputEndpointUUID(connection[1].node, connection[1].index); + if (!outputUuid || !inputUuid) { + return; } - this.workflowsStore.addConnection({ connection }); + + const uuid: [string, string] = [outputUuid, inputUuid]; + // Create connections in DOM + this.instance?.connect({ + uuids: uuid, + detachable: !this.isReadOnly, + }); setTimeout(() => { this.addPinDataConnections(this.workflowsStore.pinData); @@ -3264,7 +3261,7 @@ export default mixins( }, ] as [IConnection, IConnection]; - this.__addConnection(connectionData, true); + this.__addConnection(connectionData); }); } } @@ -3750,7 +3747,7 @@ export default mixins( }, async onRevertRemoveConnection({ connection }: { connection: [IConnection, IConnection] }) { this.suspendRecordingDetachedConnections = true; - this.__addConnection(connection, true); + this.__addConnection(connection); this.suspendRecordingDetachedConnections = false; }, async onRevertNameChange({ currentName, newName }: { currentName: string; newName: string }) { From 7fc96571e0ce294de3d643f5f29cc38211888a0a Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Thu, 9 Feb 2023 18:15:20 +0100 Subject: [PATCH 2/6] fix: MySQL migration parses database contents if necessary (fix for MariaDB) (#5441) --- ...75940580449-PurgeInvalidWorkflowConnections.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts b/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts index 654858b422..ed104c2122 100644 --- a/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts +++ b/packages/cli/src/databases/migrations/mysqldb/1675940580449-PurgeInvalidWorkflowConnections.ts @@ -12,8 +12,11 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn const tablePrefix = getTablePrefix(); - const workflows: Array<{ id: number; nodes: INode[]; connections: IConnections }> = - await queryRunner.query(` + const workflows: Array<{ + id: number; + nodes: INode[] | string; + connections: IConnections | string; + }> = await queryRunner.query(` SELECT id, nodes, connections FROM \`${tablePrefix}workflow_entity\` `); @@ -21,8 +24,12 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn const nodeTypes = NodeTypes(); workflows.forEach(async (workflow) => { - let connections: IConnections = workflow.connections; - const nodes: INode[] = workflow.nodes; + let connections: IConnections = + typeof workflow.connections === 'string' + ? JSON.parse(workflow.connections) + : workflow.connections; + const nodes: INode[] = + typeof workflow.nodes === 'string' ? JSON.parse(workflow.nodes) : workflow.nodes; const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { try { From 8f36ce3ffbbea83bddfdcdb56ff25aea8cb8d1e8 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 9 Feb 2023 19:33:34 +0100 Subject: [PATCH 3/6] :bookmark: Release n8n-editor-ui@0.180.3 --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 2c47080014..fa363356c2 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.180.2", + "version": "0.180.3", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 48740f87638d1223e5716d6f42aa8741e3634c2f Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 9 Feb 2023 12:36:56 -0600 Subject: [PATCH 4/6] :arrow_up: Set n8n-editor-ui@0.180.3 on n8n --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 450b42c475..b1391d44b3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -166,7 +166,7 @@ "luxon": "^3.1.0", "mysql2": "~2.3.3", "n8n-core": "~0.153.0", - "n8n-editor-ui": "~0.180.2", + "n8n-editor-ui": "~0.180.3", "n8n-nodes-base": "~0.212.2", "n8n-workflow": "~0.135.0", "nodemailer": "^6.7.1", From c278f010ef83541f166fafdaafe3b851419bc04e Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 9 Feb 2023 12:38:05 -0600 Subject: [PATCH 5/6] =?UTF-8?q?:bookmark:=20Release=C2=A0n8n@0.214.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index b1391d44b3..1ce845a75d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.214.2", + "version": "0.214.3", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", From 1c6a93feecc6c3c87724b70d781163d4a8b5d273 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 9 Feb 2023 12:40:53 -0600 Subject: [PATCH 6/6] :books: Update CHANGELOG.md and main package.json to 0.214.3 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- pnpm-lock.yaml | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0908dd4fa..d8ce37e50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [0.214.3](https://github.com/n8n-io/n8n/compare/n8n@0.214.2...n8n@0.214.3) (2023-02-09) + + +### Bug Fixes + +* **editor:** Prevent creation of input connections for nodes without input slot ([#5425](https://github.com/n8n-io/n8n/issues/5425)) ([b57ec1d](https://github.com/n8n-io/n8n/commit/b57ec1d6abbae9e23ae5f473d70674aa14701bce)) + + + ## [0.214.1](https://github.com/n8n-io/n8n/compare/n8n@0.214.0...n8n@0.214.1) (2023-02-06) diff --git a/package.json b/package.json index cefee514e2..733fdce8e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.214.1", + "version": "0.214.3", "private": true, "homepage": "https://n8n.io", "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3dc447b27d..828f0a2f9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -198,8 +198,8 @@ importers: luxon: ^3.1.0 mysql2: ~2.3.3 n8n-core: ~0.153.0 - n8n-editor-ui: ~0.180.1 - n8n-nodes-base: ~0.212.1 + n8n-editor-ui: ~0.180.3 + n8n-nodes-base: ~0.212.2 n8n-workflow: ~0.135.0 nodemailer: ^6.7.1 nodemon: ^2.0.2