Source code of node red

Hi everyone,

I cloned the Node-RED GitHub repository, but I can’t find the source code in the packages folder. I expected to see folders like node-red-editor-api/ and node-red-editor-client/.

Could someone please explain how to get the source code?

Thanks!

Hi @fouadchouag

All of the code is under packages/node_modules/**

This post explains the structure and why it is the way it is - Moving Node-RED to a monorepo with multiple modules · knolleary

Thanks for your reply. However, I need to modify the Node-RED GUI — for example, hiding the palette, displaying my own components, and changing more details.
How can I make these changes?
Thank you.

All of the front-end code is in packages/node_modules/@node-red/editor-client/src/js

Thank you, sir, for your quick response.
So, if I modify something in this folder and run " grunt dev "
will the GUI change, or is there another method, sir?

Running grunt dev will build the code and start Node-RED. It then watches for changes in the source directories and automatically rebuilds the editor (if modifying editor code) or restarts the runtime (if modifying runtime code).

If I change a file in node_modules/@node-red/editor-client/src/js/, the modifications will be applied directly when I restart Node-RED.
But this is not a clean way to customize GUI I think because
my changes will be overwritten if I run npm install or npm update.
and I also won’t be able to easily maintain or distribute my modifications.
what do you think sir ?

It very much depends on what customisations you want to make. A different approach would be to make a Node-RED plugin that allows you to inject code into the UI, where you can modify what's there.

But without knowing what changes you want to make, it's hard to suggest the best path

Ultimately, if you want to make significant changes, then yes, you'll need to decide how to maintain that moving forward.

Ok Sir,

I want to modify the UI of Node-RED to create my own personalized interface. My goal is to build RAD (Rapid Application Development) tools for developing BCI (Brain-Computer Interface) applications.

First, I need to customize the Node-RED UI to provide a no-code GUI for novice users. This GUI should include a palette of BCI components (e.g., EEGRecorder, Filter, EEGVisualizer), allowing users to simply drag and drop these components to create their flow. The core Node-RED engine will then execute the flow as usual.

Additionally, my RAD tools must offer a low-code GUI for developers to add their own custom components in any programming language (polyglot components). These components should then be automatically integrated into the no-code GUI.

I believe that using Node-RED and customizing it is the best choice, as developing such a platform from scratch would take a very long time.
What do you think, Sir? Are there any other suggestions? I would be very happy to hear them.

The files you are changing are in packages/node_modules/, not the top-level /node_modules, so npm install wouldn't effect them.

Based on what you've described, re-writing/customising the Node-RED UI is a sensible play, and many have done it before, e.g. Fluidly

thank you Sir for answers, If i need further information Can i contact you ?

Best to ask here on the forums, that way, anybody can contribute and help

Hi @fouadchouag, Christian here (creator of Fluidly).

Your goal requires some planning and considerations. The perhaps biggest is your lifecycle management – how can you implement "your thing" while keeping it on par with NR releases as cheaply as possible.

For this I've had great success with a custom little function that identifies text strings in RED.min.js and injects external js snippets either .before(), .after() or .replace(). The only time I had to "repair it" was when bumping from NR 2 to NR 3.

Here are three different approaches depending on what you want to do:

  1. Light: Plugins client-side let you change anything that is available through either the DOM or the RED object. Show/hide stuff, change appearances through d3 calls, traverse nodes and so on.
  2. Hardcore: I'm using a server-side plugin to alter RED.min.js before NR sends it to the client, and that's how I achieve the unorthodox stuff (traffic blimps on wires, labels on wires, resize nodes, groups as hulls instead of rects, groups that can be viewed in "dashboard mode", the d3-sunburst-menu aso)
  3. nodes: Give your nodes an onRedraw function if you want to control their rendering. Either add the onRedraw call in RED.min.js::_redraw using method 2, or use a hook (haven't tried that as they didn't exist when I started out). Then add node._def.onRedraw(svg) in your node.html and work your d3 magic in there.

Feel free to reach out if you need more pointers or source code.

1 Like

Hi Christian,

Thank you so much for your detailed and insightful answer — it’s really appreciated!

I’m currently a bit pressed for time, as my goal is to build a quick MVP:

  • a no-code GUI with a palette containing only my custom BCI components, where the user can drag and drop these components and connect them to build a flow,
  • and a low-code GUI for developers to add new multilingual components easily.

Based on your explanation, I believe a client-side plugin approach should be sufficient for what I need, since it would allow me to customize the palette, hide standard components, and style the interface without deep modifications on the server side.

Do you think this approach makes sense for my MVP, or would you still recommend a more advanced method?

Thanks again for your support!

Best regards,
Fouad

hi @lgrkvst

Thank you so much for your detailed and insightful answer — it’s really appreciated!

I’m currently a bit pressed for time, as my goal is to build a quick MVP:

  • a no-code GUI with a palette containing only my custom BCI components, where the user can drag and drop these components and connect them to build a flow,
  • and a low-code GUI for developers to add new multilingual components easily.

Based on your explanation, I believe a client-side plugin approach should be sufficient for what I need, since it would allow me to customize the palette, hide standard components, and style the interface without deep modifications on the server side.

Do you think this approach makes sense for my MVP, or would you still recommend a more advanced method?

Thanks again for your support!

Best regards,
Fouad

You could create a custom installation script for Node-RED that adjusts the default settings.js file (which is copied from the node-red source to the userDir on first run of a Node-RED instance). The settings file allows you to specify what nodes may appear in the palette.

In addition, the install script could automatically install your custom nodes.

None of that requires customising the node-red source code. Which, as you point out, will get overwritten if someone reinstalls or upgrades Node-RED.

A client-side editor plugin does indeed let you do various customisations to the Node-RED Editor UI and also lets you attach functions/variables, etc. Whether it will be enough for what you want to do I am not sure. But see above because you don't need this simply to customise the palette of nodes.

You might also need a runtime plugin if you need to be able to handle custom runtime functions.

This, I suspect is the most complex ask. For starters, you will need to interface between node.js (the underlying platform that Node-RED uses) and the other languages. This may be very complex. There was a node that allowed Python to be used as an alternative to the normal function node but I am not sure whether that node is still supported. Other than Scratch, I don't know of any other language integrations.

I ryed by using this settings.js:

module.exports = {

        editorTheme: {
        palette: {
            catalogues: []  
        },
        customPalette: {
            categories: [{
                id: "bci-inputs",
                label: "Entrées BCI",
                color: "#4e54c8",
                nodes: ["eeg-simulator"]
            }]
        },
        page: {
            css: ["./themes/bci-theme.css"]
        }
    },
    externalModules: {
        palette: {
            allowList: ["@bci/*"]  
        }
    },
    flowFile: "flows.json",
    userDir: "./user-data",  
    logging: {
        console: {
            level: "info"
        }
    }
};

but no changes

Assuming that you have the rest of the settings (otherwise what you have shared is invalid I believe). Here is what I have in my settings for my dev machine - just snippets, not the whole thing. Mostly shows the defaults.

    ...

    /** Configure how the runtime will handle external npm modules.
     * This covers:
     *  - whether the editor will allow new node modules to be installed
     *  - whether nodes, such as the Function node are allowed to have their
     *    own dynamically configured dependencies.
     * The allow/denyList options can be used to limit what modules the runtime
     * will install/load. It can use '*' as a wildcard that matches anything.
     * NOTE that external modules are installed to `<userDir>`
     */
    externalModules: {
        // autoInstall: false,   // Whether the runtime will attempt to automatically install missing modules
        // autoInstallRetry: 30, // Interval, in seconds, between reinstall attempts
        // palette: {              // Configuration for the Palette Manager
        //     allowInstall: true, /** Enable the Palette Manager in the editor */
        //     allowUpdate: true,  /** Allow modules to be updated in the Palette Manager */
        //     allowUpload: true,  /** Allow module tgz files to be uploaded and installed */
        //     allowList: ['*'],
        //     denyList: [],
        //     allowUpdateList: ['*'],
        //     denyUpdateList: []
        // },
        // modules: {              // Configuration for node-specified modules
        //     allowInstall: true,
        //     allowList: [],
        //     denyList: []
        // }
    },

    ...
    ...

    editorTheme: {
        ...

        /** The following property can be used to order the categories in the editor
         * palette. If a node's category is not in the list, the category will get
         * added to the end of the palette.
         * If not set, the following default order is used:
         */
        palette: {
            // categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'],

            /** Alternative palette manager catalogues */
            // catalogues: [
            //     'https://catalogue.nodered.org/catalogue.json'
            // ],

            /** Override node colours - rules test against category/type by RegExp. */
            // theme: [
            //     { category: '.*', type: '.*', color: '#f0f' } // Makes ALL nodes PINK!
            // ]

            // *Deprecated* - use externalModules.palette.allowInstall instead
            // editable: true,
        },

        ...
    }

...

Yes sir, it seems my settings.js is not valid. I don’t think changing settings.js alone can hide the Node-RED palette. I believe I might need to modify the source code and rebuild Node-RED. What do you think, sir?

@TotallyInformation's approach is by far the easiest if you have total control of the instance. It wasn't an option as I wanted to evaluate FlowFuse for scaling.

Instead I went with this in the Fluidly plug-in's client code:

            // the expert switch
            var div = d3.select("#red-ui-header").append("span").attr("id", "expertmode");
            div.append("span").text("Basic");
            div.append("input").attr("type", "checkbox").classed("fluidly-switch", true).attr("value", true).attr("id", "expertswitch")
            div.append("span").text("Expert");

            var expertswitch = div.select("#expertswitch");
            expertswitch.node().checked = RED.settings.get("fluidly.expertmode");
            expertswitch.on("click", function (e) {
                if (this.checked) {
                    RED.settings.set("fluidly.expertmode", true);
                    toggleExpertMode();
                } else {
                    RED.settings.set("fluidly.expertmode", false);
                    toggleExpertMode();
                }
            });

            function toggleExpertMode () {
                var containers = d3.selectAll("#red-ui-palette-container > .red-ui-palette-category");

                containers.each(function () {
                    var c = d3.select(this);
                    if (!c.attr("id").toLowerCase().includes("fluidly")) {
                        c.style("display", RED.settings.get("fluidly.expertmode") ? "block" : "none");
                    }
                    d3.select("#red-ui-palette-container-Fluidly_Admin").style("display", RED.settings.get("fluidly.expertmode") ? "block" : "none");
                    d3.select("#red-ui-palette-container-Store_Fluidly").style("display", RED.settings.get("fluidly.expertmode") ? "block" : "none");
                    d3.select("#red-ui-palette-container-Mobile_Payments").style("display", "block");
                    d3.select("#red-ui-palette-container-Financial_Services").style("display", "block");
                });
            }

            RED.events.on("runtime-state", function (state) {
                if (!state.state == "start") {
                    return;
                }
                toggleExpertMode();
            });


...producing the oval in this screen shot: