UNPKG

node-red-contrib-uibuilder

Version:

Easily create data-driven web UI's for Node-RED. Single- & Multi-page. Multiple UI's. Work with existing web development workflows or mix and match with no-code/low-code features.

138 lines (114 loc) 5.29 kB
/* eslint-disable jsdoc/valid-types */ /** An example template for Node-RED custom nodes * * Copyright (c) 2025-2025 Julian Knight (Totally Information) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict' /** --- Type Defs - should help with coding --- * @typedef {import('../../typedefs').runtimeRED} runtimeRED * @typedef {import('../../typedefs').runtimeNodeConfig} runtimeNodeConfig * @typedef {import('../../typedefs').runtimeNode} runtimeNode */ // #region ----- Module level variables ---- // // Uncomment this if you want to use the promisified version of evaluateNodeProperty // const { promisify } = require('util') /** Main (module) variables - acts as a configuration object * that can easily be passed around. */ const mod = { /** @type {runtimeRED|undefined} Reference to the master RED instance */ RED: undefined, /** @type {Function|undefined} Reference to a promisified version of RED.util.evaluateNodeProperty*/ // evaluateNodeProperty: undefined, /** @type {string} Custom Node Name - has to match with html file and package.json `red` section */ nodeName: 'uib-sidebar', } // #endregion ----- Module level variables ---- // // #region ----- Module-level support functions ----- // /** 1) Complete module definition for our Node. This is where things actually start. * @param {runtimeRED} RED The Node-RED runtime object */ function ModuleDefinition(RED) { // As a module-level named function, it will inherit `mod` and other module-level variables // Save a reference to the RED runtime for convenience mod.RED = RED // Save a ref to a promisified version to simplify async callback handling // mod.evaluateNodeProperty = promisify(mod.RED.util.evaluateNodeProperty) /** Register a new instance of the specified node type (2) */ RED.nodes.registerType(mod.nodeName, nodeInstance) } /** 2) This is run when an actual instance of our node is committed to a flow * type {function(this:runtimeNode&senderNode, runtimeNodeConfig & senderNode):void} * @param {runtimeNodeConfig} config The Node-RED node instance config object * @this {runtimeNode} */ function nodeInstance(config) { // As a module-level named function, it will inherit `mod` and other module-level variables // If you need it - which you will here - or just use mod.RED if you prefer: const RED = mod.RED if (RED === null) return // @ts-ignore Create the node instance - `this` can only be referenced AFTER here RED.nodes.createNode(this, config) /** Transfer config items from the Editor panel to the runtime */ // @ts-ignore this.name = config.name ?? '' // @ts-ignore this.html = config.html ?? '' // this.topic = config.topic ?? '' /** Handle incoming msg's - note that the handler fn inherits `this` */ this.on('input', inputMsgHandler) // Set up an HTTP endpoint for this node instance to receive posts from the Editor UI RED.log.trace(`📊 [uib-sidebar] Listening for posts to /uibuilder/uib-sidebar/${this.id}`) RED.httpAdmin.post(`/uibuilder/uib-sidebar/${this.id}`, (req, res) => { RED.log.trace(`📊 [uib-sidebar] POST request for /uibuilder/uib-sidebar/${this.id}`, req.body) // console.log(`📊 [uib-sidebar] POST request for /uibuilder/uib-sidebar/${this.id}`, req.body) // res.status(200).send( { 'response': 'ok', 'id': this.id } ) res.status(200).json( { response: 'ok', id: this.id, } ) this.send({ ...req.body, }) }) } /** 3) Run whenever a node instance receives a new input msg * NOTE: `this` context is still the parent (nodeInstance). * See https://nodered.org/blog/2019/09/20/node-done * @param {object} msg The msg object received. * @param {Function} send Per msg send function, node-red v1+ * @param {Function} done Per msg finish function, node-red v1+ * @this {runtimeNode} */ async function inputMsgHandler(msg, send, done) { // const RED = mod.RED // Pass straight through // send(msg) sendToEditor(this, msg) // We are done - not really needed probably done() } /** Helper function to send a msg to the Editor UI for this node instance * @param {runtimeNode} node The node instance to send the msg to the editor for * @param {object} msg The msg object to send to the editor */ function sendToEditor(node, msg) { const RED = mod.RED RED.log.trace(`📊 [uib-sidebar] Sending to editor for ${node.id}`, msg ) RED.comms.publish(`UIBUILDER/uib-sidebar/${node.id}`, { srcId: node.id, ...msg, }) } // #endregion ----- Module-level support functions ----- // // Export the module definition (1), this is consumed by Node-RED on startup. module.exports = ModuleDefinition