[{"data":1,"prerenderedAt":734},["ShallowReactive",2],{"blog-\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard":3},{"id":4,"title":5,"body":6,"description":12,"extension":724,"meta":725,"navigation":369,"path":730,"seo":731,"stem":732,"__hash__":733},"blog\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard.md","Displaying logged in user on Node-RED Dashboard 2.0",{"type":7,"value":8,"toc":713},"minimark",[9,13,21,26,29,42,45,54,58,61,66,87,91,102,111,136,139,145,148,153,156,159,165,172,176,186,195,210,649,653,665,672,676,679,703,707,710],[10,11,12],"p",{},"About a month ago, a powerful solution became available to the Node-RED community to deal with users and allow multiple to interact with the same dashboard in a personalized manner. It's called the  Multli user Dashboard for Node-RED. In this guide, we will provide a step-by-step guide to show you how to secure your dashboard and access and display logged in user information on Dashboard 2.0.",[10,14,15,16],{},"If you're new to Dashboard 2.0, refer to our blog post ",[17,18,20],"a",{"href":19},"\u002Fblog\u002F2024\u002F03\u002Fdashboard-getting-started\u002F","Getting Started with Dashboard 2.0",[22,23,25],"h2",{"id":24},"enabling-flowfuse-user-authentication","Enabling FlowFuse User Authentication",[10,27,28],{},"Before we display logged-in user data on the dashboard, first we need to set up a login mechanism with FlowFuse for the dashboard. This simplifies securing Node-RED Dashboards and provides contextual user data within the Dashboard itself for who is logged in.",[30,31,32,36,39],"ol",{},[33,34,35],"li",{},"Navigate to the Instance \"settings\".",[33,37,38],{},"Select the \"Security\" tab.",[33,40,41],{},"Enable “FlowFuse User Authentication”",[10,43,44],{},"Now, the first time you visit the dashboard, you'll need to log in with your registered FlowFuse username and password",[10,46,47],{},[48,49],"img",{"alt":50,"dataZoomable":51,"src":52,"title":53},"\"Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.\"","","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fdisplaying-logged-in-user-flowfuse-instance-setting.png","Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.",[22,55,57],{"id":56},"exploring-the-flowfuse-user-addon","Exploring the FlowFuse User Addon",[10,59,60],{},"The FlowFuse User Addon is a plugin developed for Dashboard 2.0, leveraging the FlowFuse API to retrieve information about logged in user.",[62,63,65],"h3",{"id":64},"installing-flowfuse-user-addon","Installing Flowfuse user addon",[30,67,68,71,74,77,84],{},[33,69,70],{},"Click the Node-RED Settings (top-right)",[33,72,73],{},"Click \"Manage Palette\"",[33,75,76],{},"Switch to the \"Install\" tab",[33,78,79,80],{},"Search for ",[81,82,83],"code",{},"@flowfuse\u002Fnode-red-dashboard-2-user-addon",[33,85,86],{},"Click \"Install\"",[62,88,90],{"id":89},"how-it-works","How it Works",[10,92,93,94,97,98,101],{},"In this addon, user information is attached to the ",[81,95,96],{},"msg"," emitted by Dashboard 2.0 nodes. This user information object is attached as ",[81,99,100],{},"msg._client.user",". Below is an example of how that object looks:",[103,104,109],"pre",{"className":105,"code":107,"language":108},[106],"language-text","{\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","text",[81,110,107],{"__ignoreMap":51},[10,112,113,114,116,117,123,124,127,128,131,132,135],{},"Behind the scenes, the user addon is appending the user object to the ",[81,115,96],{},", via the SocketIO auth option. We make the socketio object available via a computed ",[17,118,122],{"href":119,"rel":120},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fguides\u002Fstate-management.html#setup-store",[121],"nofollow","setup"," object, this means that we can also access user data in any ui-template widget with ",[81,125,126],{},"{{ setup.socketio.auth.user }}",", in the ",[81,129,130],{},"\u003Ctemplate>",", or ",[81,133,134],{},"this.setup.socketio.auth.user",", in the JS.",[10,137,138],{},"When running Node-RED Dashboard 2.0 on FlowFuse, you'll have a new tab available in the \"Dashboard 2.0\" sidebar in the Node-RED Editor, you just have to navigate to the \"FF Auth\" tab and you’ll see two options.",[10,140,141],{},[142,143,144],"strong",{},"Option 1: Include Client Data",[10,146,147],{},"By default, this option is enabled. When this option is enabled, an object with user information will be added to the “msg” emitted by any widget of the Node-RED Dashboard 2.0.",[10,149,150],{},[142,151,152],{},"Option 2: Accept Client Constraints",[10,154,155],{},"A feature that ensures messages are specifically targeted to individual clients, which enhances the precision and security of data transmission within the platform. It determines by enabling the nodes option in the FF Auth tab whether the enabled node type will utilize client data, such as socketid, and restrict communications to only that client.",[10,157,158],{},"For example, consider a manufacturing facility where each production line has its own monitoring system. With this feature enabled, data from sensors on Production Line A will only be sent to the monitoring system designated for Production Line A. This ensures that data remains isolated and relevant to each specific area of operation, maintaining organizational efficiency and security.",[10,160,161],{},[162,163,164],"em",{},"Note: Please note that Multi-User Addons can only be used by our Teams and Enterprise Self-Hosted customers. Upon request, we provide all required configurations to get started.",[10,166,167],{},[48,168],{"alt":169,"dataZoomable":51,"src":170,"title":171},"\"Screenshot displaying the FlowFuse Muti-user addon option\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fdisplaying-logged-in-user-ff-auth-tab.png","Screenshot displaying the FlowFuse Muti-user addon option",[22,173,175],{"id":174},"displaying-logged-in-user-on-dashboard-20","Displaying logged in user on Dashboard 2.0",[10,177,178,179,182,183,185],{},"Now you know how the user add on works, you are all set to display logged in users on Dashboard 2.0. To confirm this you can use a ",[81,180,181],{},"debug"," node that receives the ",[81,184,96],{}," object emitted by the Dashboard 2.0 widgets.",[10,187,188,189,194],{},"To display user information on the dashboard we will use Vue’s ",[17,190,193],{"href":191,"rel":192},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#teleports",[121],"Teleport"," feature to render content to a specific location in the DOM, we will display user information at the action bar’s right-hand side.",[30,196,197,204,207],{},[33,198,199,200,203],{},"Drag a ",[81,201,202],{},"ui-template"," widget onto the canvas.",[33,205,206],{},"Click on that node, and select type as “Widget (Ui-Scoped)”. ( this allows us to render this ui-template at ui scoped which means I will not required to add separate ui-templates for different pages )",[33,208,209],{},"Copy the below vue snippet and paste that into the ui-template.",[103,211,215],{"className":212,"code":213,"language":214,"meta":51,"style":51},"language-html shiki shiki-themes github-light github-dark","\u003Ctemplate>\n    \u003C!-- Teleporting user info to #app-bar-actions, which is the ID of the action bars' right corners area -->\n    \u003CTeleport v-if=\"loaded\" to=\"#app-bar-actions\">\n        \u003Cdiv class=\"user-info\">\n            \u003C!-- Displaying user image -->\n            \u003Cimg :src=\"setup.socketio.auth.user.image\" \u002F>\n            \u003C!-- Greeting the user -->\n            \u003Cspan>Hi, {{ setup.socketio.auth.user.name }}\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n    \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    data() {\n        return {\n            \u002F\u002F Flag to indicate if the component is loaded\n            loaded: false\n        };\n    },\n    mounted() {\n        \u002F\u002F This function is called when the component is inserted into the DOM.\n        \u002F\u002F Setting loaded to true here ensures the component is ready to access #app-bar-actions,\n        \u002F\u002F as it's now part of the same DOM structure.\n        \u002F\u002F Accessing it before mounted() would cause an error because the component wouldn't be initialized in the DOM yet.\n        this.loaded = true; \u002F\u002F Setting loaded to true to indicate that the component has been mounted successfully\n    }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle>\n\u002F* Styling for user info display *\u002F\n.user-info {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n}\n\u002F* Styling for user avatar image*\u002F\n.user-info img {\n    width: 24px;\n    height: 24px;\n}\n\u003C\u002Fstyle>\n","html",[81,216,217,233,240,270,289,295,314,320,334,344,354,364,371,381,394,403,411,417,427,433,439,447,453,459,465,471,491,497,503,512,517,527,533,541,556,569,585,590,596,606,621,635,640],{"__ignoreMap":51},[218,219,222,226,230],"span",{"class":220,"line":221},"line",1,[218,223,225],{"class":224},"sVt8B","\u003C",[218,227,229],{"class":228},"s9eBZ","template",[218,231,232],{"class":224},">\n",[218,234,236],{"class":220,"line":235},2,[218,237,239],{"class":238},"sJ8bj","    \u003C!-- Teleporting user info to #app-bar-actions, which is the ID of the action bars' right corners area -->\n",[218,241,243,246,249,253,256,260,263,265,268],{"class":220,"line":242},3,[218,244,245],{"class":224},"    \u003C",[218,247,193],{"class":248},"s7hpK",[218,250,252],{"class":251},"sScJk"," v-if",[218,254,255],{"class":224},"=",[218,257,259],{"class":258},"sZZnC","\"loaded\"",[218,261,262],{"class":251}," to",[218,264,255],{"class":224},[218,266,267],{"class":258},"\"#app-bar-actions\"",[218,269,232],{"class":224},[218,271,273,276,279,282,284,287],{"class":220,"line":272},4,[218,274,275],{"class":224},"        \u003C",[218,277,278],{"class":228},"div",[218,280,281],{"class":251}," class",[218,283,255],{"class":224},[218,285,286],{"class":258},"\"user-info\"",[218,288,232],{"class":224},[218,290,292],{"class":220,"line":291},5,[218,293,294],{"class":238},"            \u003C!-- Displaying user image -->\n",[218,296,298,301,303,306,308,311],{"class":220,"line":297},6,[218,299,300],{"class":224},"            \u003C",[218,302,48],{"class":228},[218,304,305],{"class":251}," :src",[218,307,255],{"class":224},[218,309,310],{"class":258},"\"setup.socketio.auth.user.image\"",[218,312,313],{"class":224}," \u002F>\n",[218,315,317],{"class":220,"line":316},7,[218,318,319],{"class":238},"            \u003C!-- Greeting the user -->\n",[218,321,323,325,327,330,332],{"class":220,"line":322},8,[218,324,300],{"class":224},[218,326,218],{"class":228},[218,328,329],{"class":224},">Hi, {{ setup.socketio.auth.user.name }}\u003C\u002F",[218,331,218],{"class":228},[218,333,232],{"class":224},[218,335,337,340,342],{"class":220,"line":336},9,[218,338,339],{"class":224},"        \u003C\u002F",[218,341,278],{"class":228},[218,343,232],{"class":224},[218,345,347,350,352],{"class":220,"line":346},10,[218,348,349],{"class":224},"    \u003C\u002F",[218,351,193],{"class":248},[218,353,232],{"class":224},[218,355,357,360,362],{"class":220,"line":356},11,[218,358,359],{"class":224},"\u003C\u002F",[218,361,229],{"class":228},[218,363,232],{"class":224},[218,365,367],{"class":220,"line":366},12,[218,368,370],{"emptyLinePlaceholder":369},true,"\n",[218,372,374,376,379],{"class":220,"line":373},13,[218,375,225],{"class":224},[218,377,378],{"class":228},"script",[218,380,232],{"class":224},[218,382,384,388,391],{"class":220,"line":383},14,[218,385,387],{"class":386},"szBVR","export",[218,389,390],{"class":386}," default",[218,392,393],{"class":224}," {\n",[218,395,397,400],{"class":220,"line":396},15,[218,398,399],{"class":251},"    data",[218,401,402],{"class":224},"() {\n",[218,404,406,409],{"class":220,"line":405},16,[218,407,408],{"class":386},"        return",[218,410,393],{"class":224},[218,412,414],{"class":220,"line":413},17,[218,415,416],{"class":238},"            \u002F\u002F Flag to indicate if the component is loaded\n",[218,418,420,423],{"class":220,"line":419},18,[218,421,422],{"class":224},"            loaded: ",[218,424,426],{"class":425},"sj4cs","false\n",[218,428,430],{"class":220,"line":429},19,[218,431,432],{"class":224},"        };\n",[218,434,436],{"class":220,"line":435},20,[218,437,438],{"class":224},"    },\n",[218,440,442,445],{"class":220,"line":441},21,[218,443,444],{"class":251},"    mounted",[218,446,402],{"class":224},[218,448,450],{"class":220,"line":449},22,[218,451,452],{"class":238},"        \u002F\u002F This function is called when the component is inserted into the DOM.\n",[218,454,456],{"class":220,"line":455},23,[218,457,458],{"class":238},"        \u002F\u002F Setting loaded to true here ensures the component is ready to access #app-bar-actions,\n",[218,460,462],{"class":220,"line":461},24,[218,463,464],{"class":238},"        \u002F\u002F as it's now part of the same DOM structure.\n",[218,466,468],{"class":220,"line":467},25,[218,469,470],{"class":238},"        \u002F\u002F Accessing it before mounted() would cause an error because the component wouldn't be initialized in the DOM yet.\n",[218,472,474,477,480,482,485,488],{"class":220,"line":473},26,[218,475,476],{"class":425},"        this",[218,478,479],{"class":224},".loaded ",[218,481,255],{"class":386},[218,483,484],{"class":425}," true",[218,486,487],{"class":224},"; ",[218,489,490],{"class":238},"\u002F\u002F Setting loaded to true to indicate that the component has been mounted successfully\n",[218,492,494],{"class":220,"line":493},27,[218,495,496],{"class":224},"    }\n",[218,498,500],{"class":220,"line":499},28,[218,501,502],{"class":224},"}\n",[218,504,506,508,510],{"class":220,"line":505},29,[218,507,359],{"class":224},[218,509,378],{"class":228},[218,511,232],{"class":224},[218,513,515],{"class":220,"line":514},30,[218,516,370],{"emptyLinePlaceholder":369},[218,518,520,522,525],{"class":220,"line":519},31,[218,521,225],{"class":224},[218,523,524],{"class":228},"style",[218,526,232],{"class":224},[218,528,530],{"class":220,"line":529},32,[218,531,532],{"class":238},"\u002F* Styling for user info display *\u002F\n",[218,534,536,539],{"class":220,"line":535},33,[218,537,538],{"class":251},".user-info",[218,540,393],{"class":224},[218,542,544,547,550,553],{"class":220,"line":543},34,[218,545,546],{"class":425},"    display",[218,548,549],{"class":224},": ",[218,551,552],{"class":425},"flex",[218,554,555],{"class":224},";\n",[218,557,559,562,564,567],{"class":220,"line":558},35,[218,560,561],{"class":425},"    align-items",[218,563,549],{"class":224},[218,565,566],{"class":425},"center",[218,568,555],{"class":224},[218,570,572,575,577,580,583],{"class":220,"line":571},36,[218,573,574],{"class":425},"    gap",[218,576,549],{"class":224},[218,578,579],{"class":425},"8",[218,581,582],{"class":386},"px",[218,584,555],{"class":224},[218,586,588],{"class":220,"line":587},37,[218,589,502],{"class":224},[218,591,593],{"class":220,"line":592},38,[218,594,595],{"class":238},"\u002F* Styling for user avatar image*\u002F\n",[218,597,599,601,604],{"class":220,"line":598},39,[218,600,538],{"class":251},[218,602,603],{"class":228}," img",[218,605,393],{"class":224},[218,607,609,612,614,617,619],{"class":220,"line":608},40,[218,610,611],{"class":425},"    width",[218,613,549],{"class":224},[218,615,616],{"class":425},"24",[218,618,582],{"class":386},[218,620,555],{"class":224},[218,622,624,627,629,631,633],{"class":220,"line":623},41,[218,625,626],{"class":425},"    height",[218,628,549],{"class":224},[218,630,616],{"class":425},[218,632,582],{"class":386},[218,634,555],{"class":224},[218,636,638],{"class":220,"line":637},42,[218,639,502],{"class":224},[218,641,643,645,647],{"class":220,"line":642},43,[218,644,359],{"class":224},[218,646,524],{"class":228},[218,648,232],{"class":224},[22,650,652],{"id":651},"deploying-the-flow","Deploying the flow",[30,654,655,658],{},[33,656,657],{},"With your flow updated to include the above, click the \"Deploy\" button in the top-right of the Node-RED Editor.",[33,659,660,661,664],{},"Navigate to ",[81,662,663],{},"https:\u002F\u002F\u003Cyour-instance-name>.flowfuse.cloud\u002Fdashboard",".",[10,666,667],{},[48,668],{"alt":669,"dataZoomable":51,"src":670,"title":671},"\"Screenshot of Dashboard displaying logged in user information\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fdisplaying-logged-in-user-dashboard-view.png","Screenshot of Dashboard displaying logged in user information",[22,673,675],{"id":674},"next-step","Next step",[10,677,678],{},"If you want to learn more about the FlowFuse Multiuser addon and Personalize Multiuser Dashboard. we do have many other resources, please refer to them to learn more.",[680,681,682,689,696],"ul",{},[33,683,684,688],{},[17,685,687],{"href":686},"\u002Fwebinars\u002F2024\u002Fnode-red-dashboard-multi-user\u002F","Webinar"," - This webinar provides an in-depth discussion of the Personalised Multi-User Dashboards feature and offers guidance on how to get started with it.",[33,690,691,695],{},[17,692,694],{"href":693},"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user\u002F","Personalised Multi-user Dashboards with Node-RED Dashboard 2.0"," - This article explores the process of building multi-user Dashboards secured with FlowFuse Cloud.",[33,697,698,702],{},[17,699,701],{"href":700},"\u002Fblueprints\u002Fflowfuse-dashboard\u002Fmulti-user-dashboard\u002F","Multi-User Dashboard for Ticket\u002FTask Management"," blueprint, which allows you to quickly utilize templates to develope Personalize multi-user dashboard.",[22,704,706],{"id":705},"conclusion","Conclusion",[10,708,709],{},"In this guide, we have demonstrated how to secure your dashboard and how to retrieve and display logged in user data on Dashboard 2.0. Additionally, we have discussed the functionality of the FlowFuse multi-user addon.",[524,711,712],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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);}",{"title":51,"searchDepth":235,"depth":235,"links":714},[715,716,720,721,722,723],{"id":24,"depth":235,"text":25},{"id":56,"depth":235,"text":57,"children":717},[718,719],{"id":64,"depth":242,"text":65},{"id":89,"depth":242,"text":90},{"id":174,"depth":235,"text":175},{"id":651,"depth":235,"text":652},{"id":674,"depth":235,"text":675},{"id":705,"depth":235,"text":706},"md",{"navTitle":5,"excerpt":726},{"type":7,"value":727},[728],[10,729,12],{},"\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard",{"title":5,"description":12},"blog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard","mwPRnBuu7kqVksAg91xkcWZtH1cHKboKtw0yGVMDFNc",1780070551658]