Need help to finish my dashboard toggle button

6,020 views
Skip to first unread message

dave....@gmail.com

unread,
Aug 31, 2016, 11:27:40 AM8/31/16
to Node-RED
Hi I have started to build a flow to produce a toggle button, I need to be able to update and feedback the state of this button from/to mqtt, blynk and the dashboard.

so an input into the button should toggle from 0 to 1 or 1 to 0, 
on the dashboard it should say Off or On  OR red or green or both, 
if the button is pressed on the dashboard it should toggle the button, 
and the output from the button should be On / Off OR 0 / 1 to feed back to mqtt etc

So as it stands the button functions as I want BUT I cannot figure out how to change the color of the button when the button state changes 0 or 1 OR change the text on the button when the button state changes 0 or 1 OR preferably both 

I have spent hours on this, now I am getting nowhere (or perhaps there's a better way) please help.

Thanks

[{"id":"5eb00add.679944","type":"ui_template","z":"b3674429.a21f68","group":"b67239fb.725888","name":"Toggle button","order":4,"width":"2","height":"1","format":"\n\n\n<style>\n:focus {\noutline: 0;\n}\nmyButton5 {\n\t-moz-box-shadow:inset 0px 0px 15px 3px #23395e;\n\t-webkit-box-shadow:inset 0px 0px 15px 3px #23395e;\n\tbox-shadow:inset 0px 0px 15px 3px #23395e;\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #2e466e), color-stop(1, #415989));\n\tbackground:-moz-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-webkit-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-o-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-ms-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:linear-gradient(to bottom, #2e466e 5%, #415989 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2e466e', endColorstr='#415989',GradientType=0);\n\tbackground-color:#2e466e;\n\t-moz-border-radius:17px;\n\t-webkit-border-radius:17px;\n\tborder-radius:17px;\n\tborder:1px solid #1f2f47;\n\tdisplay:inline-block;\n\tcursor:pointer;\n\tcolor:#ffffff;\n\tfont-family:Arial;\n\tfont-size:10px;\n\tpadding:10px 10px;\n\ttext-decoration:none;\n\ttext-shadow:0px 1px 0px #263666;\n}\nmyButton5:hover {\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #415989), color-stop(1, #2e466e));\n\tbackground:-moz-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-webkit-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-o-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-ms-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:linear-gradient(to bottom, #415989 5%, #2e466e 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#415989', endColorstr='#2e466e',GradientType=0);\n\tbackground-color:#415989;\n}\nmyButton5:active {\n\tposition:relative;\n\ttop:1px;\n}\n\n</style>\n<script>\n\nmyDiv5.innerHTML = (\"Off\");\n\n\n\n</script>\n\n<myButton5 ng-click=\"send({payload: 1})\"><div id=\"myDiv5\"></div></myButton5>\n\n","storeOutMessages":false,"fwdInMessages":true,"x":353,"y":125,"wires":[["4c6e85c4.01604c"]]},{"id":"ceb09fb0.52078","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":698,"y":99,"wires":[]},{"id":"4c6e85c4.01604c","type":"function","z":"b3674429.a21f68","name":"","func":"\ncontext.global.u_toggle = context.global.u_toggle || 0;\nmsg1={};\nmsg2={};\nif (context.global.u_toggle === 0){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"On\"});\n    context.global.u_toggle = 1;    \n    msg1.payload = 1;\n    msg2.payload = \"On\";\n} else {\n    node.status({fill:\"gray\",shape:\"dot\",text:\"Off\"});    \n    context.global.u_toggle = 0;\n    msg1.payload = 0;\n    msg2.payload = \"Off\";\n}   \n    return [msg1,msg2];","outputs":"2","noerr":0,"x":512,"y":125,"wires":[["ceb09fb0.52078"],["906d4625.10a578"]]},{"id":"906d4625.10a578","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":698,"y":159,"wires":[]},{"id":"5444cb83.c23f74","type":"inject","z":"b3674429.a21f68","name":"mqtt Toggle","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":173,"y":125,"wires":[["5eb00add.679944"]]},{"id":"b67239fb.725888","type":"ui_group","z":"b3674429.a21f68","name":"Default","tab":"7f9b3a32.177a94","disp":true,"width":"6"},{"id":"7f9b3a32.177a94","type":"ui_tab","z":"b3674429.a21f68","name":"Home","icon":"dashboard"}]

sebasti...@gmail.com

unread,
Aug 31, 2016, 1:06:14 PM8/31/16
to Node-RED
Why not using the "switch" element from the dashboard ? It exactly creates you values.

dave....@gmail.com

unread,
Aug 31, 2016, 2:16:43 PM8/31/16
to Node-RED

Sure but how do I get text On or Off etc into it ?  I can only see Material Design icons and Font Awesome icons junk stuff can i get css into it ? I want these button to match up with some others that switch iframes.

If its not possible please tell me 

Julian Knight

unread,
Aug 31, 2016, 4:08:09 PM8/31/16
to Node-RED
The switch node is a little simplistic right now but it is easy to create a template node to do what you want to while still staying within the Dashboard.

You might want to have a look at my flow example: http://flows.nodered.org/flow/2f1aaf0635f9bf23207152682323240a which may help get to grips with combining the msg data with Angular in the template node.

sebasti...@gmail.com

unread,
Aug 31, 2016, 6:58:50 PM8/31/16
to Node-RED
Hi Dave,
not so easy as we cannot supply an own CSS theme or modify the partial html templates from a given dashboard ui component (currently?)
you may do the following:
export the source from node-red-dashboard as you then have the individual components and not a minimized version.

First change to the installation directory of node-red-dashboard (e.g. /usr/lib/node_modules/node-red-dashboard )
You will need svn client in this example to get the src files.
We will then get the src files, install missing dependencies and correct user rights.
Then we disable the release folder "dist" and then restart node red to activate src folder content.

# cd /usr/lib/node_modules/node-red-dashboard
./node_modules/node-red-dashboard $ sudo svn export https://github.com/node-red/node-red-dashboard.git/tags/2.0.0/src
./node_modules/node-red-dashboard $ sudo npm install angular angular-sanitize angular-animate  angular-aria  angular-material angular-material-icons svg-morpheus font-awesome sprintf-js jquery jquery-ui raphael justgage d3 nvd3 angularjs-nvd3-directives
./node_modules/node-red-dashboard $ sudo chown -R nobody:pi src node_modules
./node_modules/node-red-dashboard $ sudo mv dist dist_


You will then need to restart node-red and see something like this

31 Aug 21:16:51 - [info] UI started at /ui
31 Aug 21:16:51 - [info] Using development folder


Which confirms, that the src folder is used. Try to reload the /ui - you may clear the caches though or reload several times because of the prior cache manifest.

You may then try to change the layout of the template for the switch: switch.html which you will in :/usr/lib/node_modules/node-red-dashboard/src/components/ui-component/templates

Maybe the following command will speed up the task to get to the development version of the dashboard, but it didnt work for my raspberrypi installation

npm install -g --dev node-red-dashboard

Unfortunately  I couldnt found information on the github page of the dashboard how to setup development environment.

Note: Be careful with the above steps as you are acting with sudo.

sebasti...@gmail.com

unread,
Aug 31, 2016, 7:06:37 PM8/31/16
to Node-RED
To clearify on the post, of course Julian's  way is the preferred one.
I chosed the way from my post to rework the complete style of the dashboard and to easier debug it.

dave....@gmail.com

unread,
Sep 1, 2016, 10:05:30 AM9/1/16
to Node-RED
This is the best I got given my limited time, 

 [{"id":"12feddde.ed0122","type":"ui_template","z":"b3674429.a21f68","group":"b67239fb.725888","name":"","order":0,"width":"2","height":"1","format":"\n\n\n<style>\n:focus {\noutline: 0;\n}\nmd-button1 {\n\t-moz-box-shadow:inset 0px 0px 15px 3px #23395e;\n\t-webkit-box-shadow:inset 0px 0px 15npx 3px #23395e;\n\tbox-shadow:inset 0px 0px 15px 3px #23395e;\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #2e466e), color-stop(1, #415989));\n\tbackground:-moz-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-webkit-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-o-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-ms-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:linear-gradient(to bottom, #2e466e 5%, #415989 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2e466e', endColorstr='#415989',GradientType=0);\n\tbackground-color:#2e466e;\n\t-moz-border-radius:17px;\n\t-webkit-border-radius:17px;\n\tborder-radius:17px;\n\tborder:1px solid #1f2f47;\n\tdisplay:inline-block;\n\tcursor:pointer;\n\tcolor:#ffffff;\n\tfont-family:Arial;\n\tfont-size:10px;\n\tpadding:10px 10px;\n\ttext-decoration:none;\n\ttext-shadow:0px 1px 0px #263666;\n}\nmd-button1:hover {\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #415989), color-stop(1, #2e466e));\n\tbackground:-moz-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-webkit-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-o-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-ms-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:linear-gradient(to bottom, #415989 5%, #2e466e 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#415989', endColorstr='#2e466e',GradientType=0);\n\tbackground-color:#415989;\n}\nmd-button1:active {\n\tposition:relative;\n\ttop:1px;\n}\n\n//    move to md-button code for text color\n//    ng-style=\"{color: msg.payload=='1' ?'green':'red'}\" \n\n</style>\n\n\n<md-button1\n    ng-style=\"{background: msg.payload=='1' ?'green':'transparrent'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? send({payload: '1'}) : send({payload: '0'})) \"\n>\nButton 1\n</md-button1>","storeOutMessages":true,"fwdInMessages":true,"x":364.5,"y":138,"wires":[["ba50cb23.eef3c8"]]},{"id":"ba50cb23.eef3c8","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":531.8888893127441,"y":137.11111450195312,"wires":[]},{"id":"721275dd.7263ac","type":"inject","z":"b3674429.a21f68","name":"","topic":"","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"x":148,"y":118,"wires":[["12feddde.ed0122"]]},{"id":"61659cfc.ec72f4","type":"inject","z":"b3674429.a21f68","name":"","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":149,"y":158,"wires":[["12feddde.ed0122"]]},{"id":"b67239fb.725888","type":"ui_group","z":"b3674429.a21f68","name":"Default","tab":"7f9b3a32.177a94","disp":true,"width":"6"},{"id":"7f9b3a32.177a94","type":"ui_tab","z":"b3674429.a21f68","name":"Home","icon":"dashboard"}]

Cannot crack changing text yet.

dave....@gmail.com

unread,
Sep 1, 2016, 11:48:52 AM9/1/16
to Node-RED
Now I cracked text BUT I cannot figure out how to have 2 actions on ng-click 

So I have for text....

<md-button1 
ng-click="toggle = !toggle">
    <span ng-show="toggle">Power off</span>
    <span ng-hide="toggle">Power on</span>
</md-button1

BUT I need to combine it with following so both action happen, totally stuck now any one has an idea ?

<md-button1
ng-click="msg.payload = (msg.payload=='0' ? send({payload: '1'}) : send({payload: '0'}))"
</md-button1

sebasti...@gmail.com

unread,
Sep 1, 2016, 12:02:48 PM9/1/16
to Node-RED
msg.payload = (msg.payload=='0' ? send({payload: '1'}) : send({payload: '0'}))
I thin assigning to msg.payload in combination with send may not work...

you may change it to 
 ng-click="msg.payload = (msg.payload=='0' ?1 : 0) "

as you pass-through the msg from input to output

Message has been deleted

dave....@gmail.com

unread,
Sep 1, 2016, 12:26:53 PM9/1/16
to Node-RED

ng-click="msg.payload = (msg.payload=='0' ?1 : 0) " does not work there is no output from the node when the button is pressed.

msg.payload = (msg.payload=='0' ? send({payload: '1'}) : send({payload: '0'}))   works fine see the post with import clipboard code above 

But the issue I have is how to use the toggle text code AND msg.payload code IN the ng-click code so that when the button is clicked or you send 1 or zero via the node input, text on button changes, and 1 or zero is recieved on node output


sebasti...@gmail.com

unread,
Sep 1, 2016, 2:09:35 PM9/1/16
to Node-RED

I do not know if I understand you correctly, maybe try this:

<md-button1

   
ng-style="{background: msg.payload=='1' ?'green':'transparrent'}"

   
ng-click="msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) "
   
>
{{msg.payload == '0' ? 'Off' : 'On'}}
</md-button1>

not  that elegant, but works full flow following

note, that you can uses "AngularJS" power ... https://docs.angularjs.org/api/ng/


[{"id":"63432ea1.cdf29","type":"ui_template","z":"ba6aa8e3.6fc508","group":"ecba562d.fd9138","name":"","order":0,"width":"2","height":"1","format":"\n\n\n<style>\n:focus {\noutline: 0;\n}\nmd-button1 {\n\t-moz-box-shadow:inset 0px 0px 15px 3px #23395e;\n\t-webkit-box-shadow:inset 0px 0px 15npx 3px #23395e;\n\tbox-shadow:inset 0px 0px 15px 3px #23395e;\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #2e466e), color-stop(1, #415989));\n\tbackground:-moz-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-webkit-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-o-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-ms-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:linear-gradient(to bottom, #2e466e 5%, #415989 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2e466e', endColorstr='#415989',GradientType=0);\n\tbackground-color:#2e466e;\n\t-moz-border-radius:17px;\n\t-webkit-border-radius:17px;\n\tborder-radius:17px;\n\tborder:1px solid #1f2f47;\n\tdisplay:inline-block;\n\tcursor:pointer;\n\tcolor:#ffffff;\n\tfont-family:Arial;\n\tfont-size:10px;\n\tpadding:10px 10px;\n\ttext-decoration:none;\n\ttext-shadow:0px 1px 0px #263666;\n}\nmd-button1:hover {\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #415989), color-stop(1, #2e466e));\n\tbackground:-moz-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-webkit-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-o-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-ms-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:linear-gradient(to bottom, #415989 5%, #2e466e 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#415989', endColorstr='#2e466e',GradientType=0);\n\tbackground-color:#415989;\n}\nmd-button1:active {\n\tposition:relative;\n\ttop:1px;\n}\n\n//    move to md-button code for text color\n//    ng-style=\"{color: msg.payload=='1' ?'green':'red'}\" \n\n</style>\n\n\n<md-button1\n    ng-style=\"{background: msg.payload=='1' ?'green':'transparrent'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n    \n>\n{{msg.payload == '0' ? 'Off' : 'On'}}\n</md-button1>","storeOutMessages":true,"fwdInMessages":true,"x":820,"y":340,"wires":[["15659e9f.d08b31"]]},{"id":"15659e9f.d08b31","type":"debug","z":"ba6aa8e3.6fc508","name":"","active":true,"console":"false","complete":"false","x":987.3888893127441,"y":339.1111145019531,"wires":[]},{"id":"4a642e39.f559e","type":"inject","z":"ba6aa8e3.6fc508","name":"","topic":"","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"x":603.5,"y":320,"wires":[["63432ea1.cdf29"]]},{"id":"86a38c3c.9795d","type":"inject","z":"ba6aa8e3.6fc508","name":"","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":604.5,"y":360,"wires":[["63432ea1.cdf29"]]},{"id":"ecba562d.fd9138","type":"ui_group","z":"ba6aa8e3.6fc508","name":"Default","tab":"20b7ae29.e21bf2","disp":true,"width":"6"},{"id":"20b7ae29.e21bf2","type":"ui_tab","z":"ba6aa8e3.6fc508","name":"Home","icon":"dashboard"}]

dave....@gmail.com

unread,
Sep 1, 2016, 2:53:04 PM9/1/16
to Node-RED
Clearly you understood it works perfectly,

S U P E R B  thank you very much.

 
Capture.JPG
Capture1.JPG

Julian Knight

unread,
Sep 1, 2016, 4:35:40 PM9/1/16
to Node-RED
A little late I'm afraid but I would recommend putting the "click" logic into a JavaScript function and including a <script> block in the template that contains the function definition. Then you can do whatever you want and it will be much easier to maintain. All you need to do is to "return true" or "return false" in the function as required.

Julian Knight

unread,
Sep 1, 2016, 5:50:44 PM9/1/16
to Node-RED
And here is some template code that is a bit more Materially designed and a bit more angularly ;-)

<md-button class="md-cornered"
        ng-class="msg.payload=='On' ? 'md-accent md-raised md-hue-2' : 'md-primary'"
        ng-click="msg.payload = (msg.payload=='On' ? 'Off' : 'On');send(msg);"
        title="Click to turn on/off"
    >
    {{(msg.topic.split('/'))[1]}} {{msg.payload}}
</md-button>

This time changing classes and using the base MD classes - though it looks like the MD theme has been changed for Node-Red and that the primary background colour for buttons is rather too light without making the text colour dark.
Also note the more complex expression in the button text where I've split out the second part of the topic which comes from my home automation system in the form "COMMAND/SWITCHnn".

Fun. I'm going to replace the switch nodes on my home automation dashboard with this because the switch nodes go absolutely bonkers when used on mobile devices and end up crashing Node-Red. Though it is possible that is just my flow logic and I need to rate limit the output. In any case, the switch nodes don't look that good and these buttons look much better.

sebasti...@gmail.com

unread,
Sep 1, 2016, 6:25:52 PM9/1/16
to Node-RED
Thx, Julian - will take that as well..
 

dave....@gmail.com

unread,
Sep 4, 2016, 2:07:22 PM9/4/16
to Node-RED
Here's my final toggle button, css is slightly optimized from the original.....hope someone finds it usefull

[{"id":"f233537f.8a2a9","type":"ui_template","z":"b3674429.a21f68","group":"b67239fb.725888","name":"Button","order":4,"width":"2","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-button45{\n    display: block;\n    background-color:#2e466e;\n\tmargin: 0px 0px -5px 0px; \n\twidth: 85px; \n\t//height: 34px;\n    line-height: 30px;\t\t\n    border: 2px solid #666666;\n    border-radius:30px;\n    -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;\n    border-radius: 30px;\n    box-shadow: 0px 15px 0px rgba(0,0,0,0.08) inset;\n    cursor:pointer;\n    color:#ffffff;\n    font-family:Arial;\n    font-size:10px;\n    text-align:center;\t\n}\nmd-button45:hover {\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #415989), color-stop(1, #2e466e));\n\tbackground:-moz-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-webkit-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-o-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-ms-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:linear-gradient(to bottom, #415989 5%, #2e466e 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#415989', endColorstr='#2e466e',GradientType=0);\n\tbackground-color:#415989;\n}\nmd-button45:active {\n\tposition:relative;\n\ttop:1px;\n}\n</style>\n\n<md-button45\n    ng-style=\"{background: msg.payload=='1' ?'green':'transparrent'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? 'Power Off' : 'Power On'}}\n</md-button45>","storeOutMessages":true,"fwdInMessages":true,"x":429.0000114440918,"y":260.00000762939453,"wires":[["6b2a6f8c.19913"]]},{"id":"6b2a6f8c.19913","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":574.888916015625,"y":260.6111297607422,"wires":[]},{"id":"8afbe01f.6251b","type":"inject","z":"b3674429.a21f68","name":"Off","topic":"power","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"x":255,"y":242.5,"wires":[["f233537f.8a2a9"]]},{"id":"d711d876.733838","type":"inject","z":"b3674429.a21f68","name":"On","topic":"power","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":256,"y":282.5,"wires":[["f233537f.8a2a9"]]},{"id":"b67239fb.725888","type":"ui_group","z":"b3674429.a21f68","name":"Default","tab":"7f9b3a32.177a94","disp":true,"width":"6"},{"id":"7f9b3a32.177a94","type":"ui_tab","z":"b3674429.a21f68","name":"Test","icon":"dashboard","order":4}]

Toshi Bass

unread,
Sep 7, 2016, 5:22:05 AM9/7/16
to Node-RED
Dave great button thanks for posting, I followed your example and with a bit of a mod created some button however, I too need some help:

I need a button that sends 1 when pressed and 0 when released, I was successful using mousedown / mouse up and it works fine on desktop

but the problem I have is on ipad instead of the button functioning when I touch the button it insists to select the text on the button 

I tried some css to prevent this:

.noselect {
  user-select: none;
}

But doesn't do the job any ideas anyone ?

Here's the code I came up with:

<!DOCTYPE html>

<style>
:focus {
outline: 0;
}
.noselect {
  user-select: none;
}
md-push{
margin: 10px 0px 0px 10px; 
    background-color:WhiteSmoke;
border-radius:70px;
-moz-border-radius:70px;
-webkit-border-radius:70px;
height:60px;
width: 60px;
text-indent:0px;
border:4px solid #666666;
display:inline-block;
    line-height: 60px;
font-family:Verdana;
font-size:13px;
font-weight:500;
text-decoration:none;
text-align:center;
color:Black
 }

md-push:active {
position:relative;
top:1px;
}
</style>


<p class="noselect" style="font-size:70%;text-align:center;margin: -2px;">mouseup / down</p>
<md-push class="noselect"
    ng-style="{background: msg.payload=='1' ?'lightgray':'transparrent'}"
    ng-mousedown="msg.payload = '1'; send(msg)"
    ng-mouseup = "msg.payload = '0'; send(msg)"
>
{{msg.payload == '0' ? 'Up' : 'Down'}}
</md-push>

Also made some LED's if anyone's interested (see attached).
snip.JPG

Giovanni Castania

unread,
Sep 8, 2016, 2:23:10 AM9/8/16
to Node-RED
Hi Toshi, would you mind to sahre the flow/code for those LEDs ? they looks nice and I'd like to use them in my UI :)

Dave C-J

unread,
Sep 8, 2016, 3:53:28 AM9/8/16
to node...@googlegroups.com
For simple indicators you can use the text widget and feed it html of the fa-icons...

eg Inline images 2Inline images 3

[{"id":"11795acc.11dc85","type":"ui_text","z":"3ee56046.c933c","group":"ca294884.9f6a68","order":5,"width":"1","height":"1","name":"on/off","label":"","format":"<font color={{msg.payload}}><i class=\"fa fa-lightbulb-o fa-2x\"></i></font>","layout":"row-center","x":810,"y":580,"wires":[]},{"id":"8f17522e.afaac","type":"ui_switch","z":"3ee56046.c933c","name":"","label":"switch","group":"ca294884.9f6a68","order":0,"width":0,"height":0,"passthru":true,"topic":"","style":"","onvalue":"red","onvalueType":"str","onicon":"","oncolor":"","offvalue":"grey","offvalueType":"str","officon":"","offcolor":"","x":640,"y":580,"wires":[["11795acc.11dc85"]]},{"id":"ca294884.9f6a68","type":"ui_group","z":"3ee56046.c933c","name":"Click","tab":"513b7ff4.3de5d","order":2,"disp":true,"width":"4"},{"id":"513b7ff4.3de5d","type":"ui_tab","z":"3ee56046.c933c","name":"Home","icon":"link","order":1}]


Dave C-J

unread,
Sep 8, 2016, 3:56:12 AM9/8/16
to node...@googlegroups.com
Or even simpler... :-)

[{"id":"11795acc.11dc85","type":"ui_text","z":"3ee56046.c933c","group":"ca294884.9f6a68","order":5,"width":"1","height":"1","name":"on/off","label":"","format":"<font color={{(msg.payload?\"red\":\"grey\")}}><i class=\"fa fa-lightbulb-o fa-2x\"></i></font>","layout":"row-center","x":810,"y":580,"wires":[]},{"id":"8f17522e.afaac","type":"ui_switch","z":"3ee56046.c933c","name":"","label":"switch","group":"ca294884.9f6a68","order":0,"width":0,"height":0,"passthru":true,"topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":640,"y":580,"wires":[["11795acc.11dc85"]]},{"id":"ca294884.9f6a68","type":"ui_group","z":"3ee56046.c933c","name":"Click","tab":"513b7ff4.3de5d","order":2,"disp":true,"width":"4"},{"id":"513b7ff4.3de5d","type":"ui_tab","z":"3ee56046.c933c","name":"Home","icon":"link","order":1}]

Giovanni Castania

unread,
Sep 8, 2016, 5:17:56 AM9/8/16
to Node-RED
Thanks Dave, this is what I'm already doing it, but this is only Icons and no TEXT :)
I see in the picture of Toshi he has as well small-text over the LED indicators, this is what I'd like to achieve

Toshi Bass

unread,
Sep 8, 2016, 6:09:28 AM9/8/16
to Node-RED
As requested (LED code x6 based on dave...@   toggle button code):   would be great if you could post a picture of your UI when you've completed it.


[{"id":"3adff02c.47d91","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 1 red","order":3,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led1{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid #666666;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(#FF6666, Red);\n    text-align:center;\t\n }\n\n</style>\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">Burn</p>\n<md-led1\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led1>","storeOutMessages":true,"fwdInMessages":true,"x":733.4444465637207,"y":350.1111068725586,"wires":[["74f66822.22eea8"]]},{"id":"15677202.85b9ae","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 2 green","order":4,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led2{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid #666666;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(#9AF589, #42B821);\n    text-align:center;\t\n }\n\n</style>\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">Relay</p>\n<md-led2\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led2>","storeOutMessages":true,"fwdInMessages":true,"x":730.4444580078125,"y":428.1111145019531,"wires":[["74e76dc8.8d97d4"]]},{"id":"35cbf7fe.86d5c8","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 3 white","order":5,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led3{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid #666666;//#243131;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(#f0f0f0, #ffffff);\n    text-align:center;\t\n }\n\n</style>\n\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">W Dog</p>\n<md-led3\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led3>","storeOutMessages":true,"fwdInMessages":true,"x":732.4444465637207,"y":516.1111068725586,"wires":[["5fdcf4e8.037b6c"]]},{"id":"f1b645b.e2bbfb8","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 4 blue","order":6,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led4{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid #666666;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(#91B4FF, #0051FF);\n    text-align:center;\t\n }\n\n</style>\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">Sensor</p>\n<md-led4\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led4>","storeOutMessages":false,"fwdInMessages":true,"x":730.4444465637207,"y":599.1111068725586,"wires":[["19036afe.331fc5"]]},{"id":"fa996161.8ec87","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 5 yellow","order":7,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led5{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid gray;//#243131;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(yellow,#FC9642);\n    text-align:center;\t\n }\n\n</style>\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">Data</p>\n<md-led5\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led5>","storeOutMessages":true,"fwdInMessages":true,"x":731.4444465637207,"y":680.1111068725586,"wires":[["6c4a27e.d3353d8"]]},{"id":"4cf8289d.a59ad8","type":"ui_template","z":"94b25a16.617b58","group":"4f0d363.e2908c8","name":"LED 6 orange","order":8,"width":"1","height":"1","format":"<!DOCTYPE html>\n\n<style>\n:focus {\noutline: 0;\n}\nmd-led6{\n    display: block;\n\tborder-radius:80px;\n\tborder:2px solid gray;//#243131;\n\twidth: 16px; \n\theight:16px;\n\tmargin: 5px 0px 0px 5px; \t\n\tbackground: -webkit-radial-gradient(orange, #FF6666);\n    text-align:center;\t\n }\n\n</style>\n<p style=\"font-size:50%;text-align:center;margin: -2px;\">PIR</p>\n<md-led6\n    ng-style=\"{background: msg.payload=='1' ?'transparrent':'#423f3f'}\"\n    ng-click=\"msg.payload = (msg.payload=='0' ? '1' : '0'); send(msg) \"\n>\n{{msg.payload == '0' ? '' : ''}}\n</md-led6>","storeOutMessages":true,"fwdInMessages":true,"x":742.4444465637207,"y":767.1111068725586,"wires":[["27e1b553.5969fa"]]},{"id":"4f0d363.e2908c8","type":"ui_group","z":"94b25a16.617b58","name":"Default","tab":"76a45181.acc3","disp":true,"width":"6"},{"id":"76a45181.acc3","type":"ui_tab","z":"94b25a16.617b58","name":"Test","icon":"dashboard","order":6}]

Dave C-J

unread,
Sep 8, 2016, 7:29:31 AM9/8/16
to node...@googlegroups.com
Giovanni - I'm not sure it's too hard to add
<br/><font size="-2">Hello World</font>
to the end of the html, to give you both ;-)

On 8 September 2016 at 10:17, Giovanni Castania <giovanni...@gmail.com> wrote:
Thanks Dave, this is what I'm already doing it, but this is only Icons and no TEXT :)
I see in the picture of Toshi he has as well small-text over the LED indicators, this is what I'd like to achieve

--
http://nodered.org
 
Join us on Slack to continue the conversation: http://nodered.org/slack
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+unsubscribe@googlegroups.com.
To post to this group, send email to node...@googlegroups.com.
Visit this group at https://groups.google.com/group/node-red.
For more options, visit https://groups.google.com/d/optout.



--
regards

Dave Conway-Jones

Toshi Bass

unread,
Sep 8, 2016, 8:15:28 AM9/8/16
to Node-RED

Dave Obviously most people are new to this dashboard thing so I would just like to clarify:

Is your suggestion and the previous post from Julan ("a bit more Materially designed and a bit more angularly") the right way /correct way / prefered way,

I mean is there some detrimental / downside / rule breaking / wrong with the toggle button / Led code?
snip.JPG

Dave C-J

unread,
Sep 8, 2016, 9:47:42 AM9/8/16
to node...@googlegroups.com
Hey we're all learning here ! it's totally down to your user preference.
nothing wrong with the led / button code... 
What we would like to do (and rarely achieve) is to cover as many of the most basic use cases as possible... so beginners are catered for, and everyone can do the simple/quick stuff, while leaving it open/flexible enough for more advanced users to extend / enhance / rip apart as they see fit.
We really like these discussions as they often provide really nice advanced examples, and also point out things that we may be missing lower down the ability curve.

The dashboard is built using Angular and in particular most of the Material design widgets, so if you wanted to make use of the functions/style already there then that is possible as Julian pointed out. And if you wanted a really simple get-go then you can use a single line of html as I suggest. Nothing wrong with the fancy buttons - just somewhat harder for some people to get their heads around if they want to change it slightly. 

Toshi Bass

unread,
Sep 8, 2016, 11:44:41 AM9/8/16
to Node-RED
OK good, just wanted to ensure I wasn't digging myself into a hole, 

I have another request for Julian :

In a previous post in this thread you mentioned  "I would recommend putting the "click" logic into a JavaScript function and including a <script> block in the template that contains the function definition." as I am pretty dim Is there any chance that you could give an example, I tried doing this but have not been very successful.

Thanks

Dave C-J

unread,
Sep 8, 2016, 3:56:09 PM9/8/16
to node...@googlegroups.com
No problem, it's your hole - you can dig as deep as you like :-)

Julian Knight

unread,
Sep 9, 2016, 4:49:19 AM9/9/16
to Node-RED
Hi Toshi,

All I meant (and sadly, I deleted my example not long before I saw this post!) was that instead of doing logic in the angular tag, you can just put the name of a JavaScript function there and it will be called at the appropriate time. Having the logic in the tag is OK but not only can it become confusing very quickly, you also have to redo it for every repeat of the tag whereas putting the logic into a function allows you to only write it once.

I can see from your last code that you've used multiple template nodes rather than 1 with all the buttons. This means that you have multiple places where you have to define the CSS and code. OK until you need to change something! So my comment really applies when you put everything into a single template.

Actually, I had another go and I realise that it isn't quite as simple as I made out! To replace the inline code with a function, you have to add the function to Angular's $scope. Normally, you would do this by adding it to the main controller but that is hidden in the case of Dashboard.

Normally with Angular, you would probably create a service function and include that in your base controller. Unfortunately, though I've tried a number of methods, I haven't managed to extend the base controller for the UI app. I think it is just my poor understanding of Angular and the UI code. It certainly should be possible and maybe would be something that could be looked at for future updates to Dashboard so that custom functions could easily be included.

Toshi Bass

unread,
Sep 9, 2016, 5:44:31 AM9/9/16
to Node-RED
Well that confirms what I am finding I search on google for examples, all of them use controllers etc but none of those appear to work, in other words I hit bedrock in the hole i was digging.

Is there some document regarding whats included in the UI code regarding Angular stuffs ?

In reality I am not so bothered about having multiple template nodes for buttons etc as its just 1 template node with just a change to the md-button"number" each time its used, I even thought I might try to make a node for that but its probably beyond my capability same with LED code a LED node with choice for number and colour

Anyway perhaps you can help with what seams a simple thing but still am stuck    in the code for the buttons and led's there's a line :

    ng-style="{background: msg.payload=='1' ?'orange':'red'}" // it changes background colour

if I replace this with:

    ng-style="{color: msg.payload=='1' ?'black':'white'}"       // it changes  text colour

but I want to do both how can I combine  ?



  

Dave C-J

unread,
Sep 9, 2016, 5:51:51 AM9/9/16
to node...@googlegroups.com
typing without testing... but something like

  ng-style="{color: (msg.payload=='1' ?'black':'white') ; background: (msg.payload=='1' ?'orange':'red' ) }" 

Toshi Bass

unread,
Sep 9, 2016, 7:17:26 AM9/9/16
to Node-RED
Nope I tried that previously, I am getting very frustrated with this angular stuffs I think I need to leave it alone for a while.

Julian Knight

unread,
Sep 9, 2016, 12:56:29 PM9/9/16
to Node-RED
Nearly right, the attribute is a JavaScript object so it shoudl be:

ng-style="{color: (msg.payload=='1' ?'black':'white'), background: (msg.payload=='1' ?'orange':'red' ) }"

e.g. a comma between the attributes not a semi-colon.

Dave C-J

unread,
Sep 9, 2016, 1:05:29 PM9/9/16
to node...@googlegroups.com

Thanks J


Julian Knight

unread,
Sep 9, 2016, 1:57:23 PM9/9/16
to Node-RED
Quite honestly, that's why I gave up on it too. Simple stuff is OK but then you fall off this almighty cliff into dark and twisted tunnels.

However, it is still early days for the Dashboard so hopefully between everyone's efforts it will continue to improve. It is already a really useful tool for many things.

Csongor Varga

unread,
Oct 27, 2017, 4:38:12 PM10/27/17
to Node-RED
Hi Guys,

If somebody is still listening... I tried to use the concept here to create a sort of a momentary button which would send a message when pressed and released. Also wanted to work on a mobile, so added the touchstart and touchend event. But it is not sending a message. I assume i put the code in the wrong place, but can't figure out how it should be. This code is in a ui_template node:

<p class="noselect" style="font-size:100%;text-align:left;margin: -2px;">Blinds Up</p>

<md-push class="noselect vibrate"
    id ="msg"
    ng-style="{background: msg.payload=='1' ?'lightgray':'transparrent'}"
    >
Stop
</md-push>

<script>
document.getElementById("msg").addEventListener("touchstart", mouseDown);
document.getElementById("msg").addEventListener("touchend", mouseUp);
document.getElementById("msg").addEventListener("mousedown", mouseDown);
document.getElementById("msg").addEventListener("mouseup", mouseUp);

 
function mouseDown() {
    document.getElementById("msg").innerHTML = "Start";
   $('.vibrate').on('touchstart', function() {
  navigator.vibrate(100); 
});
    msg.payload = '0'; send(msg);
}

function mouseUp() {
    document.getElementById("msg").innerHTML = "Stop";
    $('.vibrate').on('touchend', function() {
  navigator.vibrate(100); 
}); 
msg.payload = '0'; send(msg);
}

</script>


On Wednesday, August 31, 2016 at 5:27:40 PM UTC+2, dave....@gmail.com wrote:
Hi I have started to build a flow to produce a toggle button, I need to be able to update and feedback the state of this button from/to mqtt, blynk and the dashboard.

so an input into the button should toggle from 0 to 1 or 1 to 0, 
on the dashboard it should say Off or On  OR red or green or both, 
if the button is pressed on the dashboard it should toggle the button, 
and the output from the button should be On / Off OR 0 / 1 to feed back to mqtt etc

So as it stands the button functions as I want BUT I cannot figure out how to change the color of the button when the button state changes 0 or 1 OR change the text on the button when the button state changes 0 or 1 OR preferably both 

I have spent hours on this, now I am getting nowhere (or perhaps there's a better way) please help.

Thanks

[{"id":"5eb00add.679944","type":"ui_template","z":"b3674429.a21f68","group":"b67239fb.725888","name":"Toggle button","order":4,"width":"2","height":"1","format":"\n\n\n<style>\n:focus {\noutline: 0;\n}\nmyButton5 {\n\t-moz-box-shadow:inset 0px 0px 15px 3px #23395e;\n\t-webkit-box-shadow:inset 0px 0px 15px 3px #23395e;\n\tbox-shadow:inset 0px 0px 15px 3px #23395e;\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #2e466e), color-stop(1, #415989));\n\tbackground:-moz-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-webkit-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-o-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:-ms-linear-gradient(top, #2e466e 5%, #415989 100%);\n\tbackground:linear-gradient(to bottom, #2e466e 5%, #415989 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2e466e', endColorstr='#415989',GradientType=0);\n\tbackground-color:#2e466e;\n\t-moz-border-radius:17px;\n\t-webkit-border-radius:17px;\n\tborder-radius:17px;\n\tborder:1px solid #1f2f47;\n\tdisplay:inline-block;\n\tcursor:pointer;\n\tcolor:#ffffff;\n\tfont-family:Arial;\n\tfont-size:10px;\n\tpadding:10px 10px;\n\ttext-decoration:none;\n\ttext-shadow:0px 1px 0px #263666;\n}\nmyButton5:hover {\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #415989), color-stop(1, #2e466e));\n\tbackground:-moz-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-webkit-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-o-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:-ms-linear-gradient(top, #415989 5%, #2e466e 100%);\n\tbackground:linear-gradient(to bottom, #415989 5%, #2e466e 100%);\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#415989', endColorstr='#2e466e',GradientType=0);\n\tbackground-color:#415989;\n}\nmyButton5:active {\n\tposition:relative;\n\ttop:1px;\n}\n\n</style>\n<script>\n\nmyDiv5.innerHTML = (\"Off\");\n\n\n\n</script>\n\n<myButton5 ng-click=\"send({payload: 1})\"><div id=\"myDiv5\"></div></myButton5>\n\n","storeOutMessages":false,"fwdInMessages":true,"x":353,"y":125,"wires":[["4c6e85c4.01604c"]]},{"id":"ceb09fb0.52078","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":698,"y":99,"wires":[]},{"id":"4c6e85c4.01604c","type":"function","z":"b3674429.a21f68","name":"","func":"\ncontext.global.u_toggle = context.global.u_toggle || 0;\nmsg1={};\nmsg2={};\nif (context.global.u_toggle === 0){\n    node.status({fill:\"gray\",shape:\"ring\",text:\"On\"});\n    context.global.u_toggle = 1;    \n    msg1.payload = 1;\n    msg2.payload = \"On\";\n} else {\n    node.status({fill:\"gray\",shape:\"dot\",text:\"Off\"});    \n    context.global.u_toggle = 0;\n    msg1.payload = 0;\n    msg2.payload = \"Off\";\n}   \n    return [msg1,msg2];","outputs":"2","noerr":0,"x":512,"y":125,"wires":[["ceb09fb0.52078"],["906d4625.10a578"]]},{"id":"906d4625.10a578","type":"debug","z":"b3674429.a21f68","name":"","active":true,"console":"false","complete":"false","x":698,"y":159,"wires":[]},{"id":"5444cb83.c23f74","type":"inject","z":"b3674429.a21f68","name":"mqtt Toggle","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"x":173,"y":125,"wires":[["5eb00add.679944"]]},{"id":"b67239fb.725888","type":"ui_group","z":"b3674429.a21f68","name":"Default","tab":"7f9b3a32.177a94","disp":true,"width":"6"},{"id":"7f9b3a32.177a94","type":"ui_tab","z":"b3674429.a21f68","name":"Home","icon":"dashboard"}]
Reply all
Reply to author
Forward
0 new messages