TotallyInformation / node-red-contrib-uibuilder

Easily create data-driven web UI's for Node-RED using any (or no) front-end framework.

Home Page:https://totallyinformation.github.io/node-red-contrib-uibuilder/#/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: Best practice for automating UI Builder dependency installation?

dczysz opened this issue · comments

We're using docker to run Node-RED. Currently we have uibuilder getting installed automatically by providing a package.json to Node-RED, per these instructions https://nodered.org/docs/getting-started/docker:

# Copy package.json to the WORKDIR so npm builds all
# of your added nodes modules for Node-RED
COPY package.json .
RUN npm install --unsafe-perm --no-update-notifier --no-fund --only=production

This gets us halfway there with node-red's dependencies, but then we still need to manually install uibuilder dependencies (vue, etc.) through the admin interface after starting Node-RED.

I did some testing and it seems like we can provide a minimal /data/uibuilder/package.json file and run an npm install in the Dockerfile and everything works for the most part. ("PACKAGE vue NOT FOUND" error if we provide package.json but don't run an npm install before starting)


Dockerfile which installs uibuilder and its dependencies, sets up minimal index.html for testing:

FROM nodered/node-red:3.0.1

# Install node-red dependencies (uibuilder)
COPY package.json .
RUN npm install --unsafe-perm --no-update-notifier --no-fund --only=production

COPY flows.json /data/flows.json

# Prepare uibuilder directory
RUN mkdir -p /data/uibuilder/ui/src
RUN echo "Hello from /ui/" > /data/uibuilder/ui/src/index.html

# Install uibuilder's dependencies (vue)
COPY uib-package.json /data/uibuilder/package.json

USER 0
RUN chown -R node-red:node-red /data
USER node-red

WORKDIR /data/uibuilder
RUN npm install

WORKDIR /usr/src/node-red

Minimal test flows.json:

[
    {
        "id": "f6f2187d.f17ca8",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": ""
    },
    {
        "id": "32a328ad2c36f043",
        "type": "uibuilder",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "topic": "",
        "url": "ui",
        "fwdInMessages": false,
        "allowScripts": false,
        "allowStyles": false,
        "copyIndex": true,
        "templateFolder": "blank",
        "extTemplate": "",
        "showfolder": false,
        "reload": false,
        "sourceFolder": "src",
        "deployedVersion": "5.1.1",
        "x": 530,
        "y": 340,
        "wires": [
            [],
            []
        ]
    }
]

Node-RED package.json:

{
  "name": "uib-dependencies-test",
  "description": "Node-RED dependencies",
  "scripts": {
    "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS"
  },
  "dependencies": {
    "node-red": "^2.2.2",
    "node-red-contrib-uibuilder": "^5.0.2"
  }
}

Minimal uib-package.json:

{
  "name": "uib_root",
  "version": "5.1.1",
  "description": "Root configuration and data folder for uibuilder",
  "scripts": {},
  "dependencies": {
    "vue": "^2.7.8"
  }
}

The only issues I see doing it this way is that UI Builder isn't updating the package.json's uibuilder.packages, only creating an empty stub:

uib-package.json after starting Node-RED:

{
  "name": "uib_root",
  "version": "5.1.1",
  "description": "Root configuration and data folder for uibuilder",
  "scripts": {},
  "dependencies": {
    "vue": "^2.7.8"
  },
  "uibuilder": {
    "packages": {}  // <- this gets added, but not populated
  }
}

which results in an incorrect/missing "Est. link" in the admin interface:

image

This isn't really an issue though since our actual index.html already has the correct paths for the dependencies so this is just a small visual issue as far as I can tell. The file itself is still available where it should be at http://localhost:1880/uibuilder/vendor/vue/dist/vue.js, and no errors are logged.


So I guess my question is, is this the most correct/reliable way to be doing this?

  1. Provide only a minimal package.json to uibuilder
  2. Run npm install at the build stage from the Dockerfile
  3. Just deal with the empty uibuilder.packages entry in package.json as it seems to only cause visual issues and no actual errors?

I don't really like the idea of providing a package.json with a pre-populated uibuilder.packages, since that seems like something that may change over time (like it just did in the last major release!) and should be handled internally by uibuilder instead so we don't have to keep up with changes to the structure of this file. Are there any hidden issues I may have missed that could be introduced by installing uibuilder dependencies this way? Or any planned changes to uibuilder that may break this in the future?

Hmm, interesting - are you on the latest version (v5.1.1)? Because that metadata should be getting updated whenever node-red starts up. the package-mgt.js startup function is called as uibuilder is initialised in NR startup.

https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/v5.1.1/nodes/libs/package-mgt.js#L110

Line 120 updates the details both in-memory and in the package.json file.

I wonder if that process is failing to update the file?

...I was apparently testing with 5.0.2. Let me try with 5.1.1. Sorry, should've made sure I was on the latest version first. 🤦‍♂️

Not a problem, and I did make quite a few "improvements" in those processes, some of them probably even worked!

some of them probably even worked!

🤣

It looks like my package.json had ^5.0.2, so the npm install brought it up to 5.1.1 anyway. So even with 5.1.1 I'm still ending up with a blank uibuilder.packages:

{
  "name": "uib_root",
  "version": "5.1.1",
  "description": "Root configuration and data folder for uibuilder",
  "scripts": {},
  "dependencies": {
    "vue": "^2.7.8"
  },
  "uibuilder": {
    "packages": {}
  }
}

Hmm, OK. I fear you will need to increase the log level to trace so that we can see what order things are happening in. It might be easier, if you can, to do a simpler install first without using Docker. Just install node-red into a folder and set it to start with a different local sub-folder as the userDir. My alternate installer repo has the appropriate configuration. Set to use a different nr port. Manually do the same pre-config you do for your docker install, change the log level to trace and start node-red. See whether the metadata is updated.

Apologies for not doing this myself right now but My hand is in a pot (broken thumb). I can just about type but coding is too painful.

Apologies for not doing this myself right now but My hand is in a pot (broken thumb). I can just about type but coding is too painful.

Ouch, hopefully it makes for a good story at least!

If I need to I can always try without Docker, but I'm currently at ~6G of space left on this laptop so I'm trying to keep things easily removable if possible. I can always test it on a pi if needed though. But maybe this is good enough for now, logs set to trace but still using docker:

28 Jul 19:20:50 - [trace] utils.writeFile - written content to /data/package.json.$$$
28 Jul 19:20:50 - [trace] utils.writeFile - renamed /data/package.json.$$$ to /data/package.json
28 Jul 19:20:50 - [info] 

Welcome to Node-RED
===================

28 Jul 19:20:50 - [info] Node-RED version: v3.0.1
28 Jul 19:20:50 - [info] Node.js  version: v16.16.0
28 Jul 19:20:50 - [info] Linux 5.10.16.3-microsoft-standard-WSL2 x64 LE
28 Jul 19:20:51 - [info] Loading palette nodes
28 Jul 19:20:51 - [debug] Module: node-red-contrib-uibuilder 5.1.1 /usr/src/node-red/node_modules/node-red-contrib-uibuilder
28 Jul 19:20:51 - [trace] [uibuilder:runtimeSetup] ----------------- uibuilder - module started -----------------
28 Jul 19:20:51 - [trace] [uibuilder:runtimeSetup] uibRoot folder exists. /data/uibuilder
28 Jul 19:20:51 - [trace] [uibuilder:runtimeSetup] uibRoot folder is read/write accessible. /data/uibuilder
28 Jul 19:20:51 - [trace] [uibuilder:runtimeSetup] Copied template .config folder to local .config folder /data/uibuilder/.config (not overwriting)
28 Jul 19:20:51 - [trace] [uibuilder:package-mgt:readPackageJson] package.json file read successfully from /data/uibuilder
28 Jul 19:20:51 - [trace] [uibuilder:web:setMasterStaticFolder] Using master production build folder. /usr/src/node-red/node_modules/node-red-contrib-uibuilder/front-end
28 Jul 19:20:51 - [trace] [uibuilder:web:webSetup] Using Node-RED ExpressJS server at http://0.0.0.0:1880/
28 Jul 19:20:51 - [trace] [uibuilder:package-mgt:readPackageJson] package.json file read successfully from /data/uibuilder
28 Jul 19:20:51 - [trace] [uibuilder:package-mgt:readPackageJson] package.json file read successfully from /data/uibuilder/node_modules/vue
28 Jul 19:20:51 - [warn] [uibuilder:package-mgt:getPackagePath2] PACKAGE socket.io-client NOT FOUND
28 Jul 19:20:51 - [trace] [uibuilder:socket:socketIoSetup] Socket.IO initialisation - Socket Path=/uibuilder/vendor/socket.io, CORS Origin=*
28 Jul 19:20:51 - [trace] utils.writeFile - copied /data/.config.nodes.json TO /data/.config.nodes.json.backup
28 Jul 19:20:52 - [trace] [uibuilder:runtimeSetup] Copied common template folder to local common folder /data/uibuilder/common (not overwriting)
28 Jul 19:20:52 - [trace] utils.writeFile - written content to /data/.config.nodes.json.$$$
28 Jul 19:20:52 - [trace] utils.writeFile - renamed /data/.config.nodes.json.$$$ to /data/.config.nodes.json
28 Jul 19:20:52 - [info] Settings file  : /data/settings.js
28 Jul 19:20:52 - [info] Context store  : 'default' [module=memory]
28 Jul 19:20:52 - [info] User directory : /data
28 Jul 19:20:52 - [warn] Projects disabled : editorTheme.projects.enabled=false
28 Jul 19:20:52 - [info] Flows file     : /data/flows.json
28 Jul 19:20:52 - [debug] loaded flow revision: ed6a770969b387cd00c1e8b83f413638
28 Jul 19:20:52 - [debug] red/runtime/nodes/credentials.load : no user key present
28 Jul 19:20:52 - [debug] red/runtime/nodes/credentials.load : no default key present - generating one
28 Jul 19:20:52 - [debug] red/runtime/nodes/credentials.load : keyType=system
28 Jul 19:20:52 - [warn] 

---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.

If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.

You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------

28 Jul 19:20:52 - [trace] utils.writeFile - copied /data/.config.runtime.json TO /data/.config.runtime.json.backup
28 Jul 19:20:52 - [info] Server now running at http://127.0.0.1:1880/
28 Jul 19:20:52 - [trace] utils.writeFile - written content to /data/.config.runtime.json.$$$
28 Jul 19:20:52 - [trace] utils.writeFile - renamed /data/.config.runtime.json.$$$ to /data/.config.runtime.json
28 Jul 19:20:52 - [warn] Encrypted credentials not found
28 Jul 19:20:52 - [trace] runtime event: {"id":"runtime-state","retain":true}
28 Jul 19:20:52 - [info] +-----------------------------------------------------
28 Jul 19:20:52 - [info] | uibuilder v5.1.1 initialised
28 Jul 19:20:52 - [info] | root folder: /data/uibuilder
28 Jul 19:20:52 - [info] | Using Node-RED's webserver at:
28 Jul 19:20:52 - [info] |   http://0.0.0.0:1880/
28 Jul 19:20:52 - [info] | Installed packages:
28 Jul 19:20:52 - [info] |   vue
28 Jul 19:20:52 - [info] +-----------------------------------------------------
28 Jul 19:20:52 - [trace] runtime event: {"id":"runtime-deploy","payload":{"revision":"ed6a770969b387cd00c1e8b83f413638"},"retain":true}
28 Jul 19:20:52 - [info] Starting flows
28 Jul 19:20:52 - [debug] red/nodes/flows.start : starting flow : global
28 Jul 19:20:52 - [debug] red/nodes/flows.start : starting flow : f6f2187d.f17ca8
28 Jul 19:20:52 - [trace] [flow:global] start flow [global]
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8] start flow [f6f2187d.f17ca8]
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] ================ instance registered ================
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] node keys: ["id","type","z","g","_closeCallbacks","_inputCallback","_inputCallbacks","wires","_wireCount","send","credentials","name","topic","url","oldUrl","fwdInMessages","allowScripts","allowStyles","copyIndex","templateFolder","extTemplate","showfolder","reload","sourceFolder","deployedVersion"]
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] config keys: ["id","type","z","name","topic","url","fwdInMessages","allowScripts","allowStyles","copyIndex","templateFolder","extTemplate","showfolder","reload","sourceFolder","deployedVersion","x","y","wires"]
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Deployed Version: 5.1.1
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Node instance settings: {"name":"","topic":"","url":"ui","copyIndex":true,"fwdIn":false,"allowScripts":false,"allowStyles":false,"showfolder":false}
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Node uib.Instances Registered: {"32a328ad2c36f043":"ui"}
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Number of uib.Deployments: 1
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Using local front-end folders in: /data/uibuilder/ui
28 Jul 19:20:52 - [trace] [uibuilder:web.js:instanceSetup] Setup for URL: ui
28 Jul 19:20:52 - [trace] [uibuilder:web:addMiddlewareFile:ui] uibuilder common Middleware file failed to load. Path: /data/uibuilder/.config/uibMiddleware.js, Reason: Cannot find module '/data/uibuilder/.config/uibMiddleware.js'
Require stack:
- /usr/src/node-red/node_modules/node-red-contrib-uibuilder/nodes/libs/web.js
- /usr/src/node-red/node_modules/node-red-contrib-uibuilder/nodes/uibuilder.js
- /usr/src/node-red/node_modules/@node-red/registry/lib/loader.js
- /usr/src/node-red/node_modules/@node-red/registry/lib/index.js
- /usr/src/node-red/node_modules/@node-red/runtime/lib/nodes/index.js
- /usr/src/node-red/node_modules/@node-red/runtime/lib/index.js
- /usr/src/node-red/node_modules/node-red/lib/red.js
- /usr/src/node-red/node_modules/node-red/red.js
28 Jul 19:20:52 - [trace] [uibuilder:webjs:instanceSetup] Instance API's not permitted. 'ui'
28 Jul 19:20:52 - [trace] [uibuilder:web:setupInstanceStatic:ui] Using local src folder
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] URL . . . . .  : /ui
28 Jul 19:20:52 - [trace] [uibuilder:nodeInstance:ui] Source files . : /data/uibuilder/ui
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8] ------------------|--------------|-----------------
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8]  id               | type         | alias
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8] ------------------|--------------|-----------------
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8]  32a328ad2c36f043 | uibuilder    | 
28 Jul 19:20:52 - [trace] [flow:f6f2187d.f17ca8] ------------------|--------------|-----------------
28 Jul 19:20:52 - [trace] runtime event: {"id":"runtime-state","payload":{"state":"start"},"retain":true}
28 Jul 19:20:52 - [info] Started flows
28 Jul 19:20:53 - [trace] [uibuilder:UibPackages:npmLatestVersion] npm output: 
 {
  "vue": {
    "current": "2.7.8",
    "wanted": "2.7.8",
    "latest": "3.2.37",
    "dependent": "uibuilder",
    "location": "/data/uibuilder/node_modules/vue"
  }
}
 
28 Jul 19:20:59 - [trace] comms.open 7kOvxZg3ywSPDy/f8KIkGJ0uPe967ZLxI+1JAhIs0SQ=

Still not populated:

$ cat /data/uibuilder/package.json
{
  "name": "uib_root",
  "version": "5.1.1",
  "description": "Root configuration and data folder for uibuilder",
  "scripts": {},
  "dependencies": {
    "vue": "^2.7.8"
  },
  "uibuilder": {
    "packages": {}
  }
}

I think this may be (at least part of) the issue, haven't done any further testing:

await Object.keys(lsParsed.dependencies || {}).forEach( async pkgName => {
await this.updIndividualPkgDetails(pkgName, lsParsed)
})

await doesn't really work on forEach, so it's calling writePackageJson before every updIndividualPkgDetails is able to run.

Small test:

async function updIndividualPkgDetails(pkgName, lsParsed) {
  return new Promise(resolve => {
    setTimeout(() => {
      lsParsed.dependencies[pkgName] = 'done';
      resolve();
    }, 500);
  });
}

async function forEach() {
  const lsParsed = { dependencies: { vue: '^2.7.8', test: '1.0.0' } };

  await Object.keys(lsParsed.dependencies || {}).forEach( async pkgName => {
    await updIndividualPkgDetails(pkgName, lsParsed);
    console.log('updated package:', pkgName);
  });

  console.log(lsParsed);
}

async function promiseAll() {
  const lsParsed = { dependencies: { vue: '^2.7.8', test: '1.0.0' } };
  
  await Promise.all(
    Object.keys(lsParsed.dependencies || {}).map(async (pkgName) => {
      await updIndividualPkgDetails(pkgName, lsParsed);
      console.log('updated package:', pkgName);
    })
  );

  console.log(lsParsed);
}

promiseAll();
// forEach();

Promise.all():

$ node async-test.js 
updated package: vue
updated package: test
{ dependencies: { vue: 'done', test: 'done' } }

forEach:

$ node async-test.js 
{ dependencies: { vue: '^2.7.8', test: '1.0.0' } }
updated package: vue
updated package: test

Ah, I hate await!

Don't suppose you'd like to provide a PR? The main branch can be used and I can issue an updated version.

Yeah sure I could definitely do that. Probably not until tomorrow though, got busy with some other stuff today.

Hmm seems there's more to it than that. Changing to Promise.all didn't make a difference as far as I can tell.

I'll have to play around with it a bit more when I have some time to find the root cause and provide a worthwhile PR.

I think, on further reading, this may have the answer:

https://gist.github.com/joeytwiddle/37d2085425c049629b80956d3c618971

If you get a chance to try it. Could you please try

let depPkgNames = Object.keys(lsParsed.dependencies || {})
await Promise.all( depPkgNames.map(async (pkgName) => {
    await this.updIndividualPkgDetails(pkgName, lsParsed)
}))

That should process all of the package dependencies in parallel.

Hmm still doesn't seem to fix it, logs look about the same (with an empty {} for bootstrap-vue's npmLatestVersion log?):

...

16 Sep 10:57:47 - [info] Started flows
16 Sep 10:57:47 - [trace] [uibuilder:runtimeSetup] Copied common template folder to local common folder \Users\Derek\.node-red\uibuilder\common (not overwriting)
16 Sep 10:57:49 - [trace] comms.open 0rq19HQu/NJoGgp2lb1KoZZOu5FaVhCjaR/9E7GHZhM=
16 Sep 10:57:49 - [trace] [uibuilder:UibPackages:npmLatestVersion] npm output:
 {}

16 Sep 10:57:49 - [trace] [uibuilder:UibPackages:npmLatestVersion] npm output:
 {
  "bootstrap": {
    "current": "4.6.2",
    "wanted": "4.6.2",
    "latest": "5.2.1",
    "dependent": "bootstrap-vue",
    "location": "C:\\Users\\Derek\\.node-red\\uibuilder\\node_modules\\bootstrap"
  }
}

16 Sep 10:57:50 - [trace] [uibuilder:UibPackages:npmLatestVersion] npm output:
 {
  "vue": {
    "current": "2.7.10",
    "wanted": "2.7.10",
    "latest": "3.2.39",
    "dependent": "portal-vue",
    "location": "C:\\Users\\Derek\\.node-red\\uibuilder\\node_modules\\vue"
  }
}

and package.json is still only partially filled out like before:

$ cat package.json
{
  "name": "uib_root",
  "version": "5.1.1",
  "description": "Root configuration and data folder for uibuilder",
  "scripts": {},
  "dependencies": {
    "bootstrap-vue": "^2.22.0",
    "vue": "^2.7.8",
    "bootstrap": "^4.6.1"
  },
  "uibuilder": {
    "packages": {}
  }
}

I believe the empty uibuilder.packages is due to updIndividualPkgDetails not making any changes to pj, which is what gets written at this.writePackageJson(rootFolder, pj). So it makes sense why that part doesn't get updated at least... I'm struggling to follow what all is going on inside updIndividualPkgDetails though, so I'll have to spend some more time looking over that part.

I'm thinking updIndividualPkgDetails may need access to pj as well, to populate uibuilder.packages. But need to look more/test

I'm thinking updIndividualPkgDetails may need access to pj as well, to populate uibuilder.packages. But need to look more/test

It does. The code is rather convoluted I'm afraid. Not sure what I was drinking at the time! But it sets pj to this.uibPackageJson at the top. That is the actual container, It is populated in the setup function by calling getUibRootPJ which reads the file. The variable name pj is only ever used locally within one of the class functions as a short-code.

The fundamental issue is that the npm checks HAVE to be done async otherwise the whole node-red startup is delayed by at least 2-3 seconds. BUT, that starts an async promise chain that is very hard to stop. JavaScript promises are just plain stupid. await should never have been limited to async functions.

So one thing to check. WHEN are you checking the package.json file? It does take an appreciable amount of time for the file to get updated. Especially if you have a lot of libraries installed. On my fast dev system with just 4 libraries, it still takes around 2-3 seconds.


Just checking the code again - there are some really funky things going on after a few adjustments. I suspect that the whole package handler needs a serious re-write.

I'm going to have to go through the whole process line by line I'm afraid.

Looks like if you start with an empty uibuilder.packages object in package.json, it gets populated but then a second later, it gets emptied again. If you start with that object populated, everything is OK.

So I need to find what is emptying the object again.

OK, so the npm ls command takes far too long so I'm trying to create the minimal version of the data on startup. Just enough to satisfy the web startup (where the libraries are added to the vendor routes to make them available to the front-end.

The following manual changes should work:

In package-mgt.js in the setup() function, add the following lines after the line that says if ( !pj.uibuilder.packages ) pj.uibuilder.packages = {} and before the line // (Re)build package.json uibuilder.packages & rewrite file [after 3sec] (async)

        // Make sure no extra package details
        for (const pkgName in pj.uibuilder.packages) {
            if ( !pj.dependencies[pkgName] ) delete pj.uibuilder.packages[pkgName]
        }
        // Make sure all dependencies are reflected in uibuilder.packagedetails
        for (const depName in pj.dependencies) {
            if ( !pj.uibuilder.packages[depName] ) {
                pj.uibuilder.packages[depName] = {installedVersion: pj.dependencies[depName]}
            }
        }
        // Get folders for web:startup:serveVendorPackages()
        for (const pkgName in pj.uibuilder.packages) {
            let pkg = pj.uibuilder.packages[pkgName]
            if ( this.uib.rootFolder === null ) throw this.#rootFldrNullError
            // The actual location of the package folder
            pkg.installFolder = path.join(this.uib.rootFolder, pkgName)
            // The base url used by uib - note this is changed if this is a scoped package
            pkg.packageUrl = '/' + pkgName
        }

and after this.#isConfigured = true add a new line: this.setUibRootPackageJson(pj).

Then in web.js in serveVendorPackages(), replace the line const pj = packageMgt.getUibRootPackageJson() with

const pj = packageMgt.uibPackageJson

Hopefully that should work now. The package.json file is still written to twice but from different places now. Firstly to get the simplistic entries for web.js and then again for the full data needed for the libraries tab in the Editor (which is the bit that takes the time and has to be async).

I'll be pushing these changes to the v6 branch shortly.

I need to do some more tidying up since I think there are now several functions in package-mgt.js that are no longer needed.

Thanks for taking the time to look into this. I made these changes and it looks like package.json gets updated as it should now, but I'm still getting the ? at the end of the "Est link".

It also seems like this somehow broke installing packages through the editor UI. I installed one through your UI, it says it completed but there's no new row added to the package list in the UI. The package.json has it listed as a dependency at this point, but somehow didn't make its way into uibuilder.packages...

Drat. It is installing but not updating the list in the editor again. Another fix needed. If you remove a package, it is removed but also not being removed from the list.

OK, another set of changes. This time to admin-api-v2.js.

To be honest, you would now be better off trying out the v6 branch direct from github which is where all the changes are.

But if you want to carry on with your own patched version, you should be able to derive patch versions from the commits I think.

I can try your v6 branch tomorrow so we're on the same page, just been a bit distracted with other stuff today.

Seems like the UI install is working again now, still ending up with a ? though for my manually installed dependencies. So progress at least. I'll try to play around with it a bit more when I have a chance.

Stale issue message

Sorry I haven't had a chance to get back to this for a while. Feel free to close this if you'd like as it's not a huge issue, just takes an extra minute to manually install dependencies. When I get a chance I can hopefully try to take a look at this again sometime.

Thanks, I'm pretty sure every thing is working again now in the v6 branch. I need to get back to working on it. I've had a bit of a break. Thanks for your patience. I'll close this but if you discover any other issues, please do let me know.

Confirmed that manually installed packages in your uibRoot folder correctly populate all of the metadata after node-red is restarted.