[{"data":1,"prerenderedAt":664},["ShallowReactive",2],{"blog-\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user":3},{"id":4,"title":5,"body":6,"description":648,"extension":649,"meta":650,"navigation":659,"path":660,"seo":661,"stem":662,"__hash__":663},"blog\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user.md","Personalised Multi-user Dashboards with Node-RED Dashboard 2.0!",{"type":7,"value":8,"toc":639},"minimark",[9,19,22,27,30,35,38,43,51,60,70,74,79,84,97,103,106,110,113,121,125,132,236,239,245,251,273,290,296,302,319,323,327,333,339,345,371,433,446,450,453,465,472,475,502,545,554,560,565,584,588,595,599,602,626,635],[10,11,12,13,18],"p",{},"This week has seen the release of the ",[14,15,17],"a",{"href":16},"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-ga","first major version of Node-RED Dashboard 2.0",", with it, we've made available a new FlowFuse-exclusive feature, personalised multi-user dashboards.",[10,20,21],{},"This new feature will allow you to build applications that provide unique data to each user, build admin-only views, and track user activity, to name but a few. We're really excited to see what the Node-RED Community and our FlowFuse customers can do with such a powerful and flexible framework.",[23,24,26],"h2",{"id":25},"personalised-multi-user-dashboards","Personalised Multi User Dashboards",[10,28,29],{},"The original Node-RED Dashboard was built with a \"single source of truth\", no matter how many users interacted with the dashboard, each user would always see the same data. This is great for prototyping, or hobby projects, but as you scale up your Node-RED usage, you'll want to be able to have unique dashboard experiences for each user.",[31,32,34],"h3",{"id":33},"getting-started","Getting Started",[10,36,37],{},"To enable personalised multi-user dashboards, you'll need to be using FlowFuse, and complete two steps:",[39,40,42],"h4",{"id":41},"step-1-enable-flowfuse-user-authentication","Step 1: Enable \"FlowFuse User Authentication\"",[10,44,45,46,50],{},"All instances on FlowFuse can be configured with ",[47,48,49],"em",{},"\"FlowFuse User Authentication\""," in the \"Security\" Settings. This option requires any user that wants access to your Editor or dashboard to be authorized by FlowFuse first.",[10,52,53],{},[54,55],"img",{"alt":56,"dataZoomable":57,"src":58,"title":59},"\"Screenshot of the 'Security' settings available for any Instances running in FlowFuse\"","","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-ffauth.png","Screenshot of the 'Security' settings available for any Instances running in FlowFuse",[61,62,67],"figcaption",{"className":63},[64,65,66],"-mt-6","mb-4","text-center",[68,69,56],"b",{},[39,71,73],{"id":72},"step-2-install-flowfuses-user-addon","Step 2: Install FlowFuse's User Addon",[75,76,78],"h5",{"id":77},"flowfuse-cloud","FlowFuse Cloud",[10,80,81],{},[47,82,83],{},"Note: Every instance created from today onwards automatically comes with the necessary configuration. Already created instances need to be manually restarted.",[10,85,86,87,91,92,96],{},"The Personalised Multi-User Dashboard plugin, ",[88,89,90],"code",{},"@flowfuse\u002Fnode-red-dashboard-2-user-addon",", is available in our ",[14,93,95],{"href":94},"\u002Fcertified-nodes\u002F","Certified Nodes"," catalogue, accessible to our Teams and Enterprise customers.",[10,98,99,100,102],{},"Once the \"FlowFuse User Authentication\" option has been enabled on your instance, you can then install our plugin, ",[88,101,90],{},", through the \"Manage Palette\" option in the Node-RED Editor.",[10,104,105],{},"For your devices, we provide the necessary configuration and access token upon request, so that your Node-RED devices can also benefit from a Personalised Multi-user Dashboard.",[75,107,109],{"id":108},"flowfuse-self-hosted","FlowFuse Self-Hosted",[10,111,112],{},"For all our Teams and Enterprise Self-Hosted customers who also want to use the Certified Nodes and the Multi-User Dashboard, we provide all necessary configurations upon request to get started.",[10,114,115,116,120],{},"Alternatively, if you're looking to elevate your Node-RED infrastructure, ",[14,117,119],{"href":118},"\u002Fcontact-us","book in a chat with us"," to talk about how FlowFuse can help.",[31,122,124],{"id":123},"using-the-plugin","Using the Plugin",[10,126,127,128,131],{},"Once enabled, any messages emitted by a Dashboard 2.0 node will contain a new ",[88,129,130],{},"msg._client.user"," object, e.g:",[133,134,138],"pre",{"className":135,"code":136,"language":137,"meta":57,"style":57},"language-js shiki shiki-themes github-light github-dark","{\n    \"userId\": \"\",   \u002F\u002F unique identifier for the user\n    \"username\": \"\", \u002F\u002F FlowFuse Username\n    \"email\": \"\",    \u002F\u002F E-Mail Address connected to their FlowFuse account\n    \"name\": \"\",     \u002F\u002F Full Name\n    \"image\": \"\"     \u002F\u002F User Avatar from FlowFuse\n}\n","js",[88,139,140,149,169,185,201,217,230],{"__ignoreMap":57},[141,142,145],"span",{"class":143,"line":144},"line",1,[141,146,148],{"class":147},"sVt8B","{\n",[141,150,152,156,159,162,165],{"class":143,"line":151},2,[141,153,155],{"class":154},"sZZnC","    \"userId\"",[141,157,158],{"class":147},": ",[141,160,161],{"class":154},"\"\"",[141,163,164],{"class":147},",   ",[141,166,168],{"class":167},"sJ8bj","\u002F\u002F unique identifier for the user\n",[141,170,172,175,177,179,182],{"class":143,"line":171},3,[141,173,174],{"class":154},"    \"username\"",[141,176,158],{"class":147},[141,178,161],{"class":154},[141,180,181],{"class":147},", ",[141,183,184],{"class":167},"\u002F\u002F FlowFuse Username\n",[141,186,188,191,193,195,198],{"class":143,"line":187},4,[141,189,190],{"class":154},"    \"email\"",[141,192,158],{"class":147},[141,194,161],{"class":154},[141,196,197],{"class":147},",    ",[141,199,200],{"class":167},"\u002F\u002F E-Mail Address connected to their FlowFuse account\n",[141,202,204,207,209,211,214],{"class":143,"line":203},5,[141,205,206],{"class":154},"    \"name\"",[141,208,158],{"class":147},[141,210,161],{"class":154},[141,212,213],{"class":147},",     ",[141,215,216],{"class":167},"\u002F\u002F Full Name\n",[141,218,220,223,225,227],{"class":143,"line":219},6,[141,221,222],{"class":154},"    \"image\"",[141,224,158],{"class":147},[141,226,161],{"class":154},[141,228,229],{"class":167},"     \u002F\u002F User Avatar from FlowFuse\n",[141,231,233],{"class":143,"line":232},7,[141,234,235],{"class":147},"}\n",[10,237,238],{},"Then, when running Node-RED Dashboard 2.0 on FlowFuse, you'll have a new sidebar option in the Node-RED Editor, which allows you to control which node types allow for \"client constraints\".",[10,240,241],{},[54,242],{"alt":243,"dataZoomable":57,"src":244,"title":243},"The new 'FF Auth' options available in Node-RED to allow for client constraints","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-ff-settings.png",[61,246,248],{"className":247},[64,65,66],[68,249,250],{},"A screenshot of the new 'FF Auth' options available in Node-RED to allow for client constraints on different node types.",[10,252,253,254,257,258,261,262,265,266,269,270,272],{},"In the original Node-RED Dashboard, this was ",[47,255,256],{},"always"," enabled for the ",[88,259,260],{},"ui-notification"," and ",[88,263,264],{},"ui-control"," nodes, whereby you could include ",[88,267,268],{},"msg.socket"," data and it would only then send that message to the specified client. For Dashboard 2.0 we've extended this concept so that as a Node-RED Developer, you can now include ",[88,271,130],{}," data in any message sent to a Dashboard 2.0 node. Under the covers, our FlowFuse-exclusive plugin will then automatically filter messages to only send to the relevant user's connection.",[10,274,275,276,279,280,283,284,286,287,289],{},"Utilising this feature, below you can see an example where we send data to a ",[88,277,278],{},"ui-template"," to render a custom table for each user. Under the covers this is a ",[88,281,282],{},"ui-event"," node (triggered on a page view), which then uses the ",[88,285,130],{}," object to make a REST API call to retrieve a list of todo items for that specific user. We then wire the response into the ",[88,288,278],{},", which has been configured to \"Accept Client Constraints\", and so only sends this data to User 2's dashboard.",[10,291,292],{},[54,293],{"alt":294,"dataZoomable":57,"src":295,"title":294},"Showing Admin Task View","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-admin-tasks.png",[61,297,299],{"className":298},[64,65,66],[68,300,301],{},"Example of a dashboard that displays user-specific content.",[10,303,304,305,311,312,314,315,318],{},"Note too that we're also utilising the new ",[14,306,310],{"href":307,"rel":308},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#teleports",[309],"nofollow","Teleport"," option available in a ",[88,313,278],{}," which allows us to define content to show in the top-right of the dashboard, in this case, a little ",[47,316,317],{},"\"Hi {username}\""," message.",[31,320,322],{"id":321},"examples","Examples",[39,324,326],{"id":325},"rendering-logged-in-user-data","Rendering Logged In User Data",[10,328,329,330,332],{},"In the previous example, you may have noticed that we're also displaying a welcome to the authenticated user on our dashboard, this means that we have access to the full User object within any ",[88,331,278],{}," that we render too.",[10,334,335],{},[54,336],{"alt":337,"dataZoomable":57,"src":338,"title":337},"Showing User Unique Data","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-user2.png",[61,340,342],{"className":341},[64,65,66],[68,343,344],{},"The \"Admin\" view that is only made available to users registered as an \"admin\".",[10,346,347,348,351,352,355,356,359,360,363,364,367,368,370],{},"Under the covers, we're appending our ",[88,349,350],{},"user"," object to the ",[88,353,354],{},"msg"," object, via the SocketIO ",[88,357,358],{},"auth"," option. We make the ",[88,361,362],{},"socketio"," object available via a computed ",[88,365,366],{},"setup"," variable, this means that we can access this data in any ",[88,369,278],{}," node, and render like so:",[133,372,376],{"className":373,"code":374,"language":375,"meta":57,"style":57},"language-html shiki shiki-themes github-light github-dark","\u003Ctemplate>\n    \u003Cdiv>\n        \u003Ch1>Hi, {{ setup?.socketio?.auth?.user?.name }}!\u003C\u002Fh1>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","html",[88,377,378,390,400,415,424],{"__ignoreMap":57},[141,379,380,383,387],{"class":143,"line":144},[141,381,382],{"class":147},"\u003C",[141,384,386],{"class":385},"s9eBZ","template",[141,388,389],{"class":147},">\n",[141,391,392,395,398],{"class":143,"line":151},[141,393,394],{"class":147},"    \u003C",[141,396,397],{"class":385},"div",[141,399,389],{"class":147},[141,401,402,405,408,411,413],{"class":143,"line":171},[141,403,404],{"class":147},"        \u003C",[141,406,407],{"class":385},"h1",[141,409,410],{"class":147},">Hi, {{ setup?.socketio?.auth?.user?.name }}!\u003C\u002F",[141,412,407],{"class":385},[141,414,389],{"class":147},[141,416,417,420,422],{"class":143,"line":187},[141,418,419],{"class":147},"    \u003C\u002F",[141,421,397],{"class":385},[141,423,389],{"class":147},[141,425,426,429,431],{"class":143,"line":203},[141,427,428],{"class":147},"\u003C\u002F",[141,430,386],{"class":385},[141,432,389],{"class":147},[10,434,435,436,438,439,442,443,445],{},"To enable custom user-by-user content in a ",[88,437,278],{}," though, we must allow it to \"Accept Client Constraints\". This means that if a ",[88,440,441],{},".msg._client.user"," value is included in any messages sent to a ",[88,444,278],{}," node, then the underlying SocketIO message will be filtered to only send to the relevant user's connection, and no others.",[39,447,449],{"id":448},"admin-only-views","Admin Only Views",[10,451,452],{},"With this new functionality we can also now show\u002Fhide content based on the authenticated user.",[10,454,455,456,461,462,464],{},"We recently introduced the option to ",[14,457,460],{"href":458,"rel":459},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F484",[309],"set default visiblity & interaction states",". This was partly introduced because it's a good practice to set the default \"Visibility\" option for any admin-only pages to \"Hidden\", and then use a ",[88,463,264],{}," node to show the content only to the relevant admins.",[466,467],"iframe",{"width":468,"height":468,"src":469,"allow":470,"style":471},"100%","https:\u002F\u002Fflows.nodered.org\u002Fflow\u002F2fe8e6f1e7002f1ff6a9195ad1a153b6\u002Fshare","clipboard-read; clipboard-write","border: none; margin-bottom: 12px;",[10,473,474],{},"Let's breakdown the above flow:",[476,477,478,485,492],"ol",{},[479,480,481,482,484],"li",{},"We wire a ",[88,483,282],{}," node (which emits each time a user views a page) into a switch node",[479,486,487,488,491],{},"Our switch node checks the ",[88,489,490],{},"user.username"," against a known list of admin users and branches \"admin:\" and \"non-admin\" users",[479,493,494,495,498,499,501],{},"For admin users, the ",[88,496,497],{},"change"," node defines a message for our ",[88,500,264],{}," node to dynamically show content, in this case an \"Admin\" page, when appropriate.",[133,503,507],{"className":504,"code":505,"language":506,"meta":57,"style":57},"language-json shiki shiki-themes github-light github-dark","{\n    \"pages\":{\n        \"show\": [\"Admin View\"]\n    }\n}\n","json",[88,508,509,513,522,536,541],{"__ignoreMap":57},[141,510,511],{"class":143,"line":144},[141,512,148],{"class":147},[141,514,515,519],{"class":143,"line":151},[141,516,518],{"class":517},"sj4cs","    \"pages\"",[141,520,521],{"class":147},":{\n",[141,523,524,527,530,533],{"class":143,"line":171},[141,525,526],{"class":517},"        \"show\"",[141,528,529],{"class":147},": [",[141,531,532],{"class":154},"\"Admin View\"",[141,534,535],{"class":147},"]\n",[141,537,538],{"class":143,"line":187},[141,539,540],{"class":147},"    }\n",[141,542,543],{"class":143,"line":203},[141,544,235],{"class":147},[10,546,547,548,550,551,553],{},"All events going into ",[88,549,264],{}," are automatically filtered based on the ",[88,552,130],{}," object, so only the Admin users will receive the message to show the \"Admin View\" page, resulting in:",[10,555,556],{},[54,557],{"alt":558,"dataZoomable":57,"src":559,"title":558},"Showing Admin Only View","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-admin.png",[61,561,563],{"className":562},[64,65,66],[68,564,344],{},[10,566,567,568,570,571,574,575,577,578,583],{},"Further extensions of this could also check ",[88,569,282],{}," in case a non-admin user tries to access the ",[88,572,573],{},"\u002Fadmin"," page directly, in which case we can utilise ",[88,576,264],{}," to navigate the user away from the page immediately. See the ",[14,579,582],{"href":580,"rel":581},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-control.html#navigation",[309],"ui-control documentation"," for more details on this.",[23,585,587],{"id":586},"upcoming-webinar","Upcoming Webinar",[10,589,590,591],{},"If you're interested in learning more about Dashboard 2.0 and in particular multi-user Dashboards, we're hosting a webinar on Thursday, 29th February. You can find out more information ",[14,592,594],{"href":593},"\u002Fwebinars\u002F2024\u002Fnode-red-dashboard-multi-user\u002F","here",[23,596,598],{"id":597},"follow-our-progress","Follow our Progress",[10,600,601],{},"We aren't stopping here, we'll continue to push Dashboard 2.0 forward with future development, and you can track that progress on our GitHub Projects:",[603,604,605,612,619],"ul",{},[479,606,607],{},[14,608,611],{"href":609,"rel":610},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F1",[309],"Dashboard 2.0 Activity Tracker",[479,613,614],{},[14,615,618],{"href":616,"rel":617},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F4",[309],"Dashboard 2.0 Planning Board",[479,620,621],{},[14,622,625],{"href":623,"rel":624},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F5",[309],"Dashboard 1.0 Feature Parity Tracker",[10,627,628,629,634],{},"If you have any feature requests, bugs\u002Fcomplaints or general feedback, please do reach out, and raise issues on our relevant ",[14,630,633],{"href":631,"rel":632},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard",[309],"GitHub repository",".",[636,637,638],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":57,"searchDepth":151,"depth":151,"links":640},[641,646,647],{"id":25,"depth":151,"text":26,"children":642},[643,644,645],{"id":33,"depth":171,"text":34},{"id":123,"depth":171,"text":124},{"id":321,"depth":171,"text":322},{"id":586,"depth":151,"text":587},{"id":597,"depth":151,"text":598},"This week has seen the release of the first major version of Node-RED Dashboard 2.0, with it, we've made available a new FlowFuse-exclusive feature, personalised multi-user dashboards.","md",{"navTitle":5,"excerpt":651},{"type":7,"value":652},[653,657],[10,654,12,655,18],{},[14,656,17],{"href":16},[10,658,21],{},true,"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user",{"title":5,"description":648},"blog\u002F2024\u002F01\u002Fdashboard-2-multi-user","pXNdXNrZIFnpjUZ-IEzReKX7Hlc5s2VFz9Gtzykuh1g",1780070551325]