mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #2435 from PaulWieland/dev
Adding user definable properties to inject node
This commit is contained in:
commit
20e84a847a
@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
<script type="text/html" data-template-name="inject">
|
<script type="text/html" data-template-name="inject">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-payload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
<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-payload" style="width:70%">
|
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||||
<input type="hidden" id="node-input-payloadType">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row node-input-property-container-row">
|
||||||
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
<ol id="node-input-property-container"></ol>
|
||||||
<input type="text" id="node-input-topic">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row" id="node-once">
|
<div class="form-row" id="node-once">
|
||||||
@ -114,12 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<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-tips" data-i18n="[html]inject.tip"></div>
|
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.inject-time-row {
|
.inject-time-row {
|
||||||
@ -160,19 +153,44 @@
|
|||||||
color:"#a6bbcf",
|
color:"#a6bbcf",
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
topic: {value:""},
|
props:{value:[{p:"payload",v:"",vt:"date"},{p:"topic",v:"",vt:"str"}]},
|
||||||
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
|
|
||||||
payloadType: {value:"date"},
|
|
||||||
repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
|
repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
|
||||||
crontab: {value:""},
|
crontab: {value:""},
|
||||||
once: {value:false},
|
once: {value:false},
|
||||||
onceDelay: {value:0.1}
|
onceDelay: {value:0.1},
|
||||||
|
/* Legacy */
|
||||||
|
topic: {value:""},
|
||||||
|
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
|
||||||
|
payloadType: {value:"date"},
|
||||||
|
/* */
|
||||||
},
|
},
|
||||||
icon: "inject.svg",
|
icon: "inject.svg",
|
||||||
inputs:0,
|
inputs:0,
|
||||||
outputs:1,
|
outputs:1,
|
||||||
outputLabels: function(index) {
|
outputLabels: function(index) {
|
||||||
var lab = this.payloadType;
|
var lab = '';
|
||||||
|
|
||||||
|
// if only payload and topic - display payload type
|
||||||
|
// if only one property - show it's type
|
||||||
|
// if more than one property (other than payload and topic) - show "x properties" where x is the number of properties.
|
||||||
|
|
||||||
|
// this.props will not be an array for legacy inject nodes until they are re-deployed
|
||||||
|
if (Array.isArray(this.props)) {
|
||||||
|
var propertyCount = this.props.length;
|
||||||
|
var payloadProperty = this.props.find(p => p.p === 'payload');
|
||||||
|
var topicProperty = this.props.find(p => p.p === 'topic' && p.vt === 'str');
|
||||||
|
|
||||||
|
if (payloadProperty && topicProperty) {
|
||||||
|
lab = payloadProperty.vt;
|
||||||
|
} else if (propertyCount > 1){
|
||||||
|
lab = propertyCount + " " + this._("inject.label.properties");
|
||||||
|
} else if(propertyCount === 1){
|
||||||
|
lab = this.props[0].vt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lab = this.payloadType;
|
||||||
if (lab === "json") {
|
if (lab === "json") {
|
||||||
try {
|
try {
|
||||||
lab = typeof JSON.parse(this.payload);
|
lab = typeof JSON.parse(this.payload);
|
||||||
@ -180,16 +198,40 @@
|
|||||||
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; }
|
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; }
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
return this._("inject.label.invalid"); }
|
return this._("inject.label.invalid");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var name = "inject.label."+lab;
|
var name = "inject.label."+lab;
|
||||||
var label = this._(name);
|
var label = this._(name);
|
||||||
if (name !== label) {
|
if (name !== label) { lab = label; }
|
||||||
return label;
|
|
||||||
}
|
|
||||||
return lab;
|
return lab;
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
|
if (Array.isArray(this.props)) {
|
||||||
|
// find the payload & topic
|
||||||
|
var payloadProperty = this.props.find(p => p.p === 'payload');
|
||||||
|
var topicProperty = this.props.find(p => p.p === 'topic' && p.vt === 'str');
|
||||||
|
|
||||||
|
// If no payload/topic are found, use the first property instead
|
||||||
|
if(this.props[0]){
|
||||||
|
payloadProperty = payloadProperty === undefined ? this.props[0] : payloadProperty;
|
||||||
|
topicProperty = topicProperty === undefined ? {v: payloadProperty.p} : topicProperty; // if no topic, use the property name of the payload
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = payloadProperty === undefined ? "" : payloadProperty.v;
|
||||||
|
var payloadType = payloadProperty === undefined ? "str" : payloadProperty.vt;
|
||||||
|
var topic = topicProperty === undefined ? "" : topicProperty.v;
|
||||||
|
} else {
|
||||||
|
/* Legacy */
|
||||||
|
var payload = this.payload;
|
||||||
|
var payloadType = this.payloadType;
|
||||||
|
var topic = this.topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var suffix = "";
|
var suffix = "";
|
||||||
// if fire once then add small indication
|
// if fire once then add small indication
|
||||||
if (this.once) {
|
if (this.once) {
|
||||||
@ -201,27 +243,27 @@
|
|||||||
}
|
}
|
||||||
if (this.name) {
|
if (this.name) {
|
||||||
return this.name+suffix;
|
return this.name+suffix;
|
||||||
} else if (this.payloadType === "string" ||
|
} else if (payloadType === "string" ||
|
||||||
this.payloadType === "str" ||
|
payloadType === "str" ||
|
||||||
this.payloadType === "num" ||
|
payloadType === "num" ||
|
||||||
this.payloadType === "bool" ||
|
payloadType === "bool" ||
|
||||||
this.payloadType === "json") {
|
payloadType === "json") {
|
||||||
if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
|
if ((topic !== "") && ((topic.length + payload.length) <= 32)) {
|
||||||
return this.topic + ":" + this.payload+suffix;
|
return topic + ":" + payload+suffix;
|
||||||
} else if (this.payload.length > 0 && this.payload.length < 24) {
|
} else if (payload.length > 0 && payload.length < 24) {
|
||||||
return this.payload+suffix;
|
return payload+suffix;
|
||||||
} else {
|
} else {
|
||||||
return this._("inject.inject")+suffix;
|
return this._("inject.inject")+suffix;
|
||||||
}
|
}
|
||||||
} else if (this.payloadType === 'date') {
|
} else if (payloadType === 'date' || payloadType === 'bin' || payloadType === 'env') {
|
||||||
if ((this.topic !== "") && (this.topic.length <= 16)) {
|
if ((topic !== "") && (topic.length <= 16)) {
|
||||||
return this.topic + ":" + this._("inject.timestamp")+suffix;
|
return topic + ":" + this._(`inject.label.${payloadType}`)+suffix;
|
||||||
} else {
|
} else {
|
||||||
return this._("inject.timestamp")+suffix;
|
return this._(`inject.label.${payloadType}`)+suffix;
|
||||||
}
|
}
|
||||||
} else if (this.payloadType === 'flow' || this.payloadType === 'global') {
|
} else if (payloadType === 'flow' || payloadType === 'global') {
|
||||||
var key = RED.utils.parseContextKey(this.payload);
|
var key = RED.utils.parseContextKey(payload);
|
||||||
return this.payloadType+"."+key.key+suffix;
|
return payloadType+"."+key.key+suffix;
|
||||||
} else {
|
} else {
|
||||||
return this._("inject.inject")+suffix;
|
return this._("inject.inject")+suffix;
|
||||||
}
|
}
|
||||||
@ -259,6 +301,10 @@
|
|||||||
$("#node-once").hide();
|
$("#node-once").hide();
|
||||||
$("#node-input-once").prop('checked', false);
|
$("#node-input-once").prop('checked', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scroll down
|
||||||
|
var scrollDiv = $("#dialog-form").parent();
|
||||||
|
scrollDiv.scrollTop(scrollDiv.prop('scrollHeight'));
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#node-input-once").on("change", function() {
|
$("#node-input-once").on("change", function() {
|
||||||
@ -383,8 +429,117 @@
|
|||||||
$("#inject-time-type-select").trigger("change");
|
$("#inject-time-type-select").trigger("change");
|
||||||
$("#inject-time-interval-time-start").trigger("change");
|
$("#inject-time-interval-time-start").trigger("change");
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
function resizeItem(item) {
|
||||||
|
var newWidth = item.width();
|
||||||
|
|
||||||
|
item.find('.node-input-prop-property-name').typedInput("width", '155px');
|
||||||
|
item.find('.node-input-prop-property-value').typedInput("width", `${newWidth - 180}px`);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#node-input-property-container').css('min-height','150px').css('min-width','450px').editableList({
|
||||||
|
addItem: function(container,i,opt) {
|
||||||
|
var prop = opt;
|
||||||
|
if (!prop.hasOwnProperty('p')) {
|
||||||
|
prop = {p:"",v:"",vt:"str"};
|
||||||
|
}
|
||||||
|
container.css({
|
||||||
|
overflow: 'hidden',
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
});
|
||||||
|
var row = $('<div/>').appendTo(container);
|
||||||
|
|
||||||
|
var propertyName = $('<input/>',{class:"node-input-prop-property-name",type:"text"})
|
||||||
|
.appendTo(row)
|
||||||
|
.typedInput({types:['msg']});
|
||||||
|
|
||||||
|
$('<div/>',{style: 'display:inline-block; padding:0px 4px 0px 4px;'})
|
||||||
|
.text('=')
|
||||||
|
.appendTo(row);
|
||||||
|
|
||||||
|
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
|
||||||
|
.appendTo(row)
|
||||||
|
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
|
||||||
|
|
||||||
|
propertyName.typedInput('value',prop.p);
|
||||||
|
|
||||||
|
propertyValue.typedInput('value',prop.v);
|
||||||
|
propertyValue.typedInput('type',prop.vt);
|
||||||
|
|
||||||
|
resizeItem(container);
|
||||||
|
},
|
||||||
|
resizeItem: resizeItem,
|
||||||
|
removable: true,
|
||||||
|
sortable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.props) {
|
||||||
|
var payload = {
|
||||||
|
p:'payload',
|
||||||
|
v: this.payload ? this.payload : '',
|
||||||
|
vt:this.payloadType ? this.payloadType : 'date'
|
||||||
|
};
|
||||||
|
var topic = {
|
||||||
|
p:'topic',
|
||||||
|
v: this.topic ? this.topic : '',
|
||||||
|
vt:'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props = [payload,topic];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0; i<this.props.length; i++) {
|
||||||
|
var prop = this.props[i];
|
||||||
|
$("#node-input-property-container").editableList('addItem',prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Experimental paste object
|
||||||
|
* This allows you to copy an object to your clipboard from the debug and then paste it back into an inject node
|
||||||
|
*/
|
||||||
|
// $("#dialog-form").on('paste', function(e) {
|
||||||
|
// var pasteData = e.originalEvent.clipboardData.getData('text');
|
||||||
|
// try{
|
||||||
|
// var pasteObject = JSON.parse(pasteData);
|
||||||
|
// } catch(e){ }
|
||||||
|
//
|
||||||
|
// if(pasteObject){
|
||||||
|
// for(var p in pasteObject){
|
||||||
|
// if(p === '_msgid') continue;
|
||||||
|
// var v = pasteObject[p];
|
||||||
|
// var vt = 'json';
|
||||||
|
//
|
||||||
|
// // Remove existing property before adding to avoid duplicates
|
||||||
|
// $(`#node-input-property-container .node-input-prop-property-name[value=${p}]`).closest('.red-ui-editableList-item-content').parent().remove();
|
||||||
|
//
|
||||||
|
// if(typeof v === 'string'){
|
||||||
|
// vt = 'str';
|
||||||
|
// } else if (typeof v === "boolean") {
|
||||||
|
// vt = 'bool';
|
||||||
|
// } else if (!isNaN(v)) {
|
||||||
|
// vt = 'num';
|
||||||
|
// } else if(Array.isArray(v) && v.every(e => Number.isInteger(e) && e >= 0 && e <=255)) { // Fuzzy buffer detection
|
||||||
|
// vt = 'bin';
|
||||||
|
// v = JSON.stringify(pasteObject[p]);
|
||||||
|
// } else {
|
||||||
|
// vt = 'json';
|
||||||
|
// v = JSON.stringify(pasteObject[p]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var prop = {p, v, vt};
|
||||||
|
// $("#node-input-property-container").editableList('addItem',prop);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
},
|
},
|
||||||
oneditsave: function() {
|
oneditsave: function() {
|
||||||
|
/* Cleanup Legacy */
|
||||||
|
delete this.payload;
|
||||||
|
delete this.payloadType
|
||||||
|
delete this.topic
|
||||||
|
/* */
|
||||||
|
|
||||||
var repeat = "";
|
var repeat = "";
|
||||||
var crontab = "";
|
var crontab = "";
|
||||||
var type = $("#inject-time-type-select").val();
|
var type = $("#inject-time-type-select").val();
|
||||||
@ -474,6 +629,22 @@
|
|||||||
|
|
||||||
$("#node-input-repeat").val(repeat);
|
$("#node-input-repeat").val(repeat);
|
||||||
$("#node-input-crontab").val(crontab);
|
$("#node-input-crontab").val(crontab);
|
||||||
|
|
||||||
|
/* Gather the injected properties of the msg object */
|
||||||
|
var props = $("#node-input-property-container").editableList('items');
|
||||||
|
var node = this;
|
||||||
|
node.props= [];
|
||||||
|
props.each(function(i) {
|
||||||
|
var prop = $(this);
|
||||||
|
var p = {
|
||||||
|
p:prop.find(".node-input-prop-property-name").typedInput('value')
|
||||||
|
};
|
||||||
|
|
||||||
|
p.v = prop.find(".node-input-prop-property-value").typedInput('value');
|
||||||
|
p.vt = prop.find(".node-input-prop-property-value").typedInput('type');
|
||||||
|
|
||||||
|
node.props.push(p);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
enabled: function() {
|
enabled: function() {
|
||||||
@ -483,12 +654,7 @@
|
|||||||
if (this.changed) {
|
if (this.changed) {
|
||||||
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
|
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
|
||||||
}
|
}
|
||||||
var payload = this.payload;
|
|
||||||
if ((this.payloadType === 'flow') ||
|
|
||||||
(this.payloadType === 'global')) {
|
|
||||||
var key = RED.utils.parseContextKey(payload);
|
|
||||||
payload = this.payloadType+"."+key.key;
|
|
||||||
}
|
|
||||||
var label = this._def.label.call(this);
|
var label = this._def.label.call(this);
|
||||||
if (label.length > 30) {
|
if (label.length > 30) {
|
||||||
label = label.substring(0,50)+"...";
|
label = label.substring(0,50)+"...";
|
||||||
@ -514,6 +680,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
oneditresize: function(size) {
|
||||||
|
var rows = $("#dialog-form>div:not(.node-input-property-container-row):visible");
|
||||||
|
var height = size.height;
|
||||||
|
for (var i=0; i<rows.length; i++) {
|
||||||
|
height -= $(rows[i]).outerHeight(true);
|
||||||
|
}
|
||||||
|
var editorRow = $("#dialog-form>div.node-input-property-container-row");
|
||||||
|
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||||
|
height += 16;
|
||||||
|
$("#node-input-property-container").editableList('height',height);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,9 +20,23 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
function InjectNode(n) {
|
function InjectNode(n) {
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
this.topic = n.topic;
|
|
||||||
this.payload = n.payload;
|
/* Handle legacy */
|
||||||
this.payloadType = n.payloadType;
|
if(!Array.isArray(n.props)){
|
||||||
|
n.props = [];
|
||||||
|
n.props.push({
|
||||||
|
p:'payload',
|
||||||
|
v:n.payload,
|
||||||
|
vt:n.payloadType
|
||||||
|
});
|
||||||
|
n.props.push({
|
||||||
|
p:'topic',
|
||||||
|
v:n.topic,
|
||||||
|
vt:'str'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props = n.props;
|
||||||
this.repeat = n.repeat;
|
this.repeat = n.repeat;
|
||||||
this.crontab = n.crontab;
|
this.crontab = n.crontab;
|
||||||
this.once = n.once;
|
this.once = n.once;
|
||||||
@ -62,34 +76,27 @@ module.exports = function(RED) {
|
|||||||
node.repeaterSetup();
|
node.repeaterSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.on("input",function(msg) {
|
this.on("input", function(msg) {
|
||||||
msg.topic = this.topic;
|
var errors = [];
|
||||||
if (this.payloadType !== 'flow' && this.payloadType !== 'global') {
|
|
||||||
try {
|
|
||||||
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
|
|
||||||
msg.payload = Date.now();
|
|
||||||
} else if (this.payloadType == null) {
|
|
||||||
msg.payload = this.payload;
|
|
||||||
} else if (this.payloadType === 'none') {
|
|
||||||
msg.payload = "";
|
|
||||||
} else {
|
|
||||||
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
|
|
||||||
}
|
|
||||||
this.send(msg);
|
|
||||||
msg = null;
|
|
||||||
} catch(err) {
|
|
||||||
this.error(err,msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg, function(err,res) {
|
|
||||||
if (err) {
|
|
||||||
node.error(err,msg);
|
|
||||||
} else {
|
|
||||||
msg.payload = res;
|
|
||||||
node.send(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.props.forEach(p => {
|
||||||
|
var property = p.p;
|
||||||
|
var value = p.v ? p.v : '';
|
||||||
|
var valueType = p.vt ? p.vt : 'str';
|
||||||
|
|
||||||
|
if (!property) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
|
||||||
|
} catch (err) {
|
||||||
|
errors.push(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
node.error(errors.join('; '), msg);
|
||||||
|
} else {
|
||||||
|
node.send(msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"stopped": "stopped",
|
"stopped": "stopped",
|
||||||
"failed": "Inject failed: __error__",
|
"failed": "Inject failed: __error__",
|
||||||
"label": {
|
"label": {
|
||||||
|
"properties": "Properties",
|
||||||
"repeat": "Repeat",
|
"repeat": "Repeat",
|
||||||
"flow": "flow context",
|
"flow": "flow context",
|
||||||
"global": "global context",
|
"global": "global context",
|
||||||
@ -79,7 +80,6 @@
|
|||||||
"on": "on",
|
"on": "on",
|
||||||
"onstart": "Inject once after",
|
"onstart": "Inject once after",
|
||||||
"onceDelay": "seconds, then",
|
"onceDelay": "seconds, then",
|
||||||
"tip": "<b>Note:</b> \"interval between times\" and \"at a specific time\" will use cron.<br/>\"interval\" should be 596 hours or less.<br/>See info box for details.",
|
|
||||||
"success": "Successfully injected: __label__",
|
"success": "Successfully injected: __label__",
|
||||||
"errors": {
|
"errors": {
|
||||||
"failed": "inject failed, see log for details",
|
"failed": "inject failed, see log for details",
|
||||||
|
Loading…
Reference in New Issue
Block a user