An idea for third-party UI in ui-builder

Split from: Custom node appearance and event handlers. Proof on concept: Inline Gauge - #44 by TotallyInformation

@jackcarey :

How would you feel about having a new node in uibuilder that could extract a property named something like uib from other nodes in order for them to package their own HTML, UI, or ui-builder config? Do you think there is enough potential to make this worth investigating?

@TotallyInformation :

There is something on the backlog I've had for quite a while (I think it is still there - the backlog is a bit large!) to help facilitate 3rd-party nodes for uibuilder. So certainly worth a discussion.

The idea I had:

For node developers: The node developer can configure a _uib attribute to contain two properties of type, a string matching an existing uibuilder node type (tag, element, html, etc) and data, a synchronous function that returns an object containing the properties needed for uibuilder.

For uibuilder: Add a new node called uib-integrate that fetches the current flow object when the editor side panel is opened, and filters node instances to those with a _uib attribute. These become selectable by the flow creator.

For the flow creator: The user then selects the third-party node they wish to render from a drop-down in the uib-integrate, using the node labels and IDs to identify them.

For flow execution: When the uib-integrate node is triggered, it calls the data function on the integrated node to return the latest uibuilder config for the UI.

With this set up, the UI could be updated out of order from the underlying data and vice versa and the data structures for third party integration can match what uibuilder already expects.

Thanks for raising this topic Jack. Definitely interested in making it easier for other developers to add to the UIBUILDER universe.

An interesting approach. Though I'm not sure the uib-integrate node is actually needed. You see, the current no-code nodes (uib-element, uib-tag and uib-update) don't need anything special because all they do is output a message containing a msg._ui object property that describes the elements to be created or updated.

So anyone could take a copy of the uib-tag node (the simplest of the no-code creator nodes) and alter it to output something different and adjust the settings accordingly.

I've been trying to find time to produce a uib-uplot node as an example. You can see the progress here: TotallyInformation/nr-uibuilder-uplot: An add-on node for node-red-contrib-uibuilder that outputs a working uPlot chart. Also an exemplar for building your own uibuilder extensions (github.com) though I don't believe it works at present & it doesn't use the latest code like uib-tag does. But, of course, the idea is to output a msg._ui that outputs a description of the required HTML, JavaScript, etc needed to add a uPlot chart to your web page. Anyway, if you do look at the code, you will find the buildUi function which does the basic construction of the output in about 50 lines of code. Of course, that does not, as yet, include all the parts for actually creating the plot. Check the uib-elements equivalent function to see sometihng a lot more complex. And, also of course, such nodes would not be restricted to being able to produce a single element type, like uib-element, they could produce any number of different outputs and could even incorporate update, not just create capabilities.

The advantages of this approach being that:

  • Contributed nodes are entirely de-coupled from uibuilder itself.
  • Nodes can be hydrated to HTML server-side by the uib-html node, not just client-side. Indeed, the ui.js library is pretty much standalone and could easily be incorporated into other nodes or to projects completely outside of Node-RED (in fact, I used it in a work project not so long back).

So while I'm certainly not discounting your idea, I wonder if it is going to add much benefit to users? Perhaps some good examples using the existing capabilities might be a good place to start. That way we could find any rough edges to the process and see about dealing with those?

This, I think is the bit I haven't quite got my head around.

At the moment, we have nodes that create/replace (possibly compound) elements - These can already be run out of order since they attach to specific locations on the page. And a node that does updates of anything. What we don't have, though it is absolutely possible to create because all of the no-code nodes output low-code JSON configuration, are any nodes that can do both create/replace OR update. An I think that is necessary at some point, for some types of elements - I'm particularly thinking of charts - because more complex elements will probably have very specific data update requirements that might need client-side processing. Adding a new data point, possibly dropping off old data points, adding annotations, animation, .... For those kinds of things, I suspect that having a node that does both create/replace and update would be very beneficial.

Again, though, because all of the nodes simply output low-code configuration data, all of this should be doable with the existing capabilities - I think.

Thoughts?

My reasoning behind the uib-integrate node was to make code-reuse simpler, but if that's not needed then it can obviously be ignored. The high-level idea for me is to essentially stack the simplicity of Dashboard on top of uibuilder, such that some arbitrary HTML UI can be packaged with any node and dropped into a specified position on a page. uib-integrate was intended to take the third party config, then wrap/transform it with something predictable like a CSS selector it should replace/append to. The reason for this is that with third-party nodes passing their own _ui property around, I think flow designers would then have to use function nodes to alter the _ui property to fit their template. Is that correct?

There is something there, The most complex part of creating a new no-code node is dealing with the settings - especially if you want to use typed inputs. I have a standard function that makes it easier in the runtime but I'm wondering if there is something I could do to make the Editor side easier. That is actually one of the worst aspects of Node-RED in my view, creating the edit panels is rather more complex than desirable.

So this has got me thinking as to whether some kind of standard support library for creating node edit panels might be even more useful. I've already started moving some common processing in uibuilder nodes to a common library. Maybe some simple web components to simplify the actual panel HTML, they could possibly even do some of the processing in the component.

If we could make it easier to create edit panels that have flexible typed inputs, that would be a nice addition to Node-RED as a whole, not just UIBUILDER.

Well, you don't just have to use a function node of course, the advantage of having a standardised data schema is that ANYTHING in Node-RED that can work on a msg can manipulate (improve/change/add-to) a msg._ui that another node has created. This is incredibly powerful without being too complex.

But here, perhaps might be another approach. A node that can easily be used to manipulate certain aspects of a msg containing a _ui property. Specifically, one that can add/change the top-level parent. At the moment, the uib-update node is designed to update at the front-end, not in Node-RED. So another node that can work on the _ui property in Node-RED would indeed be very useful.

Nodes that create _ui properties could then not only send direct to the front-end but could instead (or as well as) use standard Node-RED capabilities for storing and reuse as templates. (a vague thought occurs about a node designed to manage templates - need to think about that a bit more).

So that is something interesting I could fairly easily add to uibuilder. Not sure if uib-integrate would still be the right name though?

Anyway, thoughts on this?

Agreed on all of this. It’s something we actually spoke about last year: Ideas for Node Authoring: Auto-HTML Generation, Rendering Extra Info, Type-checking, Multiple Inputs

I think this is a good idea :+1: uib-override or uib-config could be more appropriate names?

1 Like

Drat, there's that aging brain again! I'd completely forgotten about that :slight_smile:

I think I might start yet another thread about this. I've certainly some interesting ideas floating in the noggin but doubtless others will want to contribute as well.

Great! I'll start to look at this - I'm already started on v6.9 anyway and hopefully, this can be a feature highlight.

Haha, I only remembered the conversation when I read your message! I’m happy to keep the conversation here until the ideas can be formulated a bit more?

One thing I’m curious about is what you think of HTMX? It performs similar work to uibuilder, but a simple implementation in NR can be made without any extra packages. I think it would face the same challenges as uibuilder with regards to third party components though, as there is no standardised way to refer to them in the msg object. A greenfield UI/dashboard project could probably make great use of a html property like we have with payload already so now I’m curious now about comparing flows for the same UI made with HTMX vs with uibuilder… :thinking:

I've looked at it. It is, of course, a lot younger than uibuilder :slight_smile: so it didn't exist when I started (it is 4yo, uibuilder is 7). And without wishing to denigrate it, it is another opinionated front-end framework. That isn't to say it isn't good - but there are lots of good frameworks around. I do my best to try and stop uibuilder from being a framework (though I recognise that convergent evolution tends to lead that way). The UI part of uibuilder is about being as close to HTML as you can be without needing to exactly know all of the many foibles and traps of the DOM API's.

Well, it might well be an alternative to uibuilder's low-code UI features. But of course, the actual code for those is pretty tiny. The bulk of uibuilder code is about having a robust set of interfaces with Node-RED, dealing with the complexities of managing supporting front-end packages, providing the many endpoints for shared and instance specific services, the API's, middleware capabilities, template management, alternate web server options, .... 582 files, probably 10's of thousands of lines of code.

That is absolutely the case. And I've previously tried to interest others in spending time enhancing a standardised JSON low-code configuration schema for building web UI's for Node-RED. Unfortunately, I perhaps didn't get the concept or its benefits across properly because nobody else seemed interested. So I soldiered on because I saw a set of strong benefits that fit in with the overall ethos of Node-RED.

And while the current schema is far from perfect, I've already demonstrated to myself several times that it is incredibly powerful and quick to build web UI's - at least of a certain level of complexity. BUT, the big thing is that, unlike most other front-end frameworks, it does not lock you out of native HTML since it actually produces native HTML.

And I've always said that if anyone wanted to use the schema in their own projects - I would welcome that and support them as best I could. It is Apache licensed open source after all.

And UIBUILDER can help you with that! Just use HTMX instead of uibuilder's UI schema. :grinning: Just remember though, that with HTMX, you are not building HTML. That brings certain baggage and commitments that you will need to carry for a long time. With uibuider's UI features, you absolutely are building HTML and you can simply turn off those features and you still have HTML. You could take the resulting page out of Node-RED altogether and wire it to some other realtime data service and it would mostly still work (with a few tweaks to handle differences in API's) if you had to. You can even build using the UI no-/low-code features and save the resulting HTML back to your HTML page as static HTML. I don't believe you can do that with any of the front-end frameworks.

But even so, if JSON config low-code doesn't do it for you, by all means use something different and let the rest of uibuilder's features continue to support you.

What about it do you think is opinionated?

This is what I'd struggle with in HTMX, how best to construct the HTMX code to ensure instance specific information is only delivered to the right client.

It's interesting that the backend data flow has been standardised around a freeform msg object, but such a thing for the frontend is inherently hard to do, if only because of the complexity and diversity of components that are out there.

I'm not sure I understand what you mean here, especially with HTMX being an extension to HTML attributes and compatible APIs returning HTML themselves

The interesting angle on HTMX is that it allows backend developers to focus on the backend, but ultimately it does take a similar place as SignalR, uibuilder, etc in that it streamlines the two-way communication between front and back. Like you said, the complexities you mention around endpoints are probably going to deter me from switching to HTMX anyway

All of the frameworks are. They assume that vanilla HTML and the DOM API's can't do the job and they propose their own opinions as to how to "fix" it.

uibuilder has mostly already dealt with that, especially now that you can limit sent messages to specific client id's and/or page names (actually, currently everything is still send everywhere but the receiving client ignores it if not for them, this is something I want to enhance in the future by using socket.io's rooms features so as to be a bit more efficient and secure).

This is why the schema is a simplification of vanilla HMTL/DOM, it is inherently capable of accommodating future HTML/DOM features with minimal change and maximal backwards compatibility. This is largely because of the way that HTML and the DOM API's are constructed. HTML only allows a few interactions. For example, you can only add string attributes to HTML but you can add more complex properties via the DOM API's.

Is it really an extension? I don't believe it is (though perfectly possible I misinterpreted), it is an opinionated alternative to native HTML capabilities. It uses its own attribute types that are not native. Does it need to? What does that add and how does it have to bend HTML to accommodate those proprietary extensions? In the case of more complex frameworks, they have to generally take things out of the DOM in order to add their capabilities - maybe HTMX avoids that? But it still isn't standard, native HTML.

Yes, you would still have to take care of all the other things I mentioned that uibuilder has already taken care of.

Interesting discussion by the way. Keep it coming. :slight_smile:

I think it's fair to say that this could be said of any code that provides an abstraction on top of the W3C standards, including the schema implemented on the frontend of uibuilder? At what point would you draw the line between a package that’s plainly using the DOM APIs and a package that has an opinion about them? Is uibuilder therefore opinionated too, since it "fixes" the act of updating the DOM using its own schema in the websocket messages (not a bad thing, just exploring the definition)? The rooms feature of socket.io is great, definitely useful for security like you said.

My understanding and (admittedly limited) experience of HTMX is that it does avoid taking things out of the DOM since it's replacing/modifying the elements already within it. HTMX could just as easily use data-hx- attributes in place of the hx- it uses currently, or implement custom elements as wrappers for the rest of the DOM. Those would then be native by meeting web standards. It instead provides syntactic sugar for existing DOM-driven operations, using the DOM itself as the orchestrator of events and updates. My opinion is that it seems to put the 'hyper' back into 'hypertext' with the least amount of opinion possible

I may be a little biased but I don't think so. The low-code schema is an abstraction, that is true. But it does not add or replace anything. It IS ALL DOM, the ui code simply "hydrates" the low-code into pure HTML and adds a few "levelling" pieces of JavaScript, nothing else.

The JavaScript is mostly about saving you having to know about the fact that there are elements of the DOM API's where a returned object cannot simply be stringified because nobody bothered to add that capability to some parts but they did in others. Or it levels out the oddity where all the <input> tag type have a value property - except for a checkbox type which doesn't.

Perhaps I'm splitting hairs a little with some of the other lightweight frameworks, I'm not totally sure, but certainly Angular, Vue, REACT, etc, none of them do this, they all add their own opinionated way of doing things that are not the DOM way. And, to be completely fair, this was a good approach when the DOM was a shadow of its current self.

OK, so now we are really venturing into slightly different territory. The UI aspects of uibuilder really are pure DOM as described above, it offers no opinion about that other than to say that mostly the DOM is fine and can now do pretty much everything. Only that it has a few quirks that catch non-experts out (and experts too!).

But the messaging side is different. The DOM does not include native realtime messaging of course and while browsers all natively support the websockets protocol, it is just that, a protocol, it is not a full API. So yes, there we do express an opinion and that opinion is the more capabilities are needed than raw websockets provides and that Socket.IO is the industry-leading library for Node.JS and the browser that provides the needed features.

So you really need to think of uibuilder's UI and communications features separately. After all, the UI features are now in a completely separate library that can be used totally independently of uibuilder.

The comms features relate to Node-RED, the UI features do not.

Well, I'm not really arguing one way of the other as to whether HTMX is a useful framework for certain use-cases or ways of thinking. After all, I've not spent a lot of time looking at it. All I am saying is that my experiences with many different frameworks over the years have all ended with the same conclusion which is that they look great to start with and then wear thin on extended use. But by that time, you end up committed to a direction and it is hard to change. Over the years, uibuilder aligned to 3 different frameworks (jQuery, MoonJS and VueJS v2), each eventually proved to be a burden more than an asset. And, over those same years, HTML, CSS, JavaScript have all "improved" massively - at least from the perspective of showing and manipulating a browser-based UI. To the point that I found I no longer needed a framework for anything.

Not to say that there aren't places for frameworks even now. If you need a lot of very high-quality components for example then a framework gives you a rapid leg-up. Though, again, at the cost of being wedded to the framework - but that may sometimes be an acceptable trade-off.

Over time, I expect to see increasingly better and more consistent sets of pure web components as well and then I think the days of the traditional frameworks will be numbered. Only ones such as Svelte and LIT will survive because they can offer progressive enhancement of HTML not a different approach. But UIBUILDER will also continue to survive because it "just" uses vanilla stuff under the skin. It doesn't even attempt to enhance HTML, it just uses it. Enhancement is mostly then left to using either pure web components or a compatible framework according to the needs of your project. And, a reminder, I've not found ANY front-end framework that would not work with uibuilder.

By the way, if you wanted to propose a version of the uibuilder front-end library that does not include the ui parts, I could absolutely do that.

1 Like

I agree with you 100%. I think even a pure web component based UI will have issues with state management though, so it'll be interesting to see which parts of the current frameworks survive.

1 Like

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