Dashboard 2.0 Pre-Alpha Available

That appears to be specifically about labels. The value format field allows selection of message property and formatting of that (specifying decimal places etc) for the value shown in the widget, not for the label.

All 3 now added to GH.

1 Like

Has the layout of switches changed with 0.8.0? If I have a full width Switch widget then the Label is being positioned at the left hand side but the switch is positioned somwhere in the middle, depending on the length of the label string. For example

I am almost certain that the switch used to be at the RHS.

I have confirmed that the switches were positioned at the right hand side in version 0.7.2 so have reported an issue.
[Regression] Switch widget in v0.8.0 shows switch in wrong place · Issue #396 · FlowFuse/node-red-dashboard · GitHub

3 Likes

I see that version 0.9.0 has been released with ui-control and ui-event, which is great, thanks for this.

A question: from the ui-event node I get a notification when a page is opened. The message includes msg.socketid. I am using the event to update the time in a ui-text node in time picker mode, which works fine. I thought, though, that if I include msg.socketid from the event in the message writing to the text node that it should only update the field in the browser that opened the page, but in fact it updates in all browser windows showing that page. Is this a bug, a not yet implemented feature, or is my understanding wrong?

For now, it's informative only. Was this a feature in Dashboard 1.0? I wasn't aware if so. Happy for you to open a feature request for this. Thanks Colin.

That should be msg._socketId and it is a standard feature of Socket.IO - are you not using that in D2?

If not, how will you provide a feature to limit responses to only a single connected client browser tab?

In Dashboard 1.0, this was injected under msg.socketid (Dashboard 1.0 Docs), so I have done the same. I actually add msg.socketid now to all Dashboard generated events, button clicks, form submissions, etc.

A future plan would be to then have a control that defines whether or not that is actually appended each time, such that you could have multi-tenant interaction in Dashboard.

Right now - not possible, but it's on the todo list.

I thought it was, but I must admit that I don't seem to be able to get it to work. Can anyone confirm whether what I am doing should work in D1? That is sending a message to a text input node, containing msg.socketid from the ui_control node, to update the text in the text node.

Oops, inconsistent - since Node-RED seems to use _socketId everywhere else?

Also worth remembering the limitations of the socket id. It can change very easily. All it takes is for there to be a network hiccup or for the users OS or browser tab to temporarily go to sleep and it will change.

For UIBUILDER, that meant that I eventually added 3 other options that can be used for automatic filtering. A client ID (set by the server as a UID and given to the client in a cookie, reset if the users browser is closed and re-opened), a tab ID (set by the browser and stable as long as the browser instance and tab remain open, a browser feature that uib ties into), and a page name.

Might be nice if we could align? I did try to get interest in that previously.

Happy to work it out. Feel free to put some time in Calendly - Joe Pavitt

Cool. Thanks Joe. As it happens I'm using up some holiday so I'm free on Tue PM. Will be good to actually talk. :grinning: Time booked.

4 Likes

It seems this is not a feature of D1 (the ability to use socketid to update data on only one connected session). See Unable to update text field on just one session using msg.socketid.

1 Like

Dave makes a good point - for IoT systems - but not for general purpose I don't believe. Surely the flow designer/author should make the decision? In a general-purpose UI, there is really no fixed reason why different clients - even different tabs on the same client browser - shouldn't have different displays if that is the design decision. But, of course, it needs to be clearly documented.

In reality, the socketid is so prone to change anyway that it is a poor choice other than for direct return responses such as an acknowledgement of an action from a client back to the client.

That's why I settled on the 3 properties I chose for uibuilder. It gives the flow author useful choices without the need to build a full multi-user session handler.

What I'd really like to do in uibuilder, when time permits, is to build further on these properties and socket.io's rooms capabilities. At the moment, messages would still get sent to all connected clients and are filtered by the front-end library. This is obviously not ideal. It would be better for each property to create a socket.io room and for the uibuilder node to use those to properly direct messages to the right clients. Clearly, that could then be expanded further to easily allow arbitrary rooms to be created and used giving even more flexibility but maintaining security and privacy and minimising bandwidth usage.

I offer up these thoughts for consideration for D2 as well in case you want to think about any of them.

2 Likes

Just trying some examples using the Template node, but finding vue not as easy to work with as javascript :face_with_raised_eyebrow:
I'm trying to get the 'selected option' to be emitted when clicked, so that it could be used to vary chart timescales, or navigate dashboard pages, etc, but failing badly so far.

menu

<template>
  <div class="d-flex justify-space-around">
    <v-menu>
      <template v-slot:activator="{ props }">
        <v-btn
          color="primary"
          v-bind="props"
        >
          Select Option
        </v-btn>
      </template>
      <v-list>
        <v-list-item
          v-for="(item, index) in items"
          :key="index"
          :value="index"
        >
          <v-list-item-title>{{ item.title }}</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-menu>
  </div>
</template>

<script>
  export default {
    data: () => ({
      items: [
        { title: 'Option 1' },
        { title: 'Option 2' },
        { title: 'Option 3' },
        { title: 'Option 4' },
      ],
    }),
  }
</script>

add an event listener to your v-list-item
in Vue it can be like @click="send({payload: item.title})

...
<v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="send({payload: item.title})">
     <v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
...
3 Likes

Thanks Andy, you made that look very easy :laughing:

1 Like

Hi @Paul-Reed - thanks for giving this a go.

TLDR:

Add @click="send(item.title)" to the v-list-item element, that will send that message onwards in Node-RED.

Explanations:

Will quickly point to our docs, which do include some related examples of this: Text ui-template | Node-RED Dashboard 2.0

I also want to detail this particular case too though.

Quick VueJS tips:

  • When you want to bind a value to a widget in VueJS, you can use v-model="myVar"
  • When you want to action any updates on that value, you can use @update:modelValue="<fcnToRun()>"

Normally, you can just utilise these features to get the result you're after. Annoyingly, the v-menu element you've used is generally designed for navigation in a top header usage, rather than having a single active value (you'd normally use v-select - docs for something like that).

Sticking with v-menu though, I quickly tested what it stores as it's internal modelValue by adding an active variable to our data, binding it to v-model="active" and just printing it's value into the HTML:

{{ active }}
<v-menu v-model="active">

That seems to bind a true/false value depending on whether the menu or open or not, rather than the active option from the v-list.

As a result, if you're set on using v-menu, I would instead recommend utilising the @click handlers on the v-list-item elements. You can then utilise our built-in send(payload) function, which would look something like this in it's entirety:

<template>
    <div class="d-flex justify-space-around">
        <v-menu>
            <template v-slot:activator="{ props }">
                <v-btn color="primary" v-bind="props">
                    Select Option
                </v-btn>
            </template>
            <v-list>
                <v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="send(item.title)">
                    <v-list-item-title>{{ item.title }}</v-list-item-title>
                </v-list-item>
            </v-list>
        </v-menu>
    </div>
</template>

<script>
    export default {
    data: () => ({
        items: [
            { title: 'Option 1' },
            { title: 'Option 2' },
            { title: 'Option 3' },
            { title: 'Option 4' },
        ]
    })
  }
</script>

Wiring this to a debug node, I see "Option X" printed out each time. You could then add other properties to your item object, and have different labels from what values are emitted, etc.

Hope that helps

2 Likes

Also worth mentioning that I have an article due for publishing tomorrow which is a tutorial on building a custom Video Player using the new UI Template, which should introduce a lot of the concepts for new Vue devs too.

Also also, the <script> tags can also contain raw JS, doesn't have to be VueJS, however, we do build in all of the helpers (e.g. send(payload)) into the Vue Component framework, so it does make life a lot easier.

1 Like

There is clearly a lot of potential in the Template node using Vuetify, but it has taken me 10 years to learn basic javascript, so don't expect anything great from me coding Vue in the foreseeable :laughing:
...but, I've made a start.

Thanks for the explanation Joe

1 Like