diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..dfdb8b771c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/.github/workflows/e2e-tests-pr.yml b/.github/workflows/e2e-tests-pr.yml index 0b92e187bd..1d9ead6db8 100644 --- a/.github/workflows/e2e-tests-pr.yml +++ b/.github/workflows/e2e-tests-pr.yml @@ -47,5 +47,5 @@ jobs: run: exit 0 - name: Fail job if run-e2e-tests failed - if: ${{ github.event.review.state != 'approved' || needs.run-e2e-tests.result == 'failure' }} + if: ${{ (github.event.review.state != 'approved' && github.event.review.state != 'commented') || needs.run-e2e-tests.result == 'failure' }} run: exit 1 diff --git a/cypress/constants.ts b/cypress/constants.ts index 5118696bc8..a7e2966577 100644 --- a/cypress/constants.ts +++ b/cypress/constants.ts @@ -1,3 +1,5 @@ +export const BACKEND_BASE_URL = 'http://localhost:5678'; + export const N8N_AUTH_COOKIE = 'n8n-auth'; export const DEFAULT_USER_EMAIL = 'nathan@n8n.io'; diff --git a/cypress/e2e/12-canvas.cy.ts b/cypress/e2e/12-canvas.cy.ts index 29869e4434..65428acda8 100644 --- a/cypress/e2e/12-canvas.cy.ts +++ b/cypress/e2e/12-canvas.cy.ts @@ -29,7 +29,6 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.visit(); }); - it('should add switch node and test connections', () => { WorkflowPage.actions.addNodeToCanvas(SWITCH_NODE_NAME, true); @@ -114,7 +113,7 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.zoomToFit(); cy.get('.plus-draggable-endpoint').filter(':visible').should('not.have.class', 'ep-success'); - cy.get('.jtk-connector.success').should('have.length', 3); + cy.get('.jtk-connector.success').should('have.length', 4); cy.get('.jtk-connector').should('have.length', 4); }); diff --git a/cypress/e2e/14-mapping.cy.ts b/cypress/e2e/14-mapping.cy.ts index b66e909b59..c7035396d3 100644 --- a/cypress/e2e/14-mapping.cy.ts +++ b/cypress/e2e/14-mapping.cy.ts @@ -16,12 +16,10 @@ describe('Data mapping', () => { beforeEach(() => { workflowPage.actions.visit(); - cy.window().then( - (win) => { - // @ts-ignore - win.preventNodeViewBeforeUnload = true; - }, - ); + cy.window().then((win) => { + // @ts-ignore + win.preventNodeViewBeforeUnload = true; + }); }); it('maps expressions from table header', () => { @@ -303,19 +301,28 @@ describe('Data mapping', () => { ndv.getters.parameterInput('keepOnlySet').find('input[type="checkbox"]').should('exist'); ndv.getters.parameterInput('keepOnlySet').find('input[type="text"]').should('not.exist'); - ndv.getters.inputDataContainer().should('exist').find('span').contains('count').realMouseDown().realMouseMove(100, 100); + ndv.getters + .inputDataContainer() + .should('exist') + .find('span') + .contains('count') + .realMouseDown() + .realMouseMove(100, 100); cy.wait(50); ndv.getters.parameterInput('keepOnlySet').find('input[type="checkbox"]').should('not.exist'); - ndv.getters.parameterInput('keepOnlySet').find('input[type="text"]') + ndv.getters + .parameterInput('keepOnlySet') + .find('input[type="text"]') .should('exist') .invoke('css', 'border') .then((border) => expect(border).to.include('dashed rgb(90, 76, 194)')); - ndv.getters.parameterInput('value').find('input[type="text"]') - .should('exist') - .invoke('css', 'border') - .then((border) => expect(border).to.include('dashed rgb(90, 76, 194)')); + ndv.getters + .parameterInput('value') + .find('input[type="text"]') + .should('exist') + .invoke('css', 'border') + .then((border) => expect(border).to.include('dashed rgb(90, 76, 194)')); }); - }); diff --git a/cypress/e2e/15-scheduler-node.cy.ts b/cypress/e2e/15-scheduler-node.cy.ts index b3ffd430e1..cc4b3d7758 100644 --- a/cypress/e2e/15-scheduler-node.cy.ts +++ b/cypress/e2e/15-scheduler-node.cy.ts @@ -1,4 +1,5 @@ import { WorkflowPage, WorkflowsPage, NDV } from '../pages'; +import { BACKEND_BASE_URL } from '../constants'; const workflowsPage = new WorkflowsPage(); const workflowPage = new WorkflowPage(); @@ -39,44 +40,34 @@ describe('Schedule Trigger node', async () => { workflowPage.actions.activateWorkflow(); workflowPage.getters.activatorSwitch().should('have.class', 'is-checked'); - cy.request('GET', '/rest/workflows') - .then((response) => { + cy.url().then((url) => { + const workflowId = url.split('/').pop(); + + cy.wait(1200); + cy.request('GET', `${BACKEND_BASE_URL}/rest/executions`).then((response) => { expect(response.status).to.eq(200); - expect(response.body.data).to.have.length(1); - const workflowId = response.body.data[0].id.toString(); - expect(workflowId).to.not.be.empty; - return workflowId; - }) - .then((workflowId) => { + expect(workflowId).to.not.be.undefined; + expect(response.body.data.results.length).to.be.greaterThan(0); + const matchingExecutions = response.body.data.results.filter( + (execution: any) => execution.workflowId === workflowId, + ); + expect(matchingExecutions).to.have.length(1); + cy.wait(1200); - cy.request('GET', '/rest/executions') - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body.data.results.length).to.be.greaterThan(0); - const matchingExecutions = response.body.data.results.filter( - (execution: any) => execution.workflowId === workflowId, - ); - expect(matchingExecutions).to.have.length(1); - return workflowId; - }) - .then((workflowId) => { - cy.wait(1200); - cy.request('GET', '/rest/executions') - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body.data.results.length).to.be.greaterThan(0); - const matchingExecutions = response.body.data.results.filter( - (execution: any) => execution.workflowId === workflowId, - ); - expect(matchingExecutions).to.have.length(2); - }) - .then(() => { - workflowPage.actions.activateWorkflow(); - workflowPage.getters.activatorSwitch().should('not.have.class', 'is-checked'); - cy.visit(workflowsPage.url); - workflowsPage.actions.deleteWorkFlow('Schedule Trigger Workflow'); - }); - }); + cy.request('GET', `${BACKEND_BASE_URL}/rest/executions`).then((response) => { + expect(response.status).to.eq(200); + expect(response.body.data.results.length).to.be.greaterThan(0); + const matchingExecutions = response.body.data.results.filter( + (execution: any) => execution.workflowId === workflowId, + ); + expect(matchingExecutions).to.have.length(2); + + workflowPage.actions.activateWorkflow(); + workflowPage.getters.activatorSwitch().should('not.have.class', 'is-checked'); + cy.visit(workflowsPage.url); + workflowsPage.actions.deleteWorkFlow('Schedule Trigger Workflow'); + }); }); + }); }); }); diff --git a/cypress/e2e/16-webhook-node.cy.ts b/cypress/e2e/16-webhook-node.cy.ts index 64556037d8..178350a32b 100644 --- a/cypress/e2e/16-webhook-node.cy.ts +++ b/cypress/e2e/16-webhook-node.cy.ts @@ -1,6 +1,7 @@ import { WorkflowPage, NDV, CredentialsModal } from '../pages'; import { v4 as uuid } from 'uuid'; import { cowBase64 } from '../support/binaryTestFiles'; +import { BACKEND_BASE_URL } from '../constants'; const workflowPage = new WorkflowPage(); const ndv = new NDV(); @@ -83,7 +84,7 @@ const simpleWebhookCall = (options: SimpleWebhookCallOptions) => { ndv.actions.execute(); cy.wait(waitForWebhook); - cy.request(method, '/webhook-test/' + webhookPath).then((response) => { + cy.request(method, `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(200); ndv.getters.outputPanel().contains('headers'); }); @@ -98,12 +99,10 @@ describe('Webhook Trigger node', async () => { beforeEach(() => { workflowPage.actions.visit(); - cy.window().then( - (win) => { - // @ts-ignore - win.preventNodeViewBeforeUnload = true; - }, - ); + cy.window().then((win) => { + // @ts-ignore + win.preventNodeViewBeforeUnload = true; + }); }); it('should listen for a GET request', () => { @@ -154,7 +153,7 @@ describe('Webhook Trigger node', async () => { workflowPage.actions.executeWorkflow(); cy.wait(waitForWebhook); - cy.request('GET', '/webhook-test/' + webhookPath).then((response) => { + cy.request('GET', `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(200); expect(response.body.MyValue).to.eq(1234); }); @@ -172,7 +171,7 @@ describe('Webhook Trigger node', async () => { ndv.actions.execute(); cy.wait(waitForWebhook); - cy.request('GET', '/webhook-test/' + webhookPath).then((response) => { + cy.request('GET', `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(201); }); }); @@ -201,7 +200,7 @@ describe('Webhook Trigger node', async () => { workflowPage.actions.executeWorkflow(); cy.wait(waitForWebhook); - cy.request('GET', '/webhook-test/' + webhookPath).then((response) => { + cy.request('GET', `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(200); expect(response.body.MyValue).to.eq(1234); }); @@ -246,7 +245,7 @@ describe('Webhook Trigger node', async () => { workflowPage.actions.executeWorkflow(); cy.wait(waitForWebhook); - cy.request('GET', '/webhook-test/' + webhookPath).then((response) => { + cy.request('GET', `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(200); expect(Object.keys(response.body).includes('data')).to.be.true; }); @@ -263,7 +262,7 @@ describe('Webhook Trigger node', async () => { }); ndv.actions.execute(); cy.wait(waitForWebhook); - cy.request('GET', '/webhook-test/' + webhookPath).then((response) => { + cy.request('GET', `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then((response) => { expect(response.status).to.eq(200); expect(response.body.MyValue).to.be.undefined; }); @@ -287,7 +286,7 @@ describe('Webhook Trigger node', async () => { cy.wait(waitForWebhook); cy.request({ method: 'GET', - url: '/webhook-test/' + webhookPath, + url: `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`, auth: { user: 'username', pass: 'password', @@ -300,7 +299,7 @@ describe('Webhook Trigger node', async () => { .then(() => { cy.request({ method: 'GET', - url: '/webhook-test/' + webhookPath, + url: `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`, auth: { user: 'test', pass: 'test', @@ -330,7 +329,7 @@ describe('Webhook Trigger node', async () => { cy.wait(waitForWebhook); cy.request({ method: 'GET', - url: '/webhook-test/' + webhookPath, + url: `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`, headers: { test: 'wrong', }, @@ -342,7 +341,7 @@ describe('Webhook Trigger node', async () => { .then(() => { cy.request({ method: 'GET', - url: '/webhook-test/' + webhookPath, + url: `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`, headers: { test: 'test', }, diff --git a/cypress/pages/ndv.ts b/cypress/pages/ndv.ts index f23eb97f4f..2a9b6edc4f 100644 --- a/cypress/pages/ndv.ts +++ b/cypress/pages/ndv.ts @@ -13,14 +13,17 @@ export class NDV extends BasePage { outputPanel: () => cy.getByTestId('output-panel'), executingLoader: () => cy.getByTestId('ndv-executing'), inputDataContainer: () => this.getters.inputPanel().findChildByTestId('ndv-data-container'), - inputDisplayMode: () => this.getters.inputPanel().findChildByTestId('ndv-run-data-display-mode').first(), + inputDisplayMode: () => + this.getters.inputPanel().findChildByTestId('ndv-run-data-display-mode').first(), outputDataContainer: () => this.getters.outputPanel().findChildByTestId('ndv-data-container'), - outputDisplayMode: () => this.getters.outputPanel().findChildByTestId('ndv-run-data-display-mode').first(), + outputDisplayMode: () => + this.getters.outputPanel().findChildByTestId('ndv-run-data-display-mode').first(), pinDataButton: () => cy.getByTestId('ndv-pin-data'), editPinnedDataButton: () => cy.getByTestId('ndv-edit-pinned-data'), pinnedDataEditor: () => this.getters.outputPanel().find('.cm-editor .cm-scroller'), runDataPaneHeader: () => cy.getByTestId('run-data-pane-header'), - savePinnedDataButton: () => this.getters.runDataPaneHeader().find('button').filter(':visible').contains('Save'), + savePinnedDataButton: () => + this.getters.runDataPaneHeader().find('button').filter(':visible').contains('Save'), outputTableRows: () => this.getters.outputDataContainer().find('table tr'), outputTableHeaders: () => this.getters.outputDataContainer().find('table thead th'), outputTableRow: (row: number) => this.getters.outputTableRows().eq(row), @@ -52,10 +55,13 @@ export class NDV extends BasePage { outputBranches: () => this.getters.outputPanel().findChildByTestId('branches'), inputBranches: () => this.getters.inputPanel().findChildByTestId('branches'), resourceLocator: (paramName: string) => cy.getByTestId(`resource-locator-${paramName}`), - resourceLocatorInput: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="rlc-input-container"]'), - resourceLocatorDropdown: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="resource-locator-dropdown"]'), + resourceLocatorInput: (paramName: string) => + this.getters.resourceLocator(paramName).find('[data-test-id="rlc-input-container"]'), + resourceLocatorDropdown: (paramName: string) => + this.getters.resourceLocator(paramName).find('[data-test-id="resource-locator-dropdown"]'), resourceLocatorErrorMessage: () => cy.getByTestId('rlc-error-container'), - resourceLocatorModeSelector: (paramName: string) => this.getters.resourceLocator(paramName).find('[data-test-id="rlc-mode-selector"]'), + resourceLocatorModeSelector: (paramName: string) => + this.getters.resourceLocator(paramName).find('[data-test-id="rlc-mode-selector"]'), }; actions = { @@ -82,7 +88,9 @@ export class NDV extends BasePage { this.getters.editPinnedDataButton().click(); this.getters.pinnedDataEditor().click(); - this.getters.pinnedDataEditor().type(`{selectall}{backspace}${JSON.stringify(data).replace(new RegExp('{', 'g'), '{{}')}`); + this.getters + .pinnedDataEditor() + .type(`{selectall}{backspace}${JSON.stringify(data).replace(new RegExp('{', 'g'), '{{}')}`); this.actions.savePinnedData(); }, @@ -131,15 +139,11 @@ export class NDV extends BasePage { }, changeInputRunSelector: (runName: string) => { this.getters.inputRunSelector().click(); - cy.get('.el-select-dropdown:visible .el-select-dropdown__item') - .contains(runName) - .click(); + cy.get('.el-select-dropdown:visible .el-select-dropdown__item').contains(runName).click(); }, changeOutputRunSelector: (runName: string) => { this.getters.outputRunSelector().click(); - cy.get('.el-select-dropdown:visible .el-select-dropdown__item') - .contains(runName) - .click(); + cy.get('.el-select-dropdown:visible .el-select-dropdown__item').contains(runName).click(); }, toggleOutputRunLinking: () => { this.getters.outputRunSelector().find('button').click(); @@ -159,7 +163,10 @@ export class NDV extends BasePage { this.getters.resourceLocatorInput(paramName).type(value); }, validateExpressionPreview: (paramName: string, value: string) => { - this.getters.parameterExpressionPreview(paramName).find('span').should('include.html', asEncodedHTML(value)); + this.getters + .parameterExpressionPreview(paramName) + .find('span') + .should('include.html', asEncodedHTML(value)); }, }; } @@ -172,4 +179,3 @@ function asEncodedHTML(str: string): string { .replace(/"/g, '"') .replace(/ /g, ' '); } - diff --git a/packages/cli/package.json b/packages/cli/package.json index a64f9a6747..1eb626456d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -77,22 +77,7 @@ "@types/json-diff": "^0.5.1", "@types/jsonwebtoken": "^9.0.1", "@types/localtunnel": "^1.9.0", - "@types/lodash.debounce": "^4.0.7", - "@types/lodash.difference": "^4", - "@types/lodash.get": "^4.4.6", - "@types/lodash.intersection": "^4.4.7", - "@types/lodash.iteratee": "^4.7.7", - "@types/lodash.merge": "^4.6.6", - "@types/lodash.omit": "^4.5.7", - "@types/lodash.pick": "^4.4.7", - "@types/lodash.remove": "^4.7.7", - "@types/lodash.set": "^4.3.6", - "@types/lodash.split": "^4.4.7", - "@types/lodash.unionby": "^4.8.7", - "@types/lodash.uniq": "^4.5.7", - "@types/lodash.uniqby": "^4.7.7", - "@types/lodash.unset": "^4.5.7", - "@types/lodash.without": "^4.4.7", + "@types/lodash": "^4.14.195", "@types/parseurl": "^1.3.1", "@types/passport-jwt": "^3.0.6", "@types/psl": "^1.1.0", @@ -109,7 +94,6 @@ "@types/yamljs": "^0.2.31", "chokidar": "^3.5.2", "concurrently": "^5.1.0", - "lodash.debounce": "^4.0.8", "mock-jwks": "^1.0.9", "nodemon": "^2.0.2", "run-script-os": "^1.0.7", @@ -161,21 +145,7 @@ "jwks-rsa": "^3.0.1", "ldapts": "^4.2.6", "localtunnel": "^2.0.0", - "lodash.difference": "^4", - "lodash.get": "^4.4.2", - "lodash.intersection": "^4.4.0", - "lodash.iteratee": "^4.7.0", - "lodash.merge": "^4.6.2", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "lodash.remove": "^4.7.0", - "lodash.set": "^4.3.2", - "lodash.split": "^4.4.2", - "lodash.unionby": "^4.8.0", - "lodash.uniq": "^4.5.0", - "lodash.uniqby": "^4.7.0", - "lodash.unset": "^4.5.2", - "lodash.without": "^4.4.0", + "lodash": "^4.17.21", "luxon": "^3.3.0", "mysql2": "~2.3.3", "n8n-core": "workspace:*", diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index 5b20ff91b2..03cbf74b68 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -7,7 +7,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ import { Credentials, NodeExecuteFunctions } from 'n8n-core'; -import get from 'lodash.get'; +import get from 'lodash/get'; import type { ICredentialDataDecryptedObject, diff --git a/packages/cli/src/CurlConverterHelper.ts b/packages/cli/src/CurlConverterHelper.ts index 06da059030..04ee444f25 100644 --- a/packages/cli/src/CurlConverterHelper.ts +++ b/packages/cli/src/CurlConverterHelper.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import curlconverter from 'curlconverter'; -import get from 'lodash.get'; +import get from 'lodash/get'; import type { IDataObject } from 'n8n-workflow'; import { jsonParse } from 'n8n-workflow'; diff --git a/packages/cli/src/LoadNodesAndCredentials.ts b/packages/cli/src/LoadNodesAndCredentials.ts index 47623076c4..d62dc464d7 100644 --- a/packages/cli/src/LoadNodesAndCredentials.ts +++ b/packages/cli/src/LoadNodesAndCredentials.ts @@ -1,4 +1,4 @@ -import uniq from 'lodash.uniq'; +import uniq from 'lodash/uniq'; import glob from 'fast-glob'; import type { DirectoryLoader, Types } from 'n8n-core'; import { diff --git a/packages/cli/src/PublicApi/v1/handlers/workflows/workflows.service.ts b/packages/cli/src/PublicApi/v1/handlers/workflows/workflows.service.ts index 8ed5031628..cc55ba547b 100644 --- a/packages/cli/src/PublicApi/v1/handlers/workflows/workflows.service.ts +++ b/packages/cli/src/PublicApi/v1/handlers/workflows/workflows.service.ts @@ -1,6 +1,6 @@ import type { FindManyOptions, UpdateResult } from 'typeorm'; import { In } from 'typeorm'; -import intersection from 'lodash.intersection'; +import intersection from 'lodash/intersection'; import type { INode } from 'n8n-workflow'; import { v4 as uuid } from 'uuid'; diff --git a/packages/cli/src/ReloadNodesAndCredentials.ts b/packages/cli/src/ReloadNodesAndCredentials.ts index 9abc08c7f4..8bb28f450b 100644 --- a/packages/cli/src/ReloadNodesAndCredentials.ts +++ b/packages/cli/src/ReloadNodesAndCredentials.ts @@ -11,7 +11,7 @@ export const reloadNodesAndCredentials = async ( push: Push, ) => { // eslint-disable-next-line import/no-extraneous-dependencies - const { default: debounce } = await import('lodash.debounce'); + const { default: debounce } = await import('lodash/debounce'); // eslint-disable-next-line import/no-extraneous-dependencies const { watch } = await import('chokidar'); diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index 4ac4dbd1fa..d1046f35fb 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -14,7 +14,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable prefer-destructuring */ import type express from 'express'; -import get from 'lodash.get'; +import get from 'lodash/get'; import stream from 'stream'; import { promisify } from 'util'; diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index cdfd6cb657..ca3c2acb1a 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -42,7 +42,7 @@ import { WorkflowHooks, } from 'n8n-workflow'; -import pick from 'lodash.pick'; +import pick from 'lodash/pick'; import type { FindOptionsWhere } from 'typeorm'; import { LessThanOrEqual, In } from 'typeorm'; import { DateUtils } from 'typeorm/util/DateUtils'; diff --git a/packages/cli/src/WorkflowHelpers.ts b/packages/cli/src/WorkflowHelpers.ts index c6a40455fe..abdc2b011e 100644 --- a/packages/cli/src/WorkflowHelpers.ts +++ b/packages/cli/src/WorkflowHelpers.ts @@ -31,7 +31,7 @@ import config from '@/config'; import type { WorkflowEntity } from '@db/entities/WorkflowEntity'; import type { User } from '@db/entities/User'; import { RoleRepository } from '@db/repositories'; -import omit from 'lodash.omit'; +import omit from 'lodash/omit'; import { PermissionChecker } from './UserManagement/PermissionChecker'; import { isWorkflowIdValid } from './utils'; import { UserService } from './user/user.service'; diff --git a/packages/cli/src/commands/executeBatch.ts b/packages/cli/src/commands/executeBatch.ts index 413a4894da..a71f9d2d2e 100644 --- a/packages/cli/src/commands/executeBatch.ts +++ b/packages/cli/src/commands/executeBatch.ts @@ -6,7 +6,7 @@ import type { ITaskData } from 'n8n-workflow'; import { sleep } from 'n8n-workflow'; import { sep } from 'path'; import { diff } from 'json-diff'; -import pick from 'lodash.pick'; +import pick from 'lodash/pick'; import { ActiveExecutions } from '@/ActiveExecutions'; import * as Db from '@/Db'; diff --git a/packages/cli/src/controllers/ldap.controller.ts b/packages/cli/src/controllers/ldap.controller.ts index b354ef6600..25c19d5d21 100644 --- a/packages/cli/src/controllers/ldap.controller.ts +++ b/packages/cli/src/controllers/ldap.controller.ts @@ -1,4 +1,4 @@ -import pick from 'lodash.pick'; +import pick from 'lodash/pick'; import { Authorized, Get, Post, Put, RestController } from '@/decorators'; import { getLdapConfig, getLdapSynchronizations, updateLdapConfig } from '@/Ldap/helpers'; import { LdapService } from '@/Ldap/LdapService.ee'; diff --git a/packages/cli/src/controllers/nodeTypes.controller.ts b/packages/cli/src/controllers/nodeTypes.controller.ts index 63002c7c12..49dec0b674 100644 --- a/packages/cli/src/controllers/nodeTypes.controller.ts +++ b/packages/cli/src/controllers/nodeTypes.controller.ts @@ -1,5 +1,5 @@ import { readFile } from 'fs/promises'; -import get from 'lodash.get'; +import get from 'lodash/get'; import { Request } from 'express'; import type { INodeTypeDescription, INodeTypeNameVersion } from 'n8n-workflow'; import { Authorized, Post, RestController } from '@/decorators'; diff --git a/packages/cli/src/controllers/passwordReset.controller.ts b/packages/cli/src/controllers/passwordReset.controller.ts index f316fe2da9..aaaf72896d 100644 --- a/packages/cli/src/controllers/passwordReset.controller.ts +++ b/packages/cli/src/controllers/passwordReset.controller.ts @@ -131,14 +131,14 @@ export class PasswordResetController { const baseUrl = getInstanceBaseUrl(); const { id, firstName, lastName } = user; - const url = UserService.generatePasswordResetUrl(user); + const url = await UserService.generatePasswordResetUrl(user); try { await this.mailer.passwordReset({ email, firstName, lastName, - passwordResetUrl: url.toString(), + passwordResetUrl: url, domain: baseUrl, }); } catch (error) { diff --git a/packages/cli/src/credentials/oauth2Credential.api.ts b/packages/cli/src/credentials/oauth2Credential.api.ts index b394dfefb5..f0e74b53fe 100644 --- a/packages/cli/src/credentials/oauth2Credential.api.ts +++ b/packages/cli/src/credentials/oauth2Credential.api.ts @@ -2,11 +2,11 @@ import type { ClientOAuth2Options } from '@n8n/client-oauth2'; import { ClientOAuth2 } from '@n8n/client-oauth2'; import Csrf from 'csrf'; import express from 'express'; -import get from 'lodash.get'; -import omit from 'lodash.omit'; -import set from 'lodash.set'; -import split from 'lodash.split'; -import unset from 'lodash.unset'; +import get from 'lodash/get'; +import omit from 'lodash/omit'; +import set from 'lodash/set'; +import split from 'lodash/split'; +import unset from 'lodash/unset'; import { Credentials, UserSettings } from 'n8n-core'; import type { WorkflowExecuteMode, diff --git a/packages/cli/src/environments/versionControl/versionControlExport.service.ee.ts b/packages/cli/src/environments/versionControl/versionControlExport.service.ee.ts index 413c4009e6..37544035f7 100644 --- a/packages/cli/src/environments/versionControl/versionControlExport.service.ee.ts +++ b/packages/cli/src/environments/versionControl/versionControlExport.service.ee.ts @@ -29,7 +29,7 @@ import { WorkflowEntity } from '@/databases/entities/WorkflowEntity'; import { WorkflowTagMapping } from '@/databases/entities/WorkflowTagMapping'; import { TagEntity } from '@/databases/entities/TagEntity'; import { ActiveWorkflowRunner } from '../../ActiveWorkflowRunner'; -import without from 'lodash.without'; +import without from 'lodash/without'; import type { VersionControllPullOptions } from './types/versionControlPullWorkFolder'; import { versionControlFoldersExistCheck } from './versionControlHelper.ee'; import { In } from 'typeorm'; diff --git a/packages/cli/src/eventbus/MessageEventBus/MessageEventBus.ts b/packages/cli/src/eventbus/MessageEventBus/MessageEventBus.ts index 5d63f57b26..ea476fea38 100644 --- a/packages/cli/src/eventbus/MessageEventBus/MessageEventBus.ts +++ b/packages/cli/src/eventbus/MessageEventBus/MessageEventBus.ts @@ -15,7 +15,7 @@ import { messageEventBusDestinationFromDb, incrementPrometheusMetric, } from '../MessageEventBusDestination/Helpers.ee'; -import uniqby from 'lodash.uniqby'; +import uniqby from 'lodash/uniqBy'; import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm'; import type { EventMessageAuditOptions } from '../EventMessageClasses/EventMessageAudit'; import { EventMessageAudit } from '../EventMessageClasses/EventMessageAudit'; diff --git a/packages/cli/src/eventbus/MessageEventBusWriter/MessageEventBusLogWriter.ts b/packages/cli/src/eventbus/MessageEventBusWriter/MessageEventBusLogWriter.ts index 87293f6149..efc0de1e21 100644 --- a/packages/cli/src/eventbus/MessageEventBusWriter/MessageEventBusLogWriter.ts +++ b/packages/cli/src/eventbus/MessageEventBusWriter/MessageEventBusLogWriter.ts @@ -7,7 +7,7 @@ import { Worker } from 'worker_threads'; import { createReadStream, existsSync, rmSync } from 'fs'; import readline from 'readline'; import { jsonParse, LoggerProxy } from 'n8n-workflow'; -import remove from 'lodash.remove'; +import remove from 'lodash/remove'; import config from '@/config'; import { getEventMessageObjectByType } from '../EventMessageClasses/Helpers'; import type { EventMessageReturnMode } from '../MessageEventBus/MessageEventBus'; diff --git a/packages/cli/src/workflows/workflows.services.ts b/packages/cli/src/workflows/workflows.services.ts index 747cede32c..74d31f1a64 100644 --- a/packages/cli/src/workflows/workflows.services.ts +++ b/packages/cli/src/workflows/workflows.services.ts @@ -4,7 +4,7 @@ import type { INode, IPinData, JsonObject } from 'n8n-workflow'; import { NodeApiError, jsonParse, LoggerProxy, Workflow } from 'n8n-workflow'; import type { FindOptionsSelect, FindOptionsWhere, UpdateResult } from 'typeorm'; import { In } from 'typeorm'; -import pick from 'lodash.pick'; +import pick from 'lodash/pick'; import { v4 as uuid } from 'uuid'; import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import * as Db from '@/Db'; diff --git a/packages/cli/test/integration/shared/utils.ts b/packages/cli/test/integration/shared/utils.ts index 19ccee37d4..359b46b2f1 100644 --- a/packages/cli/test/integration/shared/utils.ts +++ b/packages/cli/test/integration/shared/utils.ts @@ -5,7 +5,7 @@ import { existsSync } from 'fs'; import bodyParser from 'body-parser'; import { CronJob } from 'cron'; import express from 'express'; -import set from 'lodash.set'; +import set from 'lodash/set'; import { BinaryDataManager, UserSettings } from 'n8n-core'; import type { ICredentialType, diff --git a/packages/core/package.json b/packages/core/package.json index 60e865a21b..99571fcfd9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -38,8 +38,7 @@ "@types/cron": "~1.7.1", "@types/crypto-js": "^4.0.1", "@types/express": "^4.17.6", - "@types/lodash.get": "^4.4.6", - "@types/lodash.pick": "^4.4.7", + "@types/lodash": "^4.14.195", "@types/mime-types": "^2.1.0", "@types/request-promise-native": "~1.0.15", "@types/uuid": "^8.3.2" @@ -54,8 +53,7 @@ "file-type": "^16.5.4", "flatted": "^3.2.4", "form-data": "^4.0.0", - "lodash.get": "^4.4.2", - "lodash.pick": "^4.4.0", + "lodash": "^4.17.21", "mime-types": "^2.1.27", "n8n-workflow": "workspace:*", "oauth-1.0a": "^2.2.6", diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 996389c9f0..b192e9b560 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -79,7 +79,7 @@ import { validateFieldType, } from 'n8n-workflow'; -import pick from 'lodash.pick'; +import pick from 'lodash/pick'; import { Agent } from 'https'; import { IncomingMessage } from 'http'; import { stringify } from 'qs'; @@ -92,7 +92,7 @@ import type { } from '@n8n/client-oauth2'; import { ClientOAuth2 } from '@n8n/client-oauth2'; import crypto, { createHmac } from 'crypto'; -import get from 'lodash.get'; +import get from 'lodash/get'; import type { Request, Response } from 'express'; import FormData from 'form-data'; import path from 'path'; diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index 88411e4f93..7e556f2210 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -37,7 +37,7 @@ import type { WorkflowExecuteMode, } from 'n8n-workflow'; import { LoggerProxy as Logger, WorkflowOperationError } from 'n8n-workflow'; -import get from 'lodash.get'; +import get from 'lodash/get'; import * as NodeExecuteFunctions from './NodeExecuteFunctions'; export class WorkflowExecute { diff --git a/packages/core/test/Helpers.ts b/packages/core/test/Helpers.ts index 0d68744954..5b8bb76530 100644 --- a/packages/core/test/Helpers.ts +++ b/packages/core/test/Helpers.ts @@ -1,4 +1,4 @@ -import set from 'lodash.set'; +import set from 'lodash/set'; import type { ICredentialDataDecryptedObject, diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 6f51a6c821..14135f1818 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -70,7 +70,6 @@ "v-click-outside": "^3.1.2", "vue": "^2.7.14", "vue-agile": "^2.0.0", - "vue-fragment": "1.5.1", "vue-i18n": "^8.26.7", "vue-infinite-loading": "^2.4.5", "vue-json-pretty": "1.9.3", diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 6b4e872bec..b79ca557a0 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -975,13 +975,10 @@ export interface ITagsState { fetchedUsageCount: boolean; } -export type Modals = - | { - [key: string]: ModalState; - } - | { - [CREDENTIAL_EDIT_MODAL_KEY]: NewCredentialsModal; - }; +export type Modals = { + [CREDENTIAL_EDIT_MODAL_KEY]: NewCredentialsModal; + [key: string]: ModalState; +}; export type ModalState = { open: boolean; diff --git a/packages/editor-ui/src/__tests__/server/endpoints/versionControl.ts b/packages/editor-ui/src/__tests__/server/endpoints/versionControl.ts index 09a079d869..b3c6c60ac8 100644 --- a/packages/editor-ui/src/__tests__/server/endpoints/versionControl.ts +++ b/packages/editor-ui/src/__tests__/server/endpoints/versionControl.ts @@ -19,7 +19,7 @@ export function routesForVersionControl(server: Server) { }; server.post(`${versionControlApiRoot}/preferences`, (schema: AppSchema, request: Request) => { - const requestBody = jsonParse(request.requestBody) as Partial; + const requestBody: Partial = jsonParse(request.requestBody); return new Response( 200, @@ -34,7 +34,7 @@ export function routesForVersionControl(server: Server) { }); server.patch(`${versionControlApiRoot}/preferences`, (schema: AppSchema, request: Request) => { - const requestBody = jsonParse(request.requestBody) as Partial; + const requestBody: Partial = jsonParse(request.requestBody); return new Response( 200, diff --git a/packages/editor-ui/src/__tests__/setup.ts b/packages/editor-ui/src/__tests__/setup.ts index 28fef7c5d7..172da286a7 100644 --- a/packages/editor-ui/src/__tests__/setup.ts +++ b/packages/editor-ui/src/__tests__/setup.ts @@ -3,17 +3,26 @@ import { configure } from '@testing-library/vue'; import Vue from 'vue'; import '../plugins'; import { I18nPlugin } from '@/plugins/i18n'; +import { config } from '@vue/test-utils'; +import { GlobalComponentsPlugin } from '@/plugins/components'; +import { GlobalDirectivesPlugin } from '@/plugins/directives'; +import { FontAwesomePlugin } from '@/plugins/icons'; configure({ testIdAttribute: 'data-test-id' }); Vue.config.productionTip = false; Vue.config.devtools = false; +Vue.use(I18nPlugin); +Vue.use(FontAwesomePlugin); +Vue.use(GlobalComponentsPlugin); +Vue.use(GlobalDirectivesPlugin); + // TODO: Investigate why this is needed // Without having this 3rd party library imported like this, any component test using 'vue-json-pretty' fail with: // [Vue warn]: Failed to mount component: template or render function not defined. -Vue.component('vue-json-pretty', require('vue-json-pretty').default); -Vue.use((vue) => I18nPlugin(vue)); +// Vue.component('vue-json-pretty', require('vue-json-pretty').default); +config.stubs['vue-json-pretty'] = require('vue-json-pretty').default; window.ResizeObserver = window.ResizeObserver || diff --git a/packages/editor-ui/src/components/Badge.vue b/packages/editor-ui/src/components/Badge.vue index 0275081a73..1a70af7870 100644 --- a/packages/editor-ui/src/components/Badge.vue +++ b/packages/editor-ui/src/components/Badge.vue @@ -1,12 +1,10 @@