Skip to content

Commit

Permalink
fix(editor): Fix issue that frontend breaks with unkown nodes (#7596)
Browse files Browse the repository at this point in the history
Because of recent changes does the frontend break when a node is not
known.

![Screenshot from 2023-11-03
08-27-43](https://github.com/n8n-io/n8n/assets/6249596/ab340c3c-9b72-4220-b1f8-70d80f7a5522)



Github issue / Community forum post (link here to close automatically):

---------

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Oleg Ivaniv <me@olegivaniv.com>
  • Loading branch information
janober and OlegIvaniv authored Nov 6, 2023
1 parent a994ba5 commit db56a9e
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 25 deletions.
36 changes: 36 additions & 0 deletions cypress/e2e/12-canvas.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,40 @@ describe('Canvas Node Manipulation and Navigation', () => {
NDVDialog.actions.close();
});
});

it('should render connections correctly if unkown nodes are present', () => {
const unknownNodeName = 'Unknown node';
cy.createFixtureWorkflow('workflow-with-unknown-nodes.json', 'Unknown nodes');

WorkflowPage.getters.canvasNodeByName(`${unknownNodeName} 1`).should('exist');
WorkflowPage.getters.canvasNodeByName(`${unknownNodeName} 2`).should('exist');
WorkflowPage.actions.zoomToFit();

cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('plus', `${unknownNodeName} 1`),
WorkflowPage.getters.getEndpointSelector('input', EDIT_FIELDS_SET_NODE_NAME),
);

cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('plus', `${unknownNodeName} 2`),
WorkflowPage.getters.getEndpointSelector('input', `${EDIT_FIELDS_SET_NODE_NAME}1`),
);

WorkflowPage.actions.executeWorkflow();
cy.contains('Node not found').should('be.visible');

WorkflowPage.getters
.canvasNodeByName(`${unknownNodeName} 1`)
.find('[data-test-id=delete-node-button]')
.click({ force: true });

WorkflowPage.getters
.canvasNodeByName(`${unknownNodeName} 2`)
.find('[data-test-id=delete-node-button]')
.click({ force: true });

WorkflowPage.actions.executeWorkflow();

cy.contains('Node not found').should('not.exist');
});
});
90 changes: 90 additions & 0 deletions cypress/fixtures/workflow-with-unknown-nodes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"meta": {
"instanceId": "15bbf37b6a515ccc2f534cabcd8bd171ca33583ff7744b1e9420e5ce68e615bb"
},
"nodes": [
{
"parameters": {},
"id": "40720511-19b6-4421-bdb0-3fb6efef4bc5",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
280,
320
]
},
{
"parameters": {},
"id": "acdd1bdc-c642-4ea6-ad67-f4201b640cfa",
"name": "Unknown node 1",
"type": "n8n-nodes-base.thisNodeDoesntExist",
"typeVersion": 1,
"position": [
400,
500
]
},
{
"parameters": {},
"id": "acdd1bdc-c642-4ea6-ad67-f4201b640ffa",
"name": "Unknown node 2",
"type": "n8n-nodes-base.thisNodeDoesntExistEither",
"typeVersion": 1,
"position": [
600,
500
]
},
{
"parameters": {
"options": {}
},
"id": "fbe5163b-7474-4741-980a-e4956789be0a",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
500,
320
]
},
{
"parameters": {
"options": {}
},
"id": "163313b9-64ff-4ffc-b00f-09b267d8132c",
"name": "Edit Fields1",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
720,
320
]
}
],
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Edit Fields1",
"type": "main",
"index": 0
}
]
]
}
}
}
52 changes: 27 additions & 25 deletions packages/editor-ui/src/components/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -365,36 +365,38 @@ export default defineComponent({
top: this.position[1] + 'px',
};
const workflow = this.workflowsStore.getCurrentWorkflow();
const inputs =
NodeHelpers.getNodeInputs(workflow, this.node, this.nodeType) ||
([] as Array<ConnectionTypes | INodeInputConfiguration>);
const inputTypes = NodeHelpers.getConnectionTypes(inputs);
const nonMainInputs = inputTypes.filter((input) => input !== NodeConnectionType.Main);
if (nonMainInputs.length) {
const requiredNonMainInputs = inputs.filter(
(input) => typeof input !== 'string' && input.required,
);
if (this.node && this.nodeType) {
const workflow = this.workflowsStore.getCurrentWorkflow();
const inputs =
NodeHelpers.getNodeInputs(workflow, this.node, this.nodeType) ||
([] as Array<ConnectionTypes | INodeInputConfiguration>);
const inputTypes = NodeHelpers.getConnectionTypes(inputs);
const nonMainInputs = inputTypes.filter((input) => input !== NodeConnectionType.Main);
if (nonMainInputs.length) {
const requiredNonMainInputs = inputs.filter(
(input) => typeof input !== 'string' && input.required,
);
let spacerCount = 0;
if (NODE_INSERT_SPACER_BETWEEN_INPUT_GROUPS) {
const requiredNonMainInputsCount = requiredNonMainInputs.length;
const optionalNonMainInputsCount = nonMainInputs.length - requiredNonMainInputsCount;
spacerCount = requiredNonMainInputsCount > 0 && optionalNonMainInputsCount > 0 ? 1 : 0;
}
let spacerCount = 0;
if (NODE_INSERT_SPACER_BETWEEN_INPUT_GROUPS) {
const requiredNonMainInputsCount = requiredNonMainInputs.length;
const optionalNonMainInputsCount = nonMainInputs.length - requiredNonMainInputsCount;
spacerCount = requiredNonMainInputsCount > 0 && optionalNonMainInputsCount > 0 ? 1 : 0;
styles['--configurable-node-input-count'] = nonMainInputs.length + spacerCount;
}
styles['--configurable-node-input-count'] = nonMainInputs.length + spacerCount;
}
const outputs =
NodeHelpers.getNodeOutputs(workflow, this.node, this.nodeType) ||
([] as Array<ConnectionTypes | INodeOutputConfiguration>);
const outputs =
NodeHelpers.getNodeOutputs(workflow, this.node, this.nodeType) ||
([] as Array<ConnectionTypes | INodeOutputConfiguration>);
const outputTypes = NodeHelpers.getConnectionTypes(outputs);
const outputTypes = NodeHelpers.getConnectionTypes(outputs);
const mainOutputs = outputTypes.filter((output) => output === NodeConnectionType.Main);
styles['--node-main-output-count'] = mainOutputs.length;
const mainOutputs = outputTypes.filter((output) => output === NodeConnectionType.Main);
styles['--node-main-output-count'] = mainOutputs.length;
}
return styles;
},
Expand Down

0 comments on commit db56a9e

Please sign in to comment.