From c2710f4f6f422875eca8e50d245dcc3763d22ff2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 20 Dec 2023 17:52:52 +0000 Subject: [PATCH 1/2] Add auto-complete for env vars --- .../src/js/ui/common/typedInput.js | 87 ++++++++++++++++++- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js index 36e90f9c6..7977d25f9 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js @@ -108,7 +108,87 @@ return matches; } } - + + function getEnvVars (obj, envVars = {}) { + let parent + if (obj.type === 'tab' || obj.type === 'subflow') { + RED.nodes.eachConfig(function (conf) { + if (conf.type === "global-config") { + parent = conf; + } + }) + } else if (obj.g) { + parent = RED.nodes.group(obj.g) + } else if (obj.z) { + parent = RED.nodes.workspace(obj.z) || RED.nodes.subflow(obj.z) + } + if (parent) { + getEnvVars(parent, envVars) + } + if (obj.env) { + obj.env.forEach(env => { + envVars[env.name] = obj + }) + } + return envVars + } + RED.pp = getEnvVars + const envAutoComplete = function (val) { + const editStack = RED.editor.getEditStack() + if (editStack.length === 0) { + done([]) + return + } + const editingNode = editStack.pop() + if (!editingNode) { + return [] + } + const envVarsMap = getEnvVars(editingNode) + const envVars = Object.keys(envVarsMap) + const matches = [] + const i = val.lastIndexOf('${') + let searchKey = val + let isSubkey = false + if (i > -1) { + if (val.lastIndexOf('}') < i) { + searchKey = val.substring(i+2) + isSubkey = true + } + } + envVars.forEach(v => { + let valMatch = getMatch(v, searchKey); + if (valMatch.found) { + const optSrc = envVarsMap[v] + const element = $('
',{style: "display: flex"}); + const valEl = $('
',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"}); + valEl.append(generateSpans(valMatch)) + valEl.appendTo(element) + + if (optSrc) { + const optEl = $('
').css({ "font-size": "0.8em" }); + let label + if (optSrc.type === 'global-config') { + label = RED._('sidebar.context.global') + } else if (optSrc.type === 'group') { + label = RED.utils.getNodeLabel(optSrc) || (RED._('sidebar.info.group') + ': '+optSrc.id) + } else { + label = RED.utils.getNodeLabel(optSrc) || optSrc.id + } + + optEl.append(generateSpans({ match: label })); + optEl.appendTo(element); + } + matches.push({ + value: isSubkey ? val + v + '}' : v, + label: element, + i: valMatch.index + }); + } + }) + matches.sort(function(A,B){return A.i-B.i}) + return matches + } + let contextKnownKeys = {} let contextCache = {} if (RED.events) { @@ -118,9 +198,7 @@ }); } - const contextAutoComplete = function(options) { - const getContextKeysFromRuntime = function(scope, store, searchKey, done) { contextKnownKeys[scope] = contextKnownKeys[scope] || {} contextKnownKeys[scope][store] = contextKnownKeys[scope][store] || new Set() @@ -365,7 +443,8 @@ env: { value: "env", label: "env variable", - icon: "red/images/typedInput/env.svg" + icon: "red/images/typedInput/env.svg", + autoComplete: envAutoComplete }, node: { value: "node", From 54e6d60fe56b47fd524842a2ec486af2047ffcd2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 5 Jan 2024 21:07:20 +0000 Subject: [PATCH 2/2] Add simple caching of env var lookup --- .../@node-red/editor-client/src/js/ui/common/typedInput.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js index 7977d25f9..5072a12ca 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js @@ -110,6 +110,10 @@ } function getEnvVars (obj, envVars = {}) { + contextKnownKeys.env = contextKnownKeys.env || {} + if (contextKnownKeys.env[obj.id]) { + return contextKnownKeys.env[obj.id] + } let parent if (obj.type === 'tab' || obj.type === 'subflow') { RED.nodes.eachConfig(function (conf) { @@ -130,9 +134,10 @@ envVars[env.name] = obj }) } + contextKnownKeys.env[obj.id] = envVars return envVars } - RED.pp = getEnvVars + const envAutoComplete = function (val) { const editStack = RED.editor.getEditStack() if (editStack.length === 0) {