Ideas for Node Authoring: Auto-HTML Generation, Rendering Extra Info, Type-checking, Multiple Inputs

I'm writing this post to garner feedback on some ideas I have to improve the node authoring experience in NodeRED (not expecting any sort of implementation from anyone).

Automatic HTML Generation

Why: When creating nodes, the editor inputs often use known data types (number, string, bool, URL, etc) and the help text details each of them. This means that the HTML config object, editor input, and help text to describe them follow the same structure somewhat redundantly - the authoring process is repetitive.

Proposed Solution: Allow the registerType() method called in the node's .js file to accept an optional third parameter that contains the object normally seen in the .html file. Each item in the defaults attribute could have extra data for helpText, label, types, and buttons. A function in the NR runtime could then generate the HTML for these inputs using it's standard input types and classes.

Known blocks: It needs to be backwards compatible with existing nodes and complex inputs still need to be supported. For this reason, checking for a HTML file should be done before processing the new UI object. The UI object could then be ignored if a HTML file is present.

Example (lower-case):

//lower-case.js
module.exports = function(RED) {
    function LowerCaseNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        node.on('input', function(msg) {
            msg.payload = msg.payload.toLowerCase();
            node.send(msg);
        });
    }
    const LowerCaseUI = {
        category: 'function',
        color: '#a6bbcf',
        defaults: {
            name: {value:"",
                   helpText:"The display name of the node",
                   label: "Name",
                   icon: "fa-tag",
                   types:["str","num","bool"]
}
        },
        inputs:1,
        outputs:1,
        icon: "file.png",
        label: function() {
            return this.name||"lower-case";
        }
    };
    RED.nodes.registerType("lower-case",LowerCaseNode, LowerCaseUI);
}

Rendering Extra Information

Why: The blocks used in Blender and Unreal Blueprints, display extra information that makes them easier to use, such as IO labels, text, thumbnails, or parameter inputs. The status text of a node can be used for a similar purpose, but it's limited to one line of text.

Proposed Solution: image-tools renders image previews by manipulating the editor DOM, but I think it would be more useful to make this available behind an attribute in the same way the color, icon, and label already are. My thinking with inputs is to allow them to be togglable for 'quick change' from the editor sidebar, so only items the user is changing frequently would appear on the flow and these could then automatically trigger a re-deploy when they are changed. When authoring a new node, a quick-change attribute could be set to 1 for enabled by default, 0 for disabled by default, or -1 for not available to quick-change.

Known blocks: Complexity.

Type-checking (wires)

Why: The current msg object can be completely free-form in it's structure, which is great when you know what data to expect across a flow. However, when working with custom nodes, complex data, or large flows it's possible to connect blocks that would pass messages with incompatible data structures.

Proposed Solution: In order to avoid this, a types attribute could be added to nodes (perhaps in the UI object as mentioned above), that contains an array of either schema.org strings or URLs to custom types. When joining nodes with wires, the appearance of the wire could change based on the result of the type check: from solid to dashed if there might be a type mismatch, or from solid to dotted if there are no matching types. A tooltip to explain the mismatch could also be provided as well. This would be a client-side editor check and not affect runtime behaviour, though similar to bad node configurations, a warning that lists the incompatible wires could be displayed when a deploy is triggered.

Known blocks: backwards-compatibility. To overcome this, types must be specified on both ends of a wire in order for its appearance to change.

Example:

<!-- custom-node.html-->
<script type="text/javascript">
    RED.nodes.registerType('custom-node',{
        // ... node definition
        inputTypes: ["Text","*"], //an empty string or an asterisk could be used for 'any' type
        outputTypes: ["Text"]
    });
</script>

Multiple Inputs

Why: msg attributes can be used to provide everything needed to a node, however it can be difficult to visualise this flow of data when transforms are obscured inside a function block, or the single output of a node. As in Unreal, being able to visualize which msg attributes are being set by which other nodes would make understanding complex flows much easier.

Proposed Solution: Allow data attributes to be made available as inputs for the node, possibly by supplying a process function to the UI object above that would handle parsing a msg and storing information against the node instance.

Known blocks: backwards compatibility, complexity. How best to get data into these inputs: If msg objects are used then a race condition could occur where the an input attribute is not set by one message before the msg that triggers outputs is received. This requires more thought as another solution could be to allow nodes to provide 'constant' outputs that can be read at will rather than only passed through a message, but that is a complex change to make to the current structure.


I'm aware of the complexity of the last three, but I think these ideas together could vastly improve the experience of creating nodes & using nodes and using the automatic HTML generation as a starting point could be a good way to work towards the other extensions.

Some interesting ideas and some that have been repeatedly rejected for valid reasons.

This is certainly something that is interesting. The way you have to create the .html file at the moment is certainly relatively complex and repetitive. However, I suspect that it may be relatively efficient at runtime. My concern about your proposal is related to what it would do to Node-RED startup times since you would effectively be dynamically generating all of the HTML at runtime.

The only other concern would be that the definition object would need to be comprehensive enough to be able to generate all the things that can be done in raw HTML. The help panel may contain much more info than just the input fields for example. Similarly, the more complex nodes such as uibuilder, have quite complex settings panels that use tabs to structure settings along with inline help. They might also use controls that do not directly relate to the defaults which are only about the configuration data that the node records.

For my nodes, I now split the source code for the html file into 4 files. A master template, a javascript file, the main panel html and the help panel html. What would be interesting to me is a way of automating the basic construction of the html file based on some initial input settings (e.g. the fields required with their default structure, types, etc). Such a tool would also help encourage the use of best-practice in structuring the javascript (e.g. using named functions instead of one big function) as well as the html of the panels.

Not sure I've much to comment here other than saying that the mantra for node-red has always been that the Editor is not a dashboard and therefore limiting the information displayed on it is encouraged.

Some kind of optional schema_ checking might indeed be a useful standardised component. But is overkill for a lot of nodes.

This has always been strongly rejected due to the overall asynchronous nature of flow-based processing using node.js. Other flow-based tools do, indeed allow each defined input attribute to be defined as an input port. However, my experience of those is that they are generally MUCH more complex to use. One of the great strengths of node-red is its simplicity to get started but lack of "cliff-face" as you move to ever more complex processing. While Unreal is a fabulous example of a graph-based interface, it is not really a great example of simplicity! Neither is Blender. :slight_smile:

Node-RED is a flow-based processor, not really a graph-based one. The ability to think of it as a series of messages that flow from one node to another is a really simple but powerful concept. Having a single input port helps people focus on that concept and also ensures that node representations in the flow remain relatively simple. If you want to provide all of the inputs via multiple messages, then simply accumulate the data using a sequence of nodes. Compare node-red with something like n8n for example, I think that you will find that node-red is far more straight-forwards to get into.

2 Likes

I would add just two comments to @TotallyInformation's reply.

First, it might help the discussion to distinguish between tools to support the development of custom nodes on the one hand and changes to the flow editor on the other. The first are likely to be more welcome, since they would be completely optional and used by only a minority of Node-RED users. The second require modification of the NR core and can alter the basic structure of the programming tool. Your suggestion for automatic HTML generation blurs the boundary by making the core do the work.

I have misgivings about your ideas for type checking and multiple inputs. They seem to reflect an understandable tendency to think of NR in terms of states rather than messages. Except for data that the user explicitly retains in context or MQTT messages or saves in a file, all the information in NR is contained in messages. Forcing nodes to accept only fixed data structures, requiring properties to be set only by specific nodes, or "reading" node outputs rather than context, all compromise this architecture without really adding capability.

2 Likes

Some interesting thoughts there for sure.

Re Auto_HTML - don't forget you can use the nodegen project to convert a subflow to a node - not perfect by any means but does help create the html config pages for you. Also @Steveorevo has just released this project that may help - Node Maker is here!

Re type checking - when we have considered this before - we always came up with more exceptions than there were rules. The number of times they would "get in the way" and slow down developing (say) a function node by having to create a ui to create this schema that can cope with many levels deep (as many nodes output objects not simple types - which then need to be expanded etc etc)... just makes the complexity (both in implementation/maintainance and user understanding especially for beginners) seem to outweight the utility. Instead we try to encourage creators to provide consistent info for the sidebar that describes what nodes accept, both mandatory and optional, and what they output. Also one of the key aspects of the flow is the ability to pass through other properties - so they would all have to be ignored, and many properties are optional etc.. All in theory do-able of course, but....

2 Likes

However, I suspect that it may be relatively efficient at runtime. My concern about your proposal is related to what it would do to Node-RED startup times since you would effectively be dynamically generating all of the HTML at runtime.

This is a concern for me too. Looking through loader.js, I think it'll be possible to write conditional replacements for loadNodeTemplate and loadNodeConfig, but I need to investigate when they're called in order to check timing. In loadNodeTemplate a call to the file system is made and the HTML there is then parsed using regular expressions, so it seems that dynamically generated HTML could even be faster if it avoids that?

The only other concern would be that the definition object would need to be comprehensive enough to be able to generate all the things that can be done in raw HTML.

I disagree, I think. As backwards compatibility would need to be maintained for current nodes anyway, complex inputs like those seen in uibuilder could continue to use a HTML file as they do today, with this new method only used after a HTML file doesn't already exist.

Some kind of optional schema_ checking might indeed be a useful standardised component. But is overkill for a lot of nodes.

Agreed, it'd definitely need to be optional.

Node-RED is a flow-based processor, not really a graph-based one.

This concept has made me change my mind on multiple inputs. I'd never considered the difference between flow & graph-based low-code platforms before and you're right about the learning curves, thanks. Something to look into for sure!

Seems you're right about the complexity of implementing type-checking. Node Maker looks super interesting though, I'll definitely give it a go!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.