-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #981 from FlowFuse/44-file-upload
Widget: File Upload
- Loading branch information
Showing
11 changed files
with
426 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- | ||
description: The File Upload widget allows users to upload files to Node-RED. | ||
props: | ||
Group: Defines which group of the UI Dashboard this widget will render in. | ||
Size: Controls the width of the dropdown with respect to the parent group. Maximum value is the width of the group. | ||
Label: | ||
description: The text shown to the user, explaining what the user should upload. | ||
Icon: | ||
description: Defaults to "paperclip". The icon shown to the left of the input field. See the full list of icons <a href="https://pictogrammers.com/library/mdi/" target="_blank">here</a>. | ||
Accept: | ||
description: String representation of the "allow" file type selectors. See full list of options <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept#unique_file_type_specifiers" target="_blank">here</a>. | ||
Multiple: | ||
description: Allow end-users to upload multiple files at once. Each file will be sent as a unique message. | ||
--- | ||
|
||
# File Upload | ||
|
||
The File Upload widget allows users to upload files to Node-RED. The widget can be configured to accept specific file types and allow for multiple files. | ||
|
||
## Properties | ||
|
||
<PropsTable/> | ||
|
||
## Output | ||
|
||
```js | ||
{ | ||
payload: <Buffer>, | ||
file: { | ||
name: <String>, | ||
type: <String>, | ||
size: <Number> | ||
}, | ||
topic: <String>, | ||
} | ||
``` | ||
|
||
## Current Limitations | ||
|
||
_Currently_, the File Upload widget is limited by a maximum file size defined by the Websocket connection. The default maximum here is 5MB. This can be increased by modifying the `maxHttpBufferSize` property in the `settings.js` file in the Node-RED installation directory: | ||
|
||
``` | ||
dashboard: { | ||
maxHttpBufferSize: 1e8 // size in bytes, example: 100 MB | ||
} | ||
``` | ||
|
||
Read more about Dashboard configuration in the `settings.js` [here](/user/settings.html#maxhttpbuffersize). | ||
|
||
Note that we do have plans to improve this behavior by chunking files into smaller parts, and reassembling them on the server side. This will allow for larger files to be uploaded, and will be implemented in a future release. | ||
|
||
## Example | ||
|
||
![Example of a File Upload](/images/node-examples/ui-file-input-select.png "Example of a File Upload"){data-zoomable} | ||
_Screenshot to show an example file input, when ready to have a file selected_ | ||
|
||
![Example of a File Upload](/images/node-examples/ui-file-input-chosen.png "Example of a File Upload"){data-zoomable} | ||
_Screenshot to show an example file input, when a file has been selected, and is ready for "Upload"_ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<script type="text/html" data-help-name="ui-file-input"> | ||
<p> | ||
The file input node will provide a file select widget, allowing users to upload files to Node-RED. | ||
</p> | ||
<h3>Properties</h3> | ||
<dl class="message-properties"> | ||
<dt>Label <span class="property-type">string</span></dt> | ||
<dd>The text shown to the user, explaining what the user should upload.</dd> | ||
<dt>Icon <span class="property-type">string</span></dt> | ||
<dd>Defaults to "paperclip". The icon shown to the left of the input field. See the full list of icons <a href="https://pictogrammers.com/library/mdi/" target="_blank">here</a>.</dd> | ||
<dt>Accept <span class="property-type">string</span></dt> | ||
<dd>String representation of the "allow" file type selectors. See full list of options <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept#unique_file_type_specifiers" target="_blank">here</a>.</dd> | ||
<dt>Multiple <span class="property-type">boolean</span></dt> | ||
<dd>Allow end-users to upload multiple files at once. Each file will be sent as a unique message.</dd> | ||
</dl> | ||
<h3>Output</h3> | ||
<p><code>msg.payload</code> will contain a file buffer, and <code>msg.file</code> will provide meta data about the file itself.</p> | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
<script type="text/javascript"> | ||
(function () { | ||
function hasProperty (obj, prop) { | ||
return Object.prototype.hasOwnProperty.call(obj, prop) | ||
} | ||
RED.nodes.registerType('ui-file-input', { | ||
category: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.label.category'), | ||
color: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.colors.light'), | ||
defaults: { | ||
group: { type: 'ui-group', required: true }, | ||
name: { value: '' }, | ||
order: { value: 0 }, | ||
width: { | ||
value: 0, | ||
validate: function (v) { | ||
const width = v || 0 | ||
const currentGroup = $('#node-input-group').val() || this.group | ||
const groupNode = RED.nodes.node(currentGroup) | ||
const valid = !groupNode || +width <= +groupNode.width | ||
$('#node-input-size').toggleClass('input-error', !valid) | ||
return valid | ||
} | ||
}, | ||
height: { value: 0 }, | ||
topic: { value: 'topic', validate: (hasProperty(RED.validators, 'typedInput') ? RED.validators.typedInput('topicType') : function (v) { return true }) }, | ||
topicType: { value: 'msg' }, | ||
label: { value: 'File Input' }, | ||
icon: { value: 'paperclip' }, | ||
allowMultiple: { value: false }, | ||
accept: { value: '' }, | ||
className: { value: '' } | ||
}, | ||
inputs: 1, | ||
outputs: 1, | ||
icon: 'font-awesome/fa-upload', | ||
paletteLabel: 'file input', | ||
oneditprepare: function () { | ||
// if this groups parent is a subflow template, set the node-config-input-width and node-config-input-height up | ||
// as typedInputs and hide the elementSizer (as it doesn't make sense for subflow templates) | ||
if (RED.nodes.subflow(this.z)) { | ||
// change inputs from hidden to text & display them | ||
$('#node-input-width').attr('type', 'text') | ||
$('#node-input-height').attr('type', 'text') | ||
$('div.form-row.nr-db-ui-element-sizer-row').hide() | ||
$('div.form-row.nr-db-ui-manual-size-row').show() | ||
} else { | ||
// not in a subflow, use the elementSizer | ||
$('div.form-row.nr-db-ui-element-sizer-row').show() | ||
$('div.form-row.nr-db-ui-manual-size-row').hide() | ||
$('#node-input-size').elementSizer({ | ||
width: '#node-input-width', | ||
height: '#node-input-height', | ||
group: '#node-input-group' | ||
}) | ||
} | ||
// topic | ||
$('#node-input-topic').typedInput({ | ||
default: 'str', | ||
typeField: $('#node-input-topicType'), | ||
types: ['str', 'msg', 'flow', 'global'] | ||
}) | ||
}, | ||
label: function () { | ||
return this.name || this.label || 'file input' | ||
}, | ||
labelStyle: function () { return this.name ? 'node_label_italic' : '' } | ||
}) | ||
})() | ||
</script> | ||
|
||
<script type="text/html" data-template-name="ui-file-input"> | ||
<div class="form-row"> | ||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> | ||
<input type="text" id="node-input-name"> | ||
</div> | ||
<div class="form-row"> | ||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label> | ||
<input type="text" id="node-input-group"> | ||
</div> | ||
<div class="form-row"> | ||
<label><i class="fa fa-object-group"></i> Size</label> | ||
<input type="hidden" id="node-input-width"> | ||
<input type="hidden" id="node-input-height"> | ||
<button class="editor-button" id="node-input-size"></button> | ||
</div> | ||
<div class="form-row"> | ||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label> | ||
<input type="text" id="node-input-label"> | ||
</div> | ||
<div class="form-row"> | ||
<label for="node-input-icon"><i class="fa fa-picture-o"></i> Icon</label> | ||
<input type="text" id="node-input-icon"> | ||
</div> | ||
<div class="form-row"> | ||
<label for="node-input-accept"><i class="fa fa-paperclip"></i> Accept</label> | ||
<input type="text" id="node-input-accept"> | ||
</div> | ||
<div class="form-row" style="padding-left: 25px;"> | ||
<input type="checkbox" checked id="node-input-allowMultiple" style="display:inline-block; width:auto; vertical-align:top;"> | ||
<label style="width:auto" for="node-input-allowMultiple"> Allow Multiple</label> | ||
</div> | ||
<div class="form-row"> | ||
<label for="node-input-className"><i class="fa fa-code"></i> Class</label> | ||
<div style="display: inline;"> | ||
<input style="width: 70%;" type="text" id="node-input-className" placeholder="Optional CSS class name(s)" style="flex-grow: 1;"> | ||
<a | ||
data-html="true" | ||
title="Dynamic Property: Send msg.class to append new classes to this widget. NOTE: classes set at runtime will be applied in addition to any class(es) set in the nodes class field." | ||
class="red-ui-button ui-node-popover-title" | ||
style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;"> | ||
<i style="font-family: ui-serif;">fx</i> | ||
</a> | ||
</div> | ||
</div> | ||
<div class="form-row" style="padding-left: 25px;"> | ||
<label for="node-input-topic" style="margin-right:-25px">Topic</label> | ||
<input type="text" id="node-input-topic"> | ||
<input type="hidden" id="node-input-topicType"> | ||
</div> | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// const datastore = require('../store/data.js') | ||
|
||
module.exports = function (RED) { | ||
function FileInputNode (config) { | ||
const node = this | ||
|
||
// create node in Node-RED | ||
RED.nodes.createNode(this, config) | ||
|
||
// this ndoe need to store content/value from UI | ||
node.value = null | ||
|
||
// which group are we rendering this widget | ||
const group = RED.nodes.getNode(config.group) | ||
|
||
const evts = { | ||
onAction: true | ||
} | ||
|
||
// get max file size supported | ||
const MAX_FILESIZE_DEFAULT = 1e6 | ||
const maxFileSize = RED.settings.dashboard?.maxHttpBufferSize || MAX_FILESIZE_DEFAULT | ||
|
||
config.maxFileSize = maxFileSize | ||
|
||
// inform the dashboard UI that we are adding this node | ||
group.register(node, config, evts) | ||
|
||
node.on('close', async function (done) { | ||
done() | ||
}) | ||
} | ||
|
||
RED.nodes.registerType('ui-file-input', FileInputNode) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.