Sigh sorry another basic question

I am trying to get to grips with uibuilder. None of the examples or gists work. The browser seems unable to locate the script src files for vendor libraries (even though I have installed) eg

 <script src="vendor/moonjs/dist/moon.min.js"></script> 

I am running on docker and moonjs is installed in the main directory in node_modules.

I have been trying various (undeducated guesses!) values and landed on this that worked.

<script src="../uibuilder/vendor/moonjs/dist/moon.min.js">

Of course that just exposes a further error.....it is taking sooo long and I have a long learning curve ahead with webcomponents and uibuilder anyway

Can anyone point me at any topic or area to research so that I can learn what is going on?

ps another long spell resulted in translating

<script src="/uibuilder/socket.io/socket.io.js"></script>

into

<script src="../uibuilder/vendor/socket.io/socket.io.js"></script>

OK, lets start with your environment. Firstly, can you please share the startup log - the bit of the node-red log from start to where it says "flows started". That will tell me about your server environment.

Then you need to look at the uibuilder details page.
image

You will see that all of the general 3rd-party library URL's have to start with ../uibuilder/vendor/ and you've discovered that now. However, the details page shows you loads of information including the best guess as to the locations of the library files.

This seems very unlikely. Have you tried one of the Templates?

image

Or one of the library examples:

Unfortunately, you have chosen to start with MoonJS and I have to say that I've not looked at that framework for a long time.

You will see that the WIKI example for MoonJS hasn't been updated since uibuilder v2, we are now on v5. The example was last updated in 2019 which is a long time ago.

If you can explain a bit about what you are hoping to do, I can probably guide you to the best approach.

1 Like

aha......Thank you for your speedy and patient response.......

> node-red-docker@2.2.2 start /usr/src/node-red
> node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"

13 Jun 07:29:13 - [info]

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

13 Jun 07:29:13 - [info] Node-RED version: v2.2.2

13 Jun 07:29:13 - [info] Node.js version: v14.18.2

13 Jun 07:29:13 - [info] Linux 5.10.28-Unraid x64 LE
13 Jun 07:29:14 - [info] Loading palette nodes
13 Jun 07:29:14 - [info] Loading palette nodes
13 Jun 07:29:15 - [info] Dashboard version 3.1.7 started at /ui

13 Jun 07:29:15 - [info] Settings file : /data/PreProdSettings.js
13 Jun 07:29:15 - [info] Context store : 'default' [module=memory]
13 Jun 07:29:15 - [info] User directory : /data
13 Jun 07:29:15 - [warn] Projects disabled : editorTheme.projects.enabled=false
13 Jun 07:29:15 - [info] Flows file : /data/flows.json
13 Jun 07:29:16 - [info] Server now running at http://127.0.0.1:1880/
13 Jun 07:29:16 - [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.
---------------------------------------------------------------------

13 Jun 07:29:16 - [info] +-----------------------------------------------------
13 Jun 07:29:16 - [info] | uibuilder v5.0.2 initialised
13 Jun 07:29:16 - [info] | root folder: /data/uibuilder
13 Jun 07:29:16 - [info] | Using Node-RED's webserver at:
13 Jun 07:29:16 - [info] | http://0.0.0.0:1880/
13 Jun 07:29:16 - [info] | Installed packages:
13 Jun 07:29:16 - [info] | bootstrap, bootstrap-vue, jquery, moonjs
13 Jun 07:29:16 - [info] | popper, vue
13 Jun 07:29:16 - [info] +-----------------------------------------------------
13 Jun 07:29:16 - [info] Starting flows
13 Jun 07:29:16 - [info] Started flows

Argh sorry....was tired ......I should have said the examples that I was hoping would jump start my thoughts......I definitely got the basic inject message/ receive button click example to work.. The documentation and guides were perfect for this.

I am looking to build a 'simple' page that is wife friendly on IOS that will allow sending commands to node-red from an iphone. eg. 'Switch on lights' 'Activate Good night ',

I hope someone has done something like this .....would be surprised if they haven't.

Nothing to do with uibuilder - just answers your other question.

I've done a similar thing using Telegram on an Android phone (there is a version of Telegram for IOS) that makes use of in-line virtual keyboards so you can interact with your home systems. In my situation I can take photos from my security cameras, switch lights on/off, get reports on my servers and other devices on my network. The Node-RED flow is running on a RPi server.
snap
switch

Oh interesting approach..... Thanks

Which 'details page' Where is that? I suspect if I had come across that table in my stumbles it may have helped. (I know it seems like I have not put the effort in, but I did go through the walk through )

When I try and look at the details info on the uibuilder nodes I seem to get errors. eg

TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'win32' closes the circle
    at JSON.stringify (<anonymous>)
    at detailsPage (/data/node_modules/node-red-contrib-uibuilder/nodes/libs/admin-api-v2.js:174:40)
    at /data/node_modules/node-red-contrib-uibuilder/nodes/libs/admin-api-v2.js:597:28
    at Layer.handle [as handle_request] (/data/node_modules/express/lib/router/layer.js:95:5)
    at next (/data/node_modules/express/lib/router/route.js:144:13)
    at Route.dispatch (/data/node_modules/express/lib/router/route.js:114:3)
    at Layer.handle [as handle_request] (/data/node_modules/express/lib/router/layer.js:95:5)
    at /data/node_modules/express/lib/router/index.js:284:15
    at Function.process_params (/data/node_modules/express/lib/router/index.js:346:12)
    at next (/data/node_modules/express/lib/router/index.js:280:10)
    at Function.handle (/data/node_modules/express/lib/router/index.js:175:3)
    at router (/data/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/usr/src/node-red/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/usr/src/node-red/node_modules/express/lib/router/index.js:323:13)
    at /usr/src/node-red/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/usr/src/node-red/node_modules/express/lib/router/index.js:341:12)
    at next (/usr/src/node-red/node_modules/express/lib/router/index.js:275:10)
    at /data/node_modules/express/lib/router/index.js:646:15
    at next (/data/node_modules/express/lib/router/index.js:265:14)
    at Function.handle (/data/node_modules/express/lib/router/index.js:175:3)
    at router (/data/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as h

from uibuilder details

and if I click on instance details and then the URL for vendor resources detailed info
(http://192.168.1.22:1780/uibindex)
My server rejects the URL with 'Cannot GET /uibindex'

I posted the image of the button.

Ah, maybe I need to extend that with a follow-up that goes through some of the other features.

Oh, that's strange - not seen that happen before. Not sure where win32 is coming from, there shouldn't be anything like that in the object that the page is trying to show. Though looking at the code, I can no longer remember why I did it the way I did - I usually leave myself lots of comments but I seem to have failed on that this time!

OK, forget that for the moment, I'll do some more digging on why that might be failing & put some extra checks into the next version I release.

OK, so I think you are beyond the first step anyway since you have the basics working.

Are you determined to use MoonJS? If that's what you know, that's fine. It is just that there probably isn't much help on that framework. If you are still open to options, I'd recommend either using Vue with bootstrap-vue or even old failthful jQuery. Indeed, for simple things, just plain HTML and JavaScript can be enough with uibuilder's help.

It would also be helpful to understand how much experience you might have in writing HTML/JavaScript.

I need to jump on some work right now, I'll be back later.

Thanks so much for your time.

No I am not in anyway determined to use MoonJS, I chose it as there was your gist and it was IOS/iphone focused. I am just looking for a jump start on delivering an iphone friendly, reasoably intuitive app. For more background, I have a node-red/smartthings automation set up and I am trying to reduce dependency on smartthings (There iphone app is currently too flakey for me to entertain my wife using it). I have pretty well implemented all the backend funcitonality I need, I am now looking at the front end.

Sigh I am a bit of an odd example. I am an old experienced IT guy with almost no experience of web development. I would probably class myself as competent with node.js/javascript server stuff. HTML, I am ok ish, css less so (I understand it, just find it a pita)......... I am retired now, so learning this stuff is like a hobby.....

1 Like

I would be delighted if this is enough, If I backtrack on my thought processes, I think I was looking for an example that I could try to see how it looked on the iphone and then fell into the rabbit hole of library locations which because of my lack of knowledge/experience caused a major flail

don't worry - plenty of those round here... so many, that it doesn't class you as odd at all.

2 Likes

OK, so now we have some basics to work with.

It was certainly a fair-enough assumption. And certainly Something like Vue with bootstrap-vue does indeed give you a major headstart since a lot of the work around size breakpoints and other standard layouts has been done for you. If you go down the pure HTML, there will be work to do on the CSS for sure. Though I'm working on a new CSS baseline for uibuilder that should help. It is a slow and error-prone process though I'm afraid. Some of the basics are already working fine but I'm sure there is a lot more work to be done.

Unfortunately, you have to make some up-front decisions and it is likely that none of them will be perfect. Go with Vue/Bootstrap and get an early head start on the layout and visuals but with possibly a steeper early learning curve and being tied into those frameworks later on. Or go the minimal approach which won't commit you to a framework but will need (at least as your pages grow in complexity) some learning on CSS.

Totally agree!

Which ever way you choose. We will be here to cheer you on and help where we can.

I don't know if it will help you choose but you might want to read through some of my recent posts on uibuilder development so that you can see where things are going. In line with the philosophy behind uibuilder, I've been working on a brand new version of the client library that drags things into the world of modern browsers and ditches legacy (you will need mobile browsers from at least 2019 though). This will introduce the ability to dynamically create web interfaces from JSON configuration objects and files. But you can also mix that will hand-written HTML as well. It doesn't commit you to any framework and you will still be able to use it with Vue, or any other framework if you like. It also opens up the world of web components as well which are framework-less extensions to HTML. Equally importantly, it moves front-end development into the modern ES Module style to ensure future compatibility. But at the same time, the library will let you produce completely code-free web UI's driven from Node-RED.

Still much work to be done but I'm close to releasing a new version of uibuilder with early versions of the new client and CSS as an option. Had hoped to do that over the weekend but got sidetracked - partly with family focus and partly due to adding a bunch of data guards and other improvements to the uibuilder codebase.

As I say, some other posts will give you an idea as to where things are going.

This is all very good advice.....I have read some of the posts on direction of node-red dashboard/uibuilder, all your comments resonate with me. Actually those threads prompted me to have a go with uibuilder.

I think I will begin by backing away from frameworks and try with just uibuilder/html and css It will be interesting even if goes nowhere (And there are plenty of online resources)

Another part of my flail, I looked at your web components and thought that looked interesting/fun, so I watched a couple of tutorials on web components and tried to use your simple button. Of course I then got whacked with the whole 'cant find library' thing.

Perhaps your walk through could have a paragraph on that.....Your notes on Vendor Client Libraries above would have been enough to assure me I was on a reasonable path (guessing at the src tab).

Anyway thanks for all your thoughts.

Cool, it will be fun anyway :smile_cat:

Right, I was reluctant to send you to that since it is rather a set of experiments right now. However, you've come at just the right time. I will get an update out for the web-components library ASAP so that you can use the updated button as I added some further enhancements to that over the weekend.

In the meantime, here is an HTML file that I've been using for testing. If you create a new uibuilder node using the blank template, you can use this and it should give you something at least.

<!doctype html>
<html lang="en"><head>
    <meta charset="utf-8">
    <title>Web Component Test: simple-container and simple-card</title>

    <!-- This link will change to "./uib-brand.css" when it goes into uibuilder itself -->
    <link type="text/css" rel="stylesheet" href="../uibuilder/vendor/@totallyinformation/web-components/uib-brand.css" media="all">
    <!-- <style>
        @import url("./uib-brand.css");
        /* Can override the base hue and the accent colours and other things too */
        /* :root {
            --brand-hue: 200;
            --accent-offset: 30;
        } */
    </style> -->

    <script type="module" async >
        // This is the version of the new library before it is moved to the uibuilder main package:
        import '../uibuilder/vendor/@totallyinformation/web-components/libs/uibuilder.module.js'
        // This will be the access once the library has been moved
        // import './uibuilder.esm.min.js'  // Adds `uibuilder` and `$` to globals
        // import './uibuilder.esm.js'  // Adds `uibuilder` and `$` to globals

        // This will load all of the web components that even vaguely work
        import '../uibuilder/vendor/@totallyinformation/web-components/libs/load-all.js'

        // Or you can load them individually
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/simple-container.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/simple-card.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/uib-theme-changer.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/labelled-value.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/button-send.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/container-br.js'
        // import '../uibuilder/vendor/@totallyinformation/web-components/components/chart-frappe.js'

        // This works as for previous versions:
        // uibuilder.onChange('msg', (msg) => {
        //     console.log('[uibuilder] msg rcvd', msg)
        // })
    </script>

</head><body>
    <uib-theme-changer></uib-theme-changer>
    <h1>Demonstrating Web Components</h1>
    <p>This example uses <code>&lt;simple-container</code> and <code>&lt;simple-card></code>.</p>
    <p>
        The container component uses a flex row layout. The card component has header and footer slots.
    </p>

    <simple-container>
        <nav-bar></nav-bar>
        
        <simple-card>
            Hello, in a card<br>
            <labelled-value id="lbl1" label="(lbl1) My Value" value="42">&deg;</labelled-value>
            <span slot="header">Some other header</span>
            <span slot="footer">Some footer</span>
        </simple-card>
        <simple-card name="This Is a name">
            Another card
            <labelled-value label="My Other Value" value="Fourty Two">&deg;</labelled-value>
        </simple-card>
        <simple-card id="card3" data-something="Hello">
            Card #3
        </simple-card>
        <container-br></container-br>
        <div>
            <button-send id="btn1" data-something="Something interesting" class="test">(btn1) Send Me to Somewhere 😀</button-send>
        </div>
        <container-br></container-br>
        <simple-card id="card4" data-something="Hello" variant="info">
            Card #4
            <span slot="footer">Variant=info/information</span>
        </simple-card>
        <simple-card id="card5" data-something="Hello" variant="success">
            Card #5
            <span slot="footer">Variant=success</span>
        </simple-card>
        <simple-card id="card6" data-something="Hello" variant="warn">
            Card #6
            <span slot="footer">Variant=warn/warning</span>
        </simple-card>
        <simple-card id="card7" data-something="Hello" variant="error">
            Card #7
            <span slot="footer">Variant=failure/error</span>
        </simple-card>
        <container-br></container-br>
        
    </simple-container>
    
    <script>
        // Event Listeners set in module scripts wont get set up early enough to pick up the initial component load events
        // BUT an ordinary script like this WILL trigger early enough.
        // HOWEVER, this triggers so early that if you load uibuilder in a module script, it
        //   wont be available here immediately. You would have to wait for ~300 ms.

        // document.addEventListener('simple-card:connected', e => {
        //     console.log('>> (document) EVENT simple-card:connected >>', e.target, e.detail)
        // })

        // This CAN pick up the initial setup event
        // document.addEventListener('simple-card:attribChanged', e => {
        //     console.log('>> (document) EVENT simple-card:attribChanged >>', e.target, e.detail)
        // })

        // document.addEventListener('uibuilder:stdMsgReceived', e => {
        //     console.log('>> (document) EVENT uibuilder:stdMsgReceived >>', e.detail)
        // })
        // document.addEventListener('uibuilder:msg:_ui', e => {
        //     console.log('>> (document) EVENT uibuilder:msg:_ui >>', e.detail)
        // })
        // document.addEventListener('uibuilder:msg:topic:updateme', e => {
        //     console.log('>> (document) EVENT uibuilder:msg:topic:addme >>', e.detail)
        // })
        // document.addEventListener('uibuilder:msg:_ui:update', e => {
        //     console.log('>> (document) EVENT uibuilder:msg:_ui:update >>', e.detail)
        // })
        // document.addEventListener('uibuilder:msg:_ui:update:btn1', e => {
        //     console.log('>> (document) EVENT uibuilder:msg:_ui:update:btn1 >>', e.detail)
        // })


        // Things set up in uibuilder won't be available here for ~300ms
        // setTimeout(function(){
        //     console.log('HELLO', window.$)
        //     $('#card3').setAttribute("name", "helloButton")
        // }, 300)

        // We can also listen at the component instance level:
        // const sc = document.getElementsByTagName('simple-card')
        // for (const i of sc) {
        //     // When the component constructor is run
        //     // i.addEventListener('simple-card:construction', e => {
        //     //     console.log('>> EVENT simple-card:construction >>', e)
        //     // })
            
        //     // When the component instance is connected to the DOM
        //     // i.addEventListener('simple-card:connected', e => {
        //     //     console.log('>> EVENT simple-card:connected >>', e)
        //     // })

        //     // When the component instance is disconnected from the DOM
        //     // i.addEventListener('simple-card:disconnected', e => {
        //     //     console.log('>> EVENT simple-card:disconnected >>', e)
        //     // })

        // }
    </script>
</body></html>

Hopefully not too confusing with all of the comments.

There is also a uibuilder.module.md file in the same location as the js which goes into detail about what you can do with it.

(PS: Sorry, I was going to post this earlier but work got in the way!)

PPS: Updates pushed to the web-components repo, please reinstall in uibuilder to get the latest version. Please note that you might need Safari v15+ if trying to use on iOS or Mac. I'm preparing a version that should work with Safari v12+ (though I can't test I'm afraid). If you need to test with earlier Safari, let me know and I'll add the other versions.

Oh wow thanks so much.

Will try this today

Argh Ok this seems fine.......By increasing logging level, it appears that these 'fails' are part of trying to locate the correct location for the library......

Ignore all this

Ok ive made a tiny bit of progress......However, I am really struggling with this whole external library topic. Is there a good place or google search term that would help me understand how relative file paths are resolved? I assume 'vendor' in a path has some sort of significance?

I have got to the point where I get a screen rendered but there are the following console messages on chromium

uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/vendor/@totallyinformation/web-components/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264
uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/vendor/@totallyinformation/web-components/uibuilder/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264
uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264
uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/uibuilder/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264
uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/vendor/uibuilder/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264
uibuilder.module.js:264          GET http://192.168.1.22:1780/uibuilder/vendor/@totallyinformation/uibuilder/vendor/socket.io-client/socket.io.esm.min.js net::ERR_ABORTED 404 (Not Found)
(anonymous) @ uibuilder.module.js:264

The socket.io-client/socket.io.esm.min.js file is in my 'main' node_modules if it is relevant. I also tried installing it (using npm) into uibuilder directory, so it is now in there as well (mmmh...I wonder if I should have added in the uibuilder node libraries instead....I'll try that)

I feel like I am being lazy asking this. sorry! It's just this feels like I am falling at the first hurdle when I have a long long race to run :frowning:

This is soooo cool

It is all in the tech docs - which has its own search even :wink: - but of course, it doesn't mean that my prose is understandable to anyone else so please do let me know of anything you think needs improving.

It isn't easy to understand. However, I've done my best to make sure you don't need to understand it.

This is a common naming convention for web services. It simply means that these are 3rd-party libraries.

It works like this. When you see a URL path like /uibuilder/vendor/ (typically ../uibuilder/vendor/ in your code), that translates to the root of any library that you've installed using the uibuilder Library manager. You will find that it also translates to the physical folder ~/.node-red/uibuilder/node_modules/ (assuming that you've not changed any of the default folders). It helps if you understand a bit about how npm works since that is the tool that manages the installation of the libraries. As you install a library such as my web-components library, it updates the the ~/.node-red/uibuilder/package.json file. In turn, that drives the folders that the ExpressJS web server stands up as paths under ../uibuilder/vendor/.

So, lets take a simple example - and you can safely do this yourself - If you install the npm package aaa (which is a dummy package that is used for testing), you will find a filing system folder called ~/.node-red/uibuilder/node_modules/aaa and that folder is presented from the web side as the URL path ../uibuilder/vendor/aaa/. That means that any file in that folder can be accessed from your front-end code.

Just to mention the ../ part. All that is is a relative URL that, when put in your code, substitutes the front part of the url, in your case http://192.168.1.22:1780/ so ../uibuilder/vendor/aaa/ translates to http://192.168.1.22:1780/uibuilder/vendor/aaa/. It is just a short-hand that means you can change other settings like IP addresses, ports and other settings without having to re-code your front-end.

Now, looking at your log, the only library you have an issue with is socket.io-client/socket.io.esm.min.js. This is a slightly different issue. And it is my fault for trying to move a bit too quickly!

I realise that I copied the code back from the uibuilder repo where I'd made a change a couple of days ago to build the socket.io client into the library. So mea culpa! Let me fix that for you now.

Done. Please reinstall the web-components library again then it should all work.

Again, apologies for leading you astray!

Aha thanks,.....this is all very helpful......I am making progress!!!!

meh!!!! Now I am less frustrated by my own lack of knowledge, this is all good . I am very grateful for your time.

I am hoping that seeing my flails will help adoption from others.......

1 Like