diff --git a/cypress/e2e/12-canvas.cy.ts b/cypress/e2e/12-canvas.cy.ts index 94900b82065ad..9af6d25697ae0 100644 --- a/cypress/e2e/12-canvas.cy.ts +++ b/cypress/e2e/12-canvas.cy.ts @@ -34,10 +34,10 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.addNodeToCanvas(SWITCH_NODE_NAME, true, true); for (let i = 0; i < desiredOutputs; i++) { - cy.contains('Add Routing Rule').click() + cy.contains('Add Routing Rule').click(); } - NDVDialog.actions.close() + NDVDialog.actions.close(); for (let i = 0; i < desiredOutputs; i++) { WorkflowPage.getters.canvasNodePlusEndpointByName(SWITCH_NODE_NAME, i).click({ force: true }); WorkflowPage.getters.nodeCreatorSearchBar().should('be.visible'); @@ -51,7 +51,9 @@ describe('Canvas Node Manipulation and Navigation', () => { cy.reload(); cy.waitForLoad(); // Make sure outputless switch was connected correctly - cy.get(`[data-target-node="${SWITCH_NODE_NAME}1"][data-source-node="${EDIT_FIELDS_SET_NODE_NAME}3"]`).should('be.visible'); + cy.get( + `[data-target-node="${SWITCH_NODE_NAME}1"][data-source-node="${EDIT_FIELDS_SET_NODE_NAME}3"]`, + ).should('be.visible'); // Make sure all connections are there after reload for (let i = 0; i < desiredOutputs; i++) { const setName = `${EDIT_FIELDS_SET_NODE_NAME}${i > 0 ? i : ''}`; @@ -179,7 +181,7 @@ describe('Canvas Node Manipulation and Navigation', () => { .canvasNodes() .last() .should('have.css', 'left', '740px') - .should('have.css', 'top', '320px') + .should('have.css', 'top', '320px'); }); it('should zoom in', () => { @@ -350,5 +352,17 @@ describe('Canvas Node Manipulation and Navigation', () => { cy.waitForLoad(); WorkflowPage.getters.canvasNodes().should('have.length', 2); cy.get('.rect-input-endpoint.jtk-endpoint-connected').should('have.length', 1); - }) + }); + + it('should remove unknown credentials on pasting workflow', () => { + cy.fixture('workflow-with-unknown-credentials.json').then((data) => { + cy.get('body').paste(JSON.stringify(data)); + + WorkflowPage.getters.canvasNodes().should('have.have.length', 2); + + WorkflowPage.actions.openNode('n8n'); + cy.get('[class*=hasIssues]').should('have.length', 1); + NDVDialog.actions.close(); + }); + }); }); diff --git a/cypress/fixtures/workflow-with-unknown-credentials.json b/cypress/fixtures/workflow-with-unknown-credentials.json new file mode 100644 index 0000000000000..2793889fee176 --- /dev/null +++ b/cypress/fixtures/workflow-with-unknown-credentials.json @@ -0,0 +1,52 @@ +{ + "meta": { + "instanceId": "123" + }, + "nodes": [ + { + "parameters": { + "resource": "credential", + "name": "123", + "credentialTypeName": "123" + }, + "id": "a01f79f6-e8c3-44c5-be5e-4bc482e23172", + "name": "n8n", + "type": "n8n-nodes-base.n8n", + "typeVersion": 1, + "position": [ + 540, + 240 + ], + "credentials": { + "n8nApi": { + "id": "10", + "name": "n8n account" + } + } + }, + { + "parameters": {}, + "id": "acdd1bdc-c642-4ea6-ad67-f4201b640cfa", + "name": "When clicking \"Execute Workflow\"", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [ + 300, + 240 + ] + } + ], + "connections": { + "When clicking \"Execute Workflow\"": { + "main": [ + [ + { + "node": "n8n", + "type": "main", + "index": 0 + } + ] + ] + } + } +} diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 952f7389f65a3..b8228bc40d8bc 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -1677,6 +1677,8 @@ export default defineComponent({ }); } + this.removeUnknownCredentials(workflowData); + const currInstanceId = this.rootStore.instanceId; const nodeGraph = JSON.stringify( @@ -1756,6 +1758,23 @@ export default defineComponent({ this.showError(error, this.$locale.baseText('nodeView.showError.importWorkflowData.title')); } }, + + removeUnknownCredentials(workflow: IWorkflowToShare) { + if (!workflow?.nodes) return; + + for (const node of workflow.nodes) { + if (!node.credentials) continue; + + for (const [name, credential] of Object.entries(node.credentials)) { + if (credential.id === null) continue; + + if (!this.credentialsStore.getCredentialById(credential.id)) { + delete node.credentials[name]; + } + } + } + }, + onDragOver(event: DragEvent) { event.preventDefault(); },