Configuring a dashboard tab in response to a URL

Hi, I've spent some time looking and can't find a solution to this problem.
I send an email each day with a summary of multiple house sensors. On a node-red dashboard tab I have a chart that can display all daily temperatures, power usage, water usage and a few other data types. It can also show any particular day within its recorded history. Within this email I want to embed a URL that when clicked will load the chart tab with the data for a particular day and data type.
For example, the URL https://shannstainable.fewings.org/&type=power&date=13Dec19 would load the node-red dashboard with the Historic chart tab and display the power consumption for 13-Dec-19.

If you can do all this - what's causing the struggle on sticking a link into the email?

PS Like the Dog Food indicator :slight_smile:

The problem is not placing the link in the email.
The problem is receiving the URL and configuring the node-red to display the tab. It feels like it should be simple but I just can't find the solution.

I've been working on something that could help you,

Each tab of the dashboard differs from an id that depends on its position. This variable is not published in the dashboard node, so I had to publish it manually. I leave link: [Help with this] Node that lists the dashboard menu

But all this requires creating a node etc ...
basically: you can point to a dashboard url (with its id) and with the http in and out nodes
With this you can use a custom address and insert parameters.
the move is to insert the data of this node (with some variable type flow for example) and insert the address of the dashboard into an iframe within a template node (I say template, not ui-template, use the orange one)

It is a bit complicated, but this play is also serving me for multi-user panels

in short: as you see in the picture:
on line 1
you create an http url and an iframe that points to your board. the rest of the code I pass it to you

[{"id":"76a75be0.81c524","type":"ui_template","z":"dfd21047.842e8","group":"f3ffcc7c.93ed7","name":"","order":2,"width":"11","height":"6","format":"<!--div data-ng-init=\"send({payload:action()})\"></div-->\n\n<div > mi mensaje</div>   \n<div ng-bind-html=\"msg.Date\"></div>\n<div ng-bind-html=\"msg.payload\"></div>\n<div ng-bind-html=\"msg.parameter\"></div>\n<div class=\"mydiv\" ng-bind-html=\"msg.Url\" style=\"{{((msg.parameter || 0) == 123) ? 'background-color:green' : 'background-color:red'}}\"></div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":600,"y":540,"wires":[[]]},{"id":"6a631048.8c47f","type":"ui_template","z":"dfd21047.842e8","group":"f3ffcc7c.93ed7","name":"idpicker","order":1,"width":"0","height":"0","format":"\n\n<div id=\"idpickertable\" ng-init=\"send(action())\"><!-- it work at start-->\n\n</div>\n<script>\n\n    var url= parent.document.location.href\n    \n    \n    var obj = {\"Url\":url};\n\n    this.scope.action = function() { return obj; }\n</script>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":140,"y":540,"wires":[["9331803c.f6a49"]]},{"id":"9331803c.f6a49","type":"function","z":"dfd21047.842e8","name":"","func":"var url= msg.Url\n\nmsg.parameter=url.split(\"/\").slice(-1)\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":540,"wires":[["76a75be0.81c524"]]},{"id":"f3ffcc7c.93ed7","type":"ui_group","z":"","name":"Tablero Resumen Produccion","tab":"f190fbe5.75de68","order":1,"disp":false,"width":"38","collapse":false},{"id":"f190fbe5.75de68","type":"ui_tab","z":"","name":"test00","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

Thanks Nxito,
I understand what you are doing here.
Line 2 demonstrates how to get the URL for a given tab.
You say to "create an http url and an iframe that points to your board."
Could you please provide the basic nodes that do that. I am not very familiar with the entire http request=>response chain so can't quite see how you create an iFrame with the intended url that needs to be returned as a response.

I send you the http part with the iframe and a function in which you only have to add the position of the dashboard board (I recommend taking a look at the post I published on the dashboard menu variable)

[{"id":"2935e9a4.c5ba56","type":"http in","z":"dfd21047.842e8","name":"","url":"/mydashtest","method":"get","upload":false,"swaggerDoc":"","x":980,"y":740,"wires":[["39ef8038.2ee7"]]},{"id":"f7744679.470738","type":"http response","z":"dfd21047.842e8","name":"","statusCode":"","headers":{},"x":1370,"y":840,"wires":[]},{"id":"d52fbc17.07c9e","type":"template","z":"dfd21047.842e8","name":"Iframe","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<body>\n    <table><tr><th>\n    <iframe id=\"MyIFrame\"  align=\"left\" > Tu navegador no soporta iframes</iframe> </th>\n    </tr></table>\n</body>\n\n<style>\n    #MyIFrame {border: 0;  top:0px;  bottom:0px; width:100vw; height:100vh;   overflow:hidden; }\n    html{overflow:hidden;}  \n    body{margin:0px;}\n</style>\n\n<script>\n\nvar host=window.location.host\nvar dashboardDir=\"ui\"\nvar index={{payload}}\nvar tabName=window.location.href\nconsole.log(tabName)\n\nvar URL=\"http://\"+host+\"/\"+dashboardDir+\"/#!/\"+index;\nconsole.log(URL)\nvar URLtabName=\"http://\"+host+\"/\"+dashboardDir+\"/#!/\"+index;\nvar iframe = document.getElementById(\"MyIFrame\");\niframe.src = URL;\n\nconsole.log(iframe)\n\n\n</script>\n\n\n\n","output":"str","x":1170,"y":840,"wires":[["f7744679.470738"]]},{"id":"39ef8038.2ee7","type":"function","z":"dfd21047.842e8","name":"indexOf My Tab","func":"\nmsg.payload=2\nreturn msg;","outputs":1,"noerr":0,"x":1040,"y":800,"wires":[["d52fbc17.07c9e"]]}]

Thanks @Nxito,
You have solved my problem.

I have it slightly different from your flows. But it is now working well. I put the whole solution here for those who may want it.
image

  1. The top flow stores the URL that is called the first time the idpicker's Group tab is displayed. (It doesn't actualy display anything on the Group tab)
  2. The second line receives the URL request, parses the parameters and creates two messages.
    a) The first message responds with the stored URL inside an <iFrame>
    b) The second message contains the parameters from the URL request and can be passed to something else in your flow.

Here are the nodes

[{"id":"d708dc8e.a89f1","type":"http in","z":"89aed991.562928","name":"/history url handler","url":"/ui/history/:params","method":"get","upload":false,"swaggerDoc":"","x":190,"y":200,"wires":[["f42bc357.beb1b"]]},{"id":"3882eb1b.c1dd74","type":"debug","z":"89aed991.562928","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":610,"y":240,"wires":[]},{"id":"67706912.8ce228","type":"http response","z":"89aed991.562928","name":"","statusCode":"","headers":{},"x":770,"y":200,"wires":[]},{"id":"f42bc357.beb1b","type":"function","z":"89aed991.562928","name":"Set historic data","func":"//the url will arrive as http::local/history/&type=someType&date=someDate\nvar parameters = {};\nfor ( entry of msg.req.params.params.split(\"&\")) \n{\n  pair = entry.split(\"=\");\n  parameters[pair[0]] = pair[1];\n}\nvar type = parameters[\"type\"];\nvar date = parameters[\"date\"];\n\n\nmsg.url = flow.get(\"Node-red-Url\")|| \"no url\"\n//msg2 is for configuring your flow using the passed in parameteres from the URL\nmsg2 = {payload:\"From URL\", type:type, date:date };\n\nreturn [msg, msg2];","outputs":2,"noerr":0,"x":400,"y":200,"wires":[["19fcb2b9.83b4dd"],["3882eb1b.c1dd74"]]},{"id":"63ef29e2.05a538","type":"comment","z":"89aed991.562928","name":"Handle external URLs","info":"","x":200,"y":80,"wires":[]},{"id":"76dd4ee2.e4d0b","type":"ui_template","z":"89aed991.562928","group":"45a87283.4150ac","name":"idpicker","order":1,"width":"0","height":"0","format":"<div id=\"idpickertable\" ng-init=\"send(action())\"><!-- it is called at the start-->\n</div>\n<script>\n    var url= parent.document.location.href\n    var obj = {\"Url\":url};\n    this.scope.action = function() { return obj; }\n</script>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":160,"y":140,"wires":[["336f0644.28756a"]]},{"id":"336f0644.28756a","type":"function","z":"89aed991.562928","name":"Store full socketid url","func":"//Only store the first URL received. Future URLs could be external such as ./history/&type=type&date=date\n//store the full URL e.g http::local/#!/0?socketid=74hSZxlqHVZwQ1_iAAD9\nvar url= msg.Url\nif( url.includes(\"socketid\") ) \n    flow.set(\"Node-red-Url\",url);\nreturn msg","outputs":1,"noerr":0,"x":420,"y":140,"wires":[["2d1ef00f.ed848"]]},{"id":"19fcb2b9.83b4dd","type":"template","z":"89aed991.562928","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<http>\n<head>\n<style type=\"text/css\">\n    body {scrolling:no;}\n    iframe {position:absolute;\n    z-index:1;\n    top:0px;\n    left:0px;\n}\n</style>\n</head>\n<body>\n    <iframe src={{url}} height=\"100%\" width=\"100%\" frameborder=\"0\"></iframe>\n</body>    \n</http>","output":"str","x":620,"y":200,"wires":[["67706912.8ce228"]]},{"id":"2d1ef00f.ed848","type":"debug","z":"89aed991.562928","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":610,"y":140,"wires":[]},{"id":"45a87283.4150ac","type":"ui_group","z":"","name":"Testing","tab":"dadd1654.354a78","order":1,"disp":true,"width":"17","collapse":false},{"id":"dadd1654.354a78","type":"ui_tab","z":"","name":"Testing","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

Note that I changed the URL parameter format from my initial post example. You can now try https://shannstainable.fewings.org/historic/&type=power&date=20191219

2 Likes