mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(editor): update expressions display (#4171)
* N8n 4673 expressions res1 (#4149) * hide hints if necessary * refactor out parameter input * refactor param input in creds * remove any * add expression result before * update case * add types * fix spacing * update types * update expr * update parameter input * update param input * update param input * remove import * fix typo * update value * fix drop for rl * add state to track hovering item * add hover behavior to resolve values * update index * fix run selector bug * add run item to eval expr * add paired item mappings * fix rec bug * Fix for loops * handle pinned data * add missing pinned * fix bug * support parent * add input * map back from output * clean up * fix output bug * fix branching bug * update preview * only if expr * fix output * fix expr eval for outputs * add default hover state * fix hover state * fix branching * hide hint if expr * remove duplicate logic * update style * allow opening expr in demo * update expr * update row hover * update param name * clean up * update hovering state * update default output * fix duplicate import * update hover behavior * update package lock * fix pinned data case * address case when no input
This commit is contained in:
106
package-lock.json
generated
106
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n",
|
"name": "n8n",
|
||||||
"version": "0.196.0",
|
"version": "0.197.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "n8n",
|
"name": "n8n",
|
||||||
"version": "0.196.0",
|
"version": "0.197.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
@@ -43257,7 +43257,7 @@
|
|||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
"name": "n8n",
|
"name": "n8n",
|
||||||
"version": "0.196.0",
|
"version": "0.197.1",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oclif/command": "^1.5.18",
|
"@oclif/command": "^1.5.18",
|
||||||
@@ -43303,10 +43303,10 @@
|
|||||||
"lodash.split": "^4.4.2",
|
"lodash.split": "^4.4.2",
|
||||||
"lodash.unset": "^4.5.2",
|
"lodash.unset": "^4.5.2",
|
||||||
"mysql2": "~2.3.0",
|
"mysql2": "~2.3.0",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"n8n-editor-ui": "~0.162.0",
|
"n8n-editor-ui": "~0.163.1",
|
||||||
"n8n-nodes-base": "~0.194.0",
|
"n8n-nodes-base": "~0.195.1",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"nodemailer": "^6.7.1",
|
"nodemailer": "^6.7.1",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"open": "^7.0.0",
|
"open": "^7.0.0",
|
||||||
@@ -44453,7 +44453,7 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "n8n-core",
|
"name": "n8n-core",
|
||||||
"version": "0.136.0",
|
"version": "0.137.0",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
@@ -44465,7 +44465,7 @@
|
|||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"mime-types": "^2.1.27",
|
"mime-types": "^2.1.27",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"p-cancelable": "^2.0.0",
|
"p-cancelable": "^2.0.0",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.1",
|
||||||
@@ -45521,7 +45521,7 @@
|
|||||||
},
|
},
|
||||||
"packages/design-system": {
|
"packages/design-system": {
|
||||||
"name": "n8n-design-system",
|
"name": "n8n-design-system",
|
||||||
"version": "0.36.0",
|
"version": "0.37.0",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"element-ui": "~2.15.7",
|
"element-ui": "~2.15.7",
|
||||||
@@ -45704,7 +45704,7 @@
|
|||||||
},
|
},
|
||||||
"packages/editor-ui": {
|
"packages/editor-ui": {
|
||||||
"name": "n8n-editor-ui",
|
"name": "n8n-editor-ui",
|
||||||
"version": "0.162.0",
|
"version": "0.163.1",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/open-sans": "^4.5.0",
|
"@fontsource/open-sans": "^4.5.0",
|
||||||
@@ -45728,8 +45728,8 @@
|
|||||||
"lodash.set": "^4.3.2",
|
"lodash.set": "^4.3.2",
|
||||||
"luxon": "^2.3.0",
|
"luxon": "^2.3.0",
|
||||||
"monaco-editor": "^0.30.1",
|
"monaco-editor": "^0.30.1",
|
||||||
"n8n-design-system": "~0.36.0",
|
"n8n-design-system": "~0.37.0",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"normalize-wheel": "^1.0.1",
|
"normalize-wheel": "^1.0.1",
|
||||||
"prismjs": "^1.17.1",
|
"prismjs": "^1.17.1",
|
||||||
"quill": "2.0.0-dev.4",
|
"quill": "2.0.0-dev.4",
|
||||||
@@ -46156,7 +46156,7 @@
|
|||||||
},
|
},
|
||||||
"packages/node-dev": {
|
"packages/node-dev": {
|
||||||
"name": "n8n-node-dev",
|
"name": "n8n-node-dev",
|
||||||
"version": "0.75.0",
|
"version": "0.76.0",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oclif/command": "^1.5.18",
|
"@oclif/command": "^1.5.18",
|
||||||
@@ -46164,8 +46164,8 @@
|
|||||||
"change-case": "^4.1.1",
|
"change-case": "^4.1.1",
|
||||||
"fast-glob": "^3.2.5",
|
"fast-glob": "^3.2.5",
|
||||||
"inquirer": "^7.0.1",
|
"inquirer": "^7.0.1",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"replace-in-file": "^6.0.0",
|
"replace-in-file": "^6.0.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
@@ -46185,21 +46185,9 @@
|
|||||||
"@types/vorpal": "^1.11.0"
|
"@types/vorpal": "^1.11.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/node-dev/node_modules/typescript": {
|
|
||||||
"version": "4.6.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
|
||||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"packages/nodes-base": {
|
"packages/nodes-base": {
|
||||||
"name": "n8n-nodes-base",
|
"name": "n8n-nodes-base",
|
||||||
"version": "0.194.0",
|
"version": "0.195.1",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kafkajs/confluent-schema-registry": "1.0.6",
|
"@kafkajs/confluent-schema-registry": "1.0.6",
|
||||||
@@ -46237,7 +46225,7 @@
|
|||||||
"mqtt": "4.2.6",
|
"mqtt": "4.2.6",
|
||||||
"mssql": "^8.1.2",
|
"mssql": "^8.1.2",
|
||||||
"mysql2": "~2.3.0",
|
"mysql2": "~2.3.0",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"node-html-markdown": "^1.1.3",
|
"node-html-markdown": "^1.1.3",
|
||||||
"node-ssh": "^12.0.0",
|
"node-ssh": "^12.0.0",
|
||||||
"nodemailer": "^6.7.1",
|
"nodemailer": "^6.7.1",
|
||||||
@@ -46292,7 +46280,7 @@
|
|||||||
"eslint-plugin-n8n-nodes-base": "^1.9.3",
|
"eslint-plugin-n8n-nodes-base": "^1.9.3",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.0",
|
||||||
"jest": "^27.4.7",
|
"jest": "^27.4.7",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"ts-jest": "^27.1.3",
|
"ts-jest": "^27.1.3",
|
||||||
"tslint": "^6.1.2",
|
"tslint": "^6.1.2",
|
||||||
"typescript": "~4.8.0"
|
"typescript": "~4.8.0"
|
||||||
@@ -47329,7 +47317,7 @@
|
|||||||
},
|
},
|
||||||
"packages/workflow": {
|
"packages/workflow": {
|
||||||
"name": "n8n-workflow",
|
"name": "n8n-workflow",
|
||||||
"version": "0.118.0",
|
"version": "0.119.0",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@n8n_io/riot-tmpl": "^1.0.1",
|
"@n8n_io/riot-tmpl": "^1.0.1",
|
||||||
@@ -52127,7 +52115,7 @@
|
|||||||
"@oclif/errors": "^1.3.5",
|
"@oclif/errors": "^1.3.5",
|
||||||
"@oclif/parser": "^3.8.0",
|
"@oclif/parser": "^3.8.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.1",
|
||||||
"is-wsl": "^2.1.1",
|
"is-wsl": "^2.1.1",
|
||||||
"tslib": "^2.3.1"
|
"tslib": "^2.3.1"
|
||||||
},
|
},
|
||||||
@@ -52153,10 +52141,10 @@
|
|||||||
"clean-stack": "^3.0.1",
|
"clean-stack": "^3.0.1",
|
||||||
"cli-progress": "^3.10.0",
|
"cli-progress": "^3.10.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ejs": "^3.1.8",
|
"ejs": "^3.1.6",
|
||||||
"fs-extra": "^9.1.0",
|
"fs-extra": "^9.1.0",
|
||||||
"get-package-type": "^0.1.0",
|
"get-package-type": "^0.1.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.1.0",
|
||||||
"hyperlinker": "^1.0.0",
|
"hyperlinker": "^1.0.0",
|
||||||
"indent-string": "^4.0.0",
|
"indent-string": "^4.0.0",
|
||||||
"is-wsl": "^2.2.0",
|
"is-wsl": "^2.2.0",
|
||||||
@@ -52368,7 +52356,7 @@
|
|||||||
"@oclif/errors": "^1.3.3",
|
"@oclif/errors": "^1.3.3",
|
||||||
"@oclif/parser": "^3.8.0",
|
"@oclif/parser": "^3.8.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.1",
|
||||||
"is-wsl": "^2.1.1",
|
"is-wsl": "^2.1.1",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -52561,7 +52549,7 @@
|
|||||||
"@oclif/errors": "^1.3.3",
|
"@oclif/errors": "^1.3.3",
|
||||||
"@oclif/parser": "^3.8.0",
|
"@oclif/parser": "^3.8.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.1",
|
||||||
"is-wsl": "^2.1.1",
|
"is-wsl": "^2.1.1",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -53067,7 +53055,7 @@
|
|||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"find-up": "^5.0.0",
|
"find-up": "^5.0.0",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.0.4",
|
"fork-ts-checker-webpack-plugin": "^4.1.6",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"glob-promise": "^3.4.0",
|
"glob-promise": "^3.4.0",
|
||||||
"global": "^4.4.0",
|
"global": "^4.4.0",
|
||||||
@@ -55589,7 +55577,7 @@
|
|||||||
"@typescript-eslint/types": "5.38.1",
|
"@typescript-eslint/types": "5.38.1",
|
||||||
"@typescript-eslint/visitor-keys": "5.38.1",
|
"@typescript-eslint/visitor-keys": "5.38.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.3.7",
|
||||||
"tsutils": "^3.21.0"
|
"tsutils": "^3.21.0"
|
||||||
@@ -56959,7 +56947,7 @@
|
|||||||
"integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==",
|
"integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "^4.21.3",
|
"browserslist": "^4.12.0",
|
||||||
"caniuse-lite": "^1.0.30001109",
|
"caniuse-lite": "^1.0.30001109",
|
||||||
"normalize-range": "^0.1.2",
|
"normalize-range": "^0.1.2",
|
||||||
"num2fraction": "^1.2.2",
|
"num2fraction": "^1.2.2",
|
||||||
@@ -59784,7 +59772,7 @@
|
|||||||
"integrity": "sha512-xVtYpJQ5grszDHEUU9O7XbjjcZ0ccX3LgQsyqSvTnjX97ZqEgn9F5srmrwwwMtbKzDllyFPL+O+2OFMl1lU4TQ==",
|
"integrity": "sha512-xVtYpJQ5grszDHEUU9O7XbjjcZ0ccX3LgQsyqSvTnjX97ZqEgn9F5srmrwwwMtbKzDllyFPL+O+2OFMl1lU4TQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "^4.21.3"
|
"browserslist": "^4.21.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"core-js-pure": {
|
"core-js-pure": {
|
||||||
@@ -59858,7 +59846,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"arrify": "^2.0.1",
|
"arrify": "^2.0.1",
|
||||||
"cp-file": "^7.0.0",
|
"cp-file": "^7.0.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^9.2.0",
|
||||||
"has-glob": "^1.0.0",
|
"has-glob": "^1.0.0",
|
||||||
"junk": "^3.1.0",
|
"junk": "^3.1.0",
|
||||||
"nested-error-stacks": "^2.1.0",
|
"nested-error-stacks": "^2.1.0",
|
||||||
@@ -61462,7 +61450,7 @@
|
|||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
"glob-parent": "^6.0.1",
|
"glob-parent": "^6.0.1",
|
||||||
"globals": "^13.15.0",
|
"globals": "^13.15.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.1.0",
|
||||||
"grapheme-splitter": "^1.0.4",
|
"grapheme-splitter": "^1.0.4",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.0.0",
|
"import-fresh": "^3.0.0",
|
||||||
@@ -71914,10 +71902,10 @@
|
|||||||
"lodash.split": "^4.4.2",
|
"lodash.split": "^4.4.2",
|
||||||
"lodash.unset": "^4.5.2",
|
"lodash.unset": "^4.5.2",
|
||||||
"mysql2": "~2.3.0",
|
"mysql2": "~2.3.0",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"n8n-editor-ui": "~0.162.0",
|
"n8n-editor-ui": "~0.163.1",
|
||||||
"n8n-nodes-base": "~0.194.0",
|
"n8n-nodes-base": "~0.195.1",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"nodemailer": "^6.7.1",
|
"nodemailer": "^6.7.1",
|
||||||
"nodemon": "^2.0.2",
|
"nodemon": "^2.0.2",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
@@ -72807,7 +72795,7 @@
|
|||||||
"jest": "^27.4.7",
|
"jest": "^27.4.7",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"mime-types": "^2.1.27",
|
"mime-types": "^2.1.27",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"p-cancelable": "^2.0.0",
|
"p-cancelable": "^2.0.0",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.1",
|
||||||
@@ -73791,8 +73779,8 @@
|
|||||||
"lodash.set": "^4.3.2",
|
"lodash.set": "^4.3.2",
|
||||||
"luxon": "^2.3.0",
|
"luxon": "^2.3.0",
|
||||||
"monaco-editor": "^0.30.1",
|
"monaco-editor": "^0.30.1",
|
||||||
"n8n-design-system": "~0.36.0",
|
"n8n-design-system": "~0.37.0",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"normalize-wheel": "^1.0.1",
|
"normalize-wheel": "^1.0.1",
|
||||||
"prismjs": "^1.17.1",
|
"prismjs": "^1.17.1",
|
||||||
"quill": "2.0.0-dev.4",
|
"quill": "2.0.0-dev.4",
|
||||||
@@ -74109,19 +74097,13 @@
|
|||||||
"change-case": "^4.1.1",
|
"change-case": "^4.1.1",
|
||||||
"fast-glob": "^3.2.5",
|
"fast-glob": "^3.2.5",
|
||||||
"inquirer": "^7.0.1",
|
"inquirer": "^7.0.1",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"replace-in-file": "^6.0.0",
|
"replace-in-file": "^6.0.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"tmp-promise": "^3.0.2",
|
"tmp-promise": "^3.0.2",
|
||||||
"typescript": "~4.8.0"
|
"typescript": "~4.8.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"typescript": {
|
|
||||||
"version": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
|
||||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"n8n-nodes-base": {
|
"n8n-nodes-base": {
|
||||||
@@ -74194,8 +74176,8 @@
|
|||||||
"mqtt": "4.2.6",
|
"mqtt": "4.2.6",
|
||||||
"mssql": "^8.1.2",
|
"mssql": "^8.1.2",
|
||||||
"mysql2": "~2.3.0",
|
"mysql2": "~2.3.0",
|
||||||
"n8n-core": "~0.136.0",
|
"n8n-core": "~0.137.0",
|
||||||
"n8n-workflow": "~0.118.0",
|
"n8n-workflow": "~0.119.0",
|
||||||
"node-html-markdown": "^1.1.3",
|
"node-html-markdown": "^1.1.3",
|
||||||
"node-ssh": "^12.0.0",
|
"node-ssh": "^12.0.0",
|
||||||
"nodemailer": "^6.7.1",
|
"nodemailer": "^6.7.1",
|
||||||
@@ -78476,7 +78458,7 @@
|
|||||||
"fs-extra": "^6.0.1",
|
"fs-extra": "^6.0.1",
|
||||||
"get-stream": "^5.1.0",
|
"get-stream": "^5.1.0",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"globby": "^11.0.2",
|
"globby": "^10.0.1",
|
||||||
"http-call": "^5.1.2",
|
"http-call": "^5.1.2",
|
||||||
"load-json-file": "^6.2.0",
|
"load-json-file": "^6.2.0",
|
||||||
"pkg-dir": "^4.2.0",
|
"pkg-dir": "^4.2.0",
|
||||||
@@ -84173,7 +84155,7 @@
|
|||||||
"consola": "^2.15.3",
|
"consola": "^2.15.3",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"dotenv-expand": "^8.0.2",
|
"dotenv-expand": "^8.0.2",
|
||||||
"ejs": "^3.1.8",
|
"ejs": "^3.1.6",
|
||||||
"fast-glob": "^3.2.11",
|
"fast-glob": "^3.2.11",
|
||||||
"fs-extra": "^10.0.1",
|
"fs-extra": "^10.0.1",
|
||||||
"html-minifier-terser": "^6.1.0",
|
"html-minifier-terser": "^6.1.0",
|
||||||
|
|||||||
@@ -72,33 +72,34 @@
|
|||||||
var(--color-secondary-l)
|
var(--color-secondary-l)
|
||||||
);
|
);
|
||||||
|
|
||||||
--color-secondary-tint-1-h: 247;
|
|
||||||
--color-secondary-tint-1-s: 49%;
|
|
||||||
--color-secondary-tint-1-l: 85%;
|
--color-secondary-tint-1-l: 85%;
|
||||||
--color-secondary-tint-1: hsl(
|
--color-secondary-tint-1: hsl(
|
||||||
var(--color-secondary-tint-1-h),
|
var(--color-secondary-h),
|
||||||
var(--color-secondary-tint-1-s),
|
var(--color-secondary-s),
|
||||||
var(--color-secondary-tint-1-l)
|
var(--color-secondary-tint-1-l)
|
||||||
);
|
);
|
||||||
|
|
||||||
--color-secondary-tint-2-h: 247;
|
|
||||||
--color-secondary-tint-2-s: 49%;
|
|
||||||
--color-secondary-tint-2-l: 92%;
|
--color-secondary-tint-2-l: 92%;
|
||||||
--color-secondary-tint-2: hsl(
|
--color-secondary-tint-2: hsl(
|
||||||
var(--color-secondary-tint-2-h),
|
var(--color-secondary-h),
|
||||||
var(--color-secondary-tint-2-s),
|
var(--color-secondary-s),
|
||||||
var(--color-secondary-tint-2-l)
|
var(--color-secondary-tint-2-l)
|
||||||
);
|
);
|
||||||
|
|
||||||
--color-secondary-tint-3-h: 247;
|
|
||||||
--color-secondary-tint-3-s: 49%;
|
|
||||||
--color-secondary-tint-3-l: 95%;
|
--color-secondary-tint-3-l: 95%;
|
||||||
--color-secondary-tint-3: hsl(
|
--color-secondary-tint-3: hsl(
|
||||||
var(--color-secondary-tint-3-h),
|
var(--color-secondary-h),
|
||||||
var(--color-secondary-tint-3-s),
|
var(--color-secondary-s),
|
||||||
var(--color-secondary-tint-3-l)
|
var(--color-secondary-tint-3-l)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
--color-secondary-tint-4-l: 98%;
|
||||||
|
--color-secondary-tint-4: hsl(
|
||||||
|
var(--color-secondary-h),
|
||||||
|
var(--color-secondary-s),
|
||||||
|
var(--color-secondary-tint-4-l)
|
||||||
|
);
|
||||||
|
|
||||||
--color-success-h: 150.4;
|
--color-success-h: 150.4;
|
||||||
--color-success-s: 60%;
|
--color-success-s: 60%;
|
||||||
--color-success-l: 40.4%;
|
--color-success-l: 40.4%;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import ColorCircles from './ColorCircles.vue';
|
|||||||
<Canvas>
|
<Canvas>
|
||||||
<Story name="secondary">
|
<Story name="secondary">
|
||||||
{{
|
{{
|
||||||
template: `<color-circles :colors="['--color-secondary', '--color-secondary-tint-1', '--color-secondary-tint-2']" />`,
|
template: `<color-circles :colors="['--color-secondary', '--color-secondary-tint-1', '--color-secondary-tint-2', '--color-secondary-tint-3', '--color-secondary-tint-4']" />`,
|
||||||
components: {
|
components: {
|
||||||
ColorCircles,
|
ColorCircles,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -212,11 +212,6 @@ export interface IStartRunData {
|
|||||||
pinData?: IPinData;
|
pinData?: IPinData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRunDataUi {
|
|
||||||
node?: string;
|
|
||||||
workflowData: IWorkflowData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITableData {
|
export interface ITableData {
|
||||||
columns: string[];
|
columns: string[];
|
||||||
data: GenericValue[][];
|
data: GenericValue[][];
|
||||||
@@ -863,6 +858,7 @@ export interface IRootState {
|
|||||||
oauthCallbackUrls: object;
|
oauthCallbackUrls: object;
|
||||||
n8nMetadata: object;
|
n8nMetadata: object;
|
||||||
workflowExecutionData: IExecutionResponse | null;
|
workflowExecutionData: IExecutionResponse | null;
|
||||||
|
workflowExecutionPairedItemMappings: {[itemId: string]: Set<string>};
|
||||||
lastSelectedNode: string | null;
|
lastSelectedNode: string | null;
|
||||||
lastSelectedNodeOutputIndex: number | null;
|
lastSelectedNodeOutputIndex: number | null;
|
||||||
nodeViewOffsetPosition: XYPosition;
|
nodeViewOffsetPosition: XYPosition;
|
||||||
@@ -912,6 +908,13 @@ export interface IModalState {
|
|||||||
|
|
||||||
export type IRunDataDisplayMode = 'table' | 'json' | 'binary';
|
export type IRunDataDisplayMode = 'table' | 'json' | 'binary';
|
||||||
|
|
||||||
|
export interface TargetItem {
|
||||||
|
nodeName: string;
|
||||||
|
itemIndex: number;
|
||||||
|
runIndex: number;
|
||||||
|
outputIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IUiState {
|
export interface IUiState {
|
||||||
sidebarMenuCollapsed: boolean;
|
sidebarMenuCollapsed: boolean;
|
||||||
modalStack: string[];
|
modalStack: string[];
|
||||||
@@ -925,11 +928,15 @@ export interface IUiState {
|
|||||||
sessionId: string;
|
sessionId: string;
|
||||||
input: {
|
input: {
|
||||||
displayMode: IRunDataDisplayMode;
|
displayMode: IRunDataDisplayMode;
|
||||||
|
nodeName?: string;
|
||||||
|
run?: number;
|
||||||
|
branch?: number;
|
||||||
data: {
|
data: {
|
||||||
isEmpty: boolean;
|
isEmpty: boolean;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
output: {
|
output: {
|
||||||
|
branch?: number;
|
||||||
displayMode: IRunDataDisplayMode;
|
displayMode: IRunDataDisplayMode;
|
||||||
data: {
|
data: {
|
||||||
isEmpty: boolean;
|
isEmpty: boolean;
|
||||||
@@ -941,6 +948,7 @@ export interface IUiState {
|
|||||||
};
|
};
|
||||||
focusedMappableInput: string;
|
focusedMappableInput: string;
|
||||||
mappingTelemetry: {[key: string]: string | number | boolean};
|
mappingTelemetry: {[key: string]: string | number | boolean};
|
||||||
|
hoveringItem: null | TargetItem;
|
||||||
};
|
};
|
||||||
mainPanelPosition: number;
|
mainPanelPosition: number;
|
||||||
draggable: {
|
draggable: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div @keydown.stop :class="$style.container" v-if="credentialProperties.length">
|
<div @keydown.stop :class="$style.container" v-if="credentialProperties.length">
|
||||||
<form v-for="parameter in credentialProperties" :key="parameter.name" autocomplete="off">
|
<form v-for="parameter in credentialProperties" :key="parameter.name" autocomplete="off">
|
||||||
<!-- Why form? to break up inputs, to prevent Chrome autofill -->
|
<!-- Why form? to break up inputs, to prevent Chrome autofill -->
|
||||||
<ParameterInputExpanded
|
<parameter-input-expanded
|
||||||
:parameter="parameter"
|
:parameter="parameter"
|
||||||
:value="credentialData[parameter.name]"
|
:value="credentialData[parameter.name]"
|
||||||
:documentationUrl="documentationUrl"
|
:documentationUrl="documentationUrl"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
:label="$locale.nodeText().inputLabelDisplayName(property, path)"
|
:label="$locale.nodeText().inputLabelDisplayName(property, path)"
|
||||||
:underline="true"
|
:underline="true"
|
||||||
size="small"
|
size="small"
|
||||||
|
color="text-dark"
|
||||||
/>
|
/>
|
||||||
<div v-if="multipleValues === true">
|
<div v-if="multipleValues === true">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>
|
>
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
<div :class="$style.container">
|
<div :class="$style.container">
|
||||||
<n8n-input-label :label="$locale.baseText('importCurlModal.input.label')">
|
<n8n-input-label :label="$locale.baseText('importCurlModal.input.label')" color="text-dark">
|
||||||
<n8n-input
|
<n8n-input
|
||||||
:value="curlCommand"
|
:value="curlCommand"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
:showMappingHint="draggableHintShown"
|
:showMappingHint="draggableHintShown"
|
||||||
:distanceFromActive="currentNodeDepth"
|
:distanceFromActive="currentNodeDepth"
|
||||||
paneType="input"
|
paneType="input"
|
||||||
|
@itemHover="$emit('itemHover', $event)"
|
||||||
@linkRun="onLinkRun"
|
@linkRun="onLinkRun"
|
||||||
@unlinkRun="onUnlinkRun"
|
@unlinkRun="onUnlinkRun"
|
||||||
@runChange="onRunIndexChange"
|
@runChange="onRunIndexChange"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
:tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)"
|
:tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)"
|
||||||
:underline="true"
|
:underline="true"
|
||||||
size="small"
|
size="small"
|
||||||
|
color="text-dark"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-for="(value, index) in values" :key="index" class="duplicate-parameter-item" :class="parameter.type">
|
<div v-for="(value, index) in values" :key="index" class="duplicate-parameter-item" :class="parameter.type">
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
:bold="false"
|
:bold="false"
|
||||||
:set="issues = getIssues(credentialTypeDescription.name)"
|
:set="issues = getIssues(credentialTypeDescription.name)"
|
||||||
size="small"
|
size="small"
|
||||||
|
color="text-dark"
|
||||||
>
|
>
|
||||||
<div v-if="isReadOnly">
|
<div v-if="isReadOnly">
|
||||||
<n8n-input
|
<n8n-input
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
@select="onInputSelect"
|
@select="onInputSelect"
|
||||||
@execute="onNodeExecute"
|
@execute="onNodeExecute"
|
||||||
@tableMounted="onInputTableMounted"
|
@tableMounted="onInputTableMounted"
|
||||||
|
@itemHover="onInputItemHover"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #output>
|
<template #output>
|
||||||
@@ -76,6 +77,7 @@
|
|||||||
@runChange="onRunOutputIndexChange"
|
@runChange="onRunOutputIndexChange"
|
||||||
@openSettings="openSettings"
|
@openSettings="openSettings"
|
||||||
@tableMounted="onOutputTableMounted"
|
@tableMounted="onOutputTableMounted"
|
||||||
|
@itemHover="onOutputItemHover"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #main>
|
<template #main>
|
||||||
@@ -111,7 +113,7 @@ import {
|
|||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
Workflow,
|
Workflow,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { IExecutionResponse, INodeUi, IUpdateInformation } from '../Interface';
|
import { IExecutionResponse, INodeUi, IUpdateInformation, TargetItem } from '../Interface';
|
||||||
|
|
||||||
import { externalHooks } from '@/components/mixins/externalHooks';
|
import { externalHooks } from '@/components/mixins/externalHooks';
|
||||||
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
||||||
@@ -200,7 +202,7 @@ export default mixins(
|
|||||||
this.executionWaitingForWebhook
|
this.executionWaitingForWebhook
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
activeNode(): INodeUi {
|
activeNode(): INodeUi | null {
|
||||||
return this.$store.getters.activeNode;
|
return this.$store.getters.activeNode;
|
||||||
},
|
},
|
||||||
inputNodeName(): string | undefined {
|
inputNodeName(): string | undefined {
|
||||||
@@ -394,8 +396,45 @@ export default mixins(
|
|||||||
maxInputRun() {
|
maxInputRun() {
|
||||||
this.runInputIndex = -1;
|
this.runInputIndex = -1;
|
||||||
},
|
},
|
||||||
|
inputNodeName(nodeName: string | undefined) {
|
||||||
|
this.$store.commit('ui/setInputNodeName', nodeName);
|
||||||
|
},
|
||||||
|
inputRun() {
|
||||||
|
this.$store.commit('ui/setInputRunIndex', this.inputRun);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onInputItemHover(e: {itemIndex: number, outputIndex: number} | null) {
|
||||||
|
if (!this.inputNodeName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e === null) {
|
||||||
|
this.$store.commit('ui/setHoveringItem', null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item: TargetItem = {
|
||||||
|
nodeName: this.inputNodeName,
|
||||||
|
runIndex: this.inputRun,
|
||||||
|
outputIndex: e.outputIndex,
|
||||||
|
itemIndex: e.itemIndex,
|
||||||
|
};
|
||||||
|
this.$store.commit('ui/setHoveringItem', item);
|
||||||
|
},
|
||||||
|
onOutputItemHover(e: {itemIndex: number, outputIndex: number} | null) {
|
||||||
|
if (e === null || !this.activeNode) {
|
||||||
|
this.$store.commit('ui/setHoveringItem', null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item: TargetItem = {
|
||||||
|
nodeName: this.activeNode.name,
|
||||||
|
runIndex: this.outputRun,
|
||||||
|
outputIndex: e.outputIndex,
|
||||||
|
itemIndex: e.itemIndex,
|
||||||
|
};
|
||||||
|
this.$store.commit('ui/setHoveringItem', item);
|
||||||
|
},
|
||||||
onInputTableMounted(e: { avgRowHeight: number }) {
|
onInputTableMounted(e: { avgRowHeight: number }) {
|
||||||
this.avgInputRowHeight = e.avgRowHeight;
|
this.avgInputRowHeight = e.avgRowHeight;
|
||||||
},
|
},
|
||||||
@@ -410,13 +449,15 @@ export default mixins(
|
|||||||
},
|
},
|
||||||
onFeatureRequestClick() {
|
onFeatureRequestClick() {
|
||||||
window.open(this.featureRequestUrl, '_blank');
|
window.open(this.featureRequestUrl, '_blank');
|
||||||
this.$telemetry.track('User clicked ndv link', {
|
if (this.activeNode) {
|
||||||
node_type: this.activeNode.type,
|
this.$telemetry.track('User clicked ndv link', {
|
||||||
workflow_id: this.$store.getters.workflowId,
|
node_type: this.activeNode.type,
|
||||||
session_id: this.sessionId,
|
workflow_id: this.$store.getters.workflowId,
|
||||||
pane: 'main',
|
session_id: this.sessionId,
|
||||||
type: 'i-wish-this-node-would',
|
pane: 'main',
|
||||||
});
|
type: 'i-wish-this-node-would',
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onPanelsInit(e: { position: number }) {
|
onPanelsInit(e: { position: number }) {
|
||||||
this.mainPanelPosition = e.position;
|
this.mainPanelPosition = e.position;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
@linkRun="onLinkRun"
|
@linkRun="onLinkRun"
|
||||||
@unlinkRun="onUnlinkRun"
|
@unlinkRun="onUnlinkRun"
|
||||||
@tableMounted="$emit('tableMounted', $event)"
|
@tableMounted="$emit('tableMounted', $event)"
|
||||||
|
@itemHover="$emit('itemHover', $event)"
|
||||||
ref="runData"
|
ref="runData"
|
||||||
>
|
>
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
:value="value"
|
:value="value"
|
||||||
:displayTitle="displayTitle"
|
:displayTitle="displayTitle"
|
||||||
:expressionDisplayValue="expressionDisplayValue"
|
:expressionDisplayValue="expressionDisplayValue"
|
||||||
|
:expressionComputedValue="expressionEvaluated"
|
||||||
:isValueExpression="isValueExpression"
|
:isValueExpression="isValueExpression"
|
||||||
:isReadOnly="isReadOnly"
|
:isReadOnly="isReadOnly"
|
||||||
:parameterIssues="getIssues"
|
:parameterIssues="getIssues"
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
:size="inputSize"
|
:size="inputSize"
|
||||||
:type="getStringInputType"
|
:type="getStringInputType"
|
||||||
:rows="getArgument('rows')"
|
:rows="getArgument('rows')"
|
||||||
:value="activeDrop || forceShowExpression? '': expressionDisplayValue"
|
:value="expressionDisplayValue"
|
||||||
:title="displayTitle"
|
:title="displayTitle"
|
||||||
@keydown.stop
|
@keydown.stop
|
||||||
/>
|
/>
|
||||||
@@ -297,6 +298,8 @@ import {
|
|||||||
INodeParameters,
|
INodeParameters,
|
||||||
INodePropertyOptions,
|
INodePropertyOptions,
|
||||||
Workflow,
|
Workflow,
|
||||||
|
INodeProperties,
|
||||||
|
INodePropertyCollection,
|
||||||
NodeParameterValueType,
|
NodeParameterValueType,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
@@ -316,12 +319,13 @@ import { externalHooks } from '@/components/mixins/externalHooks';
|
|||||||
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
||||||
import { showMessage } from '@/components/mixins/showMessage';
|
import { showMessage } from '@/components/mixins/showMessage';
|
||||||
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
|
import { workflowHelpers } from '@/components/mixins/workflowHelpers';
|
||||||
|
import { hasExpressionMapping, isValueExpression } from './helpers';
|
||||||
|
import { isResourceLocatorValue } from '@/typeGuards';
|
||||||
|
|
||||||
import mixins from 'vue-typed-mixins';
|
import mixins from 'vue-typed-mixins';
|
||||||
import { CUSTOM_API_CALL_KEY } from '@/constants';
|
import { CUSTOM_API_CALL_KEY } from '@/constants';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { hasExpressionMapping, isValueExpression } from './helpers';
|
import { PropType } from 'vue';
|
||||||
import { isResourceLocatorValue } from '@/typeGuards';
|
|
||||||
|
|
||||||
export default mixins(
|
export default mixins(
|
||||||
externalHooks,
|
externalHooks,
|
||||||
@@ -344,21 +348,56 @@ export default mixins(
|
|||||||
TextEdit,
|
TextEdit,
|
||||||
ImportParameter,
|
ImportParameter,
|
||||||
},
|
},
|
||||||
props: [
|
props: {
|
||||||
'inputSize',
|
isReadOnly: {
|
||||||
'isReadOnly',
|
type: Boolean,
|
||||||
'documentationUrl',
|
},
|
||||||
'parameter', // NodeProperties
|
parameter: {
|
||||||
'path', // string
|
type: Object as PropType<INodeProperties>,
|
||||||
'value',
|
},
|
||||||
'hideIssues', // boolean
|
path: {
|
||||||
'errorHighlight',
|
type: String,
|
||||||
'isForCredential', // boolean
|
},
|
||||||
'eventSource', // string
|
value: {
|
||||||
'activeDrop',
|
type: [String, Number, Boolean, Array, Object] as PropType<NodeParameterValueType>,
|
||||||
'droppable',
|
},
|
||||||
'forceShowExpression',
|
hideLabel: {
|
||||||
],
|
type: Boolean,
|
||||||
|
},
|
||||||
|
droppable: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
activeDrop: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
forceShowExpression: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String as PropType<string | undefined>,
|
||||||
|
},
|
||||||
|
inputSize: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
hideIssues: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
documentationUrl: {
|
||||||
|
type: String as PropType<string | undefined>,
|
||||||
|
},
|
||||||
|
errorHighlight: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
isForCredential: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
eventSource: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
expressionEvaluated: {
|
||||||
|
type: String as PropType<string | undefined>,
|
||||||
|
},
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
codeEditDialogVisible: false,
|
codeEditDialogVisible: false,
|
||||||
@@ -419,12 +458,21 @@ export default mixins(
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('credentials', ['allCredentialTypes']),
|
...mapGetters('credentials', ['allCredentialTypes']),
|
||||||
|
expressionDisplayValue(): string {
|
||||||
|
if (this.activeDrop || this.forceShowExpression) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = isResourceLocatorValue(this.value) ? this.value.value : this.value;
|
||||||
|
if (typeof value === 'string' && value.startsWith('=')) {
|
||||||
|
return value.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
isValueExpression(): boolean {
|
isValueExpression(): boolean {
|
||||||
return isValueExpression(this.parameter, this.value);
|
return isValueExpression(this.parameter, this.value);
|
||||||
},
|
},
|
||||||
areExpressionsDisabled(): boolean {
|
|
||||||
return this.$store.getters['ui/areExpressionsDisabled'];
|
|
||||||
},
|
|
||||||
codeAutocomplete (): string | undefined {
|
codeAutocomplete (): string | undefined {
|
||||||
return this.getArgument('codeAutocomplete') as string | undefined;
|
return this.getArgument('codeAutocomplete') as string | undefined;
|
||||||
},
|
},
|
||||||
@@ -486,9 +534,9 @@ export default mixins(
|
|||||||
|
|
||||||
let returnValue;
|
let returnValue;
|
||||||
if (this.isValueExpression === false) {
|
if (this.isValueExpression === false) {
|
||||||
returnValue = this.isResourceLocatorParameter ? (this.value ? this.value.value: '') : this.value;
|
returnValue = this.isResourceLocatorParameter ? (isResourceLocatorValue(this.value) ? this.value.value: '') : this.value;
|
||||||
} else {
|
} else {
|
||||||
returnValue = this.expressionValueComputed;
|
returnValue = this.expressionEvaluated;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parameter.type === 'credentialsSelect') {
|
if (this.parameter.type === 'credentialsSelect') {
|
||||||
@@ -519,39 +567,6 @@ export default mixins(
|
|||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
},
|
},
|
||||||
expressionDisplayValue (): string {
|
|
||||||
const value = this.displayValue;
|
|
||||||
|
|
||||||
// address type errors for text input
|
|
||||||
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
||||||
return JSON.stringify(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
expressionValueComputed (): NodeParameterValue | string[] | null {
|
|
||||||
if (this.areExpressionsDisabled) {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.node === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let computedValue: NodeParameterValue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
computedValue = this.resolveExpression(this.value.value || this.value) as NodeParameterValue;
|
|
||||||
} catch (error) {
|
|
||||||
computedValue = `[${this.$locale.baseText('parameterInput.error')}}: ${error.message}]`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return computedValue;
|
|
||||||
},
|
|
||||||
getStringInputType () {
|
getStringInputType () {
|
||||||
if (this.getArgument('password') === true) {
|
if (this.getArgument('password') === true) {
|
||||||
return 'password';
|
return 'password';
|
||||||
@@ -562,7 +577,7 @@ export default mixins(
|
|||||||
return 'textarea';
|
return 'textarea';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parameter.type === 'code') {
|
if (this.parameter.typeOptions && this.parameter.typeOptions.editor === 'code') {
|
||||||
return 'textarea';
|
return 'textarea';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,13 +602,14 @@ export default mixins(
|
|||||||
} else if (
|
} else if (
|
||||||
['options', 'multiOptions'].includes(this.parameter.type) &&
|
['options', 'multiOptions'].includes(this.parameter.type) &&
|
||||||
this.remoteParameterOptionsLoading === false &&
|
this.remoteParameterOptionsLoading === false &&
|
||||||
this.remoteParameterOptionsLoadingIssues === null
|
this.remoteParameterOptionsLoadingIssues === null &&
|
||||||
|
this.parameterOptions
|
||||||
) {
|
) {
|
||||||
// Check if the value resolves to a valid option
|
// Check if the value resolves to a valid option
|
||||||
// Currently it only displays an error in the node itself in
|
// Currently it only displays an error in the node itself in
|
||||||
// case the value is not valid. The workflow can still be executed
|
// case the value is not valid. The workflow can still be executed
|
||||||
// and the error is not displayed on the node in the workflow
|
// and the error is not displayed on the node in the workflow
|
||||||
const validOptions = this.parameterOptions!.map((options: INodePropertyOptions) => options.value);
|
const validOptions = this.parameterOptions.map((options) => (options as INodePropertyOptions).value);
|
||||||
|
|
||||||
const checkValues: string[] = [];
|
const checkValues: string[] = [];
|
||||||
|
|
||||||
@@ -640,7 +656,7 @@ export default mixins(
|
|||||||
editorType (): string {
|
editorType (): string {
|
||||||
return this.getArgument('editor') as string;
|
return this.getArgument('editor') as string;
|
||||||
},
|
},
|
||||||
parameterOptions (): INodePropertyOptions[] {
|
parameterOptions (): Array<INodePropertyOptions | INodeProperties | INodePropertyCollection> | undefined {
|
||||||
if (this.hasRemoteMethod === false) {
|
if (this.hasRemoteMethod === false) {
|
||||||
// Options are already given
|
// Options are already given
|
||||||
return this.parameter.options;
|
return this.parameter.options;
|
||||||
@@ -828,10 +844,6 @@ export default mixins(
|
|||||||
this.valueChanged(val);
|
this.valueChanged(val);
|
||||||
},
|
},
|
||||||
openExpressionEdit() {
|
openExpressionEdit() {
|
||||||
if (this.areExpressionsDisabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isValueExpression) {
|
if (this.isValueExpression) {
|
||||||
this.expressionEditDialogVisible = true;
|
this.expressionEditDialogVisible = true;
|
||||||
this.trackExpressionEditOpen();
|
this.trackExpressionEditOpen();
|
||||||
@@ -896,7 +908,7 @@ export default mixins(
|
|||||||
|
|
||||||
this.$emit('textInput', parameterData);
|
this.$emit('textInput', parameterData);
|
||||||
},
|
},
|
||||||
valueChanged (value: string[] | string | number | boolean | Date | {} | null) {
|
valueChanged (value: NodeParameterValueType | {} | Date) {
|
||||||
if (this.parameter.name === 'nodeCredentialType') {
|
if (this.parameter.name === 'nodeCredentialType') {
|
||||||
this.activeCredentialType = value as string;
|
this.activeCredentialType = value as string;
|
||||||
}
|
}
|
||||||
@@ -905,7 +917,7 @@ export default mixins(
|
|||||||
value = value.toISOString();
|
value = value.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true && value !== null && value.toString().charAt(0) !== '#') {
|
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true && value !== null && value !== undefined && value.toString().charAt(0) !== '#') {
|
||||||
const newValue = this.rgbaToHex(value as string);
|
const newValue = this.rgbaToHex(value as string);
|
||||||
if (newValue !== null) {
|
if (newValue !== null) {
|
||||||
this.tempValue = newValue;
|
this.tempValue = newValue;
|
||||||
@@ -959,14 +971,14 @@ export default mixins(
|
|||||||
this.trackExpressionEditOpen();
|
this.trackExpressionEditOpen();
|
||||||
}, 375);
|
}, 375);
|
||||||
} else if (command === 'removeExpression') {
|
} else if (command === 'removeExpression') {
|
||||||
let value = this.expressionValueComputed;
|
let value: NodeParameterValueType = this.expressionEvaluated;
|
||||||
|
|
||||||
if (this.parameter.type === 'multiOptions' && typeof value === 'string') {
|
if (this.parameter.type === 'multiOptions' && typeof value === 'string') {
|
||||||
value = (value || '').split(',')
|
value = (value || '').split(',')
|
||||||
.filter((value) => (this.parameterOptions || []).find((option) => option.value === value));
|
.filter((value) => (this.parameterOptions || []).find((option) => (option as INodePropertyOptions).value === value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isResourceLocatorParameter) {
|
if (this.isResourceLocatorParameter && isResourceLocatorValue(this.value)) {
|
||||||
this.valueChanged({ __rl: true, value, mode: this.value.mode });
|
this.valueChanged({ __rl: true, value, mode: this.value.mode });
|
||||||
} else {
|
} else {
|
||||||
this.valueChanged(typeof value !== 'undefined' ? value : null);
|
this.valueChanged(typeof value !== 'undefined' ? value : null);
|
||||||
|
|||||||
@@ -18,19 +18,18 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template>
|
<template>
|
||||||
<parameter-input
|
<parameter-input-wrapper
|
||||||
ref="param"
|
ref="param"
|
||||||
inputSize="large"
|
inputSize="large"
|
||||||
:parameter="parameter"
|
:parameter="parameter"
|
||||||
:value="value"
|
:value="value"
|
||||||
:path="parameter.name"
|
:path="parameter.name"
|
||||||
:hideIssues="true"
|
:hideIssues="true"
|
||||||
:displayOptions="true"
|
|
||||||
:documentationUrl="documentationUrl"
|
:documentationUrl="documentationUrl"
|
||||||
:errorHighlight="showRequiredErrors"
|
:errorHighlight="showRequiredErrors"
|
||||||
:isForCredential="true"
|
:isForCredential="true"
|
||||||
:eventSource="eventSource"
|
:eventSource="eventSource"
|
||||||
:isValueExpression="isValueExpression"
|
:hint="!showRequiredErrors? hint: ''"
|
||||||
@focus="onFocus"
|
@focus="onFocus"
|
||||||
@blur="onBlur"
|
@blur="onBlur"
|
||||||
@textInput="valueChanged"
|
@textInput="valueChanged"
|
||||||
@@ -44,30 +43,27 @@
|
|||||||
</n8n-link>
|
</n8n-link>
|
||||||
</n8n-text>
|
</n8n-text>
|
||||||
</div>
|
</div>
|
||||||
<input-hint :class="$style.hint" :hint="$locale.credText().hint(parameter)" />
|
|
||||||
</template>
|
</template>
|
||||||
</n8n-input-label>
|
</n8n-input-label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { IUpdateInformation } from '@/Interface';
|
import { IUpdateInformation } from '@/Interface';
|
||||||
import ParameterInput from './ParameterInput.vue';
|
|
||||||
import ParameterOptions from './ParameterOptions.vue';
|
import ParameterOptions from './ParameterOptions.vue';
|
||||||
import InputHint from './ParameterInputHint.vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import Vue from 'vue';
|
import ParameterInputWrapper from './ParameterInputWrapper.vue';
|
||||||
import { isValueExpression } from './helpers';
|
import { isValueExpression } from './helpers';
|
||||||
import { INodeParameterResourceLocator, INodeProperties } from 'n8n-workflow';
|
import { INodeParameterResourceLocator, INodeProperties } from 'n8n-workflow';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'ParameterInputExpanded',
|
name: 'parameter-input-expanded',
|
||||||
components: {
|
components: {
|
||||||
ParameterInput,
|
|
||||||
InputHint,
|
|
||||||
ParameterOptions,
|
ParameterOptions,
|
||||||
|
ParameterInputWrapper,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
parameter: {
|
parameter: {
|
||||||
type: Object as () => INodeProperties,
|
type: Object as PropType<INodeProperties>,
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
},
|
},
|
||||||
@@ -106,6 +102,13 @@ export default Vue.extend({
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
hint(): string | null {
|
||||||
|
if (this.isValueExpression) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.$locale.credText().hint(this.parameter);
|
||||||
|
},
|
||||||
isValueExpression (): boolean {
|
isValueExpression (): boolean {
|
||||||
return isValueExpression(this.parameter, this.value as string | INodeParameterResourceLocator);
|
return isValueExpression(this.parameter, this.value as string | INodeParameterResourceLocator);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
:showOptions="menuExpanded || focused || forceShowExpression"
|
:showOptions="menuExpanded || focused || forceShowExpression"
|
||||||
:bold="false"
|
:bold="false"
|
||||||
size="small"
|
size="small"
|
||||||
|
color="text-dark"
|
||||||
>
|
>
|
||||||
<template #options>
|
<template #options>
|
||||||
<parameter-options
|
<parameter-options
|
||||||
@@ -34,16 +35,16 @@
|
|||||||
:buttons="dataMappingTooltipButtons"
|
:buttons="dataMappingTooltipButtons"
|
||||||
>
|
>
|
||||||
<span slot="content" v-html="$locale.baseText(`dataMapping.${displayMode}Hint`, { interpolate: { name: parameter.displayName } })" />
|
<span slot="content" v-html="$locale.baseText(`dataMapping.${displayMode}Hint`, { interpolate: { name: parameter.displayName } })" />
|
||||||
<parameter-input
|
<parameter-input-wrapper
|
||||||
ref="param"
|
ref="param"
|
||||||
:parameter="parameter"
|
:parameter="parameter"
|
||||||
:value="value"
|
:value="value"
|
||||||
:displayOptions="displayOptions"
|
|
||||||
:path="path"
|
:path="path"
|
||||||
:isReadOnly="isReadOnly"
|
:isReadOnly="isReadOnly"
|
||||||
:droppable="droppable"
|
:droppable="droppable"
|
||||||
:activeDrop="activeDrop"
|
:activeDrop="activeDrop"
|
||||||
:forceShowExpression="forceShowExpression"
|
:forceShowExpression="forceShowExpression"
|
||||||
|
:hint="hint"
|
||||||
@valueChanged="valueChanged"
|
@valueChanged="valueChanged"
|
||||||
@focus="onFocus"
|
@focus="onFocus"
|
||||||
@blur="onBlur"
|
@blur="onBlur"
|
||||||
@@ -53,7 +54,6 @@
|
|||||||
</n8n-tooltip>
|
</n8n-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</draggable-target>
|
</draggable-target>
|
||||||
<input-hint :class="$style.hint" :hint="$locale.nodeText().hint(parameter, path)" />
|
|
||||||
</template>
|
</template>
|
||||||
</n8n-input-label>
|
</n8n-input-label>
|
||||||
</template>
|
</template>
|
||||||
@@ -68,7 +68,6 @@ import {
|
|||||||
IUpdateInformation,
|
IUpdateInformation,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
|
||||||
import ParameterInput from '@/components/ParameterInput.vue';
|
|
||||||
import InputHint from './ParameterInputHint.vue';
|
import InputHint from './ParameterInputHint.vue';
|
||||||
import ParameterOptions from './ParameterOptions.vue';
|
import ParameterOptions from './ParameterOptions.vue';
|
||||||
import DraggableTarget from '@/components/DraggableTarget.vue';
|
import DraggableTarget from '@/components/DraggableTarget.vue';
|
||||||
@@ -76,6 +75,7 @@ import mixins from 'vue-typed-mixins';
|
|||||||
import { showMessage } from './mixins/showMessage';
|
import { showMessage } from './mixins/showMessage';
|
||||||
import { LOCAL_STORAGE_MAPPING_FLAG } from '@/constants';
|
import { LOCAL_STORAGE_MAPPING_FLAG } from '@/constants';
|
||||||
import { hasExpressionMapping } from './helpers';
|
import { hasExpressionMapping } from './helpers';
|
||||||
|
import ParameterInputWrapper from './ParameterInputWrapper.vue';
|
||||||
import { hasOnlyListMode } from './ResourceLocator/helpers';
|
import { hasOnlyListMode } from './ResourceLocator/helpers';
|
||||||
import { INodePropertyMode } from 'n8n-workflow';
|
import { INodePropertyMode } from 'n8n-workflow';
|
||||||
import { isResourceLocatorValue } from '@/typeGuards';
|
import { isResourceLocatorValue } from '@/typeGuards';
|
||||||
@@ -87,10 +87,10 @@ export default mixins(
|
|||||||
.extend({
|
.extend({
|
||||||
name: 'parameter-input-full',
|
name: 'parameter-input-full',
|
||||||
components: {
|
components: {
|
||||||
ParameterInput,
|
|
||||||
InputHint,
|
InputHint,
|
||||||
ParameterOptions,
|
ParameterOptions,
|
||||||
DraggableTarget,
|
DraggableTarget,
|
||||||
|
ParameterInputWrapper,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -125,6 +125,9 @@ export default mixins(
|
|||||||
node (): INodeUi | null {
|
node (): INodeUi | null {
|
||||||
return this.$store.getters.activeNode;
|
return this.$store.getters.activeNode;
|
||||||
},
|
},
|
||||||
|
hint (): string | null {
|
||||||
|
return this.$locale.nodeText().hint(this.parameter, this.path);
|
||||||
|
},
|
||||||
isResourceLocator (): boolean {
|
isResourceLocator (): boolean {
|
||||||
return this.parameter.type === 'resourceLocator';
|
return this.parameter.type === 'resourceLocator';
|
||||||
},
|
},
|
||||||
@@ -256,9 +259,3 @@ export default mixins(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
|
||||||
.hint {
|
|
||||||
margin-top: var(--spacing-4xs);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<n8n-text size="small" color="text-base" tag="div" v-if="hint">
|
||||||
<n8n-text size="xsmall" color="text-base" v-if="hint">
|
<div ref="hint" :class="{[$style.hint]: true, [$style.highlight]: highlight}" v-html="hint"></div>
|
||||||
<div ref="hint" v-html="hint"></div>
|
</n8n-text>
|
||||||
</n8n-text>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -11,7 +9,14 @@ import Vue from "vue";
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'InputHint',
|
name: 'InputHint',
|
||||||
props: ['hint'],
|
props: {
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
if(this.$refs.hint){
|
if(this.$refs.hint){
|
||||||
(this.$refs.hint as Element).querySelectorAll('a').forEach(a => a.target = "_blank");
|
(this.$refs.hint as Element).querySelectorAll('a').forEach(a => a.target = "_blank");
|
||||||
@@ -20,3 +25,17 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.hint {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
:tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)"
|
:tooltipText="$locale.nodeText().inputLabelDescription(parameter, path)"
|
||||||
size="small"
|
size="small"
|
||||||
:underline="true"
|
:underline="true"
|
||||||
|
color="text-dark"
|
||||||
/>
|
/>
|
||||||
<collection-parameter
|
<collection-parameter
|
||||||
v-if="parameter.type === 'collection'"
|
v-if="parameter.type === 'collection'"
|
||||||
|
|||||||
210
packages/editor-ui/src/components/ParameterInputWrapper.vue
Normal file
210
packages/editor-ui/src/components/ParameterInputWrapper.vue
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<parameter-input
|
||||||
|
ref="param"
|
||||||
|
:inputSize="inputSize"
|
||||||
|
:parameter="parameter"
|
||||||
|
:value="value"
|
||||||
|
:path="path"
|
||||||
|
:isReadOnly="isReadOnly"
|
||||||
|
:droppable="droppable"
|
||||||
|
:activeDrop="activeDrop"
|
||||||
|
:forceShowExpression="forceShowExpression"
|
||||||
|
:hideIssues="hideIssues"
|
||||||
|
:documentationUrl="documentationUrl"
|
||||||
|
:errorHighlight="errorHighlight"
|
||||||
|
:isForCredential="isForCredential"
|
||||||
|
:eventSource="eventSource"
|
||||||
|
:expressionEvaluated="expressionValueComputed"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="onBlur"
|
||||||
|
@drop="onDrop"
|
||||||
|
@textInput="onTextInput"
|
||||||
|
@valueChanged="onValueChanged" />
|
||||||
|
<input-hint v-if="expressionOutput || parameterHint" :class="$style.hint" :highlight="!!(expressionOutput && targetItem)" :hint="expressionOutput || parameterHint" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue, { PropType } from 'vue';
|
||||||
|
|
||||||
|
import ParameterInput from '@/components/ParameterInput.vue';
|
||||||
|
import InputHint from './ParameterInputHint.vue';
|
||||||
|
import mixins from 'vue-typed-mixins';
|
||||||
|
import { showMessage } from './mixins/showMessage';
|
||||||
|
import { INodeProperties, INodePropertyMode, IRunData, isResourceLocatorValue, NodeParameterValue, NodeParameterValueType } from 'n8n-workflow';
|
||||||
|
import { INodeUi, IUiState, IUpdateInformation, TargetItem } from '@/Interface';
|
||||||
|
import { workflowHelpers } from './mixins/workflowHelpers';
|
||||||
|
import { isValueExpression } from './helpers';
|
||||||
|
|
||||||
|
export default mixins(
|
||||||
|
showMessage,
|
||||||
|
workflowHelpers,
|
||||||
|
)
|
||||||
|
.extend({
|
||||||
|
name: 'parameter-input-wrapper',
|
||||||
|
components: {
|
||||||
|
ParameterInput,
|
||||||
|
InputHint,
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$on('optionSelected', this.optionSelected);
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
type: Object as PropType<INodeProperties>,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Boolean, Array, Object] as PropType<NodeParameterValueType>,
|
||||||
|
},
|
||||||
|
hideLabel: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
droppable: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
activeDrop: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
forceShowExpression: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
inputSize: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
hideIssues: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
documentationUrl: {
|
||||||
|
type: String as PropType<string | undefined>,
|
||||||
|
},
|
||||||
|
errorHighlight: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
isForCredential: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
eventSource: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isValueExpression () {
|
||||||
|
return isValueExpression(this.parameter, this.value);
|
||||||
|
},
|
||||||
|
activeNode(): INodeUi | null {
|
||||||
|
return this.$store.getters.activeNode;
|
||||||
|
},
|
||||||
|
selectedRLMode(): INodePropertyMode | undefined {
|
||||||
|
if (typeof this.value !== 'object' ||this.parameter.type !== 'resourceLocator' || !isResourceLocatorValue(this.value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mode = this.value.mode;
|
||||||
|
if (mode) {
|
||||||
|
return this.parameter.modes?.find((m: INodePropertyMode) => m.name === mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
parameterHint(): string | undefined {
|
||||||
|
if (this.isValueExpression) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (this.selectedRLMode && this.selectedRLMode.hint) {
|
||||||
|
return this.selectedRLMode.hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.hint;
|
||||||
|
},
|
||||||
|
targetItem(): TargetItem | null {
|
||||||
|
return this.$store.getters['ui/hoveringItem'];
|
||||||
|
},
|
||||||
|
expressionValueComputed (): string | null {
|
||||||
|
const inputNodeName: string | undefined = this.$store.getters['ui/ndvInputNodeName'];
|
||||||
|
const value = isResourceLocatorValue(this.value)? this.value.value: this.value;
|
||||||
|
if (this.activeNode === null || !this.isValueExpression || typeof value !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputRunIndex: number | undefined = this.$store.getters['ui/ndvInputRunIndex'];
|
||||||
|
const inputBranchIndex: number | undefined = this.$store.getters['ui/ndvInputBranchIndex'];
|
||||||
|
|
||||||
|
let computedValue: NodeParameterValue;
|
||||||
|
try {
|
||||||
|
const targetItem = this.targetItem ?? undefined;
|
||||||
|
computedValue = this.resolveExpression(value, undefined, {targetItem, inputNodeName, inputRunIndex, inputBranchIndex});
|
||||||
|
if (computedValue === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof computedValue === 'string' && computedValue.trim().length === 0) {
|
||||||
|
computedValue = this.$locale.baseText('parameterInput.emptyString');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
computedValue = `[${this.$locale.baseText('parameterInput.error')}}: ${error.message}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof computedValue === 'string' ? computedValue : JSON.stringify(computedValue);
|
||||||
|
},
|
||||||
|
expressionOutput(): string | null {
|
||||||
|
if (this.isValueExpression && this.expressionValueComputed) {
|
||||||
|
const inputData = this.$store.getters['ui/ndvInputData'];
|
||||||
|
if (!inputData || (inputData && inputData.length <= 1)) {
|
||||||
|
return this.expressionValueComputed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.$locale.baseText(`parameterInput.expressionResult`, {
|
||||||
|
interpolate: {
|
||||||
|
result: this.expressionValueComputed,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFocus() {
|
||||||
|
this.$emit('focus');
|
||||||
|
},
|
||||||
|
onBlur() {
|
||||||
|
this.$emit('blur');
|
||||||
|
},
|
||||||
|
onDrop(data: string) {
|
||||||
|
this.$emit('drop', data);
|
||||||
|
},
|
||||||
|
optionSelected(command: string) {
|
||||||
|
if (this.$refs.param) {
|
||||||
|
(this.$refs.param as Vue).$emit('optionSelected', command);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onValueChanged(parameterData: IUpdateInformation) {
|
||||||
|
this.$emit('valueChanged', parameterData);
|
||||||
|
},
|
||||||
|
onTextInput(parameterData: IUpdateInformation) {
|
||||||
|
this.$emit('textInput', parameterData);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.hint {
|
||||||
|
margin-top: var(--spacing-4xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hovering {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
v-if="isValueExpression || droppable || forceShowExpression"
|
v-if="isValueExpression || droppable || forceShowExpression"
|
||||||
type="text"
|
type="text"
|
||||||
:size="inputSize"
|
:size="inputSize"
|
||||||
:value="activeDrop || forceShowExpression ? '' : expressionDisplayValue"
|
:value="expressionDisplayValue"
|
||||||
:title="displayTitle"
|
:title="displayTitle"
|
||||||
@keydown.stop
|
@keydown.stop
|
||||||
ref="input"
|
ref="input"
|
||||||
@@ -137,7 +137,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</resource-locator-dropdown>
|
</resource-locator-dropdown>
|
||||||
<parameter-input-hint v-if="infoText" class="mt-4xs" :hint="infoText" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -163,7 +162,6 @@ import {
|
|||||||
import DraggableTarget from '@/components/DraggableTarget.vue';
|
import DraggableTarget from '@/components/DraggableTarget.vue';
|
||||||
import ExpressionEdit from '@/components/ExpressionEdit.vue';
|
import ExpressionEdit from '@/components/ExpressionEdit.vue';
|
||||||
import ParameterIssues from '@/components/ParameterIssues.vue';
|
import ParameterIssues from '@/components/ParameterIssues.vue';
|
||||||
import ParameterInputHint from '@/components/ParameterInputHint.vue';
|
|
||||||
import ResourceLocatorDropdown from './ResourceLocatorDropdown.vue';
|
import ResourceLocatorDropdown from './ResourceLocatorDropdown.vue';
|
||||||
import Vue, { PropType } from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import { INodeUi, IResourceLocatorReqParams, IResourceLocatorResultExpanded } from '@/Interface';
|
import { INodeUi, IResourceLocatorReqParams, IResourceLocatorResultExpanded } from '@/Interface';
|
||||||
@@ -172,7 +170,6 @@ import stringify from 'fast-json-stable-stringify';
|
|||||||
import { workflowHelpers } from '../mixins/workflowHelpers';
|
import { workflowHelpers } from '../mixins/workflowHelpers';
|
||||||
import { nodeHelpers } from '../mixins/nodeHelpers';
|
import { nodeHelpers } from '../mixins/nodeHelpers';
|
||||||
import { getAppNameFromNodeName } from '../helpers';
|
import { getAppNameFromNodeName } from '../helpers';
|
||||||
import { type } from 'os';
|
|
||||||
import { isResourceLocatorValue } from '@/typeGuards';
|
import { isResourceLocatorValue } from '@/typeGuards';
|
||||||
|
|
||||||
interface IResourceLocatorQuery {
|
interface IResourceLocatorQuery {
|
||||||
@@ -188,7 +185,6 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
DraggableTarget,
|
DraggableTarget,
|
||||||
ExpressionEdit,
|
ExpressionEdit,
|
||||||
ParameterIssues,
|
ParameterIssues,
|
||||||
ParameterInputHint,
|
|
||||||
ResourceLocatorDropdown,
|
ResourceLocatorDropdown,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@@ -216,7 +212,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
expressionDisplayValue: {
|
expressionComputedValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
@@ -224,6 +220,9 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
expressionDisplayValue: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
forceShowExpression: {
|
forceShowExpression: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -298,9 +297,6 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
|
|
||||||
return defaults[this.selectedMode] || '';
|
return defaults[this.selectedMode] || '';
|
||||||
},
|
},
|
||||||
infoText(): string {
|
|
||||||
return this.currentMode.hint ? this.currentMode.hint : '';
|
|
||||||
},
|
|
||||||
currentMode(): INodePropertyMode {
|
currentMode(): INodePropertyMode {
|
||||||
return this.findModeByName(this.selectedMode) || ({} as INodePropertyMode);
|
return this.findModeByName(this.selectedMode) || ({} as INodePropertyMode);
|
||||||
},
|
},
|
||||||
@@ -327,8 +323,8 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.selectedMode === 'url') {
|
if (this.selectedMode === 'url') {
|
||||||
if (this.isValueExpression && typeof this.expressionDisplayValue === 'string' && this.expressionDisplayValue.startsWith('http')) {
|
if (this.isValueExpression && typeof this.expressionComputedValue === 'string' && this.expressionComputedValue.startsWith('http')) {
|
||||||
return this.expressionDisplayValue;
|
return this.expressionComputedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof this.valueToDisplay === 'string' && this.valueToDisplay.startsWith('http')) {
|
if (typeof this.valueToDisplay === 'string' && this.valueToDisplay.startsWith('http')) {
|
||||||
@@ -337,7 +333,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentMode.url) {
|
if (this.currentMode.url) {
|
||||||
const value = this.isValueExpression? this.expressionDisplayValue : this.valueToDisplay;
|
const value = this.isValueExpression? this.expressionComputedValue : this.valueToDisplay;
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
const expression = this.currentMode.url.replace(/\{\{\$value\}\}/g, value);
|
const expression = this.currentMode.url.replace(/\{\{\$value\}\}/g, value);
|
||||||
const resolved = this.resolveExpression(expression);
|
const resolved = this.resolveExpression(expression);
|
||||||
|
|||||||
@@ -220,8 +220,11 @@
|
|||||||
:distanceFromActive="distanceFromActive"
|
:distanceFromActive="distanceFromActive"
|
||||||
:showMappingHint="showMappingHint"
|
:showMappingHint="showMappingHint"
|
||||||
:runIndex="runIndex"
|
:runIndex="runIndex"
|
||||||
|
:pageOffset="currentPageOffset"
|
||||||
:totalRuns="maxRunIndex"
|
:totalRuns="maxRunIndex"
|
||||||
|
:hasDefaultHoverState="paneType === 'input'"
|
||||||
@mounted="$emit('tableMounted', $event)"
|
@mounted="$emit('tableMounted', $event)"
|
||||||
|
@activeRowChanged="onItemHover"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<run-data-json
|
<run-data-json
|
||||||
@@ -419,7 +422,7 @@ export default mixins(
|
|||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
overrideOutputs: {
|
overrideOutputs: {
|
||||||
type: Array,
|
type: Array as PropType<number[]>,
|
||||||
},
|
},
|
||||||
mappingEnabled: {
|
mappingEnabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -463,6 +466,10 @@ export default mixins(
|
|||||||
this.showPinDataDiscoveryTooltip(this.jsonData);
|
this.showPinDataDiscoveryTooltip(this.jsonData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.$store.commit('ui/setNDVBranchIndex', {
|
||||||
|
pane: this.paneType,
|
||||||
|
branchIndex: this.currentOutputIndex,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.hidePinDataDiscoveryTooltip();
|
this.hidePinDataDiscoveryTooltip();
|
||||||
@@ -561,6 +568,9 @@ export default mixins(
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
|
currentPageOffset(): number {
|
||||||
|
return this.pageSize * (this.currentPage - 1);
|
||||||
|
},
|
||||||
maxRunIndex (): number {
|
maxRunIndex (): number {
|
||||||
if (this.node === null) {
|
if (this.node === null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -662,6 +672,17 @@ export default mixins(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onItemHover(itemIndex: number | null) {
|
||||||
|
if (itemIndex === null) {
|
||||||
|
this.$emit('itemHover', null);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit('itemHover', {
|
||||||
|
outputIndex: this.currentOutputIndex,
|
||||||
|
itemIndex,
|
||||||
|
});
|
||||||
|
},
|
||||||
onClickDataPinningDocsLink() {
|
onClickDataPinningDocsLink() {
|
||||||
this.$telemetry.track('User clicked ndv link', {
|
this.$telemetry.track('User clicked ndv link', {
|
||||||
workflow_id: this.$store.getters.workflowId,
|
workflow_id: this.$store.getters.workflowId,
|
||||||
@@ -1094,6 +1115,12 @@ export default mixins(
|
|||||||
this.onDisplayModeChange('table');
|
this.onDisplayModeChange('table');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
currentOutputIndex(branchIndex: number) {
|
||||||
|
this.$store.commit('ui/setNDVBranchIndex', {
|
||||||
|
pane: this.paneType,
|
||||||
|
branchIndex,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,8 +5,13 @@
|
|||||||
<th :class="$style.emptyCell"></th>
|
<th :class="$style.emptyCell"></th>
|
||||||
<th :class="$style.tableRightMargin"></th>
|
<th :class="$style.tableRightMargin"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="(row, index1) in tableData.data" :key="index1">
|
<tr v-for="(row, index1) in tableData.data" :key="index1" :class="{[$style.hoveringRow]: isHoveringRow(index1)}">
|
||||||
<td>
|
<td
|
||||||
|
:data-row="index1"
|
||||||
|
:data-col="0"
|
||||||
|
@mouseenter="onMouseEnterCell"
|
||||||
|
@mouseleave="onMouseLeaveCell"
|
||||||
|
>
|
||||||
<n8n-text>{{ $locale.baseText('runData.emptyItemHint') }}</n8n-text>
|
<n8n-text>{{ $locale.baseText('runData.emptyItemHint') }}</n8n-text>
|
||||||
</td>
|
</td>
|
||||||
<td :class="$style.tableRightMargin"></td>
|
<td :class="$style.tableRightMargin"></td>
|
||||||
@@ -88,10 +93,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template>
|
<template>
|
||||||
<tr v-for="(row, index1) in tableData.data" :key="index1">
|
<tr v-for="(row, index1) in tableData.data" :key="index1" :class="{[$style.hoveringRow]: isHoveringRow(index1)}">
|
||||||
<td
|
<td
|
||||||
v-for="(data, index2) in row"
|
v-for="(data, index2) in row"
|
||||||
:key="index2"
|
:key="index2"
|
||||||
|
:data-row="index1"
|
||||||
:data-col="index2"
|
:data-col="index2"
|
||||||
@mouseenter="onMouseEnterCell"
|
@mouseenter="onMouseEnterCell"
|
||||||
@mouseleave="onMouseLeaveCell"
|
@mouseleave="onMouseLeaveCell"
|
||||||
@@ -136,9 +142,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/* eslint-disable prefer-spread */
|
/* eslint-disable prefer-spread */
|
||||||
|
|
||||||
|
import { INodeUi, IRootState, ITableData, IUiState } from '@/Interface';
|
||||||
|
import { getPairedItemId } from '@/pairedItemUtils';
|
||||||
import Vue, { PropType } from 'vue';
|
import Vue, { PropType } from 'vue';
|
||||||
import mixins from 'vue-typed-mixins';
|
import mixins from 'vue-typed-mixins';
|
||||||
import { INodeUi, ITableData } from '@/Interface';
|
|
||||||
import { GenericValue, IDataObject, INodeExecutionData } from 'n8n-workflow';
|
import { GenericValue, IDataObject, INodeExecutionData } from 'n8n-workflow';
|
||||||
import Draggable from './Draggable.vue';
|
import Draggable from './Draggable.vue';
|
||||||
import { shorten } from './helpers';
|
import { shorten } from './helpers';
|
||||||
@@ -163,9 +170,18 @@ export default mixins(externalHooks).extend({
|
|||||||
runIndex: {
|
runIndex: {
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
|
outputIndex: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
totalRuns: {
|
totalRuns: {
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
|
pageOffset: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
hasDefaultHoverState: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -174,6 +190,7 @@ export default mixins(externalHooks).extend({
|
|||||||
draggingPath: null as null | string,
|
draggingPath: null as null | string,
|
||||||
hoveringPath: null as null | string,
|
hoveringPath: null as null | string,
|
||||||
mappingHintVisible: false,
|
mappingHintVisible: false,
|
||||||
|
activeRow: null as number | null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -187,12 +204,35 @@ export default mixins(externalHooks).extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
hoveringItem(): IUiState['ndv']['hoveringItem'] {
|
||||||
|
return this.$store.getters['ui/hoveringItem'];
|
||||||
|
},
|
||||||
|
pairedItemMappings(): IRootState['workflowExecutionPairedItemMappings'] {
|
||||||
|
return this.$store.getters['workflowExecutionPairedItemMappings'];
|
||||||
|
},
|
||||||
tableData(): ITableData {
|
tableData(): ITableData {
|
||||||
return this.convertToTable(this.inputData);
|
return this.convertToTable(this.inputData);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
shorten,
|
shorten,
|
||||||
|
isHoveringRow(row: number): boolean {
|
||||||
|
if (row === this.activeRow) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemIndex = this.pageOffset + row;
|
||||||
|
if (itemIndex === 0 && !this.hoveringItem && this.hasDefaultHoverState && this.distanceFromActive === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const itemNodeId = getPairedItemId(this.node.name, this.runIndex || 0, this.outputIndex || 0, itemIndex);
|
||||||
|
if (!this.hoveringItem || !this.pairedItemMappings[itemNodeId]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hoveringItemId = getPairedItemId(this.hoveringItem.nodeName, this.hoveringItem.runIndex, this.hoveringItem.outputIndex, this.hoveringItem.itemIndex);
|
||||||
|
return this.pairedItemMappings[itemNodeId].has(hoveringItemId);
|
||||||
|
},
|
||||||
onMouseEnterCell(e: MouseEvent) {
|
onMouseEnterCell(e: MouseEvent) {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
if (target && this.mappingEnabled) {
|
if (target && this.mappingEnabled) {
|
||||||
@@ -201,9 +241,19 @@ export default mixins(externalHooks).extend({
|
|||||||
this.activeColumn = parseInt(col, 10);
|
this.activeColumn = parseInt(col, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
const row = (target as HTMLElement).dataset.row;
|
||||||
|
if (row && !isNaN(parseInt(row, 10))) {
|
||||||
|
this.activeRow = parseInt(row, 10);
|
||||||
|
this.$emit('activeRowChanged', this.pageOffset + this.activeRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onMouseLeaveCell() {
|
onMouseLeaveCell() {
|
||||||
this.activeColumn = -1;
|
this.activeColumn = -1;
|
||||||
|
this.activeRow = null;
|
||||||
|
this.$emit('activeRowChanged', null);
|
||||||
},
|
},
|
||||||
onMouseEnterKey(path: string[], colIndex: number) {
|
onMouseEnterKey(path: string[], colIndex: number) {
|
||||||
this.hoveringPath = this.getCellExpression(path, colIndex);
|
this.hoveringPath = this.getCellExpression(path, colIndex);
|
||||||
@@ -438,6 +488,7 @@ export default mixins(externalHooks).extend({
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
color: var(--color-text-dark);
|
color: var(--color-text-dark);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -449,6 +500,27 @@ export default mixins(externalHooks).extend({
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td:first-child, td:nth-last-child(2) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
|
||||||
|
&:after { // add border without shifting content
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 2px;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-last-child(2):after {
|
||||||
|
right: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:first-child:after {
|
||||||
|
left: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
th:last-child,
|
th:last-child,
|
||||||
td:last-child {
|
td:last-child {
|
||||||
border-right: var(--border-base);
|
border-right: var(--border-base);
|
||||||
@@ -565,9 +637,16 @@ export default mixins(externalHooks).extend({
|
|||||||
|
|
||||||
.tableRightMargin {
|
.tableRightMargin {
|
||||||
// becomes necessary with large tables
|
// becomes necessary with large tables
|
||||||
|
background-color: var(--color-background-base) !important;
|
||||||
width: var(--spacing-s);
|
width: var(--spacing-s);
|
||||||
border-right: none !important;
|
border-right: none !important;
|
||||||
border-top: none !important;
|
border-top: none !important;
|
||||||
border-bottom: none !important;
|
border-bottom: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hoveringRow {
|
||||||
|
td:first-child:after, td:nth-last-child(2):after {
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import {
|
|||||||
XYPosition,
|
XYPosition,
|
||||||
ITag,
|
ITag,
|
||||||
IUpdateInformation,
|
IUpdateInformation,
|
||||||
|
TargetItem,
|
||||||
} from '../../Interface';
|
} from '../../Interface';
|
||||||
|
|
||||||
import { externalHooks } from '@/components/mixins/externalHooks';
|
import { externalHooks } from '@/components/mixins/externalHooks';
|
||||||
@@ -54,6 +55,7 @@ import { isEqual } from 'lodash';
|
|||||||
|
|
||||||
import mixins from 'vue-typed-mixins';
|
import mixins from 'vue-typed-mixins';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { getSourceItems } from '@/pairedItemUtils';
|
||||||
|
|
||||||
let cachedWorkflowKey: string | null = '';
|
let cachedWorkflowKey: string | null = '';
|
||||||
let cachedWorkflow: Workflow | null = null;
|
let cachedWorkflow: Workflow | null = null;
|
||||||
@@ -98,6 +100,7 @@ export const workflowHelpers = mixins(
|
|||||||
|
|
||||||
if (!workflowRunData[parentNodeName] ||
|
if (!workflowRunData[parentNodeName] ||
|
||||||
workflowRunData[parentNodeName].length <= runIndex ||
|
workflowRunData[parentNodeName].length <= runIndex ||
|
||||||
|
!workflowRunData[parentNodeName][runIndex] ||
|
||||||
!workflowRunData[parentNodeName][runIndex].hasOwnProperty('data') ||
|
!workflowRunData[parentNodeName][runIndex].hasOwnProperty('data') ||
|
||||||
workflowRunData[parentNodeName][runIndex].data === undefined ||
|
workflowRunData[parentNodeName][runIndex].data === undefined ||
|
||||||
!workflowRunData[parentNodeName][runIndex].data!.hasOwnProperty(inputName)
|
!workflowRunData[parentNodeName][runIndex].data!.hasOwnProperty(inputName)
|
||||||
@@ -526,24 +529,47 @@ export const workflowHelpers = mixins(
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
resolveParameter(parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]) {
|
resolveParameter(parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], opts: {targetItem?: TargetItem, inputNodeName?: string, inputRunIndex?: number, inputBranchIndex?: number} = {}): IDataObject | null {
|
||||||
const itemIndex = 0;
|
let itemIndex = opts?.targetItem?.itemIndex || 0;
|
||||||
|
|
||||||
const inputName = 'main';
|
const inputName = 'main';
|
||||||
const activeNode = this.$store.getters.activeNode;
|
const activeNode = this.$store.getters.activeNode;
|
||||||
const workflow = this.getCurrentWorkflow();
|
const workflow = this.getCurrentWorkflow();
|
||||||
const parentNode = workflow.getParentNodes(activeNode.name, inputName, 1);
|
const workflowRunData = this.$store.getters.getWorkflowRunData as IRunData | null;
|
||||||
|
let parentNode = workflow.getParentNodes(activeNode.name, inputName, 1);
|
||||||
const executionData = this.$store.getters.getWorkflowExecution as IExecutionResponse | null;
|
const executionData = this.$store.getters.getWorkflowExecution as IExecutionResponse | null;
|
||||||
|
|
||||||
const workflowRunData = this.$store.getters.getWorkflowRunData as IRunData | null;
|
if (opts?.inputNodeName && !parentNode.includes(opts.inputNodeName)) {
|
||||||
let runIndexParent = 0;
|
return null;
|
||||||
if (workflowRunData !== null && parentNode.length) {
|
}
|
||||||
const firstParentWithWorkflowRunData = parentNode.find((parentNodeName) => workflowRunData[parentNodeName]);
|
|
||||||
if (firstParentWithWorkflowRunData) {
|
let runIndexParent = opts?.inputRunIndex ?? 0;
|
||||||
runIndexParent = workflowRunData[firstParentWithWorkflowRunData].length - 1;
|
const nodeConnection = workflow.getNodeConnectionIndexes(activeNode!.name, parentNode[0]);
|
||||||
|
if (opts.targetItem && opts?.targetItem?.nodeName === activeNode.name && executionData) {
|
||||||
|
const sourceItems = getSourceItems(executionData, opts.targetItem);
|
||||||
|
if (!sourceItems.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
parentNode = [sourceItems[0].nodeName];
|
||||||
|
runIndexParent = sourceItems[0].runIndex;
|
||||||
|
itemIndex = sourceItems[0].itemIndex;
|
||||||
|
if (nodeConnection) {
|
||||||
|
nodeConnection.sourceIndex = sourceItems[0].outputIndex;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentNode = opts.inputNodeName ? [opts.inputNodeName] : parentNode;
|
||||||
|
if (nodeConnection) {
|
||||||
|
nodeConnection.sourceIndex = opts.inputBranchIndex ?? nodeConnection.sourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts?.inputRunIndex === undefined && workflowRunData !== null && parentNode.length) {
|
||||||
|
const firstParentWithWorkflowRunData = parentNode.find((parentNodeName) => workflowRunData[parentNodeName]);
|
||||||
|
if (firstParentWithWorkflowRunData) {
|
||||||
|
runIndexParent = workflowRunData[firstParentWithWorkflowRunData].length - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeConnection = workflow.getNodeConnectionIndexes(activeNode!.name, parentNode[0]);
|
|
||||||
let connectionInputData = this.connectionInputData(parentNode, activeNode.name, inputName, runIndexParent, nodeConnection);
|
let connectionInputData = this.connectionInputData(parentNode, activeNode.name, inputName, runIndexParent, nodeConnection);
|
||||||
|
|
||||||
let runExecutionData: IRunExecutionData;
|
let runExecutionData: IRunExecutionData;
|
||||||
@@ -601,8 +627,8 @@ export const workflowHelpers = mixins(
|
|||||||
$resumeWebhookUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
|
$resumeWebhookUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
|
||||||
};
|
};
|
||||||
|
|
||||||
let runIndexCurrent = 0;
|
let runIndexCurrent = opts?.targetItem?.runIndex ?? 0;
|
||||||
if (workflowRunData !== null && workflowRunData[activeNode.name]) {
|
if (opts?.targetItem === undefined && workflowRunData !== null && workflowRunData[activeNode.name]) {
|
||||||
runIndexCurrent = workflowRunData[activeNode.name].length -1;
|
runIndexCurrent = workflowRunData[activeNode.name].length -1;
|
||||||
}
|
}
|
||||||
const executeData = this.executeData(parentNode, activeNode.name, inputName, runIndexCurrent);
|
const executeData = this.executeData(parentNode, activeNode.name, inputName, runIndexCurrent);
|
||||||
@@ -610,12 +636,15 @@ export const workflowHelpers = mixins(
|
|||||||
return workflow.expression.getParameterValue(parameter, runExecutionData, runIndexCurrent, itemIndex, activeNode.name, connectionInputData, 'manual', this.$store.getters.timezone, additionalKeys, executeData, false) as IDataObject;
|
return workflow.expression.getParameterValue(parameter, runExecutionData, runIndexCurrent, itemIndex, activeNode.name, connectionInputData, 'manual', this.$store.getters.timezone, additionalKeys, executeData, false) as IDataObject;
|
||||||
},
|
},
|
||||||
|
|
||||||
resolveExpression(expression: string, siblingParameters: INodeParameters = {}) {
|
resolveExpression(expression: string, siblingParameters: INodeParameters = {}, opts: {targetItem?: TargetItem, inputNodeName?: string, inputRunIndex?: number, inputBranchIndex?: number, c?: number} = {}) {
|
||||||
const parameters = {
|
const parameters = {
|
||||||
'__xxxxxxx__': expression,
|
'__xxxxxxx__': expression,
|
||||||
...siblingParameters,
|
...siblingParameters,
|
||||||
};
|
};
|
||||||
const returnData = this.resolveParameter(parameters) as IDataObject;
|
const returnData: IDataObject | null = this.resolveParameter(parameters, opts);
|
||||||
|
if (!returnData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof returnData['__xxxxxxx__'] === 'object') {
|
if (typeof returnData['__xxxxxxx__'] === 'object') {
|
||||||
const workflow = this.getCurrentWorkflow();
|
const workflow = this.getCurrentWorkflow();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { ActionContext, Module } from 'vuex';
|
import { ActionContext, Module } from 'vuex';
|
||||||
import {
|
import {
|
||||||
|
IExecutionResponse,
|
||||||
IFakeDoor,
|
IFakeDoor,
|
||||||
IFakeDoorLocation,
|
IFakeDoorLocation,
|
||||||
IRootState,
|
IRootState,
|
||||||
@@ -117,12 +118,16 @@ const module: Module<IUiState, IRootState> = {
|
|||||||
sessionId: '',
|
sessionId: '',
|
||||||
input: {
|
input: {
|
||||||
displayMode: 'table',
|
displayMode: 'table',
|
||||||
|
nodeName: undefined,
|
||||||
|
run: undefined,
|
||||||
|
branch: undefined,
|
||||||
data: {
|
data: {
|
||||||
isEmpty: true,
|
isEmpty: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
displayMode: 'table',
|
displayMode: 'table',
|
||||||
|
branch: undefined,
|
||||||
data: {
|
data: {
|
||||||
isEmpty: true,
|
isEmpty: true,
|
||||||
},
|
},
|
||||||
@@ -133,6 +138,7 @@ const module: Module<IUiState, IRootState> = {
|
|||||||
},
|
},
|
||||||
focusedMappableInput: '',
|
focusedMappableInput: '',
|
||||||
mappingTelemetry: {},
|
mappingTelemetry: {},
|
||||||
|
hoveringItem: null,
|
||||||
},
|
},
|
||||||
mainPanelPosition: 0.5,
|
mainPanelPosition: 0.5,
|
||||||
draggable: {
|
draggable: {
|
||||||
@@ -174,8 +180,17 @@ const module: Module<IUiState, IRootState> = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
areExpressionsDisabled(state: IUiState) {
|
ndvInputData: (state: IUiState, getters, rootState: IRootState, rootGetters) => {
|
||||||
return state.currentView === VIEWS.DEMO;
|
const executionData = rootGetters.getWorkflowExecution as IExecutionResponse | null;
|
||||||
|
const inputNodeName: string | undefined = state.ndv.input.nodeName;
|
||||||
|
const inputRunIndex: number = state.ndv.input.run ?? 0;
|
||||||
|
const inputBranchIndex: number = state.ndv.input.branch?? 0;
|
||||||
|
|
||||||
|
if (!executionData || !inputNodeName || inputRunIndex === undefined || inputBranchIndex === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return executionData.data?.resultData?.runData?.[inputNodeName]?.[inputRunIndex]?.data?.main?.[inputBranchIndex];
|
||||||
},
|
},
|
||||||
isVersionsOpen: (state: IUiState) => {
|
isVersionsOpen: (state: IUiState) => {
|
||||||
return state.modals[VERSIONS_MODAL_KEY].open;
|
return state.modals[VERSIONS_MODAL_KEY].open;
|
||||||
@@ -230,9 +245,19 @@ const module: Module<IUiState, IRootState> = {
|
|||||||
mappingTelemetry: (state: IUiState) => state.ndv.mappingTelemetry,
|
mappingTelemetry: (state: IUiState) => state.ndv.mappingTelemetry,
|
||||||
getCurrentView: (state: IUiState) => state.currentView,
|
getCurrentView: (state: IUiState) => state.currentView,
|
||||||
isNodeView: (state: IUiState) => [VIEWS.NEW_WORKFLOW.toString(), VIEWS.WORKFLOW.toString(), VIEWS.EXECUTION.toString()].includes(state.currentView),
|
isNodeView: (state: IUiState) => [VIEWS.NEW_WORKFLOW.toString(), VIEWS.WORKFLOW.toString(), VIEWS.EXECUTION.toString()].includes(state.currentView),
|
||||||
|
hoveringItem: (state: IUiState) => state.ndv.hoveringItem,
|
||||||
|
ndvInputNodeName: (state: IUiState) => state.ndv.input.nodeName,
|
||||||
|
ndvInputRunIndex: (state: IUiState) => state.ndv.input.run,
|
||||||
|
ndvInputBranchIndex: (state: IUiState) => state.ndv.input.branch,
|
||||||
getNDVDataIsEmpty: (state: IUiState) => (panel: 'input' | 'output'): boolean => state.ndv[panel].data.isEmpty,
|
getNDVDataIsEmpty: (state: IUiState) => (panel: 'input' | 'output'): boolean => state.ndv[panel].data.isEmpty,
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
setInputNodeName: (state: IUiState, name: string | undefined) => {
|
||||||
|
Vue.set(state.ndv.input, 'nodeName', name);
|
||||||
|
},
|
||||||
|
setInputRunIndex: (state: IUiState, run?: string) => {
|
||||||
|
Vue.set(state.ndv.input, 'run', run);
|
||||||
|
},
|
||||||
setMainPanelDimensions: (state: IUiState, params: { panelType:string, dimensions: { relativeLeft?: number, relativeRight?: number, relativeWidth?: number }}) => {
|
setMainPanelDimensions: (state: IUiState, params: { panelType:string, dimensions: { relativeLeft?: number, relativeRight?: number, relativeWidth?: number }}) => {
|
||||||
Vue.set(
|
Vue.set(
|
||||||
state.mainPanelDimensions,
|
state.mainPanelDimensions,
|
||||||
@@ -337,6 +362,12 @@ const module: Module<IUiState, IRootState> = {
|
|||||||
resetMappingTelemetry(state: IUiState) {
|
resetMappingTelemetry(state: IUiState) {
|
||||||
state.ndv.mappingTelemetry = {};
|
state.ndv.mappingTelemetry = {};
|
||||||
},
|
},
|
||||||
|
setHoveringItem(state: IUiState, item: null | IUiState['ndv']['hoveringItem']) {
|
||||||
|
Vue.set(state.ndv, 'hoveringItem', item);
|
||||||
|
},
|
||||||
|
setNDVBranchIndex(state: IUiState, e: {pane: 'input' | 'output', branchIndex: number}) {
|
||||||
|
Vue.set(state.ndv[e.pane], 'branch', e.branchIndex);
|
||||||
|
},
|
||||||
setNDVPanelDataIsEmpty(state: IUiState, payload: {panel: 'input' | 'output', isEmpty: boolean}) {
|
setNDVPanelDataIsEmpty(state: IUiState, payload: {panel: 'input' | 'output', isEmpty: boolean}) {
|
||||||
Vue.set(state.ndv[payload.panel].data, 'isEmpty', payload.isEmpty);
|
Vue.set(state.ndv[payload.panel].data, 'isEmpty', payload.isEmpty);
|
||||||
},
|
},
|
||||||
|
|||||||
159
packages/editor-ui/src/pairedItemUtils.ts
Normal file
159
packages/editor-ui/src/pairedItemUtils.ts
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import { INodeExecutionData, IPairedItemData, IRunData, ITaskData } from "n8n-workflow";
|
||||||
|
import { IExecutionResponse, TargetItem } from "./Interface";
|
||||||
|
import { isNotNull } from "./typeGuards";
|
||||||
|
|
||||||
|
export function getPairedItemId(node: string, run: number, output: number, item: number): string {
|
||||||
|
return `${node}_r${run}_o${output}_i${item}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getSourceItems(data: IExecutionResponse, target: TargetItem): TargetItem[] {
|
||||||
|
if (!data?.data?.resultData?.runData) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const runData = data.data.resultData.runData;
|
||||||
|
const taskData: ITaskData | undefined = runData[target.nodeName]?.[target.runIndex];
|
||||||
|
const source = taskData?.source || [];
|
||||||
|
if (source.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = taskData?.data?.main?.[target.outputIndex]?.[target.itemIndex];
|
||||||
|
if (!item || item.pairedItem === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const pairedItem: IPairedItemData[] = Array.isArray(item.pairedItem) ? item.pairedItem : (typeof item.pairedItem === 'object' ? [item.pairedItem] : [{item: item.pairedItem}]);
|
||||||
|
const sourceItems = pairedItem.map((item) => {
|
||||||
|
const input = item.input || 0;
|
||||||
|
return {
|
||||||
|
nodeName: source?.[input]?.previousNode,
|
||||||
|
runIndex: source?.[input]?.previousNodeRun || 0,
|
||||||
|
itemIndex: item.item,
|
||||||
|
outputIndex: source[input]?.previousNodeOutput || 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return sourceItems.filter((item): item is TargetItem => isNotNull(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPairing(paths: {[item: string]: string[][]}, pairedItemId: string, pairedItem: IPairedItemData, sources: ITaskData['source']) {
|
||||||
|
paths[pairedItemId] = paths[pairedItemId] || [];
|
||||||
|
|
||||||
|
const input = pairedItem.input || 0;
|
||||||
|
const sourceNode = sources[input]?.previousNode;
|
||||||
|
if (!sourceNode) { // trigger nodes for example
|
||||||
|
paths[pairedItemId].push([pairedItemId]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const sourceNodeOutput = sources[input]?.previousNodeOutput || 0;
|
||||||
|
const sourceNodeRun = sources[input]?.previousNodeRun || 0;
|
||||||
|
|
||||||
|
const sourceItem = getPairedItemId(sourceNode, sourceNodeRun, sourceNodeOutput, pairedItem.item);
|
||||||
|
if (!paths[sourceItem]) {
|
||||||
|
paths[sourceItem] = [[sourceItem]]; // pinned data case
|
||||||
|
}
|
||||||
|
paths[sourceItem]?.forEach((path) => {
|
||||||
|
paths?.[pairedItemId]?.push([...path, pairedItemId]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPairedItemIdsRec(node: string, runIndex: number, runData: IRunData, seen: Set<string>, paths: {[item: string]: string[][]}, pinned: Set<string>) {
|
||||||
|
const key = `${node}_r${runIndex}`;
|
||||||
|
if (seen.has(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen.add(key);
|
||||||
|
|
||||||
|
if (pinned.has(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeRunData = runData[node];
|
||||||
|
if (!Array.isArray(nodeRunData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = nodeRunData[runIndex];
|
||||||
|
if (!data?.data?.main) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sources = data.source || [];
|
||||||
|
sources.forEach((source) => {
|
||||||
|
if (source?.previousNode) {
|
||||||
|
addPairedItemIdsRec(source.previousNode, source.previousNodeRun ?? 0, runData, seen, paths, pinned);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mainData = data.data.main || [];
|
||||||
|
mainData.forEach((outputData, output: number) => {
|
||||||
|
if (!outputData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputData.forEach((executionData, item: number) => {
|
||||||
|
const pairedItemId = getPairedItemId(node, runIndex, output, item);
|
||||||
|
if (!executionData.pairedItem) {
|
||||||
|
paths[pairedItemId] = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pairedItem = executionData.pairedItem;
|
||||||
|
if (Array.isArray(pairedItem)) {
|
||||||
|
pairedItem.forEach((item) => {
|
||||||
|
addPairing(paths, pairedItemId, item, sources);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof pairedItem === 'object') {
|
||||||
|
addPairing(paths, pairedItemId, pairedItem, sources);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPairing(paths, pairedItemId, {item: pairedItem}, sources);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMapping(paths: {[item: string]: string[][]}): {[item: string]: Set<string>} {
|
||||||
|
const mapping: {[itemId: string]: Set<string>} = {};
|
||||||
|
|
||||||
|
Object.keys(paths).forEach((item) => {
|
||||||
|
paths?.[item]?.forEach((path) => {
|
||||||
|
path.forEach((otherItem) => {
|
||||||
|
if (otherItem !== item) {
|
||||||
|
mapping[otherItem] = mapping[otherItem] || new Set();
|
||||||
|
mapping[otherItem].add(item);
|
||||||
|
|
||||||
|
mapping[item] = mapping[item] || new Set();
|
||||||
|
mapping[item].add(otherItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPairedItemsMapping(executionResponse: IExecutionResponse | null): {[itemId: string]: Set<string>} {
|
||||||
|
if (!executionResponse?.data?.resultData?.runData) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set<string>();
|
||||||
|
const runData = executionResponse.data.resultData.runData;
|
||||||
|
|
||||||
|
const pinned = new Set(Object.keys(executionResponse.data.resultData.pinData || {}));
|
||||||
|
|
||||||
|
const paths: {[item: string]: string[][]} = {};
|
||||||
|
Object.keys(runData).forEach((node) => {
|
||||||
|
runData[node].forEach((_, runIndex: number) => {
|
||||||
|
addPairedItemIdsRec(node, runIndex, runData, seen, paths, pinned);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return getMapping(paths);
|
||||||
|
}
|
||||||
@@ -124,11 +124,11 @@ export class I18nClass {
|
|||||||
* Hint for a top-level param.
|
* Hint for a top-level param.
|
||||||
*/
|
*/
|
||||||
hint(
|
hint(
|
||||||
{ name: parameterName, hint }: { name: string; hint: string; },
|
{ name: parameterName, hint }: { name: string; hint?: string; },
|
||||||
) {
|
) {
|
||||||
return context.dynamicRender({
|
return context.dynamicRender({
|
||||||
key: `${credentialPrefix}.${parameterName}.hint`,
|
key: `${credentialPrefix}.${parameterName}.hint`,
|
||||||
fallback: hint,
|
fallback: hint || '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -174,11 +174,11 @@ export class I18nClass {
|
|||||||
* Placeholder for a `string` param.
|
* Placeholder for a `string` param.
|
||||||
*/
|
*/
|
||||||
placeholder(
|
placeholder(
|
||||||
{ name: parameterName, placeholder }: { name: string; placeholder: string; },
|
{ name: parameterName, placeholder }: { name: string; placeholder?: string; },
|
||||||
) {
|
) {
|
||||||
return context.dynamicRender({
|
return context.dynamicRender({
|
||||||
key: `${credentialPrefix}.${parameterName}.placeholder`,
|
key: `${credentialPrefix}.${parameterName}.placeholder`,
|
||||||
fallback: placeholder,
|
fallback: placeholder || '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -247,7 +247,7 @@ export class I18nClass {
|
|||||||
* - For a `collection` or `fixedCollection`, the placeholder is the button text.
|
* - For a `collection` or `fixedCollection`, the placeholder is the button text.
|
||||||
*/
|
*/
|
||||||
placeholder(
|
placeholder(
|
||||||
parameter: { name: string; placeholder: string; type: string },
|
parameter: { name: string; placeholder?: string; type: string },
|
||||||
path: string,
|
path: string,
|
||||||
) {
|
) {
|
||||||
let middleKey = parameter.name;
|
let middleKey = parameter.name;
|
||||||
@@ -259,7 +259,7 @@ export class I18nClass {
|
|||||||
|
|
||||||
return context.dynamicRender({
|
return context.dynamicRender({
|
||||||
key: `${initialKey}.${middleKey}.placeholder`,
|
key: `${initialKey}.${middleKey}.placeholder`,
|
||||||
fallback: parameter.placeholder,
|
fallback: parameter.placeholder || '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -635,6 +635,8 @@
|
|||||||
"onboardingWorkflow.stickyContent": "## 👇 Get started faster \nLightning tour of the key concepts [3 min] \n\n[](https://www.youtube.com/watch?v=RpjQTGKm-ok)",
|
"onboardingWorkflow.stickyContent": "## 👇 Get started faster \nLightning tour of the key concepts [3 min] \n\n[](https://www.youtube.com/watch?v=RpjQTGKm-ok)",
|
||||||
"openWorkflow.workflowImportError": "Could not import workflow",
|
"openWorkflow.workflowImportError": "Could not import workflow",
|
||||||
"openWorkflow.workflowNotFoundError": "Could not find workflow",
|
"openWorkflow.workflowNotFoundError": "Could not find workflow",
|
||||||
|
"parameterInput.expressionResult": "e.g. {result}",
|
||||||
|
"parameterInput.emptyString": "[empty]",
|
||||||
"parameterInput.customApiCall": "Custom API Call",
|
"parameterInput.customApiCall": "Custom API Call",
|
||||||
"parameterInput.error": "ERROR",
|
"parameterInput.error": "ERROR",
|
||||||
"parameterInput.expression": "Expression",
|
"parameterInput.expression": "Expression",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import Vuex from 'vuex';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
||||||
DEFAULT_NODETYPE_VERSION,
|
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -48,6 +47,7 @@ import {stringSizeInBytes} from "@/components/helpers";
|
|||||||
import {dataPinningEventBus} from "@/event-bus/data-pinning-event-bus";
|
import {dataPinningEventBus} from "@/event-bus/data-pinning-event-bus";
|
||||||
import communityNodes from './modules/communityNodes';
|
import communityNodes from './modules/communityNodes';
|
||||||
import { isJsonKeyObject } from './utils';
|
import { isJsonKeyObject } from './utils';
|
||||||
|
import { getPairedItemsMapping } from './pairedItemUtils';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ const state: IRootState = {
|
|||||||
oauthCallbackUrls: {},
|
oauthCallbackUrls: {},
|
||||||
n8nMetadata: {},
|
n8nMetadata: {},
|
||||||
workflowExecutionData: null,
|
workflowExecutionData: null,
|
||||||
|
workflowExecutionPairedItemMappings: {},
|
||||||
lastSelectedNode: null,
|
lastSelectedNode: null,
|
||||||
lastSelectedNodeOutputIndex: null,
|
lastSelectedNodeOutputIndex: null,
|
||||||
nodeViewOffsetPosition: [0, 0],
|
nodeViewOffsetPosition: [0, 0],
|
||||||
@@ -379,6 +380,8 @@ export const store = new Vuex.Store({
|
|||||||
Vue.set(state.workflow.pinData, nameData.new, state.workflow.pinData[nameData.old]);
|
Vue.set(state.workflow.pinData, nameData.new, state.workflow.pinData[nameData.old]);
|
||||||
Vue.delete(state.workflow.pinData, nameData.old);
|
Vue.delete(state.workflow.pinData, nameData.old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.workflowExecutionPairedItemMappings = getPairedItemsMapping(state.workflowExecutionData);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetAllNodesIssues(state) {
|
resetAllNodesIssues(state) {
|
||||||
@@ -633,6 +636,7 @@ export const store = new Vuex.Store({
|
|||||||
|
|
||||||
setWorkflowExecutionData(state, workflowResultData: IExecutionResponse | null) {
|
setWorkflowExecutionData(state, workflowResultData: IExecutionResponse | null) {
|
||||||
state.workflowExecutionData = workflowResultData;
|
state.workflowExecutionData = workflowResultData;
|
||||||
|
state.workflowExecutionPairedItemMappings = getPairedItemsMapping(state.workflowExecutionData);
|
||||||
},
|
},
|
||||||
addNodeExecutionData(state, pushData: IPushDataNodeExecuteAfter): void {
|
addNodeExecutionData(state, pushData: IPushDataNodeExecuteAfter): void {
|
||||||
if (state.workflowExecutionData === null || !state.workflowExecutionData.data) {
|
if (state.workflowExecutionData === null || !state.workflowExecutionData.data) {
|
||||||
@@ -642,6 +646,7 @@ export const store = new Vuex.Store({
|
|||||||
Vue.set(state.workflowExecutionData.data.resultData.runData, pushData.nodeName, []);
|
Vue.set(state.workflowExecutionData.data.resultData.runData, pushData.nodeName, []);
|
||||||
}
|
}
|
||||||
state.workflowExecutionData.data.resultData.runData[pushData.nodeName].push(pushData.data);
|
state.workflowExecutionData.data.resultData.runData[pushData.nodeName].push(pushData.data);
|
||||||
|
state.workflowExecutionPairedItemMappings = getPairedItemsMapping(state.workflowExecutionData);
|
||||||
},
|
},
|
||||||
clearNodeExecutionData(state, nodeName: string): void {
|
clearNodeExecutionData(state, nodeName: string): void {
|
||||||
if (state.workflowExecutionData === null || !state.workflowExecutionData.data) {
|
if (state.workflowExecutionData === null || !state.workflowExecutionData.data) {
|
||||||
@@ -709,6 +714,9 @@ export const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
workflowExecutionPairedItemMappings: (state): IRootState['workflowExecutionPairedItemMappings'] => {
|
||||||
|
return state.workflowExecutionPairedItemMappings;
|
||||||
|
},
|
||||||
executedNode: (state): string | undefined => {
|
executedNode: (state): string | undefined => {
|
||||||
return state.workflowExecutionData ? state.workflowExecutionData.executedNode : undefined;
|
return state.workflowExecutionData ? state.workflowExecutionData.executedNode : undefined;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ import { INodeParameterResourceLocator } from "n8n-workflow";
|
|||||||
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
||||||
return Boolean(typeof value === 'object' && value && 'mode' in value && 'value' in value);
|
return Boolean(typeof value === 'object' && value && 'mode' in value && 'value' in value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isNotNull<T>(value: T | null): value is T {
|
||||||
|
return value !== null;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user