Dashboard 2 Beta development

<style>   
    /* cuida de imagens e cores do fundo da pagina */
    body {        
        background-image: url('/fundo.jpg');        
        background-size: cover; 
        //background-color: #000000;
    }

    /* cuida da transparencia da barra de titulo */
    body.nr-dashboard-theme md-toolbar {
        background-color: transparent !important;
    }
    
    /* cuida da transperancia dos botões dos cartões */
    body.nr-dashboard-theme md-content md-card {
        background-color: transparent !important;
    }

    /* cuida da transperencia de fundo do menu */
    body.nr-dashboard-theme md-sidenav {        
        background-color: transparent !important;        
    }

    /* cuida do arredondamento do item selecionado no menu */
    button.md-no-style {
        border-radius: 10px !important;        
    } 

    /* cuida da cor da seleção do item selecionado no menu */
    .nr-menu-item-active div button {
        border-right: 4px solid #000000 !important;        
    } 

    /* cuida das configurações do menu */
    body.nr-dashboard-theme md-sidenav div.md-list-item-inner {
        color: #000000 !important; /* cor das letras dos itens do menu */ 
        background-color: #ffffff !important; /* cor do fundo dos itens do menu */
        border-radius: 10px !important; /* cuida da curva dos cantos dos itens do menu */
    }

    /* cuida das configurações dos cartões de grupo */
    ui-card-panel {      
        background-color: #00000040 !important; /* cuida da cor do fundo dos grupos do menu */
        border-radius: 10px !important; /* cuida da curva dos cantos do cartão de grupo */
        border: 1px solid #000000 !important;
    }  

    /* cuida da cor do nome do cartão de grupo */
    .nr-dashboard-theme ui-card-panel p.nr-dashboard-cardtitle {        
        color: #ffffff40 !important;
        
    }

    /* cuida da cor do titulo da pagina */
    body.nr-dashboard-theme md-toolbar .md-toolbar-tools {
        color: #ffffff40 !important;
    }
</style>

This is the configuration I used in 1.0.. These are basic things that the vast majority of my clients ask to change.. I noticed that the front updates don't happen after the deploy.. they kind of have a mind of their own.. sometimes it works, sometimes it doesn't ..

This little flow hangs the browser rather spectacularly. It took me 5 minutes to close the dashboard tab and close MS Edge.
The trigger is a missing single quote after black in the second line of the template, which contains

<v-icon 
    :color="msg.payload === 'On' ? 'red' : 'black"
    :icon="msg.payload === 'On' ? 'mdi-led-on' : 'mdi-led-off'"
    size="x-large">
</v-icon>

Nothing in the node-red log, though the developer console was being thrashed with errors continually. I don't know if there is anything that can be done to make the system more resilient to typos.

image

[{"id":"1c35624c74ddbdcf","type":"ui-template","z":"997da33a0beedade","group":"7545fdb22e4a388c","dashboard":"04ee189a49c54f22","page":"","name":"Browser crasher","order":0,"width":"1","height":"1","head":"","format":"<v-icon \n    :color=\"msg.payload === 'On' ? 'red' : 'black\"\n    :icon=\"msg.payload === 'On' ? 'mdi-led-on' : 'mdi-led-off'\"\n    size=\"x-large\">\n</v-icon>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":480,"y":1400,"wires":[[]]},{"id":"12a9d15fa006200b","type":"inject","z":"997da33a0beedade","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Off","payloadType":"str","x":210,"y":1420,"wires":[["1c35624c74ddbdcf"]]},{"id":"827648ca0e1fad66","type":"inject","z":"997da33a0beedade","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"On","payloadType":"str","x":210,"y":1380,"wires":[["1c35624c74ddbdcf"]]},{"id":"7545fdb22e4a388c","type":"ui-group","name":"D2 tests","page":"d7fcdd33578e5d34","width":"6","height":"1","order":-1,"showTitle":true,"className":""},{"id":"04ee189a49c54f22","type":"ui-base","name":"Dashboard","path":"/dashboard"},{"id":"d7fcdd33578e5d34","type":"ui-page","name":"d2","ui":"ID-BASE-1","path":"/d2","layout":"flex","theme":"48d09dabddfb21da","order":-1,"className":""},{"id":"ID-BASE-1","type":"ui-base","name":"Dashboard","path":"/dashboard"},{"id":"48d09dabddfb21da","type":"ui-theme","name":"Theme 1","colors":{"surface":"#ffffff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"}}]
1 Like

This is a gripe I have too - mentioned it to @Steve-Mcl and it's been fedback to me that this would require NR-level changes, out of the control of Dashboard. We essentially need a Vue eslinter running in that editor window.

Are you expecting this to just work in D2.0, without further changes? We do not use the same styling/underlying CSS libraries, so these classes won't just work out of the box. They need to be updated to reflect the D2.0 classes in use.

The only thing I've noticed is that if you're using a D2.0 ui-template with "CSS (All Pages)" or "CSS (Single Page)", then you do not need to wrap your CSS in <style/> you can just write the CSS straight into the template node's editor.

Monaco only does syntax highlighting on embedded code blocks (never mind understanding vue (or even angular for that matter)). For example, it wont even tell you there is a regular JS error inside a <script> tag - this is a known limitation.

Essentially, we need a language server for the vue language.

It is something I am looking into but this will not be a quick turnaround I'm afraid.

I am fully aware that I will need to rediscover the components and how I will use them in new projects.. I am not very knowledgeable and even less so in Vue.js. I noticed that dynamically the changes I'm making are not going up to the front and this is making me skip straight to the creations made through error and trial. I only gave one example of what I always used and not one stated that it wasn't working. I know I need to adapt to the new way. Thank you and I will continue my studies.

That still wouldn't be all that resilient though would it?

What errors were those Colin? (not really wanting to put my own Node-RED instance through that experience! :slight_smile: ).

Regarding the above here, did you try:

I will see if I can catch something. They go whizzing past and the browser is essentially locked up so it isn't easy to do....

1 Like

image

As for components, I'm doing exactly that, but things like visual configuration of groups, wallpapers, menus and others I'm still learning about. I noticed that by completely restarting the flows some errors were corrected..

Hmm, that is interesting. When I remove the quote, deploy, and go to the dashboard page in the browser, then in the tools I see a number of messages like below. Are those coming from the build phase?

index-dgU0Lv9G.js:203 SIO connected
index-dgU0Lv9G.js:195 ui-config received. topic: ID-BASE-1 payload: Object
index-dgU0Lv9G.js:195 ui-config received. topic: 04ee189a49c54f22 payload: Object
index-dgU0Lv9G.js:195  errorCaptured TypeError: Cannot read properties of undefined (reading 'state')
    at Proxy.render (eval at compileToFunction (index-dgU0Lv9G.js:7:33845), <anonymous>:12:26)
    at renderComponentRoot (index-dgU0Lv9G.js:1:44378)
    at ReactiveEffect.he [as fn] (index-dgU0Lv9G.js:1:90949)
    at ReactiveEffect.run (index-dgU0Lv9G.js:1:25915)
    at K.j.update (index-dgU0Lv9G.js:1:91361)
    at K (index-dgU0Lv9G.js:1:91399)
    at W (index-dgU0Lv9G.js:1:89785)
    at U (index-dgU0Lv9G.js:1:89501)
    at C (index-dgU0Lv9G.js:1:85720)
    at ReactiveEffect.he [as fn] (index-dgU0Lv9G.js:1:90972) Proxy(Object) 1
errorCaptured @ index-dgU0Lv9G.js:195
Promise.then (async)
queueFlush @ index-dgU0Lv9G.js:1
queuePostFlushCb @ index-dgU0Lv9G.js:1
queueEffectWithSuspense @ index-dgU0Lv9G.js:1
A @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
(anonymous) @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
(anonymous) @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
set value @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:199
(anonymous) @ index-dgU0Lv9G.js:199
Promise.then (async)
P @ index-dgU0Lv9G.js:199
P @ index-dgU0Lv9G.js:199
O @ index-dgU0Lv9G.js:199
(anonymous) @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
emitEvent @ index-dgU0Lv9G.js:195
onevent @ index-dgU0Lv9G.js:195
onpacket @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
(anonymous) @ index-dgU0Lv9G.js:195
Promise.then (async)
(anonymous) @ index-dgU0Lv9G.js:195
ondecoded @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
add @ index-dgU0Lv9G.js:195
ondata @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onPacket @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onPacket @ index-dgU0Lv9G.js:195
r @ index-dgU0Lv9G.js:195
onData @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onLoad @ index-dgU0Lv9G.js:195
a.onreadystatechange @ index-dgU0Lv9G.js:195
XMLHttpRequest.send (async)
create @ index-dgU0Lv9G.js:195
Request @ index-dgU0Lv9G.js:195
request @ index-dgU0Lv9G.js:195
doPoll @ index-dgU0Lv9G.js:195
poll @ index-dgU0Lv9G.js:195
onData @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onLoad @ index-dgU0Lv9G.js:195
a.onreadystatechange @ index-dgU0Lv9G.js:195
XMLHttpRequest.send (async)
create @ index-dgU0Lv9G.js:195
Request @ index-dgU0Lv9G.js:195
request @ index-dgU0Lv9G.js:195
doPoll @ index-dgU0Lv9G.js:195
poll @ index-dgU0Lv9G.js:195
doOpen @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
ut @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
Manager @ index-dgU0Lv9G.js:195
lookup @ index-dgU0Lv9G.js:195
(anonymous) @ index-dgU0Lv9G.js:203
index-dgU0Lv9G.js:195  errorCaptured TypeError: Cannot read properties of undefined (reading 'state')
    at Proxy.render (eval at compileToFunction (index-dgU0Lv9G.js:7:33845), <anonymous>:12:26)
    at renderComponentRoot (index-dgU0Lv9G.js:1:44378)
    at ReactiveEffect.he [as fn] (index-dgU0Lv9G.js:1:90949)
    at ReactiveEffect.run (index-dgU0Lv9G.js:1:25915)
    at K.j.update (index-dgU0Lv9G.js:1:91361)
    at K (index-dgU0Lv9G.js:1:91399)
    at W (index-dgU0Lv9G.js:1:89785)
    at U (index-dgU0Lv9G.js:1:89501)
    at C (index-dgU0Lv9G.js:1:85720)
    at ReactiveEffect.he [as fn] (index-dgU0Lv9G.js:1:90972) Proxy(Object) 1
errorCaptured @ index-dgU0Lv9G.js:195
Promise.then (async)
...

It doesn't hang the browser till I refresh the page. Perhaps one can catch those errors somehow and do something clever to prevent the hang.

Ah, well I started to try and help but I'm stuck. A regression seems to have crept in because - despite completely removing all D2 nodes - including config nodes - removing D2, restarting, adding D2, restarting then adding a single text node, I cannot access the D2 dashboard page.

This is because, as always, I have the httpNodeRoot set to "nr" so that Node-RED page URLS are always prefixed - found this problem the hard way in the past whihc is why it is always set on my dev PC. D2 is still making assumptions that ignore httpNodeRoot and I get these errors:

image

As you can see, it is trying to load resources without the /nr prefix which is incorrect and so cannot find them.

So I'm afraid I can't help debug for now.

Almost certainly, this is the result of coded URL's that don't use the relative prefix of ./ so that they pick up the current URL prefix. The link in the Node-RED Editor has been corrected but the resource links haven't.

Though even after fixing the template I still see this when I refresh the page. These may be down to something else entirely though

In fact I am not sure that the errors I posted above are anything to do with the template node.

I have managed to capture the log from the page refresh, here is the start of it:

Navigated to http://localhost:1880/dashboard/d2
index-dgU0Lv9G.js:203 SIO connected
index-dgU0Lv9G.js:195 ui-config received. topic: ID-BASE-1 payload: {dashboards: {…}, heads: {…}, pages: {…}, themes: {…}, groups: {…}, …}
index-dgU0Lv9G.js:195 ui-config received. topic: 04ee189a49c54f22 payload: {dashboards: {…}, heads: {…}, pages: {…}, themes: {…}, groups: {…}, …}
index-dgU0Lv9G.js:195  errorCaptured  Proxy(Object) {_: {…}, $socket: Socket, send: ƒ, submit: ƒ, …} 1
errorCaptured @ index-dgU0Lv9G.js:195
callWithErrorHandling @ index-dgU0Lv9G.js:1
callWithAsyncErrorHandling @ index-dgU0Lv9G.js:1
t.__weh.t.__weh @ index-dgU0Lv9G.js:1
handleError$1 @ index-dgU0Lv9G.js:1
renderComponentRoot @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
D @ index-dgU0Lv9G.js:1
k @ index-dgU0Lv9G.js:1
I @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
K @ index-dgU0Lv9G.js:1
W @ index-dgU0Lv9G.js:1
U @ index-dgU0Lv9G.js:1
C @ index-dgU0Lv9G.js:1
he @ index-dgU0Lv9G.js:1
run @ index-dgU0Lv9G.js:1
K.j.update @ index-dgU0Lv9G.js:1
callWithErrorHandling @ index-dgU0Lv9G.js:1
flushJobs @ index-dgU0Lv9G.js:1
Promise.then (async)
queueFlush @ index-dgU0Lv9G.js:1
queuePostFlushCb @ index-dgU0Lv9G.js:1
queueEffectWithSuspense @ index-dgU0Lv9G.js:1
A @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
(anonymous) @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
(anonymous) @ index-dgU0Lv9G.js:1
triggerEffect @ index-dgU0Lv9G.js:1
triggerEffects @ index-dgU0Lv9G.js:1
triggerRefValue @ index-dgU0Lv9G.js:1
set value @ index-dgU0Lv9G.js:1
$ @ index-dgU0Lv9G.js:199
(anonymous) @ index-dgU0Lv9G.js:199
Promise.then (async)
P @ index-dgU0Lv9G.js:199
O @ index-dgU0Lv9G.js:199
(anonymous) @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
emitEvent @ index-dgU0Lv9G.js:195
onevent @ index-dgU0Lv9G.js:195
onpacket @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
(anonymous) @ index-dgU0Lv9G.js:195
Promise.then (async)
(anonymous) @ index-dgU0Lv9G.js:195
ondecoded @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
add @ index-dgU0Lv9G.js:195
ondata @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onPacket @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onPacket @ index-dgU0Lv9G.js:195
r @ index-dgU0Lv9G.js:195
onData @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onLoad @ index-dgU0Lv9G.js:195
a.onreadystatechange @ index-dgU0Lv9G.js:195
XMLHttpRequest.send (async)
create @ index-dgU0Lv9G.js:195
Request @ index-dgU0Lv9G.js:195
request @ index-dgU0Lv9G.js:195
doPoll @ index-dgU0Lv9G.js:195
poll @ index-dgU0Lv9G.js:195
onData @ index-dgU0Lv9G.js:195
Emitter.emit @ index-dgU0Lv9G.js:195
onLoad @ index-dgU0Lv9G.js:195
a.onreadystatechange @ index-dgU0Lv9G.js:195
XMLHttpRequest.send (async)
create @ index-dgU0Lv9G.js:195
Request @ index-dgU0Lv9G.js:195
request @ index-dgU0Lv9G.js:195
doPoll @ index-dgU0Lv9G.js:195
poll @ index-dgU0Lv9G.js:195
doOpen @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
ut @ index-dgU0Lv9G.js:195
open @ index-dgU0Lv9G.js:195
Manager @ index-dgU0Lv9G.js:195
lookup @ index-dgU0Lv9G.js:195
(anonymous) @ index-dgU0Lv9G.js:203
index-dgU0Lv9G.js:195  errorCaptured  Proxy(Object) {_: {…}, $socket: Socket, send: ƒ, submit: ƒ, …} 1
errorCaptured @ index-dgU0Lv9G.js:195
callWithErrorHandling @ index-dgU0Lv9G.js:1
callWithAsyncErrorHandling @ index-dgU0Lv9G.js:1
t.__weh.t.__weh @ index-dgU0Lv9G.js:1
handleError$1 @ index-dgU0Lv9G.js:1
...

It appears to repeat that error ad infinitum

I like the fact that if I send something other than an Object it becomes a value of msg.payload, but as you say, when sending an Object the keys should be treated as keys of a msg

One other point, if false or 0 are sent they are ignored so somewhere something is ignoring anything that does not compute as truthy.

1 Like

image

<template>
    <v-btn ref="botao" stacked @click="alternar">
        Titulo 2
        <v-icon ref="icon">mdi-timeline</v-icon>
    </v-btn>
</template>

<script>
    export default {
        data() {
            return {
                chave: 'a2'
            };
        },
        methods: {
            alternar: function () {
                if (window.localStorage.getItem(this.chave) === 'ON') {
                    this.desligar();
                    this.send({ payload: 'OFF' });
                } else if (window.localStorage.getItem(this.chave) === 'OFF') {
                    this.ligar();
                    this.send({ payload: 'ON' });
                }
            },
            ligar: function () {            
                window.localStorage.setItem(this.chave, 'ON');
                this.$refs.icon.$el.style.color = '#BD9608';
                this.$refs.icon.$el.style.textShadow = '0px 0px 10px #BD9608';                              
            },
            desligar: function () {                
                window.localStorage.setItem(this.chave, 'OFF');
                this.$refs.icon.$el.style.color = '#A9A9A9';
                this.$refs.icon.$el.style.textShadow = '0px 0px 0px';                              
            },
            setState (value) {
                if (value === 'ON') {                    
                    this.ligar();
                } else if (value === 'OFF') {                    
                    this.desligar();
                }
            }
        },
        mounted () {            
            this.setState(window.localStorage.getItem(this.chave));            
            this.$socket.on("msg-input:" + this.id, (msg) => {
                this.setState(msg.payload);
            });
            this.$nextTick(() => {
                // tanho do icone
                this.$refs.icon.$el.style.fontSize = '40px';  
                // cor e espessura da borda do botão              
                this.$refs.botao.$el.style.border = '1px solid #000000';
                // altura do botão
                this.$refs.botao.$el.style.width = '75px';
                // largura do botão
                this.$refs.botao.$el.style.height = '75px';
                // cor da letra do titulo do botão
                this.$refs.botao.$el.style.color = '#000000';
                // tamanho da fonte do titulo do botão
                this.$refs.botao.$el.style.fontSize = '11px';
                // cor do fundo do botão
                this.$refs.botao.$el.style.backgroundColor = '#4F4F4F';
                // arredondamento dos cantos do botão
                this.$refs.botao.$el.style.borderRadius = '10px';
            });                    
        }
    }
</script>


For some reason, some icons don't load correctly. "mdi-lightbulb" works, but "mdi-timeline" loads a totally different icon. I'm using the Google repository. What can it be?

Looks right to me: timeline - Material Design Icons - Pictogrammers

You are not alone Colin...

I adjusted the icon problem, as I imagined, it was my fault. lol.. Below is the example of a corrected button.

<template>
    <v-btn ref="botao" stacked @click="alternar">
        Externa
        <v-icon ref="icone">mdi-beach</v-icon>
    </v-btn>
</template>

<script>
    export default {
        data() {
            return {
                chave: 'a1'
            };
        },
        methods: {
            alternar: function () {
                if (window.localStorage.getItem(this.chave) === 'ON') {
                    this.desligar();
                    this.send({ payload: 'OFF' });
                } else if (window.localStorage.getItem(this.chave) === 'OFF') {
                    this.ligar();
                    this.send({ payload: 'ON' });
                } else {
                    this.desligar();
                }
            },
            ligar: function () {            
                window.localStorage.setItem(this.chave, 'ON');
                this.$refs.icone.$el.style.color = '#BD9608';
                this.$refs.icone.$el.style.textShadow = '0px 0px 10px #BD9608';                              
            },
            desligar: function () {                
                window.localStorage.setItem(this.chave, 'OFF');
                this.$refs.icone.$el.style.color = '#A9A9A9';
                this.$refs.icone.$el.style.textShadow = '0px 0px 0px';                              
            },
            setState (value) {
                if (value === 'ON') {                    
                    this.ligar();
                } else if (value === 'OFF') {                    
                    this.desligar();
                }
            }
        },
        mounted () {            
            this.setState(window.localStorage.getItem(this.chave));            
            this.$socket.on("msg-input:" + this.id, (msg) => {
                this.setState(msg.payload);
            });
            this.$nextTick(() => {
                // tanho do icone
                this.$refs.icone.$el.style.fontSize = '40px';  
                // cor e espessura da borda do botão              
                this.$refs.botao.$el.style.border = '1px solid #000000';
                // altura do botão
                this.$refs.botao.$el.style.width = '75px';
                // largura do botão
                this.$refs.botao.$el.style.height = '75px';
                // cor da letra do titulo do botão
                this.$refs.botao.$el.style.color = '#000000';
                // tamanho da fonte do titulo do botão
                this.$refs.botao.$el.style.fontSize = '11px';
                // cor do fundo do botão
                this.$refs.botao.$el.style.backgroundColor = '#4F4F4F';
                // arredondamento dos cantos do botão
                this.$refs.botao.$el.style.borderRadius = '10px';
            });                    
        }
    }
</script>


I have now updated the set of nodes and I still have problems with the organization of the grid. Continue as is.

I continue working and developing the components I need.

I just realized that when the button follows specific sizes in the CSS, the Grid does not correctly size the groups.

@joepavitt do you know the cause of this? I see it does not happen with a dashboard consisting of just one text node. I can attempt to work out what in the flow triggers it if that would be useful.