Collapsable dashboard suggestion

Collapsible groups are a great idea.
It can save a lot of screen real estate.

But the problem is if that group changes its data, unless it is expanded, you will never know.

Screenshot from 2019-12-26 07-02-59

It would be nice if there was a way to include some kind of indicator in the title bar to indicate change.
Granted that is in itself not easy, but I am saying it would simply be a bit of code so if any thing in the group receives an input the indicator is turned on.

Screenshot from 2019-12-26 07-02-59

That way if anyone gets to use the collapse feature, there is less chance they miss something they need to see because that group is collapsed.

1 Like

I my opinion the visual would be cleaner if you style the group icon toolbar to indicate changes (instead of adding text to the toolbar). Anyway, it is a matter of personal preference.

Such styling is straightforward with CSS. No need to consider a feature request.

The complexity lies in the logic of your flow. You would need to create a controller logic to keep state for each dashboard group and update the state every time some data changes in the group. This logic should be implemented in your flow, not in Node-RED core.

4 Likes

Silly me never thought of that.

Could you show me the code to do that?

I was thinking about the very same topic whilst designing my smart home's dashboard. I wanted to have it as lean as possible.

Bottom line my conclusion though is; if I need to monitor data right away I will not move it into a collapsible group at all. It remains always visible.

All other stuff is organized in collapsible groups and I simply don't care what is going on under their hood, until I open any one of them to get the current status of whatever is inside :slight_smile:

At the end I found the exercise to build a lean dashboard, due this particular aspect, quite healthy. I selected far less data items to be always visible. Cause really needed were just a very small number.

On the other hand I sometimes wished to be able to show at least one or two data items in the collapsible groups headline if this group is collapsed. If that is what @Trying_to_learn is referring to, I would support this Feature Request. But with low priority for the developer :smiley:

The toolbar icon can be styled by using a CSS rule like shown below.

<style>

#T1_G1 > div > p > span > i { 
    color: {{payload.g1}};
}

#T1_G2 > div > p > span > i { 
    color: {{payload.g2}};
}

</style>

Testing flow below. You need to click the inject node in the second flow to have to icons updated in the dashboard.

[{"id":"9599022b.cc44f","type":"tab","label":"Change icon in the group toolbar","disabled":false,"info":""},{"id":"288b7dfd.f69d42","type":"ui_text","z":"9599022b.cc44f","group":"65f72cab.018aa4","order":3,"width":0,"height":0,"name":"","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":390,"y":280,"wires":[]},{"id":"87a6c95b.accd78","type":"ui_text","z":"9599022b.cc44f","group":"7e69523c.27a13c","order":2,"width":0,"height":0,"name":"","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":390,"y":320,"wires":[]},{"id":"6f42c733.890768","type":"inject","z":"9599022b.cc44f","name":"red,yellow","topic":"","payload":"{\"g1\":\"red\",\"g2\":\"yellow\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":140,"wires":[["2cef9923.63c8f6"]]},{"id":"39096eaf.bf6102","type":"inject","z":"9599022b.cc44f","name":"red,normal","topic":"","payload":"{\"g1\":\"red\",\"g2\":\"#0eb8c0\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":180,"wires":[["2cef9923.63c8f6"]]},{"id":"c93617ff.9dfb58","type":"inject","z":"9599022b.cc44f","name":"normal,normal","topic":"","payload":"{\"g1\":\"#0eb8c0\",\"g2\":\"#0eb8c0\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":220,"wires":[["2cef9923.63c8f6"]]},{"id":"2cef9923.63c8f6","type":"change","z":"9599022b.cc44f","name":"set g1, g2","rules":[{"t":"set","p":"g1","pt":"global","to":"payload.g1","tot":"msg"},{"t":"set","p":"g2","pt":"global","to":"payload.g2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":180,"wires":[[]]},{"id":"d95cea8f.f1f9e8","type":"inject","z":"9599022b.cc44f","name":"","topic":"","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":590,"y":180,"wires":[["a207b109.a0e2f"]]},{"id":"2e281d45.c02fb2","type":"comment","z":"9599022b.cc44f","name":"Update toolbar status","info":"","x":620,"y":140,"wires":[]},{"id":"75c47038.b3cb3","type":"comment","z":"9599022b.cc44f","name":"Change toolbar status","info":"","x":220,"y":100,"wires":[]},{"id":"eb471cee.8b887","type":"ui_template","z":"9599022b.cc44f","group":"65f72cab.018aa4","name":"","order":1,"width":0,"height":0,"format":"<style>\n  \n:root {\n    --changeG1: {{msg.payload.g1}};\n    --changeG2: {{msg.payload.g2}};\n    }\n\n    \n    \n#T1_G1 > div > p > span > i { \n     color: var(--changeG1, #0eb8c0);\n}\n\n#T1_G2 > div > p > span > i { \n     color: var(--changeG2, #0eb8c0);\n}\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":1040,"y":180,"wires":[[]]},{"id":"cde1cbd3.2397b8","type":"template","z":"9599022b.cc44f","name":"","field":"template","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<style>\n\n#T1_G1 > div > p > span > i { \n    color: {{payload.g1}};\n}\n\n#T1_G2 > div > p > span > i { \n    color: {{payload.g2}};\n}\n\n</style>","output":"str","x":900,"y":180,"wires":[["eb471cee.8b887"]]},{"id":"a207b109.a0e2f","type":"change","z":"9599022b.cc44f","name":"Read g1, g2","rules":[{"t":"set","p":"payload.g1","pt":"msg","to":"g1","tot":"global"},{"t":"set","p":"payload.g2","pt":"msg","to":"g2","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":180,"wires":[["cde1cbd3.2397b8"]]},{"id":"65f72cab.018aa4","type":"ui_group","z":"","name":"G1","tab":"64fcccff.6082a4","disp":true,"width":"6","collapse":true},{"id":"7e69523c.27a13c","type":"ui_group","z":"","name":"G2","tab":"64fcccff.6082a4","disp":true,"width":"6","collapse":true},{"id":"64fcccff.6082a4","type":"ui_tab","z":"","name":"T1","icon":"dashboard","disabled":false,"hidden":false}]
2 Likes

Wow! Nice!

I'll now stick my hand up and show how dumb I am.

In the code to change the colour of the icon:
I know there are a few ways of writing code and where/how to use the { }
Some like me do it this way:

if (j == 2)
{
    // code here.
}

and others do it like this:

if (j ==2) {
    //code here
}

And neither is right or wrong.

But in my (way under-rated) knowledge of coding, (well bash scripting comes to mind) lines starting with # are also comments. Or something like that.

Obviously this is not the case.

I'll sit down and study the mechanics of how to get it so it has better/more features and is easy for people to use.

(No offence. You were simply showing me how to do it.)

I'll take it to the next level.

This is effort #1 for a working model.

Version 2 is coming shortly.

[{"id":"80c5b44d.414928","type":"ui_text","z":"b819c6ab.29703","group":"2eb0377b.3d7","order":3,"width":0,"height":0,"name":"","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":770,"y":520,"wires":[]},{"id":"3c171ee.98dcb62","type":"ui_text","z":"b819c6ab.29703","group":"bdaf5ce1.b20ab","order":2,"width":0,"height":0,"name":"","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":1070,"y":520,"wires":[]},{"id":"6023a5cc.5081fc","type":"inject","z":"b819c6ab.29703","name":"","topic":"","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":790,"y":430,"wires":[["b82471d8.b29b88"]]},{"id":"6831920b.1f4dac","type":"comment","z":"b819c6ab.29703","name":"Update toolbar status","info":"","x":910,"y":380,"wires":[]},{"id":"8287f3c1.d60a3","type":"ui_template","z":"b819c6ab.29703","group":"2eb0377b.3d7","name":"","order":1,"width":0,"height":0,"format":"<style>\n  \n:root {\n    --changeG1: {{msg.payload.g1}};\n    --changeG2: {{msg.payload.g2}};\n    }\n\n    \n    \n#T1_G1 > div > p > span > i { \n     color: var(--changeG1, #0eb8c0);\n}\n\n#T1_G2 > div > p > span > i { \n     color: var(--changeG2, #0eb8c0);\n}\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":1240,"y":430,"wires":[[]]},{"id":"d90554d4.4f38f8","type":"template","z":"b819c6ab.29703","name":"","field":"template","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<style>\n\n#T1_G1 > div > p > span > i { \n    color: {{payload.g1}};\n}\n\n#T1_G2 > div > p > span > i { \n    color: {{payload.g2}};\n}\n\n</style>","output":"str","x":1100,"y":430,"wires":[["8287f3c1.d60a3"]]},{"id":"b82471d8.b29b88","type":"change","z":"b819c6ab.29703","name":"Read g1, g2","rules":[{"t":"set","p":"payload.g1","pt":"msg","to":"g1","tot":"flow"},{"t":"set","p":"payload.g2","pt":"msg","to":"g2","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":930,"y":430,"wires":[["d90554d4.4f38f8"]]},{"id":"f65c67d0.5b60e","type":"ui_button","z":"b819c6ab.29703","name":"G1 ACK","group":"2eb0377b.3d7","order":2,"width":"1","height":"1","passthru":false,"label":"Ack","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g1\":\"lime\"}","payloadType":"json","topic":"","x":770,"y":570,"wires":[["d0012a0d.ee8a8"]]},{"id":"d0012a0d.ee8a8","type":"change","z":"b819c6ab.29703","name":"set g1","rules":[{"t":"set","p":"g1","pt":"flow","to":"payload.g1","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":920,"y":570,"wires":[["49cba629.4a51d8"]]},{"id":"c60f6e02.2cf5a8","type":"link in","z":"b819c6ab.29703","name":"","links":["7a41babc.3d28fc","49cba629.4a51d8","77b05f0d.3d7428","9f08453c.180ab8","1cffb0ed.189267"],"x":825,"y":470,"wires":[["b82471d8.b29b88"]]},{"id":"49cba629.4a51d8","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":1025,"y":570,"wires":[]},{"id":"93de8d31.6ec4d","type":"ui_button","z":"b819c6ab.29703","name":"Event","group":"ab7f7c2f.3ced98","order":2,"width":"3","height":"1","passthru":false,"label":"G1 event","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g1\":\"red\"}","payloadType":"json","topic":"","x":210,"y":450,"wires":[["66f10f2b.80a388"]]},{"id":"66f10f2b.80a388","type":"change","z":"b819c6ab.29703","name":"set g1","rules":[{"t":"set","p":"g1","pt":"flow","to":"payload.g1","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":450,"wires":[["77b05f0d.3d7428"]]},{"id":"77b05f0d.3d7428","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":595,"y":450,"wires":[]},{"id":"cc80552e.10b8b8","type":"ui_button","z":"b819c6ab.29703","name":"Event","group":"ab7f7c2f.3ced98","order":2,"width":"3","height":"1","passthru":false,"label":"G2 event","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g2\":\"red\"}","payloadType":"json","topic":"","x":210,"y":490,"wires":[["1de8bd1.d3acbc3"]]},{"id":"1de8bd1.d3acbc3","type":"change","z":"b819c6ab.29703","name":"set g2","rules":[{"t":"set","p":"g2","pt":"flow","to":"payload.g2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":490,"wires":[["9f08453c.180ab8"]]},{"id":"9f08453c.180ab8","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":595,"y":490,"wires":[]},{"id":"13e6d9ce.4e2566","type":"ui_button","z":"b819c6ab.29703","name":"G2 ACK","group":"bdaf5ce1.b20ab","order":1,"width":"1","height":"1","passthru":false,"label":"Ack","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g2\":\"lime\"}","payloadType":"json","topic":"","x":770,"y":620,"wires":[["918a16d.5c1a3e8"]]},{"id":"918a16d.5c1a3e8","type":"change","z":"b819c6ab.29703","name":"set g1","rules":[{"t":"set","p":"g2","pt":"flow","to":"payload.g2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":920,"y":620,"wires":[["1cffb0ed.189267"]]},{"id":"1cffb0ed.189267","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":1025,"y":620,"wires":[]},{"id":"97388207.3c1bf","type":"comment","z":"b819c6ab.29703","name":"Buttons","info":"These are here only to allow you to see what\nhappens all from the \"GUI\" side of things.\n\nReally this part of the flow would be (probably)\na `switch` node which allows only certain\nconditions to pass then it sets the `G1` (or G2)\nvariables.\n","x":200,"y":400,"wires":[]},{"id":"28611143.994e36","type":"comment","z":"b819c6ab.29703","name":"LINKS","info":"With what ever invoked the situation, a signal\nis then sent on to update the GUI side of things\n","x":650,"y":380,"wires":[]},{"id":"f4805709.710ca","type":"comment","z":"b819c6ab.29703","name":"These buttons","info":"They are *hidden* in the collapsed fields and\nshown when opened/expanded.\nPressing the button clears the notification.","x":860,"y":660,"wires":[]},{"id":"2eb0377b.3d7","type":"ui_group","z":"","name":"G1","tab":"50e22e57.59eea8","order":2,"disp":true,"width":"6","collapse":true},{"id":"bdaf5ce1.b20ab","type":"ui_group","z":"","name":"G2","tab":"50e22e57.59eea8","order":3,"disp":true,"width":"6","collapse":true},{"id":"ab7f7c2f.3ced98","type":"ui_group","z":"","name":"Invoke","tab":"50e22e57.59eea8","order":1,"disp":true,"width":"6","collapse":false},{"id":"50e22e57.59eea8","type":"ui_tab","z":"","name":"T1","icon":"dashboard","disabled":false,"hidden":false}]

This is #2:

I have simplified it only in that rather than using flow variables, it is all kept in the flow.

This may be better if you want to have a lot of collapsed areas and use of flow variable names.

[{"id":"80c5b44d.414928","type":"ui_text","z":"b819c6ab.29703","group":"2eb0377b.3d7","order":3,"width":0,"height":0,"name":"G1 text","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":420,"y":540,"wires":[]},{"id":"3c171ee.98dcb62","type":"ui_text","z":"b819c6ab.29703","group":"bdaf5ce1.b20ab","order":2,"width":0,"height":0,"name":"G2 text","label":"text","format":"{{msg.payload}}","layout":"row-spread","x":420,"y":580,"wires":[]},{"id":"6831920b.1f4dac","type":"comment","z":"b819c6ab.29703","name":"Update toolbar status","info":"","x":550,"y":360,"wires":[]},{"id":"8287f3c1.d60a3","type":"ui_template","z":"b819c6ab.29703","group":"2eb0377b.3d7","name":"","order":1,"width":0,"height":0,"format":"<style>\n  \n:root {\n    --changeG1: {{msg.payload.g1}};\n    --changeG2: {{msg.payload.g2}};\n    }\n\n    \n    \n#T1_G1 > div > p > span > i { \n     color: var(--changeG1, #0eb8c0);\n}\n\n#T1_G2 > div > p > span > i { \n     color: var(--changeG2, #0eb8c0);\n}\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":810,"y":470,"wires":[[]]},{"id":"d90554d4.4f38f8","type":"template","z":"b819c6ab.29703","name":"","field":"template","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<style>\n\n#T1_G1 > div > p > span > i { \n    color: {{payload.g1}};\n}\n\n#T1_G2 > div > p > span > i { \n    color: {{payload.g2}};\n}\n\n</style>","output":"str","x":670,"y":470,"wires":[["8287f3c1.d60a3"]]},{"id":"f65c67d0.5b60e","type":"ui_button","z":"b819c6ab.29703","name":"G1 ACK","group":"2eb0377b.3d7","order":2,"width":"1","height":"1","passthru":false,"label":"Ack","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g1\":\"lime\"}","payloadType":"json","topic":"","x":310,"y":630,"wires":[["49cba629.4a51d8"]]},{"id":"c60f6e02.2cf5a8","type":"link in","z":"b819c6ab.29703","name":"","links":["7a41babc.3d28fc","49cba629.4a51d8","77b05f0d.3d7428","9f08453c.180ab8","1cffb0ed.189267","fdd32640.ceb718"],"x":545,"y":470,"wires":[["d90554d4.4f38f8"]]},{"id":"49cba629.4a51d8","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":455,"y":630,"wires":[]},{"id":"93de8d31.6ec4d","type":"ui_button","z":"b819c6ab.29703","name":"Event","group":"ab7f7c2f.3ced98","order":2,"width":"3","height":"1","passthru":false,"label":"G1 event","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g1\":\"red\"}","payloadType":"json","topic":"","x":210,"y":450,"wires":[["fdd32640.ceb718"]]},{"id":"cc80552e.10b8b8","type":"ui_button","z":"b819c6ab.29703","name":"Event","group":"ab7f7c2f.3ced98","order":2,"width":"3","height":"1","passthru":false,"label":"G2 event","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g2\":\"red\"}","payloadType":"json","topic":"","x":210,"y":490,"wires":[["fdd32640.ceb718"]]},{"id":"13e6d9ce.4e2566","type":"ui_button","z":"b819c6ab.29703","name":"G2 ACK","group":"bdaf5ce1.b20ab","order":1,"width":"1","height":"1","passthru":false,"label":"Ack","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"g2\":\"lime\"}","payloadType":"json","topic":"","x":310,"y":680,"wires":[["1cffb0ed.189267"]]},{"id":"1cffb0ed.189267","type":"link out","z":"b819c6ab.29703","name":"","links":["c60f6e02.2cf5a8"],"x":455,"y":680,"wires":[]},{"id":"97388207.3c1bf","type":"comment","z":"b819c6ab.29703","name":"Buttons","info":"These are here only to allow you to see what\nhappens all from the \"GUI\" side of things.\n\nReally this part of the flow would be (probably)\na `switch` node which allows only certain\nconditions to pass then it sets the `G1` (or G2)\nvariables.\n","x":200,"y":400,"wires":[]},{"id":"28611143.994e36","type":"comment","z":"b819c6ab.29703","name":"LINKS","info":"With what ever invoked the situation, a signal\nis then sent on to update the GUI side of things\n","x":420,"y":440,"wires":[]},{"id":"f4805709.710ca","type":"comment","z":"b819c6ab.29703","name":"These buttons","info":"They are *hidden* in the collapsed fields and\nshown when opened/expanded.\nPressing the button clears the notification.","x":400,"y":720,"wires":[]},{"id":"fdd32640.ceb718","type":"link out","z":"b819c6ab.29703","name":"","links":["d59a89a0.dd1288","c60f6e02.2cf5a8"],"x":355,"y":470,"wires":[]},{"id":"2eb0377b.3d7","type":"ui_group","z":"","name":"G1","tab":"50e22e57.59eea8","order":2,"disp":true,"width":"6","collapse":true},{"id":"bdaf5ce1.b20ab","type":"ui_group","z":"","name":"G2","tab":"50e22e57.59eea8","order":3,"disp":true,"width":"6","collapse":true},{"id":"ab7f7c2f.3ced98","type":"ui_group","z":"","name":"Invoke","tab":"50e22e57.59eea8","order":1,"disp":true,"width":"6","collapse":false},{"id":"50e22e57.59eea8","type":"ui_tab","z":"","name":"T1","icon":"dashboard","disabled":false,"hidden":false}]

Hey guys,
I think it would be useful, if you could get this integrated into the dashoad somehow. By default of course no collapsing, but at least make it available for those who want to use it (e.g. on small screens). Nice work!!
Bart

You did the magic Bart.

The "indicator" may need to be a bit bigger though. (Twice as big?)

Unfortunately I'm a CSS noob, so I have to count on on others to provide magic for this kind of stuff...

Hey Bart, not sure how you mean... ? The groups are not visible nodes so you can't wire an event to them to trigger this in a simple fashion. Doing it this way via CSS is probably the easiest (and most flexible) method.

Ah. I have at the moment no pc, but I really thought that a group node also had a config screen. Then forget my interruption as soon as possible...

The first is a very C-like way of doing it. Personally I hate it because it is visually distracting and occupies valuable screen real estate for no good reason :slight_smile: Just my personal opinion of course.

My preference for that code would be:

if ( j === 2 ) {
    //code here
}

Note the extra spaces and the === instead of == which is stricter so catches odd errors with variable contents (like j containing the string "2" instead of the number 2).

The main advantage I see of having vertically aligned curly brackets is to be able to quickly match them up by eye, to ensure nested logic is consistent and avoid the time wasted looking for the odd missing one. Probably a point more relevant for less experienced programmers, but nevertheless relevant when debugging others code.

A point certainly. Though I think that most if not all code editors including the ACE editor in Node-RED will spot those errors for you anyway.

I still think that the loss of screen real-estate and visual distraction are the larger issues for all but the most trivial of code.

Doubtless also I am influenced by the languages I learned first - FORTRAN, COBOL, BASIC, APL, Assembler, FORTH, LISP, PL/1, PYTHON. You will notice that I didn't really do any PASCAL which I believe to be the basis of the grammars that use curly braces and semi-colons (C/C++/C#, PERL, PHP, JavaScript, etc). LISP being the slight oddity in my list, lots of curly braces there! I've included PYTHON in that list but that's a bit of a cheat since I actually learned PERL and PHP before PYTHON.

I still find it weird when I look at the list of languages I've used since I don't even class myself as a programmer!