mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
15 Commits
4334-conte
...
4396-fix-g
Author | SHA1 | Date | |
---|---|---|---|
|
33a978a246 | ||
|
861dc0c383 | ||
|
ee48a2f2bf | ||
|
680d5b8216 | ||
|
c9320c190d | ||
|
566c667c5d | ||
|
ec6e42e655 | ||
|
bba6b6f71d | ||
|
c261f6625a | ||
|
a489b270d1 | ||
|
51cb61940d | ||
|
6635ff9a69 | ||
|
41797f8cef | ||
|
797cea5394 | ||
|
2880d4120e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ docs
|
||||
.vscode
|
||||
.nyc_output
|
||||
sync.ffs_db
|
||||
package-lock.json
|
||||
|
@@ -151,7 +151,6 @@ module.exports = function(grunt) {
|
||||
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
||||
|
@@ -109,7 +109,7 @@
|
||||
"jquery-i18next": "1.2.1",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "4.3.0",
|
||||
"mermaid": "^9.4.3",
|
||||
"mermaid": "^10.4.0",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.2.2",
|
||||
"node-red-node-test-helper": "^0.3.2",
|
||||
|
@@ -1215,11 +1215,9 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Invalid JSON data: __error__",
|
||||
"invalid-json-prop": "__prop__: invalid JSON data: __error__",
|
||||
"invalid-expr": "Invalid JSONata expression: __error__",
|
||||
"invalid-prop": "Invalid property expression",
|
||||
"invalid-prop-prop": "__prop__: invalid property expression",
|
||||
"invalid-num": "Invalid number",
|
||||
"invalid-num-prop": "__prop__: invalid number",
|
||||
"invalid-regexp": "Invalid input pattern",
|
||||
"invalid-regex-prop": "__prop__: invalid input pattern",
|
||||
"missing-required-prop": "__prop__: property value missing",
|
||||
|
@@ -1215,11 +1215,8 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Données JSON invalides : __error__",
|
||||
"invalid-json-prop": "__prop__: données JSON invalides : __error__",
|
||||
"invalid-prop": "Expression de propriété non valide",
|
||||
"invalid-prop-prop": "__prop__: expression de propriété invalide",
|
||||
"invalid-num": "Numéro invalide",
|
||||
"invalid-num-prop": "__prop__: numéro invalide",
|
||||
"invalid-regexp": "Modèle d'entrée non valide",
|
||||
"invalid-regex-prop": "__prop__: modèle d'entrée non valide",
|
||||
"missing-required-prop": "__prop__: valeur de la propriété manquante",
|
||||
|
@@ -1215,11 +1215,8 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "JSONデータが不正: __error__",
|
||||
"invalid-json-prop": "__prop__: JSONデータが不正: __error__",
|
||||
"invalid-prop": "プロパティ式が不正",
|
||||
"invalid-prop-prop": "__prop__: プロパティ式が不正",
|
||||
"invalid-num": "数値が不正",
|
||||
"invalid-num-prop": "__prop__: 数値が不正",
|
||||
"invalid-regexp": "入力パターンが不正",
|
||||
"invalid-regex-prop": "__prop__: 入力パターンが不正",
|
||||
"missing-required-prop": "__prop__: プロパティが未設定",
|
||||
|
@@ -1186,11 +1186,8 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Dados JSON inválidos: __error__",
|
||||
"invalid-json-prop": "__prop__: dados JSON inválidos: __error__",
|
||||
"invalid-prop": "Expressão de propriedade inválida",
|
||||
"invalid-prop-prop": "__prop__: expressão de propriedade inválida",
|
||||
"invalid-num": "Número inválido",
|
||||
"invalid-num-prop": "__prop__: número inválido",
|
||||
"invalid-regexp": "Padrão de entrada inválido",
|
||||
"invalid-regex-prop": "__prop__: Padrão de entrada inválido",
|
||||
"missing-required-prop": "__prop__: valor de propriedade ausente",
|
||||
|
@@ -1199,11 +1199,8 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "无效的 JSON 数据: __error__",
|
||||
"invalid-json-prop": "__prop__: 无效的 JSON 数据: __error__",
|
||||
"invalid-prop": "无效的属性表达式",
|
||||
"invalid-prop-prop": "__prop__: 无效的属性表达式",
|
||||
"invalid-num": "无效的数字",
|
||||
"invalid-num-prop": "__prop__: 无效的数字",
|
||||
"invalid-regexp": "输入格式无效",
|
||||
"invalid-regex-prop": "__prop__: 输入格式无效",
|
||||
"missing-required-prop": "__prop__: 缺少属性值",
|
||||
|
@@ -115,8 +115,9 @@ RED.editor = (function() {
|
||||
var valid = validateNodeProperty(node, definition, prop, properties[prop]);
|
||||
if ((typeof valid) === "string") {
|
||||
result.push(valid);
|
||||
}
|
||||
else if(!valid) {
|
||||
} else if (Array.isArray(valid)) {
|
||||
result = result.concat(valid)
|
||||
} else if(!valid) {
|
||||
result.push(prop);
|
||||
}
|
||||
}
|
||||
@@ -165,7 +166,7 @@ RED.editor = (function() {
|
||||
// If the validator takes two arguments, it is a 3.x validator that
|
||||
// can return a String to mean 'invalid' and provide a reason
|
||||
if ((definition[property].validate.length === 2) &&
|
||||
((typeof valid) === "string")) {
|
||||
((typeof valid) === "string") || Array.isArray(valid)) {
|
||||
return valid;
|
||||
} else {
|
||||
// Otherwise, a 2.x returns a truth-like/false-like value that
|
||||
|
@@ -169,7 +169,7 @@
|
||||
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
|
||||
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
|
||||
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
|
||||
mermaid.init();
|
||||
RED.editor.mermaid.render()
|
||||
},200);
|
||||
})
|
||||
if (options.header) {
|
||||
@@ -178,7 +178,7 @@
|
||||
|
||||
if (value) {
|
||||
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
|
||||
mermaid.init();
|
||||
RED.editor.mermaid.render()
|
||||
}
|
||||
panels = RED.panels.create({
|
||||
id:"red-ui-editor-type-markdown-panels",
|
||||
|
53
packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js
vendored
Normal file
53
packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
RED.editor.mermaid = (function () {
|
||||
let initializing = false
|
||||
let loaded = false
|
||||
let pendingEvals = []
|
||||
let diagramIds = 0
|
||||
|
||||
function render(selector = '.mermaid') {
|
||||
// $(selector).hide()
|
||||
if (!loaded) {
|
||||
pendingEvals.push(selector)
|
||||
|
||||
if (!initializing) {
|
||||
initializing = true
|
||||
$.getScript(
|
||||
'vendor/mermaid/mermaid.min.js',
|
||||
function (data, stat, jqxhr) {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false
|
||||
})
|
||||
loaded = true
|
||||
while(pendingEvals.length > 0) {
|
||||
const pending = pendingEvals.shift()
|
||||
render(pending)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const nodes = document.querySelectorAll(selector)
|
||||
|
||||
nodes.forEach(async node => {
|
||||
if (!node.getAttribute('mermaid-processed')) {
|
||||
const mermaidContent = node.innerText
|
||||
node.setAttribute('mermaid-processed', true)
|
||||
try {
|
||||
const { svg } = await mermaid.render('mermaid-render-'+Date.now()+'-'+(diagramIds++), mermaidContent);
|
||||
node.innerHTML = svg
|
||||
} catch (err) {
|
||||
$('<div>').css({
|
||||
fontSize: '0.8em',
|
||||
border: '1px solid var(--red-ui-border-color-error)',
|
||||
padding: '5px',
|
||||
marginBottom: '10px',
|
||||
}).text(err.toString()).prependTo(node)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return {
|
||||
render: render,
|
||||
};
|
||||
})();
|
@@ -1,46 +0,0 @@
|
||||
// Mermaid diagram stub library for on-demand dynamic loading
|
||||
// Will be overwritten after script loading by $.getScript
|
||||
var mermaid = (function () {
|
||||
var enabled /* = undefined */;
|
||||
|
||||
var initializing = false;
|
||||
var initCalled = false;
|
||||
|
||||
function initialize(opt) {
|
||||
if (enabled === undefined) {
|
||||
if (RED.settings.markdownEditor &&
|
||||
RED.settings.markdownEditor.mermaid) {
|
||||
enabled = RED.settings.markdownEditor.mermaid.enabled;
|
||||
}
|
||||
else {
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
initializing = true;
|
||||
$.getScript("vendor/mermaid/mermaid.min.js",
|
||||
function (data, stat, jqxhr) {
|
||||
$(".mermaid").show();
|
||||
// invoke loaded mermaid API
|
||||
initializing = false;
|
||||
mermaid.initialize(opt);
|
||||
if (initCalled) {
|
||||
mermaid.init();
|
||||
initCalled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (initializing) {
|
||||
$(".mermaid").hide();
|
||||
initCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
initialize: initialize,
|
||||
init: init,
|
||||
};
|
||||
})();
|
@@ -166,7 +166,7 @@ RED.projects.settings = (function() {
|
||||
var description = addTargetToExternalLinks($('<span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(desc)+'">'+desc+'</span>')).appendTo(container);
|
||||
description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||
setTimeout(function () {
|
||||
mermaid.init();
|
||||
RED.editor.mermaid.render()
|
||||
}, 200);
|
||||
}
|
||||
|
||||
|
@@ -383,6 +383,7 @@ RED.sidebar.help = (function() {
|
||||
$(this).toggleClass('expanded',!isExpanded);
|
||||
})
|
||||
helpSection.parent().scrollTop(0);
|
||||
RED.editor.mermaid.render()
|
||||
}
|
||||
|
||||
function set(html,title) {
|
||||
|
@@ -464,7 +464,7 @@ RED.sidebar.info = (function() {
|
||||
}
|
||||
$(this).toggleClass('expanded',!isExpanded);
|
||||
});
|
||||
mermaid.init();
|
||||
RED.editor.mermaid.render()
|
||||
}
|
||||
|
||||
var tips = (function() {
|
||||
|
@@ -101,28 +101,8 @@ RED.utils = (function() {
|
||||
|
||||
renderer.code = function (code, lang) {
|
||||
if(lang === "mermaid") {
|
||||
// mermaid diagram rendering
|
||||
if (mermaidIsEnabled === undefined) {
|
||||
if (RED.settings.markdownEditor &&
|
||||
RED.settings.markdownEditor.mermaid) {
|
||||
mermaidIsEnabled = RED.settings.markdownEditor.mermaid.enabled;
|
||||
}
|
||||
else {
|
||||
mermaidIsEnabled = true;
|
||||
}
|
||||
}
|
||||
if (mermaidIsEnabled) {
|
||||
if (!mermaidIsInitialized) {
|
||||
mermaidIsInitialized = true;
|
||||
mermaid.initialize({startOnLoad:false});
|
||||
}
|
||||
return `<pre class='mermaid'>${code}</pre>`;
|
||||
}
|
||||
else {
|
||||
return `<details><summary>${RED._("markdownEditor.mermaid.summary")}</summary><pre><code>${code}</code></pre></details>`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return `<pre class='mermaid'>${code}</pre>`;
|
||||
} else {
|
||||
return "<pre><code>" +code +"</code></pre>";
|
||||
}
|
||||
};
|
||||
@@ -917,6 +897,51 @@ RED.utils = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a typed property is valid according to the type.
|
||||
* Returns true if valid.
|
||||
* Return String error message if invalid
|
||||
* @param {*} propertyType
|
||||
* @param {*} propertyValue
|
||||
* @returns true if valid, String if invalid
|
||||
*/
|
||||
function validateTypedProperty(propertyValue, propertyType, opt) {
|
||||
|
||||
let error
|
||||
if (propertyType === 'json') {
|
||||
try {
|
||||
JSON.parse(propertyValue);
|
||||
} catch(err) {
|
||||
error = RED._("validator.errors.invalid-json", {
|
||||
error: err.message
|
||||
})
|
||||
}
|
||||
} else if (propertyType === 'msg' || propertyType === 'flow' || propertyType === 'global' ) {
|
||||
if (!RED.utils.validatePropertyExpression(propertyValue)) {
|
||||
error = RED._("validator.errors.invalid-prop")
|
||||
}
|
||||
} else if (propertyType === 'num') {
|
||||
if (!/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(propertyValue)) {
|
||||
error = RED._("validator.errors.invalid-num")
|
||||
}
|
||||
} else if (propertyType === 'jsonata') {
|
||||
try {
|
||||
jsonata(propertyValue)
|
||||
} catch(err) {
|
||||
error = RED._("validator.errors.invalid-expr", {
|
||||
error: err.message
|
||||
})
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
if (opt && opt.label) {
|
||||
return opt.label+': '+error
|
||||
}
|
||||
return error
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function getMessageProperty(msg,expr) {
|
||||
var result = null;
|
||||
var msgPropParts;
|
||||
@@ -1451,6 +1476,7 @@ RED.utils = (function() {
|
||||
getDarkerColor: getDarkerColor,
|
||||
parseModuleList: parseModuleList,
|
||||
checkModuleAllowed: checkModuleAllowed,
|
||||
getBrowserInfo: getBrowserInfo
|
||||
getBrowserInfo: getBrowserInfo,
|
||||
validateTypedProperty: validateTypedProperty
|
||||
}
|
||||
})();
|
||||
|
@@ -43,43 +43,13 @@ RED.validators = {
|
||||
typedInput: function(ptypeName,isConfig,mopt) {
|
||||
return function(v, opt) {
|
||||
var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName];
|
||||
if (ptype === 'json') {
|
||||
try {
|
||||
JSON.parse(v);
|
||||
return true;
|
||||
} catch(err) {
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-json-prop", {
|
||||
error: err.message,
|
||||
prop: opt.label,
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-json", {
|
||||
error: err.message
|
||||
}) : false;
|
||||
}
|
||||
} else if (ptype === 'msg' || ptype === 'flow' || ptype === 'global' ) {
|
||||
if (RED.utils.validatePropertyExpression(v)) {
|
||||
return true;
|
||||
}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-prop-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-prop") : false;
|
||||
} else if (ptype === 'num') {
|
||||
if (/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v)) {
|
||||
return true;
|
||||
}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-num-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-num") : false;
|
||||
const result = RED.utils.validateTypedProperty(v, ptype, opt)
|
||||
if (result === true || opt) {
|
||||
// Valid, or opt provided - return result as-is
|
||||
return result
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// No opt - need to return false for backwards compatibilty
|
||||
return false
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
@@ -167,7 +167,33 @@
|
||||
label:RED._("node-red:common.label.payload"),
|
||||
validate: RED.validators.typedInput("propertyType", false)},
|
||||
propertyType: { value:"msg" },
|
||||
rules: {value:[{t:"eq", v:"", vt:"str"}]},
|
||||
rules: {
|
||||
value:[{t:"eq", v:"", vt:"str"}],
|
||||
validate: function (rules, opt) {
|
||||
let msg;
|
||||
const errors = []
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
const opt = { label: RED._('node-red:switch.label.rule')+' '+(i+1) }
|
||||
const r = rules[i];
|
||||
if (r.hasOwnProperty('v')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v,r.vt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
if (r.hasOwnProperty('v2')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v2,r.v2t,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
console.log(errors)
|
||||
return errors
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
checkall: {value:"true", required:true},
|
||||
repair: {value:false},
|
||||
outputs: {value:1}
|
||||
|
@@ -19,71 +19,42 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
function isInvalidProperty(v,vt) {
|
||||
if (/msg|flow|global/.test(vt)) {
|
||||
if (!RED.utils.validatePropertyExpression(v)) {
|
||||
return RED._("node-red:change.errors.invalid-prop", {
|
||||
property: v
|
||||
});
|
||||
}
|
||||
} else if (vt === "jsonata") {
|
||||
try{ jsonata(v); } catch(e) {
|
||||
return RED._("node-red:change.errors.invalid-expr", {
|
||||
error: e.message
|
||||
});
|
||||
}
|
||||
} else if (vt === "json") {
|
||||
try{ JSON.parse(v); } catch(e) {
|
||||
return RED._("node-red:change.errors.invalid-json-data", {
|
||||
error: e.message
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RED.nodes.registerType('change', {
|
||||
color: "#E2D96E",
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
rules:{value:[{t:"set",p:"payload",pt:"msg",to:"",tot:"str"}],validate: function(rules, opt) {
|
||||
var msg;
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
var r = rules[i];
|
||||
if (r.t === 'set') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
rules:{
|
||||
value:[{t:"set",p:"payload",pt:"msg",to:"",tot:"str"}],
|
||||
validate: function(rules, opt) {
|
||||
let msg;
|
||||
const errors = []
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
const opt = { label: RED._('node-red:change.label.rule')+' '+(i+1) }
|
||||
const r = rules[i];
|
||||
if (r.t === 'set' || r.t === 'change' || r.t === 'delete' || r.t === 'move') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.p,r.pt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
if (msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
if (r.t === 'set' || r.t === 'change' || r.t === 'move') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.to,r.tot,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
} else if (r.t === 'change') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
if(msg = isInvalidProperty(r.from,r.fromt)) {
|
||||
return msg;
|
||||
}
|
||||
if(msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
}
|
||||
} else if (r.t === 'delete') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
} else if (r.t === 'move') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
if (msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
if (r.t === 'change') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.from,r.fromt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
return errors
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}},
|
||||
},
|
||||
// legacy
|
||||
action: {value:""},
|
||||
property: {value:""},
|
||||
|
@@ -161,7 +161,8 @@ class Flow {
|
||||
for (let i = 0; i < configNodes.length; i++) {
|
||||
const node = this.flow.configs[configNodes[i]]
|
||||
if (node.type === 'global-config' && node.env) {
|
||||
const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, credentials.get(node.id))
|
||||
const globalCreds = credentials.get(node.id)?.map || {}
|
||||
const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, globalCreds)
|
||||
this._env = { ...this._env, ...nodeEnv }
|
||||
}
|
||||
}
|
||||
|
@@ -80,6 +80,7 @@ function mapEnvVarProperties(obj,prop,flow,config) {
|
||||
}
|
||||
|
||||
async function evaluateEnvProperties(flow, env, credentials) {
|
||||
credentials = credentials || {}
|
||||
const pendingEvaluations = []
|
||||
const evaluatedEnv = {}
|
||||
const envTypes = []
|
||||
@@ -112,6 +113,7 @@ async function evaluateEnvProperties(flow, env, credentials) {
|
||||
if (pendingEvaluations.length > 0) {
|
||||
await Promise.all(pendingEvaluations)
|
||||
}
|
||||
// Now loop over the env types and evaluate them properly
|
||||
for (let i = 0; i < envTypes.length; i++) {
|
||||
let { name, value, type } = envTypes[i]
|
||||
// If an env-var wants to lookup itself, delegate straight to the parent
|
||||
@@ -122,7 +124,17 @@ async function evaluateEnvProperties(flow, env, credentials) {
|
||||
if (evaluatedEnv.hasOwnProperty(value)) {
|
||||
value = evaluatedEnv[value]
|
||||
} else {
|
||||
value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null);
|
||||
value = redUtil.evaluateNodeProperty(value, type, {_flow: {
|
||||
// Provide a hook so when it tries to look up a flow setting,
|
||||
// we can insert the just-evaluated value which hasn't yet
|
||||
// been set on the flow object - otherwise delegate up to the flow
|
||||
getSetting: function(name) {
|
||||
if (evaluatedEnv.hasOwnProperty(name)){
|
||||
return evaluatedEnv[name]
|
||||
}
|
||||
return flow.getSetting(name)
|
||||
}
|
||||
}}, null, null);
|
||||
}
|
||||
evaluatedEnv[name] = value
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ var flowUtils = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/util");
|
||||
var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");
|
||||
var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
|
||||
var Node = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
|
||||
var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
|
||||
var hooks = NR_TEST_UTILS.require("@node-red/util/lib/hooks");
|
||||
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
|
||||
|
||||
@@ -61,6 +62,7 @@ describe('Flow', function() {
|
||||
this.scope = n.scope;
|
||||
var node = this;
|
||||
this.foo = n.foo;
|
||||
this.bar = n.bar;
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
@@ -1235,11 +1237,12 @@ describe('Flow', function() {
|
||||
})
|
||||
|
||||
describe("#env", function () {
|
||||
afterEach(() => {
|
||||
delete process.env.V0;
|
||||
delete process.env.V1;
|
||||
credentials.get.restore?.()
|
||||
})
|
||||
it("can instantiate a node with environment variable property values of group and tab", async function () {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
delete process.env.V1;
|
||||
})
|
||||
process.env.V0 = "gv0";
|
||||
process.env.V1 = "gv1";
|
||||
process.env.V3 = "gv3";
|
||||
@@ -1283,10 +1286,6 @@ describe('Flow', function() {
|
||||
});
|
||||
|
||||
it("can access environment variable property using $parent", async function () {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
delete process.env.V1;
|
||||
})
|
||||
process.env.V0 = "gv0";
|
||||
process.env.V1 = "gv1";
|
||||
var config = flowUtils.parseConfig([
|
||||
@@ -1321,9 +1320,6 @@ describe('Flow', function() {
|
||||
});
|
||||
|
||||
it("can define environment variable using JSONata", async function () {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
})
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab",env:[
|
||||
{"name": "V0", value: "1+2", type: "jsonata"}
|
||||
@@ -1346,9 +1342,6 @@ describe('Flow', function() {
|
||||
});
|
||||
|
||||
it("can access global environment variables defined as JSONata values", async function () {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
})
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab",env:[
|
||||
{"name": "V0", value: "1+2", type: "jsonata"}
|
||||
@@ -1370,15 +1363,21 @@ describe('Flow', function() {
|
||||
await flow.stop()
|
||||
});
|
||||
it("global flow can access global-config defined environment variables", async function () {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
sinon.stub(credentials,"get").callsFake(function(id) {
|
||||
if (id === 'gc') {
|
||||
return { map: { GC_CRED: 'gc_cred' }}
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
const config = flowUtils.parseConfig([
|
||||
{id:"gc", type:"global-config", env:[
|
||||
{"name": "GC0", value: "3+4", type: "jsonata"}
|
||||
{"name": "GC0", value: "3+4", type: "jsonata"},
|
||||
{"name": "GC_CRED", type: "cred"},
|
||||
|
||||
]},
|
||||
{id:"t1",type:"tab" },
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"${GC0}",wires:[]},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"${GC0}", bar:"${GC_CRED}", wires:[]},
|
||||
]);
|
||||
// Two-arg call - makes this the global flow that handles global-config nodes
|
||||
const globalFlow = Flow.create({getSetting:v=>process.env[v]},config);
|
||||
@@ -1390,6 +1389,7 @@ describe('Flow', function() {
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
activeNodes["1"].foo.should.equal(7);
|
||||
activeNodes["1"].bar.should.equal('gc_cred');
|
||||
|
||||
await flow.stop()
|
||||
await globalFlow.stop()
|
||||
|
Reference in New Issue
Block a user