diff --git a/.github/workflows/e2e-tests-pr.yml b/.github/workflows/e2e-tests-pr.yml
index 648383750d1abc..4d6aea14cfde03 100644
--- a/.github/workflows/e2e-tests-pr.yml
+++ b/.github/workflows/e2e-tests-pr.yml
@@ -48,5 +48,5 @@ jobs:
run: exit 0
- name: Fail job if run-e2e-tests failed
- if: needs.run-e2e-tests.result == 'failure'
+ if: ${{ github.event.review.state != 'approved' || needs.run-e2e-tests.result == 'failure' }}
run: exit 1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38c765cb5e6fa5..3bcc6f99c00dfd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,43 @@
+# [0.228.0](https://github.com/n8n-io/n8n/compare/n8n@0.227.0...n8n@0.228.0) (2023-05-11)
+
+
+### Bug Fixes
+
+* **AWS Rekognition Node:** Fix all different action type ([#6136](https://github.com/n8n-io/n8n/issues/6136)) ([22b82a4](https://github.com/n8n-io/n8n/commit/22b82a43a24bb8415eb8f4a941b05647ef8904c2))
+* **core:** Ensure DB repositories are initialized before the DB migrations are run ([#6220](https://github.com/n8n-io/n8n/issues/6220)) ([500c0eb](https://github.com/n8n-io/n8n/commit/500c0ebce34dc2d21a531176dee965a70abec5f8))
+* **core:** Move nodeExecute InternalHook calls to hookFunctionsSave ([#6193](https://github.com/n8n-io/n8n/issues/6193)) ([f00b2ae](https://github.com/n8n-io/n8n/commit/f00b2ae3eaa225e483abc8defdc58d27b7d2c5e8))
+* Correctly save executions that failed when polling as error instead of new ([#6192](https://github.com/n8n-io/n8n/issues/6192)) ([06948b5](https://github.com/n8n-io/n8n/commit/06948b5ba5775b4f03d1ce46d57a461014317d51))
+* **editor:** Add loading skeletons to Executions list page ([#6184](https://github.com/n8n-io/n8n/issues/6184)) ([eae3a55](https://github.com/n8n-io/n8n/commit/eae3a55cc6b87bc8998d18d3d32d0d03013996b1))
+* **editor:** Display SSO entry in Settings on Cloud ([#6181](https://github.com/n8n-io/n8n/issues/6181)) ([b0a1899](https://github.com/n8n-io/n8n/commit/b0a1899e7141e5726d4fcbca6bba47e8e4b5cef7))
+* **editor:** Fix polling trigger check for `runData` ([#6130](https://github.com/n8n-io/n8n/issues/6130)) ([80831cd](https://github.com/n8n-io/n8n/commit/80831cd7c60f77557c37317600690a289d966448))
+* **editor:** Fix viewing and downloading of binary data ([#6218](https://github.com/n8n-io/n8n/issues/6218)) ([b9779c3](https://github.com/n8n-io/n8n/commit/b9779c32936c8b5e2385226ecab1025ff88d7044))
+* **editor:** Flag issues only on workflow activation ([#6127](https://github.com/n8n-io/n8n/issues/6127)) ([1b49c17](https://github.com/n8n-io/n8n/commit/1b49c17f38e97547430c407e21284b0c508469fa))
+* **editor:** Remove duplicate mapping of `item.json` key in data pinning ([#6135](https://github.com/n8n-io/n8n/issues/6135)) ([91fee0c](https://github.com/n8n-io/n8n/commit/91fee0ca667f233c0bde0dc6089bbed7d7db5b5f))
+* **editor:** Show the correct actions count in the nodes list ([#6183](https://github.com/n8n-io/n8n/issues/6183)) ([751e132](https://github.com/n8n-io/n8n/commit/751e132968470144cfca1c1b7ca22caf2c4c1de4))
+* **editor:** Update and add design system checkbox component to Editor ([#6178](https://github.com/n8n-io/n8n/issues/6178)) ([13c143e](https://github.com/n8n-io/n8n/commit/13c143eb6df41457fbd361674f2063b983a0e077))
+* **editor:** Update and fix storybook (was failing to run in local dev mode) ([#6180](https://github.com/n8n-io/n8n/issues/6180)) ([1e6a75f](https://github.com/n8n-io/n8n/commit/1e6a75f3416cdfcce1299dc9d242e23d0ea97ad3))
+* **FTP Node:** Use filename instead of remote filepath for downloaded binary data ([#6170](https://github.com/n8n-io/n8n/issues/6170)) ([be08933](https://github.com/n8n-io/n8n/commit/be089331b372e029ab5516b91e63a2d5d9033719))
+* **Google Sheets Node:** Upgrade xlsx to address CVE-2023-30533 ([#6172](https://github.com/n8n-io/n8n/issues/6172)) ([45dc985](https://github.com/n8n-io/n8n/commit/45dc985af742b049dc5673cf972da704d1f1f220))
+* **HTTP Request Node:** Correctly doesn't redirect on non GET method ([#6132](https://github.com/n8n-io/n8n/issues/6132)) ([3f5c606](https://github.com/n8n-io/n8n/commit/3f5c6062542f3b2b8a02cf0820e03da3f01d8bf2))
+* **MySQL Node:** Node should return date types as strings ([#6169](https://github.com/n8n-io/n8n/issues/6169)) ([5d77ec7](https://github.com/n8n-io/n8n/commit/5d77ec76e3c47fe9f9d7f31fe6c03827685ec576))
+* **Postgres Node:** Always return TIMESTAMP and TIMESTAMPZ as ISO string ([#6145](https://github.com/n8n-io/n8n/issues/6145)) ([0eb4d9f](https://github.com/n8n-io/n8n/commit/0eb4d9fc16aad1d1a350ba074c4b86712fbd90a1))
+* Prevent overflow when rendering expression hints ([#6214](https://github.com/n8n-io/n8n/issues/6214)) ([c717771](https://github.com/n8n-io/n8n/commit/c7177719e5f60813f4d15f7f97f1b4f253e29b07))
+* Prevent unnecessary error messages also for data loaded flag ([#6201](https://github.com/n8n-io/n8n/issues/6201)) ([d5e62ff](https://github.com/n8n-io/n8n/commit/d5e62ff096ddefd52dae742166fe92ceef17ded6))
+
+
+### Features
+
+* **Airtable Node:** Access token support ([#6160](https://github.com/n8n-io/n8n/issues/6160)) ([f9fd820](https://github.com/n8n-io/n8n/commit/f9fd82040ac09914a03e5b9f8f84fce5f6a99835))
+* **Code Node:** Add Python support ([#4295](https://github.com/n8n-io/n8n/issues/4295)) ([35c8510](https://github.com/n8n-io/n8n/commit/35c8510ab6d607fe59056a4aa1d8d148e194d12c))
+* **core:** Improve health check ([#6205](https://github.com/n8n-io/n8n/issues/6205)) ([9e7b9fb](https://github.com/n8n-io/n8n/commit/9e7b9fb443046c73135efb70d0d1894207125f66))
+* Create NPM node ([#6177](https://github.com/n8n-io/n8n/issues/6177)) ([f3bc6f1](https://github.com/n8n-io/n8n/commit/f3bc6f19b68f6bd4bd99614f60bd6833bd15813f))
+* **Date & Time Node:** Overhaul of the node ([#5904](https://github.com/n8n-io/n8n/issues/5904)) ([7d1d1f7](https://github.com/n8n-io/n8n/commit/7d1d1f7872163cecb468c317670da2d8b89a7651))
+* **HubSpot Node:** Overhaul the HubSpot Node ([#4337](https://github.com/n8n-io/n8n/issues/4337)) ([2913e67](https://github.com/n8n-io/n8n/commit/2913e676e639757cdf1a513ad35a7df0e494fa6f))
+* **JotForm Trigger Node:** Add support for hipaa-api.jotform.com ([#6171](https://github.com/n8n-io/n8n/issues/6171)) ([3074f42](https://github.com/n8n-io/n8n/commit/3074f42b3b98cf0dbdc13ad7b927d6b7fc726fab))
+* **Kafka Trigger Node:** Add non-parallel execution ([#6175](https://github.com/n8n-io/n8n/issues/6175)) ([814ea51](https://github.com/n8n-io/n8n/commit/814ea5185ce82e0a7687b41161602b45f92bee93))
+
+
+
# [0.227.0](https://github.com/n8n-io/n8n/compare/n8n@0.226.0...n8n@0.227.0) (2023-05-03)
diff --git a/cypress/e2e/14-mapping.cy.ts b/cypress/e2e/14-mapping.cy.ts
index 2a42998ec75a66..134deeb9fc3124 100644
--- a/cypress/e2e/14-mapping.cy.ts
+++ b/cypress/e2e/14-mapping.cy.ts
@@ -194,7 +194,7 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters
.inlineExpressionEditorInput()
- .should('have.text', `{{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input[0].count }}`);
+ .should('have.text', `{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input[0].count }}`);
ndv.getters.parameterExpressionPreview('value').should('not.exist');
ndv.actions.switchInputMode('Table');
@@ -203,7 +203,7 @@ describe('Data mapping', () => {
.inlineExpressionEditorInput()
.should(
'have.text',
- `{{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input[0].count }} {{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input }}`,
+ `{{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input[0].count }} {{ $('${SCHEDULE_TRIGGER_NODE_NAME}').item.json.input }}`,
);
ndv.actions.validateExpressionPreview('value', ' ');
@@ -311,12 +311,12 @@ describe('Data mapping', () => {
ndv.getters.parameterInput('keepOnlySet').find('input[type="text"]')
.should('exist')
.invoke('css', 'border')
- .then((border) => expect(border).to.include('1.5px dashed rgb(90, 76, 194)'));
+ .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('1.5px dashed rgb(90, 76, 194)'));
+ .then((border) => expect(border).to.include('dashed rgb(90, 76, 194)'));
});
});
diff --git a/package.json b/package.json
index f3117e3b155c5f..9fdba9cbc70bec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n",
- "version": "0.227.0",
+ "version": "0.228.0",
"private": true,
"homepage": "https://n8n.io",
"engines": {
@@ -41,6 +41,10 @@
"@ngneat/falso": "^6.1.0",
"@types/jest": "^29.5.0",
"@types/supertest": "^2.0.12",
+ "@vitejs/plugin-legacy": "^3.0.1",
+ "@vitejs/plugin-vue2": "^2.2.0",
+ "@vitest/coverage-c8": "^0.28.5",
+ "c8": "^7.12.0",
"cross-env": "^7.0.3",
"cypress": "^12.8.1",
"cypress-real-events": "^1.7.6",
@@ -60,7 +64,11 @@
"ts-jest": "^29.1.0",
"tsc-watch": "^6.0.0",
"turbo": "1.8.8",
- "typescript": "*"
+ "typescript": "*",
+ "vite": "^4.0.4",
+ "vitest": "^0.28.5",
+ "vue-template-compiler": "^2.7.14",
+ "vue-tsc": "^1.0.24"
},
"pnpm": {
"onlyBuiltDependencies": [
@@ -80,7 +88,6 @@
"tslib": "^2.5.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.3",
- "xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz",
"xml2js": "^0.5.0",
"cpy@8>globby": "^11.1.0",
"qqjs>globby": "^11.1.0"
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 39112605e2851d..a153189ba55526 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n",
- "version": "0.227.0",
+ "version": "0.228.0",
"description": "n8n Workflow Automation Tool",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
diff --git a/packages/cli/src/NodeTypes.ts b/packages/cli/src/NodeTypes.ts
index b2dfb4d2d8f660..8bb2335355df96 100644
--- a/packages/cli/src/NodeTypes.ts
+++ b/packages/cli/src/NodeTypes.ts
@@ -13,7 +13,9 @@ import { LoadNodesAndCredentials } from './LoadNodesAndCredentials';
@Service()
export class NodeTypes implements INodeTypes {
- constructor(private nodesAndCredentials: LoadNodesAndCredentials) {
+ constructor(private nodesAndCredentials: LoadNodesAndCredentials) {}
+
+ init() {
// Some nodeTypes need to get special parameters applied like the
// polling nodes the polling times
this.applySpecialNodeParameters();
diff --git a/packages/cli/src/commands/BaseCommand.ts b/packages/cli/src/commands/BaseCommand.ts
index e629458b91b1a2..2368918a5705d7 100644
--- a/packages/cli/src/commands/BaseCommand.ts
+++ b/packages/cli/src/commands/BaseCommand.ts
@@ -1,7 +1,6 @@
import { Command } from '@oclif/command';
import { ExitError } from '@oclif/errors';
import { Container } from 'typedi';
-import type { INodeTypes } from 'n8n-workflow';
import { LoggerProxy, ErrorReporterProxy as ErrorReporter, sleep } from 'n8n-workflow';
import type { IUserSettings } from 'n8n-core';
import { BinaryDataManager, UserSettings } from 'n8n-core';
@@ -31,7 +30,7 @@ export abstract class BaseCommand extends Command {
protected loadNodesAndCredentials: LoadNodesAndCredentials;
- protected nodeTypes: INodeTypes;
+ protected nodeTypes: NodeTypes;
protected userSettings: IUserSettings;
@@ -51,6 +50,7 @@ export abstract class BaseCommand extends Command {
this.loadNodesAndCredentials = Container.get(LoadNodesAndCredentials);
await this.loadNodesAndCredentials.init();
this.nodeTypes = Container.get(NodeTypes);
+ this.nodeTypes.init();
const credentialTypes = Container.get(CredentialTypes);
CredentialsOverwrites(credentialTypes);
diff --git a/packages/core/package.json b/packages/core/package.json
index 699e12149c62b9..5df23866e6fce2 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n-core",
- "version": "0.166.0",
+ "version": "0.167.0",
"description": "Core functionality of n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts
index 072105c76a6e8d..88411e4f93cbb3 100644
--- a/packages/core/src/WorkflowExecute.ts
+++ b/packages/core/src/WorkflowExecute.ts
@@ -199,10 +199,11 @@ export class WorkflowExecute {
if (node && pinData && pinData[node.name]) {
incomingData.push(pinData[node.name]);
} else {
- incomingData.push(
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- runData[connection.node][runIndex].data![connection.type][connection.index]!,
- );
+ const nodeIncomingData =
+ runData[connection.node][runIndex]?.data?.[connection.type][connection.index];
+ if (nodeIncomingData) {
+ incomingData.push(nodeIncomingData);
+ }
}
incomingSourceData.main.push({
diff --git a/packages/design-system/package.json b/packages/design-system/package.json
index 27e945f2198d8d..093fe2f94ba932 100644
--- a/packages/design-system/package.json
+++ b/packages/design-system/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n-design-system",
- "version": "0.63.0",
+ "version": "0.64.0",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
"author": {
@@ -36,7 +36,7 @@
"markdown-it-task-lists": "^2.1.1",
"vue": "^2.7.14",
"vue-typed-mixins": "^0.2.0",
- "xss": "^1.0.10"
+ "xss": "^1.0.14"
},
"devDependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.36",
@@ -55,25 +55,13 @@
"@types/markdown-it-emoji": "^2.0.2",
"@types/markdown-it-link-attributes": "^3.0.1",
"@types/sanitize-html": "^2.8.0",
- "@vitest/coverage-c8": "^0.28.5",
- "@vitejs/plugin-vue2": "^2.2.0",
"autoprefixer": "^10.4.13",
- "c8": "7.12.0",
"core-js": "^3.27.2",
"jsdom": "21.1.0",
- "node-notifier": "^10.0.1",
"sass": "^1.58.0",
"sass-loader": "^13.2.0",
"storybook": "^7.0.7",
- "storybook-addon-themes": "^6.1.0",
- "trim": "^1.0.1",
- "vite": "^4.0.4",
- "vitest": "^0.28.5",
- "vue-class-component": "^7.2.6",
- "vue-loader": "^15.10.1",
- "vue-property-decorator": "^9.1.2",
- "vue-template-compiler": "^2.7.14",
- "vue-tsc": "^1.0.24"
+ "storybook-addon-themes": "^6.1.0"
},
"dependencies": {
"element-ui": "~2.15.12",
diff --git a/packages/design-system/src/components/N8nColorPicker/ColorPicker.stories.ts b/packages/design-system/src/components/N8nColorPicker/ColorPicker.stories.ts
new file mode 100644
index 00000000000000..65ac0d6dfe561a
--- /dev/null
+++ b/packages/design-system/src/components/N8nColorPicker/ColorPicker.stories.ts
@@ -0,0 +1,59 @@
+import { action } from '@storybook/addon-actions';
+import type { StoryFn } from '@storybook/vue';
+import N8nColorPicker from './ColorPicker.vue';
+
+export default {
+ title: 'Atoms/ColorPicker',
+ component: N8nColorPicker,
+ argTypes: {
+ disabled: {
+ control: 'boolean',
+ },
+ size: {
+ control: 'select',
+ options: ['mini', 'small', 'medium', 'large'],
+ },
+ showAlpha: {
+ control: 'boolean',
+ },
+ colorFormat: {
+ control: 'select',
+ options: ['hsl', 'hsv', 'hex', 'rgb'],
+ },
+ popperClass: {
+ control: 'text',
+ },
+ predefine: {
+ control: 'array',
+ },
+ },
+};
+
+const methods = {
+ onChange: action('change'),
+ onActiveChange: action('active-change'),
+ onInput: action('input'),
+};
+
+const DefaultTemplate: StoryFn = (args, { argTypes }) => ({
+ props: Object.keys(argTypes),
+ components: {
+ N8nColorPicker,
+ },
+ data: () => ({
+ color: null,
+ }),
+ template:
+ '',
+ methods,
+});
+
+export const Default = DefaultTemplate.bind({});
+Default.args = {
+ disabled: false,
+ size: 'medium',
+ showAlpha: false,
+ colorFormat: '',
+ popperClass: '',
+ showInput: true,
+};
diff --git a/packages/design-system/src/components/N8nColorPicker/ColorPicker.vue b/packages/design-system/src/components/N8nColorPicker/ColorPicker.vue
new file mode 100644
index 00000000000000..5a52c6d109350c
--- /dev/null
+++ b/packages/design-system/src/components/N8nColorPicker/ColorPicker.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/design-system/src/components/N8nColorPicker/__tests__/ColorPicker.spec.ts b/packages/design-system/src/components/N8nColorPicker/__tests__/ColorPicker.spec.ts
new file mode 100644
index 00000000000000..0367928bc4bebc
--- /dev/null
+++ b/packages/design-system/src/components/N8nColorPicker/__tests__/ColorPicker.spec.ts
@@ -0,0 +1,16 @@
+import { render } from '@testing-library/vue';
+import N8nColorPicker from '../ColorPicker.vue';
+
+describe('components', () => {
+ describe('N8nColorPicker', () => {
+ it('should render with input', () => {
+ const { container } = render(N8nColorPicker);
+ expect(container).toMatchSnapshot();
+ });
+
+ it('should render without input', () => {
+ const { container } = render(N8nColorPicker, { props: { showInput: false } });
+ expect(container).toMatchSnapshot();
+ });
+ });
+});
diff --git a/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap b/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap
new file mode 100644
index 00000000000000..1e4756cfee7199
--- /dev/null
+++ b/packages/design-system/src/components/N8nColorPicker/__tests__/__snapshots__/ColorPicker.spec.ts.snap
@@ -0,0 +1,269 @@
+// Vitest Snapshot v1
+
+exports[`components > N8nColorPicker > should render with input 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`components > N8nColorPicker > should render without input 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/design-system/src/components/N8nColorPicker/index.ts b/packages/design-system/src/components/N8nColorPicker/index.ts
new file mode 100644
index 00000000000000..f9bdd8901d05ae
--- /dev/null
+++ b/packages/design-system/src/components/N8nColorPicker/index.ts
@@ -0,0 +1,3 @@
+import N8nColorPicker from './ColorPicker.vue';
+
+export default N8nColorPicker;
diff --git a/packages/design-system/src/components/index.ts b/packages/design-system/src/components/index.ts
index 32fdfd9e0cf7c6..3aa18cf0b100e8 100644
--- a/packages/design-system/src/components/index.ts
+++ b/packages/design-system/src/components/index.ts
@@ -48,3 +48,4 @@ export { default as N8nUsersList } from './N8nUsersList';
export { default as N8nResizeWrapper } from './N8nResizeWrapper';
export { default as N8nRecycleScroller } from './N8nRecycleScroller';
export { default as N8nCheckbox } from './N8nCheckbox';
+export { default as N8nColorPicker } from './N8nColorPicker';
diff --git a/packages/design-system/src/plugin.ts b/packages/design-system/src/plugin.ts
index 71d7ff4df772d8..2166c6dc371d37 100644
--- a/packages/design-system/src/plugin.ts
+++ b/packages/design-system/src/plugin.ts
@@ -51,6 +51,7 @@ import {
N8nResizeWrapper,
N8nRecycleScroller,
N8nCheckbox,
+ N8nColorPicker,
} from './components';
export const N8nPlugin: PluginObject<{}> = {
@@ -105,5 +106,6 @@ export const N8nPlugin: PluginObject<{}> = {
app.component('n8n-resize-wrapper', N8nResizeWrapper);
app.component('n8n-recycle-scroller', N8nRecycleScroller);
app.component('n8n-checkbox', N8nCheckbox);
+ app.component('n8n-color-picker', N8nColorPicker);
},
};
diff --git a/packages/design-system/vite.config.ts b/packages/design-system/vite.config.ts
index e742ba8aad1623..a1ae7d976a672a 100644
--- a/packages/design-system/vite.config.ts
+++ b/packages/design-system/vite.config.ts
@@ -43,7 +43,6 @@ export default mergeConfig(
coverage: {
provider: 'c8',
reporter: coverageReporters,
- include: ['src/**/*.ts'],
all: true,
},
css: {
diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json
index a2ce0bd8ecca1a..9a0fe5f96c2591 100644
--- a/packages/editor-ui/package.json
+++ b/packages/editor-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n-editor-ui",
- "version": "0.193.0",
+ "version": "0.194.0",
"description": "Workflow Editor UI for n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
@@ -57,7 +57,6 @@
"file-saver": "^2.0.2",
"flatted": "^3.2.4",
"humanize-duration": "^3.27.2",
- "jquery": "^3.4.1",
"jsonpath": "^1.1.1",
"lodash-es": "^4.17.21",
"luxon": "^3.3.0",
@@ -77,12 +76,10 @@
"vue-infinite-loading": "^2.4.5",
"vue-json-pretty": "1.9.3",
"vue-router": "^3.6.5",
- "vue-template-compiler": "^2.7.14",
"vue-typed-mixins": "^0.2.0",
- "vue2-boring-avatars": "0.3.4",
"vue2-teleport": "^1.0.1",
"vue2-touch-events": "^3.2.1",
- "xss": "^1.0.10"
+ "xss": "^1.0.14"
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
@@ -93,28 +90,12 @@
"@testing-library/vue": "^5.8.3",
"@types/canvas-confetti": "^1.6.0",
"@types/dateformat": "^3.0.0",
- "@types/express": "^4.17.6",
"@types/file-saver": "^2.0.1",
"@types/humanize-duration": "^3.27.1",
"@types/jsonpath": "^0.2.0",
"@types/lodash-es": "^4.17.6",
- "@types/lodash.camelcase": "^4.3.6",
- "@types/lodash.get": "^4.4.6",
- "@types/lodash.set": "^4.3.6",
"@types/luxon": "^3.2.0",
"@types/uuid": "^8.3.2",
- "@vitejs/plugin-legacy": "^3.0.1",
- "@vitejs/plugin-vue2": "^2.2.0",
- "@vitest/coverage-c8": "^0.28.5",
- "@volar-plugins/eslint": "^0.0.4",
- "c8": "^7.12.0",
- "jshint": "^2.9.7",
- "miragejs": "^0.1.47",
- "sass": "^1.55.0",
- "sass-loader": "^10.1.1",
- "string-template-parser": "^1.2.6",
- "vite": "4.0.4",
- "vitest": "^0.28.5",
- "vue-tsc": "^1.0.24"
+ "miragejs": "^0.1.47"
}
}
diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts
index c90e18da3a59e3..ee2365b8b81a03 100644
--- a/packages/editor-ui/src/Interface.ts
+++ b/packages/editor-ui/src/Interface.ts
@@ -587,6 +587,12 @@ export interface IVersionNotificationSettings {
infoUrl: string;
}
+export interface IUserListAction {
+ label: string;
+ value: string;
+ guard?: (user: IUser) => boolean;
+}
+
export interface IN8nPrompts {
message: string;
title: string;
@@ -1438,7 +1444,8 @@ export type VersionControlPreferences = {
repositoryUrl: string;
authorName: string;
authorEmail: string;
- branchName: string;
+ currentBranch: string;
+ branches: string[];
branchReadOnly: boolean;
branchColor: string;
publicKey?: string;
diff --git a/packages/editor-ui/src/components/ExpressionEdit.vue b/packages/editor-ui/src/components/ExpressionEdit.vue
index 0da57bbf2bd1e6..3b1e308aa5b0c8 100644
--- a/packages/editor-ui/src/components/ExpressionEdit.vue
+++ b/packages/editor-ui/src/components/ExpressionEdit.vue
@@ -181,21 +181,22 @@ export default mixins(externalHooks, genericHelpers, debounceHelper).extend({
trackProperties.variable_type = 'Raw value';
}
- if (splitVar[0].startsWith('$node')) {
- const sourceNodeName = splitVar[0].split('"')[1];
- trackProperties.node_type_source =
- this.workflowsStore.getNodeByName(sourceNodeName)?.type;
- const nodeConnections: Array> =
- this.workflowsStore.outgoingConnectionsByNodeName(sourceNodeName).main;
- trackProperties.is_immediate_input =
- nodeConnections &&
- nodeConnections[0] &&
- !!nodeConnections[0].find(({ node }) => node === this.ndvStore.activeNode?.name || '')
- ? true
- : false;
-
- if (splitVar[1].startsWith('parameter')) {
- trackProperties.parameter_name_source = splitVar[1].split('"')[1];
+ if (splitVar[0].startsWith("$('")) {
+ const match = /\$\('(.*?)'\)/.exec(splitVar[0]);
+ if (match && match.length > 1) {
+ const sourceNodeName = match[1];
+ trackProperties.node_type_source =
+ this.workflowsStore.getNodeByName(sourceNodeName)?.type;
+ const nodeConnections: Array> =
+ this.workflowsStore.outgoingConnectionsByNodeName(sourceNodeName).main;
+ trackProperties.is_immediate_input =
+ nodeConnections &&
+ nodeConnections[0] &&
+ nodeConnections[0].some(({ node }) => node === this.ndvStore.activeNode?.name || '');
+
+ if (splitVar[1].startsWith('parameter')) {
+ trackProperties.parameter_name_source = splitVar[1].split('"')[1];
+ }
}
} else {
trackProperties.is_immediate_input = true;
diff --git a/packages/editor-ui/src/components/VariableSelector.vue b/packages/editor-ui/src/components/VariableSelector.vue
index 1c2fa1f9ce3627..f200fc89ddd3b9 100644
--- a/packages/editor-ui/src/components/VariableSelector.vue
+++ b/packages/editor-ui/src/components/VariableSelector.vue
@@ -290,7 +290,7 @@ export default mixins(workflowHelpers).extend({
* @param {number} [runIndex=0] The index of the run
* @param {string} [inputName='main'] The name of the input
* @param {number} [outputIndex=0] The index of the output
- * @param {boolean} [useShort=false] Use short notation $json vs. $node[NodeName].json
+ * @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
*/
getNodeRunDataOutput(
nodeName: string,
@@ -351,7 +351,7 @@ export default mixins(workflowHelpers).extend({
* @param {string} nodeName The name of the node to get the data of
* @param {IPinData[string]} pinData The node's pin data
* @param {string} filterText Filter text for parameters
- * @param {boolean} [useShort=false] Use short notation $json vs. $node[NodeName].json
+ * @param {boolean} [useShort=false] Use short notation $json vs. $('NodeName').json
*/
getNodePinDataOutput(
nodeName: string,
@@ -382,7 +382,7 @@ export default mixins(workflowHelpers).extend({
// Get json data
if (outputData.hasOwnProperty('json')) {
- const jsonPropertyPrefix = useShort === true ? '$json' : `$node["${nodeName}"].json`;
+ const jsonPropertyPrefix = useShort === true ? '$json' : `$('${nodeName}').item.json`;
const jsonDataOptions: IVariableSelectorOption[] = [];
for (const propertyName of Object.keys(outputData.json)) {
@@ -407,7 +407,7 @@ export default mixins(workflowHelpers).extend({
// Get binary data
if (outputData.hasOwnProperty('binary')) {
- const binaryPropertyPrefix = useShort === true ? '$binary' : `$node["${nodeName}"].binary`;
+ const binaryPropertyPrefix = useShort === true ? '$binary' : `$('${nodeName}').item.binary`;
const binaryData = [];
let binaryPropertyData = [];
@@ -523,7 +523,7 @@ export default mixins(workflowHelpers).extend({
returnData.push({
name: key,
- key: `$node["${nodeName}"].context["${key}"]`,
+ key: `$('${nodeName}').context["${key}"]`,
// @ts-ignore
value: nodeContext[key],
});
@@ -604,6 +604,7 @@ export default mixins(workflowHelpers).extend({
const currentNodeData: IVariableSelectorOption[] = [];
let tempOptions: IVariableSelectorOption[];
+
if (executionData !== null && executionData.data !== undefined) {
const runExecutionData: IRunExecutionData = executionData.data;
@@ -774,12 +775,7 @@ export default mixins(workflowHelpers).extend({
{
name: this.$locale.baseText('variableSelector.parameters'),
options: this.sortOptions(
- this.getNodeParameters(
- nodeName,
- `$node["${nodeName}"].parameter`,
- undefined,
- filterText,
- ),
+ this.getNodeParameters(nodeName, `$('${nodeName}').params`, undefined, filterText),
),
} as IVariableSelectorOption,
];
diff --git a/packages/editor-ui/src/components/__tests__/__snapshots__/RunDataJson.test.ts.snap b/packages/editor-ui/src/components/__tests__/__snapshots__/RunDataJson.test.ts.snap
index e7f97d56767c8c..a0116bd5ec97c5 100644
--- a/packages/editor-ui/src/components/__tests__/__snapshots__/RunDataJson.test.ts.snap
+++ b/packages/editor-ui/src/components/__tests__/__snapshots__/RunDataJson.test.ts.snap
@@ -94,7 +94,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="list"
data-path="[0].list"
data-target="mappable"
- data-value="{{ $node.Set.json.list }}"
+ data-value="{{ $('Set').item.json.list }}"
>
"list"
@@ -143,7 +143,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="list[0]"
data-path="[0].list[0]"
data-target="mappable"
- data-value="{{ $node.Set.json.list[0] }}"
+ data-value="{{ $('Set').item.json.list[0] }}"
>
1
@@ -185,7 +185,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="list[1]"
data-path="[0].list[1]"
data-target="mappable"
- data-value="{{ $node.Set.json.list[1] }}"
+ data-value="{{ $('Set').item.json.list[1] }}"
>
2
@@ -227,7 +227,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="list[2]"
data-path="[0].list[2]"
data-target="mappable"
- data-value="{{ $node.Set.json.list[2] }}"
+ data-value="{{ $('Set').item.json.list[2] }}"
>
3
@@ -292,7 +292,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="record"
data-path="[0].record"
data-target="mappable"
- data-value="{{ $node.Set.json.record }}"
+ data-value="{{ $('Set').item.json.record }}"
>
"record"
@@ -339,7 +339,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="name"
data-path="[0].record.name"
data-target="mappable"
- data-value="{{ $node.Set.json.record.name }}"
+ data-value="{{ $('Set').item.json.record.name }}"
>
"name"
@@ -417,7 +417,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="myNumber"
data-path="[0].myNumber"
data-target="mappable"
- data-value="{{ $node.Set.json.myNumber }}"
+ data-value="{{ $('Set').item.json.myNumber }}"
>
"myNumber"
@@ -467,7 +467,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="myStringNumber"
data-path="[0].myStringNumber"
data-target="mappable"
- data-value="{{ $node.Set.json.myStringNumber }}"
+ data-value="{{ $('Set').item.json.myStringNumber }}"
>
"myStringNumber"
@@ -517,7 +517,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="myStringText"
data-path="[0].myStringText"
data-target="mappable"
- data-value="{{ $node.Set.json.myStringText }}"
+ data-value="{{ $('Set').item.json.myStringText }}"
>
"myStringText"
@@ -567,7 +567,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="nil"
data-path="[0].nil"
data-target="mappable"
- data-value="{{ $node.Set.json.nil }}"
+ data-value="{{ $('Set').item.json.nil }}"
>
"nil"
@@ -617,7 +617,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
data-name="d"
data-path="[0].d"
data-target="mappable"
- data-value="{{ $node.Set.json.d }}"
+ data-value="{{ $('Set').item.json.d }}"
>
"d"
diff --git a/packages/editor-ui/src/plugins/i18n/docs/README.md b/packages/editor-ui/src/plugins/i18n/docs/README.md
index 344ae7ab572262..664c3e1a2f6963 100644
--- a/packages/editor-ui/src/plugins/i18n/docs/README.md
+++ b/packages/editor-ui/src/plugins/i18n/docs/README.md
@@ -507,3 +507,4 @@ After changing the dynamic text file:
If a `headerText` section was changed, re-run `pnpm build:translations` in `/nodes-base`.
> **Note**: To translate base and dynamic text simultaneously, run three terminals following the steps from both sections (first terminal running only once) and browse `http://localhost:8080`.
+
diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json
index 64dce45c60d7cf..b398af6c24e390 100644
--- a/packages/editor-ui/src/plugins/i18n/locales/en.json
+++ b/packages/editor-ui/src/plugins/i18n/locales/en.json
@@ -1290,18 +1290,26 @@
"settings.versionControl.actionBox.title": "Available on Enterprise plan",
"settings.versionControl.actionBox.description": "Use Version Control to connect your instance to an external Git repository to backup and track changes made to your workflows, variables, and credentials. With Version Control you can also sync instances across multiple environments (development, production...).",
"settings.versionControl.actionBox.buttonText": "See plans",
- "settings.versionControl.description": "Versioning allows you to connect your n8n instance to a Git branch of a repository. You can connect your branches to multiples n8n instances to create a multi environments setup. Learn how to set up versioning and environments in n8n.",
- "settings.versionControl.repoUrl": "Git repository URL",
+ "settings.versionControl.description": "Versioning allows you to connect your n8n instance to a Git branch of a repository. You can connect your branches to multiples n8n instances to create a multi environments setup. {link}",
+ "settings.versionControl.description.link": "Learn how to set up versioning and environments in n8n.",
+ "settings.versionControl.gitConfig": "Git configuration",
+ "settings.versionControl.repoUrl": "Git repository URL (SSH)",
"settings.versionControl.repoUrlPlaceholder": "e.g. git@github.com:my-team/my-repository",
"settings.versionControl.repoUrlDescription": "The SSH url of your Git repository",
- "settings.versionControl.authorName": "Author name",
- "settings.versionControl.authorEmail": "Author email",
+ "settings.versionControl.authorName": "Commit author name",
+ "settings.versionControl.authorEmail": "Commit author email",
"settings.versionControl.sshKey": "SSH Key",
"settings.versionControl.sshKeyDescription": "Paste the SSH key in yout git repository settings. {link}.",
"settings.versionControl.sshKeyDescriptionLink": "More info.",
"settings.versionControl.button.continue": "Continue",
"settings.versionControl.button.connect": "Connect",
- "settings.versionControl.branches": "Select branch",
+ "settings.versionControl.button.save": "Save settings",
+ "settings.versionControl.instanceSettings": "Instance settings",
+ "settings.versionControl.branches": "Branch connected to this n8n instance",
+ "settings.versionControl.readonly": "{bold}: prevent editing workflows (recommended for production environments). {link}",
+ "settings.versionControl.readonly.bold": "Read-only instance",
+ "settings.versionControl.readonly.link": "Learn more.",
+ "settings.versionControl.color": "Color",
"settings.versionControl.switchBranch.title": "Switch to {branch} branch",
"settings.versionControl.switchBranch.description": "Please confirm you want to switch the current n8n instance to the branch: {branch}",
"settings.versionControl.sync.prompt.title": "Sync changes in {branch} branch",
diff --git a/packages/editor-ui/src/stores/versionControl.store.ts b/packages/editor-ui/src/stores/versionControl.store.ts
index 6cc0da32db091c..81983643217d23 100644
--- a/packages/editor-ui/src/stores/versionControl.store.ts
+++ b/packages/editor-ui/src/stores/versionControl.store.ts
@@ -16,12 +16,13 @@ export const useVersionControlStore = defineStore('versionControl', () => {
);
const preferences = reactive({
- branchName: '',
+ currentBranch: '',
+ branches: [],
authorName: '',
authorEmail: '',
repositoryUrl: '',
branchReadOnly: false,
- branchColor: '#000000',
+ branchColor: '#F4A6DC',
connected: false,
publicKey: '',
});
@@ -77,6 +78,7 @@ export const useVersionControlStore = defineStore('versionControl', () => {
return {
isEnterpriseVersionControlEnabled,
state,
+ preferences,
initSsh,
initRepository,
sync,
diff --git a/packages/editor-ui/src/utils/__tests__/mappingUtils.test.ts b/packages/editor-ui/src/utils/__tests__/mappingUtils.test.ts
index 51862efecab619..a46912c5e7963b 100644
--- a/packages/editor-ui/src/utils/__tests__/mappingUtils.test.ts
+++ b/packages/editor-ui/src/utils/__tests__/mappingUtils.test.ts
@@ -207,7 +207,7 @@ describe('Mapping Utils', () => {
path: ['sample', 'path'],
};
const result = getMappedExpression(input);
- expect(result).toBe('{{ $node.nodeName.json.sample.path }}');
+ expect(result).toBe("{{ $('nodeName').item.json.sample.path }}");
});
it('should generate a mapped expression with mixed array path', () => {
@@ -217,7 +217,7 @@ describe('Mapping Utils', () => {
path: ['sample', 0, 'path'],
};
const result = getMappedExpression(input);
- expect(result).toBe('{{ $node.nodeName.json.sample[0].path }}');
+ expect(result).toBe("{{ $('nodeName').item.json.sample[0].path }}");
});
it('should generate a mapped expression with special characters in array path', () => {
@@ -228,7 +228,7 @@ describe('Mapping Utils', () => {
};
const result = getMappedExpression(input);
expect(result).toBe(
- "{{ $node.nodeName.json.sample['path with-space']['path-with-hyphen'] }}",
+ "{{ $('nodeName').item.json.sample['path with-space']['path-with-hyphen'] }}",
);
});
@@ -251,7 +251,7 @@ describe('Mapping Utils', () => {
};
const result = getMappedExpression(input);
expect(result).toBe(
- "{{ $node.nodeName.json.sample['\"Execute\"']['`Execute`']['\\'Execute\\'']['[Execute]']['{Execute}']['execute?']['test,']['test:']['path.'] }}",
+ "{{ $('nodeName').item.json.sample['\"Execute\"']['`Execute`']['\\'Execute\\'']['[Execute]']['{Execute}']['execute?']['test,']['test:']['path.'] }}",
);
});
diff --git a/packages/editor-ui/src/utils/mappingUtils.ts b/packages/editor-ui/src/utils/mappingUtils.ts
index 47adeffdec2282..2591c3bf337021 100644
--- a/packages/editor-ui/src/utils/mappingUtils.ts
+++ b/packages/editor-ui/src/utils/mappingUtils.ts
@@ -27,7 +27,8 @@ export function getMappedExpression({
distanceFromActive: number;
path: Array | string;
}) {
- const root = distanceFromActive === 1 ? '$json' : generatePath('$node', [nodeName, 'json']);
+ const root =
+ distanceFromActive === 1 ? '$json' : generatePath(`$('${nodeName}')`, ['item', 'json']);
if (typeof path === 'string') {
return `{{ ${root}${path} }}`;
diff --git a/packages/editor-ui/src/views/SettingsVersionControl.vue b/packages/editor-ui/src/views/SettingsVersionControl.vue
index ca1971b1aa057d..bb5ca35247c1bd 100644
--- a/packages/editor-ui/src/views/SettingsVersionControl.vue
+++ b/packages/editor-ui/src/views/SettingsVersionControl.vue
@@ -1,19 +1,14 @@