๐ŸŒŸ It's here! uibuilder v6.1.0. Coming of age - uibuilder grows up

In this release, it feels like uibuilder really is growing up. No more apologising for not being a direct Node-RED Dashboard replacement, uibuilder has its own path.

You can now create and update visible web page elements direct from Node-RED data without needing to understand all of the intricacies and inconsistencies of HTML. You can create your own utility tools either in Node-RED or in front-end code that leverages the low-code UI features of uibuilder. You can get information about the current state of your web pages back into Node-RED. You can save and reload the current state of your web pages. You get custom information from the front-end to help with security decisions and control. You can use a custom web server rather than Node-RED's and you can use custom middleware for fine-grained control. And so much more. A comprehensive review of the documentation has also started with some notable updates already that will hopefully make things easier to follow.

So please enjoy this new release it might be a small number change, but it is a big leap forward that paves the way for a lot more to come.

Summary of notable changes

Just a quick summary here. See the main sections for more details.

Please remember that no changes are being made to the old uibuilderfe.js client. Nothing listed here applies to that.

  • New zero-code nodes uib-element and uib-update let you use simple data to create dynamic web UI's. Including in this release: tables, forms, lists, raw HTML and page title. More to come.

  • The client library has a number of fixes and new features

    • Extensions to the eventSend function to include form data and value changes. Should greatly simplify creating and using FORMs and providing quick inputs for Node-RED flows. Used by uib-element to create zero-code input forms.

    • New function: uibuilder.showMsg() Displays/hides an on-screen card that automatically updates with the last msg received from Node-RED.

    • New function: uibuilder.showStatus() Displays/hides an on-screen card that shows the current status of the uibuilder client. Use for debugging where console output is not available or not desirable (e.g. debugging pages on mobile devices).

    • Some client functions can now be controlled direct from Node-RED via simple messages. Changing log levels, show/hide message and status displays, getting uibuilder client variable values join the ability to reload the page. More to come in the next release.

    • New function: uibuilder.uiGet(cssSelector) Gets useful data about an HTML element direct from the DOM. Saves lots of faffing when digging through DOM details.

    • New function: uibuilder.watchDom(true) Starts watching the content of the page and saves it to browser localStorage so that it can be recovered at any time. Use uibuilder.restoreHtmlFromCache() to recover the stored HTML (e.g. on page load). Use uibuilder.watchDom(false) to turn off and uibuilder.clearHtmlCache() to remove the saved HTML. If desired, you can manually save the HTML at any point using uibuilder.saveHtmlCache().

    • The uibuilder client now reports changes of visibility of pages back to node-red via a new control msg.

    • When using the _ui low-code features, you can now position a new element anywhere within its parent. Either first/last or a position number can be used.

    • There is a new mode for the _ui low-code features - "removeAll". This allows a selection of elements to be the target of a remove - for example, all list entries could be removed with a single command.

    • Creates a browser tabId which is reported back to node-red when messages are sent. Helps identify the origin. Future uibuilder versions will let you send messages to a specific tab id which does not change even if the page is reloaded (only if the tab is closed).

    • Messages sent from the client either inherit the topic from the last inbound msg or from a default set using uibuilder.set('topic', 'my topic string'). The default will take preference. Reset by setting to an empty string.

  • If you turn on the advanced option "Include msg._uib in standard msg output", messages from the client now include client details for you to use in your own security processing or just to identify where things have come from (e.g. what page name as well as what client).

  • uibuilder now makes a copy of its main <uibRoot>/package.json file to package.json.bak before it updates it. Trace and error messages have been added to the process.

  • All of the templates and example flows have been refreshed with the latest standards.

  • The default style-sheet uib-brand.css has various updates and improvements.

  • Plenty of documentation updates and additions.

Notes for this release

v6.1.0 makes the new client libraries (uibuilder.esm.min.js and uibuilder.iife.min.js) current and the old client library (uibuilderfe.js) is now no longer recommended and is not being updated, it is on the road to being deprecated (it will remain until at least v7, mahbe v8 but probably not longer unless someone calls for it).

The experimental uib-list node is now deprecated, the features are moved to the new uib-element node. It will be removed certainly by v7.

The new uib-brand.css style library is not yet feature complete - if you find something missing or wrong, please raise an issue. It does, however, continue to develop.

Dynamic content does not currently work fully with VueJS (and probably not other frameworks that rely on pre-building components). It is possible though to combine the vanilla HTML from the low-/no-code features with front-end frameworks. Such frameworks require both the components and the structure to be pre-defined before the DOM is fully loaded. They have their own methods to provide dynamic includes, lazy loading, etc that are very different (and generally much more complex) than uibuilder's simple to use feature. However, dynamic content DOES work with HTML components and any frameworks that are compatible with them such as Svelte. The component definitions have to be loaded before you use them (that can be dynamic too!) and you must use the ESM build of the uibuilder client library since HTML Components are ES Module only.

uibuilder node

  • Added JSON and Form encoded body processing to all user instance routes to allow for processing POST requests

  • Added new user web endpoint ./_clientLog (web.js::addLogRoute()). This can only be POSTed to and should only be used for navigator.sendBeacon text messages (the body of the POST has to be plain text).

  • Updated optional msg._uib properties on standard output messages, additional metadata added:

    msg._uib = {
      "clientId":"0yB8nqLSbhWAEyEpEuPYa",
      "remoteAddress":"::1",
      "pageName":"index.html",
      // The uibuilder URL setting
      "url":"uibUrl",
      // ID of the client tab - NOTE: If a tab is duplicated, it will have the same ID
      "tabId":"t568878"
    }
    

    This data should help when working out identities for authentication and authorisation as well as enabling specific page/tab/user processing.

  • Updated connect, disconnect and error control messages. They now show more details about the originating client and page.

    In particular, the connect msg now has msg.lastNavType which shows what the browser reported about the last time the originating page loaded. e.g. "navigate", "reload", "back_forward", "prerender". This comes from the Performance browser API.

  • Reinstated ability for client to send uibuilder control messages.

    • New "visibility" control msg now added which uses the document visibilitychange event.
  • Editor

    • Added Open button to top button bar next to Delete. Add globe icon to open buttons.
    • Added Docs button next to new Open button. Add book icon to docs buttons.
    • Disable the new Open button along with other disabled things when new or url has changed.
    • Icon changed.
  • socket.js

    • When asked to add msg._uib to std output msgs, Standardised on the same client details as for control msgs to make downstream processing easier.
    • Added visibility-change control msg. Sent by FE client. Fires when the open page changes from hidden-to-visible or visa versa.
    • New functions: sendCtrlMsg, getClientDetails. Standardise/simplify client details shown on control msgs.
  • web.js

    • Added new addBeaconRoute function that sets up the ./_clientLog instance endpoint. Use the new client uibuilder.beaconLog(txtToSend, logLevel) function to send a simple text log back to Node-RED even if socket.io isn't working.
  • package-mgt.js

    • A backup copy of package.json to package.json.bak is now made on each write.
    • Trace/Error log messages added to writePackageJson.

IIFE/ESM/Module client library

  • Bug fixes

    • Fixed issue where method:update for msg._ui handling would cause a loop and console error. An assign by reference error fixed by forcing a shallow copy at the start of _uiUpdate.
    • Fixed bug where the library was loading uib-brand.css even when it didn't need to. It now doesn't load automatically even if there is a single stylesheet loaded on startup.
  • uibuilder.eventSend(event) function improved.

    • Now prevents the default event action from happening.

    • If the element that triggers the event is part of an HTML form, the names and values for all input elements in the form at the time of sending will be attached as msg.payload properties. Extended data for all input elements inside the form are included in msg._ui.form.

    • If the event type is change(e.g. a user changed an input field and then moved to a new field), a msg._ui.newValue property is generated.

      If you want to report the old value as well, you need to add something like onfocus="this.setAttribute('data-oldvalue', this.value)" to the element's attributes. This would be included both in msg.payload.oldvalue and in msg._ui.attribs.data-oldvalue.

      Alternatively, onfocus="this.uib_oldvalue = this.value" would cause the previous value to be included as msg._ui.props.uib_oldvalue.

  • Added a default msg.topic option. uibuilder.set('topic', '....') Will be used in msgs sent back to node-red if no topic specified. Note that if the default topic is not set, messages will inherit the topic from the previous inbound message if that had a topic. Reset by setting to an empty string.

  • The following client functions can now be called direct from Node-RED via a msg like: {_uib: {command:"showMsg", value:true}}. get, set, showMsg, showStatus. More will follow in the next release.

  • Added new functions

    • uibuilder.showMsg(true, selector=body) - Adds a visual display of incoming messages from Node-RED to the web page. Use uibuilder.showMsg(false) to remove it. selector is a CSS selector to use as the parent position. Will always show the last incoming standard msg from Node-RED.

    • uibuilder.showStatus(true, selector=body) - Adds a visual display of the current status of the client library. Use uibuilder.showMsg(false) to remove it.selector is a CSS selector to use as the parent position. May be helpful when trying to debug pages and connectivity, especially from mobile devices.

    • uibuilder.syntaxHighlight(json) - Converts JSON/JavaScript object into highlighted HTML. Useful for debugging messages sent from/to Node-RED. This used to be in each template so you don't need it there any more.

    • uibuilder.uiGet(cssSelector, propName=null) - Get data from the DOM. Returns selection of useful properties unless a specific property requested.

      Data can be sent straight back to Node-RED: uibuilder.send( uibuilder.uiGet('input') ) (gets all useful properties from all input fields on the page).

    • uibuilder.watchDom(true) - Starts watching the content of the page and saves it to browser localStorage so that it can be recovered at any time. Use uibuilder.restoreHtmlFromCache() to recover the stored HTML (e.g. on page load). Use uibuilder.watchDom(false) to turn off and uibuilder.clearHtmlCache() to remove the saved HTML. If desired, you can also manually save the HTML at any point using uibuilder.saveHtmlCache().

    • uibuilder.beaconLog(txtToSend, logLevel) which allows sending a simple, short log message back to Node-RED even if socket.io is not connected. In Node-RED, outputs to the Node-RED log and sends a uibuilder control message where msg.uibuilderCtrl = "client beacon log". Still somewhat experimental and may not always work reliably.

    • uibuilder.logToServer() which will take any number and type of arguments and send them all back to Node-RED in the msg.payload of a control message (out of port #2) where msg.uibuilderCtrl = "client log message". Client details are added to the message. Still somewhat experimental and may not always work reliably.

  • Added a unique tab identifier uibuilder.tabId that remains while the tab does. Is include in std outputs. Based on this. NOTE however, that duplicating the browser tab will result in a duplicate tab id.

  • Added uibuilder.isVisible property. Is true when the browser tab containing the page is actually visible. On visibility change, sends a new control msg msg.uibuilderCtrl = "visibility" with the property isVisible true or false. Does not send this when the page loads but does set the property. Uses the document visibilitychange event.

  • Added flag uibuilder.isVue if VueJS is loaded. To be used for dynamic UI processing. Also added uibuilder.vueVersion though this may not be always populated due to differences between VueJS versions.

  • _ui handler updates

    • When triggering showDialog() either in the FE or by sending a toast notification from node-red, setting "variant" now allows any CSS class name to be used. Not just the previous list of names ('primary', 'secondary', 'success', 'info', 'warn', 'warning', 'failure', 'error', 'danger') though since they are all included as classes in uib-brand.css, they all still work.

    • Extended the standards for msg._ui with mode=update to include the properties selector or select. These take CSS selectors as their value (as does the type property) and take preference over a name or type property but not over an id property. Mostly for convenience and just easier to remember. Documentation also updated.

    • Added a position property to the add _ui mode. "first"/"last": Adds start/end of parent's children respectively. An integer will add the element after the nth child.

    • Added a new ui handler removeAll and updated the handler function with an optional 2nd parameter to remove all (rather than the 1st) matching elements.

  • Added 2 new events: uibuilder:constructorComplete and uibuilder:startComplete. Mostly for potential internal use.

uib-cache node

  • Added filter to remove msg.res and msg.req which come from ExpressJS and cannot be serialised so create errors.

NEW uib-element node

This node lets you easily create new front-end UI elements from within Node-RED. It has a selection of element types ranging from simple text structures, through different types of list and full tables. It is a much more comprehensive node than the previous, experimental, uib-list node. This node is classed as zero-code since no coding is required in order to produce a web user interface.

Note that this generates pure HTML - no frameworks are used.

It creates configuration-driven dynamic additions to your front-end UI while letting you send fairly simple data to dynamically create the structure. For example, sending an array of objects with the Table type will create/replace a complete table in your front-end.

Has a single output. Outputs can be chained to more uib-element nodes. At the end of the chain, simply send to a uibuilder node input. Optionally, make sure each chain has a unique topic and send to a uib-cache node so that new and reloaded browser clients get the last output.

Note: The range of options built into the node for each element type is deliberately fairly restricted. If you want more complex layouts, you should either craft the JSON yourself. This node can output the raw JSON if you want so that you can save it and enhance it yourself. Also, this initial release is mostly driven by the input data; in future releases some options will be capable of override using configuration inputs in the node.

This is NOT meant as a Dashboard replacement. It is mostly meant for people who need a quick and simple method of dynamically creating UI elements's within a pre-defined HTML design. The element content is rebuilt every time you send data so this is certainly not the most efficient method of working with data-driven UI's. However, it will often be good-enough for relatively simple requirements.

Element types included in this release:

  • Simple Table - Generates a simple HTML table from an input array of objects where the first element of the data array will define the columns. Future enhancements will allow more control over the columns. Future types will be added to allow add/update/remove of individual rows and/or cells.
  • Simple Form - Generate a simple but accessible input form from an array of objects where each object in the array defines the attributes and label.
  • Unordered List (ul)/Ordered List (ol) - Generates a bullet or number list from a simple input array or object.
  • Description List (dl) - Generates a description list from a simple input array of objects.
  • Text box - A simple "card" like article element with a border.
  • HTML - Pass-though HTML (e.g. from a Node-RED Template node) wrapped in a div.
  • Page Title - Change the page HTML title, description and the first H1 tag on the page to all be the same input text. Also add sub-heading if input is an array.

Where an ID is specified in the config, each of the above will attempt to replace an existing instance when called again. If no ID is specified, they will always add a new element.

Each element except the page title is wrapped in a <div> tag which has the specified HTML ID applied to it. Where possible, rows and columns are given their own identifiers to make updates and styling easier. Attempts are made to ensure that the resulting HTML is accessible.

Each element can have an optional heading. If used, a aria-labelledby attribute is added to the div tag for accessibility.

The following element types are also available but behave slightly differently in that they will always add a new row regardless of the ID setting, they are not wrapped in a div and you cannot add a heading:

  • Add row to existing table - Adds a single row, must provide the Parent of the table to update, can insert the row anywhere via the Position input.
  • Add row to existing unordered or ordered list - Adds a single row, must provide the Parent of the list to update, can insert the row anywhere via the Position input.

In addition, a special msg may be sent to this node: msg.mode where mode = "remove". In this case, as long as an HTML ID has been provided, the element will be removed from the UI.

Unfortunately, many front-end frameworks such as REACT and VueJS require the UI page structure to be pre-defined at load time. Because of this, many of the features in this node are of limited use when working with those frameworks.

Oher frameworks though are better behaved (e.g. Svelte) and will work well with this node.

NEW uib-update node

Zero-code UI updates from Node-RED flows. Outputs msg._ui low-code config data that the uibuilder client library can turn into full HTML. (Same format as the uib-element node)

Can also delete (remove) existing elements. Note that in delete mode, this node will remove ALL element specified by the CSS Selector. e.g. if you specify a selector of "li", every list entry from every list on the page will be deleted. Use with caution.

In update mode (the default), any combination of attributes (e.g. class, style, etc) and inner content (the so-called "slot" content) can be updated. Slot content can be text, HTML or (if the markdown-it library is loaded) Markdown.

uib-list node - NOW DEPRECATED

Please switch to using the uib-element node. This node will be removed in the next major release of uibuilder (v7).

uib-brand.css

  • Is now the default CSS for all of the templates.
  • Added JSON syntax highlight rules from uib-styles.css. Also improved the layout and features.

Templates

  • All of the templates have been updated to the latest uibuilder standards for v6.
  • The default blank template and any others that don't specify which client build is used now use the new uibuilder.IIFE.min.js build.
  • All templates using the new clients have a <div id="more"><!-- '#more' is used as a parent for dynamic content in examples --></div> line in the HTML which is a useful target for adding dynamic content from Node-RED.
  • All templates have updated and rationalised README.md and package.json files in the root folder.
  • All templates have .eslintrc.js files in the root folder. You may need to install eslint extensions to match. If this file gets in the way, it can be safely deleted. It helps maintain standard coding practices and helps avoid the use of JavaScript which is too new.
  • Removed the (c) from the remaining templates. There is no (c) on any of them. They all fall under MIT license. Use as you will, there are no intellectual property restraints on the template code.
  • Change all to load client from ../uibuilder/uibuilder.xxx.min.js instead of ./uibuilder.xxx.min.js for consistency with other standard and installed library loads. Note that both locations remain valid.
  • Moved all scripts to head with defer now we no longer expect IE. Much cleaner code.
  • Changed templates to use CSS from ../uibuilder/uib-brand.css rather than ./uib-brand.css for better consistency.
  • Updated:
    • blank - now truly blank, a clean canvas.
    • blank-iife-client
    • blank-esm-client
    • svelte-basic
    • iife-vue3-nobuild
    • vue v2 + bootstrap-vue
    • vue v2 + bootstrap-vue - simple
    • blank-old-client

Examples

  • Report Builder. Create HTML reports direct from Node-RED. See Forum thread, Flow site.
  • Updated/New - all should have descriptive comments throughout
    • jQuery - removed. No longer needed.
    • logging - removed. Old code, superceded by newer features.
    • low-code-report-builder - NEW Replicates pdfmaker's tables example using uibuilder to demonstrate how easy it is to build complex documents using uibuilder.
    • simple - Implements a very simple Quote of the Day display using vanilla HTML.
    • svelte-basic - removed. See "templates" example instead.
    • templates - NEW "Template Tests" tab
    • toast-notifications - removed. Needs rework in next release to use _ui.
    • uib-cache - "uib-cache" tab. Examples of using uib-cache with and without uibuilder.
    • uib-list - removed. Node is deprecated, See the "zero-code" examples instead.
    • uib-sender - "uib-sender" tab.
    • vue - removed. See the "templates" examples instead.
    • zero-code - NEW "uib-element tests" tab

Documentation

  • Improvements to h1-h5 headings to make them stand out more clearly.
  • Split the "The modern front-end client" into multiple pages for easier reading and navigation.
  • Updated the modern front-end client docs with the latest client updates.
  • Renamed "Tech Docs" to "Docs" throughout.
10 Likes

@TotallyInformation : Great work. Thanks for your efforts and hardwork.

May I request for a small addition as this is used by many people quite often. Can we add a dropdown list selection in the FORM element.

if this is already existing, can you please give me some pointers.

1 Like

Hi, thanks for the encouragement.

A select input (dropdown) is already implemented for the next release.

In case you are interested, this is where I'm up to with changes for the next release (v6.5 most likely).


NEW Features

  • Instance routes/middleware

    You can now add ExpressJS routes and other middleware to a single instance of uibuilder (a specific uibuilder node), not just to all nodes. Especially useful if you want to add custom security (login, registration, etc) to just one instance.

    The new feature lets you specify the sub-url-path, the HTTP method and the callback function. Paths can include wildcards and parameters too. The routes are always added to the instance router which forces them to only ever be sub-url-paths of the specified instance. e.g. if your instance url is test, a route with a path of /foo/:bah will ALWAYS be .../test/foo/.... This is for security. Note that you are responsible for creating unique URL paths, no checking is done and ExpressJS is quite happy to have multiple path handlers but if you provide a terminating response (e.g. res.status(200)) and no next() call, the call stack is obviously terminated. If you include a call to next(), overlapping route callbacks will also be triggered. In that case, make sure you do not do any more res.xxxx() responses otherwise you will get an ERR_HTTP_HEADERS_SENT error.

    To add route handlers, create 1 or more .js files in the <instanceRoot>/routes/ folder. See the docs for details.

    What can I do? Authentication, authorisation, http headers, dynamic html changes/additions, js inserts, logging, server-side includes, server-side rendering (e.g. Jade, ...) ...

Changes to uibuilder client Library

  • NEW FUNCTION uibuilder.notify(config) - If possible (not all browsers yet fully support it), use the browser Notification API to show an operating system notification. Supports a simple click reponse which can be used with uibuilder.eventSend to notify Node-RED that a user clicked the notification. Note that there are significant inconsistencies in how/whether this API is handled by browsers. It may not always work.
  • Added window.uib as a synonym of window.uibuilder. So you can do things like uib.logLevel = 5 instead of uibuilder.logLevel = 5
  • Added flag to indicate if the DOMPurify library is loaded. Added warnings to the include() function when it is loaded since some includes will be filtered by the purify process for safety. Updated the front-end client introduction document with details about DOMPurify, how to load it and use it.
  • Added flag to indicate if the Markdown-IT library is loaded. Updated the front-end client introduction document with details about how to load the library and use it.

Changes to uibuilder main node

  • NEW Instance route/middleware handlers - allows you to create custom url routes and custom middleware functions that only impact routes for a single instance of uibuilder.

Changes to CSS styles (uib-brand.css)

  • NEW Minified version included, use as @import url("../uibuilder/uib-brand.min.css");
  • Reduced thickness of error border on input fields.
  • CSS Variables
    • NEW --mode - "light" or "dark" according to the current browser preference or html class override.
    • NEW --text-hue and --surface-hue allows independent colour control of standard text and backgrounds. Defaults to --brand-hue.
    • NEW --complementary-offset - defaults to 180, you are unlikely to want to change this.
    • NEW --font-style - set to sans-serif by default.
  • CSS Classes
    • NEW .flex-wrap - auto-wrapping flex layout.
    • NEW .grid-fit - auto-columns with number set by --grid-fit-min.
    • NEW .compact - removes margin and reduces top/bottom padding to a minimum (0.2rem).
    • NEW button.compact - Removes rounded corners and reverts background to parent. Minimises margin and padding.

Changes to uibuilder templates

  • Replaced all references to uib-brand.css with uib-brand.min.css for efficiency.

Documentation updates

  • Details and links for using the DOMPurify external library.
  • Lots more detail added to the uib-brand.css documentation.

Oops! Noticed that the list is missing the select input. Must correct that.

6 Likes