mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add support for credential-stored env var in subflow
This commit is contained in:
parent
87b9b56b65
commit
cd210d9fbf
@ -398,6 +398,10 @@ RED.nodes = (function() {
|
|||||||
paletteLabel: function() { return RED.nodes.subflow(sf.id).name },
|
paletteLabel: function() { return RED.nodes.subflow(sf.id).name },
|
||||||
inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null },
|
inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null },
|
||||||
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
|
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
|
||||||
|
oneditprepare: function() {
|
||||||
|
RED.subflow.buildEditForm("subflow",this);
|
||||||
|
RED.subflow.buildPropertiesForm(this);
|
||||||
|
},
|
||||||
oneditresize: function(size) {
|
oneditresize: function(size) {
|
||||||
// var rows = $(".dialog-form>div:not(.node-input-env-container-row)");
|
// var rows = $(".dialog-form>div:not(.node-input-env-container-row)");
|
||||||
var height = size.height;
|
var height = size.height;
|
||||||
@ -505,19 +509,33 @@ RED.nodes = (function() {
|
|||||||
node[d] = n[d];
|
node[d] = n[d];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(exportCreds && n.credentials) {
|
if (exportCreds) {
|
||||||
var credentialSet = {};
|
var credentialSet = {};
|
||||||
node.credentials = {};
|
if (/^subflow:/.test(node.type) && n.credentials) {
|
||||||
for (var cred in n._def.credentials) {
|
// A subflow instance node can have arbitrary creds
|
||||||
if (n._def.credentials.hasOwnProperty(cred)) {
|
for (var sfCred in n.credentials) {
|
||||||
if (n._def.credentials[cred].type == 'password') {
|
if (n.credentials.hasOwnProperty(sfCred)) {
|
||||||
if (!n.credentials._ ||
|
if (!n.credentials._ ||
|
||||||
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
|
||||||
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
|
||||||
|
credentialSet[sfCred] = n.credentials[sfCred];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (n.credentials) {
|
||||||
|
node.credentials = {};
|
||||||
|
// All other nodes have a well-defined list of possible credentials
|
||||||
|
for (var cred in n._def.credentials) {
|
||||||
|
if (n._def.credentials.hasOwnProperty(cred)) {
|
||||||
|
if (n._def.credentials[cred].type == 'password') {
|
||||||
|
if (!n.credentials._ ||
|
||||||
|
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
||||||
|
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
||||||
|
credentialSet[cred] = n.credentials[cred];
|
||||||
|
}
|
||||||
|
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
|
||||||
credentialSet[cred] = n.credentials[cred];
|
credentialSet[cred] = n.credentials[cred];
|
||||||
}
|
}
|
||||||
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
|
|
||||||
credentialSet[cred] = n.credentials[cred];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -568,7 +586,8 @@ RED.nodes = (function() {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertSubflow(n) {
|
function convertSubflow(n, exportCreds) {
|
||||||
|
exportCreds = true;
|
||||||
var node = {};
|
var node = {};
|
||||||
node.id = n.id;
|
node.id = n.id;
|
||||||
node.type = n.type;
|
node.type = n.type;
|
||||||
@ -578,6 +597,24 @@ RED.nodes = (function() {
|
|||||||
node.in = [];
|
node.in = [];
|
||||||
node.out = [];
|
node.out = [];
|
||||||
node.env = n.env;
|
node.env = n.env;
|
||||||
|
|
||||||
|
if (exportCreds) {
|
||||||
|
var credentialSet = {};
|
||||||
|
// A subflow node can have arbitrary creds
|
||||||
|
for (var sfCred in n.credentials) {
|
||||||
|
if (n.credentials.hasOwnProperty(sfCred)) {
|
||||||
|
if (!n.credentials._ ||
|
||||||
|
n.credentials["has_"+sfCred] != n.credentials._["has_"+sfCred] ||
|
||||||
|
(n.credentials["has_"+sfCred] && n.credentials[sfCred])) {
|
||||||
|
credentialSet[sfCred] = n.credentials[sfCred];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(credentialSet).length > 0) {
|
||||||
|
node.credentials = credentialSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node.color = n.color;
|
node.color = n.color;
|
||||||
|
|
||||||
n.in.forEach(function(p) {
|
n.in.forEach(function(p) {
|
||||||
@ -693,7 +730,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
for (i in subflows) {
|
for (i in subflows) {
|
||||||
if (subflows.hasOwnProperty(i)) {
|
if (subflows.hasOwnProperty(i)) {
|
||||||
nns.push(convertSubflow(subflows[i]));
|
nns.push(convertSubflow(subflows[i], exportCredentials));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i in configNodes) {
|
for (i in configNodes) {
|
||||||
|
@ -490,8 +490,7 @@ RED.editor = (function() {
|
|||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (definition.credentials || /^subflow:/.test(definition.type)) {
|
||||||
if (definition.credentials) {
|
|
||||||
if (node.credentials) {
|
if (node.credentials) {
|
||||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||||
completePrepare();
|
completePrepare();
|
||||||
@ -499,7 +498,9 @@ RED.editor = (function() {
|
|||||||
$.getJSON(getCredentialsURL(node.type, node.id), function (data) {
|
$.getJSON(getCredentialsURL(node.type, node.id), function (data) {
|
||||||
node.credentials = data;
|
node.credentials = data;
|
||||||
node.credentials._ = $.extend(true,{},data);
|
node.credentials._ = $.extend(true,{},data);
|
||||||
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
if (!/^subflow:/.test(definition.type)) {
|
||||||
|
populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
|
||||||
|
}
|
||||||
completePrepare();
|
completePrepare();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -576,8 +577,11 @@ RED.editor = (function() {
|
|||||||
$(this).attr("data-i18n",keys.join(";"));
|
$(this).attr("data-i18n",keys.join(";"));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (type === "subflow-template" || type === "subflow") {
|
if (type === "subflow-template") {
|
||||||
RED.subflow.buildEditForm(dialogForm,type,node);
|
// This is the 'edit properties' dialog for a subflow template
|
||||||
|
// TODO: this needs to happen later in the dialog open sequence
|
||||||
|
// so that credentials can be loaded prior to building the form
|
||||||
|
RED.subflow.buildEditForm(type,node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add dummy fields to prevent 'Enter' submitting the form in some
|
// Add dummy fields to prevent 'Enter' submitting the form in some
|
||||||
@ -1471,6 +1475,19 @@ RED.editor = (function() {
|
|||||||
if (type === "subflow") {
|
if (type === "subflow") {
|
||||||
var old_env = editing_node.env;
|
var old_env = editing_node.env;
|
||||||
var new_env = RED.subflow.exportSubflowInstanceEnv(editing_node);
|
var new_env = RED.subflow.exportSubflowInstanceEnv(editing_node);
|
||||||
|
if (new_env && new_env.length > 0) {
|
||||||
|
new_env.forEach(function(prop) {
|
||||||
|
if (prop.type === "cred") {
|
||||||
|
editing_node.credentials = editing_node.credentials || {_:{}};
|
||||||
|
editing_node.credentials[prop.name] = prop.value;
|
||||||
|
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
|
||||||
|
if (prop.value !== '__PWRD__') {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
delete prop.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!isSameObj(old_env, new_env)) {
|
if (!isSameObj(old_env, new_env)) {
|
||||||
editing_node.env = new_env;
|
editing_node.env = new_env;
|
||||||
changes.env = editing_node.env;
|
changes.env = editing_node.env;
|
||||||
@ -1599,12 +1616,13 @@ RED.editor = (function() {
|
|||||||
id: "editor-subflow-envProperties",
|
id: "editor-subflow-envProperties",
|
||||||
label: RED._("editor-tab.envProperties"),
|
label: RED._("editor-tab.envProperties"),
|
||||||
name: RED._("editor-tab.envProperties"),
|
name: RED._("editor-tab.envProperties"),
|
||||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
content: $('<div>', {id:"editor-subflow-envProperties-content",class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||||
iconClass: "fa fa-list"
|
iconClass: "fa fa-list"
|
||||||
};
|
};
|
||||||
|
|
||||||
RED.subflow.buildPropertiesForm(subflowPropertiesTab.content,node);
|
|
||||||
editorTabs.addTab(subflowPropertiesTab);
|
editorTabs.addTab(subflowPropertiesTab);
|
||||||
|
// This tab is populated by the oneditprepare function of this
|
||||||
|
// subflow. That ensures it is done *after* any credentials
|
||||||
|
// have been loaded for the instance.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
||||||
@ -2252,6 +2270,21 @@ RED.editor = (function() {
|
|||||||
|
|
||||||
var old_env = editing_node.env;
|
var old_env = editing_node.env;
|
||||||
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
|
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
|
||||||
|
|
||||||
|
if (new_env && new_env.length > 0) {
|
||||||
|
new_env.forEach(function(prop) {
|
||||||
|
if (prop.type === "cred") {
|
||||||
|
editing_node.credentials = editing_node.credentials || {_:{}};
|
||||||
|
editing_node.credentials[prop.name] = prop.value;
|
||||||
|
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
|
||||||
|
if (prop.value !== '__PWRD__') {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
delete prop.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!isSameObj(old_env, new_env)) {
|
if (!isSameObj(old_env, new_env)) {
|
||||||
editing_node.env = new_env;
|
editing_node.env = new_env;
|
||||||
changes.env = editing_node.env;
|
changes.env = editing_node.env;
|
||||||
@ -2311,7 +2344,7 @@ RED.editor = (function() {
|
|||||||
$("#node-input-env-container").editableList('height',height-95);
|
$("#node-input-env-container").editableList('height',height-95);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
open: function(tray) {
|
open: function(tray, done) {
|
||||||
var trayFooter = tray.find(".red-ui-tray-footer");
|
var trayFooter = tray.find(".red-ui-tray-footer");
|
||||||
var trayFooterLeft = $("<div/>", {
|
var trayFooterLeft = $("<div/>", {
|
||||||
class: "red-ui-tray-footer-left"
|
class: "red-ui-tray-footer-left"
|
||||||
@ -2362,7 +2395,6 @@ RED.editor = (function() {
|
|||||||
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
content: $('<div>', {class:"red-ui-tray-content"}).appendTo(editorContent).hide(),
|
||||||
iconClass: "fa fa-cog"
|
iconClass: "fa fa-cog"
|
||||||
};
|
};
|
||||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
|
||||||
editorTabs.addTab(nodePropertiesTab);
|
editorTabs.addTab(nodePropertiesTab);
|
||||||
|
|
||||||
var descriptionTab = {
|
var descriptionTab = {
|
||||||
@ -2391,11 +2423,18 @@ RED.editor = (function() {
|
|||||||
buildAppearanceForm(appearanceTab.content,editing_node);
|
buildAppearanceForm(appearanceTab.content,editing_node);
|
||||||
editorTabs.addTab(appearanceTab);
|
editorTabs.addTab(appearanceTab);
|
||||||
|
|
||||||
$("#subflow-input-name").val(subflow.name);
|
$.getJSON(getCredentialsURL("subflow", subflow.id), function (data) {
|
||||||
RED.text.bidi.prepareInput($("#subflow-input-name"));
|
subflow.credentials = data;
|
||||||
|
subflow.credentials._ = $.extend(true,{},data);
|
||||||
|
|
||||||
trayBody.i18n();
|
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
||||||
finishedBuilding = true;
|
$("#subflow-input-name").val(subflow.name);
|
||||||
|
RED.text.bidi.prepareInput($("#subflow-input-name"));
|
||||||
|
|
||||||
|
trayBody.i18n();
|
||||||
|
finishedBuilding = true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||||
|
@ -770,7 +770,7 @@ RED.subflow = (function() {
|
|||||||
/**
|
/**
|
||||||
* Create interface for controlling env var UI definition
|
* Create interface for controlling env var UI definition
|
||||||
*/
|
*/
|
||||||
function buildEnvControl(envList) {
|
function buildEnvControl(envList,node) {
|
||||||
|
|
||||||
var tabs = RED.tabs.create({
|
var tabs = RED.tabs.create({
|
||||||
id: "subflow-env-tabs",
|
id: "subflow-env-tabs",
|
||||||
@ -779,7 +779,7 @@ RED.subflow = (function() {
|
|||||||
var inputContainer = $("#subflow-input-ui");
|
var inputContainer = $("#subflow-input-ui");
|
||||||
var list = envList.editableList("items");
|
var list = envList.editableList("items");
|
||||||
var exportedEnv = exportEnvList(list, true);
|
var exportedEnv = exportEnvList(list, true);
|
||||||
buildEnvUI(inputContainer, exportedEnv);
|
buildEnvUI(inputContainer, exportedEnv,node);
|
||||||
}
|
}
|
||||||
$("#subflow-env-tabs-content").children().hide();
|
$("#subflow-env-tabs-content").children().hide();
|
||||||
$("#" + tab.id).show();
|
$("#" + tab.id).show();
|
||||||
@ -831,6 +831,9 @@ RED.subflow = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||||
|
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create env var edit interface
|
* Create env var edit interface
|
||||||
* @param container - container
|
* @param container - container
|
||||||
@ -841,7 +844,7 @@ RED.subflow = (function() {
|
|||||||
var isTemplateNode = (node.type === "subflow");
|
var isTemplateNode = (node.type === "subflow");
|
||||||
|
|
||||||
if (isTemplateNode) {
|
if (isTemplateNode) {
|
||||||
buildEnvControl(envContainer);
|
buildEnvControl(envContainer, node);
|
||||||
}
|
}
|
||||||
envContainer
|
envContainer
|
||||||
.css({
|
.css({
|
||||||
@ -851,6 +854,9 @@ RED.subflow = (function() {
|
|||||||
.editableList({
|
.editableList({
|
||||||
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
||||||
addItem: function(container, i, opt) {
|
addItem: function(container, i, opt) {
|
||||||
|
// If this is an instance node, these are properties unique to
|
||||||
|
// this instance - ie opt.parent will not be defined.
|
||||||
|
|
||||||
if (isTemplateNode) {
|
if (isTemplateNode) {
|
||||||
container.addClass("red-ui-editor-subflow-env-editable")
|
container.addClass("red-ui-editor-subflow-env-editable")
|
||||||
}
|
}
|
||||||
@ -859,52 +865,64 @@ RED.subflow = (function() {
|
|||||||
var nameField = null;
|
var nameField = null;
|
||||||
var valueField = null;
|
var valueField = null;
|
||||||
|
|
||||||
// if (opt.parent) {
|
nameField = $('<input/>', {
|
||||||
// buildEnvUIRow(envRow,opt,opt.parent.ui||{})
|
class: "node-input-env-name",
|
||||||
// } else {
|
type: "text",
|
||||||
nameField = $('<input/>', {
|
placeholder: RED._("common.label.name")
|
||||||
class: "node-input-env-name",
|
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
||||||
type: "text",
|
valueField = $('<input/>',{
|
||||||
placeholder: RED._("common.label.name")
|
style: "width:100%",
|
||||||
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
class: "node-input-env-value",
|
||||||
valueField = $('<input/>',{
|
type: "text",
|
||||||
style: "width:100%",
|
}).attr("autocomplete","disable").appendTo(envRow)
|
||||||
class: "node-input-env-value",
|
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||||
type: "text",
|
valueField.typedInput('type', opt.type);
|
||||||
}).attr("autocomplete","disable").appendTo(envRow)
|
if (opt.type === "cred") {
|
||||||
valueField.typedInput({default:'str',types:['str','num','bool','json','bin','env']});
|
if (opt.value) {
|
||||||
valueField.typedInput('type', opt.parent?(opt.type||opt.parent.type):opt.type);
|
valueField.typedInput('value', opt.value);
|
||||||
valueField.typedInput('value', opt.parent?((opt.value !== undefined)?opt.value:opt.parent.value):opt.value);
|
} else if (node.credentials && node.credentials[opt.name]) {
|
||||||
// }
|
valueField.typedInput('value', node.credentials[opt.name]);
|
||||||
|
} else if (node.credentials && node.credentials['has_'+opt.name]) {
|
||||||
|
valueField.typedInput('value', "__PWRD__");
|
||||||
|
} else {
|
||||||
|
valueField.typedInput('value', "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valueField.typedInput('value', opt.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
opt.nameField = nameField;
|
opt.nameField = nameField;
|
||||||
opt.valueField = valueField;
|
opt.valueField = valueField;
|
||||||
|
|
||||||
if (!opt.parent) {
|
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
||||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
actionButton.on("click", function(evt) {
|
||||||
actionButton.on("click", function(evt) {
|
evt.preventDefault();
|
||||||
evt.preventDefault();
|
removeTip.close();
|
||||||
removeTip.close();
|
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
container.fadeOut(300, function() {
|
||||||
container.fadeOut(300, function() {
|
envContainer.editableList('removeItem',opt);
|
||||||
envContainer.editableList('removeItem',opt);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
if (isTemplateNode) {
|
if (isTemplateNode) {
|
||||||
// Add the UI customisation row
|
// Add the UI customisation row
|
||||||
// if `opt.ui` does not exist, then apply defaults. If these
|
// if `opt.ui` does not exist, then apply defaults. If these
|
||||||
// defaults do not change then they will get stripped off
|
// defaults do not change then they will get stripped off
|
||||||
// before saving.
|
// before saving.
|
||||||
opt.ui = opt.ui || {
|
if (opt.type === 'cred') {
|
||||||
icon: "",
|
opt.ui = opt.ui || {
|
||||||
label: {},
|
icon: "",
|
||||||
type: "input",
|
type: "cred"
|
||||||
opts: {types:['str','num','bool','json','bin','env']}
|
}
|
||||||
|
} else {
|
||||||
|
opt.ui = opt.ui || {
|
||||||
|
icon: "",
|
||||||
|
type: "input",
|
||||||
|
opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
opt.ui.label = opt.ui.label || {};
|
opt.ui.label = opt.ui.label || {};
|
||||||
opt.ui.type = opt.ui.type || "input";
|
opt.ui.type = opt.ui.type || "input";
|
||||||
@ -995,11 +1013,11 @@ RED.subflow = (function() {
|
|||||||
|
|
||||||
var row = $('<div></div>').appendTo(container);
|
var row = $('<div></div>').appendTo(container);
|
||||||
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
||||||
|
|
||||||
var typeOptions = {
|
var typeOptions = {
|
||||||
'input': {types:['str','num','bool','json','bin','env']},
|
'input': {types:DEFAULT_ENV_TYPE_LIST},
|
||||||
'select': {opts:[]},
|
'select': {opts:[]},
|
||||||
'spinner': {}
|
'spinner': {},
|
||||||
|
'cred': {}
|
||||||
};
|
};
|
||||||
if (ui.opts) {
|
if (ui.opts) {
|
||||||
typeOptions[ui.type] = ui.opts;
|
typeOptions[ui.type] = ui.opts;
|
||||||
@ -1054,7 +1072,7 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
langs.forEach(function(l) {
|
langs.forEach(function(l) {
|
||||||
var row = $('<div>').appendTo(content);
|
var row = $('<div>').appendTo(content);
|
||||||
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
||||||
$('<span>').text(ui.label[l]||"").appendTo(row);
|
$('<span>').text(ui.label[l]||"").appendTo(row);
|
||||||
});
|
});
|
||||||
return content;
|
return content;
|
||||||
@ -1062,314 +1080,341 @@ RED.subflow = (function() {
|
|||||||
|
|
||||||
nameField.on('change',function(evt) {
|
nameField.on('change',function(evt) {
|
||||||
labelInput.attr("placeholder",$(this).val())
|
labelInput.attr("placeholder",$(this).val())
|
||||||
});
|
});
|
||||||
|
|
||||||
var inputCell = $('<div></div>').appendTo(row);
|
var inputCell = $('<div></div>').appendTo(row);
|
||||||
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
||||||
if (ui.type === "input") {
|
if (ui.type === "input") {
|
||||||
inputCellInput.val(ui.opts.types.join(","));
|
inputCellInput.val(ui.opts.types.join(","));
|
||||||
}
|
}
|
||||||
var checkbox;
|
var checkbox;
|
||||||
var selectBox;
|
var selectBox;
|
||||||
|
|
||||||
inputCellInput.typedInput({
|
inputCellInput.typedInput({
|
||||||
types: [
|
types: [
|
||||||
{
|
{
|
||||||
value:"input",
|
value:"input",
|
||||||
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
||||||
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
||||||
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
||||||
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
||||||
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
||||||
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
||||||
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"}
|
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
|
||||||
],
|
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
|
||||||
default: ['str','num','bool','json','bin','env'],
|
],
|
||||||
valueLabel: function(container,value) {
|
default: DEFAULT_ENV_TYPE_LIST,
|
||||||
container.css("padding",0);
|
valueLabel: function(container,value) {
|
||||||
var innerContainer = $('<div>').css({
|
container.css("padding",0);
|
||||||
"background":"white",
|
var innerContainer = $('<div>').css({
|
||||||
"height":"100%",
|
"background":"white",
|
||||||
"box-sizing": "border-box"
|
"height":"100%",
|
||||||
}).appendTo(container);
|
"box-sizing": "border-box"
|
||||||
|
}).appendTo(container);
|
||||||
|
|
||||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||||
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
||||||
if (value.length) {
|
if (value.length) {
|
||||||
value.forEach(function(v) {
|
value.forEach(function(v) {
|
||||||
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 3px"}).appendTo(input);
|
if (!/^fa /.test(v.icon)) {
|
||||||
})
|
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||||
} else {
|
} else {
|
||||||
$("<span>").css({
|
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||||
"color":"#aaa",
|
$("<i>",{class: v.icon}).appendTo(s);
|
||||||
"padding-left": "4px"
|
}
|
||||||
}).text("select types...").appendTo(input);
|
})
|
||||||
}
|
} else {
|
||||||
}
|
$("<span>").css({
|
||||||
},
|
"color":"#aaa",
|
||||||
{
|
"padding-left": "4px"
|
||||||
value:"select",
|
}).text("select types...").appendTo(input);
|
||||||
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
}
|
||||||
valueLabel: function(container,value) {
|
}
|
||||||
container.css("padding","0");
|
},
|
||||||
|
{
|
||||||
|
value: "cred",
|
||||||
|
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
|
||||||
|
valueLabel: function(container,value) {
|
||||||
|
container.css("padding",0);
|
||||||
|
var innerContainer = $('<div>').css({
|
||||||
|
"background":"white",
|
||||||
|
"height":"100%",
|
||||||
|
"box-sizing": "border-box",
|
||||||
|
"border-top-right-radius": "4px",
|
||||||
|
"border-bottom-right-radius": "4px"
|
||||||
|
}).appendTo(container);
|
||||||
|
$('<div class="placeholder-input">').html("••••••••").appendTo(innerContainer);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value:"select",
|
||||||
|
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
||||||
|
valueLabel: function(container,value) {
|
||||||
|
container.css("padding","0");
|
||||||
|
|
||||||
selectBox = $('<select></select>').appendTo(container);
|
selectBox = $('<select></select>').appendTo(container);
|
||||||
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
||||||
ui.opts.opts.forEach(function(o) {
|
ui.opts.opts.forEach(function(o) {
|
||||||
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
||||||
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
||||||
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
selectBox.on('change', function(evt) {
|
selectBox.on('change', function(evt) {
|
||||||
var v = selectBox.val();
|
var v = selectBox.val();
|
||||||
// var parts = v.split(":");
|
// var parts = v.split(":");
|
||||||
// var t = parts.shift();
|
// var t = parts.shift();
|
||||||
// v = parts.join(":");
|
// v = parts.join(":");
|
||||||
//
|
//
|
||||||
// valueField.typedInput("type",'str')
|
// valueField.typedInput("type",'str')
|
||||||
valueField.typedInput("value",v)
|
valueField.typedInput("value",v)
|
||||||
});
|
});
|
||||||
selectBox.val(valueField.typedInput("value"));
|
selectBox.val(valueField.typedInput("value"));
|
||||||
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
||||||
},
|
},
|
||||||
expand: {
|
expand: {
|
||||||
icon: "fa-caret-down",
|
icon: "fa-caret-down",
|
||||||
minWidth: 400,
|
minWidth: 400,
|
||||||
content: function(container) {
|
content: function(container) {
|
||||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||||
var optList = $('<ol>').appendTo(content).editableList({
|
var optList = $('<ol>').appendTo(content).editableList({
|
||||||
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
||||||
addItem: function(row,index,itemData) {
|
addItem: function(row,index,itemData) {
|
||||||
var labelDiv = $('<div>').appendTo(row);
|
var labelDiv = $('<div>').appendTo(row);
|
||||||
var label = lookupLabel(itemData.l, "", currentLocale);
|
var label = lookupLabel(itemData.l, "", currentLocale);
|
||||||
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
||||||
itemData.label.on('keydown', function(evt) {
|
itemData.label.on('keydown', function(evt) {
|
||||||
if (evt.keyCode === 13) {
|
if (evt.keyCode === 13) {
|
||||||
itemData.input.focus();
|
itemData.input.focus();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
||||||
RED.popover.tooltip(labelIcon,function() {
|
RED.popover.tooltip(labelIcon,function() {
|
||||||
return currentLocale;
|
return currentLocale;
|
||||||
})
|
})
|
||||||
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
||||||
|
|
||||||
// Problem using a TI here:
|
// Problem using a TI here:
|
||||||
// - this is in a popout panel
|
// - this is in a popout panel
|
||||||
// - clicking the expand button in the TI will close the parent edit tray
|
// - clicking the expand button in the TI will close the parent edit tray
|
||||||
// and open the type editor.
|
// and open the type editor.
|
||||||
// - but it leaves the popout panel over the top.
|
// - but it leaves the popout panel over the top.
|
||||||
// - there is no way to get back to the popout panel after closing the type editor
|
// - there is no way to get back to the popout panel after closing the type editor
|
||||||
//.typedInput({default:itemData.t||'str', types:['str','num','bool','json','bin','env']});
|
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
|
||||||
itemData.input.on('keydown', function(evt) {
|
itemData.input.on('keydown', function(evt) {
|
||||||
if (evt.keyCode === 13) {
|
if (evt.keyCode === 13) {
|
||||||
// Enter or Tab
|
// Enter or Tab
|
||||||
var index = optList.editableList('indexOf',itemData);
|
var index = optList.editableList('indexOf',itemData);
|
||||||
var length = optList.editableList('length');
|
var length = optList.editableList('length');
|
||||||
if (index + 1 === length) {
|
if (index + 1 === length) {
|
||||||
var newItem = {};
|
var newItem = {};
|
||||||
optList.editableList('addItem',newItem);
|
optList.editableList('addItem',newItem);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (newItem.label) {
|
if (newItem.label) {
|
||||||
newItem.label.focus();
|
newItem.label.focus();
|
||||||
}
|
}
|
||||||
},100)
|
},100)
|
||||||
} else {
|
} else {
|
||||||
var nextItem = optList.editableList('getItemAt',index+1);
|
var nextItem = optList.editableList('getItemAt',index+1);
|
||||||
if (nextItem.label) {
|
if (nextItem.label) {
|
||||||
nextItem.label.focus()
|
nextItem.label.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sortable: true,
|
sortable: true,
|
||||||
removable: true,
|
removable: true,
|
||||||
height: 160
|
height: 160
|
||||||
})
|
})
|
||||||
if (ui.opts.opts.length > 0) {
|
if (ui.opts.opts.length > 0) {
|
||||||
ui.opts.opts.forEach(function(o) {
|
ui.opts.opts.forEach(function(o) {
|
||||||
optList.editableList('addItem',$.extend(true,{},o))
|
optList.editableList('addItem',$.extend(true,{},o))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
optList.editableList('addItem',{})
|
optList.editableList('addItem',{})
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
onclose: function() {
|
onclose: function() {
|
||||||
var items = optList.editableList('items');
|
var items = optList.editableList('items');
|
||||||
var vals = [];
|
var vals = [];
|
||||||
items.each(function (i,el) {
|
items.each(function (i,el) {
|
||||||
var data = el.data('data');
|
var data = el.data('data');
|
||||||
var l = data.label.val().trim();
|
var l = data.label.val().trim();
|
||||||
var v = data.input.val();
|
var v = data.input.val();
|
||||||
// var t = data.input.typedInput('type');
|
// var t = data.input.typedInput('type');
|
||||||
// var v = data.input.typedInput('value');
|
// var v = data.input.typedInput('value');
|
||||||
if (l.length > 0) {
|
if (l.length > 0) {
|
||||||
data.l = data.l || {};
|
data.l = data.l || {};
|
||||||
data.l[currentLocale] = l;
|
data.l[currentLocale] = l;
|
||||||
}
|
}
|
||||||
data.v = v;
|
data.v = v;
|
||||||
|
|
||||||
if (l.length > 0 || v.length > 0) {
|
if (l.length > 0 || v.length > 0) {
|
||||||
var val = {l:data.l,v:data.v};
|
var val = {l:data.l,v:data.v};
|
||||||
// if (t !== 'str') {
|
// if (t !== 'str') {
|
||||||
// val.t = t;
|
// val.t = t;
|
||||||
// }
|
// }
|
||||||
vals.push(val);
|
vals.push(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.opts.opts = vals;
|
ui.opts.opts = vals;
|
||||||
inputCellInput.typedInput('value',Date.now())
|
inputCellInput.typedInput('value',Date.now())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value:"checkbox",
|
value:"checkbox",
|
||||||
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
||||||
valueLabel: function(container,value) {
|
valueLabel: function(container,value) {
|
||||||
container.css("padding",0);
|
container.css("padding",0);
|
||||||
checkbox = $('<input type="checkbox">').appendTo(container);
|
checkbox = $('<input type="checkbox">').appendTo(container);
|
||||||
checkbox.on('change', function(evt) {
|
checkbox.on('change', function(evt) {
|
||||||
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
||||||
})
|
})
|
||||||
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value:"spinner",
|
value:"spinner",
|
||||||
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
||||||
valueLabel: function(container,value) {
|
valueLabel: function(container,value) {
|
||||||
container.css("padding",0);
|
container.css("padding",0);
|
||||||
var innerContainer = $('<div>').css({
|
var innerContainer = $('<div>').css({
|
||||||
"background":"white",
|
"background":"white",
|
||||||
"height":"100%",
|
"height":"100%",
|
||||||
"box-sizing": "border-box"
|
"box-sizing": "border-box"
|
||||||
}).appendTo(container);
|
}).appendTo(container);
|
||||||
|
|
||||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||||
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
||||||
|
|
||||||
var min = ui.opts && ui.opts.min;
|
var min = ui.opts && ui.opts.min;
|
||||||
var max = ui.opts && ui.opts.max;
|
var max = ui.opts && ui.opts.max;
|
||||||
var label = "";
|
var label = "";
|
||||||
if (min !== undefined && max !== undefined) {
|
if (min !== undefined && max !== undefined) {
|
||||||
label = Math.min(min,max)+" - "+Math.max(min,max);
|
label = Math.min(min,max)+" - "+Math.max(min,max);
|
||||||
} else if (min !== undefined) {
|
} else if (min !== undefined) {
|
||||||
label = "> "+min;
|
label = "> "+min;
|
||||||
} else if (max !== undefined) {
|
} else if (max !== undefined) {
|
||||||
label = "< "+max;
|
label = "< "+max;
|
||||||
}
|
}
|
||||||
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
||||||
},
|
},
|
||||||
expand: {
|
expand: {
|
||||||
icon: "fa-caret-down",
|
icon: "fa-caret-down",
|
||||||
content: function(container) {
|
content: function(container) {
|
||||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||||
content.css("padding","8px 5px")
|
content.css("padding","8px 5px")
|
||||||
var min = ui.opts.min;
|
var min = ui.opts.min;
|
||||||
var max = ui.opts.max;
|
var max = ui.opts.max;
|
||||||
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||||
minInput.val(min);
|
minInput.val(min);
|
||||||
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||||
maxInput.val(max);
|
maxInput.val(max);
|
||||||
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
||||||
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
||||||
return {
|
return {
|
||||||
onclose: function() {
|
onclose: function() {
|
||||||
var min = minInput.val().trim();
|
var min = minInput.val().trim();
|
||||||
var max = maxInput.val().trim();
|
var max = maxInput.val().trim();
|
||||||
if (min !== "") {
|
if (min !== "") {
|
||||||
ui.opts.min = parseInt(min);
|
ui.opts.min = parseInt(min);
|
||||||
} else {
|
} else {
|
||||||
delete ui.opts.min;
|
delete ui.opts.min;
|
||||||
}
|
}
|
||||||
if (max !== "") {
|
if (max !== "") {
|
||||||
ui.opts.max = parseInt(max);
|
ui.opts.max = parseInt(max);
|
||||||
} else {
|
} else {
|
||||||
delete ui.opts.max;
|
delete ui.opts.max;
|
||||||
}
|
}
|
||||||
inputCellInput.typedInput('value',Date.now())
|
inputCellInput.typedInput('value',Date.now())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value:"none",
|
value:"none",
|
||||||
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value:"hide",
|
value:"hide",
|
||||||
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
default: 'none'
|
default: 'none'
|
||||||
}).on("typedinputtypechange", function(evt,type) {
|
}).on("typedinputtypechange", function(evt,type) {
|
||||||
ui.type = $(this).typedInput("type");
|
ui.type = $(this).typedInput("type");
|
||||||
ui.opts = typeOptions[ui.type];
|
ui.opts = typeOptions[ui.type];
|
||||||
if (ui.type === 'input') {
|
if (ui.type === 'input') {
|
||||||
// In the case of 'input' type, the typedInput uses the multiple-option
|
// In the case of 'input' type, the typedInput uses the multiple-option
|
||||||
// mode. Its value needs to be set to a comma-separately list of the
|
// mode. Its value needs to be set to a comma-separately list of the
|
||||||
// selected options.
|
// selected options.
|
||||||
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
||||||
} else {
|
} else {
|
||||||
// No other type cares about `value`, but doing this will
|
// No other type cares about `value`, but doing this will
|
||||||
// force a refresh of the label now that `ui.opts` has
|
// force a refresh of the label now that `ui.opts` has
|
||||||
// been updated.
|
// been updated.
|
||||||
inputCellInput.typedInput('value',Date.now())
|
inputCellInput.typedInput('value',Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ui.type) {
|
switch (ui.type) {
|
||||||
case 'input':
|
case 'input':
|
||||||
valueField.typedInput('types',ui.opts.types);
|
valueField.typedInput('types',ui.opts.types);
|
||||||
break;
|
break;
|
||||||
case 'select':
|
case 'select':
|
||||||
valueField.typedInput('types',['str']);
|
valueField.typedInput('types',['str']);
|
||||||
break;
|
break;
|
||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
valueField.typedInput('types',['bool']);
|
valueField.typedInput('types',['bool']);
|
||||||
break;
|
break;
|
||||||
case 'spinner':
|
case 'spinner':
|
||||||
valueField.typedInput('types',['num'])
|
valueField.typedInput('types',['num']);
|
||||||
|
break;
|
||||||
|
case 'cred':
|
||||||
|
valueField.typedInput('types',['cred']);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
valueField.typedInput('types',['str','num','bool','json','bin','env'])
|
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
||||||
}
|
}
|
||||||
if (ui.type === 'checkbox') {
|
if (ui.type === 'checkbox') {
|
||||||
valueField.typedInput('type','bool');
|
valueField.typedInput('type','bool');
|
||||||
} else if (ui.type === 'spinner') {
|
} else if (ui.type === 'spinner') {
|
||||||
valueField.typedInput('type','num');
|
valueField.typedInput('type','num');
|
||||||
}
|
}
|
||||||
if (ui.type !== 'checkbox') {
|
if (ui.type !== 'checkbox') {
|
||||||
checkbox = null;
|
checkbox = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}).on("change", function(evt,type) {
|
}).on("change", function(evt,type) {
|
||||||
if (ui.type === 'input') {
|
if (ui.type === 'input') {
|
||||||
ui.opts.types = inputCellInput.typedInput('value').split(",");
|
ui.opts.types = inputCellInput.typedInput('value').split(",");
|
||||||
valueField.typedInput('types',ui.opts.types);
|
valueField.typedInput('types',ui.opts.types);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
valueField.on("change", function(evt) {
|
valueField.on("change", function(evt) {
|
||||||
if (checkbox) {
|
if (checkbox) {
|
||||||
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
||||||
// event handler (just above ^^) to update the value if needed
|
// event handler (just above ^^) to update the value if needed
|
||||||
inputCellInput.typedInput('type',ui.type)
|
inputCellInput.typedInput('type',ui.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEnvUIRow(row, tenv, ui) {
|
function buildEnvUIRow(row, tenv, ui, node) {
|
||||||
ui.label = ui.label||{};
|
ui.label = ui.label||{};
|
||||||
if (!ui.type) {
|
if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
|
||||||
|
ui.type = "cred";
|
||||||
|
ui.opts = {};
|
||||||
|
} else if (!ui.type) {
|
||||||
ui.type = "input";
|
ui.type = "input";
|
||||||
ui.opts = {types:['str','num','bool','json','bin','env']}
|
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||||
} else {
|
} else {
|
||||||
if (!ui.opts) {
|
if (!ui.opts) {
|
||||||
ui.opts = (ui.type === "select") ? {opts:[]} : {};
|
ui.opts = (ui.type === "select") ? {opts:[]} : {};
|
||||||
@ -1467,6 +1512,24 @@ RED.subflow = (function() {
|
|||||||
input.spinner(spinnerOpts).parent().width('70%');
|
input.spinner(spinnerOpts).parent().width('70%');
|
||||||
input.val(val.value);
|
input.val(val.value);
|
||||||
break;
|
break;
|
||||||
|
case "cred":
|
||||||
|
input = $('<input type="password">').css('width','70%').appendTo(row);
|
||||||
|
if (node.credentials) {
|
||||||
|
if (node.credentials[tenv.name]) {
|
||||||
|
input.val(node.credentials[tenv.name]);
|
||||||
|
} else if (node.credentials['has_'+tenv.name]) {
|
||||||
|
input.val("__PWRD__")
|
||||||
|
} else {
|
||||||
|
input.val("");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input.val("");
|
||||||
|
}
|
||||||
|
input.typedInput({
|
||||||
|
types: ['cred'],
|
||||||
|
default: 'cred'
|
||||||
|
})
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (input) {
|
if (input) {
|
||||||
input.attr('id',getSubflowEnvPropertyName(tenv.name))
|
input.attr('id',getSubflowEnvPropertyName(tenv.name))
|
||||||
@ -1478,7 +1541,7 @@ RED.subflow = (function() {
|
|||||||
* @param uiContainer - container for UI
|
* @param uiContainer - container for UI
|
||||||
* @param envList - env var definitions of template
|
* @param envList - env var definitions of template
|
||||||
*/
|
*/
|
||||||
function buildEnvUI(uiContainer, envList) {
|
function buildEnvUI(uiContainer, envList,node) {
|
||||||
uiContainer.empty();
|
uiContainer.empty();
|
||||||
var elementID = 0;
|
var elementID = 0;
|
||||||
for (var i = 0; i < envList.length; i++) {
|
for (var i = 0; i < envList.length; i++) {
|
||||||
@ -1487,7 +1550,7 @@ RED.subflow = (function() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
||||||
buildEnvUIRow(row,tenv, tenv.ui || {});
|
buildEnvUIRow(row,tenv, tenv.ui || {}, node);
|
||||||
|
|
||||||
// console.log(ui);
|
// console.log(ui);
|
||||||
}
|
}
|
||||||
@ -1525,7 +1588,7 @@ RED.subflow = (function() {
|
|||||||
// icon: "",
|
// icon: "",
|
||||||
// label: {},
|
// label: {},
|
||||||
// type: "input",
|
// type: "input",
|
||||||
// opts: {types:['str','num','bool','json','bin','env']}
|
// opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||||
// }
|
// }
|
||||||
if (!ui.icon) {
|
if (!ui.icon) {
|
||||||
delete ui.icon;
|
delete ui.icon;
|
||||||
@ -1535,13 +1598,19 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
switch (ui.type) {
|
switch (ui.type) {
|
||||||
case "input":
|
case "input":
|
||||||
if (JSON.stringify(ui.opts) === JSON.stringify({types:['str','num','bool','json','bin','env']})) {
|
if (JSON.stringify(ui.opts) === JSON.stringify({types:DEFAULT_ENV_TYPE_LIST})) {
|
||||||
// This is the default input config. Delete it as it will
|
// This is the default input config. Delete it as it will
|
||||||
// be applied automatically
|
// be applied automatically
|
||||||
delete ui.type;
|
delete ui.type;
|
||||||
delete ui.opts;
|
delete ui.opts;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "cred":
|
||||||
|
if (envItem.type === "cred") {
|
||||||
|
delete ui.type;
|
||||||
|
}
|
||||||
|
delete ui.opts;
|
||||||
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
if (ui.opts && $.isEmptyObject(ui.opts.opts)) {
|
if (ui.opts && $.isEmptyObject(ui.opts.opts)) {
|
||||||
// This is the default select config.
|
// This is the default select config.
|
||||||
@ -1585,7 +1654,7 @@ RED.subflow = (function() {
|
|||||||
type: env.type,
|
type: env.type,
|
||||||
value: env.value
|
value: env.value
|
||||||
},
|
},
|
||||||
ui: env.ui
|
ui: $.extend(true,{},env.ui)
|
||||||
}
|
}
|
||||||
envList.push(item);
|
envList.push(item);
|
||||||
parentEnv[env.name] = item;
|
parentEnv[env.name] = item;
|
||||||
@ -1621,13 +1690,17 @@ RED.subflow = (function() {
|
|||||||
var item;
|
var item;
|
||||||
var ui = data.ui || {};
|
var ui = data.ui || {};
|
||||||
if (!ui.type) {
|
if (!ui.type) {
|
||||||
ui.type = "input";
|
if (data.parent && data.parent.type === "cred") {
|
||||||
ui.opts = {types:['str','num','bool','json','bin','env']}
|
ui.type = "cred";
|
||||||
|
} else {
|
||||||
|
ui.type = "input";
|
||||||
|
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ui.opts = ui.opts || {};
|
ui.opts = ui.opts || {};
|
||||||
}
|
}
|
||||||
var input = $("#"+getSubflowEnvPropertyName(data.name));
|
var input = $("#"+getSubflowEnvPropertyName(data.name));
|
||||||
if (input.length) {
|
if (input.length || ui.type === "cred") {
|
||||||
item = { name: data.name };
|
item = { name: data.name };
|
||||||
switch(ui.type) {
|
switch(ui.type) {
|
||||||
case "input":
|
case "input":
|
||||||
@ -1639,6 +1712,10 @@ RED.subflow = (function() {
|
|||||||
item.type = 'str';
|
item.type = 'str';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "cred":
|
||||||
|
item.value = input.val();
|
||||||
|
item.type = 'cred';
|
||||||
|
break;
|
||||||
case "spinner":
|
case "spinner":
|
||||||
item.value = input.val();
|
item.value = input.val();
|
||||||
item.type = 'num';
|
item.type = 'num';
|
||||||
@ -1652,7 +1729,7 @@ RED.subflow = (function() {
|
|||||||
item.value = ""+input.prop("checked");
|
item.value = ""+input.prop("checked");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (item.type !== data.parent.type || item.value !== data.parent.value) {
|
if (ui.type === "cred" || item.type !== data.parent.type || item.value !== data.parent.value) {
|
||||||
env.push(item);
|
env.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1702,14 +1779,17 @@ RED.subflow = (function() {
|
|||||||
return defaultLabel;
|
return defaultLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEditForm(container,type,node) {
|
function buildEditForm(type,node) {
|
||||||
if (type === "subflow-template") {
|
if (type === "subflow-template") {
|
||||||
buildPropertiesList($('#node-input-env-container'), node);
|
buildPropertiesList($('#node-input-env-container'), node);
|
||||||
} else if (type === "subflow") {
|
} else if (type === "subflow") {
|
||||||
buildEnvUI($("#subflow-input-ui"), getSubflowInstanceParentEnv(node));
|
// This gets called by the subflow type `oneditprepare` function
|
||||||
|
// registered in nodes.js#addSubflow()
|
||||||
|
buildEnvUI($("#subflow-input-ui"), getSubflowInstanceParentEnv(node), node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function buildPropertiesForm(container, node) {
|
function buildPropertiesForm(node) {
|
||||||
|
var container = $('#editor-subflow-envProperties-content');
|
||||||
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
|
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
|
||||||
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
|
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
|
||||||
var list = $('<ol id="red-ui-editor-subflow-env-list" class="red-ui-editor-subflow-env-list"></ol>').appendTo(listContainer);
|
var list = $('<ol id="red-ui-editor-subflow-env-list" class="red-ui-editor-subflow-env-list"></ol>').appendTo(listContainer);
|
||||||
|
@ -238,17 +238,25 @@ var api = module.exports = {
|
|||||||
if (!credentials) {
|
if (!credentials) {
|
||||||
return resolve({});
|
return resolve({});
|
||||||
}
|
}
|
||||||
var definition = runtime.nodes.getCredentialDefinition(opts.type) || {};
|
|
||||||
|
|
||||||
var sendCredentials = {};
|
var sendCredentials = {};
|
||||||
for (var cred in definition) {
|
var cred;
|
||||||
if (definition.hasOwnProperty(cred)) {
|
if (/^subflow(:|$)/.test(opts.type)) {
|
||||||
if (definition[cred].type == "password") {
|
for (cred in credentials) {
|
||||||
var key = 'has_' + cred;
|
if (credentials.hasOwnProperty(cred)) {
|
||||||
sendCredentials[key] = credentials[cred] != null && credentials[cred] !== '';
|
sendCredentials['has_'+cred] = credentials[cred] != null && credentials[cred] !== '';
|
||||||
continue;
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var definition = runtime.nodes.getCredentialDefinition(opts.type) || {};
|
||||||
|
for (cred in definition) {
|
||||||
|
if (definition.hasOwnProperty(cred)) {
|
||||||
|
if (definition[cred].type == "password") {
|
||||||
|
var key = 'has_' + cred;
|
||||||
|
sendCredentials[key] = credentials[cred] != null && credentials[cred] !== '';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sendCredentials[cred] = credentials[cred] || '';
|
||||||
}
|
}
|
||||||
sendCredentials[cred] = credentials[cred] || '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(sendCredentials);
|
resolve(sendCredentials);
|
||||||
|
@ -341,33 +341,62 @@ var api = module.exports = {
|
|||||||
extract: function(node) {
|
extract: function(node) {
|
||||||
var nodeID = node.id;
|
var nodeID = node.id;
|
||||||
var nodeType = node.type;
|
var nodeType = node.type;
|
||||||
|
var cred;
|
||||||
var newCreds = node.credentials;
|
var newCreds = node.credentials;
|
||||||
if (newCreds) {
|
if (newCreds) {
|
||||||
delete node.credentials;
|
delete node.credentials;
|
||||||
var savedCredentials = credentialCache[nodeID] || {};
|
var savedCredentials = credentialCache[nodeID] || {};
|
||||||
var dashedType = nodeType.replace(/\s+/g, '-');
|
if (/^subflow(:|$)/.test(nodeType)) {
|
||||||
var definition = credentialsDef[dashedType];
|
for (cred in newCreds) {
|
||||||
if (!definition) {
|
if (newCreds.hasOwnProperty(cred)) {
|
||||||
log.warn(log._("nodes.credentials.not-registered",{type:nodeType}));
|
if (newCreds[cred] === "__PWRD__") {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
|
||||||
|
delete savedCredentials[cred];
|
||||||
|
dirty = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!savedCredentials.hasOwnProperty(cred) || JSON.stringify(savedCredentials[cred]) !== JSON.stringify(newCreds[cred])) {
|
||||||
|
savedCredentials[cred] = newCreds[cred];
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (var cred in definition) {
|
|
||||||
if (definition.hasOwnProperty(cred)) {
|
|
||||||
if (newCreds[cred] === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') {
|
}
|
||||||
continue;
|
for (cred in savedCredentials) {
|
||||||
|
if (savedCredentials.hasOwnProperty(cred)) {
|
||||||
|
if (!newCreds.hasOwnProperty(cred)) {
|
||||||
|
delete savedCredentials[cred];
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
|
}
|
||||||
delete savedCredentials[cred];
|
} else {
|
||||||
dirty = true;
|
var dashedType = nodeType.replace(/\s+/g, '-');
|
||||||
continue;
|
var definition = credentialsDef[dashedType];
|
||||||
}
|
if (!definition) {
|
||||||
if (!savedCredentials.hasOwnProperty(cred) || JSON.stringify(savedCredentials[cred]) !== JSON.stringify(newCreds[cred])) {
|
log.warn(log._("nodes.credentials.not-registered",{type:nodeType}));
|
||||||
savedCredentials[cred] = newCreds[cred];
|
return;
|
||||||
dirty = true;
|
}
|
||||||
|
|
||||||
|
for (cred in definition) {
|
||||||
|
if (definition.hasOwnProperty(cred)) {
|
||||||
|
if (newCreds[cred] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
|
||||||
|
delete savedCredentials[cred];
|
||||||
|
dirty = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!savedCredentials.hasOwnProperty(cred) || JSON.stringify(savedCredentials[cred]) !== JSON.stringify(newCreds[cred])) {
|
||||||
|
savedCredentials[cred] = newCreds[cred];
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ const util = require("util");
|
|||||||
const redUtil = require("@node-red/util").util;
|
const redUtil = require("@node-red/util").util;
|
||||||
const flowUtil = require("./util");
|
const flowUtil = require("./util");
|
||||||
|
|
||||||
|
|
||||||
|
const credentials = require("../credentials");
|
||||||
|
|
||||||
var Log;
|
var Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +41,9 @@ function evaluateInputValue(value, type, node) {
|
|||||||
if (type === "bool") {
|
if (type === "bool") {
|
||||||
return (value === "true") || (value === true);
|
return (value === "true") || (value === true);
|
||||||
}
|
}
|
||||||
|
if (type === "cred") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
return redUtil.evaluateNodeProperty(value, type, node, null, null);
|
return redUtil.evaluateNodeProperty(value, type, node, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,10 +148,16 @@ class Subflow extends Flow {
|
|||||||
this.node_map = node_map;
|
this.node_map = node_map;
|
||||||
this.path = parent.path+"/"+(subflowInstance._alias||subflowInstance.id);
|
this.path = parent.path+"/"+(subflowInstance._alias||subflowInstance.id);
|
||||||
|
|
||||||
|
this.templateCredentials = credentials.get(subflowDef.id);
|
||||||
|
this.instanceCredentials = credentials.get(this.id);
|
||||||
|
|
||||||
var env = [];
|
var env = [];
|
||||||
if (this.subflowDef.env) {
|
if (this.subflowDef.env) {
|
||||||
this.subflowDef.env.forEach(e => {
|
this.subflowDef.env.forEach(e => {
|
||||||
env[e.name] = e;
|
env[e.name] = e;
|
||||||
|
if (e.type === "cred") {
|
||||||
|
e.value = this.templateCredentials[e.name];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.subflowInstance.env) {
|
if (this.subflowInstance.env) {
|
||||||
@ -154,7 +166,14 @@ class Subflow extends Flow {
|
|||||||
var ui = old ? old.ui : null;
|
var ui = old ? old.ui : null;
|
||||||
env[e.name] = e;
|
env[e.name] = e;
|
||||||
if (ui) {
|
if (ui) {
|
||||||
env[e.name].ui = ui;
|
env[e.name].ui = ui;
|
||||||
|
}
|
||||||
|
if (e.type === "cred") {
|
||||||
|
if (!old || this.instanceCredentials.hasOwnProperty(e.name) ) {
|
||||||
|
e.value = this.instanceCredentials[e.name];
|
||||||
|
} else if (old) {
|
||||||
|
e.value = this.templateCredentials[e.name];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -324,7 +343,6 @@ class Subflow extends Flow {
|
|||||||
* @return {Object} val value of env var
|
* @return {Object} val value of env var
|
||||||
*/
|
*/
|
||||||
getSetting(name) {
|
getSetting(name) {
|
||||||
this.trace("getSetting:"+name);
|
|
||||||
if (!/^\$parent\./.test(name)) {
|
if (!/^\$parent\./.test(name)) {
|
||||||
var env = this.env;
|
var env = this.env;
|
||||||
var is_info = name.endsWith("_info");
|
var is_info = name.endsWith("_info");
|
||||||
@ -333,7 +351,6 @@ class Subflow extends Flow {
|
|||||||
|
|
||||||
if (env && env.hasOwnProperty(ename)) {
|
if (env && env.hasOwnProperty(ename)) {
|
||||||
var val = env[ename];
|
var val = env[ename];
|
||||||
|
|
||||||
if (is_type) {
|
if (is_type) {
|
||||||
return val ? val.type : undefined;
|
return val ? val.type : undefined;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user