diff --git a/packages/cli/package.json b/packages/cli/package.json index 468adbf379..252994f485 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.119.0", + "version": "0.121.0", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", @@ -55,6 +55,7 @@ "devDependencies": { "@oclif/dev-cli": "^1.22.2", "@types/basic-auth": "^1.1.2", + "@types/bcryptjs": "^2.4.2", "@types/bull": "^3.3.10", "@types/compression": "1.0.1", "@types/connect-history-api-fallback": "^1.3.1", @@ -79,11 +80,11 @@ "typescript": "~3.9.7" }, "dependencies": { - "@node-rs/bcrypt": "^1.2.0", "@oclif/command": "^1.5.18", "@oclif/errors": "^1.2.2", "@types/jsonwebtoken": "^8.3.4", "basic-auth": "^2.0.1", + "bcryptjs": "^2.4.3", "body-parser": "^1.18.3", "body-parser-xml": "^1.1.0", "bull": "^3.19.0", @@ -104,10 +105,10 @@ "localtunnel": "^2.0.0", "lodash.get": "^4.4.2", "mysql2": "~2.2.0", - "n8n-core": "~0.70.0", - "n8n-editor-ui": "~0.89.0", - "n8n-nodes-base": "~0.116.0", - "n8n-workflow": "~0.57.0", + "n8n-core": "~0.72.0", + "n8n-editor-ui": "~0.91.0", + "n8n-nodes-base": "~0.118.0", + "n8n-workflow": "~0.59.0", "oauth-1.0a": "^2.2.6", "open": "^7.0.0", "pg": "^8.3.0", diff --git a/packages/cli/src/GenericHelpers.ts b/packages/cli/src/GenericHelpers.ts index 8dba633baa..80b107f2be 100644 --- a/packages/cli/src/GenericHelpers.ts +++ b/packages/cli/src/GenericHelpers.ts @@ -11,22 +11,6 @@ import { IPackageVersions } from './'; let versionCache: IPackageVersions | undefined; -/** - * Displays a message to the user - * - * @export - * @param {string} message The message to display - * @param {string} [level='log'] - */ -export function logOutput(message: string, level = 'log'): void { - if (level === 'log') { - console.log(message); - } else if (level === 'error') { - console.error(message); - } -} - - /** * Returns the base URL n8n is reachable from * diff --git a/packages/cli/src/LoadNodesAndCredentials.ts b/packages/cli/src/LoadNodesAndCredentials.ts index a69c6be33f..2b1263e6d0 100644 --- a/packages/cli/src/LoadNodesAndCredentials.ts +++ b/packages/cli/src/LoadNodesAndCredentials.ts @@ -4,11 +4,18 @@ import { } from 'n8n-core'; import { ICredentialType, + ILogger, INodeType, INodeTypeData, + LoggerProxy, } from 'n8n-workflow'; import * as config from '../config'; + +import { + getLogger, +} from '../src/Logger'; + import { access as fsAccess, readdir as fsReaddir, @@ -31,7 +38,12 @@ class LoadNodesAndCredentialsClass { nodeModulesPath = ''; + logger: ILogger; + async init() { + this.logger = getLogger(); + LoggerProxy.init(this.logger); + // Get the path to the node-modules folder to be later able // to load the credentials and nodes const checkPaths = [ @@ -171,6 +183,10 @@ class LoadNodesAndCredentialsClass { tempNode.description.icon = 'file:' + path.join(path.dirname(filePath), tempNode.description.icon.substr(5)); } + if (tempNode.executeSingle) { + this.logger.warn(`"executeSingle" will get deprecated soon. Please update the code of node "${packageName}.${nodeName}" to use "execute" instead!`, { filePath }); + } + if (this.includeNodes !== undefined && !this.includeNodes.includes(fullNodeName)) { return; } diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index fb4523af3c..ba4eb543d0 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -8,7 +8,6 @@ import { resolve as pathResolve, } from 'path'; import { - getConnection, getConnectionManager, In, } from 'typeorm'; @@ -22,7 +21,9 @@ import { RequestOptions } from 'oauth-1.0a'; import * as csrf from 'csrf'; import * as requestPromise from 'request-promise-native'; import { createHmac } from 'crypto'; -import { compare } from '@node-rs/bcrypt'; +// IMPORTANT! Do not switch to anther bcrypt library unless really necessary and +// tested with all possible systems like Windows, Alpine on ARM, FreeBSD, ... +import { compare } from 'bcryptjs'; import * as promClient from 'prom-client'; import { @@ -572,6 +573,7 @@ class App { const newWorkflowData = req.body as IWorkflowBase; const id = req.params.id; + newWorkflowData.id = id; await this.externalHooks.run('workflow.update', [newWorkflowData]); @@ -716,6 +718,7 @@ class App { // get generated dynamically this.app.get(`/${this.restEndpoint}/node-parameter-options`, ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { const nodeType = req.query.nodeType as string; + const path = req.query.path as string; let credentials: INodeCredentials | undefined = undefined; const currentNodeParameters = JSON.parse('' + req.query.currentNodeParameters) as INodeParameters; if (req.query.credentials !== undefined) { @@ -725,7 +728,7 @@ class App { const nodeTypes = NodeTypes(); - const loadDataInstance = new LoadNodeParameterOptions(nodeType, nodeTypes, JSON.parse('' + req.query.currentNodeParameters), credentials!); + const loadDataInstance = new LoadNodeParameterOptions(nodeType, nodeTypes, path, JSON.parse('' + req.query.currentNodeParameters), credentials!); const workflowData = loadDataInstance.getWorkflowData() as IWorkflowBase; const workflowCredentials = await WorkflowCredentials(workflowData.nodes); diff --git a/packages/core/package.json b/packages/core/package.json index 35b12c5b17..26f3b8b9d2 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "n8n-core", - "version": "0.70.0", + "version": "0.72.0", "description": "Core functionality of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", @@ -47,7 +47,7 @@ "file-type": "^14.6.2", "lodash.get": "^4.4.2", "mime-types": "^2.1.27", - "n8n-workflow": "~0.57.0", + "n8n-workflow": "~0.59.0", "oauth-1.0a": "^2.2.6", "p-cancelable": "^2.0.0", "request": "^2.88.2", diff --git a/packages/core/src/LoadNodeParameterOptions.ts b/packages/core/src/LoadNodeParameterOptions.ts index 6a9b457503..d112f63bfd 100644 --- a/packages/core/src/LoadNodeParameterOptions.ts +++ b/packages/core/src/LoadNodeParameterOptions.ts @@ -18,10 +18,12 @@ const TEMP_WORKFLOW_NAME = 'Temp-Workflow'; export class LoadNodeParameterOptions { + path: string; workflow: Workflow; - constructor(nodeTypeName: string, nodeTypes: INodeTypes, currentNodeParameters: INodeParameters, credentials?: INodeCredentials) { + constructor(nodeTypeName: string, nodeTypes: INodeTypes, path: string, currentNodeParameters: INodeParameters, credentials?: INodeCredentials) { + this.path = path; const nodeType = nodeTypes.getByName(nodeTypeName); if (nodeType === undefined) { @@ -89,7 +91,7 @@ export class LoadNodeParameterOptions { throw new Error(`The node-type "${node!.type}" does not have the method "${methodName}" defined!`); } - const thisArgs = NodeExecuteFunctions.getLoadOptionsFunctions(this.workflow, node!, additionalData); + const thisArgs = NodeExecuteFunctions.getLoadOptionsFunctions(this.workflow, node!, this.path, additionalData); return nodeType!.methods.loadOptions[methodName].call(thisArgs); } diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index aeeb39c810..36004fd10c 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -691,7 +691,7 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx return continueOnFail(node); }, evaluateExpression: (expression: string, itemIndex: number) => { - return workflow.expression.resolveSimpleParameterValue('=' + expression, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); + return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); }, async executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise { // tslint:disable-line:no-any return additionalData.executeWorkflow(workflowInfo, additionalData, inputData); @@ -742,7 +742,7 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx return getWorkflowMetadata(workflow); }, getWorkflowDataProxy: (itemIndex: number): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode); return dataProxy.getDataProxy(); }, getWorkflowStaticData(type: string): IDataObject { @@ -789,7 +789,7 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: }, evaluateExpression: (expression: string, evaluateItemIndex: number | undefined) => { evaluateItemIndex = evaluateItemIndex === undefined ? itemIndex : evaluateItemIndex; - return workflow.expression.resolveSimpleParameterValue('=' + expression, runExecutionData, runIndex, evaluateItemIndex, node.name, connectionInputData, mode); + return workflow.expression.resolveSimpleParameterValue('=' + expression, {}, runExecutionData, runIndex, evaluateItemIndex, node.name, connectionInputData, mode); }, getContext(type: string): IContextObject { return NodeHelpers.getContext(runExecutionData, type, node); @@ -841,7 +841,7 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: return getWorkflowMetadata(workflow); }, getWorkflowDataProxy: (): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode); + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, {}, mode); return dataProxy.getDataProxy(); }, getWorkflowStaticData(type: string): IDataObject { @@ -871,18 +871,20 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: * @param {IWorkflowExecuteAdditionalData} additionalData * @returns {ILoadOptionsFunctions} */ -export function getLoadOptionsFunctions(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData): ILoadOptionsFunctions { - return ((workflow: Workflow, node: INode) => { +export function getLoadOptionsFunctions(workflow: Workflow, node: INode, path: string, additionalData: IWorkflowExecuteAdditionalData): ILoadOptionsFunctions { + return ((workflow: Workflow, node: INode, path: string) => { const that = { getCredentials(type: string): ICredentialDataDecryptedObject | undefined { return getCredentials(workflow, node, type, additionalData, 'internal'); }, - getCurrentNodeParameter: (parameterName: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object | undefined => { + getCurrentNodeParameter: (parameterPath: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object | undefined => { const nodeParameters = additionalData.currentNodeParameters; - if (nodeParameters && nodeParameters[parameterName]) { - return nodeParameters[parameterName]; + + if (parameterPath.charAt(0) === '&') { + parameterPath = `${path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`; } - return undefined; + + return get(nodeParameters, parameterPath); }, getCurrentNodeParameters: (): INodeParameters | undefined => { return additionalData.currentNodeParameters; @@ -915,7 +917,7 @@ export function getLoadOptionsFunctions(workflow: Workflow, node: INode, additio }, }; return that; - })(workflow, node); + })(workflow, node, path); } diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 54311ff034..b86a1f9a4e 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.89.0", + "version": "0.91.0", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", @@ -65,7 +65,7 @@ "lodash.debounce": "^4.0.8", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", - "n8n-workflow": "~0.57.0", + "n8n-workflow": "~0.59.0", "node-sass": "^4.12.0", "normalize-wheel": "^1.0.1", "prismjs": "^1.17.1", diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 1ac72fd90a..4fdbd770f8 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -131,7 +131,7 @@ export interface IRestApi { getSettings(): Promise; getNodeTypes(): Promise; getNodesInformation(nodeList: string[]): Promise; - getNodeParameterOptions(nodeType: string, methodName: string, currentNodeParameters: INodeParameters, credentials?: INodeCredentials): Promise; + getNodeParameterOptions(nodeType: string, path: string, methodName: string, currentNodeParameters: INodeParameters, credentials?: INodeCredentials): Promise; removeTestWebhook(workflowId: string): Promise; runWorkflow(runData: IStartRunData): Promise; createNewWorkflow(sendData: IWorkflowData): Promise; @@ -444,4 +444,4 @@ export interface ILinkMenuItemProperties { icon: string; href: string; newWindow?: boolean; -} \ No newline at end of file +} diff --git a/packages/editor-ui/src/components/FixedCollectionParameter.vue b/packages/editor-ui/src/components/FixedCollectionParameter.vue index 9588e51a80..2d10f5b3ad 100644 --- a/packages/editor-ui/src/components/FixedCollectionParameter.vue +++ b/packages/editor-ui/src/components/FixedCollectionParameter.vue @@ -177,7 +177,11 @@ export default mixins(genericHelpers) } else if (optionParameter.typeOptions !== undefined && optionParameter.typeOptions.multipleValues === true) { // Multiple values are allowed so append option to array newParameterValue[optionParameter.name] = get(this.nodeValues, `${this.path}.${optionParameter.name}`, []); - (newParameterValue[optionParameter.name] as INodeParameters[]).push(JSON.parse(JSON.stringify(optionParameter.default))); + if (Array.isArray(optionParameter.default)) { + (newParameterValue[optionParameter.name] as INodeParameters[]).push(...JSON.parse(JSON.stringify(optionParameter.default))); + } else if (optionParameter.default !== '' && typeof optionParameter.default !== 'object') { + (newParameterValue[optionParameter.name] as INodeParameters[]).push(JSON.parse(JSON.stringify(optionParameter.default))); + } } else { // Add a new option newParameterValue[optionParameter.name] = JSON.parse(JSON.stringify(optionParameter.default)); diff --git a/packages/editor-ui/src/components/NodeSettings.vue b/packages/editor-ui/src/components/NodeSettings.vue index 7bdf7ea5dd..303b1fcb26 100644 --- a/packages/editor-ui/src/components/NodeSettings.vue +++ b/packages/editor-ui/src/components/NodeSettings.vue @@ -37,9 +37,6 @@