mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3533 from Steve-Mcl/filename-typedinput
Feature: Change basic Filename field to a typedInput
This commit is contained in:
commit
9565aee3c5
@ -3,6 +3,7 @@
|
|||||||
<div class="form-row node-input-filename">
|
<div class="form-row node-input-filename">
|
||||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||||
<input id="node-input-filename" type="text">
|
<input id="node-input-filename" type="text">
|
||||||
|
<input type="hidden" id="node-input-filenameType">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
||||||
@ -29,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></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-name" data-i18n="[placeholder]common.label.name">
|
<input type="text" id="node-input-name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
||||||
</script>
|
</script>
|
||||||
@ -37,7 +38,8 @@
|
|||||||
<script type="text/html" data-template-name="file in">
|
<script type="text/html" data-template-name="file in">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||||
<input id="node-input-filename" type="text" data-i18n="[placeholder]file.label.filename">
|
<input id="node-input-filename" type="text">
|
||||||
|
<input type="hidden" id="node-input-filenameType">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
||||||
@ -60,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></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-name" data-i18n="[placeholder]common.label.name">
|
<input type="text" id="node-input-name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
||||||
</script>
|
</script>
|
||||||
@ -196,7 +198,8 @@
|
|||||||
category: 'storage',
|
category: 'storage',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:""},
|
filename: {value:"filename"},
|
||||||
|
filenameType: {value:"msg"},
|
||||||
appendNewline: {value:true},
|
appendNewline: {value:true},
|
||||||
createDir: {value:false},
|
createDir: {value:false},
|
||||||
overwriteFile: {value:"false"},
|
overwriteFile: {value:"false"},
|
||||||
@ -207,10 +210,13 @@
|
|||||||
outputs:1,
|
outputs:1,
|
||||||
icon: "file-out.svg",
|
icon: "file-out.svg",
|
||||||
label: function() {
|
label: function() {
|
||||||
|
var fn = this.filename;
|
||||||
|
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
|
||||||
|
if(this.filenameType === "env") { fn = "env."+fn; }
|
||||||
if (this.overwriteFile === "delete") {
|
if (this.overwriteFile === "delete") {
|
||||||
return this.name||this._("file.label.deletelabel",{file:this.filename});
|
return this.name||this._("file.label.deletelabel",{file:fn});
|
||||||
} else {
|
} else {
|
||||||
return this.name||this.filename||this._("file.label.write");
|
return this.name||fn||this._("file.label.write");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
paletteLabel: RED._("node-red:file.label.write"),
|
paletteLabel: RED._("node-red:file.label.write"),
|
||||||
@ -229,6 +235,31 @@
|
|||||||
value: "setbymsg",
|
value: "setbymsg",
|
||||||
label: node._("file.encoding.setbymsg")
|
label: node._("file.encoding.setbymsg")
|
||||||
}).text(label).appendTo(encSel);
|
}).text(label).appendTo(encSel);
|
||||||
|
$("#node-input-filename").typedInput({
|
||||||
|
default: "msg",
|
||||||
|
types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
|
||||||
|
typeField: $("#node-input-filenameType")
|
||||||
|
});
|
||||||
|
if(typeof node.filenameType == 'undefined') {
|
||||||
|
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
|
||||||
|
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
|
||||||
|
node.filename = "filename";
|
||||||
|
node.filenameType = "msg";
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
|
||||||
|
node.filenameType = "env";
|
||||||
|
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
|
||||||
|
return (name === undefined)?"":name;
|
||||||
|
});
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
} else { //was using a static filename - set typedInput type to str
|
||||||
|
node.filenameType = "str";
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
encodings.forEach(function(item) {
|
encodings.forEach(function(item) {
|
||||||
if(Array.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
var group = $("<optgroup/>", {
|
var group = $("<optgroup/>", {
|
||||||
@ -266,7 +297,8 @@
|
|||||||
category: 'storage',
|
category: 'storage',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:""},
|
filename: {value:"filename"},
|
||||||
|
filenameType: {value:"msg"},
|
||||||
format: {value:"utf8"},
|
format: {value:"utf8"},
|
||||||
chunk: {value:false},
|
chunk: {value:false},
|
||||||
sendError: {value: false},
|
sendError: {value: false},
|
||||||
@ -291,7 +323,10 @@
|
|||||||
},
|
},
|
||||||
icon: "file-in.svg",
|
icon: "file-in.svg",
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name||this.filename||this._("file.label.read");
|
var fn = this.filename;
|
||||||
|
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
|
||||||
|
if(this.filenameType === "env") { fn = "env."+fn; }
|
||||||
|
return this.name||fn||this._("file.label.read");
|
||||||
},
|
},
|
||||||
paletteLabel: RED._("node-red:file.label.read"),
|
paletteLabel: RED._("node-red:file.label.read"),
|
||||||
labelStyle: function() {
|
labelStyle: function() {
|
||||||
@ -305,6 +340,31 @@
|
|||||||
value: "none",
|
value: "none",
|
||||||
label: label
|
label: label
|
||||||
}).text(label).appendTo(encSel);
|
}).text(label).appendTo(encSel);
|
||||||
|
$("#node-input-filename").typedInput({
|
||||||
|
default: "msg",
|
||||||
|
types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
|
||||||
|
typeField: $("#node-input-filenameType")
|
||||||
|
});
|
||||||
|
if(typeof node.filenameType == 'undefined') {
|
||||||
|
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
|
||||||
|
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
|
||||||
|
node.filename = "filename";
|
||||||
|
node.filenameType = "msg";
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
|
||||||
|
node.filenameType = "env";
|
||||||
|
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
|
||||||
|
return (name === undefined)?"":name;
|
||||||
|
});
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
} else { //was using a static filename - set typedInput type to str
|
||||||
|
node.filenameType = "str";
|
||||||
|
$("#node-input-filename").typedInput("type", node.filenameType);
|
||||||
|
$("#node-input-filename").typedInput("value", node.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
encodings.forEach(function(item) {
|
encodings.forEach(function(item) {
|
||||||
if(Array.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
var group = $("<optgroup/>", {
|
var group = $("<optgroup/>", {
|
||||||
|
@ -39,6 +39,7 @@ module.exports = function(RED) {
|
|||||||
// Write/delete a file
|
// Write/delete a file
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
this.filename = n.filename;
|
this.filename = n.filename;
|
||||||
|
this.filenameType = n.filenameType;
|
||||||
this.appendNewline = n.appendNewline;
|
this.appendNewline = n.appendNewline;
|
||||||
this.overwriteFile = n.overwriteFile.toString();
|
this.overwriteFile = n.overwriteFile.toString();
|
||||||
this.createDir = n.createDir || false;
|
this.createDir = n.createDir || false;
|
||||||
@ -50,7 +51,28 @@ module.exports = function(RED) {
|
|||||||
node.closeCallback = null;
|
node.closeCallback = null;
|
||||||
|
|
||||||
function processMsg(msg,nodeSend, done) {
|
function processMsg(msg,nodeSend, done) {
|
||||||
var filename = node.filename || msg.filename || "";
|
var filename = node.filename || "";
|
||||||
|
//Pre V3 compatibility - if filenameType is empty, do in place upgrade
|
||||||
|
if(typeof node.filenameType == 'undefined' || node.filenameType == "") {
|
||||||
|
//existing node AND filenameType is not set - inplace (compatible) upgrade
|
||||||
|
if(filename == "") { //was using empty value to denote msg.filename
|
||||||
|
node.filename = "filename";
|
||||||
|
node.filenameType = "msg";
|
||||||
|
} else { //was using a static filename - set typedInput type to str
|
||||||
|
node.filenameType = "str";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => {
|
||||||
|
if (err) {
|
||||||
|
node.error(err,msg);
|
||||||
|
return done();
|
||||||
|
} else {
|
||||||
|
filename = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
filename = filename || "";
|
||||||
|
msg.filename = filename;
|
||||||
var fullFilename = filename;
|
var fullFilename = filename;
|
||||||
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
||||||
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
||||||
@ -158,7 +180,7 @@ module.exports = function(RED) {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (node.filename) {
|
if (node.filenameType === "str" || node.filenameType === "env") {
|
||||||
// Static filename - write and reuse the stream next time
|
// Static filename - write and reuse the stream next time
|
||||||
node.wstream.write(buf, function() {
|
node.wstream.write(buf, function() {
|
||||||
nodeSend(msg);
|
nodeSend(msg);
|
||||||
@ -256,6 +278,7 @@ module.exports = function(RED) {
|
|||||||
// Read a file
|
// Read a file
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
this.filename = n.filename;
|
this.filename = n.filename;
|
||||||
|
this.filenameType = n.filenameType;
|
||||||
this.format = n.format;
|
this.format = n.format;
|
||||||
this.chunk = false;
|
this.chunk = false;
|
||||||
this.encoding = n.encoding || "none";
|
this.encoding = n.encoding || "none";
|
||||||
@ -270,8 +293,28 @@ module.exports = function(RED) {
|
|||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
this.on("input",function(msg, nodeSend, nodeDone) {
|
this.on("input",function(msg, nodeSend, nodeDone) {
|
||||||
var filename = (node.filename || msg.filename || "").replace(/\t|\r|\n/g,'');
|
var filename = node.filename || "";
|
||||||
|
//Pre V3 compatibility - if filenameType is empty, do in place upgrade
|
||||||
|
if(typeof node.filenameType == 'undefined' || node.filenameType == "") {
|
||||||
|
//existing node AND filenameType is not set - inplace (compatible) upgrade
|
||||||
|
if(filename == "") { //was using empty value to denote msg.filename
|
||||||
|
node.filename = "filename";
|
||||||
|
node.filenameType = "msg";
|
||||||
|
} else { //was using a static filename - set typedInput type to str
|
||||||
|
node.filenameType = "str";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => {
|
||||||
|
if (err) {
|
||||||
|
node.error(err,msg);
|
||||||
|
return done();
|
||||||
|
} else {
|
||||||
|
filename = (value || "").replace(/\t|\r|\n/g,'');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
filename = filename || "";
|
||||||
var fullFilename = filename;
|
var fullFilename = filename;
|
||||||
|
var filePath = "";
|
||||||
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
||||||
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt class="optional">filename <span class="property-type">string</span></dt>
|
<dt class="optional">filename <span class="property-type">string</span></dt>
|
||||||
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
|
<dd>The name of the file to be updated can be provided in the node configuration, or as a message property.
|
||||||
|
By default it will use <code>msg.filename</code> but this can be customised in the node.
|
||||||
|
</dd>
|
||||||
<dt class="optional">encoding <span class="property-type">string</span></dt>
|
<dt class="optional">encoding <span class="property-type">string</span></dt>
|
||||||
<dd>If encoding is configured to be set by msg, then this optional property can set the encoding.</dt>
|
<dd>If encoding is configured to be set by msg, then this optional property can set the encoding.</dt>
|
||||||
</dl>
|
</dl>
|
||||||
@ -43,7 +45,9 @@
|
|||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt class="optional">filename <span class="property-type">string</span></dt>
|
<dt class="optional">filename <span class="property-type">string</span></dt>
|
||||||
<dd>if not set in the node configuration, this property sets the filename to read.</dd>
|
<dd>The name of the file to be read can be provided in the node configuration, or as a message property.
|
||||||
|
By default it will use <code>msg.filename</code> but this can be customised in the node.
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
|
@ -48,6 +48,7 @@ describe('file Nodes', function() {
|
|||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
//fs.writeFileSync(fileToTest, "File message line 1\File message line 2\n");
|
//fs.writeFileSync(fileToTest, "File message line 1\File message line 2\n");
|
||||||
|
process.env.TEST_FILE = fileToTest;
|
||||||
helper.startServer(done);
|
helper.startServer(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ describe('file Nodes', function() {
|
|||||||
//fs.unlinkSync(fileToTest);
|
//fs.unlinkSync(fileToTest);
|
||||||
helper.stopServer(done);
|
helper.stopServer(done);
|
||||||
});
|
});
|
||||||
|
delete process.env.TEST_FILE
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be loaded', function(done) {
|
it('should be loaded', function(done) {
|
||||||
@ -343,6 +345,64 @@ describe('file Nodes', function() {
|
|||||||
n1.receive({payload:"fine", filename:fileToTest});
|
n1.receive({payload:"fine", filename:fileToTest});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should use msg._user_specified_filename set in nodes typedInput', function(done) {
|
||||||
|
var flow = [{id:"fileNode1", type:"file", filename:"_user_specified_filename", filenameType: "msg", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
|
helper.load(fileNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("fileNode1");
|
||||||
|
var n2 = helper.getNode("helperNode1");
|
||||||
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload", "typedInput");
|
||||||
|
msg.should.have.property("filename", fileToTest);
|
||||||
|
|
||||||
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
if (os.type() !== "Windows_NT") {
|
||||||
|
f.should.equal("typedInput\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f.should.equal("typedInput\r\n");
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
n1.receive({payload:"typedInput", _user_specified_filename:fileToTest});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should use env.TEST_FILE set in nodes typedInput', function(done) {
|
||||||
|
var flow = [{id:"fileNode1", type:"file", filename:"TEST_FILE", filenameType: "env", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper"}];
|
||||||
|
helper.load(fileNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("fileNode1");
|
||||||
|
var n2 = helper.getNode("helperNode1");
|
||||||
|
|
||||||
|
n2.on("input", function (msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload", "envTest");
|
||||||
|
msg.should.have.property("filename", fileToTest);
|
||||||
|
|
||||||
|
var f = fs.readFileSync(fileToTest).toString();
|
||||||
|
if (os.type() !== "Windows_NT") {
|
||||||
|
f.should.equal("envTest\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f.should.equal("envTest\r\n");
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
n1.receive({payload:"envTest"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to delete the file', function(done) {
|
it('should be able to delete the file', function(done) {
|
||||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete", wires: [["helperNode1"]]},
|
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete", wires: [["helperNode1"]]},
|
||||||
|
Loading…
Reference in New Issue
Block a user