Add link-call node and add return mode for link-out node

This commit is contained in:
Nick O'Leary
2021-09-29 10:45:00 +01:00
parent c9d1329fc2
commit b01fd24e15
10 changed files with 192 additions and 35 deletions

View File

@@ -8,6 +8,22 @@
<div class="form-row node-input-link-row"></div>
</script>
<script type="text/html" data-template-name="link out">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-mode"><span data-i18n="link.outMode"></span></label>
<select id="node-input-mode" style="width: 70%">
<option value="link" selected data-i18n="link.sendToAll"></option>
<option value="return" data-i18n="link.returnToCaller"></option>
</select>
</div>
<div class="node-input-link-rows" style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row node-input-link-rows"></div>
</script>
<script type="text/html" data-template-name="link call">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@@ -48,7 +64,6 @@
}
});
var candidateNodes = RED.nodes.filterNodes({type:targetType});
var search = $("#node-input-link-target-filter").searchBox({
style: "compact",
delay: 300,
@@ -104,7 +119,8 @@
node: n,
label: n.name||n.id,
selected: isChecked,
checkbox: true
checkbox: node.type !== "link call",
radio: node.type === "link call"
})
}
});
@@ -129,15 +145,22 @@
function onEditSave(node) {
var flows = treeList.treeList('data');
node.links = [];
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {
node.links.push(n.id);
}
if (node.type !== "link out" || $("node-input-mode").val() === 'link') {
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {
node.links.push(n.id);
}
})
})
})
}
node.oldLinks.sort();
node.links.sort();
if (node.type === "link call") {
return
}
var nodeMap = {};
var length = Math.max(node.oldLinks.length,node.links.length);
for (var i=0;i<length;i++) {
@@ -195,6 +218,7 @@
outputLabels: function(i) {
return this.name||this._("link.linkIn");
},
showLabel: false,
label: function() {
return this.name||this._("link.linkIn");
},
@@ -211,25 +235,31 @@
oneditresize: resizeNodeList
});
RED.nodes.registerType('link out',{
RED.nodes.registerType('link call',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: {value:""},
links: { value: [], type:"link in[]"}
},
align:"right",
inputs:1,
outputs:0,
icon: "link-out.svg",
inputs: 1,
outputs: 1,
icon: "link-call.svg",
inputLabels: function(i) {
return this.name||this._("link.linkOut");
return this.name||this._("link.linkCall");
},
label: function() {
return this.name||this._("link.linkOut");
if (this.name) {
return this.name;
}
if (this.links.length > 0) {
var targetNode = RED.nodes.node(this.links[0]);
return targetNode && (targetNode.name || targetNode.id);
}
return this._("link.linkCall");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
return (this.name || this.links.length > 0)?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link in");
@@ -237,8 +267,56 @@
oneditsave: function() {
onEditSave(this);
},
oneditresize: resizeNodeList
});
RED.nodes.registerType('link out',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: {value:""},
mode: { value: "link" },// link || return
links: { value: [], type:"link in[]"}
},
align:"right",
inputs:1,
outputs:0,
icon: function() {
if (this.mode === "return") {
return "link-return.svg";
} else {
return "link-out.svg";
}
},
inputLabels: function(i) {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
showLabel: false,
label: function() {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link in");
$("#node-input-mode").on("change", function() {
$(".node-input-link-rows").toggle(this.value === "link")
})
if (!this.mode) {
$("#node-input-mode").val('link').trigger("change");
}
},
oneditsave: function() {
onEditSave(this);
},
onadd: onAdd,
oneditresize: resizeNodeList
});
})();
</script>

View File

@@ -17,6 +17,8 @@
module.exports = function(RED) {
"use strict";
const crypto = require("crypto");
function LinkInNode(n) {
RED.nodes.createNode(this,n);
var node = this;
@@ -40,13 +42,70 @@ module.exports = function(RED) {
function LinkOutNode(n) {
RED.nodes.createNode(this,n);
var node = this;
var mode = n.mode || "link";
var event = "node:"+n.id;
this.on("input", function(msg, send, done) {
msg._event = event;
RED.events.emit(event,msg)
send(msg);
done();
if (mode === "return") {
if (Array.isArray(msg._linkSource) && msg._linkSource.length > 0) {
var messageEvent = msg._linkSource.pop();
var returnNode = RED.nodes.getNode(messageEvent.node);
if (returnNode && returnNode.returnLinkMessage) {
returnNode.returnLinkMessage(messageEvent.id, msg);
} else {
node.warn("Return target not a link-call node")
}
} else {
node.warn("No call return target")
}
done();
} else if (mode === "link") {
send(msg);
done();
}
});
}
RED.nodes.registerType("link out",LinkOutNode);
function LinkCallNode(n) {
RED.nodes.createNode(this,n);
const node = this;
const target = n.links[0];
const messageEvents = {};
this.on("input", function(msg, send, done) {
msg._linkSource = msg._linkSource || [];
const messageEvent = {
id: crypto.randomBytes(14).toString('hex'),
node: node.id,
}
messageEvents[messageEvent.id] = { send, done };
msg._linkSource.push(messageEvent);
var targetNode = RED.nodes.getNode(target);
if (targetNode) {
targetNode.receive(msg);
}
});
this.returnLinkMessage = function(eventId, msg) {
if (Array.isArray(msg._linkSource) && msg._linkSource.length === 0) {
delete msg._linkSource;
}
const messageEvent = messageEvents[eventId];
if (messageEvent) {
delete messageEvents[eventId];
messageEvent.send(msg);
messageEvent.done();
} else {
node.warn("Unrecognised message returned")
}
}
}
RED.nodes.registerType("link call",LinkCallNode);
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="10.583mm" height="15.875mm" version="1.1" viewBox="0 0 10.583 15.875" xmlns="http://www.w3.org/2000/svg">
<path d="m8.2021 2.3812-4.8922 0.53612 1.604 0.92604-1.0395 1.8004c0.73719-0.37402 1.6437-0.38227 2.4095 0.059892 0.76511 0.44174 1.2118 1.2301 1.2577 2.055l1.0384-1.7986 1.604 0.92604zm-2.3813 4.1244c-0.77016-0.44465-1.7402-0.18474-2.1848 0.58542-0.44465 0.77016-0.185 1.7406 0.58516 2.1853 0.77016 0.44465 1.7422 0.18533 2.1869-0.58483 0.44465-0.77016 0.18295-1.7412-0.58721-2.1858zm-3.3193 1.5159-1.8211 3.1542 3.6662 2.1167 1.82-3.1524c-0.73731 0.37266-1.6431 0.37961-2.4082-0.062129-0.76585-0.44216-1.2122-1.2309-1.2569-2.0563z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 771 B

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="10.583mm" height="15.875mm" version="1.1" viewBox="0 0 10.583 15.875" xmlns="http://www.w3.org/2000/svg">
<path d="m2.6623 13.292 4.8922-0.53612-1.604-0.92604 1.0395-1.8004c-0.73719 0.37402-1.6437 0.38227-2.4095-0.059892-0.76511-0.44174-1.2118-1.2301-1.2577-2.055l-1.0384 1.7986-1.604-0.92604zm2.3813-4.1244c0.77016 0.44465 1.7402 0.18474 2.1848-0.58542 0.44465-0.77016 0.185-1.7406-0.58516-2.1853-0.77016-0.44465-1.7422-0.18533-2.1869 0.58483-0.44465 0.77016-0.18295 1.7412 0.58721 2.1858zm3.3193-1.5159 1.8211-3.1542-3.6662-2.1167-1.82 3.1524c0.73731-0.37266 1.6431-0.37961 2.4082 0.062129 0.76585 0.44216 1.2122 1.2309 1.2569 2.0563z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 769 B

View File

@@ -159,7 +159,13 @@
},
"link": {
"linkIn": "link in",
"linkOut": "link out"
"linkOut": "link out",
"linkCall": "link call",
"linkOutReturn": "link return",
"outMode": "Mode",
"sendToAll": "Send to all connected link nodes",
"returnToCaller": "Return to calling link node"
},
"tls": {
"tls": "TLS configuration",