When are config nodes defined in the flow editor?

From another thread:

I think the question here is what do you need this for, because there may be better ways to organize things.

Waiting for the runtime-state event is not cool because you assume that the runtime will start, which is not a given. Especially if there's something wrong and Node-RED is in safe mode then the event will never trigger (I believe). The flow editor should really work without the run-time (other than of course having to be served-up).

The loading of node types is very async. There is also fun stuff where, if a config node type doesn't get registered and nodes reference it, then the flow-editor creates a place-holder type that is essentially empty. The process and ordering of hydrating the config is pretty involved, rather complex, and very difficult to follow in the codebase.

Again, your best bet may be to describe what you use eachConfig for 'cause perhaps there's a different solution.

1 Like

onpaletteadd is called when the node is added to the palette. That happens before the current flow configuration is loaded. So it is entirely expected that eachConfig wouldn't return anything for code called in onpaletteadd.

Indeed. Is this really a one-time only action you want to run, or something you need to do whenever a new config node of a particular type is added/import or removed?

Thank you for confirming that is to be expected. I was mimicking what the node-red-dashboard does when it adds a singleton config node automatically. node-red-dashboard/ui_base.html at master · node-red/node-red-dashboard · GitHub. My problem was that I was trying to add the config node a little too early.

Well, I am in the very early stages of my experiment, so it is not fully thought out just yet. I am trying to find a good workflow for adding something that is not a standard node or plugin. A couple years ago I made my own private use (non-admin) middleware auth to give myself finer control for the node-red-dashboard access and my video streaming apis, such as user level, route access, etc. It has worked good, but it was all manually configure with json files. I am trying to utilize a config node as a place to secure the details and credentials and manage my middleware. As far as I know, a config node is usually added by a regular node, so I am taking the route of making a self initializing singleton config node. It works!

In the backend, the node checks if the middleware has been imported and called. This flags a variable that the middleware is in use. Also, I check the settings to verify that https is configured and that httpNodeAuth is not in use. Errors are logged on the server side and a friendly reminder is given to the user in the editor if they have gone through the trouble of manually adding my middleware and now are compelled to fix the configuration error in settings.js and add the config node. If the config node is not created, then the middleware is in a default state of preventing access to any route it is protecting.

Probably sounds more complicated than it is.
The middleware has been added and they have any conflict, then they see something similar to this:


If no conflict is detected, but user has not had the config node added yet, they will get something like this:

Once an instance of the config node has been saved and deployed, the middleware can now function properly.

User only receives notifications if they have manually added the middleware to the settings.js file. I am trying to be the least intrusive as possible, while also enforcing that the middleware must be configured to be functional.

If I understand correctly, the issue you're having is to detect when the user has configured the middleware in the settings but has not added a config node to manage it. What I would do:

  • in the node .js outside of the node itself check the settings to see whether the middleware is configured and set-up an API endpoint to be able to serve-up the info to the flow editor
  • in the node .html outside of the call to registerType query:
    • make an API request to the API endpoint to find out what the settings situation is
    • set-up a handler for the add-node event so you find out whether a config node is created
    • set a 1-second timer and when it fires evaluate the settings/config-node combo to decide whether to pop-up a warning

The 1-second timer ought to work OK 'cause the type you're registering isn't going to be delayed (since it happens in the same JS module). But yeah, you're looking for the same notification that everything loadable has been loaded... It's that absence-of-a-node check that is not otherwise possible... I need it for garbage collection, you need it for a 'hey dude, you're missing something' pop-up.

1 Like

Why don't you like to implement this as a plugin?
Defining the UI is almost the same effort as for a dedicated config node & you will be able to manage (save / load) your settings on your own behalf?!
There's an additional benefit from my perspective: Plugins are loaded very early in the process of setting up the client side - thus you can get things under control quite easy!

You are also going to have handle the case where a user imports an existing flow and ends up with two instances of your config node.

This is where I would use the nodes:add event to listen for anything being added, start a timer so you can debounce the multiple events you get when importing lots of nodes (including the initial load) and then run your processing.

Couple of points:

  • 'til the next release you can't safely have a plugin and a node in the same NPM module due to a potential race condition
  • plugins don't have config saved in the flow file, so he'd have to come up with a different way to save state
  • a plugin doesn't eliminate the "is a config node configured or not?" issue

I know! What I wasn't aware of is the indication that this should / could be fixed with the next release; that's good news! :+1:

That's what I said:

It does, as there's then no need anymore to use a config node - when the plugins panel is used to manage the settings.

BTW, it eliminates in addition the issue raised by Nick ... to ensure that only one config node is present. I wonder how to decide which one to utilize, when there is a choice...

How did you know? i did that exact thing.

RED.httpAdmin.get('/middleware', RED.auth.needsPermission('middleware.read'), (req, res) => {
        res.type('json').send(JSON.stringify({ usingMiddleware, usingHttpNodeAuth, usingHttps, errors }));
    });

I was calling fetch to that endpoint in onpaletteadd. I had not tried doing it before registerType. I will experiment with that.

I was a bit lazy. And I really wanted to easily use the credentials and did not see an easy way to do that from a plugin. That was my first failed attempt. Maybe I would have gotten further had I not gotten stumped when checking the existence of the config node during the plugin's onadd function.

I hadn't considered the importing. Currently, I was planning on mostly using only credentials in the config node. I didn't think credentials could be exported. Also, I do it similar to how node-red-dashboard does and only keep the first node found and remove any extras to ensure only 1 exists.

That would be my preferred way if it saved the details outside of the regular flows and used something like the credentials. Do you have a link to any repo that does that?

I know, that these two packages (I'm the author of the second) store data outside of flows:

I haven't checked, if you can re-route the Node-RED Credentials API to utilize a non-standard storage location. It yet doesn't seem to be a lot of effort to refactor the relevant parts...

1 Like

Thanks. I will read through the code and see what I can do.

uibuilder has extensive data outside flows. But you do then have a lot of details you need to manage such as dealing with environments that don't have a full OS (e.g the IBM cloud), clashing folder names, people accidentally deleting things - or adding/renaming, and user desire to move things to more convenient locations.