[{"data":1,"prerenderedAt":18854},["ShallowReactive",2],{"blog-\u002Fblog\u002Fdashboard":3,"blog-all-for-related":4,"blog-all-dashboard":5},null,[],[6,305,490,673,839,2167,3014,3500,3826,4182,5517,6041,6572,8106,9616,10131,11688,11861,12487,13051,14536,14766,14930,15621,15805,16096,16413,16630,16798,17683,17769,18035,18361],{"id":7,"title":8,"authors":9,"body":11,"cta":3,"date":285,"description":286,"extension":287,"image":288,"lastUpdated":3,"meta":289,"navigation":295,"path":296,"seo":297,"sitemap":298,"stem":299,"subtitle":300,"tags":301,"tldr":3,"video":3,"__hash__":304},"blog\u002Fblog\u002F2025\u002F09\u002Fwhat-is-5s-checklist.md","What is 5S Checklist: Definition, Benefits, Implementation, and Template",[10],"sumit-shinde",{"type":12,"value":13,"toc":264},"minimark",[14,18,23,26,61,64,68,71,74,78,81,86,100,104,118,122,136,140,154,158,172,176,179,182,185,188,192,195,198,201,205,208,211,214,217,220,224,227],[15,16,17],"p",{},"Manufacturing environments face increasing pressure to eliminate waste, improve safety, and maintain quality standards. Disorganized workspaces contribute to production delays, safety incidents, and quality defects that directly impact operational performance. The 5S methodology addresses these challenges through systematic work area organization, but implementation requires consistent evaluation and measurement. A 5S checklist provides the structured framework necessary to assess, maintain, and improve work area organization standards across manufacturing operations.",[19,20,22],"h2",{"id":21},"understanding-5s-methodology","Understanding 5S Methodology",[15,24,25],{},"The 5S methodology originated in Japanese manufacturing and has become the gold standard for work area organization worldwide. The name comes from five Japanese words that each begin with 'S', representing a systematic approach to creating efficient, safe workspaces:",[27,28,29,37,43,49,55],"ul",{},[30,31,32,36],"li",{},[33,34,35],"strong",{},"Sort (Seiri)"," means removing everything that doesn't belong in your workspace. This involves ruthlessly eliminating \"just in case\" items that create clutter and reduce efficiency.",[30,38,39,42],{},[33,40,41],{},"Set in Order (Seiton)"," gives everything that remains a logical, designated home based on frequency of use and workflow patterns.",[30,44,45,48],{},[33,46,47],{},"Shine (Seiso)"," focuses on cleanliness that reveals problems early. Oil leaks, wear patterns, and safety hazards become immediately visible in clean environments.",[30,50,51,54],{},[33,52,53],{},"Standardize (Seiketsu)"," creates consistent procedures so everyone follows identical organizational principles across shifts and departments.",[30,56,57,60],{},[33,58,59],{},"Sustain (Shitsuke)"," builds the culture and accountability systems needed to maintain improvements permanently.",[15,62,63],{},"The challenge isn’t just understanding these concepts; it’s implementing them consistently across different operations.",[19,65,67],{"id":66},"what-makes-a-5s-checklist-essential","What Makes a 5S Checklist Essential",[15,69,70],{},"A 5S checklist transforms abstract organizational principles into concrete, measurable actions with specific evaluation criteria. Instead of subjective opinions about workspace organization, teams get objective standards: Is every tool in its designated shadow board outline? Are walkways completely obstacle-free? Can someone new find required materials within two minutes?",[15,72,73],{},"Beyond simple evaluation, these checklists serve as training tools for new employees, communication devices between shifts, historical records showing improvement trends, and accountability systems that prevent 5S from becoming another forgotten initiative.",[19,75,77],{"id":76},"essential-5s-checklist-items-every-work-area-needs","Essential 5S Checklist Items Every work area Needs",[15,79,80],{},"While each work environment requires specific evaluation criteria, certain fundamental items should be included in every 5S checklist. Here is a practical framework of 25 questions that you can adapt for your operations.",[82,83,85],"h3",{"id":84},"sort","Sort",[27,87,88,91,94,97],{},[30,89,90],{},"Are workstations free of unnecessary materials, tools, and equipment?",[30,92,93],{},"Have outdated documents and reference materials been removed?",[30,95,96],{},"Are broken or obsolete items properly tagged for disposal?",[30,98,99],{},"Do storage areas contain only frequently used items?",[82,101,103],{"id":102},"set-in-order","Set in Order",[27,105,106,109,112,115],{},[30,107,108],{},"Is every tool in its designated location with clear identification?",[30,110,111],{},"Are frequently used items positioned within easy reach?",[30,113,114],{},"Are visual management systems (labels, shadow boards, floor markings) clearly visible?",[30,116,117],{},"Can workers retrieve needed items without searching or moving obstacles?",[82,119,121],{"id":120},"shine","Shine",[27,123,124,127,130,133],{},[30,125,126],{},"Are all surfaces, equipment, and floors properly cleaned?",[30,128,129],{},"Are maintenance schedules current and inspection logs up-to-date?",[30,131,132],{},"Are cleaning supplies readily available and properly stored?",[30,134,135],{},"Are leaks, spills, and abnormal conditions immediately visible?",[82,137,139],{"id":138},"standardize","Standardize",[27,141,142,145,148,151],{},[30,143,144],{},"Are work instructions current, accessible, and consistently followed?",[30,146,147],{},"Do similar workstations follow identical organizational principles?",[30,149,150],{},"Are all team members trained on current 5S standards?",[30,152,153],{},"Are procedures regularly reviewed and updated?",[82,155,157],{"id":156},"sustain","Sustain",[27,159,160,163,166,169],{},[30,161,162],{},"Do workers maintain organizational standards without constant supervision?",[30,164,165],{},"Are team members actively identifying improvement opportunities?",[30,167,168],{},"Do supervisors regularly participate in evaluations and improvements?",[30,170,171],{},"Are 5S achievements recognized and celebrated?",[19,173,175],{"id":174},"the-real-impact-on-your-operations","The Real Impact on Your Operations",[15,177,178],{},"Companies that implement 5S checklists consistently report dramatic improvements that go far beyond having a tidy workspace. Workers typically spend less time searching for tools and materials once proper organization takes hold. This isn't just about efficiency, it's about frustration levels and job satisfaction too.",[15,180,181],{},"Safety improvements often exceed expectations. When everything has a proper place and workspaces stay clean, accident rates can drop. Spills get noticed and cleaned immediately instead of becoming slip hazards. Tools don't get left in walkways where someone might trip.",[15,183,184],{},"Quality improvements follow naturally from better organization. Clean, well-organized environments make it easier to spot problems before they become defects. When workers aren't rushed or frustrated from searching for materials, they make fewer mistakes. The predictability of well-organized processes reduces variability in outcomes.",[15,186,187],{},"Perhaps surprisingly, employee engagement often increases significantly. Teams take pride in maintaining organized workspaces, especially when they participate in regular evaluations and see their scores improve over time. The checklist process gives everyone a voice in work area improvement.",[19,189,191],{"id":190},"making-implementation-work","Making Implementation Work",[15,193,194],{},"Starting a successful 5S checklist program requires more than distributing forms. Begin with leadership commitment and comprehensive training so everyone understands both the evaluation process and its connection to their daily work experience.",[15,196,197],{},"Create area-specific checklists rather than generic ones. A machine shop needs different evaluation criteria than an assembly line or office environment. While core 5S principles remain constant, specific items should reflect each workspace's unique requirements.",[15,199,200],{},"Establish regular evaluation cycles: daily quick checks for immediate problems, weekly detailed reviews for improvement planning, and monthly comprehensive evaluations for trend analysis. The crucial element many programs miss is systematic follow-through. Identifying problems only creates value when those problems get solved with assigned responsibility and completion tracking.",[19,202,204],{"id":203},"the-digital-advantage-with-flowfuse","The Digital Advantage with FlowFuse",[15,206,207],{},"Traditional paper checklists have inherent limitations. Results get lost, data analysis becomes time-consuming, and accessing information from multiple locations proves challenging. Digital solutions eliminate these problems while adding capabilities that paper cannot match.",[15,209,210],{},"FlowFuse's low-code Node-RED interface makes building sophisticated 5S checklist applications accessible without extensive programming backgrounds. You can create custom evaluation forms capturing exactly the information your operation needs. Simple yes\u002Fno questions, numerical scores, or detailed condition comments.",[15,212,213],{},"As an industrial data platform, FlowFuse enables seamless integration of 5S checklists into broader operational workflows, connecting work area organization efforts with real-time factory data for comprehensive improvement insights.",[15,215,216],{},"Mobile access transforms team interaction with the evaluation process. Workers complete checklists on tablets or smartphones directly in work areas, take photos documenting conditions, and immediately see how current scores compare to previous evaluations. This real-time feedback creates engagement impossible with paper forms.",[15,218,219],{},"[Sign up]({% include \"sign-up-url.njk\" %}) for FlowFuse now and get started building your individual 5S checklist.",[19,221,223],{"id":222},"up-next","Up next",[15,225,226],{},"If you want to start immediately without creating a checklist from scratch, FlowFuse’s pre-built 5S Checklist Blueprint is ready to use. It includes 25 evaluation questions to assess work area organization, scoring to measure compliance, and follow-up tracking to ensure issues are resolved. The dashboard provides a clear view of improvements over time, and the entire system is fully customizable to match the unique needs of your operations.",[228,229,233,233,234,233,244,263],"div",{"className":230,"style":232},[231],"cta-card","display: flex; align-items: center; gap: 20px; background-color: #EEF2FF; padding: 20px; border-radius: 8px; font-family: sans-serif; border: 1px solid #6366F1;","  \n    ",[228,235,237,238,233],{"style":236},"flex: 1;","  \n        ",[239,240],"img",{"src":241,"alt":242,"style":243},"https:\u002F\u002Fflowfuse.com\u002Fimg\u002F5s-checklist-eYy2xo4REM-650.avif","FlowFuse 5S Checklist Blueprint","width: 100%; height: auto; border-radius: 6px;",[228,245,237,246,237,251,237,255,233],{"style":236},[82,247,250],{"style":248,"id":249},"font-size: 1.5em; margin: 0 0 10px;","ready-to-transform-your-work-area","Ready to Transform Your Work Area?",[15,252,254],{"style":253},"font-size: 1em; margin: 0 0 20px;","Get started with FlowFuse's customizable 5S Checklist Blueprint and build your digital evaluation system in minutes.",[256,257,262],"a",{"href":258,"className":259,"style":261},"https:\u002F\u002Fflowfuse.com\u002Fblueprints\u002Fmanufacturing\u002F5s-checklist\u002F",[260],"cta-button","display: inline-block; background-color:#4f46e5; color: #ffffff; padding: 8px 18px; text-decoration: none; border-radius: 9999px; font-weight: bold; font-size: 0.95em; transition: background-color 0.3s ease;","Explore 5S Checklist Blueprint →","  \n",{"title":265,"searchDepth":266,"depth":266,"links":267},"",4,[268,270,271,279,280,281,282],{"id":21,"depth":269,"text":22},2,{"id":66,"depth":269,"text":67},{"id":76,"depth":269,"text":77,"children":272},[273,275,276,277,278],{"id":84,"depth":274,"text":85},3,{"id":102,"depth":274,"text":103},{"id":120,"depth":274,"text":121},{"id":138,"depth":274,"text":139},{"id":156,"depth":274,"text":157},{"id":174,"depth":269,"text":175},{"id":190,"depth":269,"text":191},{"id":203,"depth":269,"text":204},{"id":222,"depth":269,"text":223,"children":283},[284],{"id":249,"depth":274,"text":250},"2025-09-10","Learn what a 5S checklist is, how it improves work area organization, and how to implement it easily with FlowFuse, plus get a ready-to-use template.","md","\u002Fblog\u002F2025\u002F09\u002Fimages\u002Fwhat-is-5s-checklist.png",{"keywords":290,"excerpt":291},"5s checklist, 5s audit checklist, 5s audit, 5s audit scorecard, 5s checklist template, check list 5s, manufacturing 5s checklist, 5s audit template, 5s cleaning checklist, 5s audit form, 5s audit sheet, 5s daily checklist, daily 5s checklist for manufacturing excel, 5s audit checklist for manufacturing",{"type":12,"value":292},[293],[15,294,17],{},true,"\u002Fblog\u002F2025\u002F09\u002Fwhat-is-5s-checklist",{"title":8,"description":286},{"loc":296},"blog\u002F2025\u002F09\u002Fwhat-is-5s-checklist","Understand 5S Checklists, Improve Work Area Efficiency, and Start with a Ready-to-Use FlowFuse Template",[302,303],"flowfuse","dashboard","2ll2MeKpncJX3XIV4UhzqxOoUR4W_nK5uldmePL17LA",{"id":306,"title":307,"authors":308,"body":310,"cta":3,"date":474,"description":475,"extension":287,"image":476,"lastUpdated":3,"meta":477,"navigation":295,"path":482,"seo":483,"sitemap":484,"stem":485,"subtitle":475,"tags":486,"tldr":3,"video":3,"__hash__":489},"blog\u002Fblog\u002F2024\u002F11\u002Fdashboard-new-group-type-app-icon-and-charts.md","Visual Layout Editor - Now Available in Dashboard",[309],"joe-pavitt",{"type":12,"value":311,"toc":467},[312,315,319,322,325,336,339,347,350,370,373,380,383,387,390,404,407,411,414,422,425,429,438,456,460],[15,313,314],{},"It has been one of the most requested features for FlowFuse Dashboard, and is now available in its first iteration. It is now possible to resize and move groups in the Dashboard itself using the new \"Edit Layout\" feature. That's not all though, we've added a new \"Spacer\" widget to assist with layouts, added improvements to the rendering of charts and plenty more.",[19,316,318],{"id":317},"layout-editor-quick-guide","Layout Editor - Quick Guide",[15,320,321],{},"For those transitioning over from the original Node-RED Dashboard 1.0, you'll notice some difference in how you can now edit the layout of your dashboard. Now, the editing is done directly in the Dashboard itself, rather than in the Node-RED editor.",[15,323,324],{},"To open the Dashboard in \"Edit Mode\", click the \"Edit Layout\" button for the relevant page in the Dashboard sidebar:",[15,326,327,331,332],{},[239,328],{"alt":329,"dataZoomable":265,"src":330},"Screenshot showing the Edit Layout button in the Dashboard sidebar","\u002Fblog\u002F2024\u002F11\u002Fimages\u002Fedit-layout-button.png","{width=\"500px\"}\n",[333,334,335],"em",{},"Screenshot to show the buttons available to \"Edit Layout\" for a given page",[15,337,338],{},"This will open the relevant page in \"Edit Mode\":",[15,340,341,345],{},[239,342],{"alt":343,"dataZoomable":265,"src":344},"Short recording to show resizing and reordering in the visual layout editor","\u002Fblog\u002F2024\u002F11\u002Fimages\u002Fwysiwyg-demo.gif",[333,346,343],{},[15,348,349],{},"The three controls at the top of the page are:",[27,351,352,358,364],{},[30,353,354,357],{},[33,355,356],{},"Save Changes:"," Deploy any changes to the underlying Node-RED flow.",[30,359,360,363],{},[33,361,362],{},"Discard Changes:"," Clear any in-browser changes that have not yet been saved.",[30,365,366,369],{},[33,367,368],{},"Exit Edit Mode:"," Stop \"Edit Mode\" and interact with teh Dashboard as a standard end-user.",[15,371,372],{},"You can then use the handles on each group to resize them, or click and drag to re-position the groups on the page. How this re-positioning is done is controlled by the \"Layout\" property of the page. The Visual Editor is currently available for \"Grid\" and \"Fixed\" layouts only.",[15,374,375,376,379],{},"Once you're happy with your changes clicked the \"Save Changes\" button to deploy them to the underlying Node-RED flow. Note, you will then be made aware that ",[333,377,378],{},"\"your flows have been updated\""," by Dashboard when you return to your Node-RED Editor.",[15,381,382],{},"Note that you can only enter \"Edit Mode\" via the Node-RED Editor, this is to ensure security and stability of your Dashboard, in cases where you may have users for your Dashboard that should not have access to modify your Dashboard's layout.",[19,384,386],{"id":385},"layout-editor-next-steps","Layout Editor - Next Steps",[15,388,389],{},"We are very aware that is this is just the first iteration of the Layout Editor, and we have plenty of plans to improve it further. Here are some of the features we are considering for future releases:",[27,391,392,395],{},[30,393,394],{},"Include widget resizing and ordering in the Layout Editor",[30,396,397,398],{},"Overhauling sizing options for groups and widgets ",[256,399,403],{"href":400,"rel":401},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F835",[402],"nofollow","#835",[15,405,406],{},"If there are any other key editor features you'd like to see, then please do reach out to us, open GitHub issues and help us shape the future of FlowFuse Dashboard.",[19,408,410],{"id":409},"new-widget-ui-spacer","New Widget: UI Spacer",[15,412,413],{},"In the Dashboard sidebar, you now have the option to add a \"Spacer\", this is just an empty widget that can be used to shift the position of other widgets. This can be useful for creating more complex layouts, or for adding space between widgets. For example, if you wanted to have some directional controls with up\u002Fdown\u002Fleft\u002Fright buttons, you could use a spacer to separate and align them:",[15,415,416,420],{},[239,417],{"alt":418,"dataZoomable":265,"src":419},"(left) A d-pad controller layout using spacers, (right) the spacer's highlighted to demonstrate their positioning","\u002Fblog\u002F2024\u002F11\u002Fimages\u002Fspacer-example.png",[333,421,418],{},[15,423,424],{},"Spacers can be any width and height, and will always render empty-space. To add a new spacer, you can click the \"+\" button in the Dashboard sidebar next to any Groups. You can then re-order the widgets there too (re-ordering of widgets in the visual layout editor will be coming soon).",[19,426,428],{"id":427},"what-else-is-new","What else is new?",[15,430,431,432,437],{},"You can find the full 1.19.0 Release Notes ",[256,433,436],{"href":434,"rel":435},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv1.19.0",[402],"here",".",[15,439,440,441,445,446,450,451],{},"Work has already begun on the next release, ",[442,443,444],"code",{},"1.20.0",", you can see what items we have queued up ",[256,447,436],{"href":448,"rel":449},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F1",[402],", if you've got any feedback or suggestions, please do let us know, and feel free to open new issues on our ",[256,452,455],{"href":453,"rel":454},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues",[402],"GitHub",[19,457,459],{"id":458},"we-are-hiring","We are Hiring!",[15,461,462,463,437],{},"You may have seen already that we are hiring for a full-time Front-End Engineer to join our team, and work on Dashboard, full-time. If you are interested in working with us, please do check out the job listing ",[256,464,436],{"href":465,"rel":466},"https:\u002F\u002Fjob-boards.greenhouse.io\u002Fflowfuse\u002Fjobs\u002F5185319004",[402],{"title":265,"searchDepth":266,"depth":266,"links":468},[469,470,471,472,473],{"id":317,"depth":269,"text":318},{"id":385,"depth":269,"text":386},{"id":409,"depth":269,"text":410},{"id":427,"depth":269,"text":428},{"id":458,"depth":269,"text":459},"2024-11-08","With the latest update we have released a new Layout Editor for Dashboard, as well as new widgets and wide-spread improvements.","\u002Fblog\u002F2024\u002F11\u002Fimages\u002Fdashboard-1-19-0-tile.png",{"excerpt":478},{"type":12,"value":479},[480],[15,481,314],{},"\u002Fblog\u002F2024\u002F11\u002Fdashboard-new-group-type-app-icon-and-charts",{"title":307,"description":475},{"loc":482},"blog\u002F2024\u002F11\u002Fdashboard-new-group-type-app-icon-and-charts",[487,488,302,303],"posts","news","20aHz5oFNsfjKYq0Tn9o2Ea2vcutx7lw4NEXD8-qVj8",{"id":491,"title":492,"authors":493,"body":495,"cta":652,"date":656,"description":657,"extension":287,"image":658,"lastUpdated":659,"meta":660,"navigation":295,"path":666,"seo":667,"sitemap":668,"stem":669,"subtitle":657,"tags":670,"tldr":671,"video":3,"__hash__":672},"blog\u002Fblog\u002F2024\u002F10\u002Fdashboard-new-group-type-app-icon-and-charts.md","Dialogs, Customizable Icons and Histograms Now Available in FlowFuse Dashboard",[494],"gayan-sandamal",{"type":12,"value":496,"toc":645},[497,500,504,507,510,518,521,529,533,536,545,548,556,560,575,578,586,589,596,598,605,608,630,634],[15,498,499],{},"This update introduces new ways to enhance data visualization and customization in your dashboards. With key improvements, including a new chart type, customizable app icon support and a dialog feature for groups, this release helps tailor dashboards for better user interaction and flexibility.",[19,501,503],{"id":502},"new-chart-type-histogram","New Chart Type: Histogram",[15,505,506],{},"Histograms are an essential tool for data analysis, offering a clear way to visualize distributions. The latest Dashboard update introduces a fully customizable histogram chart type, allowing you to present frequency distributions for your data.",[15,508,509],{},"Whether analyzing performance metrics or user activity, histograms can give you a clear view of how data points are distributed across predefined ranges. You can now easily group data and control the range, providing deeper insights at a glance.",[15,511,512,516],{},[239,513],{"alt":514,"dataZoomable":265,"src":515},"Screenshot showing the new Histogram chart type","\u002Fblog\u002F2024\u002F10\u002Fimages\u002Fchart-histogram.png",[333,517,514],{},[15,519,520],{},"The real advantage of this new Histogram chart type is that it simplifies the process for you. Just pass in the raw data, and the histogram will automatically organize it into meaningful ranges, then display how often each range occurs. This makes it incredibly easy to extract valuable insights without the need for manual data processing.",[15,522,523,524,528],{},"You can see an example flow for the Histogram chart type ",[256,525,436],{"href":526,"rel":527},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-chart.html#histograms",[402]," in our documentation.",[19,530,532],{"id":531},"customizable-app-icon","Customizable App Icon",[15,534,535],{},"Branding is an essential part of any user experience and with this new feature, you can customize your dashboard's app icon. The Node-RED Dashboard 2.0 now allows users to provide their own application icon, which appears in the browser tab and when the dashboard is installed as a Progressive Web App (PWA). This customization helps reinforce your brand, whether you’re developing IoT solutions, monitoring systems or creating dashboards for end-users.",[15,537,538,543],{},[239,539],{"alt":540,"dataZoomable":265,"src":541,"style":542},"Screenshot showing the customizable app icon in browser and as a PWA","\u002Fblog\u002F2024\u002F10\u002Fimages\u002Fapp-icon-installation.png","max-width: 400px; margin: auto;",[333,544,540],{},[15,546,547],{},"You can configure the icon by navigating to the base UI settings (ui-base) and providing an icon URL.",[15,549,550,551],{},"You can read more about how to use this feature in the ",[256,552,555],{"href":553,"rel":554},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fconfig\u002Fui-base.html#application-icon",[402],"App Icon Documentation",[19,557,559],{"id":558},"building-dialogs","Building Dialogs",[15,561,562,563,568,569,574],{},"Organizing data on dashboards has become more efficient with the new \"Dialog\u002FModal\" feature. Groups in Dashboard now have a new ",[256,564,567],{"href":565,"rel":566},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fconfig\u002Fui-group.html#type",[402],"\"Type\""," property, so they can be rendered inline as before, or instead rendered as a Dialog. The display of the dialog groups can be controlled (opened\u002Fclosed) via the ",[256,570,573],{"href":571,"rel":572},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-control.html#show-hide",[402],"Control"," node.",[15,576,577],{},"This removes the need for building custom modals and dialogs in a Template node, and makes the entire experience of building your dialogs low-code.",[15,579,580,584],{},[239,581],{"alt":582,"dataZoomable":265,"src":583},"Screenshot showing groups rendered as dialogs in the dashboard","\u002Fblog\u002F2024\u002F10\u002Fimages\u002Fui-group-type-dialog.png",[333,585,582],{},[15,587,588],{},"By utilizing groups as dialogs, users can maintain a clean dashboard while still having quick access to detailed data when required.",[15,590,591,592],{},"You can read more about the new property, and see an example flow in the ",[256,593,595],{"href":565,"rel":594},[402],"UI Group Documentation",[19,597,428],{"id":427},[15,599,600,601,437],{},"You can find the full 1.18.0 Release Notes ",[256,602,436],{"href":603,"rel":604},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv1.18.0",[402],[15,606,607],{},"Just to highlight a few, particularly valuable, updates and fixes:",[27,609,610,613,624,627],{},[30,611,612],{},"UI Chart - Group tooltips for line chart.",[30,614,615,616],{},"UI Button Group\n",[27,617,618,621],{},[30,619,620],{},"Show node status",[30,622,623],{},"Add pointerdown\u002Fpointerup event handling and fix button theming bug",[30,625,626],{},"UI Table - Support key type option for entering fixed strings as item labels",[30,628,629],{},"UI Switch - Layout Switching with Dynamic Configuration Support",[19,631,633],{"id":632},"whats-next","What's Next?",[15,635,440,636,445,639,450,642],{},[442,637,638],{},"1.19.0",[256,640,436],{"href":448,"rel":641},[402],[256,643,455],{"href":453,"rel":644},[402],{"title":265,"searchDepth":266,"depth":266,"links":646},[647,648,649,650,651],{"id":502,"depth":269,"text":503},{"id":531,"depth":269,"text":532},{"id":558,"depth":269,"text":559},{"id":427,"depth":269,"text":428},{"id":632,"depth":269,"text":633},{"type":653,"title":654,"description":655},"sign-up","Build Better Dashboards with FlowFuse","Get access to the latest FlowFuse Dashboard features including histograms, dialog groups, and custom app icons. Start your free trial today.","2024-10-11","Our latest update for FlowFuse Dashboard introduces a new group type, Dialog, a new chart variation, Histogram and customization support for the application icon.","\u002Fblog\u002F2024\u002F10\u002Fimages\u002Fdashboard-1-18-0-blog-tile.png","2026-06-03",{"keywords":661,"excerpt":662},"flowfuse dashboard, node-red dashboard, histogram chart, dialog modal, app icon, dashboard customization, node-red dashboard 2.0, ui group, pwa icon, data visualization",{"type":12,"value":663},[664],[15,665,499],{},"\u002Fblog\u002F2024\u002F10\u002Fdashboard-new-group-type-app-icon-and-charts",{"title":492,"description":657},{"loc":666},"blog\u002F2024\u002F10\u002Fdashboard-new-group-type-app-icon-and-charts",[487,488,302,303],"FlowFuse Dashboard 1.18.0 adds three major features: a Histogram chart type for frequency distribution visualization, a Dialog\u002FModal group type for low-code overlay panels, and customizable app icon support for branding in the browser tab and as a PWA. These changes reduce the need for custom Template node workarounds.","m1gRFrRJDZNHUmSz5T0g7Q6t_f7i1gXg7WJm_kojXIo",{"id":674,"title":675,"authors":676,"body":677,"cta":3,"date":825,"description":826,"extension":287,"image":827,"lastUpdated":3,"meta":828,"navigation":295,"path":833,"seo":834,"sitemap":835,"stem":836,"subtitle":826,"tags":837,"tldr":3,"video":3,"__hash__":838},"blog\u002Fblog\u002F2024\u002F08\u002Fdashboard-new-layout-widgets-and-gauges.md","New Layout, Widget and Gauges Now Available in FlowFuse Dashboard",[494],{"type":12,"value":678,"toc":815},[679,682,686,689,692,700,704,707,715,723,727,730,734,737,745,752,756,759,767,773,775,782,784,802,804],[15,680,681],{},"At FlowFuse, we're constantly evolving to make sure your dashboard experience is seamless and efficient. This month, we're excited to introduce several new features that enhance your interaction with the platform. From organizing your data with Tabs to visualizing critical information with new Gauges, we've got you covered.",[19,683,685],{"id":684},"new-layout-tabs","New Layout: Tabs",[15,687,688],{},"We know that managing multiple data sources and visualizations can get overwhelming. To streamline your workflow, we've introduced a new layout: Tabs.",[15,690,691],{},"Tabs allow you to organize your widgets into separate, easily navigable sections, reducing clutter and making it easier to focus on specific datasets. Whether you're monitoring system performance, tracking KPIs, or managing IoT devices, Tabs will help you stay organized and efficient.",[15,693,694,698],{},[239,695],{"alt":696,"dataZoomable":265,"src":697},"Screenshot showing a tab layout in Dashboard","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Flayout-tab-dashboard.png",[333,699,696],{},[19,701,703],{"id":702},"new-widget-number-input","New Widget: Number Input",[15,705,706],{},"Introducing the Number Input widget, a versatile addition that allows users to input numerical values directly into the dashboard. Whether you're setting thresholds, configuring parameters, or simply inputting data, this widget makes it easy to adjust values with precision. It’s ideal for use cases where user interaction with numerical data is required, such as controlling devices or updating settings in real time.",[15,708,709,713],{},[239,710],{"alt":711,"dataZoomable":265,"src":712},"Screenshot showing a number input widget with Dashboard","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fui-number-input-widget.png",[333,714,711],{},[15,716,717,718],{},"You can try the Number Input now in our ",[256,719,722],{"href":720,"rel":721},"https:\u002F\u002Fdashboard-demos.flowfuse.cloud\u002Fdashboard\u002Fnumber-input",[402],"live Dashboard running on FlowFuse",[19,724,726],{"id":725},"new-gauges","New Gauges",[15,728,729],{},"Data visualization is a cornerstone of any effective dashboard. We’re excited to introduce two new gauges designed to provide at-a-glance insights into your key metrics.",[82,731,733],{"id":732},"battery-charge","Battery Charge",[15,735,736],{},"Monitoring battery levels is crucial for applications that rely on mobile or remote devices. Our new Battery Gauge provides a clear visual representation of battery status, allowing you to quickly assess power levels and take action if necessary. It’s perfect for IoT deployments, mobile sensors, or any system where battery life is a key consideration.",[15,738,739,743],{},[239,740],{"alt":741,"dataZoomable":265,"src":742},"Screenshot showing a battery gauge with Dashboard","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fui-gauge-battery.png",[333,744,741],{},[15,746,747,748],{},"You can try the Tank Level now in our ",[256,749,722],{"href":750,"rel":751},"https:\u002F\u002Fdashboard-demos.flowfuse.cloud\u002Fdashboard\u002Fgauge#battery-charge",[402],[82,753,755],{"id":754},"tank-level","Tank Level",[15,757,758],{},"Managing fluid levels in tanks is a common requirement across industries. The new Tank Level Gauge gives you a straightforward way to monitor liquid or gas levels in real time. Whether you're tracking water in a reservoir, fuel in a tank or any other fluid. this gauge provides the precision and clarity you need to maintain operational efficiency.",[15,760,761,765],{},[239,762],{"alt":763,"dataZoomable":265,"src":764},"Screenshot showing a partially filled tank level gauge with Dashboard","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fui-gauge-tank-filled.png",[333,766,763],{},[15,768,747,769],{},[256,770,722],{"href":771,"rel":772},"https:\u002F\u002Fdashboard-demos.flowfuse.cloud\u002Fdashboard\u002Fgauge#tank-level",[402],[19,774,428],{"id":427},[15,776,777,778,437],{},"You can find the full 1.15.0 Release Notes ",[256,779,436],{"href":780,"rel":781},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv1.15.0",[402],[15,783,607],{},[27,785,786,789,792,795],{},[30,787,788],{},"UI Switch - Introduced an \"Indicator\" mode and enhanced memory handling for better performance.",[30,790,791],{},"UI Table - Added a \"Button\" column type for improved interactivity.",[30,793,794],{},"UI Button - Color customisation now available, without needing to write overriding CSS.",[30,796,797,798,801],{},"Dynamic Properties - Added dynamic property support for ",[442,799,800],{},"UI-Text-Input"," widget.",[19,803,633],{"id":632},[15,805,440,806,445,809,450,812],{},[442,807,808],{},"1.16.0",[256,810,436],{"href":448,"rel":811},[402],[256,813,455],{"href":453,"rel":814},[402],{"title":265,"searchDepth":266,"depth":266,"links":816},[817,818,819,823,824],{"id":684,"depth":269,"text":685},{"id":702,"depth":269,"text":703},{"id":725,"depth":269,"text":726,"children":820},[821,822],{"id":732,"depth":274,"text":733},{"id":754,"depth":274,"text":755},{"id":427,"depth":269,"text":428},{"id":632,"depth":269,"text":633},"2024-08-28","Our latest update for FlowFuse Dashboard introduces a new layout type, Tabs, a new widget, Number Input, and two fresh gauges, Battery and Tank Level, along with much more.","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-2-1150-release.png",{"excerpt":829},{"type":12,"value":830},[831],[15,832,681],{},"\u002Fblog\u002F2024\u002F08\u002Fdashboard-new-layout-widgets-and-gauges",{"title":675,"description":826},{"loc":833},"blog\u002F2024\u002F08\u002Fdashboard-new-layout-widgets-and-gauges",[487,488,302,303],"XzOm2JgJ-mdlectcyqrvxgD5fUGbuVE1YlHHAap8ZLs",{"id":840,"title":841,"authors":842,"body":843,"cta":2145,"date":2148,"description":2149,"extension":287,"image":2150,"lastUpdated":659,"meta":2151,"navigation":295,"path":2157,"seo":2158,"sitemap":2159,"stem":2160,"subtitle":2161,"tags":2162,"tldr":2165,"video":3,"__hash__":2166},"blog\u002Fblog\u002F2024\u002F08\u002Fcustomise-theming-in-your-dashboards.md","Customise theming in your FlowFuse Dashboard (2026)",[10],{"type":12,"value":844,"toc":2122},[845,848,851,854,858,871,875,882,891,896,899,902,911,920,932,936,980,1248,1257,1266,1270,1280,1303,1345,1357,1366,1370,1377,1386,1390,1399,1420,1435,1843,1853,1857,1866,1870,1882,1926,1930,1940,1968,1972,1975,1978,1984,1990,1995,2004,2007,2011,2014,2023,2027,2030,2039,2043,2046,2055,2059,2062,2065,2073,2082,2090,2099,2104,2112,2116,2119],[15,846,847],{},"A recent release of FlowFuse Dashboard (Dashboard 2.0) has taken customization to the next level.",[15,849,850],{},"Previously, users enjoyed the flexibility of tweaking navigation sidebars, themes, and group and page padding. With the new update, you can fully personalize the header too, adding unique elements to enhance your dashboard experience and customize your application to your own branding.",[15,852,853],{},"In this article, we'll delve into these exciting new features, including theme adjustments, custom styling, and layout modifications, that empower you to tailor your Node-RED Dashboard like never before.",[19,855,857],{"id":856},"adding-elements-in-the-header","Adding Elements in the Header",[15,859,860,861,866,867,870],{},"To add elements to the header, we can use ",[256,862,865],{"href":863,"rel":864},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#teleports",[402],"Teleports"," within the ",[442,868,869],{},"ui-template"," node. This allows elements to be seamlessly rendered in specific areas of the dashboard. This method simplifies the process compared to manually positioning items with CSS, which can be complex, time-consuming, and potentially disruptive to other dashboard elements.",[82,872,874],{"id":873},"left-side-of-the-header","Left Side of the Header",[15,876,877,878,881],{},"To render content on the left side of the header, we can teleport content into the ",[442,879,880],{},"#app-bar-title"," element, where our page name is displayed.",[15,883,884,889],{},[239,885],{"alt":886,"dataZoomable":265,"src":887,"title":888},"\"Screenshot of Dashboard showing the #app-bar-title container\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fleft-side-area.png","Image of Dashboard showing the #app-bar-title container",[333,890,888],{},[892,893,895],"h4",{"id":894},"hiding-the-page-name-in-the-header","Hiding the Page Name in the Header",[15,897,898],{},"Before proceeding, you should hide the page name on the left side of the header by default. This will ensure that when you add elements to the header, they do not clash with the page name.",[15,900,901],{},"To hide the page name:",[903,904,905,908],"ol",{},[30,906,907],{},"Go to the FlowFuse Dashboard sidebar",[30,909,910],{},"Click on to the \"Edit settings\" option located at the top of the FlowFuse Dashboard sidebar.",[15,912,913,918],{},[239,914],{"alt":915,"dataZoomable":265,"src":916,"title":917},"\"Screenshot showing the 'edit setting' option in the dashboard sidebar\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fedit-setting-button.png","Screenshot showing the 'edit setting' option in the dashboard sidebar",[333,919,917],{},[903,921,922],{"start":274},[30,923,924,925,930],{},"Untick the option \"Show page name in the header bar\".\n",[239,926],{"alt":927,"dataZoomable":265,"src":928,"title":929},"\"Screenshot showing the 'Show page name in the header bar' option in the dashboard settings\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fsettings.png","Screenshot showing the 'Show page name in the header bar' option in the dashboard settings",[333,931,929],{},[892,933,935],{"id":934},"example-adding-buttons","Example: Adding Buttons",[903,937,938,944,965,974],{},[30,939,940,941,943],{},"Drag a ",[442,942,869],{}," node onto the Node-RED Editor canvas.",[30,945,946,947,950,951,954,955,957,958,961,962,964],{},"Double-click on it and select the scope to either ",[442,948,949],{},"ui-scope"," or ",[442,952,953],{},"page-scope",". Selecting ",[442,956,949],{}," will render this content on ",[333,959,960],{},"all"," pages. ",[442,963,953],{}," will just render to a specified page.",[30,966,967,968,970,971,973],{},"Choose the page on which you want to render the buttons if you selected ",[442,969,953],{},", or choose correct ui if ",[442,972,949],{}," is selected.",[30,975,976,977,979],{},"Paste the following Vue snippet into the template widget. In this snippet, note how we specify the \"to\" attribute targeting the ",[442,978,880],{}," ID in the teleport tag:",[981,982,986],"pre",{"className":983,"code":984,"language":985,"meta":265,"style":265},"language-html shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Ctemplate>\n    \u003C!-- Teleport the button to the #app-bar-actions area when mounted -->\n    \u003CTeleport v-if=\"mounted\" to=\"#app-bar-title\">\n        \u003Cv-btn>Button 1\u003C\u002Fv-btn>\n        \u003Cv-btn>Button 2\u003C\u002Fv-btn>\n        \u003Cv-btn>Button 3\u003C\u002Fv-btn>\n    \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n    export default {\n        data() {\n            return {\n                mounted: false\n            }\n        },\n        mounted() {\n            \u002F\u002F Set mounted to true when the component is mounted\n            this.mounted = true\n        }\n    }\n\u003C\u002Fscript>\n","html",[442,987,988,1004,1010,1047,1069,1087,1105,1115,1124,1130,1140,1153,1164,1172,1185,1191,1197,1207,1213,1227,1233,1239],{"__ignoreMap":265},[989,990,993,997,1001],"span",{"class":991,"line":992},"line",1,[989,994,996],{"class":995},"sMK4o","\u003C",[989,998,1000],{"class":999},"swJcz","template",[989,1002,1003],{"class":995},">\n",[989,1005,1006],{"class":991,"line":269},[989,1007,1009],{"class":1008},"sHwdD","    \u003C!-- Teleport the button to the #app-bar-actions area when mounted -->\n",[989,1011,1012,1015,1018,1022,1025,1028,1032,1034,1037,1039,1041,1043,1045],{"class":991,"line":274},[989,1013,1014],{"class":995},"    \u003C",[989,1016,1017],{"class":999},"Teleport",[989,1019,1021],{"class":1020},"spNyl"," v-if",[989,1023,1024],{"class":995},"=",[989,1026,1027],{"class":995},"\"",[989,1029,1031],{"class":1030},"sfazB","mounted",[989,1033,1027],{"class":995},[989,1035,1036],{"class":1020}," to",[989,1038,1024],{"class":995},[989,1040,1027],{"class":995},[989,1042,880],{"class":1030},[989,1044,1027],{"class":995},[989,1046,1003],{"class":995},[989,1048,1049,1052,1055,1058,1062,1065,1067],{"class":991,"line":266},[989,1050,1051],{"class":995},"        \u003C",[989,1053,1054],{"class":999},"v-btn",[989,1056,1057],{"class":995},">",[989,1059,1061],{"class":1060},"sTEyZ","Button 1",[989,1063,1064],{"class":995},"\u003C\u002F",[989,1066,1054],{"class":999},[989,1068,1003],{"class":995},[989,1070,1072,1074,1076,1078,1081,1083,1085],{"class":991,"line":1071},5,[989,1073,1051],{"class":995},[989,1075,1054],{"class":999},[989,1077,1057],{"class":995},[989,1079,1080],{"class":1060},"Button 2",[989,1082,1064],{"class":995},[989,1084,1054],{"class":999},[989,1086,1003],{"class":995},[989,1088,1090,1092,1094,1096,1099,1101,1103],{"class":991,"line":1089},6,[989,1091,1051],{"class":995},[989,1093,1054],{"class":999},[989,1095,1057],{"class":995},[989,1097,1098],{"class":1060},"Button 3",[989,1100,1064],{"class":995},[989,1102,1054],{"class":999},[989,1104,1003],{"class":995},[989,1106,1108,1111,1113],{"class":991,"line":1107},7,[989,1109,1110],{"class":995},"    \u003C\u002F",[989,1112,1017],{"class":999},[989,1114,1003],{"class":995},[989,1116,1118,1120,1122],{"class":991,"line":1117},8,[989,1119,1064],{"class":995},[989,1121,1000],{"class":999},[989,1123,1003],{"class":995},[989,1125,1127],{"class":991,"line":1126},9,[989,1128,1129],{"emptyLinePlaceholder":295},"\n",[989,1131,1133,1135,1138],{"class":991,"line":1132},10,[989,1134,996],{"class":995},[989,1136,1137],{"class":999},"script",[989,1139,1003],{"class":995},[989,1141,1143,1147,1150],{"class":991,"line":1142},11,[989,1144,1146],{"class":1145},"s7zQu","    export",[989,1148,1149],{"class":1145}," default",[989,1151,1152],{"class":995}," {\n",[989,1154,1156,1159,1162],{"class":991,"line":1155},12,[989,1157,1158],{"class":999},"        data",[989,1160,1161],{"class":995},"()",[989,1163,1152],{"class":995},[989,1165,1167,1170],{"class":991,"line":1166},13,[989,1168,1169],{"class":1145},"            return",[989,1171,1152],{"class":995},[989,1173,1175,1178,1181],{"class":991,"line":1174},14,[989,1176,1177],{"class":999},"                mounted",[989,1179,1180],{"class":995},":",[989,1182,1184],{"class":1183},"sfNiH"," false\n",[989,1186,1188],{"class":991,"line":1187},15,[989,1189,1190],{"class":995},"            }\n",[989,1192,1194],{"class":991,"line":1193},16,[989,1195,1196],{"class":995},"        },\n",[989,1198,1200,1203,1205],{"class":991,"line":1199},17,[989,1201,1202],{"class":999},"        mounted",[989,1204,1161],{"class":995},[989,1206,1152],{"class":995},[989,1208,1210],{"class":991,"line":1209},18,[989,1211,1212],{"class":1008},"            \u002F\u002F Set mounted to true when the component is mounted\n",[989,1214,1216,1219,1221,1224],{"class":991,"line":1215},19,[989,1217,1218],{"class":995},"            this.",[989,1220,1031],{"class":1060},[989,1222,1223],{"class":995}," =",[989,1225,1226],{"class":1183}," true\n",[989,1228,1230],{"class":991,"line":1229},20,[989,1231,1232],{"class":995},"        }\n",[989,1234,1236],{"class":991,"line":1235},21,[989,1237,1238],{"class":995},"    }\n",[989,1240,1242,1244,1246],{"class":991,"line":1241},22,[989,1243,1064],{"class":995},[989,1245,1137],{"class":999},[989,1247,1003],{"class":995},[903,1249,1250],{"start":1071},[30,1251,1252,1253,1256],{},"Next, you can customize further by adding more buttons or different elements inside the ",[442,1254,1255],{},"\u003CTeleport>"," element.",[15,1258,1259,1264],{},[239,1260],{"alt":1261,"dataZoomable":265,"src":1262,"title":1263},"\"Screenshot of Dashboard showing the added buttons in the header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fbutton-added-dashboard.png","Screenshot of Dashboard showing the added buttons in the header",[333,1265,1263],{},[892,1267,1269],{"id":1268},"example-adding-logo","Example: Adding Logo",[15,1271,1272,1273],{},"If you want to add your brand's logo, you can replace the element inside ",[1274,1275,1276,1277,1279],"teleport",{}," with an ",[239,1278],{}," tag. You can do this in the same ui-template widget or in a different ui-template widget:",[903,1281,1282,1288,1291,1294],{},[30,1283,1284,1285,1287],{},"Drag the ",[442,1286,869],{}," node onto the canvas.",[30,1289,1290],{},"Select the correct scope for that widget to render.",[30,1292,1293],{},"Select the correct page or UI in which you want to render the element.",[30,1295,1296,1297,1299,1300],{},"Paste the same Vue snippet given in the above section into the ",[442,1298,869],{}," widget and replace the code inside ",[1274,1301,1302],{}," with the following element:",[981,1304,1306],{"className":983,"code":1305,"language":985,"meta":265,"style":265},"\u003Cimg height=\"32px\" src=\"https:\u002F\u002Fapp.flowfuse.com\u002Fff-logo--wordmark-caps--dark.png\">\u003C\u002Fimg>\n",[442,1307,1308],{"__ignoreMap":265},[989,1309,1310,1312,1314,1317,1319,1321,1324,1326,1329,1331,1333,1336,1338,1341,1343],{"class":991,"line":992},[989,1311,996],{"class":995},[989,1313,239],{"class":999},[989,1315,1316],{"class":1020}," height",[989,1318,1024],{"class":995},[989,1320,1027],{"class":995},[989,1322,1323],{"class":1030},"32px",[989,1325,1027],{"class":995},[989,1327,1328],{"class":1020}," src",[989,1330,1024],{"class":995},[989,1332,1027],{"class":995},[989,1334,1335],{"class":1030},"https:\u002F\u002Fapp.flowfuse.com\u002Fff-logo--wordmark-caps--dark.png",[989,1337,1027],{"class":995},[989,1339,1340],{"class":995},">\u003C\u002F",[989,1342,239],{"class":999},[989,1344,1003],{"class":995},[15,1346,1347,1348,1351,1352,437],{},"You can replace the URL with your logo's URL or set it using the ",[442,1349,1350],{},"msg.payload"," as shown in examples given ",[256,1353,1356],{"href":1354,"rel":1355},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#page-name-app-bar-title",[402],"documentation",[15,1358,1359,1364],{},[239,1360],{"alt":1361,"dataZoomable":265,"src":1362,"title":1363},"\"Screenshot of the Dashboard displaying the added logo in the header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Flogo-added-dashboard.png","Screenshot of the Dashboard displaying the added logo in the header",[333,1365,1363],{},[82,1367,1369],{"id":1368},"right-side-of-the-header","Right Side of the Header",[15,1371,1372,1373,1376],{},"To render elements on the right side of the header, you can use the empty div element having the ",[442,1374,1375],{},"#app-bar-actions"," ID, in which we can add elements.",[15,1378,1379,1384],{},[239,1380],{"alt":1381,"dataZoomable":265,"src":1382,"title":1383},"\"Screenshot of Dashboard showing the #app-bar-actions container\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fright-side-area.png","Screenshot of Dashboard showing the #app-bar-actions container",[333,1385,1383],{},[892,1387,1389],{"id":1388},"example-adding-logged-in-user-profile","Example: Adding logged in user profile",[15,1391,1392,1397],{},[239,1393],{"alt":1394,"dataZoomable":265,"src":1395,"title":1396},"\"Screenshot of Dashboard displaying the logged in user profile at the right side of header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fuser-profile.png","Screenshot of Dashboard displaying the logged in user profile at the right side of header",[333,1398,1396],{},[15,1400,1401,1402,1406,1407,1410,1411,1416,1417,437],{},"In this section, we will add the user profile of the currently logged-in user to the right side of the header. Make sure you have installed \"@flowfuse\u002Fnode-red-dashboard-2-user-addon\" via the palette manager and enabled ",[256,1403,1405],{"href":1404},"\u002Fdocs\u002Fuser\u002Finstance-settings\u002F#flowfuse-user-authentication","FlowFuse User Authentication",". Each message emitted by the FlowFuse Dashboard widget will include the logged-in user information under ",[442,1408,1409],{},"msg._client.user",". Additionally the ",[256,1412,1415],{"href":1413,"rel":1414},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fguides\u002Fstate-management.html#setup-store",[402],"setup object"," will also contain this information under ",[442,1418,1419],{},"setup.socketio.auth.user",[903,1421,1422,1425,1427,1429],{},[30,1423,1424],{},"Drag the ui-template widget onto the canvas.",[30,1426,1290],{},[30,1428,1293],{},[30,1430,1431,1432,1434],{},"Paste the same Vue snippet given below into the ",[442,1433,869],{}," widget:",[981,1436,1438],{"className":983,"code":1437,"language":985,"meta":265,"style":265},"\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",[442,1439,1440,1448,1453,1482,1502,1507,1529,1534,1551,1560,1568,1576,1580,1588,1597,1606,1613,1618,1627,1632,1637,1646,1651,1657,1663,1669,1688,1693,1699,1708,1713,1723,1729,1739,1754,1767,1781,1786,1792,1804,1817,1829,1834],{"__ignoreMap":265},[989,1441,1442,1444,1446],{"class":991,"line":992},[989,1443,996],{"class":995},[989,1445,1000],{"class":999},[989,1447,1003],{"class":995},[989,1449,1450],{"class":991,"line":269},[989,1451,1452],{"class":1008},"    \u003C!-- Teleporting user info to #app-bar-actions, which is the ID of the action bars' right corners area -->\n",[989,1454,1455,1457,1459,1461,1463,1465,1468,1470,1472,1474,1476,1478,1480],{"class":991,"line":274},[989,1456,1014],{"class":995},[989,1458,1017],{"class":999},[989,1460,1021],{"class":1020},[989,1462,1024],{"class":995},[989,1464,1027],{"class":995},[989,1466,1467],{"class":1030},"loaded",[989,1469,1027],{"class":995},[989,1471,1036],{"class":1020},[989,1473,1024],{"class":995},[989,1475,1027],{"class":995},[989,1477,1375],{"class":1030},[989,1479,1027],{"class":995},[989,1481,1003],{"class":995},[989,1483,1484,1486,1488,1491,1493,1495,1498,1500],{"class":991,"line":266},[989,1485,1051],{"class":995},[989,1487,228],{"class":999},[989,1489,1490],{"class":1020}," class",[989,1492,1024],{"class":995},[989,1494,1027],{"class":995},[989,1496,1497],{"class":1030},"user-info",[989,1499,1027],{"class":995},[989,1501,1003],{"class":995},[989,1503,1504],{"class":991,"line":1071},[989,1505,1506],{"class":1008},"            \u003C!-- Displaying user image -->\n",[989,1508,1509,1512,1514,1517,1519,1521,1524,1526],{"class":991,"line":1089},[989,1510,1511],{"class":995},"            \u003C",[989,1513,239],{"class":999},[989,1515,1516],{"class":1020}," :src",[989,1518,1024],{"class":995},[989,1520,1027],{"class":995},[989,1522,1523],{"class":1030},"setup.socketio.auth.user.image",[989,1525,1027],{"class":995},[989,1527,1528],{"class":995}," \u002F>\n",[989,1530,1531],{"class":991,"line":1107},[989,1532,1533],{"class":1008},"            \u003C!-- Greeting the user -->\n",[989,1535,1536,1538,1540,1542,1545,1547,1549],{"class":991,"line":1117},[989,1537,1511],{"class":995},[989,1539,989],{"class":999},[989,1541,1057],{"class":995},[989,1543,1544],{"class":1060},"Hi, {{ setup.socketio.auth.user.name }}",[989,1546,1064],{"class":995},[989,1548,989],{"class":999},[989,1550,1003],{"class":995},[989,1552,1553,1556,1558],{"class":991,"line":1126},[989,1554,1555],{"class":995},"        \u003C\u002F",[989,1557,228],{"class":999},[989,1559,1003],{"class":995},[989,1561,1562,1564,1566],{"class":991,"line":1132},[989,1563,1110],{"class":995},[989,1565,1017],{"class":999},[989,1567,1003],{"class":995},[989,1569,1570,1572,1574],{"class":991,"line":1142},[989,1571,1064],{"class":995},[989,1573,1000],{"class":999},[989,1575,1003],{"class":995},[989,1577,1578],{"class":991,"line":1155},[989,1579,1129],{"emptyLinePlaceholder":295},[989,1581,1582,1584,1586],{"class":991,"line":1166},[989,1583,996],{"class":995},[989,1585,1137],{"class":999},[989,1587,1003],{"class":995},[989,1589,1590,1593,1595],{"class":991,"line":1174},[989,1591,1592],{"class":1145},"export",[989,1594,1149],{"class":1145},[989,1596,1152],{"class":995},[989,1598,1599,1602,1604],{"class":991,"line":1187},[989,1600,1601],{"class":999},"    data",[989,1603,1161],{"class":995},[989,1605,1152],{"class":995},[989,1607,1608,1611],{"class":991,"line":1193},[989,1609,1610],{"class":1145},"        return",[989,1612,1152],{"class":995},[989,1614,1615],{"class":991,"line":1199},[989,1616,1617],{"class":1008},"            \u002F\u002F Flag to indicate if the component is loaded\n",[989,1619,1620,1623,1625],{"class":991,"line":1209},[989,1621,1622],{"class":999},"            loaded",[989,1624,1180],{"class":995},[989,1626,1184],{"class":1183},[989,1628,1629],{"class":991,"line":1215},[989,1630,1631],{"class":995},"        };\n",[989,1633,1634],{"class":991,"line":1229},[989,1635,1636],{"class":995},"    },\n",[989,1638,1639,1642,1644],{"class":991,"line":1235},[989,1640,1641],{"class":999},"    mounted",[989,1643,1161],{"class":995},[989,1645,1152],{"class":995},[989,1647,1648],{"class":991,"line":1241},[989,1649,1650],{"class":1008},"        \u002F\u002F This function is called when the component is inserted into the DOM.\n",[989,1652,1654],{"class":991,"line":1653},23,[989,1655,1656],{"class":1008},"        \u002F\u002F Setting loaded to true here ensures the component is ready to access #app-bar-actions,\n",[989,1658,1660],{"class":991,"line":1659},24,[989,1661,1662],{"class":1008},"        \u002F\u002F as it's now part of the same DOM structure.\n",[989,1664,1666],{"class":991,"line":1665},25,[989,1667,1668],{"class":1008},"        \u002F\u002F Accessing it before mounted() would cause an error because the component wouldn't be initialized in the DOM yet.\n",[989,1670,1672,1675,1677,1679,1682,1685],{"class":991,"line":1671},26,[989,1673,1674],{"class":995},"        this.",[989,1676,1467],{"class":1060},[989,1678,1223],{"class":995},[989,1680,1681],{"class":1183}," true",[989,1683,1684],{"class":995},";",[989,1686,1687],{"class":1008}," \u002F\u002F Setting loaded to true to indicate that the component has been mounted successfully\n",[989,1689,1691],{"class":991,"line":1690},27,[989,1692,1238],{"class":995},[989,1694,1696],{"class":991,"line":1695},28,[989,1697,1698],{"class":995},"}\n",[989,1700,1702,1704,1706],{"class":991,"line":1701},29,[989,1703,1064],{"class":995},[989,1705,1137],{"class":999},[989,1707,1003],{"class":995},[989,1709,1711],{"class":991,"line":1710},30,[989,1712,1129],{"emptyLinePlaceholder":295},[989,1714,1716,1718,1721],{"class":991,"line":1715},31,[989,1717,996],{"class":995},[989,1719,1720],{"class":999},"style",[989,1722,1003],{"class":995},[989,1724,1726],{"class":991,"line":1725},32,[989,1727,1728],{"class":1008},"\u002F* Styling for user info display *\u002F\n",[989,1730,1732,1734,1737],{"class":991,"line":1731},33,[989,1733,437],{"class":995},[989,1735,1497],{"class":1736},"sBMFI",[989,1738,1152],{"class":995},[989,1740,1742,1746,1748,1751],{"class":991,"line":1741},34,[989,1743,1745],{"class":1744},"sqsOY","    display",[989,1747,1180],{"class":995},[989,1749,1750],{"class":1060}," flex",[989,1752,1753],{"class":995},";\n",[989,1755,1757,1760,1762,1765],{"class":991,"line":1756},35,[989,1758,1759],{"class":1744},"    align-items",[989,1761,1180],{"class":995},[989,1763,1764],{"class":1060}," center",[989,1766,1753],{"class":995},[989,1768,1770,1773,1775,1779],{"class":991,"line":1769},36,[989,1771,1772],{"class":1744},"    gap",[989,1774,1180],{"class":995},[989,1776,1778],{"class":1777},"sbssI"," 8px",[989,1780,1753],{"class":995},[989,1782,1784],{"class":991,"line":1783},37,[989,1785,1698],{"class":995},[989,1787,1789],{"class":991,"line":1788},38,[989,1790,1791],{"class":1008},"\u002F* Styling for user avatar image*\u002F\n",[989,1793,1795,1797,1799,1802],{"class":991,"line":1794},39,[989,1796,437],{"class":995},[989,1798,1497],{"class":1736},[989,1800,1801],{"class":1736}," img",[989,1803,1152],{"class":995},[989,1805,1807,1810,1812,1815],{"class":991,"line":1806},40,[989,1808,1809],{"class":1744},"    width",[989,1811,1180],{"class":995},[989,1813,1814],{"class":1777}," 24px",[989,1816,1753],{"class":995},[989,1818,1820,1823,1825,1827],{"class":991,"line":1819},41,[989,1821,1822],{"class":1744},"    height",[989,1824,1180],{"class":995},[989,1826,1814],{"class":1777},[989,1828,1753],{"class":995},[989,1830,1832],{"class":991,"line":1831},42,[989,1833,1698],{"class":995},[989,1835,1837,1839,1841],{"class":991,"line":1836},43,[989,1838,1064],{"class":995},[989,1840,1720],{"class":999},[989,1842,1003],{"class":995},[15,1844,1845,1846,1850,1851,437],{},"For detailed guide on this section, refer to the guide on ",[256,1847,1849],{"href":1848},"\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard\u002F","Displaying logged in user on FlowFuse Dashboard",". Furthermore, if you want to add logos or buttons on the right side similar to the left side of the header, you just need to replace the to attribute with the ",[442,1852,1375],{},[82,1854,1856],{"id":1855},"centering-header-items","Centering Header Items",[15,1858,1859,1860,1862,1863,1865],{},"Sometimes you may want to center or position items added to either the ",[442,1861,880],{}," or the ",[442,1864,1375],{},". By default, these elements do not have a specified width, and when you add items into them, they grow to fit their content. To center the elements, you first need to ensure that they are sized appropriately.",[892,1867,1869],{"id":1868},"centering-items-in-the-left-side-of-the-header","Centering Items in the Left Side of the Header",[15,1871,1872,1873,1875,1876,1879,1880,1434],{},"To center items added to the ",[442,1874,880],{},", apply the following CSS in the ",[442,1877,1878],{},"\u003Cstyle>"," tag of the ",[442,1881,869],{},[981,1883,1887],{"className":1884,"code":1885,"language":1886,"meta":265,"style":265},"language-css shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","#app-bar-title {\n    flex-grow: 1;\n    justify-content: center;\n}\n","css",[442,1888,1889,1899,1911,1922],{"__ignoreMap":265},[989,1890,1891,1894,1897],{"class":991,"line":992},[989,1892,1893],{"class":995},"#",[989,1895,1896],{"class":1777},"app-bar-title",[989,1898,1152],{"class":995},[989,1900,1901,1904,1906,1909],{"class":991,"line":269},[989,1902,1903],{"class":1744},"    flex-grow",[989,1905,1180],{"class":995},[989,1907,1908],{"class":1777}," 1",[989,1910,1753],{"class":995},[989,1912,1913,1916,1918,1920],{"class":991,"line":274},[989,1914,1915],{"class":1744},"    justify-content",[989,1917,1180],{"class":995},[989,1919,1764],{"class":1060},[989,1921,1753],{"class":995},[989,1923,1924],{"class":991,"line":266},[989,1925,1698],{"class":995},[892,1927,1929],{"id":1928},"centering-items-in-the-right-side-of-the-header","Centering Items in the Right Side of the Header",[15,1931,1932,1933,1935,1936,1879,1938,1434],{},"To center items in the ",[442,1934,1375],{}," area, add the following CSS to the ",[442,1937,1878],{},[442,1939,869],{},[981,1941,1943],{"className":1884,"code":1942,"language":1886,"meta":265,"style":265},"#v-toolbar__append {\n    flex-grow: 1;\n}\n",[442,1944,1945,1954,1964],{"__ignoreMap":265},[989,1946,1947,1949,1952],{"class":991,"line":992},[989,1948,1893],{"class":995},[989,1950,1951],{"class":1777},"v-toolbar__append",[989,1953,1152],{"class":995},[989,1955,1956,1958,1960,1962],{"class":991,"line":269},[989,1957,1903],{"class":1744},[989,1959,1180],{"class":995},[989,1961,1908],{"class":1777},[989,1963,1753],{"class":995},[989,1965,1966],{"class":991,"line":274},[989,1967,1698],{"class":995},[19,1969,1971],{"id":1970},"styling-header","Styling Header",[15,1973,1974],{},"One of the significant customization features we've added recently is the ability to style the header in different ways.",[15,1976,1977],{},"To style the header:",[903,1979,1980,1982],{},[30,1981,907],{},[30,1983,910],{},[15,1985,1986,1988],{},[239,1987],{"alt":915,"dataZoomable":265,"src":916,"title":917},[333,1989,917],{},[903,1991,1992],{"start":274},[30,1993,1994],{},"Select the desired option from the \"Header Options\" dropdown.",[15,1996,1997,2002],{},[239,1998],{"alt":1999,"dataZoomable":265,"src":2000,"title":2001},"\"Screenshot showing the header style options in the dashboard settings\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fheader-style-options.png","Screenshot showing the header style options in the dashboard settings",[333,2003,2001],{},[15,2005,2006],{},"The following options are available for header styling:",[82,2008,2010],{"id":2009},"default","Default",[15,2012,2013],{},"This option as it name suggest it is the default option set for header. In which the header will get hidden if we scrolled down.",[15,2015,2016,2021],{},[239,2017],{"alt":2018,"dataZoomable":265,"src":2019,"title":2020},"\"Image showing the dashboard with default header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdefault-header.gif","Image showing the dashboard with default header",[333,2022,2020],{},[82,2024,2026],{"id":2025},"hidden","Hidden",[15,2028,2029],{},"Selecting this option completely hides the header, allowing you to use that space for other purposes.",[15,2031,2032,2037],{},[239,2033],{"alt":2034,"dataZoomable":265,"src":2035,"title":2036},"\"Image showing the dashboard with hidden header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fhidden-header.png","Image showing the dashboard with hidden header",[333,2038,2036],{},[82,2040,2042],{"id":2041},"fixed","Fixed",[15,2044,2045],{},"Selecting this option keeps the header fixed at the top. This means that when you scroll the page down, the header will remain visible.",[15,2047,2048,2053],{},[239,2049],{"alt":2050,"dataZoomable":265,"src":2051,"title":2052},"\"Image showing the dashboard with fixed header\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Ffixed-header.gif","Image showing the dashboard with fixed header",[333,2054,2052],{},[19,2056,2058],{"id":2057},"changing-dashboard-theme","Changing Dashboard Theme",[15,2060,2061],{},"In this section of the guide, you will learn how to change the Dashboard theme, where you can adjust the colors of the header, navigation sidebar, group and page backgrounds, the border color of groups, and the padding, sizing, and gaps between pages, groups, and widgets.",[15,2063,2064],{},"To edit the existing theme:",[903,2066,2067,2070],{},[30,2068,2069],{},"Go to the FlowFuse Dashboard sidebar.",[30,2071,2072],{},"Switch to the \"Theme\" tab.",[15,2074,2075,2080],{},[239,2076],{"alt":2077,"dataZoomable":265,"src":2078,"title":2079},"\"Screenshot showing the dashboard theme tab in the sidebar\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-theme-tab.png","Screenshot showing the dashboard theme tab in the sidebar",[333,2081,2079],{},[903,2083,2084,2087],{"start":274},[30,2085,2086],{},"Click on the edit button next to the theme.",[30,2088,2089],{},"You can adjust the header color and the primary color (which applies to the navigation sidebar and elements like buttons and dropdowns) under the \"Primary\" section. In the \"Pages\" section, set the background color for pages, and in the \"Groups\" section, adjust the background color and border color of groups.",[15,2091,2092,2097],{},[239,2093],{"alt":2094,"dataZoomable":265,"src":2095,"title":2096},"\"Screenshot showing the theme properties dialog\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-theme-settings.png","Screenshot showing the theme properties dialog",[333,2098,2096],{},[903,2100,2101],{"start":1071},[30,2102,2103],{},"Under \"Sizing,\" adjust the page padding (the space between dashboard groups), the page border, group gap, group border radius (the thickness of the group border), and widget gap.",[15,2105,2106,2107,2111],{},"For more information on  theme, how to add new themes, and set themes for pages, refer to the ",[256,2108,2110],{"href":2109},"\u002Fblog\u002F2024\u002F05\u002Fnode-red-dashboard-2-layout-navigation-styling\u002F#understanding-dashboard-2.0-theme","Comprehensive guide: FlowFuse Dashboard layout, sidebar, and styling",". Additionally, this guide covers FlowFuse Dashboard layouts, themes, and custom styling in detail.",[19,2113,2115],{"id":2114},"conclusion","Conclusion",[15,2117,2118],{},"In this article, we explored FlowFuse Dashboard's new customization features. We focused on adding elements like buttons and logos to the header, and discussed styling options such as default, hidden, and fixed for headers. We also covered how to adjust dashboard themes to personalize colors and layout. These insights empower users to create more personalized and functional Node-RED dashboards.",[1720,2120,2121],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":265,"searchDepth":266,"depth":266,"links":2123},[2124,2138,2143,2144],{"id":856,"depth":269,"text":857,"children":2125},[2126,2131,2134],{"id":873,"depth":274,"text":874,"children":2127},[2128,2129,2130],{"id":894,"depth":266,"text":895},{"id":934,"depth":266,"text":935},{"id":1268,"depth":266,"text":1269},{"id":1368,"depth":274,"text":1369,"children":2132},[2133],{"id":1388,"depth":266,"text":1389},{"id":1855,"depth":274,"text":1856,"children":2135},[2136,2137],{"id":1868,"depth":266,"text":1869},{"id":1928,"depth":266,"text":1929},{"id":1970,"depth":269,"text":1971,"children":2139},[2140,2141,2142],{"id":2009,"depth":274,"text":2010},{"id":2025,"depth":274,"text":2026},{"id":2041,"depth":274,"text":2042},{"id":2057,"depth":269,"text":2058},{"id":2114,"depth":269,"text":2115},{"type":653,"title":2146,"description":2147},"Build Branded Node-RED Dashboards Your Way","FlowFuse gives you everything you need to build, customize, and deploy Node-RED Dashboard applications, with full theming control, multi-user support, and production-ready infrastructure built in.","2024-08-07","Discover the latest enhancements in FlowFuse Dashboard, including customizable headers, themes, and layout modifications to personalize your dashboard experience.","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fcustomize-theming-flowfuse-dashboard.png",{"keywords":2152,"excerpt":2153},"flowfuse dashboard theming, node-red dashboard customization, dashboard 2.0 header customization, dashboard custom logo, node-red dashboard theme, ui-template teleport, dashboard header styling",{"type":12,"value":2154},[2155],[15,2156,847],{},"\u002Fblog\u002F2024\u002F08\u002Fcustomise-theming-in-your-dashboards",{"title":841,"description":2149},{"loc":2157},"blog\u002F2024\u002F08\u002Fcustomise-theming-in-your-dashboards","Customising Headers, Themes, and Layouts in FlowFuse Dashboard",[487,303,2163,2164],"dashboard theming","how-to","FlowFuse Dashboard now supports deep visual customization including custom headers, themes, and layout modifications. Using Teleports inside the ui-template node, you can inject custom elements into specific dashboard areas without complex CSS. This guide covers adding header buttons, custom logos, modifying color themes, and adjusting group and page padding.","XH7aPap1yjzKY3O8JrBOUgGKuDkw12tTxVw0VoLsokc",{"id":2168,"title":2169,"authors":2170,"body":2171,"cta":2990,"date":2993,"description":2994,"extension":287,"image":2995,"lastUpdated":2996,"meta":2997,"navigation":295,"path":3003,"seo":3004,"sitemap":3005,"stem":3006,"subtitle":3007,"tags":3008,"tldr":3012,"video":3,"__hash__":3013},"blog\u002Fblog\u002F2024\u002F08\u002Fcomparing-dashboard-2-with-uibuilder.md","FlowFuse Dashboard vs UI-Builder: A Comprehensive Comparison",[10],{"type":12,"value":2172,"toc":2922},[2173,2176,2180,2184,2191,2195,2202,2206,2209,2212,2215,2218,2222,2234,2237,2240,2248,2251,2254,2257,2261,2264,2271,2283,2286,2293,2304,2308,2311,2314,2317,2320,2324,2327,2334,2337,2340,2344,2347,2362,2365,2368,2372,2375,2378,2381,2384,2387,2391,2394,2403,2406,2409,2413,2416,2419,2427,2430,2433,2436,2440,2443,2452,2456,2459,2463,2466,2469,2472,2475,2479,2482,2485,2488,2491,2495,2498,2501,2510,2513,2516,2525,2529,2532,2535,2538,2541,2545,2548,2557,2566,2569,2572,2575,2579,2914,2916,2919],[15,2174,2175],{},"When choosing a dashboard solution for Node-RED, two popular options are FlowFuse Dashboard (also known as Dashboard 2.0) and UI-Builder. This article compares these tools across several key areas, including installation, ease of use, development activity, and customizability, to help you decide which one best suits your needs.",[19,2177,2179],{"id":2178},"how-easy-is-it-to-install","How Easy is it to Install?",[82,2181,2183],{"id":2182},"flowfuse-dashboard","FlowFuse Dashboard",[15,2185,2186,2187,2190],{},"When searching for ",[442,2188,2189],{},"flowfuse\u002Fnode-red-dashboard"," on Google, the first result we get to the documentation, which is useful. However, in the Node-RED Palette Manager, finding the correct package can be confusing because there are many community third-party nodes and plugins that work with FlowFuse Dashboard. This can make it bit confusing for new users to locate the right package.",[82,2192,2194],{"id":2193},"ui-builder","UI-Builder",[15,2196,2197,2198,2201],{},"Finding UI-Builder is straightforward, as its package name ",[442,2199,2200],{},"node-red-contrib-uibuilder"," is distinct and easily identifiable both on Google and in the Node-RED Palette Manager. This clear naming helps users quickly locate the correct package.",[19,2203,2205],{"id":2204},"how-easy-is-it-to-get-started","How Easy is it to Get Started?",[82,2207,2183],{"id":2208},"flowfuse-dashboard-1",[15,2210,2211],{},"Getting started with FlowFuse Dashboard is relatively easy due to its low-code approach. It features a sidebar for managing UI widgets, themes, configurations, and settings, with intuitive navigation to the dashboard page. This makes it accessible for users with varying levels of technical expertise.",[82,2213,2194],{"id":2214},"ui-builder-1",[15,2216,2217],{},"UI-Builder can be more challenging to start with, as it does not follow a low-code approach and lacks a separate sidebar for managing UI elements. Navigating dashboards built with UI-Builder can be less straightforward, and it requires users to have a deeper understanding of coding and UI design principles.",[19,2219,2221],{"id":2220},"migrating-from-node-red-dashboard-dashboard-10","Migrating from Node-RED Dashboard (Dashboard 1.0)",[15,2223,2224,2229,2230,437],{},[256,2225,2228],{"href":2226,"rel":2227},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-dashboard",[402],"Node-RED Dashboard"," is a module that provides a set of nodes in Node-RED to quickly create user interfaces or live data dashboards. It was developed by one of the creators of Node-RED and is the most used and downloaded package in the Node-RED ecosystem. However, it is now deprecated. For more information, refer to ",[256,2231,2233],{"href":2232},"\u002Fblog\u002F2024\u002F06\u002Fdashboard-1-deprecated\u002F","Node-RED Dashboard Formally Deprecated",[82,2235,2183],{"id":2236},"flowfuse-dashboard-2",[15,2238,2239],{},"FlowFuse Dashboard is developed to replace the the deprecated standard Node-RED Dashboard. It retains the core concepts and UI elements but introduces more advanced options and configurations.",[15,2241,2242,2243,2247],{},"To facilitate the transition, FlowFuse, the creator of FlowFuse Dashboard, provides a ",[256,2244,2246],{"href":2245},"\u002Fplatform\u002Fdashboard\u002F#migration-service","migration service"," that simplifies migration of flows or projects from the Node-RED Dashboard to FlowFuse Dashboard. This service helps ensure a smoother migration process with minimal disruption.",[82,2249,2194],{"id":2250},"ui-builder-2",[15,2252,2253],{},"Migrating from Node-RED Dashboard 1 to UI-Builder is significantly more complex. UI-Builder does not follow the same concepts or provide the same UI elements as the Node-RED Dashboard.",[15,2255,2256],{},"Users will need to recreate their dashboards from scratch, as UI-Builder relies on custom coding and frontend frameworks rather than the predefined, low-code widgets of Node-RED Dashboard. This process can be overwhelming and requires a solid understanding of HTML, CSS and the frontend frameworks if you wanted use.",[19,2258,2260],{"id":2259},"how-active-is-the-projects-development","How Active is the Project's Development?",[82,2262,2183],{"id":2263},"flowfuse-dashboard-3",[15,2265,2266,2270],{},[256,2267,2183],{"href":2268,"rel":2269},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fgraphs\u002Fcontributors",[402],", which replaced Node-RED Dashboard 1.0 in 2023, has shown consistent and high development activity. The project benefits from a dedicated team that regularly updates and improves it, ensuring it remains current with user needs and technological advancements.",[15,2272,2273,2277,2280],{},[239,2274],{"alt":2275,"src":2276},"Screenshot of the FlowFuse Dashboard GitHub commit chart","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-2-commits.png",[2278,2279],"br",{},[333,2281,2282],{},"Screenshot of the FlowFuse Dashboard GitHub commit chart.",[82,2284,2194],{"id":2285},"ui-builder-3",[15,2287,2288,2292],{},[256,2289,2194],{"href":2290,"rel":2291},"https:\u002F\u002Fgithub.com\u002FTotallyInformation\u002Fnode-red-contrib-uibuilder\u002Fgraphs\u002Fcontributors",[402]," has been an active project for a long time and remains active. However, there has been a noticeable decline in development activity starting in early 2024. While the project continues to be maintained, it does not have a dedicated, full-time team.",[15,2294,2295,2299,2301],{},[239,2296],{"alt":2297,"src":2298},"Screenshot of the UI-Builder GitHub commit chart","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fui-builder-commits.png",[2278,2300],{},[333,2302,2303],{},"Screenshot of the UI-Builder GitHub commit chart.",[19,2305,2307],{"id":2306},"pre-built-ui-elements","Pre-Built UI Elements",[82,2309,2183],{"id":2310},"flowfuse-dashboard-4",[15,2312,2313],{},"FlowFuse Dashboard offers an extensive set of UI elements, including forms, dropdowns, tables, charts, and gauges that are super easy to use. These widgets are built with complex Vue.js components, but users are completely shielded from this complexity, allowing them to focus on ease of use. Additionally, if you want to create your own custom widget, you can do so with the ui-template node that accepts complete Vue components. By default, FlowFuse Dashboard supports the Vuetify library, which provides an extensive set of UI components.",[82,2315,2194],{"id":2316},"ui-builder-4",[15,2318,2319],{},"UI-Builder also offers a number of widgets, but these are not as user-friendly as those in FlowFuse Dashboard. Users must send a JSON config object, which can be complex for new users who lack knowledge of HTML\u002FCSS. Additionally, handling widget data requires using UI-Builder's methods, which can further increase complexity. However, UI-Builder's strength lies in its flexibility, allowing any HTML element to be used as a component, and it also supports the W3C standard web components. Despite this, users need to perform a lot of additional tasks to get everything set up and will have the hassle of writing things.",[19,2321,2323],{"id":2322},"changing-the-ui-at-runtime","Changing the UI at Runtime",[82,2325,2183],{"id":2326},"flowfuse-dashboard-5",[15,2328,2329,2330,2333],{},"FlowFuse Dashboard supports dynamic control of the UI via the msg object. Each UI widget supports the ",[442,2331,2332],{},"msg.ui_update"," property, which allows you to control and update UI components dynamically. For example, you can update form fields based on user input, dynamically insert or update options in a dropdown, or change the appearance of the UI by sending CSS classes or selecting options in dropdowns or radio buttons through msg.",[82,2335,2194],{"id":2336},"ui-builder-5",[15,2338,2339],{},"UI-Builder also supports dynamic UI updates and control. Similar to FlowFuse Dashboard, you can use messages to control the state and content of UI elements.",[19,2341,2343],{"id":2342},"data-visualization","Data Visualization",[82,2345,2183],{"id":2346},"flowfuse-dashboard-6",[15,2348,2349,2350,2355,2356,2361],{},"Monitoring devices is one of the core use cases for Node-RED, and FlowFuse Dashboard makes it easy to monitor device metrics with its built-in ",[256,2351,2354],{"href":2352,"rel":2353},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-chart.html",[402],"chart"," and ",[256,2357,2360],{"href":2358,"rel":2359},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-gauge.html",[402],"gauge widgets",". The chart widgets support various types, including line, bar, scatter, pie, and donut charts, while the gauge widgets offer options like tile, 3\u002F4 gauge, and half gauge. This range of built-in options simplifies the creation of visualizations for monitoring device metrics. Additionally, you can use Vuetify or other third-party libraries in the ui-template node if you need different types of charts.",[82,2363,2194],{"id":2364},"ui-builder-6",[15,2366,2367],{},"UI-Builder does not provide built-in charting options. However, you can add charts using third-party JavaScript libraries. This approach requires additional effort to integrate and configure the libraries, as well as writing the relevant JavaScript to render the charts. While this increases the complexity of creating visualizations, it offers more control and customization.",[19,2369,2371],{"id":2370},"building-layout","Building Layout",[82,2373,2183],{"id":2374},"flowfuse-dashboard-7",[15,2376,2377],{},"FlowFuse Dashboard offers a collection of pre-defined layouts to make it easy for users to get started quickly. These are available as a configuration for each \"Page\" of your application.",[15,2379,2380],{},"These predefined layouts provide a solid foundation for most applications. If you need a different layout, FlowFuse Dashboard is limited in it's customization in terms of positioning of elements.",[82,2382,2194],{"id":2383},"ui-builder-7",[15,2385,2386],{},"UI-Builder does not come with predefined layouts, which can make it more complex for users to get started. it does however, provides the flexibility to completely define your own layout using CSS. This approach allows for complete customization, but it requires users to have a good understanding of HTML and CSS. The lack of predefined layouts means users have to create their own from scratch, which can be time-consuming.",[19,2388,2390],{"id":2389},"responsiveness-on-mobile","Responsiveness on Mobile",[82,2392,2183],{"id":2393},"flowfuse-dashboard-8",[15,2395,2396,2397,2402],{},"FlowFuse Dashboard is designed with ",[256,2398,2401],{"href":2399,"rel":2400},"https:\u002F\u002Fdashboard.flowfuse.com\u002Flayouts\u002F",[402],"responsiveness"," in mind. It ensures that dashboards automatically adapt to different screen sizes and devices, providing a consistent user experience across desktops, tablets, and mobile devices. The dashboard elements are automatically adjusted to fit various resolutions, making it user-friendly for a wide audience.",[82,2404,2194],{"id":2405},"ui-builder-8",[15,2407,2408],{},"UI-Builder's support for different devices depends on the user's implementation. While it offers the potential for responsive designs, achieving this requires a good understanding of responsive design principles and CSS.",[19,2410,2412],{"id":2411},"how-much-customization-is-available","How Much Customization is Available?",[82,2414,2183],{"id":2415},"flowfuse-dashboard-9",[15,2417,2418],{},"FlowFuse Dashboard, built on Vue.js, offers a range of customization options through its widget configurations and settings.",[15,2420,2421,2422,2426],{},"While it provides predefined UI elements, users can override CSS and theming using the ",[256,2423,2425],{"href":2424},"\u002Fblog\u002F2023\u002F12\u002Fdashboard-0-10-0\u002F","ui_template"," widget to enhance the dashboard's appearance.",[15,2428,2429],{},"This same widget also provides functionality to develop custom components or widgets for your Dashboard. These must be built with a VueJS core, but do support the integration of third-party JavaScript libraries.",[82,2431,2194],{"id":2432},"ui-builder-9",[15,2434,2435],{},"UI-Builder provides extensive customization capabilities, enabling users to build and style UI elements from scratch. This flexibility is advantageous for those with a strong background in frontend development, as it supports any frontend framework or custom design approach. However, achieving the desired results requires significant time and expertise, as users need to handle the coding and styling for each UI element they create.",[19,2437,2439],{"id":2438},"can-it-be-installed-on-mobile","Can it be Installed on Mobile?",[82,2441,2183],{"id":2442},"flowfuse-dashboard-10",[15,2444,2445,2446,2451],{},"FlowFuse Dashboard is built and deployed as a Progressive Web App. This means whilst it's built as a web application, it can be ",[256,2447,2450],{"href":2448,"rel":2449},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fpwa.html#installing-dashboards-on-mobile",[402],"installed on your mobile device"," and run as a standalone application, behaving as if it was a native app.",[82,2453,2455],{"id":2454},"ui-builder-10","Ui-Builder",[15,2457,2458],{},"Dashboards built with UI-Builder, on the other hand, cannot be installed as an app. It is designed as a web-based tool for building custom UIs and does not support installation as a standalone application.",[19,2460,2462],{"id":2461},"how-about-performance-and-speed","How About Performance and Speed?",[82,2464,2183],{"id":2465},"flowfuse-dashboard-11",[15,2467,2468],{},"FlowFuse Dashboard provides reliable performance with efficient real-time updates. Initial page load times might be slower, particularly on mobile, but the overall performance is consistent and effective for dynamic dashboards.",[82,2470,2194],{"id":2471},"ui-builder-11",[15,2473,2474],{},"UI-Builder provides faster initial load times and smooth performance across customizations, ensuring high-speed interactions.",[19,2476,2478],{"id":2477},"how-is-the-overall-user-experience","How is the Overall User Experience?",[82,2480,2183],{"id":2481},"flowfuse-dashboard-12",[15,2483,2484],{},"FlowFuse Dashboard offers a user-friendly experience with its low-code approach, intuitive UI, and extensive documentation. Users can quickly create and customize dashboards without needing advanced coding skills, making it accessible to a wide range of users, from beginners to experienced developers. This allows users to focus on solving business problems and IoT tasks rather than getting bogged down by complex coding requirements.",[82,2486,2194],{"id":2487},"ui-builder-12",[15,2489,2490],{},"UI-Builder provides a more flexible but complex user experience. While it allows for greater customization and the use of any frontend framework, it requires a solid understanding of coding and design principles. This can be daunting for users without a background in web development, but it offers powerful capabilities for those who are comfortable with custom coding.",[19,2492,2494],{"id":2493},"how-active-is-the-user-community","How Active is the User Community?",[82,2496,2183],{"id":2497},"flowfuse-dashboard-13",[15,2499,2500],{},"FlowFuse Dashboard boasts a large and active user community. Users frequently participate in forums, contribute to discussions, and share custom solutions. The number of weekly downloads is growing rapidly, reflecting its high activity and popularity.",[15,2502,2503,2507],{},[239,2504],{"alt":2505,"src":2506},"\"Screenshot of the FlowFuse Dashboard package's weekly download chart from npm\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-2-download.png",[333,2508,2509],{},"Screenshot of the FlowFuse Dashboard package's weekly download chart from npm",[82,2511,2194],{"id":2512},"ui-builder-13",[15,2514,2515],{},"UI-Builder has a smaller but still active user community. While not as large as FlowFuse Dashboard's, it includes dedicated users who also engage in forums, contribute to discussions, and share their use cases and solutions.",[15,2517,2518,2522],{},[239,2519],{"alt":2520,"src":2521},"\"Screenshot of the Ui-Builder package's weekly download chart from npm\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fui-builder-downloads.png",[333,2523,2524],{},"Screenshot of the Ui-Builder package's weekly download chart from npm",[19,2526,2528],{"id":2527},"how-good-is-the-support-and-documentation","How Good is the Support and Documentation?",[82,2530,2183],{"id":2531},"flowfuse-dashboard-14",[15,2533,2534],{},"Support for FlowFuse Dashboard is robust, with assistance from both the FlowFuse team and the active Node-RED community. The documentation is comprehensive, easy to understand, and regularly updated. The team is also working on an interactive dashboard solution for previewing examples.",[82,2536,2194],{"id":2537},"ui-builder-14",[15,2539,2540],{},"UI-Builder also has good support, with active contributions from the author and the Node-RED community. The documentation is detailed but can be complex due to extensive use of technical language.",[19,2542,2544],{"id":2543},"what-are-the-future-development-plans","What are the future development plans?",[82,2546,2183],{"id":2547},"flowfuse-dashboard-15",[15,2549,2550,2551,2556],{},"FlowFuse Dashboard is actively working on enhancing its feature set. With extensive functionality already in place, the project also has ambitious plans to introduce more advanced features to better serve its users. You can track these developments on the ",[256,2552,2555],{"href":2553,"rel":2554},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F4",[402],"FlowFuse Dashboard GitHub project board",", where ongoing and upcoming features are documented.",[15,2558,2559,2563],{},[239,2560],{"alt":2561,"src":2562},"\"Screenshot of the FlowFuse Dashboard GitHub project board\"","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-2-project-plan.png",[333,2564,2565],{},"Screenshot of the FlowFuse Dashboard GitHub project board",[15,2567,2568],{},"Additionally, updates about new features and enhancements are also provided through social media, blogs, and the Node-RED forums, ensuring that users stay informed about the latest developments.",[82,2570,2194],{"id":2571},"ui-builder-15",[15,2573,2574],{},"UI-Builder does not have a publicly accessible project roadmap or a dedicated planning board for future updates. While development continues, details about forthcoming features and enhancements are regularly updated on the Node-RED Discourse forums by its author.",[19,2576,2578],{"id":2577},"summary-table","Summary Table",[2580,2581,2582,2596],"table",{},[2583,2584,2585],"thead",{},[2586,2587,2588,2592,2594],"tr",{},[2589,2590,2591],"th",{},"Feature",[2589,2593,2183],{},[2589,2595,2194],{},[2597,2598,2599,2626,2644,2663,2682,2701,2718,2739,2747,2766,2785,2803,2822,2840,2858,2876,2895],"tbody",{},[2586,2600,2601,2607,2616],{},[2602,2603,2604],"td",{},[33,2605,2606],{},"Ease of Installation",[2602,2608,2609,2612,2613,2615],{},[33,2610,2611],{},"Moderately easy",": Search for ",[442,2614,2189],{}," can be confusing due to multiple nodes; useful documentation available",[2602,2617,2618,2621,2622,2625],{},[33,2619,2620],{},"Easy",": Clear package name ",[442,2623,2624],{},"node-red-ui-builder"," makes it straightforward to find",[2586,2627,2628,2633,2638],{},[2602,2629,2630],{},[33,2631,2632],{},"Ease of Getting Started",[2602,2634,2635,2637],{},[33,2636,2620],{},": Low-code interface with a sidebar for managing UI elements; intuitive for users of varying technical skills",[2602,2639,2640,2643],{},[33,2641,2642],{},"Challenging",": Requires understanding of coding and UI design; lacks a low-code approach",[2586,2645,2646,2651,2657],{},[2602,2647,2648],{},[33,2649,2650],{},"Migration from Node-RED Dashboard",[2602,2652,2653,2656],{},[33,2654,2655],{},"Smooth",": Migration service provided to transition from Node-RED Dashboard 1 to FlowFuse Dashboard",[2602,2658,2659,2662],{},[33,2660,2661],{},"Complex",": Requires rebuilding dashboards from scratch; significant effort needed for migration",[2586,2664,2665,2670,2676],{},[2602,2666,2667],{},[33,2668,2669],{},"Development Activity",[2602,2671,2672,2675],{},[33,2673,2674],{},"High",": Regular updates and improvements; actively maintained by a dedicated team",[2602,2677,2678,2681],{},[33,2679,2680],{},"Moderate",": Active but shows a decline in updates; less frequent enhancements",[2586,2683,2684,2689,2695],{},[2602,2685,2686],{},[33,2687,2688],{},"UI Elements Collection",[2602,2690,2691,2694],{},[33,2692,2693],{},"Extensive",": Includes a wide range of widgets like forms, charts, and gauges; built on Vue.js with Vuetify support",[2602,2696,2697,2700],{},[33,2698,2699],{},"Flexible but complex",": Allows any HTML element; requires custom coding and handling of UI elements",[2586,2702,2703,2708,2713],{},[2602,2704,2705],{},[33,2706,2707],{},"Visualization",[2602,2709,2710,2712],{},[33,2711,2620],{},": Built-in charting options for various types; additional options with third-party libraries",[2602,2714,2715,2717],{},[33,2716,2661],{},": No built-in charts; requires integration of third-party libraries for visualization",[2586,2719,2720,2725,2734],{},[2602,2721,2722],{},[33,2723,2724],{},"Dynamic UI Control",[2602,2726,2727,2730,2731,2733],{},[33,2728,2729],{},"Supported",": Can dynamically control and update UI components using ",[442,2732,2332],{}," property",[2602,2735,2736,2738],{},[33,2737,2729],{},": Dynamic updates possible, but can be more complex to implement",[2586,2740,2741,2743,2745],{},[2602,2742],{},[2602,2744],{},[2602,2746],{},[2586,2748,2749,2754,2760],{},[2602,2750,2751],{},[33,2752,2753],{},"Web Layout Support",[2602,2755,2756,2759],{},[33,2757,2758],{},"Predefined",": Offers three main layouts with some options for custom styling",[2602,2761,2762,2765],{},[33,2763,2764],{},"Customizable",": No predefined layouts; users must create their own using CSS",[2586,2767,2768,2773,2779],{},[2602,2769,2770],{},[33,2771,2772],{},"Device and Screen Size Support",[2602,2774,2775,2778],{},[33,2776,2777],{},"Excellent",": Responsive design adapts well to various devices and screen sizes",[2602,2780,2781,2784],{},[33,2782,2783],{},"Variable",": Responsiveness depends on user's implementation and knowledge of CSS",[2586,2786,2787,2792,2798],{},[2602,2788,2789],{},[33,2790,2791],{},"Customization",[2602,2793,2794,2797],{},[33,2795,2796],{},"Good",": Offers customization through widget settings and custom CSS and ui-template; supports Vue components and third-party libraries",[2602,2799,2800,2802],{},[33,2801,2674],{},": Full control over UI design and layout with custom coding; requires expertise in frontend development",[2586,2804,2805,2810,2816],{},[2602,2806,2807],{},[33,2808,2809],{},"App Installation",[2602,2811,2812,2815],{},[33,2813,2814],{},"Available",": Can be installed as a Progressive Web App (PWA) for use as a standalone application",[2602,2817,2818,2821],{},[33,2819,2820],{},"Not available",": Designed as a web-based tool; cannot be installed as an app",[2586,2823,2824,2829,2835],{},[2602,2825,2826],{},[33,2827,2828],{},"Performance and Speed",[2602,2830,2831,2834],{},[33,2832,2833],{},"Reliable",": Good performance with consistent updates; may have slower initial load times on mobile",[2602,2836,2837,2839],{},[33,2838,2796],{},": Generally good performance on both desktop and mobile",[2586,2841,2842,2847,2853],{},[2602,2843,2844],{},[33,2845,2846],{},"Support and Documentation",[2602,2848,2849,2852],{},[33,2850,2851],{},"Robust",": Comprehensive, regularly updated documentation and active community support",[2602,2854,2855,2857],{},[33,2856,2796],{},": Detailed but may be complex; documentation includes technical jargon",[2586,2859,2860,2865,2871],{},[2602,2861,2862],{},[33,2863,2864],{},"Overall User Experience",[2602,2866,2867,2870],{},[33,2868,2869],{},"User-friendly",": Accessible and easy to use with low-code approach; suitable for a wide range of users",[2602,2872,2873,2875],{},[33,2874,2699],{},": Offers greater customization but requires coding expertise; can be daunting for non-developers",[2586,2877,2878,2883,2889],{},[2602,2879,2880],{},[33,2881,2882],{},"User Community Activity",[2602,2884,2885,2888],{},[33,2886,2887],{},"Large and active",": High engagement in forums and discussions; growing number of downloads",[2602,2890,2891,2894],{},[33,2892,2893],{},"Smaller but dedicated",": Active users, but less engagement compared to FlowFuse Dashboard",[2586,2896,2897,2902,2908],{},[2602,2898,2899],{},[33,2900,2901],{},"Future Development Plans",[2602,2903,2904,2907],{},[33,2905,2906],{},"Active",": Continuous enhancements and new features planned; updates tracked on GitHub project board",[2602,2909,2910,2913],{},[33,2911,2912],{},"Less transparent",": No detailed roadmap; future features are less clearly communicated",[19,2915,2115],{"id":2114},[15,2917,2918],{},"FlowFuse Dashboard is well-suited for users seeking a user-friendly, low-code solution with a wide range of pre-built elements and strong community support. Its ease of use and active development make it ideal for quick deployment and minimal technical overhead.",[15,2920,2921],{},"UI-Builder, however, offers nice performance and customization, benefiting users with coding expertise who need highly tailored UIs. Despite its flexibility and faster load times, it requires more complex setup and migration.",{"title":265,"searchDepth":266,"depth":266,"links":2923},[2924,2928,2932,2936,2940,2944,2948,2952,2956,2960,2964,2968,2972,2976,2980,2984,2988,2989],{"id":2178,"depth":269,"text":2179,"children":2925},[2926,2927],{"id":2182,"depth":274,"text":2183},{"id":2193,"depth":274,"text":2194},{"id":2204,"depth":269,"text":2205,"children":2929},[2930,2931],{"id":2208,"depth":274,"text":2183},{"id":2214,"depth":274,"text":2194},{"id":2220,"depth":269,"text":2221,"children":2933},[2934,2935],{"id":2236,"depth":274,"text":2183},{"id":2250,"depth":274,"text":2194},{"id":2259,"depth":269,"text":2260,"children":2937},[2938,2939],{"id":2263,"depth":274,"text":2183},{"id":2285,"depth":274,"text":2194},{"id":2306,"depth":269,"text":2307,"children":2941},[2942,2943],{"id":2310,"depth":274,"text":2183},{"id":2316,"depth":274,"text":2194},{"id":2322,"depth":269,"text":2323,"children":2945},[2946,2947],{"id":2326,"depth":274,"text":2183},{"id":2336,"depth":274,"text":2194},{"id":2342,"depth":269,"text":2343,"children":2949},[2950,2951],{"id":2346,"depth":274,"text":2183},{"id":2364,"depth":274,"text":2194},{"id":2370,"depth":269,"text":2371,"children":2953},[2954,2955],{"id":2374,"depth":274,"text":2183},{"id":2383,"depth":274,"text":2194},{"id":2389,"depth":269,"text":2390,"children":2957},[2958,2959],{"id":2393,"depth":274,"text":2183},{"id":2405,"depth":274,"text":2194},{"id":2411,"depth":269,"text":2412,"children":2961},[2962,2963],{"id":2415,"depth":274,"text":2183},{"id":2432,"depth":274,"text":2194},{"id":2438,"depth":269,"text":2439,"children":2965},[2966,2967],{"id":2442,"depth":274,"text":2183},{"id":2454,"depth":274,"text":2455},{"id":2461,"depth":269,"text":2462,"children":2969},[2970,2971],{"id":2465,"depth":274,"text":2183},{"id":2471,"depth":274,"text":2194},{"id":2477,"depth":269,"text":2478,"children":2973},[2974,2975],{"id":2481,"depth":274,"text":2183},{"id":2487,"depth":274,"text":2194},{"id":2493,"depth":269,"text":2494,"children":2977},[2978,2979],{"id":2497,"depth":274,"text":2183},{"id":2512,"depth":274,"text":2194},{"id":2527,"depth":269,"text":2528,"children":2981},[2982,2983],{"id":2531,"depth":274,"text":2183},{"id":2537,"depth":274,"text":2194},{"id":2543,"depth":269,"text":2544,"children":2985},[2986,2987],{"id":2547,"depth":274,"text":2183},{"id":2571,"depth":274,"text":2194},{"id":2577,"depth":269,"text":2578},{"id":2114,"depth":269,"text":2115},{"type":653,"title":2991,"description":2992},"Build and Deploy Node-RED Dashboards in Production","FlowFuse gives you everything you need to build, secure, and scale Node-RED Dashboard applications, with team collaboration, version control, and production-ready deployment built in.","2024-08-06","Compare FlowFuse Dashboard and UI-Builder. Discover their installation ease, customization, performance, and support to find the best solution for your needs.","\u002Fblog\u002F2024\u002F08\u002Fimages\u002Fdashboard-2-vs-ui-builder.png","2025-07-23",{"keywords":2998,"excerpt":2999},"node red dashboard, node-red dashboard, node red ui builder, ui builder node red, flexdash, node red dashboard alternative, node red alternative dashboard, flowfuse dashboard",{"type":12,"value":3000},[3001],[15,3002,2175],{},"\u002Fblog\u002F2024\u002F08\u002Fcomparing-dashboard-2-with-uibuilder",{"title":2169,"description":2994},{"loc":3003},"blog\u002F2024\u002F08\u002Fcomparing-dashboard-2-with-uibuilder","Understanding the Differences Between FlowFuse Dashboard and UI-Builder",[3009,3010,303,3011],"post","node-red","comparing node-red dashboards","FlowFuse Dashboard (Dashboard 2.0) and UI-Builder are the two most popular Node-RED dashboard solutions after the deprecation of Node-RED Dashboard 1.0. FlowFuse Dashboard offers an easier low-code setup, a guided migration path from Dashboard 1.0, and active development, while UI-Builder requires deeper coding knowledge and a full rebuild when migrating.","mMBXQDhItyfWRFoWDWJPQ1ZQZnPWSMia3yFFxb8wRMk",{"id":3015,"title":3016,"authors":3017,"body":3018,"cta":3,"date":3486,"description":3487,"extension":287,"image":3488,"lastUpdated":3,"meta":3489,"navigation":295,"path":3494,"seo":3495,"sitemap":3496,"stem":3497,"subtitle":3487,"tags":3498,"tldr":3,"video":3,"__hash__":3499},"blog\u002Fblog\u002F2024\u002F07\u002Fdashboard-new-charts.md","New Charts Available in FlowFuse Dashboard",[309],{"type":12,"value":3019,"toc":3467},[3020,3023,3027,3030,3034,3042,3046,3054,3058,3061,3064,3072,3076,3080,3083,3090,3094,3098,3111,3114,3117,3121,3128,3131,3135,3138,3141,3145,3154,3349,3352,3360,3363,3371,3380,3387,3391,3399,3408,3411,3417,3419,3426,3428,3451,3453,3464],[15,3021,3022],{},"It's been a while coming, but we've finally introduced a new set of chart types to FlowFuse Dashboard. We've added Pie, Donut and Grouped (Stacks and Side-by-Side) Bar charts to the UI Chart node. We've also shipped plenty of other improvements and fixes in this release, so let's dive in.",[19,3024,3026],{"id":3025},"grouped-bar-charts","Grouped Bar Charts",[15,3028,3029],{},"We now have the option \"Group By\" available when building Bar Charts, with the options \"Stacks\" and \"Side-by-Side\". This allows you to group data in a more meaningful way, and is particularly useful when comparing multiple data sets.",[82,3031,3033],{"id":3032},"stacks","Stacks",[15,3035,3036,3040],{},[239,3037],{"alt":3038,"dataZoomable":265,"src":3039},"Screenshot showing a stacked bar chart with Dashboard","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fui-chart-bar-grouped-finance-stacks.png",[333,3041,3038],{},[82,3043,3045],{"id":3044},"side-by-side","Side-by-Side",[15,3047,3048,3052],{},[239,3049],{"alt":3050,"dataZoomable":265,"src":3051},"Screenshot showing a side-by-side grouped bar chart with Dashboard","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fui-chart-bar-grouped-finance.png",[333,3053,3050],{},[19,3055,3057],{"id":3056},"pie-donut-charts","Pie & Donut Charts",[15,3059,3060],{},"Radial charts are now available in Dashboard, with the introduction of Pie and Donut charts. These are particularly useful when you want to show the proportion of a single data set.",[15,3062,3063],{},"If you're using multiple \"Series\" here, then you'll get multiple nested radial charts, which can be particularly useful when comparing multiple data sets.",[15,3065,3066,3070],{},[239,3067],{"alt":3068,"dataZoomable":265,"src":3069},"Screenshot showing the new Pie and Donut charts available with Dashboard","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fui-chart-pie-doughnut.png",[333,3071,3068],{},[19,3073,3075],{"id":3074},"general-chart-changes-improvements","General Chart Changes & Improvements",[82,3077,3079],{"id":3078},"breaking-changes-bar-charts","Breaking Changes - Bar Charts",[15,3081,3082],{},"With the introduction of the new chart types, we've generalised the key mapping features for charts. Previously, Bar Charts were using the \"Series\" property to define how data is rendered onto the x-axis. In hindsight, this didn't really make any sense, it should be the \"X\" property that defines the data used on the x-axis, so we've corrected that going forward, but it did mean introducing a breaking change. We don't do this lightly, but in this case, it was necessary to ensure the charting experience is consistent across all chart types.",[15,3084,3085,3086,3089],{},"It does however mean that Bar Charts created in ",[442,3087,3088],{},"1.13.0"," or below will need to be updated to reflect this. You just need to set \"X\" to whatever you have in the \"Series\" property, and then set \"Series\" to \"None\".",[82,3091,3093],{"id":3092},"mapping-your-data","Mapping Your Data",[892,3095,3097],{"id":3096},"series","Series",[15,3099,3100,3101,3104,3105,3107,3108,437],{},"This property is now, consistently, how you want to group your data. If a new ",[442,3102,3103],{},"msg"," is coming in, and a property on that ",[442,3106,3103],{}," defines its group, then you can set \"Series\" to something like ",[442,3109,3110],{},"msg.myCategory",[15,3112,3113],{},"If a single data point needs to plot multiple points\u002Fbars onto a chart, then you can use the \"JSON\" type here, and list the different properties you want to plot, one for each category.",[15,3115,3116],{},"For Radial charts (Pie & Donut), having multiple series would provide multiple, nested radial charts.",[892,3118,3120],{"id":3119},"x","X",[15,3122,3123,3124,3127],{},"With this, we define which property (or ",[333,3125,3126],{},"properties"," if a single piece of data needs to plot multiple points\u002Fbars) we want to plot on the x-axis.",[15,3129,3130],{},"Note that on Radial charts (Pie & Donut), this is the value that defines the label of the segment.",[892,3132,3134],{"id":3133},"y","Y",[15,3136,3137],{},"Which property should be used to define the y-axis value, i.e. height of the bar or the y-coordinate of a point on a scatter chart.",[15,3139,3140],{},"Note that on Radial charts (Pie & Donut), this is the value that defines the size of the segment.",[892,3142,3144],{"id":3143},"example-plotting-star-wars-character-heights","Example: Plotting Star Wars Character Heights",[15,3146,3147,3148,3153],{},"The ",[256,3149,3152],{"href":3150,"rel":3151},"https:\u002F\u002Fswapi.dev\u002F",[402],"Star Wars API"," is a free, open API that provides data on the Star Wars universe, an example API call can return details about particular characters, and the response is as follows:",[981,3155,3159],{"className":3156,"code":3157,"language":3158,"meta":265,"style":265},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[{\n    \"name\":\"Luke Skywalker\",\n    \"height\":\"172\",\n    \"mass\":\"77\",\n    \"hair_color\":\"blond\",\n    \"skin_color\":\"fair\",\n    \"eye_color\":\"blue\",\n    \"birth_year\":\"19BBY\",\n    \"gender\":\"male\",\n    ...\n}, {\n    ...\n}]\n","json",[442,3160,3161,3166,3188,3208,3228,3248,3268,3288,3308,3328,3333,3340,3344],{"__ignoreMap":265},[989,3162,3163],{"class":991,"line":992},[989,3164,3165],{"class":995},"[{\n",[989,3167,3168,3171,3174,3176,3178,3180,3183,3185],{"class":991,"line":269},[989,3169,3170],{"class":995},"    \"",[989,3172,3173],{"class":1020},"name",[989,3175,1027],{"class":995},[989,3177,1180],{"class":995},[989,3179,1027],{"class":995},[989,3181,3182],{"class":1030},"Luke Skywalker",[989,3184,1027],{"class":995},[989,3186,3187],{"class":995},",\n",[989,3189,3190,3192,3195,3197,3199,3201,3204,3206],{"class":991,"line":274},[989,3191,3170],{"class":995},[989,3193,3194],{"class":1020},"height",[989,3196,1027],{"class":995},[989,3198,1180],{"class":995},[989,3200,1027],{"class":995},[989,3202,3203],{"class":1030},"172",[989,3205,1027],{"class":995},[989,3207,3187],{"class":995},[989,3209,3210,3212,3215,3217,3219,3221,3224,3226],{"class":991,"line":266},[989,3211,3170],{"class":995},[989,3213,3214],{"class":1020},"mass",[989,3216,1027],{"class":995},[989,3218,1180],{"class":995},[989,3220,1027],{"class":995},[989,3222,3223],{"class":1030},"77",[989,3225,1027],{"class":995},[989,3227,3187],{"class":995},[989,3229,3230,3232,3235,3237,3239,3241,3244,3246],{"class":991,"line":1071},[989,3231,3170],{"class":995},[989,3233,3234],{"class":1020},"hair_color",[989,3236,1027],{"class":995},[989,3238,1180],{"class":995},[989,3240,1027],{"class":995},[989,3242,3243],{"class":1030},"blond",[989,3245,1027],{"class":995},[989,3247,3187],{"class":995},[989,3249,3250,3252,3255,3257,3259,3261,3264,3266],{"class":991,"line":1089},[989,3251,3170],{"class":995},[989,3253,3254],{"class":1020},"skin_color",[989,3256,1027],{"class":995},[989,3258,1180],{"class":995},[989,3260,1027],{"class":995},[989,3262,3263],{"class":1030},"fair",[989,3265,1027],{"class":995},[989,3267,3187],{"class":995},[989,3269,3270,3272,3275,3277,3279,3281,3284,3286],{"class":991,"line":1107},[989,3271,3170],{"class":995},[989,3273,3274],{"class":1020},"eye_color",[989,3276,1027],{"class":995},[989,3278,1180],{"class":995},[989,3280,1027],{"class":995},[989,3282,3283],{"class":1030},"blue",[989,3285,1027],{"class":995},[989,3287,3187],{"class":995},[989,3289,3290,3292,3295,3297,3299,3301,3304,3306],{"class":991,"line":1117},[989,3291,3170],{"class":995},[989,3293,3294],{"class":1020},"birth_year",[989,3296,1027],{"class":995},[989,3298,1180],{"class":995},[989,3300,1027],{"class":995},[989,3302,3303],{"class":1030},"19BBY",[989,3305,1027],{"class":995},[989,3307,3187],{"class":995},[989,3309,3310,3312,3315,3317,3319,3321,3324,3326],{"class":991,"line":1126},[989,3311,3170],{"class":995},[989,3313,3314],{"class":1020},"gender",[989,3316,1027],{"class":995},[989,3318,1180],{"class":995},[989,3320,1027],{"class":995},[989,3322,3323],{"class":1030},"male",[989,3325,1027],{"class":995},[989,3327,3187],{"class":995},[989,3329,3330],{"class":991,"line":1132},[989,3331,3332],{"class":1060},"    ...\n",[989,3334,3335,3338],{"class":991,"line":1142},[989,3336,3337],{"class":995},"},",[989,3339,1152],{"class":995},[989,3341,3342],{"class":991,"line":1155},[989,3343,3332],{"class":1060},[989,3345,3346],{"class":991,"line":1166},[989,3347,3348],{"class":995},"}]\n",[15,3350,3351],{},"We can configure a chart with the following \"Mapping\" options:",[15,3353,3354,3358],{},[239,3355],{"alt":3356,"dataZoomable":265,"src":3357},"Example mapping of data to a UI Chart for data coming from the Star Wars API","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fui-chart-bar-sw-config.png",[333,3359,3356],{},[15,3361,3362],{},"and this would then be the resulting chart:",[15,3364,3365,3369],{},[239,3366],{"alt":3367,"dataZoomable":265,"src":3368},"Example bar chart showing heights of Star Wars characters","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fui-chart-bar-sw.png",[333,3370,3367],{},[15,3372,3373,3374,3376,3377,3379],{},"Note, the chart takes in all of the data sent to it, uses the ",[442,3375,3173],{}," field to define where on the x-axis the data should be plotted, and the ",[442,3378,3194],{}," field to define the height of the bar (the y-axis).",[15,3381,3382,3383],{},"You can read more about this example, and access the flow itself in our documentation ",[256,3384,436],{"href":3385,"rel":3386},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-chart.html#bar-charts",[402],[19,3388,3390],{"id":3389},"live-dashboard-demo","Live Dashboard Demo",[15,3392,3393,3397],{},[239,3394],{"alt":3395,"dataZoomable":265,"src":3396},"Screenshot of our new interactive Dashboard to demonstrate how charts render in FlowFuse Dashboard","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Fdashboard-interactive-docs.png",[333,3398,3395],{},[15,3400,3401,3402,3407],{},"With the new release also comes a new ",[256,3403,3406],{"href":3404,"rel":3405},"https:\u002F\u002Fdashboard-demos.flowfuse.cloud\u002Fdashboard\u002Fcharts-example",[402],"Public Demo Dashboard"," that we've made available for all to use and play with.",[15,3409,3410],{},"You can try it out, and interact with a range of different chart types, including the new Pie, Donut and Grouped Bar charts. We'll also be extending this soon to cover the full range of widgets available in FlowFuse Dashboard.",[15,3412,3413,3414,437],{},"If you want more technical detail, you can also check out our online documentation ",[256,3415,436],{"href":2352,"rel":3416},[402],[19,3418,428],{"id":427},[15,3420,3421,3422,437],{},"You can find the full 1.14.0 Release Notes ",[256,3423,436],{"href":3424,"rel":3425},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv1.14.0",[402],[15,3427,607],{},[27,3429,3430,3437,3442,3444],{},[30,3431,3432,3433,3436],{},"UI Button Group - Now supports ",[442,3434,3435],{},"msg.enabled"," to enable\u002Fdisable the widget.",[30,3438,3439,3440,3436],{},"UI Form - Now supports ",[442,3441,3435],{},[30,3443,794],{},[30,3445,3446,3447,3450],{},"UI Switch - Fix missing ",[442,3448,3449],{},"msg.topic"," when setting the topic to a static string.",[19,3452,633],{"id":632},[15,3454,440,3455,445,3458,450,3461],{},[442,3456,3457],{},"1.15.0",[256,3459,436],{"href":448,"rel":3460},[402],[256,3462,455],{"href":453,"rel":3463},[402],[1720,3465,3466],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":265,"searchDepth":266,"depth":266,"links":3468},[3469,3473,3474,3483,3484,3485],{"id":3025,"depth":269,"text":3026,"children":3470},[3471,3472],{"id":3032,"depth":274,"text":3033},{"id":3044,"depth":274,"text":3045},{"id":3056,"depth":269,"text":3057},{"id":3074,"depth":269,"text":3075,"children":3475},[3476,3477],{"id":3078,"depth":274,"text":3079},{"id":3092,"depth":274,"text":3093,"children":3478},[3479,3480,3481,3482],{"id":3096,"depth":266,"text":3097},{"id":3119,"depth":266,"text":3120},{"id":3133,"depth":266,"text":3134},{"id":3143,"depth":266,"text":3144},{"id":3389,"depth":269,"text":3390},{"id":427,"depth":269,"text":428},{"id":632,"depth":269,"text":633},"2024-07-26","Our most recent update for FlowFuse Dashboard has introduced Pie, Donut and Grouped Bar charts, and plenty more.","\u002Fblog\u002F2024\u002F07\u002Fimages\u002Ftile-dashboard-new-charts.png",{"excerpt":3490},{"type":12,"value":3491},[3492],[15,3493,3022],{},"\u002Fblog\u002F2024\u002F07\u002Fdashboard-new-charts",{"title":3016,"description":3487},{"loc":3494},"blog\u002F2024\u002F07\u002Fdashboard-new-charts",[487,488,302,303],"LW6Q6CIod3KKwGHoGYmqtjk5bEtLPQdaTa7QNIKEyg8",{"id":3501,"title":2233,"authors":3502,"body":3503,"cta":3,"date":3801,"description":3802,"extension":287,"image":3803,"lastUpdated":3804,"meta":3805,"navigation":295,"path":3818,"seo":3819,"sitemap":3820,"stem":3821,"subtitle":3822,"tags":3823,"tldr":3824,"video":3,"__hash__":3825},"blog\u002Fblog\u002F2024\u002F06\u002Fdashboard-1-deprecated.md",[309],{"type":12,"value":3504,"toc":3791},[3505,3514,3521,3525,3528,3595,3599,3607,3651,3660,3664,3671,3679,3682,3686,3700,3704,3712,3721,3725,3732,3739,3747,3755,3772,3776,3784],[15,3506,3507,3508,3513],{},"Dave Conway-Jones, the lead maintainer of Node-RED Dashboard, has ",[256,3509,3512],{"href":3510,"rel":3511},"https:\u002F\u002Fdiscourse.nodered.org\u002Ft\u002Fnode-red-dashboard-v1-deprecation-notice\u002F89006",[402],"just announced"," that Node-RED Dashboard has been formally deprecated, meaning there will be no further development activity on the project.",[15,3515,3516,3520],{},[256,3517,2183],{"href":3518,"rel":3519},"https:\u002F\u002Fdashboard.flowfuse.com\u002F",[402]," (also known as Node-RED Dashboard 2.0) is a natural successor to Node-RED Dashboard, and in this article, we detail what FlowFuse Dashboard offers, and how you can get started.",[19,3522,3524],{"id":3523},"whats-new-in-dashboard-20","What's new in Dashboard 2.0?",[15,3526,3527],{},"Not only have we made significant efforts to ensure that FlowFuse Dashboard has as much feature parity with Node-RED Dashboard as possible, but we've also introduced a number of new features that we think you'll love, some highlights include:",[27,3529,3530,3536,3542,3575,3581],{},[30,3531,3532,3535],{},[33,3533,3534],{},"Multi Tenancy:"," A big change from Node-RED Dashboard is the introduction of multi-tenancy features. This allows you to build Dashboards that are unique to each user that interacts with your flows.",[30,3537,3538,3541],{},[33,3539,3540],{},"Responsive Layouts:"," FlowFuse Dashboard is built with a responsive layout in mind, meaning that your Dashboards will automatically adjust to the screen size of the device they are being viewed on.",[30,3543,3544,3547,3548,3553,3554,3553,3559,3553,3564,2355,3569,3574],{},[33,3545,3546],{},"New Nodes:"," We've introduced a five new nodes; ",[256,3549,3552],{"href":3550,"rel":3551},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-button-group.html",[402],"Button Group",", ",[256,3555,3558],{"href":3556,"rel":3557},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-radio-group.html",[402],"Radio Group",[256,3560,3563],{"href":3561,"rel":3562},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-file-input.html",[402],"File Upload",[256,3565,3568],{"href":3566,"rel":3567},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-event.html",[402],"Event",[256,3570,3573],{"href":3571,"rel":3572},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-table.html",[402],"Table"," to help you build your Dashboards, without needing to write custom code, or depend on third-party libraries.",[30,3576,3577,3580],{},[33,3578,3579],{},"Directly Install on Mobile:"," FlowFuse Dashboard is built as a Progressive Web App (PWA), this means that you're able to install it directly onto your mobile device as if it were a native mobile application.",[30,3582,3583,3586,3587,3592,3593,574],{},[33,3584,3585],{},"Vuetify Framework:"," FlowFuse Dashboard is built on VueJS, and with that, we made the decision to integrate in ",[256,3588,3591],{"href":3589,"rel":3590},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Fall\u002F#containment",[402],"Vuetify",", a very rich collection of functional UI widgets. All of these widgets are available, by default when you want to build your own custom widgets in a ",[442,3594,869],{},[19,3596,3598],{"id":3597},"what-we-have-planned","What we have planned",[15,3600,3601,3602,3606],{},"We are actively investing into the development of FlowFuse Dashboard, and releasing new features and updates on a regular basis. We have a public ",[256,3603,3605],{"href":448,"rel":3604},[402],"Project Management Board"," that show exactly what we're working on, and what we have planned in the near future. Some particular highlights include:",[27,3608,3609,3619,3640],{},[30,3610,3611,3614,3615,437],{},[33,3612,3613],{},"Visual Layout Editor:"," This would be the biggest improvement to building dashboards in Node-RED. We're aiming for a fully interactive front-end to help you design your Dashboard layouts. This would live in your Dashboard itself, no more needing to switch between the Node-RED Editor and your Dashboard to sanity check changes. You can see more details ",[256,3616,436],{"href":3617,"rel":3618},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F30",[402],[30,3620,3621,3624,3625,3630,3631,3633,3634,3639],{},[33,3622,3623],{},"Diversity of Data Visualisation:"," We are planning to provide a richer ecosystem of data visualisations. We're also likely to be switching to ",[256,3626,3629],{"href":3627,"rel":3628},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F782",[402],"Apache eCharts"," (subject to further investigation), and are considering a ",[442,3632,869],{},"-type node that can be used to build ",[256,3635,3638],{"href":3636,"rel":3637},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F58",[402],"custom charts"," too.",[30,3641,3642,3645,3646,437],{},[33,3643,3644],{},"Feature Parity:"," Whilst we've covered there vast majority of Dashboard 1.0 features, we've still got a little bit to go, in particular, the most requested features we have are  ",[256,3647,3650],{"href":3648,"rel":3649},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F555",[402],"programmatic (mustache) title and labels",[15,3652,3653,3654,3659],{},"If there are any other features you'd like to see, please do open a ",[256,3655,3658],{"href":3656,"rel":3657},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002Fnew\u002Fchoose",[402],"Feature Request",", and we'll do our best to accommodate.",[19,3661,3663],{"id":3662},"getting-started-with-flowfuse-dashboard","Getting Started with FlowFuse Dashboard",[15,3665,3666,3667,3670],{},"If you're ready to get started with FlowFuse Dashboard, you can install it directly from the Node-RED Palette Manager. Simply search for ",[442,3668,3669],{},"@flowfuse\u002Fnode-red-dashboard"," and install the latest version.",[15,3672,3673,3677],{},[239,3674],{"alt":3675,"dataZoomable":265,"src":3676},"A short recording to show how easy it is to setup your first dashboard","https:\u002F\u002Fdashboard.flowfuse.com\u002Fassets\u002Fgetting-started.DHDsIsZl.gif",[333,3678,3675],{},[15,3680,3681],{},"Getting started is as easy as dropping on your first node. FlowFuse Dashboard will automatically set you up with a default group, page, theme and underlying Dashboard configuration.",[82,3683,3685],{"id":3684},"resources","Resources",[15,3687,3688,3689,3694,3695,3639],{},"We have a comprehensive ",[256,3690,3693],{"href":3691,"rel":3692},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fgetting-started.html",[402],"Getting Started Guide"," that will walk you through the process of setting up your first Dashboard. You can download our ",[256,3696,3699],{"href":3697,"rel":3698},"https:\u002F\u002Fdashboard.flowfuse.com\u002F#download-our-e-book",[402],"\"Ultimate Guide\" eBook",[82,3701,3703],{"id":3702},"dashboard-workshop","Dashboard Workshop",[15,3705,3706,3707,3711],{},"We'll running a ",[256,3708,3710],{"href":3709},"\u002Fwebinars\u002F2024\u002Fworkshop-dashboard","Workshop"," on July 2nd, where we will be covering a collection of useful tips and design patterns to help you get the most out of Dashboard.",[15,3713,3714,3715,3720],{},"The recording will also be available on the ",[256,3716,3719],{"href":3717,"rel":3718},"https:\u002F\u002Fwww.youtube.com\u002F@FlowFuseInc",[402],"FlowFuse YouTube channel"," after the event.",[19,3722,3724],{"id":3723},"migrating-to-flowfuse-dashboard","Migrating to FlowFuse Dashboard",[15,3726,3727,3728,3731],{},"If you're looking to migrate your existing Node-RED Dashboard flows to FlowFuse Dashboard, we have a ",[256,3729,3730],{"href":2245},"Migration Guide"," that details all of the features and properties that have, and haven't, been migrated into FlowFuse Dashboard.",[15,3733,3734,3735,3738],{},"It's worth noting that FlowFuse Dashboard ",[333,3736,3737],{},"will"," run side-by-side with the original Node-RED Dashboard, so you can take your time to migrate your flows over, and do so, piece-by-piece.",[15,3740,3741,3742,1180],{},"This week, we also made available the first iteration of the ",[256,3743,3746],{"href":3744,"rel":3745},"https:\u002F\u002Fflowfuse.com\u002Fplatform\u002Fdashboard\u002F#migration-service",[402],"Dashboard Migration Service",[15,3748,3749,3753],{},[239,3750],{"alt":3751,"dataZoomable":265,"src":3752},"Screenshot showing the Dashboard Migration Service available on FlowFuse's website","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdashboard-migration-service.png",[333,3754,3751],{},[15,3756,3757,3758,3553,3761,3764,3765,2355,3768,3771],{},"Currently, it'll convert your ",[442,3759,3760],{},"ui_tab",[442,3762,3763],{},"ui_group"," nodes, and setup your new ",[442,3766,3767],{},"ui-theme",[442,3769,3770],{},"ui-base"," nodes for you. We'll be extending this over time, and eventually hope to auto-convert most of your existing Dashboard 1.0 flows.",[19,3773,3775],{"id":3774},"final-thoughts","Final Thoughts",[15,3777,3778,3779,437],{},"We're really excited to see what you can build with FlowFuse Dashboard, and we're here to help you every step of the way. If you have any questions, please do reach out to us on the ",[256,3780,3783],{"href":3781,"rel":3782},"https:\u002F\u002Fdiscourse.nodered.org\u002Ftag\u002Fdashboard-2",[402],"Node-RED Community Forum",[15,3785,3786,3787,437],{},"If you're interested in contributing and extending FlowFuse Dashboard, we're very open to Pull Requests, and have a detailed contributing guide you can take a look at ",[256,3788,436],{"href":3789,"rel":3790},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002F",[402],{"title":265,"searchDepth":266,"depth":266,"links":3792},[3793,3794,3795,3799,3800],{"id":3523,"depth":269,"text":3524},{"id":3597,"depth":269,"text":3598},{"id":3662,"depth":269,"text":3663,"children":3796},[3797,3798],{"id":3684,"depth":274,"text":3685},{"id":3702,"depth":274,"text":3703},{"id":3723,"depth":269,"text":3724},{"id":3774,"depth":269,"text":3775},"2024-06-27","It has just been announced that the predecessor to FlowFuse's Dashboard, Node-RED Dashboard, has been formally deprecated. Find out what this means for your Node-RED instances, see how you can get started with FlowFuse's Dashboard, and what we have planned in the near future.","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdashboard1-deprecated.png","2026-02-23",{"excerpt":3806},{"type":12,"value":3807},[3808,3813],[15,3809,3507,3810,3513],{},[256,3811,3512],{"href":3510,"rel":3812},[402],[15,3814,3815,3520],{},[256,3816,2183],{"href":3518,"rel":3817},[402],"\u002Fblog\u002F2024\u002F06\u002Fdashboard-1-deprecated",{"title":2233,"description":3802},{"loc":3818},"blog\u002F2024\u002F06\u002Fdashboard-1-deprecated","It has just been announced that the predecessor to FlowFuse's Dashboard, Node-RED Dashboard, has been formally deprecated. Find out how FlowFuse Dashboard can help you build your Dashboards, and what we have planned in the near future.",[487,488,3010,302,303,2183],"Node-RED Dashboard (Dashboard 1.0) has been formally deprecated, with no further development planned. FlowFuse Dashboard (Dashboard 2.0) is its natural successor, offering multi-tenancy, responsive layouts, new widget nodes, and PWA support. This post covers what's new, what's planned, and how to get started with FlowFuse Dashboard.","166SbqoBIYtzmOfaUFcLssN1_o0slntLT_x9KBUDnNk",{"id":3827,"title":3828,"authors":3829,"body":3830,"cta":4162,"date":4165,"description":4166,"extension":287,"image":4167,"lastUpdated":3,"meta":4168,"navigation":295,"path":4175,"seo":4176,"sitemap":4177,"stem":4178,"subtitle":4179,"tags":4180,"tldr":3,"video":3,"__hash__":4181},"blog\u002Fblog\u002F2024\u002F06\u002Fdashboard-multi-tenancy.md","Multi-Tenancy available for everyone with FlowFuse's Dashboard 2.0",[309],{"type":12,"value":3831,"toc":4150},[3832,3835,3838,3841,3884,3888,3895,3902,3910,3933,3937,3945,3948,3962,3965,3969,3977,3980,3984,3992,4008,4030,4034,4037,4043,4053,4065,4071,4075,4078,4087,4096,4104,4113,4117,4130,4139,4143],[15,3833,3834],{},"FlowFuse Dashboard has featured multi-tenancy features through the FlowFuse User Addon. This made user based applications available only to specific FlowFuse team tiers and customers. However, the Node-RED community wanted to use the same feature set in cases FlowFuse didn't consider initially. Taking this feedback on board, today we announce some significant changes to how you can build Dashboards with multi-tenancy in mind.",[15,3836,3837],{},"Having taken that feedback on board, we've made some significant changes to how you can build Dashboards with multi-tenancy in mind.",[15,3839,3840],{},"A quick summary of the changes are as follows:",[27,3842,3843,3859,3869],{},[30,3844,3845,3848,3849,3852,3853,3855,3856,3858],{},[33,3846,3847],{},"Socket constraints moved to core Dashboard:"," The ability to constrain communications to a specific client (using the ",[442,3850,3851],{},"msg._client.socketId",") has been moved to the core of Dashboard 2.0, and is no longer a feature of the FlowFuse User Addon. As such, it's available to ",[333,3854,960],{}," users, for ",[333,3857,960],{}," node types.",[30,3860,3861,3864,3865,3868],{},[33,3862,3863],{},"FlowFuse User Addon now Source Available:"," The addon is available to install in ",[333,3866,3867],{},"any"," instances of Node-RED running on FlowFuse, so that's all team tiers on FlowFuse Cloud, and any self-hosted instances of FlowFuse too. It is available to install from Node-RED's Palette Manager.",[30,3870,3871,3874,3875,3878,3879,3883],{},[33,3872,3873],{},"Cloudflare Auth Plugin:"," Release of the first community-created Auth Plugin for Dashboard for adding a ",[442,3876,3877],{},"user"," object when authenticating with Cloudflare. (See more details and install the plugin ",[256,3880,436],{"href":3881,"rel":3882},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002F@fullmetal-fred\u002Fnode-red-dashboard-2-cloudflare-auth",[402],")",[19,3885,3887],{"id":3886},"using-client-data","Using Client Data",[15,3889,3890,3891,3894],{},"Available since our ",[442,3892,3893],{},"1.10.0"," release of Dashboard, we have a new sidebar tab - \"Client Data\".",[15,3896,3897,3898,3901],{},"This new tab acts as a portal to control whether data about the connected clients is included in any events emitted in the Node-RED editor (appended into ",[442,3899,3900],{},"msg._client","). You can then use the \"Accept CLient Data\" options to define which nodes accept that data as a constraint for communication.",[15,3903,3904,3908],{},[239,3905],{"alt":3906,"dataZoomable":265,"src":3907},"Screenshot showing the new \"Client Data\" sidebar available with Dashboard","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdashboard-multi-tenancy-sidebar.png",[333,3909,3906],{},[15,3911,3912,3913,3915,3916,950,3919,3922,3923,3925,3926,3928,3929,3932],{},"In this case, if we send a ",[442,3914,3103],{}," to any ",[442,3917,3918],{},"ui-notification",[442,3920,3921],{},"ui-control"," which a specified ",[442,3924,3851],{},", then that ",[442,3927,3103],{}," will ",[333,3930,3931],{},"only"," be sent to the relevant socket connection.",[19,3934,3936],{"id":3935},"building-multi-tenant-dashboards","Building Multi-Tenant Dashboards",[15,3938,3939,3940,437],{},"We have introduced a new section to our documentation on ",[256,3941,3944],{"href":3942,"rel":3943},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fgetting-started.html#design-patterns",[402],"Design Patterns",[15,3946,3947],{},"To summarise briefly, we now consider there to be two primary design patterns when building with Dashboard:",[27,3949,3950,3956],{},[30,3951,3952,3955],{},[33,3953,3954],{},"Single Source of Truth",": All users of your Dashboard will see the same data. This is useful for industrial IoT or Home Automation applications.",[30,3957,3958,3961],{},[33,3959,3960],{},"Multi-Tenancy",": Data shown in a particular widget is unique to a given client\u002Fsession\u002Fuser. This represents a more traditional web application, where each user has their own session and associated data.",[15,3963,3964],{},"Note that these patterns can be intertwined, some widgets on a screen may be driven by \"Single Source of Truth\", and others by \"Multi-Tenancy\".",[892,3966,3968],{"id":3967},"building-a-single-source-of-truth-dashboard","Building a Single Source of Truth Dashboard",[15,3970,3971,3975],{},[239,3972],{"alt":3973,"dataZoomable":265,"src":3974},"Example flow diagram to show the flow of data in a \"Single Source of Truth\" architecture","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdesign-pattern-single.png",[333,3976,3973],{},[15,3978,3979],{},"Data can be sent to these widgets at any time, when a user connects to the Dashboard, the respective widget will load the relevant data from the centralised data source in Node-RED and show it to the user.",[892,3981,3983],{"id":3982},"building-a-multi-tenancy-dashboard","Building a Multi-Tenancy Dashboard",[15,3985,3986,3990],{},[239,3987],{"alt":3988,"dataZoomable":265,"src":3989},"Example flow diagram to show the flow of data in a \"Multi-Tenancy\" architecture","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdesign-pattern-client.png",[333,3991,3988],{},[15,3993,3994,3995,3998,3999,4001,4002,4004,4005,4007],{},"In this pattern, a very useful node is the ",[442,3996,3997],{},"ui-event"," node which fires a ",[442,4000,3103],{}," when a user views a page. This ",[442,4003,3103],{}," will contain a ",[442,4006,3900],{}," object, detailing the client's connection.",[15,4009,4010,4011,4014,4015,4018,4019,4023,4024,4026,4027,4029],{},"This ",[442,4012,4013],{},"_client"," object contains the ",[442,4016,4017],{},"socketId"," of the user (and potentially more depending on any ",[256,4020,4022],{"href":4021},"#authentication-plugins","Authentication plugins"," used). This ",[442,4025,3103],{}," can then be passed through to any other widget, and if configured to \"Accept Client Constraints\" that ",[442,4028,3103],{}," will only be sent to the specified client.",[19,4031,4033],{"id":4032},"authentication-plugins","Authentication Plugins",[15,4035,4036],{},"In this release we've also added a special category of plugins, \"Authentication Plugins\".",[15,4038,4039,4040,4042],{},"These plugins register themselves with Dashboard, and are permitted to add to the ",[442,4041,3900],{}," object. This can be useful for adding additional information about end users, such as their user ID, e-mail address or username.",[15,4044,4045,4046,4048,4049,4052],{},"This data can be used to constrain communications from Node-RED to a specific ",[333,4047,3877],{}," rather than just a ",[333,4050,4051],{},"socket connection",", which is far more reliable and secure.",[15,4054,4055,4059],{},[239,4056],{"alt":4057,"dataZoomable":265,"src":4058},"Screenshot showing \"FlowFuse User\" being appended to _client by the FlowFuse User Addon","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fdashboard-include-client-data.png",[333,4060,4061,4062,4064],{},"Screenshot showing \"FlowFuse User\" being appended to ",[442,4063,4013],{}," by the FlowFuse User Addon",[15,4066,4067,4068,4070],{},"Any active plugins you have installed, will also be detailed in the new \"Client Data\" sidebar (detailed above) so you can see which plugins are active and what data they are adding to the ",[442,4069,3900],{}," object.",[82,4072,4074],{"id":4073},"flowfuse-user-addon","FlowFuse User Addon",[15,4076,4077],{},"Whilst the plugin was first published a few months back, after hearing community feedback, we've made changes and are now publishing the plugin to the Node_RED Palette Manager. As such, it's available to all users running FlowFuse.",[15,4079,4080,4081,4083,4084,4086],{},"The addon appends a ",[442,4082,3877],{}," object to the ",[442,4085,3900],{}," object, populated with the details of the FlowFuse user performing the relevant actions in Dashboard. You can use this information to build multi-tenant Dashboards.",[15,4088,4089,4090,4095],{},"You can ",[256,4091,4094],{"href":4092,"rel":4093},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002F@flowfuse\u002Fnode-red-dashboard-2-user-addon",[402],"install the FlowFuse User Addon"," from the Palette Manager in the Node-RED editor.",[15,4097,4098,4102],{},[239,4099],{"alt":4100,"dataZoomable":265,"src":4101},"Screenshot of the Instance settings in FlowFuse to enable \"FlowFuse User Authentication\"","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Fflowfuse-instance-security.png",[333,4103,4100],{},[15,4105,4106,4107,4112],{},"It's worth noting that instances must have ",[256,4108,4111],{"href":4109,"rel":4110},"https:\u002F\u002Fflowfuse.com\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard\u002F#enabling-flowfuse-user-authentication",[402],"\"FlowFuse User Authentication\""," switched on in the instance's settings.",[82,4114,4116],{"id":4115},"cloudfare-user-addon-community-contribution","Cloudfare User Addon (Community Contribution)",[15,4118,4119,4120,4124,4125,4083,4127,4129],{},"We're also thrilled to announce that the first community-contributed plugin has been ",[256,4121,4123],{"href":3881,"rel":4122},[402],"published"," which will append a ",[442,4126,3877],{},[442,4128,3900],{}," object when authenticating with Cloudflare.",[15,4131,4132,4133,4138],{},"A huge thanks to Fred Loucks (",[256,4134,4137],{"href":4135,"rel":4136},"https:\u002F\u002Fgithub.com\u002Ffullmetal-fred",[402],"@fullmetal-fred"," on GitHub) for his great contribution!",[19,4140,4142],{"id":4141},"build-multi-tenant-dashboards-with-flowfuse-cloud","Build Multi Tenant Dashboards with FlowFuse Cloud",[15,4144,4145,4146,437],{},"Start by following our ",[256,4147,3693],{"href":4148,"rel":4149},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fmulti-tenancy.html#building-multi-tenant-dashboards",[402],{"title":265,"searchDepth":266,"depth":266,"links":4151},[4152,4153,4157,4161],{"id":3886,"depth":269,"text":3887},{"id":3935,"depth":269,"text":3936,"children":4154},[4155,4156],{"id":3967,"depth":266,"text":3968},{"id":3982,"depth":266,"text":3983},{"id":4032,"depth":269,"text":4033,"children":4158},[4159,4160],{"id":4073,"depth":274,"text":4074},{"id":4115,"depth":274,"text":4116},{"id":4141,"depth":269,"text":4142},{"type":653,"title":4163,"description":4164},"Build Multi-Tenant Dashboards With Node-RED","FlowFuse gives you everything you need to build personalized, user-aware dashboards, with built-in authentication, client constraints, and multi-tenancy support across all team tiers.","2024-06-21","With a recent update in Node-RED Dashboard 2.0, we've made some significant changes to the multi-tenancy feature. Discover what's new and how it can benefit your projects.","\u002Fblog\u002F2024\u002F06\u002Fimages\u002Ftile-dashboard-2-multi-tenancy.png",{"excerpt":4169},{"type":12,"value":4170},[4171,4173],[15,4172,3834],{},[15,4174,3837],{},"\u002Fblog\u002F2024\u002F06\u002Fdashboard-multi-tenancy",{"title":3828,"description":4166},{"loc":4175},"blog\u002F2024\u002F06\u002Fdashboard-multi-tenancy","With a recent update in Node-RED Dashboard 2.0, we've made some significant changes to the multi-tenancy feature set. Discover what's new and how it can benefit your projects.",[487,488,302,303],"GPWqhAr5Ce2SIATKa7Fa3jf-kt4opmLF7MPQZiqXae0",{"id":4183,"title":4184,"authors":4185,"body":4186,"cta":5499,"date":5502,"description":5503,"extension":287,"image":5504,"lastUpdated":2996,"meta":5505,"navigation":295,"path":5510,"seo":5511,"sitemap":5512,"stem":5513,"subtitle":5514,"tags":5515,"tldr":3,"video":3,"__hash__":5516},"blog\u002Fblog\u002F2024\u002F05\u002Fexploring-node-red-dashboard-2-widgets.md","Exploring Node-RED Dashboard 2.0 Widgets",[10],{"type":12,"value":4187,"toc":5483},[4188,4191,4199,4203,4206,4210,4219,4222,4226,4232,4253,4262,4279,4288,4292,4301,4316,4513,4516,4520,4529,4550,4559,4563,4577,4580,4593,4600,4604,4607,4620,4660,4670,4679,4683,4690,4711,4720,4727,4731,4734,4768,4777,4786,4806,4815,4860,4869,4874,4884,4917,4921,4924,4959,4968,4972,4983,4986,5000,5299,5306,5310,5412,5428,5431,5433,5436,5480],[15,4189,4190],{},"This guide delves into Node-RED Dashboard 2.0 widgets. It is a guide on how to build a Dashboard application, and will cover many of the widgets available today.",[15,4192,4193,4194,4198],{},"If you're new to Dashboard 2.0, we recommend starting with the ",[256,4195,4197],{"href":4196},"\u002Fblog\u002F2024\u002F03\u002Fdashboard-getting-started\u002F","Getting Started with Dashboard 2.0"," guide and make sure to install it.",[19,4200,4202],{"id":4201},"what-are-widgets","What Are Widgets?",[15,4204,4205],{},"Widgets in Node-RED Dashboard 2.0 are the building blocks for creating a user interface. In Dashboard 2.0, you get a variety of widgets like forms, templates, buttons, and others to make different parts of your interface.",[19,4207,4209],{"id":4208},"building-applications-with-dashboard-20-widgets","Building Applications with Dashboard 2.0 Widgets",[15,4211,4212,4217],{},[239,4213],{"alt":4214,"dataZoomable":265,"src":4215,"title":4216},"\"Income-expense tracker build with dashboard 2.0\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-incom-expense-tracker-system.gif","Income-expense tracker build with dashboard 2.0",[333,4218,4216],{},[15,4220,4221],{},"In this guide, we'll create a basic application to input expenses and income. This will then be displayed in a chart and table for analysis. The application will utilize a wide range of widgets available in Dashboard 2.0, helping you understand and use them confidently.",[82,4223,4225],{"id":4224},"adding-forms","Adding Forms",[15,4227,4228,4229,801],{},"For the income and expense submission, we'll incorporate a form using the ",[33,4230,4231],{},"ui-form",[903,4233,4234,4239,4246],{},[30,4235,1284,4236,4238],{},[33,4237,4231],{}," widget onto the canvas.",[30,4240,4241,4242,4245],{},"Double-click on it to access various widget properties and select the ",[33,4243,4244],{},"ui-group"," where it should render.",[30,4247,4248,4249,4252],{},"Add \"date\", \"description\", \"amount\", and \"note\" form elements by clicking the ",[33,4250,4251],{},"+element"," button at the bottom left.",[15,4254,4255,4260],{},[239,4256],{"alt":4257,"dataZoomable":265,"src":4258,"title":4259},"\"Screenshot displaying Income submission ui-form's configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-income-submission-form.png","Screenshot displaying Income submission ui-form's configuration",[333,4261,4259],{},[15,4263,4264,4265,2355,4268,4270,4271,4273,4274,437],{},"Once you've added the income submission form, repeat the process to add an expense submission form on another ",[33,4266,4267],{},"ui-page",[33,4269,4244],{},". For more information on ",[33,4272,4231],{},", refer to the ",[256,4275,4278],{"href":4276,"rel":4277},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-form.html",[402],"ui-form docs",[15,4280,4281,4286],{},[239,4282],{"alt":4283,"dataZoomable":265,"src":4284,"title":4285},"\"Screenshot displaying Expense submission ui-form's configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-expense-submission-form.png","Screenshot displaying Expense submission ui-form's configuration",[333,4287,4285],{},[82,4289,4291],{"id":4290},"storing-form-data","Storing Form Data",[15,4293,3147,4294,4296,4297,437],{},[33,4295,4231],{}," widget emits a payload object with key-value pairs of form elements upon submission. We'll store this data in a global context, If you are not familiar with Node-RED context, refer to ",[256,4298,4300],{"href":4299},"\u002Fblog\u002F2024\u002F05\u002Funderstanding-node-flow-global-environment-variables-in-node-red\u002F","Understanding Node-RED varriables",[903,4302,4303],{},[30,4304,940,4305,4308,4309,4312,4313,4315],{},[33,4306,4307],{},"function"," node onto the canvas and add the following code. This will store the submission in the ",[442,4310,4311],{},"income"," global context variable, and then modify ",[442,4314,1350],{}," to pass on a notification to any further connected nodes.",[981,4317,4321],{"className":4318,"code":4319,"language":4320,"meta":265,"style":265},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Retrieve the existing 'income' array from the global context, or initialize it as an empty array if it doesn't exist\nlet income = global.get('income') || [];\n\n\u002F\u002F Push the incoming payload along with a 'type' property set to \"income\" into the 'income' array\nincome.push({\n  ...msg.payload,\n  type: \"income\",\n});\n\n\u002F\u002F Store the updated 'income' array back into the global context\nglobal.set('income', income);\n\n\u002F\u002F Set the message payload to a confirmation message for notification\nmsg.payload = \"Thank you for submitting income!\";\n\n\u002F\u002F Return the modified message\nreturn msg;\n","javascript",[442,4322,4323,4328,4368,4372,4377,4391,4405,4421,4430,4434,4439,4465,4469,4474,4494,4498,4503],{"__ignoreMap":265},[989,4324,4325],{"class":991,"line":992},[989,4326,4327],{"class":1008},"\u002F\u002F Retrieve the existing 'income' array from the global context, or initialize it as an empty array if it doesn't exist\n",[989,4329,4330,4333,4336,4338,4341,4343,4347,4350,4353,4355,4357,4360,4363,4366],{"class":991,"line":269},[989,4331,4332],{"class":1020},"let",[989,4334,4335],{"class":1060}," income ",[989,4337,1024],{"class":995},[989,4339,4340],{"class":1060}," global",[989,4342,437],{"class":995},[989,4344,4346],{"class":4345},"s2Zo4","get",[989,4348,4349],{"class":1060},"(",[989,4351,4352],{"class":995},"'",[989,4354,4311],{"class":1030},[989,4356,4352],{"class":995},[989,4358,4359],{"class":1060},") ",[989,4361,4362],{"class":995},"||",[989,4364,4365],{"class":1060}," []",[989,4367,1753],{"class":995},[989,4369,4370],{"class":991,"line":274},[989,4371,1129],{"emptyLinePlaceholder":295},[989,4373,4374],{"class":991,"line":266},[989,4375,4376],{"class":1008},"\u002F\u002F Push the incoming payload along with a 'type' property set to \"income\" into the 'income' array\n",[989,4378,4379,4381,4383,4386,4388],{"class":991,"line":1071},[989,4380,4311],{"class":1060},[989,4382,437],{"class":995},[989,4384,4385],{"class":4345},"push",[989,4387,4349],{"class":1060},[989,4389,4390],{"class":995},"{\n",[989,4392,4393,4396,4398,4400,4403],{"class":991,"line":1089},[989,4394,4395],{"class":995},"  ...",[989,4397,3103],{"class":1060},[989,4399,437],{"class":995},[989,4401,4402],{"class":1060},"payload",[989,4404,3187],{"class":995},[989,4406,4407,4410,4412,4415,4417,4419],{"class":991,"line":1107},[989,4408,4409],{"class":999},"  type",[989,4411,1180],{"class":995},[989,4413,4414],{"class":995}," \"",[989,4416,4311],{"class":1030},[989,4418,1027],{"class":995},[989,4420,3187],{"class":995},[989,4422,4423,4426,4428],{"class":991,"line":1117},[989,4424,4425],{"class":995},"}",[989,4427,3883],{"class":1060},[989,4429,1753],{"class":995},[989,4431,4432],{"class":991,"line":1126},[989,4433,1129],{"emptyLinePlaceholder":295},[989,4435,4436],{"class":991,"line":1132},[989,4437,4438],{"class":1008},"\u002F\u002F Store the updated 'income' array back into the global context\n",[989,4440,4441,4444,4446,4449,4451,4453,4455,4457,4460,4463],{"class":991,"line":1142},[989,4442,4443],{"class":1060},"global",[989,4445,437],{"class":995},[989,4447,4448],{"class":4345},"set",[989,4450,4349],{"class":1060},[989,4452,4352],{"class":995},[989,4454,4311],{"class":1030},[989,4456,4352],{"class":995},[989,4458,4459],{"class":995},",",[989,4461,4462],{"class":1060}," income)",[989,4464,1753],{"class":995},[989,4466,4467],{"class":991,"line":1155},[989,4468,1129],{"emptyLinePlaceholder":295},[989,4470,4471],{"class":991,"line":1166},[989,4472,4473],{"class":1008},"\u002F\u002F Set the message payload to a confirmation message for notification\n",[989,4475,4476,4478,4480,4483,4485,4487,4490,4492],{"class":991,"line":1174},[989,4477,3103],{"class":1060},[989,4479,437],{"class":995},[989,4481,4482],{"class":1060},"payload ",[989,4484,1024],{"class":995},[989,4486,4414],{"class":995},[989,4488,4489],{"class":1030},"Thank you for submitting income!",[989,4491,1027],{"class":995},[989,4493,1753],{"class":995},[989,4495,4496],{"class":991,"line":1187},[989,4497,1129],{"emptyLinePlaceholder":295},[989,4499,4500],{"class":991,"line":1193},[989,4501,4502],{"class":1008},"\u002F\u002F Return the modified message\n",[989,4504,4505,4508,4511],{"class":991,"line":1199},[989,4506,4507],{"class":1145},"return",[989,4509,4510],{"class":1060}," msg",[989,4512,1753],{"class":995},[15,4514,4515],{},"Similarly, you can do this for storing expense data submitted using the expense submission form.",[82,4517,4519],{"id":4518},"displaying-notifications","Displaying Notifications",[15,4521,4522,4523,4525,4526,4528],{},"For displaying notifications on the dashboard, we'll utilize the ",[33,4524,3918],{}," widget, which emits notifications to the user's dashboard. It accepts ",[442,4527,1350],{}," which should be a string format or raw HTML\u002FJavaScript for custom formatting.",[903,4530,4531,4535],{},[30,4532,1284,4533,4238],{},[33,4534,3918],{},[30,4536,4537,4538,4541,4542,4547,4548,437],{},"Set the position property to ",[33,4539,4540],{},"center",". You can also adjust colors or notification timeout by modifying the color and timeout properties. Please take a look at the ",[256,4543,4546],{"href":4544,"rel":4545},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-notification.html#properties",[402],"ui-notification docs"," for more information on ",[33,4549,3918],{},[15,4551,4552,4557],{},[239,4553],{"alt":4554,"dataZoomable":265,"src":4555,"title":4556},"\"Screenshot displaying ui-notification widgets configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-notification-widget.png","Screenshot displaying ui-notification widgets configuration",[333,4558,4556],{},[82,4560,4562],{"id":4561},"listening-for-events","Listening for events",[15,4564,4565,4566,4568,4569,4572,4573,4576],{},"In Dashboard 2.0, the ",[33,4567,3997],{}," widget allows you to listen to user behavior or events. It does not render any content or components on the dashboard. Currently, this widget only listens for page views (",[442,4570,4571],{},"$pageview",") and leave (",[442,4574,4575],{},"$pageleave",") events.",[15,4578,4579],{},"With this, we can listen for page view and page leave events and trigger tasks based on those events. For instance, in our application, we will be displaying a table containing income and expense data, along with a chart. We'll update them when navigating to a new page or leaving a page.",[903,4581,4582,4587],{},[30,4583,4584,4585,4238],{},"Drag an ",[33,4586,3997],{},[30,4588,4589,4590,4592],{},"Double-click on it and select the correct ",[33,4591,3770],{}," of your application.",[15,4594,4595,4596,437],{},"For more information on ui-event refer to ",[256,4597,4599],{"href":3566,"rel":4598},[402],"ui-event docs",[82,4601,4603],{"id":4602},"retrieving-income-expense-data","Retrieving Income-Expense Data",[15,4605,4606],{},"In our income-expense application, we will display the income and expenses in a single table.",[903,4608,4609,4614],{},[30,4610,940,4611,1287],{},[33,4612,4613],{},"change",[30,4615,4616,4617,4619],{},"Set ",[442,4618,1350],{}," to the JSONata expression below, which merges the income and expense arrays.",[981,4621,4623],{"className":4318,"code":4622,"language":4320,"meta":265,"style":265},"[$globalContext('income'), $globalContext('expense')]\n",[442,4624,4625],{"__ignoreMap":265},[989,4626,4627,4630,4633,4635,4637,4639,4641,4643,4645,4648,4650,4652,4655,4657],{"class":991,"line":992},[989,4628,4629],{"class":1060},"[",[989,4631,4632],{"class":4345},"$globalContext",[989,4634,4349],{"class":1060},[989,4636,4352],{"class":995},[989,4638,4311],{"class":1030},[989,4640,4352],{"class":995},[989,4642,3883],{"class":1060},[989,4644,4459],{"class":995},[989,4646,4647],{"class":4345}," $globalContext",[989,4649,4349],{"class":1060},[989,4651,4352],{"class":995},[989,4653,4654],{"class":1030},"expense",[989,4656,4352],{"class":995},[989,4658,4659],{"class":1060},")]\n",[903,4661,4662],{"start":274},[30,4663,4664,4665,4667,4668,574],{},"Connect the output of the ",[33,4666,3997],{}," widget to the input of the ",[33,4669,4613],{},[15,4671,4672,4677],{},[239,4673],{"alt":4674,"dataZoomable":265,"src":4675,"title":4676},"\"Screenshot displaying the change node setting JSON expression to payload for retrieving and sorting data.\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-change-node.png","Screenshot displaying the change node setting JSON expression to payload for retrieving and sorting data.",[333,4678,4676],{},[82,4680,4682],{"id":4681},"displaying-data-on-the-table","Displaying Data on the Table",[15,4684,4685,4686,4689],{},"To display data on the table, we use the ",[33,4687,4688],{},"ui-table"," widget in Dashboard 2.0. This widget accepts an array of objects as input. The columns in the table correspond to the properties of the objects within the array, and each row represents a different object with values corresponding to those properties.",[903,4691,4692,4696,4704],{},[30,4693,940,4694,4238],{},[33,4695,4688],{},[30,4697,4698,4699,2355,4701,4703],{},"Create a new ",[33,4700,4267],{},[33,4702,4244],{}," for it.",[30,4705,4664,4706,4708,4709,801],{},[33,4707,4613],{}," node to the input of the ",[33,4710,4688],{},[15,4712,4713,4718],{},[239,4714],{"alt":4715,"dataZoomable":265,"src":4716,"title":4717},"\"Screenshot displaying the ui-table widget configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-table-widget.png","Screenshot displaying the ui-table widget configuration",[333,4719,4717],{},[15,4721,4722,4723],{},"For more information on ui-table refer to ",[256,4724,4726],{"href":3571,"rel":4725},[402],"ui-table docs",[82,4728,4730],{"id":4729},"calculating-total-category-wise","Calculating total category-wise",[15,4732,4733],{},"In our application, we will display data on the chart, showing the total income and total expenses for analysis. In this section, we will calculate the total expenses and income using the function node.",[903,4735,4736,4741],{},[30,4737,4738,4739,1287],{},"Drag the two ",[33,4740,4613],{},[30,4742,4743,4744,4747,4748,4750,4751,2355,4754,4756,4757,4759,4760,4750,4762,2355,4765,4767],{},"For the first ",[33,4745,4746],{},"Change"," node Set ",[442,4749,1350],{}," to ",[442,4752,4753],{},"global.income",[442,4755,3449],{}," to \"income\" and give it name \"retrive income\". For the second ",[33,4758,4746],{}," node, set ",[442,4761,1350],{},[442,4763,4764],{},"global.expense",[442,4766,3449],{}," to \"expense\" and give that second change node name \"retrive expense\".",[15,4769,4770,4775],{},[239,4771],{"alt":4772,"dataZoomable":265,"src":4773,"title":4774},"\"Screenshot displaying the change node retrieving income data from global context\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget-retrieve-income-change-node.png","Screenshot displaying the change node retrieving income data from global context",[333,4776,4774],{},[15,4778,4779,4784],{},[239,4780],{"alt":4781,"dataZoomable":265,"src":4782,"title":4783},"\"Screenshot displaying the change node retrieving expense data from global context\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget-retrieve-expense-change-node.png","Screenshot displaying the change node retrieving expense data from global context",[333,4785,4783],{},[903,4787,4788,4793],{"start":274},[30,4789,940,4790,1287],{},[33,4791,4792],{},"Split",[30,4794,1284,4795,4797,4798,4801,4802,4805],{},[33,4796,4746],{}," node onto the canvas and set ",[442,4799,4800],{},"msg.payload.amount"," to the JSONata expression ",[442,4803,4804],{},"$number(payload.amount)"," and give it name \"Convert amount to number\".",[15,4807,4808,4813],{},[239,4809],{"alt":4810,"dataZoomable":265,"src":4811,"title":4812},"\"Screenshot displaying the change node converting amount to number\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget-convert-amount-to-number-change-node.png","Screenshot displaying the change node converting amount to number",[333,4814,4812],{},[903,4816,4817],{"start":1071},[30,4818,940,4819,4822,4823,4826,4827,4750,4830,4833,4834,4837,4838,4750,4841,4844,4845,4848,4849,4851,4852,4855,4856,437],{},[33,4820,4821],{},"Join"," node onto the canvas, select mode as ",[33,4824,4825],{},"reduced expression",", and set the ",[33,4828,4829],{},"Reduce exp",[442,4831,4832],{},"$A + payload.amount",". Set Initial value to ",[442,4835,4836],{},"0",", and ",[33,4839,4840],{},"Fix-up exp",[442,4842,4843],{},"$A",". Give this ",[33,4846,4847],{},"join"," node the name \"Calculate total\". This function operates similarly to using the javascript reduce method on an array to calculate the sum of its values. ",[442,4850,4843],{}," stores the accumulated value, and with every incoming message payload, it adds the ",[442,4853,4854],{},"payload.amount"," value to it, for more details on this refer to the ",[256,4857,4859],{"href":4858},"\u002Fnode-red\u002Fcore-nodes\u002Fjoin\u002F","core node docs on join node",[15,4861,4862,4867],{},[239,4863],{"alt":4864,"dataZoomable":265,"src":4865,"title":4866},"\"Screenshot displaying the join node calculating the total income and expense data\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget-calculate-total-join-node.png","Screenshot displaying the join node calculating the total income and expense data",[333,4868,4866],{},[903,4870,4871],{"start":1107},[30,4872,4873],{},"Drag an another join node onto the canvas set mode to manual, combine each to complete message, to create to array and After a number of message parts to 2 and give it name \"combine two objects into array\".",[15,4875,4876,4881],{},[239,4877],{"alt":4878,"dataZoomable":265,"src":4879,"title":4880},"\"Screenshot displaying the join node combining the income and expense object into the array\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget-retrieve-combine-object-join-node.png","Screenshot displaying the join node combining the income and expense object into the",[333,4882,4883],{},"Screenshot displaying the join node combining the income and expense object into the array",[903,4885,4886,4898],{"start":1107},[30,4887,4664,4888,4667,4890,4892,4893,4895,4896,574],{},[33,4889,3997],{},[33,4891,4746],{}," node named \"Retrieve Income\" and \"Retrieve Expense\". Then, connect the outputs of the \"Retrieve Income\" and \"Retrieve Expense\" ",[33,4894,4746],{}," nodes to the input of the ",[33,4897,4792],{},[30,4899,4900,4901,4903,4904,4906,4907,4708,4909,4911,4912,4708,4914,4916],{},"Next, connect the output of the ",[33,4902,4792],{}," node to the ",[33,4905,4746],{}," node named \"Convert Amount to Number\". Afterward, connect the output of that ",[33,4908,4746],{},[33,4910,4821],{}," node named \"Calculate Total\". Finally, connect the output of the \"Calculate Total\" ",[33,4913,4821],{},[33,4915,4821],{}," node named \"Combine Objects into Array\".",[82,4918,4920],{"id":4919},"displaying-data-on-the-chart","Displaying data on the chart",[15,4922,4923],{},"To display charts on the dashboard, we have to use the ui-chart widget which allows us to display different types of charts on a dashboard including linear, bar, scatter, etc. This accepts an array and object as input.",[903,4925,4926,4931,4937,4951],{},[30,4927,940,4928,4238],{},[33,4929,4930],{},"ui-chart",[30,4932,4933,4934,437],{},"Double-click on the widget and select Type as ",[33,4935,4936],{},"bar",[30,4938,4939,4940,4943,4944,4947,4948,4950],{},"Configure the series to ",[33,4941,4942],{},"category"," and the y-axis to ",[33,4945,4946],{},"amount",". This configuration informs the chart that the ",[33,4949,4946],{}," property of the input objects will be plotted on the y-axis and category to the x-axis of the chart.",[30,4952,4664,4953,4955,4956,4958],{},[33,4954,4847],{}," node named \"Combine Objects into Array\" to the ",[33,4957,4930],{}," widget's input.",[15,4960,4961,4966],{},[239,4962],{"alt":4963,"dataZoomable":265,"src":4964,"title":4965},"\"Screenshot displaying the ui-chart widget's configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-chart-widget.png","Screenshot displaying the ui-chart widget's configuration",[333,4967,4965],{},[82,4969,4971],{"id":4970},"adding-custom-footer-with-ui-template","Adding custom footer with ui-template",[15,4973,4974,4975,4977,4978,437],{},"With the ",[33,4976,869],{}," widget, we can add a custom component to our app using Vue.js. It also allows adding custom CSS for the dashboard and lot of other things. For more information refer to ",[256,4979,4982],{"href":4980,"rel":4981},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html",[402],"ui-template docs",[15,4984,4985],{},"Using this widget, we will add a footer to our application.",[903,4987,4988,4992,4995],{},[30,4989,4584,4990,4238],{},[33,4991,869],{},[30,4993,4994],{},"Set the widget type (scoped UI) that will render this widget on the entire dashboard, eliminating the need to add separate footers for each page of the dashboard.",[30,4996,4997,4998,801],{},"Insert the following vue.js code in the ",[33,4999,869],{},[981,5001,5003],{"className":4318,"code":5002,"language":4320,"meta":265,"style":265},"\u003Ctemplate>\n  \u003C!-- Footer Component -->\n  \u003Cdiv class=\"footer\">\n    \u003C!-- Description of the Income-Expense Tracker -->\n    \u003Cdiv>\n      Welcome to our comprehensive income expense tracker! Take control of your finances by monitoring your income and\n      expenses effortlessly. Our user-friendly interface makes it simple to record transactions, categorize expenses, and\n      analyze your financial trends. With real-time insights into your spending habits, you can make smarter financial\n      decisions and achieve your money goals faster.\n    \u003C\u002Fdiv>\n    \u003C!-- Copyright Information -->\n    \u003Cdiv class=\"copyright\">\n      \u003C!-- Display Current Year and Copyright Information -->\n      2024, \u003Cstrong>Vuetify\u003C\u002Fstrong>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cstyle scoped>\n  \u002F* Make the footer occupy all available space *\u002F\n  .footer {\n    position:absolute;\n    bottom:0;\n    background-color:rgb(26,26,26);\n    color:rgb(238,238,238);\n    height:130px;\n    text-align:center;\n    padding:14px;\n  }\n\n  .copyright{\n    margin-top:10px;\n  }\n\u003C\u002Fstyle>\n",[442,5004,5005,5013,5018,5038,5043,5051,5056,5061,5066,5071,5079,5084,5103,5108,5127,5135,5144,5152,5163,5168,5175,5180,5189,5219,5241,5246,5256,5261,5266,5270,5277,5287,5291],{"__ignoreMap":265},[989,5006,5007,5009,5011],{"class":991,"line":992},[989,5008,996],{"class":995},[989,5010,1000],{"class":999},[989,5012,1003],{"class":995},[989,5014,5015],{"class":991,"line":269},[989,5016,5017],{"class":1060},"  \u003C!-- Footer Component -->\n",[989,5019,5020,5023,5025,5027,5029,5031,5034,5036],{"class":991,"line":274},[989,5021,5022],{"class":995},"  \u003C",[989,5024,228],{"class":999},[989,5026,1490],{"class":1020},[989,5028,1024],{"class":995},[989,5030,1027],{"class":995},[989,5032,5033],{"class":1030},"footer",[989,5035,1027],{"class":995},[989,5037,1003],{"class":995},[989,5039,5040],{"class":991,"line":266},[989,5041,5042],{"class":1060},"    \u003C!-- Description of the Income-Expense Tracker -->\n",[989,5044,5045,5047,5049],{"class":991,"line":1071},[989,5046,1014],{"class":995},[989,5048,228],{"class":999},[989,5050,1003],{"class":995},[989,5052,5053],{"class":991,"line":1089},[989,5054,5055],{"class":1060},"      Welcome to our comprehensive income expense tracker! Take control of your finances by monitoring your income and\n",[989,5057,5058],{"class":991,"line":1107},[989,5059,5060],{"class":1060},"      expenses effortlessly. Our user-friendly interface makes it simple to record transactions, categorize expenses, and\n",[989,5062,5063],{"class":991,"line":1117},[989,5064,5065],{"class":1060},"      analyze your financial trends. With real-time insights into your spending habits, you can make smarter financial\n",[989,5067,5068],{"class":991,"line":1126},[989,5069,5070],{"class":1060},"      decisions and achieve your money goals faster.\n",[989,5072,5073,5075,5077],{"class":991,"line":1132},[989,5074,1110],{"class":995},[989,5076,228],{"class":999},[989,5078,1003],{"class":995},[989,5080,5081],{"class":991,"line":1142},[989,5082,5083],{"class":1060},"    \u003C!-- Copyright Information -->\n",[989,5085,5086,5088,5090,5092,5094,5096,5099,5101],{"class":991,"line":1155},[989,5087,1014],{"class":995},[989,5089,228],{"class":999},[989,5091,1490],{"class":1020},[989,5093,1024],{"class":995},[989,5095,1027],{"class":995},[989,5097,5098],{"class":1030},"copyright",[989,5100,1027],{"class":995},[989,5102,1003],{"class":995},[989,5104,5105],{"class":991,"line":1166},[989,5106,5107],{"class":1060},"      \u003C!-- Display Current Year and Copyright Information -->\n",[989,5109,5110,5113,5115,5117,5119,5121,5123,5125],{"class":991,"line":1174},[989,5111,5112],{"class":1060},"      2024, ",[989,5114,996],{"class":995},[989,5116,33],{"class":999},[989,5118,1057],{"class":995},[989,5120,3591],{"class":1060},[989,5122,1064],{"class":995},[989,5124,33],{"class":999},[989,5126,1003],{"class":995},[989,5128,5129,5131,5133],{"class":991,"line":1187},[989,5130,1110],{"class":995},[989,5132,228],{"class":999},[989,5134,1003],{"class":995},[989,5136,5137,5140,5142],{"class":991,"line":1193},[989,5138,5139],{"class":995},"  \u003C\u002F",[989,5141,228],{"class":999},[989,5143,1003],{"class":995},[989,5145,5146,5148,5150],{"class":991,"line":1199},[989,5147,1064],{"class":995},[989,5149,1000],{"class":999},[989,5151,1003],{"class":995},[989,5153,5154,5156,5158,5161],{"class":991,"line":1209},[989,5155,996],{"class":995},[989,5157,1720],{"class":999},[989,5159,5160],{"class":1020}," scoped",[989,5162,1003],{"class":995},[989,5164,5165],{"class":991,"line":1215},[989,5166,5167],{"class":1060},"  \u002F* Make the footer occupy all available space *\u002F\n",[989,5169,5170,5173],{"class":991,"line":1229},[989,5171,5172],{"class":1060},"  .footer ",[989,5174,4390],{"class":995},[989,5176,5177],{"class":991,"line":1235},[989,5178,5179],{"class":1060},"    position:absolute;\n",[989,5181,5182,5185,5187],{"class":991,"line":1241},[989,5183,5184],{"class":1060},"    bottom:",[989,5186,4836],{"class":1777},[989,5188,1753],{"class":1060},[989,5190,5191,5194,5197,5200,5203,5205,5208,5210,5212,5214,5216],{"class":991,"line":1653},[989,5192,5193],{"class":1060},"    background",[989,5195,5196],{"class":995},"-",[989,5198,5199],{"class":1060},"color:",[989,5201,5202],{"class":4345},"rgb",[989,5204,4349],{"class":1060},[989,5206,5207],{"class":1777},"26",[989,5209,4459],{"class":995},[989,5211,5207],{"class":1777},[989,5213,4459],{"class":995},[989,5215,5207],{"class":1777},[989,5217,5218],{"class":1060},");\n",[989,5220,5221,5224,5226,5228,5231,5233,5235,5237,5239],{"class":991,"line":1659},[989,5222,5223],{"class":1060},"    color:",[989,5225,5202],{"class":4345},[989,5227,4349],{"class":1060},[989,5229,5230],{"class":1777},"238",[989,5232,4459],{"class":995},[989,5234,5230],{"class":1777},[989,5236,4459],{"class":995},[989,5238,5230],{"class":1777},[989,5240,5218],{"class":1060},[989,5242,5243],{"class":991,"line":1665},[989,5244,5245],{"class":1060},"    height:130px;\n",[989,5247,5248,5251,5253],{"class":991,"line":1671},[989,5249,5250],{"class":1060},"    text",[989,5252,5196],{"class":995},[989,5254,5255],{"class":1060},"align:center;\n",[989,5257,5258],{"class":991,"line":1690},[989,5259,5260],{"class":1060},"    padding:14px;\n",[989,5262,5263],{"class":991,"line":1695},[989,5264,5265],{"class":995},"  }\n",[989,5267,5268],{"class":991,"line":1701},[989,5269,1129],{"emptyLinePlaceholder":295},[989,5271,5272,5275],{"class":991,"line":1710},[989,5273,5274],{"class":1060},"  .copyright",[989,5276,4390],{"class":995},[989,5278,5279,5282,5284],{"class":991,"line":1715},[989,5280,5281],{"class":1060},"    margin",[989,5283,5196],{"class":995},[989,5285,5286],{"class":1060},"top:10px;\n",[989,5288,5289],{"class":991,"line":1725},[989,5290,5265],{"class":995},[989,5292,5293,5295,5297],{"class":991,"line":1731},[989,5294,1064],{"class":995},[989,5296,1720],{"class":999},[989,5298,1003],{"class":995},[15,5300,5301],{},[239,5302],{"alt":5303,"dataZoomable":265,"src":5304,"title":5305},"\"Screenshot displaying the ui-template widget's configuration\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fexploring-dashboard-2-widgets-template-widget.png","Screenshot displaying the ui-template widget's configuration",[82,5307,5309],{"id":5308},"deploying-your-application-flow","Deploying your application flow",[15,5311,5312,5313,5411],{},"{% renderFlow 450 %}\n",[989,5314,5315,5316,5329,5330,5333,5334,5337,5338,5341,5342,5344,5345,5347,5348,5350,5351,5354,5355,5358,5359,5361,5362,5364,5365,5367,5368,5371,5372,5374,5375,5382,5383,5386,5387,5390,5391,5394,5395,5398,5399,5402,5403,5406,5407,5410],{},"{\"id\":\"301c1fd8e29c3aae\",\"type\":\"ui-template\",\"z\":\"7ac3890dfa74703b\",\"group\":\"\",\"page\":\"\",\"ui\":\"a0a85a5f4c29af50\",\"name\":\"Footer\",\"order\":0,\"width\":0,\"height\":0,\"head\":\"\",\"format\":\"",[1000,5317,5318,5319,5320,5321,5320,5324,5325,5326,5328],{},"\\n  ","\\n  \u003Cdiv class=\"footer\">\\n    ","\\n    ",[228,5322,5323],{},"\\n      Welcome to our comprehensive income expense tracker! Take control of your finances by monitoring your income and\\n      expenses effortlessly. Our user-friendly interface makes it simple to record transactions, categorize expenses,\\n      and\\n      analyze your financial trends. With real-time insights into your spending habits, you can make smarter financial\\n      decisions and achieve your money goals faster.\\n    ","\\n    \u003Cdiv class=\"copyright\">\\n      ","\\n     2024, ",[33,5327,3591],{},"\\n    \\n  \\n","\\n\\n",[1720,5331,5332],{"scoped":295},"\\n  \u002F* Make the footer occupy all available space *\u002F\\n  .footer {\\n    position: absolute;\\n    bottom: 0;\\n    background-color: rgb(26, 26, 26);\\n    color: rgb(238, 238, 238);\\n    height: 130px;\\n    text-align: center;\\n    padding: 14px;\\n  }\\n\\n  .copyright {\\n    margin-top: 10px;\\n  }\\n","\",\"storeOutMessages\":true,\"passthru\":true,\"resendOnRefresh\":true,\"templateScope\":\"widget:ui\",\"className\":\"\",\"x\":910,\"y\":700,\"wires\":[[]]},{\"id\":\"342f3ee215d32fdc\",\"type\":\"group\",\"z\":\"7ac3890dfa74703b\",\"name\":\"New Icome page\",\"style\":{\"label\":true},\"nodes\":",[989,5335,5336],{},"\"d028c878350d19e1\",\"43e79bb77d718c95\",\"5ba5d8bff1a77bea\"",",\"x\":274,\"y\":279,\"w\":752,\"h\":82},{\"id\":\"d028c878350d19e1\",\"type\":\"ui-form\",\"z\":\"7ac3890dfa74703b\",\"g\":\"342f3ee215d32fdc\",\"name\":\"Income Submission Form\",\"group\":\"961528943e1bb698\",\"label\":\"\",\"order\":1,\"width\":\"0\",\"height\":\"0\",\"options\":",[989,5339,5340],{},"{\"label\":\"Date\",\"key\":\"date\",\"type\":\"date\",\"required\":true,\"rows\":null},{\"label\":\"Description\",\"key\":\"description\",\"type\":\"text\",\"required\":true,\"rows\":null},{\"label\":\"Amount\",\"key\":\"amount\",\"type\":\"number\",\"required\":true,\"rows\":null},{\"label\":\"Note\",\"key\":\"note\",\"type\":\"text\",\"required\":false,\"rows\":null}",",\"formValue\":{\"date\":\"\",\"description\":\"\",\"amount\":\"\",\"note\":\"\"},\"payload\":\"\",\"submit\":\"submit\",\"cancel\":\"clear\",\"resetOnSubmit\":true,\"topic\":\"topic\",\"topicType\":\"msg\",\"splitLayout\":\"\",\"className\":\"\",\"x\":410,\"y\":320,\"wires\":[[\"5ba5d8bff1a77bea\"]]},{\"id\":\"43e79bb77d718c95\",\"type\":\"ui-notification\",\"z\":\"7ac3890dfa74703b\",\"g\":\"342f3ee215d32fdc\",\"ui\":\"a0a85a5f4c29af50\",\"position\":\"center center\",\"colorDefault\":true,\"color\":\"#000000\",\"displayTime\":\"3\",\"showCountdown\":true,\"outputs\":0,\"allowDismiss\":true,\"dismissText\":\"Close\",\"raw\":false,\"className\":\"\",\"name\":\"\",\"x\":910,\"y\":320,\"wires\":",[989,5343],{},"},{\"id\":\"5ba5d8bff1a77bea\",\"type\":\"function\",\"z\":\"7ac3890dfa74703b\",\"g\":\"342f3ee215d32fdc\",\"name\":\"Store income\",\"func\":\"let income = global.get('income') || ",[989,5346],{},";\\n\\nincome.push({\\n    ...msg.payload,\\n    type:\"income\",\\n});\\n\\nglobal.set('income', income);\\n\\nmsg.payload = \"Thank you for submitting income!\"\\n\\nreturn msg;\",\"outputs\":1,\"timeout\":0,\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":",[989,5349],{},",\"x\":650,\"y\":320,\"wires\":[[\"43e79bb77d718c95\"]]},{\"id\":\"961528943e1bb698\",\"type\":\"ui-group\",\"name\":\"Income Submission Form\",\"page\":\"d954d73f9dcd1472\",\"width\":\"12\",\"height\":\"1\",\"order\":1,\"showTitle\":true,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"d954d73f9dcd1472\",\"type\":\"ui-page\",\"name\":\"New Income\",\"ui\":\"a0a85a5f4c29af50\",\"path\":\"\u002Fnew-Icome\",\"icon\":\"bank-transfer-in\",\"layout\":\"notebook\",\"theme\":\"aeeec3fc1077eb1c\",\"order\":1,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"aeeec3fc1077eb1c\",\"type\":\"ui-theme\",\"name\":\"dashboard\",\"colors\":{\"surface\":\"#1a1a1a\",\"primary\":\"#0094ce\",\"bgPage\":\"#eeeeee\",\"groupBg\":\"#ffffff\",\"groupOutline\":\"#cccccc\"},\"sizes\":{\"pagePadding\":\"12px\",\"groupGap\":\"12px\",\"groupBorderRadius\":\"4px\",\"widgetGap\":\"12px\"}},{\"id\":\"4afb4814be56a9a8\",\"type\":\"group\",\"z\":\"7ac3890dfa74703b\",\"name\":\"New Expense page\",\"style\":{\"label\":true},\"nodes\":",[989,5352,5353],{},"\"e82b719d899cbf73\",\"3457848652ad75e1\",\"bd90a9ad612408d3\"",",\"x\":1054,\"y\":279,\"w\":752,\"h\":82},{\"id\":\"e82b719d899cbf73\",\"type\":\"ui-form\",\"z\":\"7ac3890dfa74703b\",\"g\":\"4afb4814be56a9a8\",\"name\":\"Expense Submission Form\",\"group\":\"854706651cd8a8f2\",\"label\":\"\",\"order\":1,\"width\":\"12\",\"height\":\"1\",\"options\":",[989,5356,5357],{},"{\"label\":\"Date\",\"key\":\"date\",\"type\":\"date\",\"required\":true,\"rows\":null},{\"label\":\"Description\",\"key\":\"description\",\"type\":\"text\",\"required\":true,\"rows\":null},{\"label\":\"Category\",\"key\":\"category\",\"type\":\"text\",\"required\":true,\"rows\":null},{\"label\":\"Amount\",\"key\":\"amount\",\"type\":\"number\",\"required\":true,\"rows\":null},{\"label\":\"Note\",\"key\":\"note\",\"type\":\"text\",\"required\":false,\"rows\":null}",",\"formValue\":{\"date\":\"\",\"description\":\"\",\"category\":\"\",\"amount\":\"\",\"note\":\"\"},\"payload\":\"\",\"submit\":\"submit\",\"cancel\":\"clear\",\"resetOnSubmit\":true,\"topic\":\"topic\",\"topicType\":\"msg\",\"splitLayout\":\"\",\"className\":\"\",\"x\":1190,\"y\":320,\"wires\":[[\"bd90a9ad612408d3\"]]},{\"id\":\"3457848652ad75e1\",\"type\":\"ui-notification\",\"z\":\"7ac3890dfa74703b\",\"g\":\"4afb4814be56a9a8\",\"ui\":\"a0a85a5f4c29af50\",\"position\":\"center center\",\"colorDefault\":true,\"color\":\"#000000\",\"displayTime\":\"3\",\"showCountdown\":true,\"outputs\":0,\"allowDismiss\":true,\"dismissText\":\"Close\",\"raw\":false,\"className\":\"\",\"name\":\"\",\"x\":1690,\"y\":320,\"wires\":",[989,5360],{},"},{\"id\":\"bd90a9ad612408d3\",\"type\":\"function\",\"z\":\"7ac3890dfa74703b\",\"g\":\"4afb4814be56a9a8\",\"name\":\"Store expense\",\"func\":\"let expense = global.get('expense') || ",[989,5363],{},";\\n\\nexpense.push({\\n    ...msg.payload,\\n    type: \"expense\",\\n});\\n\\nglobal.set('expense', expense);\\n\\nmsg.payload = \"Thank you for submitting expense!\"\\n\\nreturn msg;\",\"outputs\":1,\"timeout\":0,\"noerr\":0,\"initialize\":\"\",\"finalize\":\"\",\"libs\":",[989,5366],{},",\"x\":1420,\"y\":320,\"wires\":[[\"3457848652ad75e1\"]]},{\"id\":\"854706651cd8a8f2\",\"type\":\"ui-group\",\"name\":\"Expense Submission Form\",\"page\":\"97bf3e87f4bdddc1\",\"width\":\"12\",\"height\":\"1\",\"order\":2,\"showTitle\":true,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"97bf3e87f4bdddc1\",\"type\":\"ui-page\",\"name\":\"New Expense\",\"ui\":\"a0a85a5f4c29af50\",\"path\":\"\u002Fnew-expense\",\"icon\":\"bank-transfer-out\",\"layout\":\"notebook\",\"theme\":\"aeeec3fc1077eb1c\",\"order\":2,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"77217e256ef75328\",\"type\":\"group\",\"z\":\"7ac3890dfa74703b\",\"name\":\"Your icome and expense table\",\"style\":{\"label\":true},\"nodes\":",[989,5369,5370],{},"\"452d561bf79727cb\",\"0c64567c81dd6a8d\"",",\"x\":274,\"y\":399,\"w\":572,\"h\":82},{\"id\":\"452d561bf79727cb\",\"type\":\"ui-table\",\"z\":\"7ac3890dfa74703b\",\"g\":\"77217e256ef75328\",\"group\":\"e848a5e48a6549c9\",\"name\":\"\",\"label\":\"text\",\"order\":2,\"width\":0,\"height\":0,\"maxrows\":0,\"passthru\":false,\"autocols\":true,\"selectionType\":\"click\",\"columns\":",[989,5373],{},",\"x\":770,\"y\":440,\"wires\":[[]]},{\"id\":\"0c64567c81dd6a8d\",\"type\":\"change\",\"z\":\"7ac3890dfa74703b\",\"g\":\"77217e256ef75328\",\"name\":\"Merge income and expense data\",\"rules\":",[989,5376,5377,5378,5381],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"",[989,5379,5380],{},"    $globalContext(\"income\"),\\t   $globalContext(\"expense\")\\t","\",\"tot\":\"jsonata\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":440,\"y\":440,\"wires\":[[\"452d561bf79727cb\"]]},{\"id\":\"e848a5e48a6549c9\",\"type\":\"ui-group\",\"name\":\"Your Income and Expense\",\"page\":\"7abf0b3cb6f38ca3\",\"width\":\"12\",\"height\":\"5\",\"order\":2,\"showTitle\":true,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"7abf0b3cb6f38ca3\",\"type\":\"ui-page\",\"name\":\"Your Income and expense\",\"ui\":\"a0a85a5f4c29af50\",\"path\":\"\u002Fyour-icome-expense\",\"icon\":\"calendar-multiple-check\",\"layout\":\"grid\",\"theme\":\"aeeec3fc1077eb1c\",\"order\":3,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"1b78769d6d27d102\",\"type\":\"group\",\"z\":\"7ac3890dfa74703b\",\"name\":\"Event lister\",\"style\":{\"label\":true},\"nodes\":",[989,5384,5385],{},"\"9ce6db04b2c9d7b2\"",",\"x\":74,\"y\":479,\"w\":152,\"h\":82},{\"id\":\"9ce6db04b2c9d7b2\",\"type\":\"ui-event\",\"z\":\"7ac3890dfa74703b\",\"g\":\"1b78769d6d27d102\",\"ui\":\"a0a85a5f4c29af50\",\"name\":\"\",\"x\":150,\"y\":520,\"wires\":[[\"0c64567c81dd6a8d\",\"2ca552c7e56b3619\",\"a7360e4a62bfc518\"]]},{\"id\":\"32502807f24f79b8\",\"type\":\"group\",\"z\":\"7ac3890dfa74703b\",\"name\":\"Overview chart\",\"style\":{\"label\":true},\"nodes\":",[989,5388,5389],{},"\"424b35900722e740\",\"058a77a65653d3f8\",\"7246228e57ac1fc5\",\"2ca552c7e56b3619\",\"23a4a7d15b44876b\",\"a7360e4a62bfc518\",\"fe308581b8a5b9f1\"",",\"x\":274,\"y\":519,\"w\":1392,\"h\":142},{\"id\":\"424b35900722e740\",\"type\":\"ui-chart\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"group\":\"54eca83feb7c1479\",\"name\":\"Overview Chart\",\"label\":\"chart\",\"order\":2,\"chartType\":\"bar\",\"category\":\"topic\",\"categoryType\":\"property\",\"xAxisProperty\":\"\",\"xAxisPropertyType\":\"msg\",\"xAxisType\":\"category\",\"yAxisProperty\":\"payload\",\"ymin\":\"\",\"ymax\":\"\",\"action\":\"replace\",\"pointShape\":\"circle\",\"pointRadius\":4,\"showLegend\":false,\"removeOlder\":1,\"removeOlderUnit\":\"3600\",\"removeOlderPoints\":\"\",\"colors\":",[989,5392,5393],{},"\"#1eb33c\",\"#aec7e8\",\"#ff7f0e\",\"#5f2ed1\",\"#98df8a\",\"#d62728\",\"#ff9896\",\"#9467bd\",\"#c5b0d5\"",",\"width\":\"12\",\"height\":\"6\",\"className\":\"\",\"x\":1560,\"y\":600,\"wires\":[[]]},{\"id\":\"058a77a65653d3f8\",\"type\":\"join\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"Calculate total\",\"mode\":\"reduce\",\"build\":\"object\",\"property\":\"payload\",\"propertyType\":\"msg\",\"key\":\"topic\",\"joiner\":\"\\n\",\"joinerType\":\"str\",\"accumulate\":true,\"timeout\":\"\",\"count\":\"\",\"reduceRight\":false,\"reduceExp\":\"$A+payload.amount\",\"reduceInit\":\"0\",\"reduceInitType\":\"num\",\"reduceFixup\":\"$A\",\"x\":1000,\"y\":600,\"wires\":[[\"fe308581b8a5b9f1\"]]},{\"id\":\"7246228e57ac1fc5\",\"type\":\"split\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"\",\"splt\":\"\\n\",\"spltType\":\"str\",\"arraySplt\":1,\"arraySpltType\":\"len\",\"stream\":false,\"addname\":\"\",\"x\":550,\"y\":600,\"wires\":[[\"23a4a7d15b44876b\"]]},{\"id\":\"2ca552c7e56b3619\",\"type\":\"change\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"Retrieve income\",\"rules\":",[989,5396,5397],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"income\",\"tot\":\"global\"},{\"t\":\"set\",\"p\":\"topic\",\"pt\":\"msg\",\"to\":\"income\",\"tot\":\"str\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":380,\"y\":560,\"wires\":[[\"7246228e57ac1fc5\"]]},{\"id\":\"23a4a7d15b44876b\",\"type\":\"change\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"Convert amount to number\",\"rules\":",[989,5400,5401],{},"{\"t\":\"set\",\"p\":\"payload.amount\",\"pt\":\"msg\",\"to\":\"$number(payload.amount)\\t\",\"tot\":\"jsonata\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":760,\"y\":600,\"wires\":[[\"058a77a65653d3f8\"]]},{\"id\":\"a7360e4a62bfc518\",\"type\":\"change\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"Retrieve income\",\"rules\":",[989,5404,5405],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"expense\",\"tot\":\"global\"},{\"t\":\"set\",\"p\":\"topic\",\"pt\":\"msg\",\"to\":\"expense\",\"tot\":\"str\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":380,\"y\":620,\"wires\":[[\"7246228e57ac1fc5\"]]},{\"id\":\"fe308581b8a5b9f1\",\"type\":\"join\",\"z\":\"7ac3890dfa74703b\",\"g\":\"32502807f24f79b8\",\"name\":\"Combine two object into one array\",\"mode\":\"custom\",\"build\":\"array\",\"property\":\"\",\"propertyType\":\"full\",\"key\":\"topic\",\"joiner\":\"\\n\",\"joinerType\":\"str\",\"accumulate\":false,\"timeout\":\"\",\"count\":\"2\",\"reduceRight\":false,\"reduceExp\":\"\",\"reduceInit\":\"\",\"reduceInitType\":\"\",\"reduceFixup\":\"\",\"x\":1270,\"y\":600,\"wires\":[[\"424b35900722e740\"]]},{\"id\":\"54eca83feb7c1479\",\"type\":\"ui-group\",\"name\":\"Overview\",\"page\":\"47bde79e946933d2\",\"width\":\"12\",\"height\":\"4\",\"order\":-1,\"showTitle\":true,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"47bde79e946933d2\",\"type\":\"ui-page\",\"name\":\"Overview\",\"ui\":\"a0a85a5f4c29af50\",\"path\":\"\u002Foverview\",\"icon\":\"google-analytics\",\"layout\":\"notebook\",\"theme\":\"aeeec3fc1077eb1c\",\"order\":-1,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"a0a85a5f4c29af50\",\"type\":\"ui-base\",\"name\":\"Dashboard\",\"path\":\"\u002Fdashboard\",\"includeClientData\":true,\"acceptsClientConfig\":",[989,5408,5409],{},"\"ui-notification\",\"ui-control\",\"ui-chart\",\"ui-table\"",",\"showPathInSidebar\":false,\"navigationStyle\":\"icon\"}","\n{% endrenderFlow %}",[903,5413,5414,5421],{},[30,5415,5416,5417,5420],{},"Deploy the flow by clicking the top right ",[33,5418,5419],{},"Deploy"," button.",[30,5422,5423,5424,5427],{},"Locate the *",[33,5425,5426],{},"Open Dashboard"," button at the top-right corner of the Dashboard 2.0 sidebar and click on it to navigate to the dashboard.",[15,5429,5430],{},"Now that we've built an income-expense tracker application and gained a basic understanding of Dashboard 2.0 widgets for building dashboards.",[82,5432,223],{"id":222},[15,5434,5435],{},"If you want to enhance this simple application by adding more features or want to make the application personalize for users, consider the following resources:",[27,5437,5438,5445,5453,5459,5466,5473],{},[30,5439,5440,5444],{},[256,5441,5443],{"href":5442},"\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.",[30,5446,5447,5452],{},[256,5448,5451],{"href":5449,"rel":5450},"https:\u002F\u002Fflowfuse.com\u002Fblog\u002F2024\u002F05\u002Fnode-red-dashboard-2-layout-navigation-styling\u002F",[402],"Comprehensive guide: Node-RED Dashboard 2.0 layout, sidebar, and styling"," - This comprehensive guide will cover everything about Node-RED Dashboard 2.0 styling, layouts and sidebars.",[30,5454,5455,5458],{},[256,5456,5457],{"href":1848},"Displaying logged-in users on Dashboard 2.0"," - This detailed guide demonstrates how to display logged-in users on Dashboard 2.0 which using the FlowFuse Multiuser addon and FlowFuse.",[30,5460,5461,5465],{},[256,5462,5464],{"href":5463},"\u002Fblog\u002F2024\u002F04\u002Fbuilding-an-admin-panel-in-node-red-with-dashboard-2\u002F","How to Build an Admin Dashboard with Node-RED Dashboard 2.0"," - This detailed guide demonstrates how to build a secure admin page in Node-RED Dashboard 2.0.",[30,5467,5468,5472],{},[256,5469,5471],{"href":5470},"\u002Fblog\u002F2024\u002F04\u002Fhow-to-build-an-application-with-node-red-dashboard-2\u002F","How to Build An Application With Node-RED Dashboard 2.0"," - This guide, covers how you can build personalize multiuser dashboard using flow fuse multi-user addon.",[30,5474,5475,5479],{},[256,5476,5478],{"href":5477},"\u002Fblueprints\u002Fflowfuse-dashboard\u002Fmulti-user-dashboard\u002F","Multi-User Dashboard for Ticket\u002FTask Management blueprint"," -  this blueprint allows you to utilize templates to develop a personalized multi-user dashboard quickly. This Task management blueprint has all features such as adding, updating, and deleting tasks, user profiles, and admin dashboard.",[1720,5481,5482],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":265,"searchDepth":266,"depth":266,"links":5484},[5485,5486],{"id":4201,"depth":269,"text":4202},{"id":4208,"depth":269,"text":4209,"children":5487},[5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498],{"id":4224,"depth":274,"text":4225},{"id":4290,"depth":274,"text":4291},{"id":4518,"depth":274,"text":4519},{"id":4561,"depth":274,"text":4562},{"id":4602,"depth":274,"text":4603},{"id":4681,"depth":274,"text":4682},{"id":4729,"depth":274,"text":4730},{"id":4919,"depth":274,"text":4920},{"id":4970,"depth":274,"text":4971},{"id":5308,"depth":274,"text":5309},{"id":222,"depth":274,"text":223},{"type":653,"title":5500,"description":5501},"Build and Deploy Node-RED Dashboards in Minutes","FlowFuse gives you everything you need to build, secure, and scale Node-RED Dashboard applications, with multi-user support, authentication, and production-ready deployment built in.","2024-05-27","Learn how to use Node-RED Dashboard 2.0 widgets to build interactive applications and dynamic dashboards effortlessly.","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fdashboard-widgets.png",{"excerpt":5506},{"type":12,"value":5507},[5508],[15,5509,4190],{},"\u002Fblog\u002F2024\u002F05\u002Fexploring-node-red-dashboard-2-widgets",{"title":4184,"description":5503},{"loc":5510},"blog\u002F2024\u002F05\u002Fexploring-node-red-dashboard-2-widgets","A guide to using Node-RED 2.0 Widgets for Dashboard Development.",[487,303],"ghjnb_CAsXkUxQhF1ub0RER5_s7BclC5JLh8h9D_AHY",{"id":5518,"title":5519,"authors":5520,"body":5521,"cta":6019,"date":6022,"description":6023,"extension":287,"image":6024,"lastUpdated":659,"meta":6025,"navigation":295,"path":6031,"seo":6032,"sitemap":6033,"stem":6034,"subtitle":6035,"tags":6036,"tldr":6039,"video":3,"__hash__":6040},"blog\u002Fblog\u002F2024\u002F05\u002Fmapping-location-on-dashboard-2.md","Mapping location data within Node-RED Dashboard 2.0. (2026)",[10],{"type":12,"value":5522,"toc":6007},[5523,5526,5532,5536,5545,5565,5569,5578,5606,5613,5625,5629,5632,5648,5654,5674,5680,5696,5702,5725,5731,5750,5756,5798,5802,5813,5820,5836,5842,5846,5853,5857,5884,5888,5908,5915,5919,5926,5982,5995,6002,6004],[15,5524,5525],{},"Fleet management in IoT uses sensors and software to collect real-time data on vehicles, such as location, fuel consumption, and driver behavior. This data allows companies to optimize routes, reduce costs, improve safety, and enhance overall operational efficiency of their fleet. Building an application that allows the tracking of location to support Fleet management is what this post is about.",[15,5527,5528,5529,5531],{},"Before moving further, make sure you have installed Dashboard 2.0. If you are new to Dashboard 2.0, please refer to ",[256,5530,4197],{"href":4196}," for more information.",[19,5533,5535],{"id":5534},"installing-world-map-custom-node","Installing world map custom node",[15,5537,5538,5539,5544],{},"To render an interactive world map webpage for plotting location data, we will use a popular custom node called ",[256,5540,5543],{"href":5541,"rel":5542},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-web-worldmap",[402],"node-red-contrib-web-worldmap-page",". This node offers extensive features enabling us to render a world map and plot various items with different icons, colors, NATO symbologies, ranges, and more.",[903,5546,5547,5550,5553,5556,5562],{},[30,5548,5549],{},"Click the Node-RED Settings (top-right).",[30,5551,5552],{},"Click \"Manage Palette\".",[30,5554,5555],{},"Switch to the \"Install\" tab.",[30,5557,5558,5559,437],{},"Search for ",[442,5560,5561],{},"node-red-contrib-web-worldmap",[30,5563,5564],{},"Click \"Install\".",[19,5566,5568],{"id":5567},"retrieving-location-data","Retrieving location Data",[15,5570,5571,5572,5577],{},"Before plotting locations, we need to obtain the data first. For this purpose, we will utilize the ",[256,5573,5576],{"href":5574,"rel":5575},"https:\u002F\u002Ftfe-opendata.readme.io\u002Fdocs\u002Fgetting-started",[402],"Edenburg Open Public Transportation API",". This API provides the live locations of all of Edenburg's public buses and trams, enabling us to access the necessary data for plotting on Worldmap within Dashboard 2.0.",[903,5579,5580,5586],{},[30,5581,4584,5582,5585],{},[33,5583,5584],{},"Inject"," node onto the canvas and set the repeat property to a 20-second interval.",[30,5587,5588,5589,5592,5593,5596,5597,5600,5601,5605],{},"Drag an HTTP request node onto the canvas, Dobule-click on it and choose ",[33,5590,5591],{},"GET"," method, and enter ",[442,5594,5595],{},"https:\u002F\u002Ftfe-opendata.com\u002Fapi\u002Fv1\u002Fvehicle_locations"," in the URL field and select return  as ",[33,5598,5599],{},"a parsed json object",". This API is public, so no need for environment variables. For private APIs, consider using ",[256,5602,5604],{"href":5603},"\u002Fblog\u002F2023\u002F01\u002Fenvironment-variables-in-node-red","environment variables"," for security.",[15,5607,5608],{},[239,5609],{"alt":5610,"dataZoomable":265,"src":5611,"title":5612},"\"Screenshot of the HTTP request node configuration for retrieving data from the API\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-http-request-node.png","Screenshot of the HTTP request node configuration for retrieving data from the API",[903,5614,5615],{"start":274},[30,5616,5617,5618,5620,5621,5624],{},"Connect the ",[33,5619,5584],{}," node's output to the ",[33,5622,5623],{},"HTTP request"," node's input.",[19,5626,5628],{"id":5627},"formatting-location-data","Formatting Location Data",[15,5630,5631],{},"To ensure compatibility with the Worldmap custom node, we need to format the location data appropriately.",[903,5633,5634],{},[30,5635,1284,5636,5638,5639,4750,5641,5644,5645,437],{},[33,5637,4746],{}," node onto the canvas, and set the ",[442,5640,1350],{},[442,5642,5643],{},"msg.payload.vehicles",", and give it name ",[33,5646,5647],{},"Set payload",[15,5649,5650],{},[239,5651],{"alt":5652,"dataZoomable":265,"src":5653,"title":5652},"Screenshot of the Change node setting the payload to the vehicles JSON array containing actual vehicle location data","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-change-node.png",[903,5655,5656,5660],{"start":269},[30,5657,940,5658,1287],{},[33,5659,4792],{},[30,5661,5662,5663,5665,5666,5669,5670,5673],{},"Add another ",[33,5664,4746],{}," node to the canvas. Configure it to set and delete properties as shown in the image below, and give it name ",[33,5667,5668],{},"Change and delete properties",". By changing and deleting properties of the location, we ensure that only the properties acceptable by the ",[33,5671,5672],{},"Worldmap"," node are included in the location data.",[15,5675,5676],{},[239,5677],{"alt":5678,"dataZoomable":265,"src":5679,"title":5678},"Screenshot of the Change node configuring properties to ensure compatibility with the Worldmap node","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-change-node-changing-and-deleting-properties.png",[903,5681,5682],{"start":266},[30,5683,940,5684,5687,5688,5691,5692,5695],{},[33,5685,5686],{},"Switch"," node onto the canvas and add conditions to check if ",[442,5689,5690],{},"msg.payload.vehicle_type"," is equal to ",[33,5693,5694],{},"tram"," or not.",[15,5697,5698],{},[239,5699],{"alt":5700,"dataZoomable":265,"src":5701,"title":5700},"Screenshot of the Switch node checking if the vehicle type is tram or not","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-switch-node-checking-is-vehicale-type-is-tram-or-not.png",[903,5703,5704],{"start":1071},[30,5705,5662,5706,5708,5709,5712,5713,4750,5716,2355,5719,4750,5722,437],{},[33,5707,4746],{}," node to the canvas and give it a name ",[33,5710,5711],{},"set icon and icon color for tram",". Set ",[442,5714,5715],{},"msg.payload.icon",[33,5717,5718],{},"fa-train",[442,5720,5721],{},"msg.payload.iconColor",[33,5723,5724],{},"yellow",[15,5726,5727],{},[239,5728],{"alt":5729,"dataZoomable":265,"src":5730,"title":5729},"Screenshot of the Change node setting the icon and icon color for tram","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-change-node-setting-icon-for-tram.png",[903,5732,5733],{"start":1107},[30,5734,5662,5735,5708,5737,5712,5740,4750,5742,2355,5745,4750,5747,437],{},[33,5736,4746],{},[33,5738,5739],{},"set icon and icon color for bus",[442,5741,5715],{},[33,5743,5744],{},"bus",[442,5746,5721],{},[33,5748,5749],{},"red",[15,5751,5752],{},[239,5753],{"alt":5754,"dataZoomable":265,"src":5755,"title":5754},"Screenshot of the Change node setting the icon and icon color for bus","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-change-node-setting-icon-for-bus.png",[903,5757,5758,5773],{"start":1117},[30,5759,5617,5760,5762,5763,5765,5766,5768,5769,4708,5771,574],{},[33,5761,5623],{}," node's output to the input of the ",[33,5764,4746],{}," node named ",[33,5767,5647],{},", and connect the output of that ",[33,5770,4746],{},[33,5772,4792],{},[30,5774,5775,5776,4708,5778,5765,5780,5782,5783,5785,5786,5788,5789,5765,5791,5793,5794,5765,5796,437],{},"Then, connect the output of the ",[33,5777,4792],{},[33,5779,4746],{},[33,5781,5668],{},", and connect the output of the \"Change and delete properties\" node to the input of the ",[33,5784,5686],{}," node. Then ",[33,5787,5686],{}," node's first output to the input of the ",[33,5790,4746],{},[33,5792,5711],{},", and its second output to the input of the ",[33,5795,4746],{},[33,5797,5739],{},[19,5799,5801],{"id":5800},"plotting-location-data-on-worldmap","Plotting location data on Worldmap",[903,5803,5804],{},[30,5805,940,5806,5808,5809,5812],{},[33,5807,5672],{}," node onto the canvas. Set the path to ",[33,5810,5811],{},"\u002Fworldmap"," and keep the rest of the settings unchanged, although you can modify other properties according to your preferences.",[15,5814,5815],{},[239,5816],{"alt":5817,"dataZoomable":265,"src":5818,"title":5819},"\"Screenshot displaying the configuration of the Worldmap custom node\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-worldmap-node.png","Screenshot displaying the configuration of the Worldmap custom node",[903,5821,5822,5828],{"start":269},[30,5823,4974,5824,5827],{},[33,5825,5826],{},"worldmap"," node configured, it will generate a world map with plotted data accessible at the specified path.",[30,5829,5617,5830,5833,5834,5624],{},[33,5831,5832],{},"Function"," node's output to ",[33,5835,5672],{},[15,5837,5838,5839,437],{},"Now we have successfully created a page with a world map displaying plotted vehicle location data. To confirm, you can visit ",[442,5840,5841],{},"https:\u002F\u002F\u003Cyour-instance-name>.flowfuse.cloud\u002Fworldmap",[19,5843,5845],{"id":5844},"rendering-map-on-dashboard-20","Rendering map on Dashboard 2.0",[15,5847,5848,5849,5852],{},"To render worlmap webpage on dashboard 2.0 we will use ",[33,5850,5851],{},"iframe"," custom widget which will allow us to embed an external webpage into Dashboard 2.0 applications using an iframe.",[82,5854,5856],{"id":5855},"installing-iframe-custom-widget","Installing iframe custom widget",[903,5858,5859,5862,5868,5875,5880],{},[30,5860,5861],{},"Click the Node-RED Settings (top-right)",[30,5863,5864,5865],{},"Click ",[33,5866,5867],{},"Manage Palette",[30,5869,5870,5871,5874],{},"Switch to the ",[33,5872,5873],{},"Install"," tab",[30,5876,5558,5877],{},[442,5878,5879],{},"@flowfuse\u002Fnode-red-dashboard-2-ui-iframe",[30,5881,5864,5882],{},[33,5883,5873],{},[82,5885,5887],{"id":5886},"rendering-worlmap-on-dashboard-20","Rendering worlmap on Dashboard 2.0",[903,5889,5890,5894,5902],{},[30,5891,4584,5892,4238],{},[33,5893,5851],{},[30,5895,5896,5897,2355,5899,5901],{},"Select ",[33,5898,4244],{},[33,5900,3770],{}," for it, where you want to render the webpage.",[30,5903,5904,5905,437],{},"Set height and width for it according to your preference and set URL to ",[33,5906,5907],{},"\u002Fworlmap",[15,5909,5910],{},[239,5911],{"alt":5912,"dataZoomable":265,"src":5913,"title":5914},"\"Screenshot showing configurations of iframe widget for rendering worlmap page on dashboard\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-iframe-widget.png","Screenshot showing configurations of iframe widget for rendering worlmap page on dashboard",[19,5916,5918],{"id":5917},"deploying-the-flow","Deploying the flow",[15,5920,5921],{},[239,5922],{"alt":5923,"dataZoomable":265,"src":5924,"title":5925},"\"Image displaying live locations of UK public transport on the dashboard\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-uk-live-transport.gif","Image displaying live locations of UK public transport on the dashboard",[15,5927,5928,5929,5411],{},"{% renderFlow %}\n",[989,5930,5931,5932,5935,5936,5941,5942,5945,5946,5948,5949,5951,5952,5954,5955,5958,5959,5962,5963,5966,5967,5970,5971,5974,5975,5978,5979,5981],{},"{\"id\":\"4e45e8ef870b86fb\",\"type\":\"group\",\"z\":\"eacc68e72f120b0e\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[989,5933,5934],{},"\"b6917d83.d1bac\",\"3842171.4d487e8\",\"b4f2e2dabd5b8220\",\"5f0d149d4dc38916\",\"2ff7e9501ad50cd5\",\"a08f0a836ac412a7\",\"bc891dc2aaaedc39\",\"726a8da3fe930e54\",\"b3dd7814ea5270ca\",\"0c5d6bcfd71d40da\",\"e037ee3d1f702d25\",\"d7ca6c3cdf176e4e\"",",\"x\":814,\"y\":759,\"w\":1872,\"h\":322},{\"id\":\"b6917d83.d1bac\",\"type\":\"http request\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"\",\"method\":\"GET\",\"ret\":\"obj\",\"paytoqs\":\"ignore\",\"url\":\"",[256,5937,5940],{"href":5938,"rel":5939},"https:\u002F\u002Ftfe-opendata.com\u002Fapi\u002Fv1\u002Fvehicle_locations%22,%22tls%22:%22%22,%22persist%22:false,%22proxy%22:%22%22,%22insecureHTTPParser%22:false,%22authType%22:%22%22,%22senderr%22:false,%22headers%22:%5B%5D,%22x%22:1190,%22y%22:900,%22wires%22:%5B%5B%22a08f0a836ac412a7%22%5D%5D%7D,%7B%22id%22:%223842171.4d487e8%22,%22type%22:%22inject%22,%22z%22:%22eacc68e72f120b0e%22,%22g%22:%224e45e8ef870b86fb%22,%22name%22:%22get",[402],"https:\u002F\u002Ftfe-opendata.com\u002Fapi\u002Fv1\u002Fvehicle_locations\",\"tls\":\"\",\"persist\":false,\"proxy\":\"\",\"insecureHTTPParser\":false,\"authType\":\"\",\"senderr\":false,\"headers\":[],\"x\":1190,\"y\":900,\"wires\":[[\"a08f0a836ac412a7\"]]},{\"id\":\"3842171.4d487e8\",\"type\":\"inject\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"get"," transporatation data\",\"props\":",[989,5943,5944],{},"{\"p\":\"payload\"}",",\"repeat\":\"5\",\"crontab\":\"\",\"once\":false,\"onceDelay\":\"\",\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"x\":970,\"y\":900,\"wires\":[[\"b6917d83.d1bac\"]]},{\"id\":\"b4f2e2dabd5b8220\",\"type\":\"worldmap\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"worldmap\",\"lat\":\"\",\"lon\":\"\",\"zoom\":\"\",\"layer\":\"OSMG\",\"cluster\":\"\",\"maxage\":\"\",\"usermenu\":\"show\",\"layers\":\"show\",\"panit\":\"false\",\"panlock\":\"false\",\"zoomlock\":\"false\",\"hiderightclick\":\"false\",\"coords\":\"mgrs\",\"showgrid\":\"false\",\"showruler\":\"false\",\"allowFileDrop\":\"false\",\"path\":\"\u002Fworldmap\",\"overlist\":\"DR,CO,RA,DN\",\"maplist\":\"OSMG,OSMC,EsriC,EsriS,UKOS\",\"mapname\":\"\",\"mapurl\":\"\",\"mapopt\":\"\",\"mapwms\":false,\"x\":2600,\"y\":900,\"wires\":",[989,5947],{},"},{\"id\":\"5f0d149d4dc38916\",\"type\":\"comment\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"Retrieving, formatting, and plotting location data on a world map.\",\"info\":\"\",\"x\":1390,\"y\":800,\"wires\":",[989,5950],{},"},{\"id\":\"2ff7e9501ad50cd5\",\"type\":\"comment\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"Rendering a map with plotted data on Dashboard 2.0.\",\"info\":\"\",\"x\":1440,\"y\":980,\"wires\":",[989,5953],{},"},{\"id\":\"a08f0a836ac412a7\",\"type\":\"change\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"Set payload\",\"rules\":",[989,5956,5957],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"payload.vehicles\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":1390,\"y\":900,\"wires\":[[\"726a8da3fe930e54\"]]},{\"id\":\"bc891dc2aaaedc39\",\"type\":\"change\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"Change and delete properties\",\"rules\":",[989,5960,5961],{},"{\"t\":\"set\",\"p\":\"payload.lat\",\"pt\":\"msg\",\"to\":\"payload.latitude\",\"tot\":\"msg\"},{\"t\":\"delete\",\"p\":\"payload.latitude\",\"pt\":\"msg\"},{\"t\":\"set\",\"p\":\"payload.lon\",\"pt\":\"msg\",\"to\":\"payload.longitude\",\"tot\":\"msg\"},{\"t\":\"delete\",\"p\":\"payload.longitude\",\"pt\":\"msg\"},{\"t\":\"set\",\"p\":\"payload.color\",\"pt\":\"msg\",\"to\":\"blue\",\"tot\":\"str\"},{\"t\":\"set\",\"p\":\"payload.name\",\"pt\":\"msg\",\"to\":\"payload.vehicle_id\",\"tot\":\"msg\"},{\"t\":\"delete\",\"p\":\"payload.vehicle_id\",\"pt\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":1770,\"y\":900,\"wires\":[[\"b3dd7814ea5270ca\"]]},{\"id\":\"726a8da3fe930e54\",\"type\":\"split\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"\",\"splt\":\"\\n\",\"spltType\":\"str\",\"arraySplt\":1,\"arraySpltType\":\"len\",\"stream\":false,\"addname\":\"\",\"x\":1550,\"y\":900,\"wires\":[[\"bc891dc2aaaedc39\"]]},{\"id\":\"b3dd7814ea5270ca\",\"type\":\"switch\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"is vehical type is tram\",\"property\":\"payload.vehicle_type\",\"propertyType\":\"msg\",\"rules\":",[989,5964,5965],{},"{\"t\":\"eq\",\"v\":\"tram\",\"vt\":\"str\"},{\"t\":\"else\"}",",\"checkall\":\"true\",\"repair\":false,\"outputs\":2,\"x\":2040,\"y\":900,\"wires\":[[\"0c5d6bcfd71d40da\"],",[989,5968,5969],{},"\"e037ee3d1f702d25\"","]},{\"id\":\"0c5d6bcfd71d40da\",\"type\":\"change\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"set icon and icon color for tram\",\"rules\":",[989,5972,5973],{},"{\"t\":\"set\",\"p\":\"payload.icon\",\"pt\":\"msg\",\"to\":\"fa-train\",\"tot\":\"str\"},{\"t\":\"set\",\"p\":\"payload.iconColor\",\"pt\":\"msg\",\"to\":\"yellow\",\"tot\":\"str\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":2310,\"y\":860,\"wires\":[[\"b4f2e2dabd5b8220\"]]},{\"id\":\"e037ee3d1f702d25\",\"type\":\"change\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"set icon and icon color for bus\",\"rules\":",[989,5976,5977],{},"{\"t\":\"set\",\"p\":\"payload.icon\",\"pt\":\"msg\",\"to\":\"bus\",\"tot\":\"str\"},{\"t\":\"set\",\"p\":\"payload.iconColor\",\"pt\":\"msg\",\"to\":\"red\",\"tot\":\"str\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":2310,\"y\":940,\"wires\":[[\"b4f2e2dabd5b8220\"]]},{\"id\":\"d7ca6c3cdf176e4e\",\"type\":\"ui-iframe\",\"z\":\"eacc68e72f120b0e\",\"g\":\"4e45e8ef870b86fb\",\"name\":\"\",\"group\":\"15d2dfa55e99ea43\",\"order\":0,\"src\":\"\u002Fworldmap\",\"width\":\"12\",\"height\":\"10\",\"x\":1370,\"y\":1040,\"wires\":",[989,5980],{},"},{\"id\":\"15d2dfa55e99ea43\",\"type\":\"ui-group\",\"name\":\"U.K Transportation Live\",\"page\":\"e098e3047b4a4eaa\",\"width\":\"12\",\"height\":\"1\",\"order\":-1,\"showTitle\":false,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"e098e3047b4a4eaa\",\"type\":\"ui-page\",\"name\":\"U.K Transportation Live\",\"ui\":\"c2e1aa56f50f03bd\",\"path\":\"\u002Fworldmap\",\"icon\":\"earth\",\"layout\":\"grid\",\"theme\":\"129e99574def90a3\",\"order\":-1,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"c2e1aa56f50f03bd\",\"type\":\"ui-base\",\"name\":\"Dashboard\",\"path\":\"\u002Fdashboard\",\"showPathInSidebar\":false,\"navigationStyle\":\"default\"},{\"id\":\"129e99574def90a3\",\"type\":\"ui-theme\",\"name\":\"Another Theme\",\"colors\":{\"surface\":\"#000000\",\"primary\":\"#ff4000\",\"bgPage\":\"#f0f0f0\",\"groupBg\":\"#ffffff\",\"groupOutline\":\"#d9d9d9\"},\"sizes\":{\"pagePadding\":\"9px\",\"groupGap\":\"12px\",\"groupBorderRadius\":\"9px\",\"widgetGap\":\"6px\"}}",[903,5983,5984,5990],{},[30,5985,5986,5987,5989],{},"With your flow updated to include the above, click the ",[33,5988,5419],{}," button in the top-right of the Node-RED Editor.",[30,5991,5992,5993,5427],{},"Locate the ",[33,5994,5426],{},[15,5996,5997,5998,437],{},"Now you can view the live location of Edinburgh public transport vehicles on the dashboard. Additionally, clicking on each vehicle reveals further details such as its name, speed, and other properties you've included. Moreover, if you wish to track the live locations of your own vehicles instead of Edinburgh's public transport vehicles, you can connect your devices and access GPS and sensor data using the ",[256,5999,6001],{"href":6000},"\u002Fplatform\u002Fdevice-agent\u002F","Flowfuse device agent",[19,6003,2115],{"id":2114},[15,6005,6006],{},"In conclusion, this guide shows an easy way to map location data on Dashboard 2.0. By following these steps, you can make interactive dashboards that give you real-time info, useful for things like managing fleets and tracking logistics.",{"title":265,"searchDepth":266,"depth":266,"links":6008},[6009,6010,6011,6012,6013,6017,6018],{"id":5534,"depth":269,"text":5535},{"id":5567,"depth":269,"text":5568},{"id":5627,"depth":269,"text":5628},{"id":5800,"depth":269,"text":5801},{"id":5844,"depth":269,"text":5845,"children":6014},[6015,6016],{"id":5855,"depth":274,"text":5856},{"id":5886,"depth":274,"text":5887},{"id":5917,"depth":269,"text":5918},{"id":2114,"depth":269,"text":2115},{"type":653,"title":6020,"description":6021},"Build Real-Time Fleet Tracking Dashboards","FlowFuse gives you everything you need to connect GPS devices, visualize live location data, and deploy production-ready dashboards, all on one platform.","2024-05-13","Learn how to plot location data on Dashboard 2.0 with this comprehensive step-by-step guide.","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fmapping-location-on-dashboard-2-worldmap.png",{"keywords":6026,"excerpt":6027},"node-red dashboard map, node-red worldmap, dashboard 2.0 location, fleet tracking node-red, node-red map widget",{"type":12,"value":6028},[6029],[15,6030,5525],{},"\u002Fblog\u002F2024\u002F05\u002Fmapping-location-on-dashboard-2",{"title":5519,"description":6023},{"loc":6031},"blog\u002F2024\u002F05\u002Fmapping-location-on-dashboard-2","Step-by-step guide to plot location data on dashboard 2.0.",[487,303,6037,6038,2164],"fleet tracking","location","This guide shows how to build a real-time fleet tracking dashboard in Node-RED Dashboard 2.0 using the node-red-contrib-web-worldmap node. It covers retrieving live vehicle location data from a public API, formatting it for the Worldmap node, and embedding the interactive map inside a Dashboard 2.0 iframe widget.","7moJubu1ZyLVfHzxLjzUOI_d4fMGBubL5fmxst9JDoA",{"id":6042,"title":5451,"authors":6043,"body":6044,"cta":6549,"date":6552,"description":6553,"extension":287,"image":6554,"lastUpdated":659,"meta":6555,"navigation":295,"path":6561,"seo":6562,"sitemap":6563,"stem":6564,"subtitle":6565,"tags":6566,"tldr":6570,"video":3,"__hash__":6571},"blog\u002Fblog\u002F2024\u002F05\u002Fnode-red-dashboard-2-layout-navigation-styling.md",[10],{"type":12,"value":6045,"toc":6515},[6046,6049,6056,6060,6063,6067,6070,6074,6085,6092,6095,6099,6109,6116,6120,6131,6138,6143,6147,6159,6166,6170,6173,6179,6183,6186,6190,6193,6196,6200,6203,6211,6218,6222,6225,6228,6232,6238,6252,6263,6267,6284,6291,6295,6299,6310,6317,6321,6324,6328,6331,6338,6341,6343,6346,6353,6357,6360,6367,6371,6374,6381,6384,6388,6391,6397,6401,6404,6408,6416,6423,6427,6432,6435,6449,6452,6472,6479,6482,6485],[15,6047,6048],{},"In this comprehensive guide, we will explore different layouts and sidebar styles in Dashboard 2.0. Additionally, we will cover how you can style Dashboard 2.0 elements effortlessly.",[15,6050,6051,6052,6055],{},"If you are new to Dashboard 2.0, refer to ",[256,6053,6054],{"href":4196},"Getting started with Node-RED Dashboard 2.0"," and make sure you have installed it.",[19,6057,6059],{"id":6058},"understanding-dashboard-20-layouts","Understanding Dashboard 2.0 layouts.",[15,6061,6062],{},"A layout in Node-RED Dashboard 2.0 refers to how groups of widgets are organized and arranged on a page. It controls the visual structure and placement of these widget groups to create an organized and easy-to-use interface.",[82,6064,6066],{"id":6065},"exploring-dashboard-20-layouts","Exploring Dashboard 2.0 layouts",[15,6068,6069],{},"In Dashboard 2.0, we have three types of layouts: Grid, Notebook, and Fixed.",[892,6071,6073],{"id":6072},"grid-layout","Grid layout",[15,6075,6076,6077,6080,6081,6084],{},"Choosing this layout divides your dashboard page into ",[33,6078,6079],{},"12 equally-sized columns",", and you can specify how many columns your group will occupy using the ",[442,6082,6083],{},"size"," property. When groups within a row take up all available columns, a new row automatically starts. The height of each row is determined by the tallest widget in that row.",[15,6086,6087],{},[239,6088],{"alt":6089,"dataZoomable":265,"src":6090,"title":6091},"\"Screenshot of dashboard having grid layout\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-grid-layout.jpg","Screenshot of dashboard having grid layout",[15,6093,6094],{},"In the image above, you can see that the first and last widget groups occupy all 12 columns, while in the middle, two groups each take up six columns.",[892,6096,6098],{"id":6097},"notebook-layout","Notebook layout",[15,6100,6101,6102,2355,6105,6108],{},"Choosing the Notebook layout for your page in Dashboard 2.0 makes it work like a Jupyter Notebook, fixed at a width of ",[33,6103,6104],{},"1024px",[33,6106,6107],{},"centered",". Here, a groups' \"width\" defines the number of columns the group contains. The group itself will always render the full width of the Notebook. It's great for dynamic Markdown, data tables, and visuals. Groups of pages are stacked vertically.",[15,6110,6111],{},[239,6112],{"alt":6113,"dataZoomable":265,"src":6114,"title":6115},"\"Screenshot of dashboard having notebook layout\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-notebook-layout.png","Screenshot of dashboard having notebook layout",[892,6117,6119],{"id":6118},"fixed-layout","Fixed layout",[15,6121,6122,6123,6126,6127,6130],{},"In this layout, the width value is converted to \"units\", with each unit being ",[442,6124,6125],{},"90px"," wide. For example, if you set the group width to ",[442,6128,6129],{},"3",", it will be 3 * 90 = 270px wide. Within a given group, the group size represents a column in the group's internal grid, following the same pattern as other layouts.",[15,6132,6133],{},[239,6134],{"alt":6135,"dataZoomable":265,"src":6136,"title":6137},"\"Screenshot of dashboard having fixed layout\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-fix-layout.png","Screenshot of dashboard having fixed layout",[15,6139,6140],{},[333,6141,6142],{},"Note: Currently this layout is not optimised, with plans to make it similar to Dashboard 1.0 in how it compresses content vertically, so it is recommended to use other layouts.",[82,6144,6146],{"id":6145},"setting-page-layout","Setting page layout",[903,6148,6149,6156],{},[30,6150,6151,6152,6155],{},"Navigate to the page configuration by clicking on the ",[33,6153,6154],{},"edit"," button of your page in the Dashboard 2.0 sidebar.",[30,6157,6158],{},"In the page configuration, you can select the preferred layout for that page within the layout field.",[15,6160,6161],{},[239,6162],{"alt":6163,"dataZoomable":265,"src":6164,"title":6165},"\"Image showing process of setting page layout\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-setting-new-page-layout.gif","Image showing process of setting page layout",[19,6167,6169],{"id":6168},"setting-dashboard-20-elements-size","Setting Dashboard 2.0 elements size",[15,6171,6172],{},"Setting the size for elements in Dashboard 2.0 is straightforward, but understanding the actual unit size in the size property can be a bit tricky.",[15,6174,6175,6176,437],{},"It's important to note that the size of a single horizontal unit varies depending on the layout, but the vertical size of a single row is consistently ",[33,6177,6178],{},"48px",[19,6180,6182],{"id":6181},"sizing-widgets-within-a-group","Sizing Widgets within a Group",[15,6184,6185],{},"In any layout (Grid, Notebook, or Fixed), widgets within a group are sized using a unified approach. The size property assigned to widgets determines their width within the group. Each unit in the size property represents a fraction of the group's total width. This width is determined by an internal grid established by the group.",[82,6187,6189],{"id":6188},"widget-sizing","Widget Sizing",[15,6191,6192],{},"Widgets are sized relative to the number of columns in the internal grid. For example, if a group has 4 columns and two widgets, and the first widget is set to 1 width while the second to 3 width, the first widget will occupy 25% of the group's width, and the second widget will occupy 75%.",[15,6194,6195],{},"Regardless of the layout type, the concept of sizing widgets within a group remains consistent. Whether it's the grid, notebook, or fixed layout, the same principles apply, ensuring uniformity in widget layout and design.",[82,6197,6199],{"id":6198},"setting-element-size"," Setting element size",[15,6201,6202],{},"To set the size of groups and widgets in Dashboard 2.0, follow these steps:",[903,6204,6205,6208],{},[30,6206,6207],{},"Go to the Dashboard 2.0 sidebar and click on the edit button next to the element you want to resize.",[30,6209,6210],{},"Adjust the size using the size property.",[15,6212,6213],{},[239,6214],{"alt":6215,"dataZoomable":265,"src":6216,"title":6217},"\"Image showing process of setting element size\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-setting-size.gif","Image showing process of setting element size",[19,6219,6221],{"id":6220},"understanding-dashboard-20-theme","Understanding Dashboard 2.0 Theme",[15,6223,6224],{},"The theme is a collection of colors that control the look and feel of the widgets, groups, and other elements on the page.",[15,6226,6227],{},"In Dashboard 2.0, when adding a page ( ui-page ) we can specify which theme it will use. By default, we have one theme in Dashboard 2.0, we can add more themes using the Dashboard 2.0 side panel.",[82,6229,6231],{"id":6230},"understanding-theme-properties","Understanding theme properties",[15,6233,6234,6235,6237],{},"In the theme (",[442,6236,3767],{},") configuration, there are two main sections:",[27,6239,6240,6246],{},[30,6241,6242,6245],{},[33,6243,6244],{},"Colors:"," Specify colors for Navigation, primary elements, page background, group backgrounds, and outlines.",[30,6247,6248,6251],{},[33,6249,6250],{},"Sizing:"," Define the gaps between groups, page padding, group outline radius, and gaps between widgets, all in pixels.",[15,6253,6254,6255,6257,6258,437],{},"For additional information on the ",[442,6256,3767],{}," settings, please refer to the ",[256,6259,6262],{"href":6260,"rel":6261},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fconfig\u002Fui-theme.html",[402],"ui-theme documentation",[82,6264,6266],{"id":6265},"setting-a-new-page-theme","Setting a new page theme",[903,6268,6269,6272,6275,6278,6281],{},[30,6270,6271],{},"Navigate to the Dashboard 2.0 sidebar and switch to the theme tab.",[30,6273,6274],{},"Click on the top-right “+theme” button to add a new theme.",[30,6276,6277],{},"After specifying colors and sizing click on the top right update button to save the theme.",[30,6279,6280],{},"Now switch to the layout tab and click on the edit button next to the page for which you want to set a new theme.",[30,6282,6283],{},"In the page config, select the newly added theme in the Theme field.",[15,6285,6286],{},[239,6287],{"alt":6288,"dataZoomable":265,"src":6289,"title":6290},"\"Image showing process of adding new theme\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-adding-new-theme.gif","Image showing process of adding new theme",[19,6292,6294],{"id":6293},"dashboard-20-navigation","Dashboard 2.0 Navigation",[82,6296,6298],{"id":6297},"setting-sidebar","Setting sidebar",[903,6300,6301,6304,6307],{},[30,6302,6303],{},"Navigate to the Dashboard 2.0 sidebar in the Node-RED editor",[30,6305,6306],{},"Click on the \"Edit Settings\" button located at the top left side of the Dashboard 2.0 sidebar.",[30,6308,6309],{},"Select your preferred sidebar style from the \"Style\" field in the sidebar options section.",[15,6311,6312],{},[239,6313],{"alt":6314,"dataZoomable":265,"src":6315,"title":6316},"\"Image showing process of changing sidebar style\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-setting-sidebar.gif","Image showing process of changing sidebar style",[82,6318,6320],{"id":6319},"sidebar-navigation-options","Sidebar Navigation Options",[15,6322,6323],{},"In Dashboard 2.0, we have 5 different navigation options for your application.",[892,6325,6327],{"id":6326},"collapsing","Collapsing",[15,6329,6330],{},"This is the default sidebar, when it's opened, the page content adjusts to the width of the sidebar.",[15,6332,6333],{},[239,6334],{"alt":6335,"dataZoomable":265,"src":6336,"title":6337},"\"Image showing 'Collapsing' sidebar\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-collapsing-sidebar.gif","Image showing Collapsing sidebar",[15,6339,6340],{},"You can see in the image above how the page content automatically adjusts when the sidebar is opened.",[892,6342,2042],{"id":2041},[15,6344,6345],{},"In this type, the sidebar is always visible and fixed on the left side, and the top menu icon is hidden. The page content adjusts to the width of the sidebar.",[15,6347,6348],{},[239,6349],{"alt":6350,"dataZoomable":265,"src":6351,"title":6352},"\"Image showing 'Fixed' sidebar\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-fixed-layout.png","Image showing Fixed sidebar",[892,6354,6356],{"id":6355},"collapse-to-icon","Collapse to icon",[15,6358,6359],{},"This type of sidebar is similar to the collapsible one, but when the sidebar is collapsed, you can still navigate through different pages as the page icons become visible.",[15,6361,6362],{},[239,6363],{"alt":6364,"dataZoomable":265,"src":6365,"title":6366},"\"Image showing 'Collapse to icon' sidebar\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-collaps-to-icon-sidebar.gif","Image showing Collapse to icon sidebar",[892,6368,6370],{"id":6369},"apear-over-content","Apear over content",[15,6372,6373],{},"When the sidebar is opened, the page is partially covered by a transparent layer, and the sidebar appears on top of this layer",[15,6375,6376],{},[239,6377],{"alt":6378,"dataZoomable":265,"src":6379,"title":6380},"\"Image showing 'Apear over content' sidebar\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-appear-over-content.gif","screenshot displaying searching for botFather bot for creating custom bot",[15,6382,6383],{},"In this type of sidebar, you can notice how the sidebar opens without affecting the width of the page content",[892,6385,6387],{"id":6386},"always-hide","Always hide",[15,6389,6390],{},"In this type, the sidebar is always hidden, and navigation between different pages can be achieved using the ui-control widget.",[15,6392,6393],{},[239,6394],{"alt":6395,"dataZoomable":265,"src":6396,"title":6380},"\"screenshot displaying searching for botFather bot for creating custom bot\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-always-hidden.png",[19,6398,6400],{"id":6399},"customising-your-dashboard-20-further","Customising your Dashboard 2.0 further",[15,6402,6403],{}," \nIn Dashboard 2.0, we can add classes to almost all widgets, pages, and groups and style them using CSS.",[82,6405,6407],{"id":6406},"adding-classes","Adding classes",[903,6409,6410,6413],{},[30,6411,6412],{},"To add classes to your widget, page, or group, you'll need to open its configuration",[30,6414,6415],{},"Find the 'Class' field and enter your class.",[15,6417,6418],{},[239,6419],{"alt":6420,"dataZoomable":265,"src":6421,"title":6422},"\"Screenshot showing the class property input field\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-showing-class-property-feild.png","Screenshot showing the class property input field",[82,6424,6426],{"id":6425},"writing-custom-css","Writing custom CSS",[15,6428,4565,6429,6431],{},[442,6430,869],{}," node allows you to write custom CSS for Dashboard 2.0.",[15,6433,6434],{},"In the template node, you can add CSS for two different scopes:",[27,6436,6437,6443],{},[30,6438,6439,6442],{},[33,6440,6441],{},"Single Page:"," Selecting this allows you to specify CSS that is constrained to a single page of your dashboard.",[30,6444,6445,6448],{},[33,6446,6447],{},"All Pages:"," Selecting this allows you to define CSS that will apply across your whole dashboard.",[15,6450,6451],{},"To define your own CSS:",[903,6453,6454,6457,6460,6469],{},[30,6455,6456],{},"Drag an ui-template widget onto the canvas.",[30,6458,6459],{},"Double-click on it and select the scope within the type field.",[30,6461,6462,6463,6465,6466,6468],{},"If you select the \"CSS (Single Page)\" type, you'll then need to select the ",[442,6464,4267],{}," to which your custom class definitions will apply. If you select the \"CSS (All Pages)\" type, then you'll need to select the ",[442,6467,3770],{}," that includes those pages to which you want to add styling.",[30,6470,6471],{},"Now you can write your custom CSS within the ui-template.",[15,6473,6474],{},[239,6475],{"alt":6476,"dataZoomable":265,"src":6477,"title":6478},"\"Image displaying the left side with the page and group where custom CSS has been applied, and the right side showcasing the UI-template with the corresponding CSS\"","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling-adding-style.png","Image displaying the left side with the page and group where custom CSS has been applied, and the right side showcasing the UI-template with the corresponding CSS",[19,6480,6481],{"id":222},"Up Next",[15,6483,6484],{},"To delve deeper into Node-RED Dashboard 2.0, we recommend exploring the following resources:",[27,6486,6487,6494,6501,6508],{},[30,6488,6489,6493],{},[256,6490,6492],{"href":6491},"\u002Fblog\u002Fdashboard\u002F","FlowFuse Dashboard Articles"," - Collection of examples and guides written by FlowFuse.",[30,6495,6496,6500],{},[256,6497,6499],{"href":3518,"rel":6498},[402],"Node-RED Dashboard 2.0 Documentation"," - Detailed information for each of the nodes available in Dashboard 2.0, as well as useful guides on building custom nodes and widgets of your own.",[30,6502,6503,6507],{},[256,6504,6506],{"href":3781,"rel":6505},[402],"Node-RED Forums - Dashboard 2.0"," - The Node-RED forums are a great place to ask questions, share your projects and get help from the community.",[30,6509,6510,6514],{},[256,6511,6513],{"href":6512},"\u002Febooks\u002Fbeginner-guide-to-a-professional-nodered\u002F","Beginner Guide to a Professional Node-RED"," - A free guide to an enterprise-ready Node-RED. Learn all about Node-RED history, securing your flows, and dashboard data visualization.",{"title":265,"searchDepth":266,"depth":266,"links":6516},[6517,6525,6526,6530,6534,6544,6548],{"id":6058,"depth":269,"text":6059,"children":6518},[6519,6524],{"id":6065,"depth":274,"text":6066,"children":6520},[6521,6522,6523],{"id":6072,"depth":266,"text":6073},{"id":6097,"depth":266,"text":6098},{"id":6118,"depth":266,"text":6119},{"id":6145,"depth":274,"text":6146},{"id":6168,"depth":269,"text":6169},{"id":6181,"depth":269,"text":6182,"children":6527},[6528,6529],{"id":6188,"depth":274,"text":6189},{"id":6198,"depth":274,"text":6199},{"id":6220,"depth":269,"text":6221,"children":6531},[6532,6533],{"id":6230,"depth":274,"text":6231},{"id":6265,"depth":274,"text":6266},{"id":6293,"depth":269,"text":6294,"children":6535},[6536,6537],{"id":6297,"depth":274,"text":6298},{"id":6319,"depth":274,"text":6320,"children":6538},[6539,6540,6541,6542,6543],{"id":6326,"depth":266,"text":6327},{"id":2041,"depth":266,"text":2042},{"id":6355,"depth":266,"text":6356},{"id":6369,"depth":266,"text":6370},{"id":6386,"depth":266,"text":6387},{"id":6399,"depth":269,"text":6400,"children":6545},[6546,6547],{"id":6406,"depth":274,"text":6407},{"id":6425,"depth":274,"text":6426},{"id":222,"depth":269,"text":6481},{"type":653,"title":6550,"description":6551},"Build Beautiful Node-RED Dashboards Faster","FlowFuse gives you everything you need to build, style, and deploy Node-RED Dashboard 2.0 applications, with multi-user support, authentication, and production-ready infrastructure built in. Go from prototype to a secure, shareable dashboard without managing servers. Start free today.","2024-05-10","Discover Node-RED Dashboard 2.0's three layouts (Grid, Notebook, Fixed), five navigation sidebar styles, themes, and custom CSS styling, a complete guide to controlling how your dashboards look and behave.","\u002Fblog\u002F2024\u002F05\u002Fimages\u002Fnode-red-dashboard-2-layout-navigation-styling.png",{"keywords":6556,"excerpt":6557},"node-red dashboard 2.0, node-red dashboard layout, dashboard 2.0 grid layout, node-red dashboard sidebar, node-red dashboard styling, node-red dashboard css, ui-template node, flowfuse dashboard",{"type":12,"value":6558},[6559],[15,6560,6048],{},"\u002Fblog\u002F2024\u002F05\u002Fnode-red-dashboard-2-layout-navigation-styling",{"title":5451,"description":6553},{"loc":6561},"blog\u002F2024\u002F05\u002Fnode-red-dashboard-2-layout-navigation-styling","Explore Dashboard 2.0 Different layouts and sidebars. learn how to style Dashboard 2.0 elements effortlessly.",[487,303,6567,6568,6569,2164],"flowfuse dashboard","customizing dashboard","dashboard 2.0","Node-RED Dashboard 2.0 gives you three page layouts: Grid (12 equal columns), Notebook (centered 1024px, stacked groups), and Fixed (90px per width unit); plus five navigation sidebar styles (Collapsing, Fixed, Collapse to icon, Appear over content, Always hide). Widgets are sized as a fraction of their group's internal grid, with rows a consistent 48px tall. You control colors and spacing through themes (ui-theme) and can go further with custom CSS by adding classes and writing styles in a ui-template node, scoped to a single page or all pages.","qu_-ug7umATFlAlIEkkPylpb1Vkl4dEpxKc743BM0dg",{"id":6573,"title":6574,"authors":6575,"body":6576,"cta":3,"date":8086,"description":8087,"extension":287,"image":8088,"lastUpdated":3,"meta":8089,"navigation":295,"path":8094,"seo":8095,"sitemap":8096,"stem":8097,"subtitle":8087,"tags":8098,"tldr":3,"video":3,"__hash__":8105},"blog\u002Fblog\u002F2024\u002F04\u002Fdashboard-milestones-pwa-new-components.md","Dashboard 2.0: Milestones, PWA and New Components",[309],{"type":12,"value":6577,"toc":8072},[6578,6581,6585,6588,6591,6613,6621,6625,6632,6635,6639,6647,6663,6669,6678,6687,6703,6929,6937,6946,6955,6961,6973,7419,7430,7439,7445,7941,7949,7958,7969,7974,7977,7984,7988,7991,8025,8033,8037,8040,8061,8069],[15,6579,6580],{},"With a new release of Node-RED Dashboard 2.0 we have plenty of new fixes and improvements being added to the project. In this post, we'll deep dive into community contributions, PWA support, new Vuetify components, and the rest of the great work published in this latest release.",[19,6582,6584],{"id":6583},"community-contributions","Community Contributions",[15,6586,6587],{},"We firstly wanted to take this opportunity to point out a big milestone that we're very proud to see in Node-RED Dashboard 2.0.",[15,6589,6590],{},"This release marks the first time we've had more contributions in a single release from the community, than from FlowFuse employees. I think this is a testament to the community, and a big milestone in validating the success, and popularity, of Dashboard 2.0 in the wider Node-RED community.",[15,6592,6593,6594,3553,6599,3553,6604,2355,6607,6612],{},"So thank you very much ",[256,6595,6598],{"href":6596,"rel":6597},"https:\u002F\u002Fgithub.com\u002Fbartbutenaers",[402],"@BartButenaers",[256,6600,6603],{"href":6601,"rel":6602},"https:\u002F\u002Fgithub.com\u002FEk1nox",[402],"@Ek1nox",[256,6605,4137],{"href":4135,"rel":6606},[402],[256,6608,6611],{"href":6609,"rel":6610},"https:\u002F\u002Fgithub.com\u002Fcgjgh",[402],"@cgjgh"," for for great efforts and initiative in improving Node-RED Dashboard 2.0.",[15,6614,6615,6616,6620],{},"For anyone else that's interested in contributing to the project, please do reach out, and we'll be happy to help you get started. We also have a ",[256,6617,6619],{"href":3789,"rel":6618},[402],"Contributing Guide"," if you want to dive straight in.",[19,6622,6624],{"id":6623},"progressive-web-app-pwa-support","Progressive Web App (PWA) Support",[15,6626,6627,6628,6631],{},"The biggest community contribution we saw in this release was the addition of Progressive Web App (PWA) support. This feature was added by ",[256,6629,6611],{"href":6609,"rel":6630},[402],", and allows you to install your Node-RED Dashboard 2.0 applications directly onto your platform, including Windows, iOS and Android.",[15,6633,6634],{},"This work will give your Dashboard's a much more native\u002Fnatural feel when running on your own machines, and mean you no longer need to go via your browser to access your applications.",[19,6636,6638],{"id":6637},"new-vuetify-preview-components-available","New Vuetify (Preview) Components Available",[15,6640,6641,6642,6646],{},"Vuetify is the component library on which most of our Dashboard 2.0 components are built. Our core widgets implement the more fundamental UI elements, but that doesn't stop you from building out fully customized interfaces yourself using our ",[256,6643,6645],{"href":4980,"rel":6644},[402],"ui-template node"," with the vast collection of Vuetify components.",[15,6648,6649,6650,6652,6653,6657,6658,437],{},"Within the ",[442,6651,869],{}," node, we natively support any of the ",[256,6654,6656],{"href":3589,"rel":6655},[402],"core Vuetify components",", but Vuetify itself is always evolving and often they release components into their ",[256,6659,6662],{"href":6660,"rel":6661},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Flabs\u002Fintroduction\u002F#what-is-labs",[402],"Vuetify Labs",[15,6664,6665,6666,6668],{},"In their latest releases, a few of the new components have caught our eye as we've seen them regularly requested in Dashboard 2.0. As such, we've now made available the following Vuetify components inside a ",[442,6667,869],{}," node:",[892,6670,6672,6673,3883],{"id":6671},"number-input-docs","Number Input (",[256,6674,6677],{"href":6675,"rel":6676},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Fnumber-inputs\u002F#installation",[402],"docs",[15,6679,6680,6684],{},[239,6681],{"alt":6682,"src":6683},"Number Input","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fvuetify-numeric.png",[333,6685,6686],{},"An example v-number-input from Vuetify's component library",[15,6688,6689,6690,6695,6696,6699,6700,6702],{},"We do have ",[256,6691,6694],{"href":6692,"rel":6693},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F41",[402],"plans"," for this to become a core widget, and will likely introduce this sooner, rather than later, however, in the mean time, you can now use the ",[442,6697,6698],{},"v-number-input"," component in a ",[442,6701,869],{}," node to create your own number inputs instead.",[981,6704,6706],{"className":983,"code":6705,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n    \u003Cv-number-input v-model=\"value\">\u003C\u002Fv-number-input>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  export default {\n    data() {\n      return {\n        value: 0\n      }\n    },\n    watch: {\n      value: function () {\n        this.send({payload: this.value})\n      }\n    }\n  }\n\u003C\u002Fscript>\n\n\u003Cstyle>\n    .v-number-input__control .v-btn {\n        color: var(--v-theme-on-surface);\n    }\n\u003C\u002Fstyle>\n",[442,6707,6708,6716,6740,6748,6752,6760,6769,6777,6784,6794,6799,6803,6812,6827,6853,6857,6861,6865,6873,6877,6885,6900,6917,6921],{"__ignoreMap":265},[989,6709,6710,6712,6714],{"class":991,"line":992},[989,6711,996],{"class":995},[989,6713,1000],{"class":999},[989,6715,1003],{"class":995},[989,6717,6718,6720,6722,6725,6727,6729,6732,6734,6736,6738],{"class":991,"line":269},[989,6719,1014],{"class":995},[989,6721,6698],{"class":999},[989,6723,6724],{"class":1020}," v-model",[989,6726,1024],{"class":995},[989,6728,1027],{"class":995},[989,6730,6731],{"class":1030},"value",[989,6733,1027],{"class":995},[989,6735,1340],{"class":995},[989,6737,6698],{"class":999},[989,6739,1003],{"class":995},[989,6741,6742,6744,6746],{"class":991,"line":274},[989,6743,1064],{"class":995},[989,6745,1000],{"class":999},[989,6747,1003],{"class":995},[989,6749,6750],{"class":991,"line":266},[989,6751,1129],{"emptyLinePlaceholder":295},[989,6753,6754,6756,6758],{"class":991,"line":1071},[989,6755,996],{"class":995},[989,6757,1137],{"class":999},[989,6759,1003],{"class":995},[989,6761,6762,6765,6767],{"class":991,"line":1089},[989,6763,6764],{"class":1145},"  export",[989,6766,1149],{"class":1145},[989,6768,1152],{"class":995},[989,6770,6771,6773,6775],{"class":991,"line":1107},[989,6772,1601],{"class":999},[989,6774,1161],{"class":995},[989,6776,1152],{"class":995},[989,6778,6779,6782],{"class":991,"line":1117},[989,6780,6781],{"class":1145},"      return",[989,6783,1152],{"class":995},[989,6785,6786,6789,6791],{"class":991,"line":1126},[989,6787,6788],{"class":999},"        value",[989,6790,1180],{"class":995},[989,6792,6793],{"class":1777}," 0\n",[989,6795,6796],{"class":991,"line":1132},[989,6797,6798],{"class":995},"      }\n",[989,6800,6801],{"class":991,"line":1142},[989,6802,1636],{"class":995},[989,6804,6805,6808,6810],{"class":991,"line":1155},[989,6806,6807],{"class":999},"    watch",[989,6809,1180],{"class":995},[989,6811,1152],{"class":995},[989,6813,6814,6817,6819,6822,6825],{"class":991,"line":1166},[989,6815,6816],{"class":4345},"      value",[989,6818,1180],{"class":995},[989,6820,6821],{"class":1020}," function",[989,6823,6824],{"class":995}," ()",[989,6826,1152],{"class":995},[989,6828,6829,6831,6834,6836,6839,6841,6843,6846,6848,6850],{"class":991,"line":1174},[989,6830,1674],{"class":995},[989,6832,6833],{"class":4345},"send",[989,6835,4349],{"class":999},[989,6837,6838],{"class":995},"{",[989,6840,4402],{"class":999},[989,6842,1180],{"class":995},[989,6844,6845],{"class":995}," this.",[989,6847,6731],{"class":1060},[989,6849,4425],{"class":995},[989,6851,6852],{"class":999},")\n",[989,6854,6855],{"class":991,"line":1187},[989,6856,6798],{"class":995},[989,6858,6859],{"class":991,"line":1193},[989,6860,1238],{"class":995},[989,6862,6863],{"class":991,"line":1199},[989,6864,5265],{"class":995},[989,6866,6867,6869,6871],{"class":991,"line":1209},[989,6868,1064],{"class":995},[989,6870,1137],{"class":999},[989,6872,1003],{"class":995},[989,6874,6875],{"class":991,"line":1215},[989,6876,1129],{"emptyLinePlaceholder":295},[989,6878,6879,6881,6883],{"class":991,"line":1229},[989,6880,996],{"class":995},[989,6882,1720],{"class":999},[989,6884,1003],{"class":995},[989,6886,6887,6890,6893,6896,6898],{"class":991,"line":1235},[989,6888,6889],{"class":995},"    .",[989,6891,6892],{"class":1736},"v-number-input__control",[989,6894,6895],{"class":995}," .",[989,6897,1054],{"class":1736},[989,6899,1152],{"class":995},[989,6901,6902,6905,6907,6910,6912,6915],{"class":991,"line":1241},[989,6903,6904],{"class":1744},"        color",[989,6906,1180],{"class":995},[989,6908,6909],{"class":4345}," var",[989,6911,4349],{"class":995},[989,6913,6914],{"class":1060},"--v-theme-on-surface",[989,6916,5218],{"class":995},[989,6918,6919],{"class":991,"line":1653},[989,6920,1238],{"class":995},[989,6922,6923,6925,6927],{"class":991,"line":1659},[989,6924,1064],{"class":995},[989,6926,1720],{"class":999},[989,6928,1003],{"class":995},[892,6930,6932,6933,3883],{"id":6931},"sparkline-docs","Sparkline (",[256,6934,6677],{"href":6935,"rel":6936},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Fsparklines\u002F#installation",[402],[15,6938,6939,6943],{},[239,6940],{"alt":6941,"src":6942},"Sparkline","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fvuetify-sparkline.png",[333,6944,6945],{},"An example v-sparkline rendering the output from a ui-slider",[15,6947,6948,6949,6699,6952,6954],{},"Sparklines are a great way to visualize data trends in a small space, and we've seen them requested a few times in the past. Now you can use the ",[442,6950,6951],{},"v-sparkline",[442,6953,869],{}," node to create your own sparklines.",[15,6956,6957,6958,6960],{},"This will also likely become a standalone node at some point too, possibly as a third-party widget, but for now implementing into a ",[442,6959,869],{}," is very straight forward.",[15,6962,6963,6964,6966,6967,6969,6970,6972],{},"In the following example ",[442,6965,869],{},", we append any incoming ",[442,6968,1350],{}," to a ",[442,6971,6731],{}," array and render the sparkline accordingly.",[981,6974,6976],{"className":983,"code":6975,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n  \u003Cv-sparkline class=\"nrdb-ui-sparkline\" :auto-line-width=\"false\" :fill=\"false\" :gradient=\"gradient\"\n    :gradient-direction=\"'top'\" :line-width=\"2\" :model-value=\"value\" :padding=\"8\"\n    :smooth=\"10\" :stroke-linecap=\"'round'\" :type=\"'trend'\" auto-draw>\u003C\u002Fv-sparkline>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  export default {\n    data: function () {\n      return {\n        gradient: ['#f72047', '#ffd200', '#1feaea'],\n        value: [0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0]\n      }\n    },\n    watch: {\n      msg: function () {\n        this.value.push(this.msg.payload)\n      }\n    }\n  }\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.nrdb-ui-sparkline path {\n  stroke-dasharray: 0 !important;\n}\n\u003C\u002Fstyle>\n",[442,6977,6978,6986,7039,7088,7135,7143,7147,7155,7163,7175,7181,7222,7298,7302,7306,7314,7327,7350,7354,7358,7362,7370,7374,7382,7393,7407,7411],{"__ignoreMap":265},[989,6979,6980,6982,6984],{"class":991,"line":992},[989,6981,996],{"class":995},[989,6983,1000],{"class":999},[989,6985,1003],{"class":995},[989,6987,6988,6990,6992,6994,6996,6998,7001,7003,7006,7008,7010,7013,7015,7018,7020,7022,7024,7026,7029,7031,7033,7036],{"class":991,"line":269},[989,6989,5022],{"class":995},[989,6991,6951],{"class":999},[989,6993,1490],{"class":1020},[989,6995,1024],{"class":995},[989,6997,1027],{"class":995},[989,6999,7000],{"class":1030},"nrdb-ui-sparkline",[989,7002,1027],{"class":995},[989,7004,7005],{"class":1020}," :auto-line-width",[989,7007,1024],{"class":995},[989,7009,1027],{"class":995},[989,7011,7012],{"class":1030},"false",[989,7014,1027],{"class":995},[989,7016,7017],{"class":1020}," :fill",[989,7019,1024],{"class":995},[989,7021,1027],{"class":995},[989,7023,7012],{"class":1030},[989,7025,1027],{"class":995},[989,7027,7028],{"class":1020}," :gradient",[989,7030,1024],{"class":995},[989,7032,1027],{"class":995},[989,7034,7035],{"class":1030},"gradient",[989,7037,7038],{"class":995},"\"\n",[989,7040,7041,7044,7046,7048,7051,7053,7056,7058,7060,7063,7065,7068,7070,7072,7074,7076,7079,7081,7083,7086],{"class":991,"line":274},[989,7042,7043],{"class":1020},"    :gradient-direction",[989,7045,1024],{"class":995},[989,7047,1027],{"class":995},[989,7049,7050],{"class":1030},"'top'",[989,7052,1027],{"class":995},[989,7054,7055],{"class":1020}," :line-width",[989,7057,1024],{"class":995},[989,7059,1027],{"class":995},[989,7061,7062],{"class":1030},"2",[989,7064,1027],{"class":995},[989,7066,7067],{"class":1020}," :model-value",[989,7069,1024],{"class":995},[989,7071,1027],{"class":995},[989,7073,6731],{"class":1030},[989,7075,1027],{"class":995},[989,7077,7078],{"class":1020}," :padding",[989,7080,1024],{"class":995},[989,7082,1027],{"class":995},[989,7084,7085],{"class":1030},"8",[989,7087,7038],{"class":995},[989,7089,7090,7093,7095,7097,7100,7102,7105,7107,7109,7112,7114,7117,7119,7121,7124,7126,7129,7131,7133],{"class":991,"line":266},[989,7091,7092],{"class":1020},"    :smooth",[989,7094,1024],{"class":995},[989,7096,1027],{"class":995},[989,7098,7099],{"class":1030},"10",[989,7101,1027],{"class":995},[989,7103,7104],{"class":1020}," :stroke-linecap",[989,7106,1024],{"class":995},[989,7108,1027],{"class":995},[989,7110,7111],{"class":1030},"'round'",[989,7113,1027],{"class":995},[989,7115,7116],{"class":1020}," :type",[989,7118,1024],{"class":995},[989,7120,1027],{"class":995},[989,7122,7123],{"class":1030},"'trend'",[989,7125,1027],{"class":995},[989,7127,7128],{"class":1020}," auto-draw",[989,7130,1340],{"class":995},[989,7132,6951],{"class":999},[989,7134,1003],{"class":995},[989,7136,7137,7139,7141],{"class":991,"line":1071},[989,7138,1064],{"class":995},[989,7140,1000],{"class":999},[989,7142,1003],{"class":995},[989,7144,7145],{"class":991,"line":1089},[989,7146,1129],{"emptyLinePlaceholder":295},[989,7148,7149,7151,7153],{"class":991,"line":1107},[989,7150,996],{"class":995},[989,7152,1137],{"class":999},[989,7154,1003],{"class":995},[989,7156,7157,7159,7161],{"class":991,"line":1117},[989,7158,6764],{"class":1145},[989,7160,1149],{"class":1145},[989,7162,1152],{"class":995},[989,7164,7165,7167,7169,7171,7173],{"class":991,"line":1126},[989,7166,1601],{"class":4345},[989,7168,1180],{"class":995},[989,7170,6821],{"class":1020},[989,7172,6824],{"class":995},[989,7174,1152],{"class":995},[989,7176,7177,7179],{"class":991,"line":1132},[989,7178,6781],{"class":1145},[989,7180,1152],{"class":995},[989,7182,7183,7186,7188,7191,7193,7196,7198,7200,7203,7206,7208,7210,7212,7215,7217,7220],{"class":991,"line":1142},[989,7184,7185],{"class":999},"        gradient",[989,7187,1180],{"class":995},[989,7189,7190],{"class":999}," [",[989,7192,4352],{"class":995},[989,7194,7195],{"class":1030},"#f72047",[989,7197,4352],{"class":995},[989,7199,4459],{"class":995},[989,7201,7202],{"class":995}," '",[989,7204,7205],{"class":1030},"#ffd200",[989,7207,4352],{"class":995},[989,7209,4459],{"class":995},[989,7211,7202],{"class":995},[989,7213,7214],{"class":1030},"#1feaea",[989,7216,4352],{"class":995},[989,7218,7219],{"class":999},"]",[989,7221,3187],{"class":995},[989,7223,7224,7226,7228,7230,7232,7234,7237,7239,7242,7244,7247,7249,7251,7253,7256,7258,7261,7263,7265,7267,7270,7272,7274,7276,7278,7280,7283,7285,7287,7289,7291,7293,7295],{"class":991,"line":1155},[989,7225,6788],{"class":999},[989,7227,1180],{"class":995},[989,7229,7190],{"class":999},[989,7231,4836],{"class":1777},[989,7233,4459],{"class":995},[989,7235,7236],{"class":1777}," 2",[989,7238,4459],{"class":995},[989,7240,7241],{"class":1777}," 5",[989,7243,4459],{"class":995},[989,7245,7246],{"class":1777}," 9",[989,7248,4459],{"class":995},[989,7250,7241],{"class":1777},[989,7252,4459],{"class":995},[989,7254,7255],{"class":1777}," 10",[989,7257,4459],{"class":995},[989,7259,7260],{"class":1777}," 3",[989,7262,4459],{"class":995},[989,7264,7241],{"class":1777},[989,7266,4459],{"class":995},[989,7268,7269],{"class":1777}," 0",[989,7271,4459],{"class":995},[989,7273,7269],{"class":1777},[989,7275,4459],{"class":995},[989,7277,1908],{"class":1777},[989,7279,4459],{"class":995},[989,7281,7282],{"class":1777}," 8",[989,7284,4459],{"class":995},[989,7286,7236],{"class":1777},[989,7288,4459],{"class":995},[989,7290,7246],{"class":1777},[989,7292,4459],{"class":995},[989,7294,7269],{"class":1777},[989,7296,7297],{"class":999},"]\n",[989,7299,7300],{"class":991,"line":1166},[989,7301,6798],{"class":995},[989,7303,7304],{"class":991,"line":1174},[989,7305,1636],{"class":995},[989,7307,7308,7310,7312],{"class":991,"line":1187},[989,7309,6807],{"class":999},[989,7311,1180],{"class":995},[989,7313,1152],{"class":995},[989,7315,7316,7319,7321,7323,7325],{"class":991,"line":1193},[989,7317,7318],{"class":4345},"      msg",[989,7320,1180],{"class":995},[989,7322,6821],{"class":1020},[989,7324,6824],{"class":995},[989,7326,1152],{"class":995},[989,7328,7329,7331,7333,7335,7337,7339,7342,7344,7346,7348],{"class":991,"line":1199},[989,7330,1674],{"class":995},[989,7332,6731],{"class":1060},[989,7334,437],{"class":995},[989,7336,4385],{"class":4345},[989,7338,4349],{"class":999},[989,7340,7341],{"class":995},"this.",[989,7343,3103],{"class":1060},[989,7345,437],{"class":995},[989,7347,4402],{"class":1060},[989,7349,6852],{"class":999},[989,7351,7352],{"class":991,"line":1209},[989,7353,6798],{"class":995},[989,7355,7356],{"class":991,"line":1215},[989,7357,1238],{"class":995},[989,7359,7360],{"class":991,"line":1229},[989,7361,5265],{"class":995},[989,7363,7364,7366,7368],{"class":991,"line":1235},[989,7365,1064],{"class":995},[989,7367,1137],{"class":999},[989,7369,1003],{"class":995},[989,7371,7372],{"class":991,"line":1241},[989,7373,1129],{"emptyLinePlaceholder":295},[989,7375,7376,7378,7380],{"class":991,"line":1653},[989,7377,996],{"class":995},[989,7379,1720],{"class":999},[989,7381,1003],{"class":995},[989,7383,7384,7386,7388,7391],{"class":991,"line":1659},[989,7385,437],{"class":995},[989,7387,7000],{"class":1736},[989,7389,7390],{"class":1736}," path",[989,7392,1152],{"class":995},[989,7394,7395,7398,7400,7402,7405],{"class":991,"line":1665},[989,7396,7397],{"class":1744},"  stroke-dasharray",[989,7399,1180],{"class":995},[989,7401,7269],{"class":1777},[989,7403,7404],{"class":1777}," !important",[989,7406,1753],{"class":995},[989,7408,7409],{"class":991,"line":1671},[989,7410,1698],{"class":995},[989,7412,7413,7415,7417],{"class":991,"line":1690},[989,7414,1064],{"class":995},[989,7416,1720],{"class":999},[989,7418,1003],{"class":995},[15,7420,7421,7422,7425,7426,7429],{},"There is no limitation on ",[333,7423,7424],{},"where"," you can use the sparkline either, we could, for example, add it to a ",[442,7427,7428],{},"v-data-table"," to show a sparkline of a particular feature for each row in the table:",[15,7431,7432,7436],{},[239,7433],{"alt":7434,"src":7435},"Data Table with Sparkline","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fvuetify-data-table-sparkline.png",[333,7437,7438],{},"An example v-data-table that renders a v-sparkline on each row",[15,7440,7441,7442,7444],{},"Here we see the corresponding template for the above ",[442,7443,7428],{}," example:",[981,7446,7448],{"className":983,"code":7447,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n    \u003C!-- Provide an input text box to search the content -->\n    \u003Cv-text-field v-model=\"search\" label=\"Search\" prepend-inner-icon=\"mdi-magnify\" single-line variant=\"outlined\"\n        hide-details>\u003C\u002Fv-text-field>\n    \u003Cv-data-table v-model:search=\"search\" :items=\"msg?.payload\" :headers=\"headers\">\n        \u003Ctemplate v-slot:header.pingvalues=\"{ item }\">\n            Ping History\n        \u003C\u002Ftemplate>\n        \u003Ctemplate v-slot:item.ping=\"{ item }\">\n            {{ item.ping }}ms\n        \u003C\u002Ftemplate>\n        \u003Ctemplate v-slot:item.pingvalues=\"{ item }\">\n            \u003Cv-sparkline v-model=\"item.pingValues\" :gradient=\"['#42b3f4', '#42b3f400']\"\n                :line-width=\"2\" gradientDirection=\"top\" :smooth=\"true\" :fill=\"true\">\n        \u003C\u002Ftemplate>\n\n    \u003C\u002Fv-data-table>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  data () {\n    return {\n      search: '',\n      headers: [\n        { key: 'id', title: 'ID' },\n        { key: 'ping', title: 'Ping' },\n        { key: 'pingvalues', title: 'Ping History' }\n      ]\n    }\n  }\n}\n\u003C\u002Fscript>\n",[442,7449,7450,7458,7463,7520,7531,7574,7594,7599,7607,7626,7631,7639,7658,7686,7735,7743,7747,7755,7763,7767,7775,7783,7792,7799,7811,7821,7855,7885,7916,7921,7925,7929,7933],{"__ignoreMap":265},[989,7451,7452,7454,7456],{"class":991,"line":992},[989,7453,996],{"class":995},[989,7455,1000],{"class":999},[989,7457,1003],{"class":995},[989,7459,7460],{"class":991,"line":269},[989,7461,7462],{"class":1008},"    \u003C!-- Provide an input text box to search the content -->\n",[989,7464,7465,7467,7470,7472,7474,7476,7479,7481,7484,7486,7488,7491,7493,7496,7498,7500,7503,7505,7508,7511,7513,7515,7518],{"class":991,"line":274},[989,7466,1014],{"class":995},[989,7468,7469],{"class":999},"v-text-field",[989,7471,6724],{"class":1020},[989,7473,1024],{"class":995},[989,7475,1027],{"class":995},[989,7477,7478],{"class":1030},"search",[989,7480,1027],{"class":995},[989,7482,7483],{"class":1020}," label",[989,7485,1024],{"class":995},[989,7487,1027],{"class":995},[989,7489,7490],{"class":1030},"Search",[989,7492,1027],{"class":995},[989,7494,7495],{"class":1020}," prepend-inner-icon",[989,7497,1024],{"class":995},[989,7499,1027],{"class":995},[989,7501,7502],{"class":1030},"mdi-magnify",[989,7504,1027],{"class":995},[989,7506,7507],{"class":1020}," single-line",[989,7509,7510],{"class":1020}," variant",[989,7512,1024],{"class":995},[989,7514,1027],{"class":995},[989,7516,7517],{"class":1030},"outlined",[989,7519,7038],{"class":995},[989,7521,7522,7525,7527,7529],{"class":991,"line":266},[989,7523,7524],{"class":1020},"        hide-details",[989,7526,1340],{"class":995},[989,7528,7469],{"class":999},[989,7530,1003],{"class":995},[989,7532,7533,7535,7537,7540,7542,7544,7546,7548,7551,7553,7555,7558,7560,7563,7565,7567,7570,7572],{"class":991,"line":1071},[989,7534,1014],{"class":995},[989,7536,7428],{"class":999},[989,7538,7539],{"class":1020}," v-model:search",[989,7541,1024],{"class":995},[989,7543,1027],{"class":995},[989,7545,7478],{"class":1030},[989,7547,1027],{"class":995},[989,7549,7550],{"class":1020}," :items",[989,7552,1024],{"class":995},[989,7554,1027],{"class":995},[989,7556,7557],{"class":1030},"msg?.payload",[989,7559,1027],{"class":995},[989,7561,7562],{"class":1020}," :headers",[989,7564,1024],{"class":995},[989,7566,1027],{"class":995},[989,7568,7569],{"class":1030},"headers",[989,7571,1027],{"class":995},[989,7573,1003],{"class":995},[989,7575,7576,7578,7580,7583,7585,7587,7590,7592],{"class":991,"line":1089},[989,7577,1051],{"class":995},[989,7579,1000],{"class":999},[989,7581,7582],{"class":1020}," v-slot:header.pingvalues",[989,7584,1024],{"class":995},[989,7586,1027],{"class":995},[989,7588,7589],{"class":1030},"{ item }",[989,7591,1027],{"class":995},[989,7593,1003],{"class":995},[989,7595,7596],{"class":991,"line":1107},[989,7597,7598],{"class":1060},"            Ping History\n",[989,7600,7601,7603,7605],{"class":991,"line":1117},[989,7602,1555],{"class":995},[989,7604,1000],{"class":999},[989,7606,1003],{"class":995},[989,7608,7609,7611,7613,7616,7618,7620,7622,7624],{"class":991,"line":1126},[989,7610,1051],{"class":995},[989,7612,1000],{"class":999},[989,7614,7615],{"class":1020}," v-slot:item.ping",[989,7617,1024],{"class":995},[989,7619,1027],{"class":995},[989,7621,7589],{"class":1030},[989,7623,1027],{"class":995},[989,7625,1003],{"class":995},[989,7627,7628],{"class":991,"line":1132},[989,7629,7630],{"class":1060},"            {{ item.ping }}ms\n",[989,7632,7633,7635,7637],{"class":991,"line":1142},[989,7634,1555],{"class":995},[989,7636,1000],{"class":999},[989,7638,1003],{"class":995},[989,7640,7641,7643,7645,7648,7650,7652,7654,7656],{"class":991,"line":1155},[989,7642,1051],{"class":995},[989,7644,1000],{"class":999},[989,7646,7647],{"class":1020}," v-slot:item.pingvalues",[989,7649,1024],{"class":995},[989,7651,1027],{"class":995},[989,7653,7589],{"class":1030},[989,7655,1027],{"class":995},[989,7657,1003],{"class":995},[989,7659,7660,7662,7664,7666,7668,7670,7673,7675,7677,7679,7681,7684],{"class":991,"line":1166},[989,7661,1511],{"class":995},[989,7663,6951],{"class":999},[989,7665,6724],{"class":1020},[989,7667,1024],{"class":995},[989,7669,1027],{"class":995},[989,7671,7672],{"class":1030},"item.pingValues",[989,7674,1027],{"class":995},[989,7676,7028],{"class":1020},[989,7678,1024],{"class":995},[989,7680,1027],{"class":995},[989,7682,7683],{"class":1030},"['#42b3f4', '#42b3f400']",[989,7685,7038],{"class":995},[989,7687,7688,7691,7693,7695,7697,7699,7702,7704,7706,7709,7711,7714,7716,7718,7721,7723,7725,7727,7729,7731,7733],{"class":991,"line":1174},[989,7689,7690],{"class":1020},"                :line-width",[989,7692,1024],{"class":995},[989,7694,1027],{"class":995},[989,7696,7062],{"class":1030},[989,7698,1027],{"class":995},[989,7700,7701],{"class":1020}," gradientDirection",[989,7703,1024],{"class":995},[989,7705,1027],{"class":995},[989,7707,7708],{"class":1030},"top",[989,7710,1027],{"class":995},[989,7712,7713],{"class":1020}," :smooth",[989,7715,1024],{"class":995},[989,7717,1027],{"class":995},[989,7719,7720],{"class":1030},"true",[989,7722,1027],{"class":995},[989,7724,7017],{"class":1020},[989,7726,1024],{"class":995},[989,7728,1027],{"class":995},[989,7730,7720],{"class":1030},[989,7732,1027],{"class":995},[989,7734,1003],{"class":995},[989,7736,7737,7739,7741],{"class":991,"line":1187},[989,7738,1555],{"class":995},[989,7740,1000],{"class":999},[989,7742,1003],{"class":995},[989,7744,7745],{"class":991,"line":1193},[989,7746,1129],{"emptyLinePlaceholder":295},[989,7748,7749,7751,7753],{"class":991,"line":1199},[989,7750,1110],{"class":995},[989,7752,7428],{"class":999},[989,7754,1003],{"class":995},[989,7756,7757,7759,7761],{"class":991,"line":1209},[989,7758,1064],{"class":995},[989,7760,1000],{"class":999},[989,7762,1003],{"class":995},[989,7764,7765],{"class":991,"line":1215},[989,7766,1129],{"emptyLinePlaceholder":295},[989,7768,7769,7771,7773],{"class":991,"line":1229},[989,7770,996],{"class":995},[989,7772,1137],{"class":999},[989,7774,1003],{"class":995},[989,7776,7777,7779,7781],{"class":991,"line":1235},[989,7778,1592],{"class":1145},[989,7780,1149],{"class":1145},[989,7782,1152],{"class":995},[989,7784,7785,7788,7790],{"class":991,"line":1241},[989,7786,7787],{"class":999},"  data",[989,7789,6824],{"class":995},[989,7791,1152],{"class":995},[989,7793,7794,7797],{"class":991,"line":1653},[989,7795,7796],{"class":1145},"    return",[989,7798,1152],{"class":995},[989,7800,7801,7804,7806,7809],{"class":991,"line":1659},[989,7802,7803],{"class":999},"      search",[989,7805,1180],{"class":995},[989,7807,7808],{"class":995}," ''",[989,7810,3187],{"class":995},[989,7812,7813,7816,7818],{"class":991,"line":1665},[989,7814,7815],{"class":999},"      headers",[989,7817,1180],{"class":995},[989,7819,7820],{"class":999}," [\n",[989,7822,7823,7826,7829,7831,7833,7836,7838,7840,7843,7845,7847,7850,7852],{"class":991,"line":1671},[989,7824,7825],{"class":995},"        {",[989,7827,7828],{"class":999}," key",[989,7830,1180],{"class":995},[989,7832,7202],{"class":995},[989,7834,7835],{"class":1030},"id",[989,7837,4352],{"class":995},[989,7839,4459],{"class":995},[989,7841,7842],{"class":999}," title",[989,7844,1180],{"class":995},[989,7846,7202],{"class":995},[989,7848,7849],{"class":1030},"ID",[989,7851,4352],{"class":995},[989,7853,7854],{"class":995}," },\n",[989,7856,7857,7859,7861,7863,7865,7868,7870,7872,7874,7876,7878,7881,7883],{"class":991,"line":1690},[989,7858,7825],{"class":995},[989,7860,7828],{"class":999},[989,7862,1180],{"class":995},[989,7864,7202],{"class":995},[989,7866,7867],{"class":1030},"ping",[989,7869,4352],{"class":995},[989,7871,4459],{"class":995},[989,7873,7842],{"class":999},[989,7875,1180],{"class":995},[989,7877,7202],{"class":995},[989,7879,7880],{"class":1030},"Ping",[989,7882,4352],{"class":995},[989,7884,7854],{"class":995},[989,7886,7887,7889,7891,7893,7895,7898,7900,7902,7904,7906,7908,7911,7913],{"class":991,"line":1695},[989,7888,7825],{"class":995},[989,7890,7828],{"class":999},[989,7892,1180],{"class":995},[989,7894,7202],{"class":995},[989,7896,7897],{"class":1030},"pingvalues",[989,7899,4352],{"class":995},[989,7901,4459],{"class":995},[989,7903,7842],{"class":999},[989,7905,1180],{"class":995},[989,7907,7202],{"class":995},[989,7909,7910],{"class":1030},"Ping History",[989,7912,4352],{"class":995},[989,7914,7915],{"class":995}," }\n",[989,7917,7918],{"class":991,"line":1701},[989,7919,7920],{"class":999},"      ]\n",[989,7922,7923],{"class":991,"line":1710},[989,7924,1238],{"class":995},[989,7926,7927],{"class":991,"line":1715},[989,7928,5265],{"class":995},[989,7930,7931],{"class":991,"line":1725},[989,7932,1698],{"class":995},[989,7934,7935,7937,7939],{"class":991,"line":1731},[989,7936,1064],{"class":995},[989,7938,1137],{"class":999},[989,7940,1003],{"class":995},[892,7942,7944,7945,3883],{"id":7943},"treeview-docs","Treeview (",[256,7946,6677],{"href":7947,"rel":7948},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Ftreeview\u002F#installation",[402],[15,7950,7951,7955],{},[239,7952],{"alt":7953,"src":7954},"Treeview","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fvuetify-treeview.png",[333,7956,7957],{},"An example v-treeview from Vuetify Lab's component library",[15,7959,3147,7960,7963,7964,6699,7966,7968],{},[442,7961,7962],{},"v-treeview"," component is a great way to visualize hierarchical data in a tree-like structure. We've seen this requested a few times in the past, and now you can use the ",[442,7965,7962],{},[442,7967,869],{}," node to create your own treeviews.",[15,7970,7971,7972,574],{},"There is still scope for this to, one day, become a core or third party widget, but in the mean time, it's very easy to get this up and running in a ",[442,7973,869],{},[15,7975,7976],{},"The Treeview example, and other examples above are available in this sample flow:",[5851,7978],{"width":7979,"height":7980,"src":7981,"allow":7982,"style":7983},"100%","340px","https:\u002F\u002Fflows.nodered.org\u002Fflow\u002F0ac4d82aaf97409cb0dce9812cfa214c\u002Fshare?height=300","clipboard-read; clipboard-write","border: none;",[19,7985,7987],{"id":7986},"other-highlights","Other Highlights",[15,7989,7990],{},"Whilst the above are the main highlights of this release, we've also had a number of other smaller improvements and fixes that have been added to the project. These include:",[27,7992,7993,8001,8009,8017],{},[30,7994,7995,7996],{},"UI Radio Group - Dynamic radio options in ",[256,7997,8000],{"href":7998,"rel":7999},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F765",[402],"#765",[30,8002,8003,8004],{},"UI Notification - Notification output & output msg when button clicked in ",[256,8005,8008],{"href":8006,"rel":8007},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F766",[402],"#766",[30,8010,8011,8012],{},"UI Dropdown - Clear dropdown selection in ",[256,8013,8016],{"href":8014,"rel":8015},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F775",[402],"#775",[30,8018,8019,8020],{},"UI Button - Add \"Emulate Click\" option in ",[256,8021,8024],{"href":8022,"rel":8023},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F783",[402],"#783",[15,8026,8027,8028,437],{},"You can see the full list of changes in the ",[256,8029,8032],{"href":8030,"rel":8031},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv1.8.0",[402],"1.8.0 Release Notes",[19,8034,8036],{"id":8035},"follow-our-progress","Follow our Progress",[15,8038,8039],{},"New features and improvements are coming to Node-RED Dashboard 2.0 every week, if you're interested in what we have lined up, or want to contribute yourself, then you can track the work we have lined up on our GitHub Projects:",[27,8041,8042,8048,8054],{},[30,8043,8044],{},[256,8045,8047],{"href":448,"rel":8046},[402],"Dashboard 2.0 Activity Tracker",[30,8049,8050],{},[256,8051,8053],{"href":2553,"rel":8052},[402],"Dashboard 2.0 Planning Board",[30,8055,8056],{},[256,8057,8060],{"href":8058,"rel":8059},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F5",[402],"Dashboard 1.0 Feature Parity Tracker",[15,8062,8063,8064,437],{},"If you have any feature requests, bugs\u002Fcomplaints or general feedback, please do reach out, and raise issues on our relevant ",[256,8065,8068],{"href":8066,"rel":8067},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard",[402],"GitHub repository",[1720,8070,8071],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":265,"searchDepth":266,"depth":266,"links":8073},[8074,8075,8076,8084,8085],{"id":6583,"depth":269,"text":6584},{"id":6623,"depth":269,"text":6624},{"id":6637,"depth":269,"text":6638,"children":8077},[8078,8080,8082],{"id":6671,"depth":266,"text":8079},"Number Input (docs)",{"id":6931,"depth":266,"text":8081},"Sparkline (docs)",{"id":7943,"depth":266,"text":8083},"Treeview (docs)",{"id":7986,"depth":269,"text":7987},{"id":8035,"depth":269,"text":8036},"2024-04-26","Checkout all the great content that's been added to Dashboard 2.0 in the past few weeks and the new (in-preview) Vuetify components we've made available in UI Template nodes.","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fmilestones-pwa-new-components.png",{"excerpt":8090},{"type":12,"value":8091},[8092],[15,8093,6580],{},"\u002Fblog\u002F2024\u002F04\u002Fdashboard-milestones-pwa-new-components",{"title":6574,"description":8087},{"loc":8094},"blog\u002F2024\u002F04\u002Fdashboard-milestones-pwa-new-components",[487,8099,8100,8101,303,8102,8103,8104,3591],"releases","community","changelog","node-red Dashboard 2.0","node-red visualization","progressive web app","wN8APZfbU3DYJJbfJLITj3Q6NLQOkw0QIT7ucl46qOg",{"id":8107,"title":8108,"authors":8109,"body":8110,"cta":9596,"date":9599,"description":9600,"extension":287,"image":9601,"lastUpdated":659,"meta":9602,"navigation":295,"path":9608,"seo":9609,"sitemap":9610,"stem":9611,"subtitle":9612,"tags":9613,"tldr":9614,"video":3,"__hash__":9615},"blog\u002Fblog\u002F2024\u002F04\u002Fhow-to-build-an-application-with-node-red-dashboard-2.md","How to Build An Application With Node-RED Dashboard 2.0 (2026)",[10],{"type":12,"value":8111,"toc":9583},[8112,8115,8121,8125,8133,8139,8143,8150,8153,8157,8166,8173,8181,8188,8192,8195,8207,8378,8388,8392,8401,8408,8430,8434,8437,8459,8466,8473,8574,8587,8591,8597,8605,8612,8628,8632,8645,8659,8666,8671,9520,9530,9532,9539,9550,9553,9557,9560,9580],[15,8113,8114],{},"In this guide, we'll build a Todo application to guide you through the features and explain how you can build rich and dynamic applications too. It shows many of the features that make Dashboard 2.0 great, and why you should use it over the deprecated node-red-dashboard.",[15,8116,8117,8118,8120],{},"If you're new to Dashboard 2.0, refer to our blog post ",[256,8119,4197],{"href":4196}," to install and get things started.",[19,8122,8124],{"id":8123},"installing-flowfuse-user-addon","Installing Flowfuse user addon",[15,8126,8127,8128,8132],{},"The FlowFuse User Addon is a plugin developed for Dashboard 2.0, that levereges the FlowFuse API to access logged in user's information at Dashboard 2.0. For detailed information refer to the ",[256,8129,8131],{"href":8130},"\u002Fblog\u002F2024\u002F04\u002Fdisplaying-logged-in-users-on-dashboard\u002F#exploring-the-flowfuse-user-addon","Exploring the FlowFuse User Addon"," and make sure to install it.",[15,8134,8135,8136,8138],{},"Before you begin the application development process, please make sure that FlowFuse user authentication is enabled. This feature adds a layer of security to your application with a login page. By combining the FlowFuse user addon with user authentication, we gain access to the logged in user's data within our application. For more information on FlowFuse user authentication, refer to the ",[256,8137,1356],{"href":1404}," and make sure that it is enabled.",[19,8140,8142],{"id":8141},"building-task-management-application","Building Task Management application",[15,8144,8145],{},[239,8146],{"alt":8147,"dataZoomable":265,"src":8148,"title":8149},"\"Screenshot of the Todo application built with Node-RED Dashboard 2.0\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-2-task-management-system.gif","Screenshot of the task management system built with Node-RED Dashboard 2.0",[15,8151,8152],{},"Throughout this guide, we will be building a simple, secure, and personalized Task management application that will allow users to create and view their tasks.",[82,8154,8156],{"id":8155},"building-a-form-to-submit-tasks","Building a Form to Submit Tasks",[903,8158,8159,8163],{},[30,8160,4584,8161,4238],{},[33,8162,4231],{},[30,8164,8165],{},"Click on the edit icon next to Page 1 (The default page added when you install Dashboard 2.0) in the Dashboard 2.0 sidebar. While this step is optional, updating the page configurations as shown in the image below ensures that your application aligns with the layout described in this guide.",[15,8167,8168],{},[239,8169],{"alt":8170,"dataZoomable":265,"src":8171,"title":8172},"\"Screenshot displaying 'new task' page configurations\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-2-page1-configuration.png","Screenshot displaying 'new task' page configurations",[903,8174,8175],{"start":274},[30,8176,8177,8178,8180],{},"Click on the ",[33,8179,4231],{}," widget to add form elements such as title, description, due date, and priority.",[15,8182,8183],{},[239,8184],{"alt":8185,"dataZoomable":265,"src":8186,"title":8187},"\"Screenshot of ui widget form configuration\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-2-task-submission-form.png","Screenshot of ui widget form configuration",[82,8189,8191],{"id":8190},"storing-tasks-in-the-global-context","Storing Tasks in the Global Context",[15,8193,8194],{},"For this guide, we are storing our Tasks in Node-RED global context but storing them  in a database will make it easy to manage your task data.",[903,8196,8197,8202],{},[30,8198,940,8199,8201],{},[33,8200,4307],{}," node onto the canvas",[30,8203,8204,8205,574],{},"Paste the below code in the ",[33,8206,4307],{},[981,8208,8210],{"className":4318,"code":8209,"language":4320,"meta":265,"style":265},"\u002F\u002F Retrieve the existing tasks from the global context or initialize an empty array if none exists\n\nlet tasks = global.get('tasks') || [];\n\n\u002F\u002F Push the new task object into the tasks array, including the task details and the user object extracted from the message object, as each payload emitted by the Node-RED Dashboard 2.0 widgets contains user information due to the FlowFuse User Addon.\n\ntasks.push({\n  ...msg.payload,\n  ...{\n    user: msg._client.user \u002F\u002F Assign the user object to the task\n  }\n});\n\n\u002F\u002F Update the 'tasks' variable in the global context with the modified tasks array\n\nglobal.set('tasks', tasks);\n\nreturn msg;\n",[442,8211,8212,8217,8221,8253,8257,8262,8266,8278,8291,8296,8317,8322,8330,8334,8339,8343,8366,8370],{"__ignoreMap":265},[989,8213,8214],{"class":991,"line":992},[989,8215,8216],{"class":1008},"\u002F\u002F Retrieve the existing tasks from the global context or initialize an empty array if none exists\n",[989,8218,8219],{"class":991,"line":269},[989,8220,1129],{"emptyLinePlaceholder":295},[989,8222,8223,8225,8228,8230,8232,8234,8236,8238,8240,8243,8245,8247,8249,8251],{"class":991,"line":274},[989,8224,4332],{"class":1020},[989,8226,8227],{"class":1060}," tasks ",[989,8229,1024],{"class":995},[989,8231,4340],{"class":1060},[989,8233,437],{"class":995},[989,8235,4346],{"class":4345},[989,8237,4349],{"class":1060},[989,8239,4352],{"class":995},[989,8241,8242],{"class":1030},"tasks",[989,8244,4352],{"class":995},[989,8246,4359],{"class":1060},[989,8248,4362],{"class":995},[989,8250,4365],{"class":1060},[989,8252,1753],{"class":995},[989,8254,8255],{"class":991,"line":266},[989,8256,1129],{"emptyLinePlaceholder":295},[989,8258,8259],{"class":991,"line":1071},[989,8260,8261],{"class":1008},"\u002F\u002F Push the new task object into the tasks array, including the task details and the user object extracted from the message object, as each payload emitted by the Node-RED Dashboard 2.0 widgets contains user information due to the FlowFuse User Addon.\n",[989,8263,8264],{"class":991,"line":1089},[989,8265,1129],{"emptyLinePlaceholder":295},[989,8267,8268,8270,8272,8274,8276],{"class":991,"line":1107},[989,8269,8242],{"class":1060},[989,8271,437],{"class":995},[989,8273,4385],{"class":4345},[989,8275,4349],{"class":1060},[989,8277,4390],{"class":995},[989,8279,8280,8283,8285,8287,8289],{"class":991,"line":1117},[989,8281,8282],{"class":995},"  ...",[989,8284,3103],{"class":1060},[989,8286,437],{"class":995},[989,8288,4402],{"class":1060},[989,8290,3187],{"class":995},[989,8292,8293],{"class":991,"line":1126},[989,8294,8295],{"class":995},"  ...{\n",[989,8297,8298,8301,8303,8305,8307,8309,8311,8314],{"class":991,"line":1132},[989,8299,8300],{"class":999},"    user",[989,8302,1180],{"class":995},[989,8304,4510],{"class":1060},[989,8306,437],{"class":995},[989,8308,4013],{"class":1060},[989,8310,437],{"class":995},[989,8312,8313],{"class":1060},"user ",[989,8315,8316],{"class":1008},"\u002F\u002F Assign the user object to the task\n",[989,8318,8319],{"class":991,"line":1142},[989,8320,8321],{"class":995},"  }\n",[989,8323,8324,8326,8328],{"class":991,"line":1155},[989,8325,4425],{"class":995},[989,8327,3883],{"class":1060},[989,8329,1753],{"class":995},[989,8331,8332],{"class":991,"line":1166},[989,8333,1129],{"emptyLinePlaceholder":295},[989,8335,8336],{"class":991,"line":1174},[989,8337,8338],{"class":1008},"\u002F\u002F Update the 'tasks' variable in the global context with the modified tasks array\n",[989,8340,8341],{"class":991,"line":1187},[989,8342,1129],{"emptyLinePlaceholder":295},[989,8344,8345,8347,8349,8351,8353,8355,8357,8359,8361,8364],{"class":991,"line":1193},[989,8346,4443],{"class":1060},[989,8348,437],{"class":995},[989,8350,4448],{"class":4345},[989,8352,4349],{"class":1060},[989,8354,4352],{"class":995},[989,8356,8242],{"class":1030},[989,8358,4352],{"class":995},[989,8360,4459],{"class":995},[989,8362,8363],{"class":1060}," tasks)",[989,8365,1753],{"class":995},[989,8367,8368],{"class":991,"line":1199},[989,8369,1129],{"emptyLinePlaceholder":295},[989,8371,8372,8374,8376],{"class":991,"line":1209},[989,8373,4507],{"class":1145},[989,8375,4510],{"class":1060},[989,8377,1753],{"class":995},[903,8379,8380],{"start":274},[30,8381,5617,8382,8384,8385,8387],{},[33,8383,4231],{}," widget’s output to the ",[33,8386,4307],{}," node’s input.",[82,8389,8391],{"id":8390},"displaying-notification-on-successful-task-submission","Displaying notification on successful task submission",[903,8393,8394],{},[30,8395,940,8396,4797,8398,8400],{},[33,8397,4613],{},[442,8399,1350],{}," to the confirmation message you want to display on successful task submission.",[15,8402,8403],{},[239,8404],{"alt":8405,"dataZoomable":265,"src":8406,"title":8407},"\"screenshot of the change node setting payload for notification\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-change-node-setting-payload-for-notification.png","screenshot of the change node setting payload for notification",[903,8409,8410,8418],{"start":269},[30,8411,4584,8412,8414,8415,8417],{},[33,8413,3918],{}," onto the canvas select ",[33,8416,3770],{}," and set the position to \"center\".",[30,8419,5617,8420,8384,8422,8424,8425,8427,8428,4958],{},[33,8421,4231],{},[33,8423,4613],{}," node’s input and the ",[33,8426,4613],{}," node’s output to the ",[33,8429,3918],{},[82,8431,8433],{"id":8432},"retrieving-and-filtering-tasks","Retrieving and Filtering Tasks",[15,8435,8436],{},"Now that we can store tasks along with the user details of who submitted them, we need to retrieve and filter them based on users, ensuring that users can only see their tasks only and not others.",[903,8438,8439,8450],{},[30,8440,940,8441,8443,8444,8446,8447,8449],{},[33,8442,3997],{}," widget onto the canvas and select ",[33,8445,3770],{}," for it. The ",[33,8448,3997],{}," will enable us to display updated tasks on the table without the need for polling, as it triggers when the page reloads or changes.",[30,8451,940,8452,4797,8454,4750,8456,437],{},[33,8453,4613],{},[442,8455,1350],{},[442,8457,8458],{},"global.tasks",[15,8460,8461],{},[239,8462],{"alt":8463,"dataZoomable":265,"src":8464,"title":8465},"\"Screenshot of the change setting retriving global context and setting to msg.payload\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-change-node-retriving-global-context-data.png","Screenshot of the change setting retriving global context and setting to msg.payload",[903,8467,8468],{"start":274},[30,8469,940,8470,8472],{},[33,8471,4307],{}," node onto the canvas and paste the below code into it.",[981,8474,8476],{"className":4318,"code":8475,"language":4320,"meta":265,"style":265},"\u002F\u002F Filter the payload array of tasks to include only those tasks associated with the currently logged in user.\n\nmsg.payload = msg.payload.filter((task) => task.user.userId === msg._client.user.userId);\n\n\u002F\u002F Return the modified message object containing the filtered tasks.\n\nreturn msg;\n",[442,8477,8478,8483,8487,8553,8557,8562,8566],{"__ignoreMap":265},[989,8479,8480],{"class":991,"line":992},[989,8481,8482],{"class":1008},"\u002F\u002F Filter the payload array of tasks to include only those tasks associated with the currently logged in user.\n",[989,8484,8485],{"class":991,"line":269},[989,8486,1129],{"emptyLinePlaceholder":295},[989,8488,8489,8491,8493,8495,8497,8499,8501,8503,8505,8508,8510,8512,8516,8518,8521,8524,8526,8528,8530,8533,8536,8538,8540,8542,8544,8546,8548,8551],{"class":991,"line":274},[989,8490,3103],{"class":1060},[989,8492,437],{"class":995},[989,8494,4482],{"class":1060},[989,8496,1024],{"class":995},[989,8498,4510],{"class":1060},[989,8500,437],{"class":995},[989,8502,4402],{"class":1060},[989,8504,437],{"class":995},[989,8506,8507],{"class":4345},"filter",[989,8509,4349],{"class":1060},[989,8511,4349],{"class":995},[989,8513,8515],{"class":8514},"sHdIc","task",[989,8517,3883],{"class":995},[989,8519,8520],{"class":1020}," =>",[989,8522,8523],{"class":1060}," task",[989,8525,437],{"class":995},[989,8527,3877],{"class":1060},[989,8529,437],{"class":995},[989,8531,8532],{"class":1060},"userId ",[989,8534,8535],{"class":995},"===",[989,8537,4510],{"class":1060},[989,8539,437],{"class":995},[989,8541,4013],{"class":1060},[989,8543,437],{"class":995},[989,8545,3877],{"class":1060},[989,8547,437],{"class":995},[989,8549,8550],{"class":1060},"userId)",[989,8552,1753],{"class":995},[989,8554,8555],{"class":991,"line":266},[989,8556,1129],{"emptyLinePlaceholder":295},[989,8558,8559],{"class":991,"line":1071},[989,8560,8561],{"class":1008},"\u002F\u002F Return the modified message object containing the filtered tasks.\n",[989,8563,8564],{"class":991,"line":1089},[989,8565,1129],{"emptyLinePlaceholder":295},[989,8567,8568,8570,8572],{"class":991,"line":1107},[989,8569,4507],{"class":1145},[989,8571,4510],{"class":1060},[989,8573,1753],{"class":995},[903,8575,8576],{"start":266},[30,8577,5617,8578,8384,8580,8424,8582,8584,8585,8387],{},[33,8579,3997],{},[33,8581,4613],{},[33,8583,4613],{}," nodes’ output to the ",[33,8586,4307],{},[82,8588,8590],{"id":8589},"enabling-client-constraint-for-ui-template","Enabling client constraint for ui-template",[15,8592,8593,8594,8596],{},"Before we begin building our table to display tasks, we need to enable access to client constraints for the ",[33,8595,869],{}," widget. Access client constraints ensure that messages or actions are specifically targeted to individual clients. For instance, if 100 people are interacting with the same task management dashboard simultaneously and one person submits a task, the notification will only be visible to that person and not to the remaining 99 individuals.",[15,8598,8599,8600,2355,8602,8604],{},"If you have experience with Node-RED Dashboard 1.0, you may recall that these client constraints were only available for ",[33,8601,3921],{},[33,8603,3918],{}," widgets but in Dashboard 2.0 you can enable it for any widget.",[15,8606,8607],{},[239,8608],{"alt":8609,"dataZoomable":265,"src":8610,"title":8611},"\"Screenshot displaying FF Auth tab\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-2-ff-auth-tab.png","Screenshot displaying FF Auth tab",[903,8613,8614,8617],{},[30,8615,8616],{},"Navigate to the Dashboard 2.0 sidebar and select the top-right \"FF Auth\" Tab",[30,8618,8619,8620,2355,8622,8624,8625,8627],{},"In the \"Accept Client Constraints\" option, you'll see Dashboard 2.0 widgets where this option is by default enabled for ",[33,8621,3918],{},[33,8623,3921],{},", enable it for ",[33,8626,869],{}," as well.",[82,8629,8631],{"id":8630},"creating-a-table-and-displaying-the-task","Creating a table and displaying the task",[15,8633,8634,8635,2355,8637,8642,8643,801],{},"In this section, we will build an interactive table using ",[33,8636,869],{},[256,8638,8641],{"href":8639,"rel":8640},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Fall\u002F",[402],"vuetify component",". Vuetify offers a wide range of components, all of which are compatible with our Node-RED Dashboard 2.0's ui-template widget. You can easily use them by just simply copying and pasting them into the ",[33,8644,869],{},[903,8646,8647,8652],{},[30,8648,4584,8649,8651],{},[33,8650,869],{}," widget onto the canvas",[30,8653,4698,8654,2355,8656,8658],{},[33,8655,4267],{},[33,8657,4244],{}," for it. Below, I have provided a screenshot of the \"new task\" page configurations. Again You can replicate it if you want to align with the layout described in this guide, otherwise, it is optional.",[15,8660,8661],{},[239,8662],{"alt":8663,"dataZoomable":265,"src":8664,"title":8665},"\"Screenshot displaying ui-template widget with code for building table for displaying task\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-template-widget.png","Screenshot displaying ui-template widget with code for building table for displaying task",[903,8667,8668],{"start":274},[30,8669,8670],{},"Paste the below code into the widget, If you're new to Vue.js, rest assured I've included helpful comments for clarity.",[981,8672,8674],{"className":983,"code":8673,"language":985,"meta":265,"style":265},"` \u003Ctemplate>\n \u003C!-- Input field for searching tasks -->\n \u003Cv-text-field v-model=\"search\" label=\"Search\" prepend-inner-icon=\"mdi-magnify\" single-line variant=\"outlined\"\n  hide-details>\u003C\u002Fv-text-field>\n \n \u003C!-- Data table to display tasks -->\n \u003Cv-data-table :search=\"search\" :items=\"msg?.payload\">\n  \u003C!-- Custom header for the \"current\" column -->\n  \u003Ctemplate v-slot:header.current>\n   \u003Cdiv class=\"text-center\">Center-Aligned\u003C\u002Fdiv>\n  \u003C\u002Ftemplate>\n\n  \u003C!-- Template for the \"priority\" column -->\n  \u003Ctemplate v-slot:item.priority=\"{ item }\">\n   \u003C!-- Display priority icon if it exists -->\n   \u003Cv-icon v-if=\"item.priority\" icon=\"mdi-alert\" color=\"red\">\u003C\u002Fv-icon>\n  \u003C\u002Ftemplate>\n\n  \u003C!-- Template for the \"user\" column -->\n  \u003Ctemplate v-slot:item.user=\"{ item }\">\n   \u003C!-- Display user avatar and username -->\n   \u003Cdiv class=\"user\">\n    \u003C!-- User avatar -->\n    \u003Cimg :src=\"item.user.image\" width=\"24\" \u002F>\n    \u003C!-- Username -->\n    {% raw %}\u003Cspan>{{ item.user.username }}\u003C\u002Fspan>{% endraw %}\n   \u003C\u002Fdiv>\n  \u003C\u002Ftemplate>\n\n  \u003C!-- Template for the \"due\" column -->\n  \u003Ctemplate v-slot:item.due=\"{ item }\">\n   \u003C!-- Calculate and display the number of days between due date and current date -->\n   {% raw %}{{ daysBetween(item.due, new Date()) }} Days{% endraw %}\n  \u003C\u002Ftemplate>\n \u003C\u002Fv-data-table>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n export default {\n  data() {\n   return {\n    \u002F\u002F Search input field model\n    search: '',\n   }\n  },\n  methods: {\n   \u002F\u002F Method to calculate the number of days between two dates\n   daysBetween(date1, date2) {\n    \u002F\u002F Calculate the difference in days\n    const oneDay = 24 * 60 * 60 * 1000; \u002F\u002F hours*minutes*seconds*milliseconds\n    const firstDate = new Date(date1);\n    const secondDate = new Date(date2);\n    const diffDays = Math.round(Math.abs((firstDate - secondDate) \u002F oneDay));\n    return diffDays;\n   }\n  }\n }\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n \u002F* Styling for user avatar and username *\u002F\n .user {\n  display: flex;\n  gap: 5px; \u002F* Gap between avatar and username *\u002F\n }\n\n \u002F* Styling for user avatar *\u002F\n .user img {\n  width: 24px; \u002F* Set width of user avatar *\u002F\n }\n\u003C\u002Fstyle>\n\n",[442,8675,8676,8687,8692,8741,8752,8757,8762,8791,8796,8808,8837,8846,8850,8855,8874,8879,8926,8934,8938,8943,8962,8967,8985,8990,9022,9027,9050,9059,9067,9071,9076,9095,9100,9105,9113,9122,9130,9134,9142,9151,9160,9167,9172,9183,9189,9195,9205,9211,9231,9237,9271,9295,9318,9369,9379,9384,9389,9395,9404,9409,9420,9426,9436,9448,9464,9469,9474,9480,9491,9506,9511],{"__ignoreMap":265},[989,8677,8678,8681,8683,8685],{"class":991,"line":992},[989,8679,8680],{"class":1060},"` ",[989,8682,996],{"class":995},[989,8684,1000],{"class":999},[989,8686,1003],{"class":995},[989,8688,8689],{"class":991,"line":269},[989,8690,8691],{"class":1008}," \u003C!-- Input field for searching tasks -->\n",[989,8693,8694,8697,8699,8701,8703,8705,8707,8709,8711,8713,8715,8717,8719,8721,8723,8725,8727,8729,8731,8733,8735,8737,8739],{"class":991,"line":274},[989,8695,8696],{"class":995}," \u003C",[989,8698,7469],{"class":999},[989,8700,6724],{"class":1020},[989,8702,1024],{"class":995},[989,8704,1027],{"class":995},[989,8706,7478],{"class":1030},[989,8708,1027],{"class":995},[989,8710,7483],{"class":1020},[989,8712,1024],{"class":995},[989,8714,1027],{"class":995},[989,8716,7490],{"class":1030},[989,8718,1027],{"class":995},[989,8720,7495],{"class":1020},[989,8722,1024],{"class":995},[989,8724,1027],{"class":995},[989,8726,7502],{"class":1030},[989,8728,1027],{"class":995},[989,8730,7507],{"class":1020},[989,8732,7510],{"class":1020},[989,8734,1024],{"class":995},[989,8736,1027],{"class":995},[989,8738,7517],{"class":1030},[989,8740,7038],{"class":995},[989,8742,8743,8746,8748,8750],{"class":991,"line":266},[989,8744,8745],{"class":1020},"  hide-details",[989,8747,1340],{"class":995},[989,8749,7469],{"class":999},[989,8751,1003],{"class":995},[989,8753,8754],{"class":991,"line":1071},[989,8755,8756],{"class":1060}," \n",[989,8758,8759],{"class":991,"line":1089},[989,8760,8761],{"class":1008}," \u003C!-- Data table to display tasks -->\n",[989,8763,8764,8766,8768,8771,8773,8775,8777,8779,8781,8783,8785,8787,8789],{"class":991,"line":1107},[989,8765,8696],{"class":995},[989,8767,7428],{"class":999},[989,8769,8770],{"class":1020}," :search",[989,8772,1024],{"class":995},[989,8774,1027],{"class":995},[989,8776,7478],{"class":1030},[989,8778,1027],{"class":995},[989,8780,7550],{"class":1020},[989,8782,1024],{"class":995},[989,8784,1027],{"class":995},[989,8786,7557],{"class":1030},[989,8788,1027],{"class":995},[989,8790,1003],{"class":995},[989,8792,8793],{"class":991,"line":1117},[989,8794,8795],{"class":1008},"  \u003C!-- Custom header for the \"current\" column -->\n",[989,8797,8798,8801,8803,8806],{"class":991,"line":1126},[989,8799,8800],{"class":995},"  \u003C",[989,8802,1000],{"class":999},[989,8804,8805],{"class":1020}," v-slot:header.current",[989,8807,1003],{"class":995},[989,8809,8810,8813,8815,8817,8819,8821,8824,8826,8828,8831,8833,8835],{"class":991,"line":1132},[989,8811,8812],{"class":995},"   \u003C",[989,8814,228],{"class":999},[989,8816,1490],{"class":1020},[989,8818,1024],{"class":995},[989,8820,1027],{"class":995},[989,8822,8823],{"class":1030},"text-center",[989,8825,1027],{"class":995},[989,8827,1057],{"class":995},[989,8829,8830],{"class":1060},"Center-Aligned",[989,8832,1064],{"class":995},[989,8834,228],{"class":999},[989,8836,1003],{"class":995},[989,8838,8839,8842,8844],{"class":991,"line":1142},[989,8840,8841],{"class":995},"  \u003C\u002F",[989,8843,1000],{"class":999},[989,8845,1003],{"class":995},[989,8847,8848],{"class":991,"line":1155},[989,8849,1129],{"emptyLinePlaceholder":295},[989,8851,8852],{"class":991,"line":1166},[989,8853,8854],{"class":1008},"  \u003C!-- Template for the \"priority\" column -->\n",[989,8856,8857,8859,8861,8864,8866,8868,8870,8872],{"class":991,"line":1174},[989,8858,8800],{"class":995},[989,8860,1000],{"class":999},[989,8862,8863],{"class":1020}," v-slot:item.priority",[989,8865,1024],{"class":995},[989,8867,1027],{"class":995},[989,8869,7589],{"class":1030},[989,8871,1027],{"class":995},[989,8873,1003],{"class":995},[989,8875,8876],{"class":991,"line":1187},[989,8877,8878],{"class":1008},"   \u003C!-- Display priority icon if it exists -->\n",[989,8880,8881,8883,8886,8888,8890,8892,8895,8897,8900,8902,8904,8907,8909,8912,8914,8916,8918,8920,8922,8924],{"class":991,"line":1193},[989,8882,8812],{"class":995},[989,8884,8885],{"class":999},"v-icon",[989,8887,1021],{"class":1020},[989,8889,1024],{"class":995},[989,8891,1027],{"class":995},[989,8893,8894],{"class":1030},"item.priority",[989,8896,1027],{"class":995},[989,8898,8899],{"class":1020}," icon",[989,8901,1024],{"class":995},[989,8903,1027],{"class":995},[989,8905,8906],{"class":1030},"mdi-alert",[989,8908,1027],{"class":995},[989,8910,8911],{"class":1020}," color",[989,8913,1024],{"class":995},[989,8915,1027],{"class":995},[989,8917,5749],{"class":1030},[989,8919,1027],{"class":995},[989,8921,1340],{"class":995},[989,8923,8885],{"class":999},[989,8925,1003],{"class":995},[989,8927,8928,8930,8932],{"class":991,"line":1199},[989,8929,8841],{"class":995},[989,8931,1000],{"class":999},[989,8933,1003],{"class":995},[989,8935,8936],{"class":991,"line":1209},[989,8937,1129],{"emptyLinePlaceholder":295},[989,8939,8940],{"class":991,"line":1215},[989,8941,8942],{"class":1008},"  \u003C!-- Template for the \"user\" column -->\n",[989,8944,8945,8947,8949,8952,8954,8956,8958,8960],{"class":991,"line":1229},[989,8946,8800],{"class":995},[989,8948,1000],{"class":999},[989,8950,8951],{"class":1020}," v-slot:item.user",[989,8953,1024],{"class":995},[989,8955,1027],{"class":995},[989,8957,7589],{"class":1030},[989,8959,1027],{"class":995},[989,8961,1003],{"class":995},[989,8963,8964],{"class":991,"line":1235},[989,8965,8966],{"class":1008},"   \u003C!-- Display user avatar and username -->\n",[989,8968,8969,8971,8973,8975,8977,8979,8981,8983],{"class":991,"line":1241},[989,8970,8812],{"class":995},[989,8972,228],{"class":999},[989,8974,1490],{"class":1020},[989,8976,1024],{"class":995},[989,8978,1027],{"class":995},[989,8980,3877],{"class":1030},[989,8982,1027],{"class":995},[989,8984,1003],{"class":995},[989,8986,8987],{"class":991,"line":1653},[989,8988,8989],{"class":1008},"    \u003C!-- User avatar -->\n",[989,8991,8992,8995,8997,8999,9001,9003,9006,9008,9011,9013,9015,9018,9020],{"class":991,"line":1659},[989,8993,8994],{"class":995},"    \u003C",[989,8996,239],{"class":999},[989,8998,1516],{"class":1020},[989,9000,1024],{"class":995},[989,9002,1027],{"class":995},[989,9004,9005],{"class":1030},"item.user.image",[989,9007,1027],{"class":995},[989,9009,9010],{"class":1020}," width",[989,9012,1024],{"class":995},[989,9014,1027],{"class":995},[989,9016,9017],{"class":1030},"24",[989,9019,1027],{"class":995},[989,9021,1528],{"class":995},[989,9023,9024],{"class":991,"line":1665},[989,9025,9026],{"class":1008},"    \u003C!-- Username -->\n",[989,9028,9029,9032,9034,9036,9038,9041,9043,9045,9047],{"class":991,"line":1671},[989,9030,9031],{"class":1060},"    {% raw %}",[989,9033,996],{"class":995},[989,9035,989],{"class":999},[989,9037,1057],{"class":995},[989,9039,9040],{"class":1060},"{{ item.user.username }}",[989,9042,1064],{"class":995},[989,9044,989],{"class":999},[989,9046,1057],{"class":995},[989,9048,9049],{"class":1060},"{% endraw %}\n",[989,9051,9052,9055,9057],{"class":991,"line":1690},[989,9053,9054],{"class":995},"   \u003C\u002F",[989,9056,228],{"class":999},[989,9058,1003],{"class":995},[989,9060,9061,9063,9065],{"class":991,"line":1695},[989,9062,8841],{"class":995},[989,9064,1000],{"class":999},[989,9066,1003],{"class":995},[989,9068,9069],{"class":991,"line":1701},[989,9070,1129],{"emptyLinePlaceholder":295},[989,9072,9073],{"class":991,"line":1710},[989,9074,9075],{"class":1008},"  \u003C!-- Template for the \"due\" column -->\n",[989,9077,9078,9080,9082,9085,9087,9089,9091,9093],{"class":991,"line":1715},[989,9079,8800],{"class":995},[989,9081,1000],{"class":999},[989,9083,9084],{"class":1020}," v-slot:item.due",[989,9086,1024],{"class":995},[989,9088,1027],{"class":995},[989,9090,7589],{"class":1030},[989,9092,1027],{"class":995},[989,9094,1003],{"class":995},[989,9096,9097],{"class":991,"line":1725},[989,9098,9099],{"class":1008},"   \u003C!-- Calculate and display the number of days between due date and current date -->\n",[989,9101,9102],{"class":991,"line":1731},[989,9103,9104],{"class":1060},"   {% raw %}{{ daysBetween(item.due, new Date()) }} Days{% endraw %}\n",[989,9106,9107,9109,9111],{"class":991,"line":1741},[989,9108,8841],{"class":995},[989,9110,1000],{"class":999},[989,9112,1003],{"class":995},[989,9114,9115,9118,9120],{"class":991,"line":1756},[989,9116,9117],{"class":995}," \u003C\u002F",[989,9119,7428],{"class":999},[989,9121,1003],{"class":995},[989,9123,9124,9126,9128],{"class":991,"line":1769},[989,9125,1064],{"class":995},[989,9127,1000],{"class":999},[989,9129,1003],{"class":995},[989,9131,9132],{"class":991,"line":1783},[989,9133,1129],{"emptyLinePlaceholder":295},[989,9135,9136,9138,9140],{"class":991,"line":1788},[989,9137,996],{"class":995},[989,9139,1137],{"class":999},[989,9141,1003],{"class":995},[989,9143,9144,9147,9149],{"class":991,"line":1794},[989,9145,9146],{"class":1145}," export",[989,9148,1149],{"class":1145},[989,9150,1152],{"class":995},[989,9152,9153,9156,9158],{"class":991,"line":1806},[989,9154,9155],{"class":999},"  data",[989,9157,1161],{"class":995},[989,9159,1152],{"class":995},[989,9161,9162,9165],{"class":991,"line":1819},[989,9163,9164],{"class":1145},"   return",[989,9166,1152],{"class":995},[989,9168,9169],{"class":991,"line":1831},[989,9170,9171],{"class":1008},"    \u002F\u002F Search input field model\n",[989,9173,9174,9177,9179,9181],{"class":991,"line":1836},[989,9175,9176],{"class":999},"    search",[989,9178,1180],{"class":995},[989,9180,7808],{"class":995},[989,9182,3187],{"class":995},[989,9184,9186],{"class":991,"line":9185},44,[989,9187,9188],{"class":995},"   }\n",[989,9190,9192],{"class":991,"line":9191},45,[989,9193,9194],{"class":995},"  },\n",[989,9196,9198,9201,9203],{"class":991,"line":9197},46,[989,9199,9200],{"class":999},"  methods",[989,9202,1180],{"class":995},[989,9204,1152],{"class":995},[989,9206,9208],{"class":991,"line":9207},47,[989,9209,9210],{"class":1008},"   \u002F\u002F Method to calculate the number of days between two dates\n",[989,9212,9214,9217,9219,9222,9224,9227,9229],{"class":991,"line":9213},48,[989,9215,9216],{"class":999},"   daysBetween",[989,9218,4349],{"class":995},[989,9220,9221],{"class":8514},"date1",[989,9223,4459],{"class":995},[989,9225,9226],{"class":8514}," date2",[989,9228,3883],{"class":995},[989,9230,1152],{"class":995},[989,9232,9234],{"class":991,"line":9233},49,[989,9235,9236],{"class":1008},"    \u002F\u002F Calculate the difference in days\n",[989,9238,9240,9243,9246,9248,9251,9254,9257,9259,9261,9263,9266,9268],{"class":991,"line":9239},50,[989,9241,9242],{"class":1020},"    const",[989,9244,9245],{"class":1060}," oneDay",[989,9247,1223],{"class":995},[989,9249,9250],{"class":1777}," 24",[989,9252,9253],{"class":995}," *",[989,9255,9256],{"class":1777}," 60",[989,9258,9253],{"class":995},[989,9260,9256],{"class":1777},[989,9262,9253],{"class":995},[989,9264,9265],{"class":1777}," 1000",[989,9267,1684],{"class":995},[989,9269,9270],{"class":1008}," \u002F\u002F hours*minutes*seconds*milliseconds\n",[989,9272,9274,9276,9279,9281,9284,9287,9289,9291,9293],{"class":991,"line":9273},51,[989,9275,9242],{"class":1020},[989,9277,9278],{"class":1060}," firstDate",[989,9280,1223],{"class":995},[989,9282,9283],{"class":995}," new",[989,9285,9286],{"class":4345}," Date",[989,9288,4349],{"class":999},[989,9290,9221],{"class":1060},[989,9292,3883],{"class":999},[989,9294,1753],{"class":995},[989,9296,9298,9300,9303,9305,9307,9309,9311,9314,9316],{"class":991,"line":9297},52,[989,9299,9242],{"class":1020},[989,9301,9302],{"class":1060}," secondDate",[989,9304,1223],{"class":995},[989,9306,9283],{"class":995},[989,9308,9286],{"class":4345},[989,9310,4349],{"class":999},[989,9312,9313],{"class":1060},"date2",[989,9315,3883],{"class":999},[989,9317,1753],{"class":995},[989,9319,9321,9323,9326,9328,9331,9333,9336,9338,9341,9343,9346,9349,9352,9355,9357,9359,9362,9364,9367],{"class":991,"line":9320},53,[989,9322,9242],{"class":1020},[989,9324,9325],{"class":1060}," diffDays",[989,9327,1223],{"class":995},[989,9329,9330],{"class":1060}," Math",[989,9332,437],{"class":995},[989,9334,9335],{"class":4345},"round",[989,9337,4349],{"class":999},[989,9339,9340],{"class":1060},"Math",[989,9342,437],{"class":995},[989,9344,9345],{"class":4345},"abs",[989,9347,9348],{"class":999},"((",[989,9350,9351],{"class":1060},"firstDate",[989,9353,9354],{"class":995}," -",[989,9356,9302],{"class":1060},[989,9358,4359],{"class":999},[989,9360,9361],{"class":995},"\u002F",[989,9363,9245],{"class":1060},[989,9365,9366],{"class":999},"))",[989,9368,1753],{"class":995},[989,9370,9372,9375,9377],{"class":991,"line":9371},54,[989,9373,9374],{"class":1145},"    return",[989,9376,9325],{"class":1060},[989,9378,1753],{"class":995},[989,9380,9382],{"class":991,"line":9381},55,[989,9383,9188],{"class":995},[989,9385,9387],{"class":991,"line":9386},56,[989,9388,8321],{"class":995},[989,9390,9392],{"class":991,"line":9391},57,[989,9393,9394],{"class":995}," }\n",[989,9396,9398,9400,9402],{"class":991,"line":9397},58,[989,9399,1064],{"class":995},[989,9401,1137],{"class":999},[989,9403,1003],{"class":995},[989,9405,9407],{"class":991,"line":9406},59,[989,9408,1129],{"emptyLinePlaceholder":295},[989,9410,9412,9414,9416,9418],{"class":991,"line":9411},60,[989,9413,996],{"class":995},[989,9415,1720],{"class":999},[989,9417,5160],{"class":1020},[989,9419,1003],{"class":995},[989,9421,9423],{"class":991,"line":9422},61,[989,9424,9425],{"class":1060}," \u002F* Styling for user avatar and username *\u002F\n",[989,9427,9429,9432,9434],{"class":991,"line":9428},62,[989,9430,9431],{"class":995}," .",[989,9433,3877],{"class":1736},[989,9435,1152],{"class":995},[989,9437,9439,9442,9444,9446],{"class":991,"line":9438},63,[989,9440,9441],{"class":1744},"  display",[989,9443,1180],{"class":995},[989,9445,1750],{"class":1060},[989,9447,1753],{"class":995},[989,9449,9451,9454,9456,9459,9461],{"class":991,"line":9450},64,[989,9452,9453],{"class":1744},"  gap",[989,9455,1180],{"class":995},[989,9457,9458],{"class":1777}," 5px",[989,9460,1684],{"class":995},[989,9462,9463],{"class":1008}," \u002F* Gap between avatar and username *\u002F\n",[989,9465,9467],{"class":991,"line":9466},65,[989,9468,9394],{"class":995},[989,9470,9472],{"class":991,"line":9471},66,[989,9473,1129],{"emptyLinePlaceholder":295},[989,9475,9477],{"class":991,"line":9476},67,[989,9478,9479],{"class":1060}," \u002F* Styling for user avatar *\u002F\n",[989,9481,9483,9485,9487,9489],{"class":991,"line":9482},68,[989,9484,9431],{"class":995},[989,9486,3877],{"class":1736},[989,9488,1801],{"class":1736},[989,9490,1152],{"class":995},[989,9492,9494,9497,9499,9501,9503],{"class":991,"line":9493},69,[989,9495,9496],{"class":1744},"  width",[989,9498,1180],{"class":995},[989,9500,1814],{"class":1777},[989,9502,1684],{"class":995},[989,9504,9505],{"class":1008}," \u002F* Set width of user avatar *\u002F\n",[989,9507,9509],{"class":991,"line":9508},70,[989,9510,9394],{"class":995},[989,9512,9514,9516,9518],{"class":991,"line":9513},71,[989,9515,1064],{"class":995},[989,9517,1720],{"class":999},[989,9519,1003],{"class":995},[903,9521,9522],{"start":274},[30,9523,5617,9524,9526,9527,9529],{},[33,9525,869],{}," widget's input to the ",[33,9528,4307],{}," node's output ( function node which we have added to filter tasks based on user ).",[19,9531,5918],{"id":5917},[15,9533,9534],{},[239,9535],{"alt":9536,"dataZoomable":265,"src":9537,"title":9538},"\"Screenshot displaying Node-RED flow of Task management system\"","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuilding-an-application-with-dashboard-task-management-application-flow.png","Screenshot displaying Node-RED flow of Task management system",[903,9540,9541,9544,9547],{},[30,9542,9543],{},"Deploy the flow by clicking the top right Deploy button.",[30,9545,9546],{},"Locate the 'Open Dashboard' button at the top-right corner of the Dashboard 2.0 sidebar and click on it to navigate to the dashboard.",[30,9548,9549],{},"Login with the registered FlowFuse account username and password.",[15,9551,9552],{},"Now, we're all set to add tasks. Navigate to the \"New Task\" page to add tasks. To view tasks, navigate to the \"your Task\" page.",[19,9554,9556],{"id":9555},"next-step","Next step",[15,9558,9559],{},"If you want to enhance this simple application by adding more features, consider the following resources:",[27,9561,9562,9566,9570,9574],{},[30,9563,9564,5444],{},[256,9565,5443],{"href":5442},[30,9567,9568,5458],{},[256,9569,5457],{"href":1848},[30,9571,9572,5465],{},[256,9573,5464],{"href":5463},[30,9575,9576,9579],{},[256,9577,9578],{"href":5477},"Multi-User Dashboard for Ticket\u002FTask Management"," blueprint, which allows you to utilize templates to develop a personalized multi-user dashboard quickly. This Task management blueprint has all features such as adding, updating, and deleting tasks, user profiles, and admin dashboard.",[1720,9581,9582],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}",{"title":265,"searchDepth":266,"depth":266,"links":9584},[9585,9586,9594,9595],{"id":8123,"depth":269,"text":8124},{"id":8141,"depth":269,"text":8142,"children":9587},[9588,9589,9590,9591,9592,9593],{"id":8155,"depth":274,"text":8156},{"id":8190,"depth":274,"text":8191},{"id":8390,"depth":274,"text":8391},{"id":8432,"depth":274,"text":8433},{"id":8589,"depth":274,"text":8590},{"id":8630,"depth":274,"text":8631},{"id":5917,"depth":269,"text":5918},{"id":9555,"depth":269,"text":9556},{"type":653,"title":9597,"description":9598},"Build and Deploy Node-RED Applications Faster","FlowFuse gives you everything you need to build, secure, and scale Node-RED applications, multi-user support, authentication, and production-ready deployment included. Start your free trial today.","2024-04-25","Learn to build custom applications effortlessly with Node-RED Dashboard 2.0. This step-by-step guide walks you through building a personalized, secure, and fully functional application.","\u002Fblog\u002F2024\u002F04\u002Fimages\u002Fbuild-application-dashboard-2.png",{"keywords":9603,"excerpt":9604},"node-red dashboard 2.0 application, build application node-red dashboard, node-red dashboard 2 tutorial, flowfuse dashboard app, node-red task management dashboard",{"type":12,"value":9605},[9606],[15,9607,8114],{},"\u002Fblog\u002F2024\u002F04\u002Fhow-to-build-an-application-with-node-red-dashboard-2",{"title":8108,"description":9600},{"loc":9608},"blog\u002F2024\u002F04\u002Fhow-to-build-an-application-with-node-red-dashboard-2","A step-by-step guide to building a personalized, secure, and fully functional application with Dashboard 2.0.",[487,3010,303,2164],"This guide walks through building a personalised, multi-user task management application with Node-RED Dashboard 2.0 and FlowFuse. It covers enabling user authentication, using the FlowFuse User Addon to access logged-in user data, storing and filtering tasks in global context per user, and rendering them in a Vuetify data table inside a ui-template widget with client constraints enabled.","uCiuBK4FAHIj8MDYEGdWktzIiWOu6ccwWYe3metOsjg",{"id":9617,"title":9618,"authors":9619,"body":9620,"cta":3,"date":10110,"description":10111,"extension":287,"image":10112,"lastUpdated":2996,"meta":10113,"navigation":295,"path":10122,"seo":10123,"sitemap":10124,"stem":10125,"subtitle":10111,"tags":10126,"tldr":10129,"video":3,"__hash__":10130},"blog\u002Fblog\u002F2024\u002F03\u002Fdashboard-getting-started.md","Getting Started with Node-RED Dashboard 2.0",[309],{"type":12,"value":9621,"toc":10092},[9622,9625,9628,9631,9635,9639,9645,9648,9655,9659,9665,9667,9680,9684,9687,9693,9695,9702,9705,9739,9743,9746,9752,9754,9757,9778,9784,9787,9791,9794,9833,9837,9840,9877,9881,9884,9890,9893,9897,9906,9910,9913,9921,9927,9933,9935,9939,9942,9950,9953,9962,9972,9978,9980,9988,9994,9996,10009,10015,10017,10020,10026,10029,10033,10036,10066,10068,10070,10087],[15,9623,9624],{},"With our latest release of Node-RED Dashboard 2.0, we've made some big improvements to the onboarding experience.",[15,9626,9627],{},"We're seeing over 2,000 people download Dashboard 2.0 per week, and are seeing a great buzz in the community of brand new Node-RED users, experienced Node-RED users that haven't explored a UI solution previously and existing users migrating from Dashboard 1.0.",[15,9629,9630],{},"So, with that in mind, we wanted to offer a new \"Getting Started\" guide that will help you get up and running with building custom user interfaces and data visualizations in Node-RED.",[19,9632,9634],{"id":9633},"how-to-install-node-red-dashboard-20","How to Install Node-RED Dashboard 2.0",[82,9636,9638],{"id":9637},"step-1-manage-palette","Step 1: \"Manage Palette\"",[15,9640,9641],{},[239,9642],{"alt":9643,"dataZoomable":265,"src":9644},"Screenshot to show where to find the \"Manage Palette\" option in Node-RED","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-manage-palette.png",[9646,9647,9643],"figcaption",{},[903,9649,9650,9652],{},[30,9651,5861],{},[30,9653,9654],{},"Click \"Manage Palette\"",[82,9656,9658],{"id":9657},"step-2-search-install","Step 2: Search & \"Install\"",[15,9660,9661],{},[239,9662],{"alt":9663,"dataZoomable":265,"src":9664},"Screenshot to show where to find the \"Install\" tab, and how to find @flowfuse\u002Fnode-red-dashboard","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-search-install.png",[9646,9666,9663],{},[903,9668,9669,9672,9677],{},[30,9670,9671],{},"Switch to the \"Install\" tab",[30,9673,5558,9674],{},[333,9675,9676],{},"\"@flowfuse\u002Fnode-red-dashboard\"",[30,9678,9679],{},"Click \"Install\"",[19,9681,9683],{"id":9682},"adding-your-first-widgets","Adding your first widgets",[15,9685,9686],{},"With the nodes installed, getting started is as easy as choosing a node from the Palette (the left-hand side list of nodes) in Node-RED, and dropping it onto your canvas.",[15,9688,9689],{},[239,9690],{"alt":9691,"dataZoomable":265,"src":9692},"Screen recording to show how easy it is to deploy your first Dashboard 2.0 application.","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-add-widget.gif",[9646,9694,9691],{},[15,9696,9697,9698,9701],{},"In this case, we drop in a ",[442,9699,9700],{},"ui-button",", click \"Deploy\" and then can see the button running live in our user interface.",[15,9703,9704],{},"Notice too that Dashboard will automatically setup some underlying configurations for you (visible in the right-side menu):",[27,9706,9707,9715,9726,9731],{},[30,9708,9709,9711,9712,9714],{},[442,9710,3770],{},": Each instance of Node-RED that uses Dashboard 2.0 must have a single ",[442,9713,3770],{}," element (we're hoping to add support for multiple in the future). This element contains all of the global settings for your Dashboard instance.",[30,9716,9717,9719,9720,9722,9723,9725],{},[442,9718,4267],{},": A single Dashboard (",[442,9721,3770],{},") can consist of multiple pages, and can be navigated to using the left-side sidebar. Each page is then responsible for displaying a collection of ",[442,9724,4244],{}," elements.",[30,9727,9728,9730],{},[442,9729,4244],{},": Each group contains a collection of widgets, and can be used to organize your Dashboard into logical sections.",[30,9732,9733,9735,9736,9738],{},[442,9734,3767],{},": Each ",[442,9737,4267],{}," can be assigned a given theme. Your \"Themes\" provide control over the aesthetic of your Dashboard like color, padding and margins.",[19,9740,9742],{"id":9741},"configuring-your-layout","Configuring your layout",[15,9744,9745],{},"Dashboard 2.0 adds a dedicated sidebar to Node-RED to provide a centralized view of your pages, groups and widgets. From here you can add new pages and groups, modify existing settings, and re-order content to your liking.",[15,9747,9748],{},[239,9749],{"alt":9750,"dataZoomable":265,"src":9751},"Screenshot showing the Dashboard 2.0 sidebar in the Node-RED Editor.","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-sidebar.png",[9646,9753,9750],{},[15,9755,9756],{},"When defining your layout options, we break the choice into two sections:",[27,9758,9759,9769],{},[30,9760,9761,9764,9765,9768],{},[33,9762,9763],{},"Page Layout:"," Controls how the ",[442,9766,9767],{},"ui-groups","'s are presented on a given page in your application.",[30,9770,9771,9774,9775,9777],{},[33,9772,9773],{},"Navigation Sidebar:"," Defines the left-side navigation style, defined at the ",[442,9776,3770],{}," level.",[15,9779,9780],{},[239,9781],{"alt":9782,"dataZoomable":265,"src":9783},"Example of a \"Grid\" page layout, with \"Collapsing\" sidebar navigation.","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-layout.png",[9646,9785,9786],{},"Example of the \"Grid\" page layout, with \"Collapsing\" sidebar navigation.",[82,9788,9790],{"id":9789},"page-layout","Page Layout",[15,9792,9793],{},"Currently, we have three different options for page layout:",[27,9795,9796,9810,9823],{},[30,9797,9798,9801,9802,9806,9807,9809],{},[33,9799,9800],{},"Grid:"," (",[256,9803,6677],{"href":9804,"rel":9805},"https:\u002F\u002Fdashboard.flowfuse.com\u002Flayouts\u002Ftypes\u002Fgrid.html",[402],") This is the default layout for a page, and uses a 12-column grid system to layout your ",[442,9808,9767],{},". Widths of groups and widgets define the number of columns they will render in. So, a \"width\" of 6\" would render to 50% of the screen. Grid layouts are entirely responsive, and will adjust to the size of the screen.",[30,9811,9812,9801,9815,9819,9820,9822],{},[33,9813,9814],{},"Fixed:",[256,9816,6677],{"href":9817,"rel":9818},"https:\u002F\u002Fdashboard.flowfuse.com\u002Flayouts\u002Ftypes\u002Ffixed.html",[402],") Each component will render at a ",[333,9821,2041],{}," width, no matter what the screen size is. The \"width\" property is converted a fixed pixel value (multiples of 48px by default).",[30,9824,9825,9801,9828,9832],{},[33,9826,9827],{},"Notebook:",[256,9829,6677],{"href":9830,"rel":9831},"https:\u002F\u002Fdashboard.flowfuse.com\u002Flayouts\u002Ftypes\u002Fnotebook.html",[402],") This layout will stretch to 100% width, up to a maximum width of 1024px, and will centrally align. It's particularly useful for storytelling (e.g. articles\u002Fblogs) or analysis type user interfaces (e.g. Jupyter Notebooks), where you want the user to digest content in a particular order through scrolling.",[82,9834,9836],{"id":9835},"navigation-sidebar","Navigation Sidebar",[15,9838,9839],{},"Dashboard 2.0 offers various options on the appearance of the navigation sidebar:",[27,9841,9842,9848,9853,9859,9865],{},[30,9843,9844,9847],{},[33,9845,9846],{},"Collapsing:"," When the sidebar is opened the page content will adjust with the width of the sidebar.",[30,9849,9850,9852],{},[33,9851,9814],{}," The full sidebar will always be visible, and the page content will adjust to the width of the sidebar.",[30,9854,9855,9858],{},[33,9856,9857],{},"Collapse to Icons:"," When minimized, users can still navigate between pages by clicking on the icons representing each page in the sidebar.",[30,9860,9861,9864],{},[33,9862,9863],{},"Appear over Content:"," When the sidebar is opened, the page is given an overlay, and the sidebar sits on top.",[30,9866,9867,9870,9871,437],{},[33,9868,9869],{},"Always Hide:"," The sidebar will never show, and navigation between pages can instead be driven by ",[256,9872,9875],{"href":9873,"rel":9874},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-control.html",[402],[442,9876,3921],{},[82,9878,9880],{"id":9879},"define-your-layout","Define Your Layout",[15,9882,9883],{},"In our example, we're going to switch to a \"Notebook\" layout, with a \"Collapse to Icons\" sidebar:",[15,9885,9886],{},[239,9887],{"alt":9888,"dataZoomable":265,"src":9889},"Example of the \"Notebook\" layout and \"Collapse to icons\" sidebar","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-example.png",[9646,9891,9892],{},"Example of the \"Notebook\" layout, with \"Collapse to Icons\" sidebar navigation.",[19,9894,9896],{"id":9895},"adding-more-widgets","Adding More Widgets",[15,9898,9899,9900,9903,9904,437],{},"Now, we're going to build a quick example to demonstrate how we can wire nodes together, and visualize the output from a ",[442,9901,9902],{},"ui-slider"," onto a ",[442,9905,4930],{},[82,9907,9909],{"id":9908},"adding-a-group","Adding a Group",[15,9911,9912],{},"In the Node-RED Editor's Dashboard 2.0 sidebar, we're going to then do the following things:",[903,9914,9915,9918],{},[30,9916,9917],{},"Edit \"My Group\" and rename it to \"Controls\"",[30,9919,9920],{},"Create a new \"Group\" in your existing page called \"Data Visualization\"",[15,9922,9923,9924,9926],{},"You'll now see the two groups listed under \"Page 1\". \"Controls\" with a single ",[442,9925,9700],{}," and \"Data Visualization\" with no widgets.",[15,9928,9929],{},[239,9930],{"alt":9931,"dataZoomable":265,"src":9932},"Screenshot of the modified and newly added groups","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-new-group.png",[9646,9934,9931],{},[82,9936,9938],{"id":9937},"connecting-new-nodes","Connecting New Nodes",[15,9940,9941],{},"Then, we're going to add two new widgets:",[27,9943,9944,9947],{},[30,9945,9946],{},"UI Chart",[30,9948,9949],{},"UI Slider",[15,9951,9952],{},"Which we can do by dropping them from the left-side Palette and onto our canvas.",[15,9954,9955,9956,9958,9959,9961],{},"We'll need to double-click each new node and confirm which \"Group\" we want to add this node to. In this case, we'll add the ",[442,9957,9902],{}," to the \"Controls\" group, and the ",[442,9960,4930],{}," to the \"Data Visualization\" group.",[15,9963,9964,9965,2355,9967,9969,9970,1180],{},"We're also going to connect the output from both the ",[442,9966,9902],{},[442,9968,9700],{}," to the input of the ",[442,9971,4930],{},[15,9973,9974],{},[239,9975],{"alt":9976,"dataZoomable":265,"src":9977},"Screenshot of the Node-RED Editor, showing the ui-slider and ui-button connected to our ui-chart","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-flow.png",[9646,9979,9976],{},[15,9981,9982,9983,9985,9986,1180],{},"Now, when we view our Dashboard, we can see the ",[442,9984,9902],{}," output is def straight into our ",[442,9987,4930],{},[15,9989,9990],{},[239,9991],{"alt":9992,"dataZoomable":265,"src":9993},"Screenshot of the Dashboard with all three widgets rendered","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-final.png",[9646,9995,9992],{},[15,9997,9998,9999,10001,10002,10005,10006,10008],{},"The final step we're going to make is to modify our ",[442,10000,9700],{},". We're going to rename it to \"Clear\", and configure it's \"Payload\" option to send a JSON payload of ",[442,10003,10004],{},"[]",", which, when sent to the ",[442,10007,4930],{}," will clear the chart of all data.",[15,10010,10011],{},[239,10012],{"alt":10013,"dataZoomable":265,"src":10014},"The ui-button configuration after setting it's payload and label","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-btn-config.png",[9646,10016,10013],{},[15,10018,10019],{},"With all of this together, we have the following functional Dashboard:",[15,10021,10022],{},[239,10023],{"alt":10024,"dataZoomable":265,"src":10025},"Short animation showing the final functional dashboard","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fdashboard-getting-started-final.gif",[9646,10027,10028],{},"Short animation showing the final functional dashboard.",[19,10030,10032],{"id":10031},"next-steps","Next Steps",[15,10034,10035],{},"Whilst this is just a simple introduction of Node-RED Dashboard 2.0, we do have many other articles and documentation that can help you get started with more advanced features.",[27,10037,10038,10042,10048,10054,10059],{},[30,10039,10040,6493],{},[256,10041,6492],{"href":6491},[30,10043,10044,6500],{},[256,10045,6499],{"href":10046,"rel":10047},"https:\u002F\u002Fdashboard.flowfuse.com",[402],[30,10049,10050,10053],{},[256,10051,6506],{"href":3781,"rel":10052},[402]," -  The Node-RED forums is a great place to ask questions, share your projects and get help from the community.",[30,10055,10056,10058],{},[256,10057,6513],{"href":6512}," - A free guide to an enterprise-ready Node-RED. Learn all about Node-RED history, securing your flows and dashboard data visualization.",[30,10060,10061,10065],{},[256,10062,10064],{"href":10063},"\u002Fcontact-us","FlowFuse - Book a Demo"," - FlowFuse provides a complete platform to scale your production Node-RED applications, increase developer velocity, and enhance security in order to accelerate innovation.",[19,10067,8036],{"id":8035},[15,10069,8039],{},[27,10071,10072,10077,10082],{},[30,10073,10074],{},[256,10075,8047],{"href":448,"rel":10076},[402],[30,10078,10079],{},[256,10080,8053],{"href":2553,"rel":10081},[402],[30,10083,10084],{},[256,10085,8060],{"href":8058,"rel":10086},[402],[15,10088,8063,10089,437],{},[256,10090,8068],{"href":8066,"rel":10091},[402],{"title":265,"searchDepth":266,"depth":266,"links":10093},[10094,10098,10099,10104,10108,10109],{"id":9633,"depth":269,"text":9634,"children":10095},[10096,10097],{"id":9637,"depth":274,"text":9638},{"id":9657,"depth":274,"text":9658},{"id":9682,"depth":269,"text":9683},{"id":9741,"depth":269,"text":9742,"children":10100},[10101,10102,10103],{"id":9789,"depth":274,"text":9790},{"id":9835,"depth":274,"text":9836},{"id":9879,"depth":274,"text":9880},{"id":9895,"depth":269,"text":9896,"children":10105},[10106,10107],{"id":9908,"depth":274,"text":9909},{"id":9937,"depth":274,"text":9938},{"id":10031,"depth":269,"text":10032},{"id":8035,"depth":269,"text":8036},"2024-03-27","New to Node-RED? New to Dashboard 2.0? This guide will help you get started.","\u002Fblog\u002F2024\u002F03\u002Fimages\u002Fgetting-started-with-dashboard-2.png",{"excerpt":10114},{"type":12,"value":10115},[10116,10118,10120],[15,10117,9624],{},[15,10119,9627],{},[15,10121,9630],{},"\u002Fblog\u002F2024\u002F03\u002Fdashboard-getting-started",{"title":9618,"description":10111},{"loc":10122},"blog\u002F2024\u002F03\u002Fdashboard-getting-started",[487,8099,8100,8101,303,10127,10128],"nodered dashboard beginners guide","nodered dashboard basics","This getting-started guide walks new and experienced Node-RED users through installing FlowFuse Dashboard 2.0 and building their first dashboard. It covers installing the package via the Palette Manager, adding widgets to a canvas, and understanding the core building blocks ui-base, ui-page, ui-group, and ui-theme.","IdCxt0H-_KO3fXqHk7ysa3d9P6ThiYKYN14CU5FcDzo",{"id":10132,"title":10133,"authors":10134,"body":10135,"cta":3,"date":11670,"description":11671,"extension":287,"image":11649,"lastUpdated":3,"meta":11672,"navigation":295,"path":11679,"seo":11680,"sitemap":11681,"stem":11682,"subtitle":11683,"tags":11684,"tldr":3,"video":3,"__hash__":11687},"blog\u002Fblog\u002F2024\u002F01\u002Fspeech-driven-chatbot-with-node-red.md","Speech-Driven Chatbot System with Node-RED",[10],{"type":12,"value":10136,"toc":11659},[10137,10140,10143,10147,10150,10170,10174,10181,10185,10194,10202,10205,10208,10211,10380,10383,10386,11072,11076,11083,11094,11101,11105,11108,11119,11126,11130,11133,11148,11152,11155,11166,11169,11171,11228,11230,11233,11618,11621,11628,11631,11638,11644,11651,11653,11656],[15,10138,10139],{},"Have you ever wanted to integrate speech recognition and synthesis into your Node-RED project and thought it was too complex? Often it has required external services or APIs. However, in this guide, we show you how you can use speech recognition and synthesis in your Node-RED projects without needing an external service or API.",[15,10141,10142],{},"In addition, we make things more interesting by building a system that can listen to us and respond like humans using the Chat-GPT API.\nLet's get started!",[19,10144,10146],{"id":10145},"what-exactly-is-speech-recognition-and-synthesis","What exactly is speech recognition and synthesis?",[15,10148,10149],{},"Speech recognition is a technology where a device captures spoken words through a microphone, checks against grammar rules and vocabulary, and returns recognized words as text. On the other hand, speech synthesis converts app text into speech and plays it through a device's speaker or audio output. There are many benefits and real-world applications of this technology.",[27,10151,10152,10158,10164],{},[30,10153,10154,10157],{},[33,10155,10156],{},"Hands-Free Operation:"," Using speech recognition technology is often used today to perform tasks such as making calls, sending messages, or controlling smart home devices without the need for physical interaction.",[30,10159,10160,10163],{},[33,10161,10162],{},"Accessibility:"," It allows individuals with visual impairments to access digital content through spoken words and as discussed above, to control devices without physical interaction.",[30,10165,10166,10169],{},[33,10167,10168],{},"Efficient Content Consumption:"," It allows us to listen to information instead of reading. For example, in the audiobook industry by using speech synthesis technology they create audio versions of books which helps users to be more productive.",[19,10171,10173],{"id":10172},"installing-dashboard-20","Installing Dashboard 2.0",[15,10175,10176,10177,10180],{},"Install Dashboard 2.0. Follow these ",[256,10178,10179],{"href":4196},"instructions"," to get up and running.",[19,10182,10184],{"id":10183},"building-speech-to-text-vue-component","Building Speech-to-Text Vue component",[15,10186,10187,10188,10193],{},"In this section, we will build a Vue component that will perform a speech-to-text conversion operation using Web speech API, and display results on the dashboard.  While we did say previously that we won't need any external API for speech recognition, this ",[256,10189,10192],{"href":10190,"rel":10191},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWeb_Speech_API",[402],"Web Speech API"," is not an external API.\nThis will process your speech locally as it is a JavaScript API that allows us to use speech-related functionalities, such as speech recognition and synthesis, in a web browser directly. It is widely present in modern browsers (except Firefox) which eliminates the need for external APIs to implement these features. Let's now start to build that component.",[903,10195,10196,10199],{},[30,10197,10198],{},"Drag a ui template widget to canvas and select the created group.",[30,10200,10201],{},"Paste the below Vue snippets into the template widget step by step.",[15,10203,10204],{},"If you are unfamiliar with Vue, we have added comments that will help you to understand the code better.",[15,10206,10207],{},"We are going to start by pasting a user interface’s snippet which will allow us to interact with our system. This snippet adds a button that triggers our system to listen, an Icon, and a paragraph to display speech recognition results on the dashboard.",[15,10209,10210],{},"{% raw %}",[981,10212,10214],{"className":983,"code":10213,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n  \u003Cdiv style=\"display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n    \u003C!-- Button triggers recording when clicked -->\n    \u003Cbutton @click=\"startRecording\">\n      \u003C!-- Microphone icon inside the button -->\n      \u003Cimg alt=\"Microphone\" style=\"height: 62px; width: 62px\" :src=\"microphoneIcon\">\n    \u003C\u002Fbutton>\n    \u003C!-- Displaying speech recognition results -->\n    \u003Cp> \u003Cstrong>You:\u003C\u002Fstrong> {{ results }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[442,10215,10216,10224,10244,10249,10270,10275,10318,10326,10331,10364,10372],{"__ignoreMap":265},[989,10217,10218,10220,10222],{"class":991,"line":992},[989,10219,996],{"class":995},[989,10221,1000],{"class":999},[989,10223,1003],{"class":995},[989,10225,10226,10228,10230,10233,10235,10237,10240,10242],{"class":991,"line":269},[989,10227,5022],{"class":995},[989,10229,228],{"class":999},[989,10231,10232],{"class":1020}," style",[989,10234,1024],{"class":995},[989,10236,1027],{"class":995},[989,10238,10239],{"class":1030},"display: flex; flex-direction: column; justify-content: center; align-items: center;",[989,10241,1027],{"class":995},[989,10243,1003],{"class":995},[989,10245,10246],{"class":991,"line":274},[989,10247,10248],{"class":1008},"    \u003C!-- Button triggers recording when clicked -->\n",[989,10250,10251,10253,10256,10259,10261,10263,10266,10268],{"class":991,"line":266},[989,10252,1014],{"class":995},[989,10254,10255],{"class":999},"button",[989,10257,10258],{"class":1020}," @click",[989,10260,1024],{"class":995},[989,10262,1027],{"class":995},[989,10264,10265],{"class":1030},"startRecording",[989,10267,1027],{"class":995},[989,10269,1003],{"class":995},[989,10271,10272],{"class":991,"line":1071},[989,10273,10274],{"class":1008},"      \u003C!-- Microphone icon inside the button -->\n",[989,10276,10277,10280,10282,10285,10287,10289,10292,10294,10296,10298,10300,10303,10305,10307,10309,10311,10314,10316],{"class":991,"line":1089},[989,10278,10279],{"class":995},"      \u003C",[989,10281,239],{"class":999},[989,10283,10284],{"class":1020}," alt",[989,10286,1024],{"class":995},[989,10288,1027],{"class":995},[989,10290,10291],{"class":1030},"Microphone",[989,10293,1027],{"class":995},[989,10295,10232],{"class":1020},[989,10297,1024],{"class":995},[989,10299,1027],{"class":995},[989,10301,10302],{"class":1030},"height: 62px; width: 62px",[989,10304,1027],{"class":995},[989,10306,1516],{"class":1020},[989,10308,1024],{"class":995},[989,10310,1027],{"class":995},[989,10312,10313],{"class":1030},"microphoneIcon",[989,10315,1027],{"class":995},[989,10317,1003],{"class":995},[989,10319,10320,10322,10324],{"class":991,"line":1107},[989,10321,1110],{"class":995},[989,10323,10255],{"class":999},[989,10325,1003],{"class":995},[989,10327,10328],{"class":991,"line":1117},[989,10329,10330],{"class":1008},"    \u003C!-- Displaying speech recognition results -->\n",[989,10332,10333,10335,10337,10339,10342,10344,10346,10349,10351,10353,10355,10358,10360,10362],{"class":991,"line":1126},[989,10334,1014],{"class":995},[989,10336,15],{"class":999},[989,10338,1057],{"class":995},[989,10340,10341],{"class":995}," \u003C",[989,10343,33],{"class":999},[989,10345,1057],{"class":995},[989,10347,10348],{"class":1060},"You:",[989,10350,1064],{"class":995},[989,10352,33],{"class":999},[989,10354,1057],{"class":995},[989,10356,10357],{"class":1060}," {{ results }}",[989,10359,1064],{"class":995},[989,10361,15],{"class":999},[989,10363,1003],{"class":995},[989,10365,10366,10368,10370],{"class":991,"line":1132},[989,10367,5139],{"class":995},[989,10369,228],{"class":999},[989,10371,1003],{"class":995},[989,10373,10374,10376,10378],{"class":991,"line":1142},[989,10375,1064],{"class":995},[989,10377,1000],{"class":999},[989,10379,1003],{"class":995},[15,10381,10382],{},"{% endraw %}",[15,10384,10385],{},"Now paste the below script right after the HTML in the template widget, This script adds functionality of speech recognition in our system.",[981,10387,10389],{"className":983,"code":10388,"language":985,"meta":265,"style":265},"\u003Cscript>\nexport default {\n data() {\n   return {\n     \u002F\u002F Initial data properties\n     buttonText: 'Speak',\n     microphoneIcon: 'http:\u002F\u002Ficons.iconarchive.com\u002Ficons\u002Fblackvariant\u002Fbutton-ui-requests-15\u002F512\u002FMicrophone-icon.png',\n     recognition: null,\n     results: '',\n   };\n },\n methods: {\n   \u002F\u002F Method to start recording\n   startRecording() {\n     this.buttonText = 'Recording';\n     this.recognition.stop();\n     this.recognition.start();\n   },\n   \u002F\u002F Method to process the speech recognition results\n   processSpeech(event) {\n     let results = Array.from(event.results).map(result =>   result[0].transcript).join('');\n     this.results = results;\n     this.$emit('speak', results);\n     \u002F\u002FSending result to next node as payload\n     this.send(results);\n   },\n   \u002F\u002F Method to handle the start of recognition\n   handleRecognitionStart() {\n     this.microphoneIcon = 'https:\u002F\u002Fupload.wikimedia.org\u002Fwikipedia\u002Fcommons\u002F0\u002F06\u002FMic-Animation.gif';\n   },\n   \u002F\u002F Method to handle recognition errors\n   handleRecognitionError(event) {\n     this.microphoneIcon = event.error === 'no-speech' || event.error === 'audio-capture'\n       ? 'https:\u002F\u002Fi.ytimg.com\u002Fvi\u002F9YQU797Oy0Y\u002Fhqdefault.jpg'\n       : this.microphoneIcon;\n   },\n   \u002F\u002F Method to handle the end of recognition\n   handleRecognitionEnd() {\n     this.microphoneIcon = 'http:\u002F\u002Ficons.iconarchive.com\u002Ficons\u002Fblackvariant\u002Fbutton-ui-requests-15\u002F512\u002FMicrophone-icon.png';\n   },\n   \u002F\u002F Method to set up the SpeechRecognition object\n   setupRecognition() {\n     this.recognition = new webkitSpeechRecognition();\n     this.recognition.continuous = false;\n     this.recognition.interimResults = false;\n     this.recognition.onresult = this.processSpeech;\n     this.recognition.onstart = this.handleRecognitionStart;\n     this.recognition.onerror = this.handleRecognitionError;\n     this.recognition.onend = this.handleRecognitionEnd;\n   },\n },\n mounted() {\n   \u002F\u002F Initialize SpeechRecognition when the component is mounted\n   this.setupRecognition();\n },\n};\n\u003C\u002Fscript>\n",[442,10390,10391,10399,10407,10416,10423,10428,10444,10460,10470,10481,10486,10490,10499,10504,10513,10532,10548,10563,10568,10573,10587,10657,10669,10693,10698,10712,10716,10721,10730,10747,10751,10756,10769,10814,10826,10837,10841,10846,10855,10871,10875,10880,10889,10906,10924,10941,10961,10981,11001,11021,11025,11029,11038,11043,11055,11059,11064],{"__ignoreMap":265},[989,10392,10393,10395,10397],{"class":991,"line":992},[989,10394,996],{"class":995},[989,10396,1137],{"class":999},[989,10398,1003],{"class":995},[989,10400,10401,10403,10405],{"class":991,"line":269},[989,10402,1592],{"class":1145},[989,10404,1149],{"class":1145},[989,10406,1152],{"class":995},[989,10408,10409,10412,10414],{"class":991,"line":274},[989,10410,10411],{"class":999}," data",[989,10413,1161],{"class":995},[989,10415,1152],{"class":995},[989,10417,10418,10421],{"class":991,"line":266},[989,10419,10420],{"class":1145},"   return",[989,10422,1152],{"class":995},[989,10424,10425],{"class":991,"line":1071},[989,10426,10427],{"class":1008},"     \u002F\u002F Initial data properties\n",[989,10429,10430,10433,10435,10437,10440,10442],{"class":991,"line":1089},[989,10431,10432],{"class":999},"     buttonText",[989,10434,1180],{"class":995},[989,10436,7202],{"class":995},[989,10438,10439],{"class":1030},"Speak",[989,10441,4352],{"class":995},[989,10443,3187],{"class":995},[989,10445,10446,10449,10451,10453,10456,10458],{"class":991,"line":1107},[989,10447,10448],{"class":999},"     microphoneIcon",[989,10450,1180],{"class":995},[989,10452,7202],{"class":995},[989,10454,10455],{"class":1030},"http:\u002F\u002Ficons.iconarchive.com\u002Ficons\u002Fblackvariant\u002Fbutton-ui-requests-15\u002F512\u002FMicrophone-icon.png",[989,10457,4352],{"class":995},[989,10459,3187],{"class":995},[989,10461,10462,10465,10467],{"class":991,"line":1117},[989,10463,10464],{"class":999},"     recognition",[989,10466,1180],{"class":995},[989,10468,10469],{"class":995}," null,\n",[989,10471,10472,10475,10477,10479],{"class":991,"line":1126},[989,10473,10474],{"class":999},"     results",[989,10476,1180],{"class":995},[989,10478,7808],{"class":995},[989,10480,3187],{"class":995},[989,10482,10483],{"class":991,"line":1132},[989,10484,10485],{"class":995},"   };\n",[989,10487,10488],{"class":991,"line":1142},[989,10489,7854],{"class":995},[989,10491,10492,10495,10497],{"class":991,"line":1155},[989,10493,10494],{"class":999}," methods",[989,10496,1180],{"class":995},[989,10498,1152],{"class":995},[989,10500,10501],{"class":991,"line":1166},[989,10502,10503],{"class":1008},"   \u002F\u002F Method to start recording\n",[989,10505,10506,10509,10511],{"class":991,"line":1174},[989,10507,10508],{"class":999},"   startRecording",[989,10510,1161],{"class":995},[989,10512,1152],{"class":995},[989,10514,10515,10518,10521,10523,10525,10528,10530],{"class":991,"line":1187},[989,10516,10517],{"class":995},"     this.",[989,10519,10520],{"class":1060},"buttonText",[989,10522,1223],{"class":995},[989,10524,7202],{"class":995},[989,10526,10527],{"class":1030},"Recording",[989,10529,4352],{"class":995},[989,10531,1753],{"class":995},[989,10533,10534,10536,10539,10541,10544,10546],{"class":991,"line":1193},[989,10535,10517],{"class":995},[989,10537,10538],{"class":1060},"recognition",[989,10540,437],{"class":995},[989,10542,10543],{"class":4345},"stop",[989,10545,1161],{"class":999},[989,10547,1753],{"class":995},[989,10549,10550,10552,10554,10556,10559,10561],{"class":991,"line":1199},[989,10551,10517],{"class":995},[989,10553,10538],{"class":1060},[989,10555,437],{"class":995},[989,10557,10558],{"class":4345},"start",[989,10560,1161],{"class":999},[989,10562,1753],{"class":995},[989,10564,10565],{"class":991,"line":1209},[989,10566,10567],{"class":995},"   },\n",[989,10569,10570],{"class":991,"line":1215},[989,10571,10572],{"class":1008},"   \u002F\u002F Method to process the speech recognition results\n",[989,10574,10575,10578,10580,10583,10585],{"class":991,"line":1229},[989,10576,10577],{"class":999},"   processSpeech",[989,10579,4349],{"class":995},[989,10581,10582],{"class":8514},"event",[989,10584,3883],{"class":995},[989,10586,1152],{"class":995},[989,10588,10589,10592,10595,10597,10600,10602,10605,10607,10609,10611,10614,10616,10618,10621,10623,10626,10628,10631,10633,10635,10637,10639,10642,10644,10646,10648,10650,10653,10655],{"class":991,"line":1235},[989,10590,10591],{"class":1020},"     let",[989,10593,10594],{"class":1060}," results",[989,10596,1223],{"class":995},[989,10598,10599],{"class":1060}," Array",[989,10601,437],{"class":995},[989,10603,10604],{"class":4345},"from",[989,10606,4349],{"class":999},[989,10608,10582],{"class":1060},[989,10610,437],{"class":995},[989,10612,10613],{"class":1060},"results",[989,10615,3883],{"class":999},[989,10617,437],{"class":995},[989,10619,10620],{"class":4345},"map",[989,10622,4349],{"class":999},[989,10624,10625],{"class":8514},"result",[989,10627,8520],{"class":1020},[989,10629,10630],{"class":1060},"   result",[989,10632,4629],{"class":999},[989,10634,4836],{"class":1777},[989,10636,7219],{"class":999},[989,10638,437],{"class":995},[989,10640,10641],{"class":1060},"transcript",[989,10643,3883],{"class":999},[989,10645,437],{"class":995},[989,10647,4847],{"class":4345},[989,10649,4349],{"class":999},[989,10651,10652],{"class":995},"''",[989,10654,3883],{"class":999},[989,10656,1753],{"class":995},[989,10658,10659,10661,10663,10665,10667],{"class":991,"line":1241},[989,10660,10517],{"class":995},[989,10662,10613],{"class":1060},[989,10664,1223],{"class":995},[989,10666,10594],{"class":1060},[989,10668,1753],{"class":995},[989,10670,10671,10673,10676,10678,10680,10683,10685,10687,10689,10691],{"class":991,"line":1653},[989,10672,10517],{"class":995},[989,10674,10675],{"class":4345},"$emit",[989,10677,4349],{"class":999},[989,10679,4352],{"class":995},[989,10681,10682],{"class":1030},"speak",[989,10684,4352],{"class":995},[989,10686,4459],{"class":995},[989,10688,10594],{"class":1060},[989,10690,3883],{"class":999},[989,10692,1753],{"class":995},[989,10694,10695],{"class":991,"line":1659},[989,10696,10697],{"class":1008},"     \u002F\u002FSending result to next node as payload\n",[989,10699,10700,10702,10704,10706,10708,10710],{"class":991,"line":1665},[989,10701,10517],{"class":995},[989,10703,6833],{"class":4345},[989,10705,4349],{"class":999},[989,10707,10613],{"class":1060},[989,10709,3883],{"class":999},[989,10711,1753],{"class":995},[989,10713,10714],{"class":991,"line":1671},[989,10715,10567],{"class":995},[989,10717,10718],{"class":991,"line":1690},[989,10719,10720],{"class":1008},"   \u002F\u002F Method to handle the start of recognition\n",[989,10722,10723,10726,10728],{"class":991,"line":1695},[989,10724,10725],{"class":999},"   handleRecognitionStart",[989,10727,1161],{"class":995},[989,10729,1152],{"class":995},[989,10731,10732,10734,10736,10738,10740,10743,10745],{"class":991,"line":1701},[989,10733,10517],{"class":995},[989,10735,10313],{"class":1060},[989,10737,1223],{"class":995},[989,10739,7202],{"class":995},[989,10741,10742],{"class":1030},"https:\u002F\u002Fupload.wikimedia.org\u002Fwikipedia\u002Fcommons\u002F0\u002F06\u002FMic-Animation.gif",[989,10744,4352],{"class":995},[989,10746,1753],{"class":995},[989,10748,10749],{"class":991,"line":1710},[989,10750,10567],{"class":995},[989,10752,10753],{"class":991,"line":1715},[989,10754,10755],{"class":1008},"   \u002F\u002F Method to handle recognition errors\n",[989,10757,10758,10761,10763,10765,10767],{"class":991,"line":1725},[989,10759,10760],{"class":999},"   handleRecognitionError",[989,10762,4349],{"class":995},[989,10764,10582],{"class":8514},[989,10766,3883],{"class":995},[989,10768,1152],{"class":995},[989,10770,10771,10773,10775,10777,10780,10782,10785,10788,10790,10793,10795,10798,10800,10802,10804,10806,10808,10811],{"class":991,"line":1731},[989,10772,10517],{"class":995},[989,10774,10313],{"class":1060},[989,10776,1223],{"class":995},[989,10778,10779],{"class":1060}," event",[989,10781,437],{"class":995},[989,10783,10784],{"class":1060},"error",[989,10786,10787],{"class":995}," ===",[989,10789,7202],{"class":995},[989,10791,10792],{"class":1030},"no-speech",[989,10794,4352],{"class":995},[989,10796,10797],{"class":995}," ||",[989,10799,10779],{"class":1060},[989,10801,437],{"class":995},[989,10803,10784],{"class":1060},[989,10805,10787],{"class":995},[989,10807,7202],{"class":995},[989,10809,10810],{"class":1030},"audio-capture",[989,10812,10813],{"class":995},"'\n",[989,10815,10816,10819,10821,10824],{"class":991,"line":1741},[989,10817,10818],{"class":995},"       ?",[989,10820,7202],{"class":995},[989,10822,10823],{"class":1030},"https:\u002F\u002Fi.ytimg.com\u002Fvi\u002F9YQU797Oy0Y\u002Fhqdefault.jpg",[989,10825,10813],{"class":995},[989,10827,10828,10831,10833,10835],{"class":991,"line":1756},[989,10829,10830],{"class":995},"       :",[989,10832,6845],{"class":995},[989,10834,10313],{"class":1060},[989,10836,1753],{"class":995},[989,10838,10839],{"class":991,"line":1769},[989,10840,10567],{"class":995},[989,10842,10843],{"class":991,"line":1783},[989,10844,10845],{"class":1008},"   \u002F\u002F Method to handle the end of recognition\n",[989,10847,10848,10851,10853],{"class":991,"line":1788},[989,10849,10850],{"class":999},"   handleRecognitionEnd",[989,10852,1161],{"class":995},[989,10854,1152],{"class":995},[989,10856,10857,10859,10861,10863,10865,10867,10869],{"class":991,"line":1794},[989,10858,10517],{"class":995},[989,10860,10313],{"class":1060},[989,10862,1223],{"class":995},[989,10864,7202],{"class":995},[989,10866,10455],{"class":1030},[989,10868,4352],{"class":995},[989,10870,1753],{"class":995},[989,10872,10873],{"class":991,"line":1806},[989,10874,10567],{"class":995},[989,10876,10877],{"class":991,"line":1819},[989,10878,10879],{"class":1008},"   \u002F\u002F Method to set up the SpeechRecognition object\n",[989,10881,10882,10885,10887],{"class":991,"line":1831},[989,10883,10884],{"class":999},"   setupRecognition",[989,10886,1161],{"class":995},[989,10888,1152],{"class":995},[989,10890,10891,10893,10895,10897,10899,10902,10904],{"class":991,"line":1836},[989,10892,10517],{"class":995},[989,10894,10538],{"class":1060},[989,10896,1223],{"class":995},[989,10898,9283],{"class":995},[989,10900,10901],{"class":4345}," webkitSpeechRecognition",[989,10903,1161],{"class":999},[989,10905,1753],{"class":995},[989,10907,10908,10910,10912,10914,10917,10919,10922],{"class":991,"line":9185},[989,10909,10517],{"class":995},[989,10911,10538],{"class":1060},[989,10913,437],{"class":995},[989,10915,10916],{"class":1060},"continuous",[989,10918,1223],{"class":995},[989,10920,10921],{"class":1183}," false",[989,10923,1753],{"class":995},[989,10925,10926,10928,10930,10932,10935,10937,10939],{"class":991,"line":9191},[989,10927,10517],{"class":995},[989,10929,10538],{"class":1060},[989,10931,437],{"class":995},[989,10933,10934],{"class":1060},"interimResults",[989,10936,1223],{"class":995},[989,10938,10921],{"class":1183},[989,10940,1753],{"class":995},[989,10942,10943,10945,10947,10949,10952,10954,10956,10959],{"class":991,"line":9197},[989,10944,10517],{"class":995},[989,10946,10538],{"class":1060},[989,10948,437],{"class":995},[989,10950,10951],{"class":1060},"onresult",[989,10953,1223],{"class":995},[989,10955,6845],{"class":995},[989,10957,10958],{"class":1060},"processSpeech",[989,10960,1753],{"class":995},[989,10962,10963,10965,10967,10969,10972,10974,10976,10979],{"class":991,"line":9207},[989,10964,10517],{"class":995},[989,10966,10538],{"class":1060},[989,10968,437],{"class":995},[989,10970,10971],{"class":1060},"onstart",[989,10973,1223],{"class":995},[989,10975,6845],{"class":995},[989,10977,10978],{"class":1060},"handleRecognitionStart",[989,10980,1753],{"class":995},[989,10982,10983,10985,10987,10989,10992,10994,10996,10999],{"class":991,"line":9213},[989,10984,10517],{"class":995},[989,10986,10538],{"class":1060},[989,10988,437],{"class":995},[989,10990,10991],{"class":1060},"onerror",[989,10993,1223],{"class":995},[989,10995,6845],{"class":995},[989,10997,10998],{"class":1060},"handleRecognitionError",[989,11000,1753],{"class":995},[989,11002,11003,11005,11007,11009,11012,11014,11016,11019],{"class":991,"line":9233},[989,11004,10517],{"class":995},[989,11006,10538],{"class":1060},[989,11008,437],{"class":995},[989,11010,11011],{"class":1060},"onend",[989,11013,1223],{"class":995},[989,11015,6845],{"class":995},[989,11017,11018],{"class":1060},"handleRecognitionEnd",[989,11020,1753],{"class":995},[989,11022,11023],{"class":991,"line":9239},[989,11024,10567],{"class":995},[989,11026,11027],{"class":991,"line":9273},[989,11028,7854],{"class":995},[989,11030,11031,11034,11036],{"class":991,"line":9297},[989,11032,11033],{"class":999}," mounted",[989,11035,1161],{"class":995},[989,11037,1152],{"class":995},[989,11039,11040],{"class":991,"line":9320},[989,11041,11042],{"class":1008},"   \u002F\u002F Initialize SpeechRecognition when the component is mounted\n",[989,11044,11045,11048,11051,11053],{"class":991,"line":9371},[989,11046,11047],{"class":995},"   this.",[989,11049,11050],{"class":4345},"setupRecognition",[989,11052,1161],{"class":999},[989,11054,1753],{"class":995},[989,11056,11057],{"class":991,"line":9381},[989,11058,7854],{"class":995},[989,11060,11061],{"class":991,"line":9386},[989,11062,11063],{"class":995},"};\n",[989,11065,11066,11068,11070],{"class":991,"line":9391},[989,11067,1064],{"class":995},[989,11069,1137],{"class":999},[989,11071,1003],{"class":995},[19,11073,11075],{"id":11074},"adding-an-environment-variable","Adding an Environment variable",[15,11077,11078,11079],{},"Why do we need to add an environment variable? In this guide, we will build a speech-driven chatbot that involves integrating the Chat-GPT AI model. For this we need openAi’s API key. An API key is a form of private data that needs to be protected from being exposed. That is why we need the environment variables. It provides a secure way to store and access the API key without revealing it directly in the flow.  For more details see ",[256,11080,11082],{"href":11081},"\u002Fblog\u002F2023\u002F01\u002Fenvironment-variables-in-node-red\u002F","Using Environment Variables in Node-RED",[903,11084,11085,11088],{},[30,11086,11087],{},"Navigate to the instance's setting and then go to the environment section.",[30,11089,8177,11090,11093],{},[442,11091,11092],{},"add variable"," button and add a variable for Chat-gpt API.",[15,11095,11096],{},[239,11097],{"alt":11098,"src":11099,"title":11100},"\"Setting environment variable for Chat-gpt token\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fspeech-driven-chatbot-environment-section.png","Setting environment variable for chat-gpt token",[19,11102,11104],{"id":11103},"setting-msg-property","Setting msg property",[15,11106,11107],{},"Now let’s set that added environment variables as msg's property.",[903,11109,11110,11113,11116],{},[30,11111,11112],{},"Add a change node to canvas.",[30,11114,11115],{},"Set environment variable to ms.token property.",[30,11117,11118],{},"Connect the change node’s input to the template widget’s output.",[15,11120,11121],{},[239,11122],{"alt":11123,"src":11124,"title":11125},"\"Setting msg's property for Chat-gpt token\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fspeech-driven-chatbot-change-node.png","Setting msg's property for Chat-gpt token",[19,11127,11129],{"id":11128},"installing-and-configuring-custom-node","Installing and configuring custom node",[15,11131,11132],{},"In this section, we will install a custom node that will allow us to interact with the Chat-gpt AI model.",[903,11134,11135,11142,11145],{},[30,11136,11137,11138,11141],{},"Install ",[442,11139,11140],{},"@sumit_shinde_84\u002Fnode-red-contrib-node-gpt"," by pallet manager, you can use other nodes according to your preference.",[30,11143,11144],{},"Drag a ChatGPT node to canvas.",[30,11146,11147],{},"Connect the ChatGPT node’s input to the change node’s output.",[19,11149,11151],{"id":11150},"building-text-to-speech-vue-component","Building Text-to-Speech Vue component",[15,11153,11154],{},"We will build a Vue component that converts text received from ChatGPT into speech.",[903,11156,11157,11160,11163],{},[30,11158,11159],{},"Drag another template widget to canvas and select the added group, alternatively, you can create a separate group for this component according to your preference.",[30,11161,11162],{},"Paste the below Vue snippets into the template widget.",[30,11164,11165],{},"Connect the template widget’s input to the ChatGPT node’s output.",[15,11167,11168],{},"Paste the below snippet in the template widget which displays chat-gpt response on the dashboard",[15,11170,10210],{},[981,11172,11174],{"className":983,"code":11173,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cstrong> Chat-gpt: \u003C\u002Fstrong> {{textToSpeech}}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[442,11175,11176,11184,11192,11212,11220],{"__ignoreMap":265},[989,11177,11178,11180,11182],{"class":991,"line":992},[989,11179,996],{"class":995},[989,11181,1000],{"class":999},[989,11183,1003],{"class":995},[989,11185,11186,11188,11190],{"class":991,"line":269},[989,11187,5022],{"class":995},[989,11189,228],{"class":999},[989,11191,1003],{"class":995},[989,11193,11194,11196,11198,11200,11203,11205,11207,11209],{"class":991,"line":274},[989,11195,1014],{"class":995},[989,11197,33],{"class":999},[989,11199,1057],{"class":995},[989,11201,11202],{"class":1060}," Chat-gpt: ",[989,11204,1064],{"class":995},[989,11206,33],{"class":999},[989,11208,1057],{"class":995},[989,11210,11211],{"class":1060}," {{textToSpeech}}\n",[989,11213,11214,11216,11218],{"class":991,"line":266},[989,11215,5139],{"class":995},[989,11217,228],{"class":999},[989,11219,1003],{"class":995},[989,11221,11222,11224,11226],{"class":991,"line":1071},[989,11223,1064],{"class":995},[989,11225,1000],{"class":999},[989,11227,1003],{"class":995},[15,11229,10382],{},[15,11231,11232],{},"Paste the below snippet right after the HTML, This snippet adds the functionality of text-to-speech into our system, which triggers when msg received by the previous node.",[981,11234,11236],{"className":983,"code":11235,"language":985,"meta":265,"style":265},"\u003Cscript>\n  export default {\n  data() {\n    return {\n      \u002F\u002F Data property to store the text to be spoken\n      textToSpeech: '',\n    };\n  },\n  methods: {\n    \u002F\u002F Method to trigger text-to-speech\n    speakText() {\n      \u002F\u002F Check if there is non-empty text to speech\n      if (this.textToSpeech.trim() !== '') {\n        \u002F\u002F Create a SpeechSynthesisUtterance with the text to be spoken\n        const utterance = new  SpeechSynthesisUtterance(this.textToSpeech);\n        \u002F\u002F Use the SpeechSynthesis API to speak the provided text\n        window.speechSynthesis.speak(utterance);\n      }\n    },\n  },\n  mounted() {\n    \u002F\u002F Event listener for receiving messages    \n  \n     this.$socket.on('msg-input:' + this.id, (msg) => {\n\n      \u002F\u002F Update the textToSpeech property with the received message payload\n      this.textToSpeech = msg.payload;\n     \n      \u002F\u002F Trigger text-to-speech with the received message\n      this.speakText();\n    });\n  },\n};\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n  textarea {\n    width: 100%;\n    height: 100px;\n    margin-bottom: 10px;\n  }\n\u003C\u002Fstyle>\n",[442,11237,11238,11246,11254,11262,11268,11273,11284,11289,11294,11303,11308,11317,11322,11351,11356,11381,11386,11409,11413,11417,11421,11430,11435,11439,11479,11483,11488,11505,11510,11515,11526,11535,11539,11543,11551,11555,11565,11572,11583,11594,11606,11610],{"__ignoreMap":265},[989,11239,11240,11242,11244],{"class":991,"line":992},[989,11241,996],{"class":995},[989,11243,1137],{"class":999},[989,11245,1003],{"class":995},[989,11247,11248,11250,11252],{"class":991,"line":269},[989,11249,6764],{"class":1145},[989,11251,1149],{"class":1145},[989,11253,1152],{"class":995},[989,11255,11256,11258,11260],{"class":991,"line":274},[989,11257,7787],{"class":999},[989,11259,1161],{"class":995},[989,11261,1152],{"class":995},[989,11263,11264,11266],{"class":991,"line":266},[989,11265,7796],{"class":1145},[989,11267,1152],{"class":995},[989,11269,11270],{"class":991,"line":1071},[989,11271,11272],{"class":1008},"      \u002F\u002F Data property to store the text to be spoken\n",[989,11274,11275,11278,11280,11282],{"class":991,"line":1089},[989,11276,11277],{"class":999},"      textToSpeech",[989,11279,1180],{"class":995},[989,11281,7808],{"class":995},[989,11283,3187],{"class":995},[989,11285,11286],{"class":991,"line":1107},[989,11287,11288],{"class":995},"    };\n",[989,11290,11291],{"class":991,"line":1117},[989,11292,11293],{"class":995},"  },\n",[989,11295,11296,11299,11301],{"class":991,"line":1126},[989,11297,11298],{"class":999},"  methods",[989,11300,1180],{"class":995},[989,11302,1152],{"class":995},[989,11304,11305],{"class":991,"line":1132},[989,11306,11307],{"class":1008},"    \u002F\u002F Method to trigger text-to-speech\n",[989,11309,11310,11313,11315],{"class":991,"line":1142},[989,11311,11312],{"class":999},"    speakText",[989,11314,1161],{"class":995},[989,11316,1152],{"class":995},[989,11318,11319],{"class":991,"line":1155},[989,11320,11321],{"class":1008},"      \u002F\u002F Check if there is non-empty text to speech\n",[989,11323,11324,11327,11329,11331,11334,11336,11339,11342,11345,11347,11349],{"class":991,"line":1166},[989,11325,11326],{"class":1145},"      if",[989,11328,9801],{"class":999},[989,11330,7341],{"class":995},[989,11332,11333],{"class":1060},"textToSpeech",[989,11335,437],{"class":995},[989,11337,11338],{"class":4345},"trim",[989,11340,11341],{"class":999},"() ",[989,11343,11344],{"class":995},"!==",[989,11346,7808],{"class":995},[989,11348,4359],{"class":999},[989,11350,4390],{"class":995},[989,11352,11353],{"class":991,"line":1174},[989,11354,11355],{"class":1008},"        \u002F\u002F Create a SpeechSynthesisUtterance with the text to be spoken\n",[989,11357,11358,11361,11364,11366,11368,11371,11373,11375,11377,11379],{"class":991,"line":1187},[989,11359,11360],{"class":1020},"        const",[989,11362,11363],{"class":1060}," utterance",[989,11365,1223],{"class":995},[989,11367,9283],{"class":995},[989,11369,11370],{"class":4345},"  SpeechSynthesisUtterance",[989,11372,4349],{"class":999},[989,11374,7341],{"class":995},[989,11376,11333],{"class":1060},[989,11378,3883],{"class":999},[989,11380,1753],{"class":995},[989,11382,11383],{"class":991,"line":1193},[989,11384,11385],{"class":1008},"        \u002F\u002F Use the SpeechSynthesis API to speak the provided text\n",[989,11387,11388,11391,11393,11396,11398,11400,11402,11405,11407],{"class":991,"line":1199},[989,11389,11390],{"class":1060},"        window",[989,11392,437],{"class":995},[989,11394,11395],{"class":1060},"speechSynthesis",[989,11397,437],{"class":995},[989,11399,10682],{"class":4345},[989,11401,4349],{"class":999},[989,11403,11404],{"class":1060},"utterance",[989,11406,3883],{"class":999},[989,11408,1753],{"class":995},[989,11410,11411],{"class":991,"line":1209},[989,11412,6798],{"class":995},[989,11414,11415],{"class":991,"line":1215},[989,11416,1636],{"class":995},[989,11418,11419],{"class":991,"line":1229},[989,11420,11293],{"class":995},[989,11422,11423,11426,11428],{"class":991,"line":1235},[989,11424,11425],{"class":999},"  mounted",[989,11427,1161],{"class":995},[989,11429,1152],{"class":995},[989,11431,11432],{"class":991,"line":1241},[989,11433,11434],{"class":1008},"    \u002F\u002F Event listener for receiving messages    \n",[989,11436,11437],{"class":991,"line":1653},[989,11438,263],{"class":999},[989,11440,11441,11443,11446,11448,11451,11453,11455,11458,11460,11463,11465,11467,11469,11471,11473,11475,11477],{"class":991,"line":1659},[989,11442,10517],{"class":995},[989,11444,11445],{"class":1060},"$socket",[989,11447,437],{"class":995},[989,11449,11450],{"class":4345},"on",[989,11452,4349],{"class":999},[989,11454,4352],{"class":995},[989,11456,11457],{"class":1030},"msg-input:",[989,11459,4352],{"class":995},[989,11461,11462],{"class":995}," +",[989,11464,6845],{"class":995},[989,11466,7835],{"class":1060},[989,11468,4459],{"class":995},[989,11470,9801],{"class":995},[989,11472,3103],{"class":8514},[989,11474,3883],{"class":995},[989,11476,8520],{"class":1020},[989,11478,1152],{"class":995},[989,11480,11481],{"class":991,"line":1665},[989,11482,1129],{"emptyLinePlaceholder":295},[989,11484,11485],{"class":991,"line":1671},[989,11486,11487],{"class":1008},"      \u002F\u002F Update the textToSpeech property with the received message payload\n",[989,11489,11490,11493,11495,11497,11499,11501,11503],{"class":991,"line":1690},[989,11491,11492],{"class":995},"      this.",[989,11494,11333],{"class":1060},[989,11496,1223],{"class":995},[989,11498,4510],{"class":1060},[989,11500,437],{"class":995},[989,11502,4402],{"class":1060},[989,11504,1753],{"class":995},[989,11506,11507],{"class":991,"line":1695},[989,11508,11509],{"class":999},"     \n",[989,11511,11512],{"class":991,"line":1701},[989,11513,11514],{"class":1008},"      \u002F\u002F Trigger text-to-speech with the received message\n",[989,11516,11517,11519,11522,11524],{"class":991,"line":1710},[989,11518,11492],{"class":995},[989,11520,11521],{"class":4345},"speakText",[989,11523,1161],{"class":999},[989,11525,1753],{"class":995},[989,11527,11528,11531,11533],{"class":991,"line":1715},[989,11529,11530],{"class":995},"    }",[989,11532,3883],{"class":999},[989,11534,1753],{"class":995},[989,11536,11537],{"class":991,"line":1725},[989,11538,11293],{"class":995},[989,11540,11541],{"class":991,"line":1731},[989,11542,11063],{"class":995},[989,11544,11545,11547,11549],{"class":991,"line":1741},[989,11546,1064],{"class":995},[989,11548,1137],{"class":999},[989,11550,1003],{"class":995},[989,11552,11553],{"class":991,"line":1756},[989,11554,1129],{"emptyLinePlaceholder":295},[989,11556,11557,11559,11561,11563],{"class":991,"line":1769},[989,11558,996],{"class":995},[989,11560,1720],{"class":999},[989,11562,5160],{"class":1020},[989,11564,1003],{"class":995},[989,11566,11567,11570],{"class":991,"line":1783},[989,11568,11569],{"class":1736},"  textarea",[989,11571,1152],{"class":995},[989,11573,11574,11576,11578,11581],{"class":991,"line":1788},[989,11575,1809],{"class":1744},[989,11577,1180],{"class":995},[989,11579,11580],{"class":1777}," 100%",[989,11582,1753],{"class":995},[989,11584,11585,11587,11589,11592],{"class":991,"line":1794},[989,11586,1822],{"class":1744},[989,11588,1180],{"class":995},[989,11590,11591],{"class":1777}," 100px",[989,11593,1753],{"class":995},[989,11595,11596,11599,11601,11604],{"class":991,"line":1806},[989,11597,11598],{"class":1744},"    margin-bottom",[989,11600,1180],{"class":995},[989,11602,11603],{"class":1777}," 10px",[989,11605,1753],{"class":995},[989,11607,11608],{"class":991,"line":1819},[989,11609,5265],{"class":995},[989,11611,11612,11614,11616],{"class":991,"line":1831},[989,11613,1064],{"class":995},[989,11615,1720],{"class":999},[989,11617,1003],{"class":995},[15,11619,11620],{},"Your final flow should look like this:",[15,11622,11623],{},[239,11624],{"alt":11625,"src":11626,"title":11627},"\"Speech Driven Chatbot system flow\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fspeech-driven-chatbot-flow.png","Speech Driven Chatbot system flow",[19,11629,11630],{"id":5917},"Deploying the Flow",[15,11632,11633],{},[239,11634],{"alt":11635,"src":11636,"title":11637},"\"Deploying Sentiment analysis Node-RED flow\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fspeech-driven-chatbot-flowfue-editor.png","Deploying Sentiment analysis Node-RED flow",[15,11639,11640,11641],{},"We have successfully built our Speech-Driven Chatbot System. Now it's time to deploy the flow, to do that click on the red deploy button which you can find in the top right corner. After that go to ",[442,11642,11643],{},"https:\u002F\u002F\u003Cyour-instance-name>.flowfuse.cloud\u002Fdashboard",[15,11645,11646],{},[239,11647],{"alt":11648,"src":11649,"title":11650},"\"Speech Driven Chatbot using Node-RED Dashboard 2.0\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fspeech-driven-chatbot-system.gif","Speech Driven Chatbot using Node-RED Dashboard 2.0",[19,11652,2115],{"id":2114},[15,11654,11655],{},"In this guide, we have built a Speech-Driven Chatbot System which allows us to understand how we can add speech recognition and synthesis features into our project without any external API or custom node. It also provides a brief overview of how we can integrate chat-gpt into our system.",[1720,11657,11658],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}",{"title":265,"searchDepth":266,"depth":266,"links":11660},[11661,11662,11663,11664,11665,11666,11667,11668,11669],{"id":10145,"depth":269,"text":10146},{"id":10172,"depth":269,"text":10173},{"id":10183,"depth":269,"text":10184},{"id":11074,"depth":269,"text":11075},{"id":11103,"depth":269,"text":11104},{"id":11128,"depth":269,"text":11129},{"id":11150,"depth":269,"text":11151},{"id":5917,"depth":269,"text":11630},{"id":2114,"depth":269,"text":2115},"2024-01-29","Learn to build a speech-driven chatbot system with Node-RED and Dashboard 2.0. Integrate speech recognition, synthesis, and Chat-GPT seamlessly.",{"excerpt":11673},{"type":12,"value":11674},[11675,11677],[15,11676,10139],{},[15,11678,10142],{},"\u002Fblog\u002F2024\u002F01\u002Fspeech-driven-chatbot-with-node-red",{"title":10133,"description":11671},{"loc":11679},"blog\u002F2024\u002F01\u002Fspeech-driven-chatbot-with-node-red","Guide to building speech-driven chatbot using Node-RED, speech recognition, and Dashboard 2.0.",[487,3010,303,11685,11686],"virtual assistant","ai","3nsKTTaguSWWzjdPFIYFRNL7Q1js-r5OdBfdoMaRdm0",{"id":11689,"title":11690,"authors":11691,"body":11692,"cta":3,"date":11839,"description":11840,"extension":287,"image":11841,"lastUpdated":3,"meta":11842,"navigation":295,"path":11855,"seo":11856,"sitemap":11857,"stem":11858,"subtitle":11840,"tags":11859,"tldr":3,"video":3,"__hash__":11860},"blog\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-ga.md","Node-RED Dashboard 2.0 is Generally Available!",[309],{"type":12,"value":11693,"toc":11834},[11694,11714,11720,11737,11740,11742,11745,11764,11767,11773,11776,11784,11792,11796,11801,11803,11812,11829],[15,11695,11696,11697,11701,11702,9801,11706,11709,11710,11713],{},"Back in ",[256,11698,11700],{"href":11699},"\u002Fblog\u002F2023\u002F06\u002Fdashboard-announcement\u002F","June 2023"," we announced that FlowFuse would be investing into building out the next generation of Node-RED Dashboard, the most popular UI framework for Node-RED.\nWe followed this up with the ",[256,11703,11705],{"href":11704},"\u002Fblog\u002F2023\u002F07\u002Fdashboard-0-1-release\u002F","first release",[442,11707,11708],{},"0.0.1",") in July, just one month later, and today, we are pleased to announce that we have reached a major milestone in this journey, with the release of our first major version (",[442,11711,11712],{},"1.0.0",") of Node-RED Dashboard 2.0.",[15,11715,11716],{},[239,11717],{"alt":11718,"src":11719},"Dashboard 2.0 Example showing weather data","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fdashboard-ga-example.png",[15,11721,11722,11723,11725,11726,2355,11731,11736],{},"With our ",[442,11724,11712],{}," release, you can now build your dashboards on a reliable and stable package, and we invite you to to start contributing your own third-party ",[256,11727,11730],{"href":11728,"rel":11729},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fwidgets\u002Fthird-party.html",[402],"widgets",[256,11732,11735],{"href":11733,"rel":11734},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fplugins\u002F",[402],"plugins",". We're excited to see what the community can contribute and build on top of this new Dashboard 2.0 framework, and we'll be continuing development to the core collection of widgets too.",[15,11738,11739],{},"With Node-RED Dashboard 2.0, we have re-built the original Node-RED Dashboard from the ground up. It is now extensible due to it being VueJS-based, completely responsive down to mobile, and we've made many quality of life improvements across the board to the existing widget collection, as well as adding a few new ones too.",[19,11741,3524],{"id":3523},[15,11743,11744],{},"We've shared plenty of updates since we started, detailing the feature parity with the original Node-RED Dashboard, as well as some of the new widgets and features we've added to the new Dashboard, such as Markdown, Mermaid Charts and new Layout Options, you can read more about those here:",[27,11746,11747,11753,11759],{},[30,11748,11749],{},[256,11750,11752],{"href":11751},"\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout\u002F","Dynamic Markdown, Tables & Notebooks",[30,11754,11755],{},[256,11756,11758],{"href":11757},"\u002Fblog\u002F2023\u002F11\u002Fdashboard-0-7\u002F","UI Chart Improvements",[30,11760,11761],{},[256,11762,11763],{"href":2424},"Building a Custom Video Player",[15,11765,11766],{},"Furthermore, the most requested feature for the legacy dashboard has been implemented in Dashboard 2.0, the ability to hide charts and forms based on the user that's viewing the dashboard.",[15,11768,11769],{},[239,11770],{"alt":11771,"src":11772},"Dashboard 2.0 Example showing personalised dashboard","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-user2.png",[15,11774,11775],{},"Read more about it here:",[27,11777,11778],{},[30,11779,11780],{},[256,11781,11783],{"href":11782},"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user\u002F","Personalised Multi User Dashboards",[15,11785,11786,11787,11791],{},"If that wasn't enough, we also have ",[256,11788,11790],{"href":3518,"rel":11789},[402],"rich documentation"," for Dashboard 2.0 too, detailing all of the available nodes, details on how Dashboard 2.0 is built and how to contribute to the project too if you're that way inclined.",[19,11793,11795],{"id":11794},"upcoming-webinar","Upcoming Webinar",[15,11797,11798,11799],{},"If you're interested in learning more about Dashboard 2.0 and in particular, personalised multi-user dashboards, we're hosting a webinar on Thursday, 29th February. You can find out more information ",[256,11800,436],{"href":5442},[19,11802,8036],{"id":8035},[15,11804,11805,11806,11811],{},"We aren't stopping here, we'll continnue to push Dashboard 2.0 forward with future development, with a ",[256,11807,11810],{"href":11808,"rel":11809},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F12",[402],"new UI Gauge"," next on the list. You can track that progress of that particular issue, and the rest of the work we have lined up on our GitHub Projects:",[27,11813,11814,11819,11824],{},[30,11815,11816],{},[256,11817,8047],{"href":448,"rel":11818},[402],[30,11820,11821],{},[256,11822,8053],{"href":2553,"rel":11823},[402],[30,11825,11826],{},[256,11827,8060],{"href":8058,"rel":11828},[402],[15,11830,8063,11831,437],{},[256,11832,8068],{"href":8066,"rel":11833},[402],{"title":265,"searchDepth":266,"depth":266,"links":11835},[11836,11837,11838],{"id":3523,"depth":269,"text":3524},{"id":11794,"depth":269,"text":11795},{"id":8035,"depth":269,"text":8036},"2024-01-24","This week sees our first major version release of Node-RED Dashboard 2.0!","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Ftile-dashboard-2-ga.png",{"excerpt":11843},{"type":12,"value":11844},[11845],[15,11846,11696,11847,11701,11849,9801,11851,11709,11853,11713],{},[256,11848,11700],{"href":11699},[256,11850,11705],{"href":11704},[442,11852,11708],{},[442,11854,11712],{},"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-ga",{"title":11690,"description":11840},{"loc":11855},"blog\u002F2024\u002F01\u002Fdashboard-2-ga",[487,8099,8100,8101,303],"fJRM4rVCaEUL-VZKECJY8e6OvNoDC9hR6GiGbvJVAH8",{"id":11862,"title":11863,"authors":11864,"body":11865,"cta":3,"date":11839,"description":12469,"extension":287,"image":12470,"lastUpdated":3,"meta":12471,"navigation":295,"path":12480,"seo":12481,"sitemap":12482,"stem":12483,"subtitle":12484,"tags":12485,"tldr":3,"video":3,"__hash__":12486},"blog\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user.md","Personalised Multi-user Dashboards with Node-RED Dashboard 2.0!",[309],{"type":12,"value":11866,"toc":12451},[11867,11874,11877,11880,11883,11887,11890,11894,11900,11907,11915,11919,11924,11929,11941,11947,11950,11954,11957,11964,11968,11974,12078,12081,12087,12093,12112,12127,12133,12139,12153,12157,12161,12167,12172,12178,12201,12203,12258,12260,12273,12277,12280,12292,12296,12299,12323,12375,12384,12390,12395,12414,12416,12421,12423,12426,12443,12448],[15,11868,11869,11870,11873],{},"This week has seen the release of the ",[256,11871,11872],{"href":11855},"first major version of Node-RED Dashboard 2.0",", with it, we've made available a new FlowFuse-exclusive feature, personalised multi-user dashboards.",[15,11875,11876],{},"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.",[19,11878,11783],{"id":11879},"personalised-multi-user-dashboards",[15,11881,11882],{},"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.",[82,11884,11886],{"id":11885},"getting-started","Getting Started",[15,11888,11889],{},"To enable personalised multi-user dashboards, you'll need to be using FlowFuse, and complete two steps:",[892,11891,11893],{"id":11892},"step-1-enable-flowfuse-user-authentication","Step 1: Enable \"FlowFuse User Authentication\"",[15,11895,11896,11897,11899],{},"All instances on FlowFuse can be configured with ",[333,11898,4111],{}," in the \"Security\" Settings. This option requires any user that wants access to your Editor or dashboard to be authorized by FlowFuse first.",[15,11901,11902],{},[239,11903],{"alt":11904,"dataZoomable":265,"src":11905,"title":11906},"\"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",[9646,11908,11912],{"className":11909},[11910,11911,8823],"-mt-6","mb-4",[11913,11914,11904],"b",{},[892,11916,11918],{"id":11917},"step-2-install-flowfuses-user-addon","Step 2: Install FlowFuse's User Addon",[11920,11921,11923],"h5",{"id":11922},"flowfuse-cloud","FlowFuse Cloud",[15,11925,11926],{},[333,11927,11928],{},"Note: Every instance created from today onwards automatically comes with the necessary configuration. Already created instances need to be manually restarted.",[15,11930,11931,11932,11935,11936,11940],{},"The Personalised Multi-User Dashboard plugin, ",[442,11933,11934],{},"@flowfuse\u002Fnode-red-dashboard-2-user-addon",", is available in our ",[256,11937,11939],{"href":11938},"\u002Fcertified-nodes\u002F","Certified Nodes"," catalogue, accessible to our Teams and Enterprise customers.",[15,11942,11943,11944,11946],{},"Once the \"FlowFuse User Authentication\" option has been enabled on your instance, you can then install our plugin, ",[442,11945,11934],{},", through the \"Manage Palette\" option in the Node-RED Editor.",[15,11948,11949],{},"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.",[11920,11951,11953],{"id":11952},"flowfuse-self-hosted","FlowFuse Self-Hosted",[15,11955,11956],{},"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.",[15,11958,11959,11960,11963],{},"Alternatively, if you're looking to elevate your Node-RED infrastructure, ",[256,11961,11962],{"href":10063},"book in a chat with us"," to talk about how FlowFuse can help.",[82,11965,11967],{"id":11966},"using-the-plugin","Using the Plugin",[15,11969,11970,11971,11973],{},"Once enabled, any messages emitted by a Dashboard 2.0 node will contain a new ",[442,11972,1409],{}," object, e.g:",[981,11975,11979],{"className":11976,"code":11977,"language":11978,"meta":265,"style":265},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\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",[442,11980,11981,11985,12005,12023,12041,12058,12074],{"__ignoreMap":265},[989,11982,11983],{"class":991,"line":992},[989,11984,4390],{"class":995},[989,11986,11987,11989,11992,11994,11997,12000,12002],{"class":991,"line":269},[989,11988,3170],{"class":995},[989,11990,11991],{"class":1030},"userId",[989,11993,1027],{"class":995},[989,11995,11996],{"class":999},": ",[989,11998,11999],{"class":995},"\"\"",[989,12001,4459],{"class":995},[989,12003,12004],{"class":1008},"   \u002F\u002F unique identifier for the user\n",[989,12006,12007,12009,12012,12014,12016,12018,12020],{"class":991,"line":274},[989,12008,3170],{"class":995},[989,12010,12011],{"class":1030},"username",[989,12013,1027],{"class":995},[989,12015,11996],{"class":999},[989,12017,11999],{"class":995},[989,12019,4459],{"class":995},[989,12021,12022],{"class":1008}," \u002F\u002F FlowFuse Username\n",[989,12024,12025,12027,12030,12032,12034,12036,12038],{"class":991,"line":266},[989,12026,3170],{"class":995},[989,12028,12029],{"class":1030},"email",[989,12031,1027],{"class":995},[989,12033,11996],{"class":999},[989,12035,11999],{"class":995},[989,12037,4459],{"class":995},[989,12039,12040],{"class":1008},"    \u002F\u002F E-Mail Address connected to their FlowFuse account\n",[989,12042,12043,12045,12047,12049,12051,12053,12055],{"class":991,"line":1071},[989,12044,3170],{"class":995},[989,12046,3173],{"class":1030},[989,12048,1027],{"class":995},[989,12050,11996],{"class":999},[989,12052,11999],{"class":995},[989,12054,4459],{"class":995},[989,12056,12057],{"class":1008},"     \u002F\u002F Full Name\n",[989,12059,12060,12062,12065,12067,12069,12071],{"class":991,"line":1089},[989,12061,3170],{"class":995},[989,12063,12064],{"class":1030},"image",[989,12066,1027],{"class":995},[989,12068,11996],{"class":999},[989,12070,11999],{"class":995},[989,12072,12073],{"class":1008},"     \u002F\u002F User Avatar from FlowFuse\n",[989,12075,12076],{"class":991,"line":1107},[989,12077,1698],{"class":995},[15,12079,12080],{},"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\".",[15,12082,12083],{},[239,12084],{"alt":12085,"dataZoomable":265,"src":12086,"title":12085},"The new 'FF Auth' options available in Node-RED to allow for client constraints","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-ff-settings.png",[9646,12088,12090],{"className":12089},[11910,11911,8823],[11913,12091,12092],{},"A screenshot of the new 'FF Auth' options available in Node-RED to allow for client constraints on different node types.",[15,12094,12095,12096,12099,12100,2355,12102,12104,12105,12108,12109,12111],{},"In the original Node-RED Dashboard, this was ",[333,12097,12098],{},"always"," enabled for the ",[442,12101,3918],{},[442,12103,3921],{}," nodes, whereby you could include ",[442,12106,12107],{},"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 ",[442,12110,1409],{}," 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.",[15,12113,12114,12115,12117,12118,12120,12121,12123,12124,12126],{},"Utilising this feature, below you can see an example where we send data to a ",[442,12116,869],{}," to render a custom table for each user. Under the covers this is a ",[442,12119,3997],{}," node (triggered on a page view), which then uses the ",[442,12122,1409],{}," 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 ",[442,12125,869],{},", which has been configured to \"Accept Client Constraints\", and so only sends this data to User 2's dashboard.",[15,12128,12129],{},[239,12130],{"alt":12131,"dataZoomable":265,"src":12132,"title":12131},"Showing Admin Task View","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-admin-tasks.png",[9646,12134,12136],{"className":12135},[11910,11911,8823],[11913,12137,12138],{},"Example of a dashboard that displays user-specific content.",[15,12140,12141,12142,12145,12146,12148,12149,12152],{},"Note too that we're also utilising the new ",[256,12143,1017],{"href":863,"rel":12144},[402]," option available in a ",[442,12147,869],{}," which allows us to define content to show in the top-right of the dashboard, in this case, a little ",[333,12150,12151],{},"\"Hi {username}\""," message.",[82,12154,12156],{"id":12155},"examples","Examples",[892,12158,12160],{"id":12159},"rendering-logged-in-user-data","Rendering Logged In User Data",[15,12162,12163,12164,12166],{},"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 ",[442,12165,869],{}," that we render too.",[15,12168,12169],{},[239,12170],{"alt":12171,"dataZoomable":265,"src":11772,"title":12171},"Showing User Unique Data",[9646,12173,12175],{"className":12174},[11910,11911,8823],[11913,12176,12177],{},"The \"Admin\" view that is only made available to users registered as an \"admin\".",[15,12179,12180,12181,4083,12183,12185,12186,12189,12190,12193,12194,12197,12198,12200],{},"Under the covers, we're appending our ",[442,12182,3877],{},[442,12184,3103],{}," object, via the SocketIO ",[442,12187,12188],{},"auth"," option. We make the ",[442,12191,12192],{},"socketio"," object available via a computed ",[442,12195,12196],{},"setup"," variable, this means that we can access this data in any ",[442,12199,869],{}," node, and render like so:",[15,12202,10210],{},[981,12204,12206],{"className":983,"code":12205,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n    \u003Cdiv>\n        \u003Ch1>Hi, {{ setup?.socketio?.auth?.user?.name }}!\u003C\u002Fh1>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[442,12207,12208,12216,12224,12242,12250],{"__ignoreMap":265},[989,12209,12210,12212,12214],{"class":991,"line":992},[989,12211,996],{"class":995},[989,12213,1000],{"class":999},[989,12215,1003],{"class":995},[989,12217,12218,12220,12222],{"class":991,"line":269},[989,12219,1014],{"class":995},[989,12221,228],{"class":999},[989,12223,1003],{"class":995},[989,12225,12226,12228,12231,12233,12236,12238,12240],{"class":991,"line":274},[989,12227,1051],{"class":995},[989,12229,12230],{"class":999},"h1",[989,12232,1057],{"class":995},[989,12234,12235],{"class":1060},"Hi, {{ setup?.socketio?.auth?.user?.name }}!",[989,12237,1064],{"class":995},[989,12239,12230],{"class":999},[989,12241,1003],{"class":995},[989,12243,12244,12246,12248],{"class":991,"line":266},[989,12245,1110],{"class":995},[989,12247,228],{"class":999},[989,12249,1003],{"class":995},[989,12251,12252,12254,12256],{"class":991,"line":1071},[989,12253,1064],{"class":995},[989,12255,1000],{"class":999},[989,12257,1003],{"class":995},[15,12259,10382],{},[15,12261,12262,12263,12265,12266,12269,12270,12272],{},"To enable custom user-by-user content in a ",[442,12264,869],{}," though, we must allow it to \"Accept Client Constraints\". This means that if a ",[442,12267,12268],{},".msg._client.user"," value is included in any messages sent to a ",[442,12271,869],{}," node, then the underlying SocketIO message will be filtered to only send to the relevant user's connection, and no others.",[892,12274,12276],{"id":12275},"admin-only-views","Admin Only Views",[15,12278,12279],{},"With this new functionality we can also now show\u002Fhide content based on the authenticated user.",[15,12281,12282,12283,12288,12289,12291],{},"We recently introduced the option to ",[256,12284,12287],{"href":12285,"rel":12286},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F484",[402],"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 ",[442,12290,3921],{}," node to show the content only to the relevant admins.",[5851,12293],{"width":7979,"height":7979,"src":12294,"allow":7982,"style":12295},"https:\u002F\u002Fflows.nodered.org\u002Fflow\u002F2fe8e6f1e7002f1ff6a9195ad1a153b6\u002Fshare","border: none; margin-bottom: 12px;",[15,12297,12298],{},"Let's breakdown the above flow:",[903,12300,12301,12307,12314],{},[30,12302,12303,12304,12306],{},"We wire a ",[442,12305,3997],{}," node (which emits each time a user views a page) into a switch node",[30,12308,12309,12310,12313],{},"Our switch node checks the ",[442,12311,12312],{},"user.username"," against a known list of admin users and branches \"admin:\" and \"non-admin\" users",[30,12315,12316,12317,12319,12320,12322],{},"For admin users, the ",[442,12318,4613],{}," node defines a message for our ",[442,12321,3921],{}," node to dynamically show content, in this case an \"Admin\" page, when appropriate.",[981,12324,12326],{"className":3156,"code":12325,"language":3158,"meta":265,"style":265},"{\n    \"pages\":{\n        \"show\": [\"Admin View\"]\n    }\n}\n",[442,12327,12328,12332,12344,12367,12371],{"__ignoreMap":265},[989,12329,12330],{"class":991,"line":992},[989,12331,4390],{"class":995},[989,12333,12334,12336,12339,12341],{"class":991,"line":269},[989,12335,3170],{"class":995},[989,12337,12338],{"class":1020},"pages",[989,12340,1027],{"class":995},[989,12342,12343],{"class":995},":{\n",[989,12345,12346,12349,12352,12354,12356,12358,12360,12363,12365],{"class":991,"line":274},[989,12347,12348],{"class":995},"        \"",[989,12350,12351],{"class":1736},"show",[989,12353,1027],{"class":995},[989,12355,1180],{"class":995},[989,12357,7190],{"class":995},[989,12359,1027],{"class":995},[989,12361,12362],{"class":1030},"Admin View",[989,12364,1027],{"class":995},[989,12366,7297],{"class":995},[989,12368,12369],{"class":991,"line":266},[989,12370,1238],{"class":995},[989,12372,12373],{"class":991,"line":1071},[989,12374,1698],{"class":995},[15,12376,12377,12378,12380,12381,12383],{},"All events going into ",[442,12379,3921],{}," are automatically filtered based on the ",[442,12382,1409],{}," object, so only the Admin users will receive the message to show the \"Admin View\" page, resulting in:",[15,12385,12386],{},[239,12387],{"alt":12388,"dataZoomable":265,"src":12389,"title":12388},"Showing Admin Only View","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fmulti-user-dashboard-admin.png",[9646,12391,12393],{"className":12392},[11910,11911,8823],[11913,12394,12177],{},[15,12396,12397,12398,12400,12401,12404,12405,12407,12408,12413],{},"Further extensions of this could also check ",[442,12399,3997],{}," in case a non-admin user tries to access the ",[442,12402,12403],{},"\u002Fadmin"," page directly, in which case we can utilise ",[442,12406,3921],{}," to navigate the user away from the page immediately. See the ",[256,12409,12412],{"href":12410,"rel":12411},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-control.html#navigation",[402],"ui-control documentation"," for more details on this.",[19,12415,11795],{"id":11794},[15,12417,12418,12419],{},"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 ",[256,12420,436],{"href":5442},[19,12422,8036],{"id":8035},[15,12424,12425],{},"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:",[27,12427,12428,12433,12438],{},[30,12429,12430],{},[256,12431,8047],{"href":448,"rel":12432},[402],[30,12434,12435],{},[256,12436,8053],{"href":2553,"rel":12437},[402],[30,12439,12440],{},[256,12441,8060],{"href":8058,"rel":12442},[402],[15,12444,8063,12445,437],{},[256,12446,8068],{"href":8066,"rel":12447},[402],[1720,12449,12450],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":265,"searchDepth":266,"depth":266,"links":12452},[12453,12467,12468],{"id":11879,"depth":269,"text":11783,"children":12454},[12455,12462,12463],{"id":11885,"depth":274,"text":11886,"children":12456},[12457,12458],{"id":11892,"depth":266,"text":11893},{"id":11917,"depth":266,"text":11918,"children":12459},[12460,12461],{"id":11922,"depth":1071,"text":11923},{"id":11952,"depth":1071,"text":11953},{"id":11966,"depth":274,"text":11967},{"id":12155,"depth":274,"text":12156,"children":12464},[12465,12466],{"id":12159,"depth":266,"text":12160},{"id":12275,"depth":266,"text":12276},{"id":11794,"depth":269,"text":11795},{"id":8035,"depth":269,"text":8036},"Discover how to create personalized multi-user dashboards secured with FlowFuse Cloud! Enable FlowFuse User Authentication and install the FlowFuse Node-RED Dashboard 2.0 User Addon for a customized dashboard experience.","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Ftile-dashboard-2-multi-user.png",{"excerpt":12472},{"type":12,"value":12473},[12474,12478],[15,12475,11869,12476,11873],{},[256,12477,11872],{"href":11855},[15,12479,11876],{},"\u002Fblog\u002F2024\u002F01\u002Fdashboard-2-multi-user",{"title":11863,"description":12469},{"loc":12480},"blog\u002F2024\u002F01\u002Fdashboard-2-multi-user","Explore how to build multi-user Dashboards, secured with FlowFuse Cloud!",[487,8099,8100,8101,303],"ovrqv5gl3D6LlMBbR05ng7XRJNH4SzDm2u0e33ET_iA",{"id":12488,"title":12489,"authors":12490,"body":12491,"cta":3,"date":13036,"description":13037,"extension":287,"image":13016,"lastUpdated":3,"meta":13038,"navigation":295,"path":13043,"seo":13044,"sitemap":13045,"stem":13046,"subtitle":13047,"tags":13048,"tldr":3,"video":3,"__hash__":13050},"blog\u002Fblog\u002F2024\u002F01\u002Fsentiment-analysis-with-node-red.md","Sentiment Analysis with Node-RED",[10],{"type":12,"value":12492,"toc":13026},[12493,12496,12500,12503,12523,12527,12530,12544,12551,12555,12558,12578,12585,12589,12596,12610,12614,12617,12631,12638,12642,12645,12653,12661,12961,12990,12992,12999,13001,13006,13011,13018,13020,13023],[15,12494,12495],{},"Have you ever built a sentiment analysis system to extract insights from text content? If yes then I don’t think you'll need an explanation of how complex it is to build. In this guide, we will build a sentiment analysis system with Node-RED using Dashboard 2.0 in a few easy steps.",[19,12497,12499],{"id":12498},"what-exactly-is-sentiment-analysis","What exactly is sentiment analysis?",[15,12501,12502],{},"Sentiment analysis is a context-mining technique used to understand emotions and opinions expressed in text, often classifying them as positive, neutral, or negative. There are many real-world applications of this technique.",[27,12504,12505,12511,12517],{},[30,12506,12507,12510],{},[33,12508,12509],{},"Analysing Feedback:"," Customers, or other stakeholders like employees, are periodically requested to fill out a feedback form. Analysis of such feedback is the most widespread application of sentiment analysis.",[30,12512,12513,12516],{},[33,12514,12515],{},"Campaign Monitoring:"," Another use case of sentiment analysis is a measure of influence which is crucial in any marketing campaign.",[30,12518,12519,12522],{},[33,12520,12521],{},"Brand Monitoring:"," Brand monitoring is another great use case for sentiment analysis. Companies can use sentiment analysis to check the social media sentiments around their brand from their audience.",[19,12524,12526],{"id":12525},"building-a-form-in-dashboard-20","Building a Form in Dashboard 2.0",[15,12528,12529],{},"In this system, we will analyse the sentiment of text content obtained from the user.  For this we are going to build a user interface using Dashboard 2.0 and Node-RED.",[903,12531,12532,12538,12541],{},[30,12533,12534,12535,12537],{},"Install Node-RED Dashboard 2.0. Follow these ",[256,12536,10179],{"href":4196}," to install.",[30,12539,12540],{},"Drag a ui form widget to the canvas and select the created group.",[30,12542,12543],{},"Add an element in the form widget and give it a name and label, select the type as multiline, and set the number of rows according to your need.",[15,12545,12546],{},[239,12547],{"alt":12548,"src":12549,"title":12550},"\"Taking user input for Sentiment analysis using form\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiment-analysis-form.png","Taking user input for Sentiment analysis using form",[19,12552,12554],{"id":12553},"normalizing-the-data","Normalizing the data",[15,12556,12557],{},"We need to normalize the payload before sending it to the next node because the form widget always returns an object containing the property of values of form elements.",[903,12559,12560,12563,12575],{},[30,12561,12562],{},"Drag a change node to canvas.",[30,12564,4616,12565,4750,12568,12570,12571,12574],{},[442,12566,12567],{},"msg.payload.$FORM_ELEMENT_NAME",[442,12569,1350],{},", replace the ",[442,12572,12573],{},"$FORM_ELEMENT_NAME"," with the name of the form element that you have added to the form to obtain user input.",[30,12576,12577],{},"Connect the UI form nodes output to the change node’s input.",[15,12579,12580],{},[239,12581],{"alt":12582,"src":12583,"title":12584},"\"Normalizing the payload using change node\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiment-anlaysis-change-node(1).png","Normalizing the payload using change node",[19,12586,12588],{"id":12587},"installing-custom-node","Installing custom node",[15,12590,12591,12592,12595],{},"Now it’s time to install a custom node that can perform sentiment analysis for us. In this guide, we will use the ",[442,12593,12594],{},"node-red-node-sentiment"," which is a Node-RED node that uses the AFINN-165 wordlists for sentiment analysis of words. It returns a sentiment object containing a score and other properties but we will only use the score property. Score property typically ranges from -5 to 5.",[903,12597,12598,12604,12607],{},[30,12599,12600,12601,12603],{},"Install the ",[442,12602,12594],{}," package by the Node-RED palette manager.",[30,12605,12606],{},"Drag a sentiment node to canvas.",[30,12608,12609],{},"Connect the change nodes output to sentiment node input.",[19,12611,12613],{"id":12612},"calculating-percentage","Calculating percentage",[15,12615,12616],{},"Why do we need to calculate the percentage? We will show the final result with the help of a circular progress bar and three different emojis. Ideally we should show the progress bar based on a percentage of score instead of negative values.",[903,12618,12619,12622],{},[30,12620,12621],{},"Drag another change node to canvas.",[30,12623,12624,12625,4750,12627,12630],{},"set ",[442,12626,1350],{},[442,12628,12629],{},"((msg.sentiment.score - (-5)) \u002F (5 - (-5))) * 100"," as a JSONata expression, it will calculate the percentage of the score.",[15,12632,12633],{},[239,12634],{"alt":12635,"src":12636,"title":12637},"\"Calculating the percentage based on the score using the change node\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiment-analysis-change-node(2).png","Calculating the percentage based on the score using the change node",[19,12639,12641],{"id":12640},"displaying-result-on-dashboard-20","Displaying result on Dashboard 2.0",[15,12643,12644],{},"Finally, we are going to display the result on Dashboard 2.0 with the help of the Vuetify circular progress bar and emojis. To do that we will build a Vue component by using our ui template widget.",[903,12646,12647,12650],{},[30,12648,12649],{},"Drag a ui template widget to canvas and create another group for it.",[30,12651,12652],{},"Paste the below Vue component snippet into the template widget.",[15,12654,12655,12656,12660],{},"We're aware that not everyone coming into Dashboard 2.0 will be familiar with VueJS. We have a more detailed guide ",[256,12657,436],{"href":12658,"rel":12659},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#building-full-vue-components",[402],", but we'll also give a quick overview of the component that we'll use to display the result:",[981,12662,12664],{"className":983,"code":12663,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cv-progress-circular :rotate=\"360\" :size=\"245\" width=\"20\" :width=\"15\" :model-value=\"msg.payload\" color=\"rgb(0,255,0)\">\n      \u003Cimg v-if=\"msg.payload \u003C= 33.33\" src=\"https:\u002F\u002Fi.ibb.co\u002FVHKZ8sn\u002Fimgbin-smirk-emoji-face-emoticon-smile-png.png\" width=\"240\" height=\"240\" alt=\"sad emoji\">\n      \u003Cimg v-else-if=\"msg.payload \u003C= 66.66\" src=\"https:\u002F\u002Fi.ibb.co\u002FnMnybLJ\u002Fimgbin-emoji-computer-icons-emoticon-smiley-png.png\"  width=\"240\" height=\"240\" alt=\"neutral emoji\">\n      \u003Cimg v-else src=\"https:\u002F\u002Fi.ibb.co\u002FTK12RrH\u002FSmile-Emoji-Face-PNG-Download-Image.png\" width=\"240\" height=\"240\" alt=\"happy emoji\">\n    \u003C\u002Fv-progress-circular>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[442,12665,12666,12674,12682,12759,12821,12884,12937,12945,12953],{"__ignoreMap":265},[989,12667,12668,12670,12672],{"class":991,"line":992},[989,12669,996],{"class":995},[989,12671,1000],{"class":999},[989,12673,1003],{"class":995},[989,12675,12676,12678,12680],{"class":991,"line":269},[989,12677,5022],{"class":995},[989,12679,228],{"class":999},[989,12681,1003],{"class":995},[989,12683,12684,12686,12689,12692,12694,12696,12699,12701,12704,12706,12708,12711,12713,12715,12717,12719,12722,12724,12727,12729,12731,12734,12736,12738,12740,12742,12744,12746,12748,12750,12752,12755,12757],{"class":991,"line":274},[989,12685,1014],{"class":995},[989,12687,12688],{"class":999},"v-progress-circular",[989,12690,12691],{"class":1020}," :rotate",[989,12693,1024],{"class":995},[989,12695,1027],{"class":995},[989,12697,12698],{"class":1030},"360",[989,12700,1027],{"class":995},[989,12702,12703],{"class":1020}," :size",[989,12705,1024],{"class":995},[989,12707,1027],{"class":995},[989,12709,12710],{"class":1030},"245",[989,12712,1027],{"class":995},[989,12714,9010],{"class":1020},[989,12716,1024],{"class":995},[989,12718,1027],{"class":995},[989,12720,12721],{"class":1030},"20",[989,12723,1027],{"class":995},[989,12725,12726],{"class":1020}," :width",[989,12728,1024],{"class":995},[989,12730,1027],{"class":995},[989,12732,12733],{"class":1030},"15",[989,12735,1027],{"class":995},[989,12737,7067],{"class":1020},[989,12739,1024],{"class":995},[989,12741,1027],{"class":995},[989,12743,1350],{"class":1030},[989,12745,1027],{"class":995},[989,12747,8911],{"class":1020},[989,12749,1024],{"class":995},[989,12751,1027],{"class":995},[989,12753,12754],{"class":1030},"rgb(0,255,0)",[989,12756,1027],{"class":995},[989,12758,1003],{"class":995},[989,12760,12761,12763,12765,12767,12769,12771,12774,12776,12778,12780,12782,12785,12787,12789,12791,12793,12796,12798,12800,12802,12804,12806,12808,12810,12812,12814,12817,12819],{"class":991,"line":266},[989,12762,10279],{"class":995},[989,12764,239],{"class":999},[989,12766,1021],{"class":1020},[989,12768,1024],{"class":995},[989,12770,1027],{"class":995},[989,12772,12773],{"class":1030},"msg.payload \u003C= 33.33",[989,12775,1027],{"class":995},[989,12777,1328],{"class":1020},[989,12779,1024],{"class":995},[989,12781,1027],{"class":995},[989,12783,12784],{"class":1030},"https:\u002F\u002Fi.ibb.co\u002FVHKZ8sn\u002Fimgbin-smirk-emoji-face-emoticon-smile-png.png",[989,12786,1027],{"class":995},[989,12788,9010],{"class":1020},[989,12790,1024],{"class":995},[989,12792,1027],{"class":995},[989,12794,12795],{"class":1030},"240",[989,12797,1027],{"class":995},[989,12799,1316],{"class":1020},[989,12801,1024],{"class":995},[989,12803,1027],{"class":995},[989,12805,12795],{"class":1030},[989,12807,1027],{"class":995},[989,12809,10284],{"class":1020},[989,12811,1024],{"class":995},[989,12813,1027],{"class":995},[989,12815,12816],{"class":1030},"sad emoji",[989,12818,1027],{"class":995},[989,12820,1003],{"class":995},[989,12822,12823,12825,12827,12830,12832,12834,12837,12839,12841,12843,12845,12848,12850,12853,12855,12857,12859,12861,12863,12865,12867,12869,12871,12873,12875,12877,12880,12882],{"class":991,"line":1071},[989,12824,10279],{"class":995},[989,12826,239],{"class":999},[989,12828,12829],{"class":1020}," v-else-if",[989,12831,1024],{"class":995},[989,12833,1027],{"class":995},[989,12835,12836],{"class":1030},"msg.payload \u003C= 66.66",[989,12838,1027],{"class":995},[989,12840,1328],{"class":1020},[989,12842,1024],{"class":995},[989,12844,1027],{"class":995},[989,12846,12847],{"class":1030},"https:\u002F\u002Fi.ibb.co\u002FnMnybLJ\u002Fimgbin-emoji-computer-icons-emoticon-smiley-png.png",[989,12849,1027],{"class":995},[989,12851,12852],{"class":1020},"  width",[989,12854,1024],{"class":995},[989,12856,1027],{"class":995},[989,12858,12795],{"class":1030},[989,12860,1027],{"class":995},[989,12862,1316],{"class":1020},[989,12864,1024],{"class":995},[989,12866,1027],{"class":995},[989,12868,12795],{"class":1030},[989,12870,1027],{"class":995},[989,12872,10284],{"class":1020},[989,12874,1024],{"class":995},[989,12876,1027],{"class":995},[989,12878,12879],{"class":1030},"neutral emoji",[989,12881,1027],{"class":995},[989,12883,1003],{"class":995},[989,12885,12886,12888,12890,12893,12895,12897,12899,12902,12904,12906,12908,12910,12912,12914,12916,12918,12920,12922,12924,12926,12928,12930,12933,12935],{"class":991,"line":1089},[989,12887,10279],{"class":995},[989,12889,239],{"class":999},[989,12891,12892],{"class":1020}," v-else",[989,12894,1328],{"class":1020},[989,12896,1024],{"class":995},[989,12898,1027],{"class":995},[989,12900,12901],{"class":1030},"https:\u002F\u002Fi.ibb.co\u002FTK12RrH\u002FSmile-Emoji-Face-PNG-Download-Image.png",[989,12903,1027],{"class":995},[989,12905,9010],{"class":1020},[989,12907,1024],{"class":995},[989,12909,1027],{"class":995},[989,12911,12795],{"class":1030},[989,12913,1027],{"class":995},[989,12915,1316],{"class":1020},[989,12917,1024],{"class":995},[989,12919,1027],{"class":995},[989,12921,12795],{"class":1030},[989,12923,1027],{"class":995},[989,12925,10284],{"class":1020},[989,12927,1024],{"class":995},[989,12929,1027],{"class":995},[989,12931,12932],{"class":1030},"happy emoji",[989,12934,1027],{"class":995},[989,12936,1003],{"class":995},[989,12938,12939,12941,12943],{"class":991,"line":1107},[989,12940,1110],{"class":995},[989,12942,12688],{"class":999},[989,12944,1003],{"class":995},[989,12946,12947,12949,12951],{"class":991,"line":1117},[989,12948,5139],{"class":995},[989,12950,228],{"class":999},[989,12952,1003],{"class":995},[989,12954,12955,12957,12959],{"class":991,"line":1126},[989,12956,1064],{"class":995},[989,12958,1000],{"class":999},[989,12960,1003],{"class":995},[27,12962,12963,12970,12976,12987],{},[30,12964,12965,12966,437],{},"v-progress-circular is a Vuetify component to display a circular progress bar, for a detailed guide refer to our blog on  ",[256,12967,12969],{"href":12968},"\u002Fblog\u002F2023\u002F10\u002Fcustom-vuetify-components-dashboard\u002F","Custom Vuetify components for Dashboard 2.0",[30,12971,12972,12975],{},[442,12973,12974],{},"rotate"," is an attribute that lets you specify the rotation angle of the progress bar.",[30,12977,12978,2355,12980,12983,12984,12986],{},[442,12979,6083],{},[442,12981,12982],{},"width"," allow you to set the size of the circular progress bar, and another ",[442,12985,12982],{}," attribute allows you to set the stroke width of the circular progress bar.",[30,12988,12989],{},"v-if, v-else-if, and v-else, allow dynamic rendering of elements based on specified conditions, in this component we are rendering emojis based on percentages calculated by score.",[15,12991,11620],{},[15,12993,12994],{},[239,12995],{"alt":12996,"src":12997,"title":12998},"\"Node-RED flow to do sentiment analysis\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiment-anlaysis-flow.png","Node-RED flow to do sentiment analysis",[19,13000,11630],{"id":5917},[15,13002,13003],{},[239,13004],{"alt":11635,"src":13005,"title":11637},"\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiement-analysis-flowfuse-editor.png",[15,13007,13008,13009],{},"Finally, we have successfully built our sentiment analysis system. Now it's time to deploy the flow, to do that click on the red deploy button which you can find in the top right corner. After that go to ",[442,13010,11643],{},[15,13012,13013],{},[239,13014],{"alt":13015,"src":13016,"title":13017},"\"Sentiment analysis on Text using Node-RED Dashboard 2.0\"","\u002Fblog\u002F2024\u002F01\u002Fimages\u002Fsentiment-analysis-dashboard-gif.gif","Sentiment analysis on Text using Node-RED Dashboard 2.0",[19,13019,2115],{"id":2114},[15,13021,13022],{},"In this post, a sentiment analysis system is built with Node-RED in which the user has a form field to paste text content. After submitting the form, it calculates the percentage based on the output score, which ranges from -5 to 5. The output will be displayed on dashboard 2.0 by a circular progress bar and three different emojis based on percentage.",[1720,13024,13025],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":265,"searchDepth":266,"depth":266,"links":13027},[13028,13029,13030,13031,13032,13033,13034,13035],{"id":12498,"depth":269,"text":12499},{"id":12525,"depth":269,"text":12526},{"id":12553,"depth":269,"text":12554},{"id":12587,"depth":269,"text":12588},{"id":12612,"depth":269,"text":12613},{"id":12640,"depth":269,"text":12641},{"id":5917,"depth":269,"text":11630},{"id":2114,"depth":269,"text":2115},"2024-01-23","Learn how to build a sentiment analysis system with Node-RED using Dashboard 2.0. Extract insights from text content effortlessly with step-by-step guidance.",{"excerpt":13039},{"type":12,"value":13040},[13041],[15,13042,12495],{},"\u002Fblog\u002F2024\u002F01\u002Fsentiment-analysis-with-node-red",{"title":12489,"description":13037},{"loc":13043},"blog\u002F2024\u002F01\u002Fsentiment-analysis-with-node-red","A guide to building a simple sentiment analysis system with Node-RED.",[487,3010,303,13049,11686],"sentiment analysis","iisqRH6h3R55Z6vCA_dcKaktXIbZwYsuFDZkNumBYv8",{"id":13052,"title":13053,"authors":13054,"body":13055,"cta":3,"date":14505,"description":14506,"extension":287,"image":14507,"lastUpdated":3,"meta":14508,"navigation":295,"path":14529,"seo":14530,"sitemap":14531,"stem":14532,"subtitle":14533,"tags":14534,"tldr":3,"video":3,"__hash__":14535},"blog\u002Fblog\u002F2023\u002F12\u002Fdashboard-0-10-0.md","Building a Custom Video Player in Dashboard 2.0",[309],{"type":12,"value":13056,"toc":14491},[13057,13067,13084,13087,13090,13101,13116,13120,13123,13130,13281,13284,13339,13343,13349,13386,13393,13397,13401,13404,13529,13532,13576,13583,13589,13593,13596,13600,13619,13863,13873,13879,13883,13907,14215,14219,14225,14430,14433,14436,14452,14454,14461,14470,14476,14488],[15,13058,13059,13060,13063,13064,13066],{},"Dashboard 2.0 just got ",[333,13061,13062],{},"a lot"," more powerful with our new updates to the ",[442,13065,869],{}," node. New features added to the node include:",[27,13068,13069,13072,13079],{},[30,13070,13071],{},"Support for a full Vue component  to be defined using the VueJS Options API.",[30,13073,13074,13075,13078],{},"Running of raw JavaScript within ",[442,13076,13077],{},"\u003Cscript \u002F>"," tags",[30,13080,13081,13082,13078],{},"Loading of external dependencies through ",[442,13083,13077],{},[15,13085,13086],{},"In this article we're going to deepdive into an example of how you can use this new functionality to build a custom video player.",[15,13088,13089],{},"We're going to aim for 3 key features:",[903,13091,13092,13095,13098],{},[30,13093,13094],{},"Emit events into Node-RED when a user plays\u002Fpauses the video",[30,13096,13097],{},"Allow for the video to be played\u002Fpaused from within Node-RED",[30,13099,13100],{},"Allow the user to seek to a specific point in the video from within Node-RED",[228,13102,13104,13105,13109,13110,13112,13113,437],{"style":13103},"background-color: #fff4b9; border:1px solid #ffc400; color: #a27110; padding: 12px; border-radius: 6px; font-style: italic;","Reminder: all new releases of Dashboard are now under the ",[442,13106,13108],{"style":13107},"background-color: transparent;","@flowfuse"," namespace, so you'll need to update to use ",[442,13111,3669],{"style":13107},", and not ",[442,13114,13115],{"style":13107},"@flowforge",[19,13117,13119],{"id":13118},"building-a-vue-component","Building a Vue Component",[15,13121,13122],{},"With Dashboard 2.0, we switched over our underlying front-end framework to VueJS. We're aware that not everyone coming into Dashboard 2.0 will be familiar with VueJS.",[15,13124,13125,13126,13129],{},"We have a more detailed guide ",[256,13127,436],{"href":12658,"rel":13128},[402],", but we'll also give a quick overview of the elements from Vue \"component\" that we'll use here:",[981,13131,13133],{"className":983,"code":13132,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n    \u003C!-- Our HTML content will go here -->\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: 'MyComponent',\n  methods: {\n    \u002F\u002F JS methods we want to use across our component will go here\n  },\n  mounted () {\n    \u002F\u002F Code we want to run when our component is loaded will go here\n  },\n  unmounted () {\n    \u002F\u002F Code we want to run when our component is unloaded will go here\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle>\n    \u002F* We can define custom CSS here too *\u002F\n\u003C\u002Fstyle>\n",[442,13134,13135,13143,13148,13156,13160,13168,13176,13192,13200,13205,13209,13217,13222,13226,13235,13240,13244,13248,13256,13260,13268,13273],{"__ignoreMap":265},[989,13136,13137,13139,13141],{"class":991,"line":992},[989,13138,996],{"class":995},[989,13140,1000],{"class":999},[989,13142,1003],{"class":995},[989,13144,13145],{"class":991,"line":269},[989,13146,13147],{"class":1008},"    \u003C!-- Our HTML content will go here -->\n",[989,13149,13150,13152,13154],{"class":991,"line":274},[989,13151,1064],{"class":995},[989,13153,1000],{"class":999},[989,13155,1003],{"class":995},[989,13157,13158],{"class":991,"line":266},[989,13159,1129],{"emptyLinePlaceholder":295},[989,13161,13162,13164,13166],{"class":991,"line":1071},[989,13163,996],{"class":995},[989,13165,1137],{"class":999},[989,13167,1003],{"class":995},[989,13169,13170,13172,13174],{"class":991,"line":1089},[989,13171,1592],{"class":1145},[989,13173,1149],{"class":1145},[989,13175,1152],{"class":995},[989,13177,13178,13181,13183,13185,13188,13190],{"class":991,"line":1107},[989,13179,13180],{"class":999},"  name",[989,13182,1180],{"class":995},[989,13184,7202],{"class":995},[989,13186,13187],{"class":1030},"MyComponent",[989,13189,4352],{"class":995},[989,13191,3187],{"class":995},[989,13193,13194,13196,13198],{"class":991,"line":1117},[989,13195,11298],{"class":999},[989,13197,1180],{"class":995},[989,13199,1152],{"class":995},[989,13201,13202],{"class":991,"line":1126},[989,13203,13204],{"class":1008},"    \u002F\u002F JS methods we want to use across our component will go here\n",[989,13206,13207],{"class":991,"line":1132},[989,13208,11293],{"class":995},[989,13210,13211,13213,13215],{"class":991,"line":1142},[989,13212,11425],{"class":999},[989,13214,6824],{"class":995},[989,13216,1152],{"class":995},[989,13218,13219],{"class":991,"line":1155},[989,13220,13221],{"class":1008},"    \u002F\u002F Code we want to run when our component is loaded will go here\n",[989,13223,13224],{"class":991,"line":1166},[989,13225,11293],{"class":995},[989,13227,13228,13231,13233],{"class":991,"line":1174},[989,13229,13230],{"class":999},"  unmounted",[989,13232,6824],{"class":995},[989,13234,1152],{"class":995},[989,13236,13237],{"class":991,"line":1187},[989,13238,13239],{"class":1008},"    \u002F\u002F Code we want to run when our component is unloaded will go here\n",[989,13241,13242],{"class":991,"line":1193},[989,13243,5265],{"class":995},[989,13245,13246],{"class":991,"line":1199},[989,13247,1698],{"class":995},[989,13249,13250,13252,13254],{"class":991,"line":1209},[989,13251,1064],{"class":995},[989,13253,1137],{"class":999},[989,13255,1003],{"class":995},[989,13257,13258],{"class":991,"line":1215},[989,13259,1129],{"emptyLinePlaceholder":295},[989,13261,13262,13264,13266],{"class":991,"line":1229},[989,13263,996],{"class":995},[989,13265,1720],{"class":999},[989,13267,1003],{"class":995},[989,13269,13270],{"class":991,"line":1235},[989,13271,13272],{"class":1008},"    \u002F* We can define custom CSS here too *\u002F\n",[989,13274,13275,13277,13279],{"class":991,"line":1241},[989,13276,1064],{"class":995},[989,13278,1720],{"class":999},[989,13280,1003],{"class":995},[15,13282,13283],{},"Some quick gotchas to note:",[27,13285,13286,13292,13298,13304,13310,13327],{},[30,13287,10210,13288,13291],{},[442,13289,13290],{},"\u003Cdiv>{{ msg }}\u003C\u002Fdiv>","{% endraw %} - is an example of how you render variables into the HTML.",[30,13293,13294,13297],{},[442,13295,13296],{},"\u003Cdiv v-if=\"myVar\">\u003C\u002Fdiv>"," - lets you conditionally show\u002Fhide content based on a variable.",[30,13299,13300,13303],{},[442,13301,13302],{},"\u003Cdiv v-for=\"item in items\">\u003C\u002Fdiv>"," - lets you loop over an array of items and render them into the HTML.",[30,13305,13306,13309],{},[442,13307,13308],{},"\u003Cdiv @click=\"myMethod\">\u003C\u002Fdiv>"," - lets you bind a method to an event, in this case, when the user clicks on the div.",[30,13311,13312,13315,13316,13318,13319,13322,13323,13326],{},[442,13313,13314],{},"\u003Cdiv :class=\"{ 'my-class': isActive }\">\u003C\u002Fdiv>"," - ",[442,13317,1180],{}," is a way to define a \"bound\" property. In this case, the class ",[442,13320,13321],{},"my-class"," will be applied when ",[442,13324,13325],{},"isActive"," is true.",[30,13328,13329,13332,13333,13335,13336,437],{},[442,13330,13331],{},"console.log(this.myVar)"," - when you're writing code inside the ",[442,13334,13077],{}," tags, you can access Component variables and methods using ",[442,13337,13338],{},"this",[82,13340,13342],{"id":13341},"built-in-extras","Built-in Extras",[15,13344,13345,13346,13348],{},"In addition to building a component from scratch, we'll also utilize some built-in features of ",[442,13347,869],{}," too. These will be:",[27,13350,13351,13373],{},[30,13352,13353,13356],{},[33,13354,13355],{},"Variables:",[27,13357,13358,13363,13368],{},[30,13359,13360,13362],{},[442,13361,7835],{}," - The unique ID for this node in Node-RED",[30,13364,13365,13367],{},[442,13366,3103],{}," - The message that was most recently received into the node",[30,13369,13370,13372],{},[442,13371,11445],{}," - The underlying SocketIO connection to Node-RED. Use this to listen to any incoming events, and send new ones back.",[30,13374,13375,13378],{},[33,13376,13377],{},"Functions:",[27,13379,13380],{},[30,13381,13382,13385],{},[442,13383,13384],{},"send(payload)"," - Send a message back to Node-RED",[15,13387,13388,13389,437],{},"As above, we have more detailed documentation on these features ",[256,13390,436],{"href":13391,"rel":13392},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#built-in-functionality",[402],[19,13394,13396],{"id":13395},"building-the-video-player","Building the Video Player",[82,13398,13400],{"id":13399},"defining-the-content-html","Defining the Content (HTML)",[15,13402,13403],{},"We're going to start by adding a basic HTML video player:",[981,13405,13407],{"className":983,"code":13406,"language":985,"meta":265,"style":265},"\u003Ctemplate>\n    \u003Cvideo ref=\"my-video\" style=\"width: 100%\" controls @play=\"onPlay\" @pause=\"onPause\">\n        \u003Csource src=\"http:\u002F\u002Fcommondatastorage.googleapis.com\u002Fgtv-videos-bucket\u002Fsample\u002FBigBuckBunny.mp4\" type=\"video\u002Fmp4\">\n        Your browser does not support the video tag.\n    \u003C\u002Fvideo>\n\u003C\u002Ftemplate>\n",[442,13408,13409,13417,13476,13508,13513,13521],{"__ignoreMap":265},[989,13410,13411,13413,13415],{"class":991,"line":992},[989,13412,996],{"class":995},[989,13414,1000],{"class":999},[989,13416,1003],{"class":995},[989,13418,13419,13421,13424,13427,13429,13431,13434,13436,13438,13440,13442,13445,13447,13450,13453,13455,13457,13460,13462,13465,13467,13469,13472,13474],{"class":991,"line":269},[989,13420,1014],{"class":995},[989,13422,13423],{"class":999},"video",[989,13425,13426],{"class":1020}," ref",[989,13428,1024],{"class":995},[989,13430,1027],{"class":995},[989,13432,13433],{"class":1030},"my-video",[989,13435,1027],{"class":995},[989,13437,10232],{"class":1020},[989,13439,1024],{"class":995},[989,13441,1027],{"class":995},[989,13443,13444],{"class":1030},"width: 100%",[989,13446,1027],{"class":995},[989,13448,13449],{"class":1020}," controls",[989,13451,13452],{"class":1020}," @play",[989,13454,1024],{"class":995},[989,13456,1027],{"class":995},[989,13458,13459],{"class":1030},"onPlay",[989,13461,1027],{"class":995},[989,13463,13464],{"class":1020}," @pause",[989,13466,1024],{"class":995},[989,13468,1027],{"class":995},[989,13470,13471],{"class":1030},"onPause",[989,13473,1027],{"class":995},[989,13475,1003],{"class":995},[989,13477,13478,13480,13483,13485,13487,13489,13492,13494,13497,13499,13501,13504,13506],{"class":991,"line":274},[989,13479,1051],{"class":995},[989,13481,13482],{"class":999},"source",[989,13484,1328],{"class":1020},[989,13486,1024],{"class":995},[989,13488,1027],{"class":995},[989,13490,13491],{"class":1030},"http:\u002F\u002Fcommondatastorage.googleapis.com\u002Fgtv-videos-bucket\u002Fsample\u002FBigBuckBunny.mp4",[989,13493,1027],{"class":995},[989,13495,13496],{"class":1020}," type",[989,13498,1024],{"class":995},[989,13500,1027],{"class":995},[989,13502,13503],{"class":1030},"video\u002Fmp4",[989,13505,1027],{"class":995},[989,13507,1003],{"class":995},[989,13509,13510],{"class":991,"line":266},[989,13511,13512],{"class":1060},"        Your browser does not support the video tag.\n",[989,13514,13515,13517,13519],{"class":991,"line":1071},[989,13516,1110],{"class":995},[989,13518,13423],{"class":999},[989,13520,1003],{"class":995},[989,13522,13523,13525,13527],{"class":991,"line":1089},[989,13524,1064],{"class":995},[989,13526,1000],{"class":999},[989,13528,1003],{"class":995},[15,13530,13531],{},"A few things of importance to note here:",[27,13533,13534,13548,13554,13567],{},[30,13535,13536,13539,13540,13543,13544,13547],{},[442,13537,13538],{},"ref"," is Vue's replacement for ",[442,13541,13542],{},"document.getElementById()",". This is copied to each instance of the component, meaning we can call ",[442,13545,13546],{},"this.$refs['my-video']"," to access the video element, and this doesn't break when duplicating the widget multiple times in Dashboard.",[30,13549,13550,13553],{},[442,13551,13552],{},"style=\"\""," is required here to ensure the video fills the group\u002Fwrapper that it is contained within.",[30,13555,13556,13559,13560,13563,13564,13566],{},[442,13557,13558],{},"@play="," is Vue's way of binding onto the standard ",[442,13561,13562],{},"onplay"," event listener available on HTML video players. We'll define the ",[442,13565,13459],{}," method in the next section.",[30,13568,13569,13572,13573,13575],{},[442,13570,13571],{},"@pause="," is our event listener for when the video is paused by the user. As with ",[442,13574,13459],{},", we'll define this shortly.",[15,13577,13578,13579,13582],{},"With ",[333,13580,13581],{},"just"," the above defined, we end up with a standard video player rendered:",[15,13584,13585],{},[239,13586],{"alt":13587,"src":13588},"HTML5 Video Player rendered in Dashboard","\u002Fblog\u002F2023\u002F12\u002Fimages\u002Fdashboard-video-1.png",[82,13590,13592],{"id":13591},"defining-the-behaviors-vuejs","Defining the Behaviors (VueJS)",[15,13594,13595],{},"Now we begin to build our Vue component. Referring back to our earlier set of features, we'll tackle these one at a time.",[892,13597,13599],{"id":13598},"_1-emitting-events-to-node-red-on-playpause","1. Emitting Events to Node-RED on Play\u002FPause",[15,13601,13602,13603,13606,13607,2355,13609,13611,13612,9361,13615,13618],{},"We can use ",[442,13604,13605],{},"methods"," to define our ",[442,13608,13459],{},[442,13610,13471],{}," functions that are called ",[442,13613,13614],{},"@play",[442,13616,13617],{},"@pause"," respectively.",[981,13620,13622],{"className":983,"code":13621,"language":985,"meta":265,"style":265},"\u003Cscript>\nexport default {\n  name: 'MyVideoPlayer',\n  methods: {\n    capture (eventType) {\n        \u002F\u002F let's define our own function that can be called onPlay\u002FonPause\n        \u002F\u002F this prevents duplicated code across the two methods\n\n        \u002F\u002F get the Video's DOM element\n        const video = this.$refs['my-video']\n\n        \u002F\u002F send a msg to Node-RED using built-in \"send\" fcn\n        this.send({\n            \u002F\u002F specify which action is taking place\n            event: eventType,\n            \u002F\u002F use Vue's $refs to get the video's currentTime\n            time: video.currentTime\n        })\n    },\n    onPlay () {\n        this.capture('play')\n    },\n    onPause () {\n        this.capture('pause')\n    }\n  }\n}\n\u003C\u002Fscript>\n",[442,13623,13624,13632,13640,13655,13663,13677,13682,13687,13691,13696,13720,13724,13729,13739,13744,13756,13761,13775,13782,13786,13795,13813,13817,13826,13843,13847,13851,13855],{"__ignoreMap":265},[989,13625,13626,13628,13630],{"class":991,"line":992},[989,13627,996],{"class":995},[989,13629,1137],{"class":999},[989,13631,1003],{"class":995},[989,13633,13634,13636,13638],{"class":991,"line":269},[989,13635,1592],{"class":1145},[989,13637,1149],{"class":1145},[989,13639,1152],{"class":995},[989,13641,13642,13644,13646,13648,13651,13653],{"class":991,"line":274},[989,13643,13180],{"class":999},[989,13645,1180],{"class":995},[989,13647,7202],{"class":995},[989,13649,13650],{"class":1030},"MyVideoPlayer",[989,13652,4352],{"class":995},[989,13654,3187],{"class":995},[989,13656,13657,13659,13661],{"class":991,"line":266},[989,13658,11298],{"class":999},[989,13660,1180],{"class":995},[989,13662,1152],{"class":995},[989,13664,13665,13668,13670,13673,13675],{"class":991,"line":1071},[989,13666,13667],{"class":999},"    capture",[989,13669,9801],{"class":995},[989,13671,13672],{"class":8514},"eventType",[989,13674,3883],{"class":995},[989,13676,1152],{"class":995},[989,13678,13679],{"class":991,"line":1089},[989,13680,13681],{"class":1008},"        \u002F\u002F let's define our own function that can be called onPlay\u002FonPause\n",[989,13683,13684],{"class":991,"line":1107},[989,13685,13686],{"class":1008},"        \u002F\u002F this prevents duplicated code across the two methods\n",[989,13688,13689],{"class":991,"line":1117},[989,13690,1129],{"emptyLinePlaceholder":295},[989,13692,13693],{"class":991,"line":1126},[989,13694,13695],{"class":1008},"        \u002F\u002F get the Video's DOM element\n",[989,13697,13698,13700,13703,13705,13707,13710,13712,13714,13716,13718],{"class":991,"line":1132},[989,13699,11360],{"class":1020},[989,13701,13702],{"class":1060}," video",[989,13704,1223],{"class":995},[989,13706,6845],{"class":995},[989,13708,13709],{"class":1060},"$refs",[989,13711,4629],{"class":999},[989,13713,4352],{"class":995},[989,13715,13433],{"class":1030},[989,13717,4352],{"class":995},[989,13719,7297],{"class":999},[989,13721,13722],{"class":991,"line":1142},[989,13723,1129],{"emptyLinePlaceholder":295},[989,13725,13726],{"class":991,"line":1155},[989,13727,13728],{"class":1008},"        \u002F\u002F send a msg to Node-RED using built-in \"send\" fcn\n",[989,13730,13731,13733,13735,13737],{"class":991,"line":1166},[989,13732,1674],{"class":995},[989,13734,6833],{"class":4345},[989,13736,4349],{"class":999},[989,13738,4390],{"class":995},[989,13740,13741],{"class":991,"line":1174},[989,13742,13743],{"class":1008},"            \u002F\u002F specify which action is taking place\n",[989,13745,13746,13749,13751,13754],{"class":991,"line":1187},[989,13747,13748],{"class":999},"            event",[989,13750,1180],{"class":995},[989,13752,13753],{"class":1060}," eventType",[989,13755,3187],{"class":995},[989,13757,13758],{"class":991,"line":1193},[989,13759,13760],{"class":1008},"            \u002F\u002F use Vue's $refs to get the video's currentTime\n",[989,13762,13763,13766,13768,13770,13772],{"class":991,"line":1199},[989,13764,13765],{"class":999},"            time",[989,13767,1180],{"class":995},[989,13769,13702],{"class":1060},[989,13771,437],{"class":995},[989,13773,13774],{"class":1060},"currentTime\n",[989,13776,13777,13780],{"class":991,"line":1209},[989,13778,13779],{"class":995},"        }",[989,13781,6852],{"class":999},[989,13783,13784],{"class":991,"line":1215},[989,13785,1636],{"class":995},[989,13787,13788,13791,13793],{"class":991,"line":1229},[989,13789,13790],{"class":999},"    onPlay",[989,13792,6824],{"class":995},[989,13794,1152],{"class":995},[989,13796,13797,13799,13802,13804,13806,13809,13811],{"class":991,"line":1235},[989,13798,1674],{"class":995},[989,13800,13801],{"class":4345},"capture",[989,13803,4349],{"class":999},[989,13805,4352],{"class":995},[989,13807,13808],{"class":1030},"play",[989,13810,4352],{"class":995},[989,13812,6852],{"class":999},[989,13814,13815],{"class":991,"line":1241},[989,13816,1636],{"class":995},[989,13818,13819,13822,13824],{"class":991,"line":1653},[989,13820,13821],{"class":999},"    onPause",[989,13823,6824],{"class":995},[989,13825,1152],{"class":995},[989,13827,13828,13830,13832,13834,13836,13839,13841],{"class":991,"line":1659},[989,13829,1674],{"class":995},[989,13831,13801],{"class":4345},[989,13833,4349],{"class":999},[989,13835,4352],{"class":995},[989,13837,13838],{"class":1030},"pause",[989,13840,4352],{"class":995},[989,13842,6852],{"class":999},[989,13844,13845],{"class":991,"line":1665},[989,13846,1238],{"class":995},[989,13848,13849],{"class":991,"line":1671},[989,13850,5265],{"class":995},[989,13852,13853],{"class":991,"line":1690},[989,13854,1698],{"class":995},[989,13856,13857,13859,13861],{"class":991,"line":1695},[989,13858,1064],{"class":995},[989,13860,1137],{"class":999},[989,13862,1003],{"class":995},[15,13864,13865,13866,13868,13869,13872],{},"With this functionality in place, we can wire the ",[442,13867,869],{}," node to a ",[442,13870,13871],{},"debug"," node, and see the following when we play\u002Fpause the video:",[15,13874,13875],{},[239,13876],{"alt":13877,"src":13878},"Example debug output when our custom build video player is played\u002Fpaused","\u002Fblog\u002F2023\u002F12\u002Fimages\u002Fdashboard-video-2.png",[892,13880,13882],{"id":13881},"_2-remote-control-of-playpause-from-node-red","2. Remote control of play\u002Fpause from Node-RED",[15,13884,13885,13886,13888,13889,13891,13892,13895,13896,2355,13899,13902,13903,13906],{},"We can use the built-in ",[442,13887,11445],{}," variable to listen for incoming events from Node-RED. When Dashboard 2.0's nodes receive a ",[442,13890,3103],{}," inside Node-RED, they send a ",[442,13893,13894],{},"msg-input:\u003Cnode-id>"," event to the Dashboard client. We can listen for this event and then call the ",[442,13897,13898],{},"play()",[442,13900,13901],{},"pause()"," methods on the video element, depending on any properties of that message, in this case, the ",[442,13904,13905],{},"msg.payload.event"," value.",[981,13908,13910],{"className":983,"code":13909,"language":985,"meta":265,"style":265},"\u003Cscript>\nexport default {\n  name: 'MyVideoPlayer',\n  methods: {\n    \u002F\u002F ...\n  },\n  mounted () {\n    \u002F\u002F listen for incoming msg's from Node-RED\n    \u002F\u002F note our topic is \"msg-input\" + the node's unique ID\n    this.$socket.on('msg-input:' + this.id, (msg) => {\n        \u002F\u002F get the Video's DOM element\n        const video = this.$refs['my-video']\n\n        \u002F\u002F if the event is \"play\", call the video's play() method\n        if (msg.payload?.event === 'play') {\n            video.play()\n        }\n\n        \u002F\u002F if the event is \"pause\", call the video's pause() method\n        if (msg.payload?.event === 'pause') {\n            video.pause()\n        }\n    })\n  },\n  unmounted () {\n    \u002F\u002F make sure we remove our listeners when the widget is destroyed\n    this.$socket.off(`msg-input:${this.id}`)\n  }\n}\n\u003C\u002Fscript>\n",[442,13911,13912,13920,13928,13942,13950,13955,13959,13967,13972,13977,14014,14018,14040,14044,14049,14079,14091,14095,14099,14104,14132,14142,14146,14152,14156,14164,14169,14199,14203,14207],{"__ignoreMap":265},[989,13913,13914,13916,13918],{"class":991,"line":992},[989,13915,996],{"class":995},[989,13917,1137],{"class":999},[989,13919,1003],{"class":995},[989,13921,13922,13924,13926],{"class":991,"line":269},[989,13923,1592],{"class":1145},[989,13925,1149],{"class":1145},[989,13927,1152],{"class":995},[989,13929,13930,13932,13934,13936,13938,13940],{"class":991,"line":274},[989,13931,13180],{"class":999},[989,13933,1180],{"class":995},[989,13935,7202],{"class":995},[989,13937,13650],{"class":1030},[989,13939,4352],{"class":995},[989,13941,3187],{"class":995},[989,13943,13944,13946,13948],{"class":991,"line":266},[989,13945,11298],{"class":999},[989,13947,1180],{"class":995},[989,13949,1152],{"class":995},[989,13951,13952],{"class":991,"line":1071},[989,13953,13954],{"class":1008},"    \u002F\u002F ...\n",[989,13956,13957],{"class":991,"line":1089},[989,13958,11293],{"class":995},[989,13960,13961,13963,13965],{"class":991,"line":1107},[989,13962,11425],{"class":999},[989,13964,6824],{"class":995},[989,13966,1152],{"class":995},[989,13968,13969],{"class":991,"line":1117},[989,13970,13971],{"class":1008},"    \u002F\u002F listen for incoming msg's from Node-RED\n",[989,13973,13974],{"class":991,"line":1126},[989,13975,13976],{"class":1008},"    \u002F\u002F note our topic is \"msg-input\" + the node's unique ID\n",[989,13978,13979,13982,13984,13986,13988,13990,13992,13994,13996,13998,14000,14002,14004,14006,14008,14010,14012],{"class":991,"line":1132},[989,13980,13981],{"class":995},"    this.",[989,13983,11445],{"class":1060},[989,13985,437],{"class":995},[989,13987,11450],{"class":4345},[989,13989,4349],{"class":999},[989,13991,4352],{"class":995},[989,13993,11457],{"class":1030},[989,13995,4352],{"class":995},[989,13997,11462],{"class":995},[989,13999,6845],{"class":995},[989,14001,7835],{"class":1060},[989,14003,4459],{"class":995},[989,14005,9801],{"class":995},[989,14007,3103],{"class":8514},[989,14009,3883],{"class":995},[989,14011,8520],{"class":1020},[989,14013,1152],{"class":995},[989,14015,14016],{"class":991,"line":1142},[989,14017,13695],{"class":1008},[989,14019,14020,14022,14024,14026,14028,14030,14032,14034,14036,14038],{"class":991,"line":1155},[989,14021,11360],{"class":1020},[989,14023,13702],{"class":1060},[989,14025,1223],{"class":995},[989,14027,6845],{"class":995},[989,14029,13709],{"class":1060},[989,14031,4629],{"class":999},[989,14033,4352],{"class":995},[989,14035,13433],{"class":1030},[989,14037,4352],{"class":995},[989,14039,7297],{"class":999},[989,14041,14042],{"class":991,"line":1166},[989,14043,1129],{"emptyLinePlaceholder":295},[989,14045,14046],{"class":991,"line":1174},[989,14047,14048],{"class":1008},"        \u002F\u002F if the event is \"play\", call the video's play() method\n",[989,14050,14051,14054,14056,14058,14060,14062,14065,14067,14069,14071,14073,14075,14077],{"class":991,"line":1187},[989,14052,14053],{"class":1145},"        if",[989,14055,9801],{"class":999},[989,14057,3103],{"class":1060},[989,14059,437],{"class":995},[989,14061,4402],{"class":1060},[989,14063,14064],{"class":995},"?.",[989,14066,10582],{"class":1060},[989,14068,10787],{"class":995},[989,14070,7202],{"class":995},[989,14072,13808],{"class":1030},[989,14074,4352],{"class":995},[989,14076,4359],{"class":999},[989,14078,4390],{"class":995},[989,14080,14081,14084,14086,14088],{"class":991,"line":1193},[989,14082,14083],{"class":1060},"            video",[989,14085,437],{"class":995},[989,14087,13808],{"class":4345},[989,14089,14090],{"class":999},"()\n",[989,14092,14093],{"class":991,"line":1199},[989,14094,1232],{"class":995},[989,14096,14097],{"class":991,"line":1209},[989,14098,1129],{"emptyLinePlaceholder":295},[989,14100,14101],{"class":991,"line":1215},[989,14102,14103],{"class":1008},"        \u002F\u002F if the event is \"pause\", call the video's pause() method\n",[989,14105,14106,14108,14110,14112,14114,14116,14118,14120,14122,14124,14126,14128,14130],{"class":991,"line":1229},[989,14107,14053],{"class":1145},[989,14109,9801],{"class":999},[989,14111,3103],{"class":1060},[989,14113,437],{"class":995},[989,14115,4402],{"class":1060},[989,14117,14064],{"class":995},[989,14119,10582],{"class":1060},[989,14121,10787],{"class":995},[989,14123,7202],{"class":995},[989,14125,13838],{"class":1030},[989,14127,4352],{"class":995},[989,14129,4359],{"class":999},[989,14131,4390],{"class":995},[989,14133,14134,14136,14138,14140],{"class":991,"line":1235},[989,14135,14083],{"class":1060},[989,14137,437],{"class":995},[989,14139,13838],{"class":4345},[989,14141,14090],{"class":999},[989,14143,14144],{"class":991,"line":1241},[989,14145,1232],{"class":995},[989,14147,14148,14150],{"class":991,"line":1653},[989,14149,11530],{"class":995},[989,14151,6852],{"class":999},[989,14153,14154],{"class":991,"line":1659},[989,14155,11293],{"class":995},[989,14157,14158,14160,14162],{"class":991,"line":1665},[989,14159,13230],{"class":999},[989,14161,6824],{"class":995},[989,14163,1152],{"class":995},[989,14165,14166],{"class":991,"line":1671},[989,14167,14168],{"class":1008},"    \u002F\u002F make sure we remove our listeners when the widget is destroyed\n",[989,14170,14171,14173,14175,14177,14180,14182,14185,14187,14190,14192,14194,14197],{"class":991,"line":1690},[989,14172,13981],{"class":995},[989,14174,11445],{"class":1060},[989,14176,437],{"class":995},[989,14178,14179],{"class":4345},"off",[989,14181,4349],{"class":999},[989,14183,14184],{"class":995},"`",[989,14186,11457],{"class":1030},[989,14188,14189],{"class":995},"${",[989,14191,7341],{"class":995},[989,14193,7835],{"class":1060},[989,14195,14196],{"class":995},"}`",[989,14198,6852],{"class":999},[989,14200,14201],{"class":991,"line":1695},[989,14202,5265],{"class":995},[989,14204,14205],{"class":991,"line":1701},[989,14206,1698],{"class":995},[989,14208,14209,14211,14213],{"class":991,"line":1710},[989,14210,1064],{"class":995},[989,14212,1137],{"class":999},[989,14214,1003],{"class":995},[892,14216,14218],{"id":14217},"_3-seeking-to-a-specific-point-in-the-video-from-within-node-red","3. Seeking to a specific point in the video from within Node-RED",[15,14220,4974,14221,14224],{},[442,14222,14223],{},"on('msg-input')"," listener in place, we can now extend our handler to handle seeking to a specific point in the video.",[981,14226,14228],{"className":983,"code":14227,"language":985,"meta":265,"style":265},"\u003Cscript>\nexport default {\n  name: 'MyVideoPlayer',\n  methods: {\n    \u002F\u002F ...\n  },\n  mounted () {\n    \u002F\u002F ...\n    this.$socket.on('msg-input:' + this.id, (msg) => {\n        \u002F\u002F ... other handlers\n\n        \u002F\u002F if the event is \"seek\", call the video's currentTime() method\n        if (msg.payload?.event === 'seek') {\n            video.currentTime = msg.payload.currentTime\n        }\n    })\n  },\n  unmounted () {\n    \u002F\u002F ...\n  }\n}\n\u003C\u002Fscript>\n",[442,14229,14230,14238,14246,14260,14268,14272,14276,14284,14288,14324,14329,14333,14338,14367,14388,14392,14398,14402,14410,14414,14418,14422],{"__ignoreMap":265},[989,14231,14232,14234,14236],{"class":991,"line":992},[989,14233,996],{"class":995},[989,14235,1137],{"class":999},[989,14237,1003],{"class":995},[989,14239,14240,14242,14244],{"class":991,"line":269},[989,14241,1592],{"class":1145},[989,14243,1149],{"class":1145},[989,14245,1152],{"class":995},[989,14247,14248,14250,14252,14254,14256,14258],{"class":991,"line":274},[989,14249,13180],{"class":999},[989,14251,1180],{"class":995},[989,14253,7202],{"class":995},[989,14255,13650],{"class":1030},[989,14257,4352],{"class":995},[989,14259,3187],{"class":995},[989,14261,14262,14264,14266],{"class":991,"line":266},[989,14263,11298],{"class":999},[989,14265,1180],{"class":995},[989,14267,1152],{"class":995},[989,14269,14270],{"class":991,"line":1071},[989,14271,13954],{"class":1008},[989,14273,14274],{"class":991,"line":1089},[989,14275,11293],{"class":995},[989,14277,14278,14280,14282],{"class":991,"line":1107},[989,14279,11425],{"class":999},[989,14281,6824],{"class":995},[989,14283,1152],{"class":995},[989,14285,14286],{"class":991,"line":1117},[989,14287,13954],{"class":1008},[989,14289,14290,14292,14294,14296,14298,14300,14302,14304,14306,14308,14310,14312,14314,14316,14318,14320,14322],{"class":991,"line":1126},[989,14291,13981],{"class":995},[989,14293,11445],{"class":1060},[989,14295,437],{"class":995},[989,14297,11450],{"class":4345},[989,14299,4349],{"class":999},[989,14301,4352],{"class":995},[989,14303,11457],{"class":1030},[989,14305,4352],{"class":995},[989,14307,11462],{"class":995},[989,14309,6845],{"class":995},[989,14311,7835],{"class":1060},[989,14313,4459],{"class":995},[989,14315,9801],{"class":995},[989,14317,3103],{"class":8514},[989,14319,3883],{"class":995},[989,14321,8520],{"class":1020},[989,14323,1152],{"class":995},[989,14325,14326],{"class":991,"line":1132},[989,14327,14328],{"class":1008},"        \u002F\u002F ... other handlers\n",[989,14330,14331],{"class":991,"line":1142},[989,14332,1129],{"emptyLinePlaceholder":295},[989,14334,14335],{"class":991,"line":1155},[989,14336,14337],{"class":1008},"        \u002F\u002F if the event is \"seek\", call the video's currentTime() method\n",[989,14339,14340,14342,14344,14346,14348,14350,14352,14354,14356,14358,14361,14363,14365],{"class":991,"line":1166},[989,14341,14053],{"class":1145},[989,14343,9801],{"class":999},[989,14345,3103],{"class":1060},[989,14347,437],{"class":995},[989,14349,4402],{"class":1060},[989,14351,14064],{"class":995},[989,14353,10582],{"class":1060},[989,14355,10787],{"class":995},[989,14357,7202],{"class":995},[989,14359,14360],{"class":1030},"seek",[989,14362,4352],{"class":995},[989,14364,4359],{"class":999},[989,14366,4390],{"class":995},[989,14368,14369,14371,14373,14376,14378,14380,14382,14384,14386],{"class":991,"line":1174},[989,14370,14083],{"class":1060},[989,14372,437],{"class":995},[989,14374,14375],{"class":1060},"currentTime",[989,14377,1223],{"class":995},[989,14379,4510],{"class":1060},[989,14381,437],{"class":995},[989,14383,4402],{"class":1060},[989,14385,437],{"class":995},[989,14387,13774],{"class":1060},[989,14389,14390],{"class":991,"line":1187},[989,14391,1232],{"class":995},[989,14393,14394,14396],{"class":991,"line":1193},[989,14395,11530],{"class":995},[989,14397,6852],{"class":999},[989,14399,14400],{"class":991,"line":1199},[989,14401,11293],{"class":995},[989,14403,14404,14406,14408],{"class":991,"line":1209},[989,14405,13230],{"class":999},[989,14407,6824],{"class":995},[989,14409,1152],{"class":995},[989,14411,14412],{"class":991,"line":1215},[989,14413,13954],{"class":1008},[989,14415,14416],{"class":991,"line":1229},[989,14417,5265],{"class":995},[989,14419,14420],{"class":991,"line":1235},[989,14421,1698],{"class":995},[989,14423,14424,14426,14428],{"class":991,"line":1241},[989,14425,1064],{"class":995},[989,14427,1137],{"class":999},[989,14429,1003],{"class":995},[15,14431,14432],{},"and with that, we now have a Dashboard 2.0 widget to display a video, that can be controlled from Node-RED, and logs details of user activity back into Node-RED.",[15,14434,14435],{},"Other features available with the UI Template are detailed in the online documentation, and include:",[27,14437,14438,14445],{},[30,14439,14440],{},[256,14441,14444],{"href":14442,"rel":14443},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#loading-external-dependencies",[402],"Loading External Dependencies",[30,14446,14447],{},[256,14448,14451],{"href":14449,"rel":14450},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-template.html#writing-raw-javascript",[402],"Running raw JavaScript",[19,14453,8036],{"id":8035},[15,14455,14456,14457,14460],{},"You can also read the more comprehensive release notes for ",[442,14458,14459],{},"v0.10.0"," release here:",[27,14462,14463],{},[30,14464,14465],{},[256,14466,14469],{"href":14467,"rel":14468},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.10.0",[402],"0.10.0 Release Notes",[15,14471,14472,14473,437],{},"As always, thanks for reading and your interest in Dashboard 2.0. If you have any feature requests, bugs\u002Fcomplaints or general feedback, please do reach out, and raise issues on our relevant ",[256,14474,8068],{"href":8066,"rel":14475},[402],[27,14477,14478,14483],{},[30,14479,14480],{},[256,14481,8047],{"href":448,"rel":14482},[402],[30,14484,14485],{},[256,14486,8053],{"href":2553,"rel":14487},[402],[1720,14489,14490],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":265,"searchDepth":266,"depth":266,"links":14492},[14493,14496,14504],{"id":13118,"depth":269,"text":13119,"children":14494},[14495],{"id":13341,"depth":274,"text":13342},{"id":13395,"depth":269,"text":13396,"children":14497},[14498,14499],{"id":13399,"depth":274,"text":13400},{"id":13591,"depth":274,"text":13592,"children":14500},[14501,14502,14503],{"id":13598,"depth":266,"text":13599},{"id":13881,"depth":266,"text":13882},{"id":14217,"depth":266,"text":14218},{"id":8035,"depth":269,"text":8036},"2023-12-07","Delve into the possibilities of Dashboard 2.0's new UI Templates with a comprehensive tutorial on building a custom video player.","\u002Fblog\u002F2023\u002F12\u002Fimages\u002Ftile-dashboard-0-10-0.png",{"excerpt":14509},{"type":12,"value":14510},[14511,14517],[15,14512,13059,14513,13063,14515,13066],{},[333,14514,13062],{},[442,14516,869],{},[27,14518,14519,14521,14525],{},[30,14520,13071],{},[30,14522,13074,14523,13078],{},[442,14524,13077],{},[30,14526,13081,14527,13078],{},[442,14528,13077],{},"\u002Fblog\u002F2023\u002F12\u002Fdashboard-0-10-0",{"title":13053,"description":14506},{"loc":14529},"blog\u002F2023\u002F12\u002Fdashboard-0-10-0","We've just released the latest version of Dashboard 2.0, with a fully featured UI Templates node which now allows for full definition of a Vue component, external JS dependencies and CSS.",[487,8099,8100,8101,303],"pFYofgu7OtLAMd_JKnY0DZ51wfEtz4nB2vUmHlVNWhs",{"id":14537,"title":14538,"authors":14539,"body":14541,"cta":3,"date":14751,"description":14752,"extension":287,"image":14753,"lastUpdated":3,"meta":14754,"navigation":295,"path":14759,"seo":14760,"sitemap":14761,"stem":14762,"subtitle":14763,"tags":14764,"tldr":3,"video":3,"__hash__":14765},"blog\u002Fblog\u002F2023\u002F11\u002Fdashboard-0-8-0.md","Overhauling the Dashboard 2.0 Build Pipeline",[309,14540],"pez-cuckow",{"type":12,"value":14542,"toc":14745},[14543,14546,14560,14567,14575,14579,14586,14607,14614,14620,14628,14632,14642,14645,14651,14662,14669,14673,14676,14713,14716,14725,14727,14733],[15,14544,14545],{},"As a developer, sometimes you have to hold up your hands and realise something you've spent two weeks building needs to be thrown away and restarted.",[15,14547,14548,14549,14553,14554,14559],{},"Having shipped the ",[256,14550,14552],{"href":14551},"\u002Fblog\u002F2023\u002F10\u002Fdashboard-integrations\u002F","third-party widget support for Dashboard 2.0"," in line with Dashboard 1.0's approach, we then had the ",[256,14555,14558],{"href":14556,"rel":14557},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F307",[402],"feedback"," that the way Dashboard 1.0 did things really wasn't good, and asking us to consider re-building the process to make the developer experience of working with Dashboard 2.0 far more seamless.",[15,14561,14562,14563,14566],{},"So, that's exactly what we've done with the ",[442,14564,14565],{},"0.8.0"," release, amongst a few other things.",[228,14568,13104,14569,13109,14571,13112,14573,437],{"style":13103},[442,14570,13108],{"style":13107},[442,14572,3669],{"style":13107},[442,14574,13115],{"style":13107},[19,14576,14578],{"id":14577},"migrating-our-build-pipeline","Migrating our Build Pipeline",[15,14580,14581,14582,14585],{},"Without getting ",[333,14583,14584],{},"too"," technical, as part of this work in supporting third-party widgets, we overhauled our build pipeline for Dashboard 2.0. This pipeline is responsible for taking our source code, and compiling it into a format that then gets deployed by Node-RED when running Dashboard.",[15,14587,14588,14589,14594,14595,14600,14601,14606],{},"Previously, we used ",[333,14590,14591],{},[33,14592,14593],{},"Webpack",", but now, we've switched over to ",[333,14596,14597],{},[33,14598,14599],{},"Vite",". This is a newer build tool, and is much faster than Webpack. It's also what we've now updated out ",[256,14602,14605],{"href":14603,"rel":14604},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard-2-ui-example",[402],"Example Node"," to use too.",[15,14608,14609,14610,14613],{},"So now, when working with a third-party widget, Vite builds up all of your code, wraps it into a single ",[442,14611,14612],{},"umd.js"," file, and Node-RED then serves that file up for Dashboard 2.0 to load in.",[15,14615,14616],{},[239,14617],{"alt":14618,"src":14619},"Vite Build Process","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fdashboard-build.png",[15,14621,14622,14623,14627],{},"We've also re-written our ",[256,14624,14626],{"href":11728,"rel":14625},[402],"\"Building Third Party Widgets\""," guide to reflect this change.",[19,14629,14631],{"id":14630},"debugging-dashboard","Debugging Dashboard",[15,14633,14634,14635,14637,14638,14641],{},"A new feature we've added in ",[442,14636,14565],{}," is also for those developing Dashboard's core and third-party widgets. You can now navigate to ",[442,14639,14640],{},"\u002Fdashboard\u002F_debug"," to explore the full configuration that Dashboard receives from Node-RED.",[15,14643,14644],{},"This is particularly useful when you're trying to debug why a widget isn't loading, showing the correct data, or generally isn't behaving as you expect.",[15,14646,14647],{},[239,14648],{"alt":14649,"src":14650},"Dashboard's Debug View","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fdebug-view.png",[15,14652,14653,14654,14657,14658,14661],{},"Note in the above example, where we can see that the ",[442,14655,14656],{},"ui-dropdown"," has had it's options overriden by ",[442,14659,14660],{},"msg.options"," on injection.",[15,14663,14664,14665],{},"You can read more about the debugging view ",[256,14666,436],{"href":14667,"rel":14668},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fwidgets\u002Fdebugging.html",[402],[19,14670,14672],{"id":14671},"what-else-is-new-in-080","What else is new in 0.8.0?",[15,14674,14675],{},"Whilst we focussed this article on the build pipeline overhaul, changes to third-party wdgets and debugging Dashboard, we did also squeeze quite a lot more into the 0.8.0 releases too with plenty other fixes and improvements:",[27,14677,14678,14685,14692,14699,14706],{},[30,14679,14680],{},[256,14681,14684],{"href":14682,"rel":14683},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F345",[402],"Dynamic setting of msg.options for UI Dropdown",[30,14686,14687],{},[256,14688,14691],{"href":14689,"rel":14690},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F346",[402],"\"Date\" type for UI Text Input",[30,14693,14694],{},[256,14695,14698],{"href":14696,"rel":14697},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F365",[402],"Finer grain controls of Text Input event emissions",[30,14700,14701],{},[256,14702,14705],{"href":14703,"rel":14704},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F367",[402],"Control over when UI Slider emits events",[30,14707,14708],{},[256,14709,14712],{"href":14710,"rel":14711},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F364",[402],"Improved documentation for Bar Charts",[15,14714,14715],{},"You can also read the more comprehensive release notes for the release here:",[27,14717,14718],{},[30,14719,14720],{},[256,14721,14724],{"href":14722,"rel":14723},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.8.0",[402],"0.8.0 Release Notes",[19,14726,8036],{"id":8035},[15,14728,14729,14730,437],{},"As always, thanks for reading and your interested in Dashboard 2.0. If you have any feature requests, bugs\u002Fcomplaints or general feedback, please do reach out, and raise issues on our relevant ",[256,14731,8068],{"href":8066,"rel":14732},[402],[27,14734,14735,14740],{},[30,14736,14737],{},[256,14738,8047],{"href":448,"rel":14739},[402],[30,14741,14742],{},[256,14743,8053],{"href":2553,"rel":14744},[402],{"title":265,"searchDepth":266,"depth":266,"links":14746},[14747,14748,14749,14750],{"id":14577,"depth":269,"text":14578},{"id":14630,"depth":269,"text":14631},{"id":14671,"depth":269,"text":14672},{"id":8035,"depth":269,"text":8036},"2023-11-23","Explore the latest updates in Dashboard 2.0 with the 0.8.0 release, featuring an overhauled build pipeline, improved debugging capabilities, and more.","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fdashboard-0-8-0.png",{"excerpt":14755},{"type":12,"value":14756},[14757],[15,14758,14545],{},"\u002Fblog\u002F2023\u002F11\u002Fdashboard-0-8-0",{"title":14538,"description":14752},{"loc":14759},"blog\u002F2023\u002F11\u002Fdashboard-0-8-0","A month or so ago, we released the Third-Party widget support for Dashboard 2.0, but having seen the feedback, we missed the beat, so we've built it again!",[487,8099,8100,8101,303],"XKtaP6Lj7REJ386OQmkvAg_66ojpS4zP8x38fRnFbUM",{"id":14767,"title":14768,"authors":14769,"body":14771,"cta":3,"date":14915,"description":14916,"extension":287,"image":14917,"lastUpdated":3,"meta":14918,"navigation":295,"path":14923,"seo":14924,"sitemap":14925,"stem":14926,"subtitle":14927,"tags":14928,"tldr":3,"video":3,"__hash__":14929},"blog\u002Fblog\u002F2023\u002F11\u002Fdashboard-2.0-user-tracking.md","Tracking Who Has Opened a Dashboard",[14770],"ben-hardill",{"type":12,"value":14772,"toc":14910},[14773,14776,14780,14783,14786,14789,14792,14795,14799,14802,14808,14811,14829,14832,14898,14901,14905,14908],[15,14774,14775],{},"As we continue to add features to the Node-RED Dashboard v2 one feature request that came in was to track which users had visited a Dashboard. Multi user support for the Dashboard is on the backlog but this could be solved with the parts that are currently available.",[19,14777,14779],{"id":14778},"flowfuse-authentication","FlowFuse Authentication",[15,14781,14782],{},"One of the features we offer on FlowFuse is the ability to protect HTTP endpoints and Dashboards using the same FlowFuse user authentication that protects access to the FlowFuse Application and the Node-RED instances.",[15,14784,14785],{},"We even offer a specific RBAC 'viewer' role that just allows access to these endpoints but not the FlowFuse application.",[15,14787,14788],{},"FlowFuse authentication can be enabled from the Instance Settings page on the Security tab",[15,14790,14791],{},"This can be used to secure access to a Dashboard hosted in a Node-RED Instance. At the moment the Dashboard while protected by this authentication, it is not aware of which user is accessing it.",[15,14793,14794],{},"But if we include an element in the Dashboard loaded via a HTTP-in\u002FHTTP-response node we gain access to details of the authenticated user.",[19,14796,14798],{"id":14797},"implementation","Implementation",[15,14800,14801],{},"First we will create a HTTP-in\u002FHTTP-response pair to serve up a single pixel SVG image. I chose SVG as it doesn't require creating a binary image file to load.",[15,14803,14804,14805,14807],{},"The following flow snippet includes both the HTTP-in\u002FHTTP-response nodes and a change node to set the ",[442,14806,1350],{}," to the SVG content and to set the HTTP headers to include the correct mime type.",[15,14809,14810],{},"There is also a second change node which extracts the user information.",[15,14812,5928,14813,5411],{},[989,14814,14815,14816,14818,14819,14822,14823,14826,14827,4425],{},"{\"id\":\"7f22dc81d8192d4d\",\"type\":\"http in\",\"z\":\"98c8d7ea66149291\",\"name\":\"\",\"url\":\"\u002Ftracker\",\"method\":\"get\",\"upload\":false,\"swaggerDoc\":\"\",\"x\":210,\"y\":460,\"wires\":[[\"7d36739c02cd04ec\",\"5f4647c97917cce1\"]]},{\"id\":\"58fd30516a077e29\",\"type\":\"http response\",\"z\":\"98c8d7ea66149291\",\"name\":\"\",\"statusCode\":\"\",\"headers\":{},\"x\":630,\"y\":460,\"wires\":",[989,14817],{},"},{\"id\":\"7d36739c02cd04ec\",\"type\":\"change\",\"z\":\"98c8d7ea66149291\",\"name\":\"\",\"rules\":",[989,14820,14821],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"\u003Csvg width=\"1\" height=\"1\"> \u003Crect width=\"1\" height=\"1\" style=\"fill:rgb(255,255,255);stroke-width:3;stroke:rgb(0,0,0)\" \u002F> Sorry, your browser does not support inline SVG.\",\"tot\":\"str\"},{\"t\":\"set\",\"p\":\"headers\",\"pt\":\"msg\",\"to\":\"{\"Content-Type\":\"image\u002Fsvg+xml\"}\",\"tot\":\"json\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":420,\"y\":460,\"wires\":[[\"58fd30516a077e29\"]]},{\"id\":\"5f4647c97917cce1\",\"type\":\"change\",\"z\":\"98c8d7ea66149291\",\"name\":\"\",\"rules\":",[989,14824,14825],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"req.session.user\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":420,\"y\":520,\"wires\":[[\"ddc02b4e9c30c807\"]]},{\"id\":\"ddc02b4e9c30c807\",\"type\":\"debug\",\"z\":\"98c8d7ea66149291\",\"name\":\"debug 2\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":600,\"y\":520,\"wires\":",[989,14828],{},[15,14830,14831],{},"Next we need to add the SVG to the Dashboard, this can be done by adding a Template node with the following HTML content.",[981,14833,14835],{"className":983,"code":14834,"language":985,"meta":265,"style":265},"\u003Cdiv>\n    \u003Cobject data=\"\u002Ftracker\" height=\"1\" width=\"1\">\u003C\u002Fobject>\n\u003C\u002Fdiv>\n",[442,14836,14837,14845,14890],{"__ignoreMap":265},[989,14838,14839,14841,14843],{"class":991,"line":992},[989,14840,996],{"class":995},[989,14842,228],{"class":999},[989,14844,1003],{"class":995},[989,14846,14847,14849,14852,14854,14856,14858,14861,14863,14865,14867,14869,14872,14874,14876,14878,14880,14882,14884,14886,14888],{"class":991,"line":269},[989,14848,1014],{"class":995},[989,14850,14851],{"class":999},"object",[989,14853,10411],{"class":1020},[989,14855,1024],{"class":995},[989,14857,1027],{"class":995},[989,14859,14860],{"class":1030},"\u002Ftracker",[989,14862,1027],{"class":995},[989,14864,1316],{"class":1020},[989,14866,1024],{"class":995},[989,14868,1027],{"class":995},[989,14870,14871],{"class":1030},"1",[989,14873,1027],{"class":995},[989,14875,9010],{"class":1020},[989,14877,1024],{"class":995},[989,14879,1027],{"class":995},[989,14881,14871],{"class":1030},[989,14883,1027],{"class":995},[989,14885,1340],{"class":995},[989,14887,14851],{"class":999},[989,14889,1003],{"class":995},[989,14891,14892,14894,14896],{"class":991,"line":274},[989,14893,1064],{"class":995},[989,14895,228],{"class":999},[989,14897,1003],{"class":995},[15,14899,14900],{},"This will load the image every time the Dashboard page loads and hence trigger the earlier flow allowing the user to be logged.",[19,14902,14904],{"id":14903},"linking-to-sso-users","Linking to SSO Users",[15,14906,14907],{},"With the release of FlowFuse v1.14.0 the session object will also include the users email address which is the shared identifier between FlowFuse and the SSO system. This will allow the logging to use a single unified identifier.",[1720,14909,13025],{},{"title":265,"searchDepth":266,"depth":266,"links":14911},[14912,14913,14914],{"id":14778,"depth":269,"text":14779},{"id":14797,"depth":269,"text":14798},{"id":14903,"depth":269,"text":14904},"2023-11-13","Learn how to track user visits to your Node-RED Dashboard v2 using FlowFuse Authentication. Secure access and identify users accessing your dashboard with this implementation.","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fdashboard-user-flow.png",{"excerpt":14919},{"type":12,"value":14920},[14921],[15,14922,14775],{},"\u002Fblog\u002F2023\u002F11\u002Fdashboard-2.0-user-tracking",{"title":14768,"description":14916},{"loc":14923},"blog\u002F2023\u002F11\u002Fdashboard-2.0-user-tracking","Using FlowFuse Authentication Audit Dashboard v2 Access",[3010,303,302],"RA1SYFFb9kjmMqpG73yW9koy71uD353RY5q5kEj8RG8",{"id":14931,"title":14932,"authors":14933,"body":14934,"cta":3,"date":15606,"description":15607,"extension":287,"image":15608,"lastUpdated":3,"meta":15609,"navigation":295,"path":15614,"seo":15615,"sitemap":15616,"stem":15617,"subtitle":15618,"tags":15619,"tldr":3,"video":3,"__hash__":15620},"blog\u002Fblog\u002F2023\u002F11\u002Fdashboard-0-7.md","Chart Improvements & Migrating to Dashboard 2.0",[309],{"type":12,"value":14935,"toc":15589},[14936,14939,14943,14960,14963,14967,14977,14986,14990,14993,15010,15013,15028,15032,15045,15048,15052,15059,15066,15072,15075,15078,15081,15085,15094,15097,15101,15105,15108,15123,15126,15247,15260,15266,15269,15274,15278,15292,15303,15306,15474,15481,15486,15489,15494,15497,15501,15504,15541,15544,15567,15569,15574,15586],[15,14937,14938],{},"It's been a little while since we've done an update, since we last posted we've moved into the 0.7.x releases for Dashboard 2.0. With these we're making big strides in improving the UX for charting your data, as well as starting to focus on migration paths from Dashboard 1.0 to 2.0.",[19,14940,14942],{"id":14941},"package-name-changes","Package Name Changes",[15,14944,14945,14946,14949,14950,14954,14955,4750,14958,437],{},"Firstly a bit of news regarding the ",[442,14947,14948],{},"npm"," package we publish. Inline with our own ",[256,14951,14953],{"href":14952},"\u002Fblog\u002F2023\u002F08\u002Fflowforge-is-now-flowfuse","company name change",", we've had to update Dashboard 2.0's npm package, and so, we've changed from ",[442,14956,14957],{},"@flowforge\u002Fnode-red-dashboard",[442,14959,3669],{},[15,14961,14962],{},"In the short term, we'll be keeping @flowforge available on the Node-RED Palette Manager, but it will be removed soon, and the associated NPM Package will be put into a \"deprecated\" mode.",[82,14964,14966],{"id":14965},"npm-package-migration","NPM Package Migration",[15,14968,14969,14970,4750,14973,14976],{},"Unfortunately, this migration from ",[442,14971,14972],{},"@flowforge\u002F",[442,14974,14975],{},"@flowfuse\u002F"," requires a little bit of manual work, and isn't as easy as just clicking \"update\" in the Node-RED Editor.",[15,14978,14979,14980,14982,14983,14985],{},"In any case, there is no need to update your flow in this migration, you'll just need to uninstall ",[442,14981,14957],{}," and install ",[442,14984,3669],{}," instead.",[892,14987,14989],{"id":14988},"running-locally","Running Locally",[15,14991,14992],{},"If you're running Node-RED locally, or in your own infrastructure, you'll need to manually uninstall the old package:",[981,14994,14998],{"className":14995,"code":14996,"language":14997,"meta":265,"style":265},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","npm uninstall @flowforge\u002Fnode-red-dashboard\n","bash",[442,14999,15000],{"__ignoreMap":265},[989,15001,15002,15004,15007],{"class":991,"line":992},[989,15003,14948],{"class":1736},[989,15005,15006],{"class":1030}," uninstall",[989,15008,15009],{"class":1030}," @flowforge\u002Fnode-red-dashboard\n",[15,15011,15012],{},"and re-install the new one:",[981,15014,15016],{"className":14995,"code":15015,"language":14997,"meta":265,"style":265},"npm install @flowfuse\u002Fnode-red-dashboard\n",[442,15017,15018],{"__ignoreMap":265},[989,15019,15020,15022,15025],{"class":991,"line":992},[989,15021,14948],{"class":1736},[989,15023,15024],{"class":1030}," install",[989,15026,15027],{"class":1030}," @flowfuse\u002Fnode-red-dashboard\n",[892,15029,15031],{"id":15030},"running-in-flowfuse","Running in FlowFuse",[15,15033,15034,15035,15037,15038,15040,15041,15044],{},"Navigate to your Instance > Settings > Palette, and then change the ",[442,15036,14957],{}," entry to ",[442,15039,3669],{}," (the latest version as of this post is ",[442,15042,15043],{},"0.7.2",").",[15,15046,15047],{},"Restart your instance, and the new package will automatically install.",[19,15049,15051],{"id":15050},"dashboard-10-to-20-migration-guide","Dashboard 1.0 to 2.0 Migration Guide",[15,15053,15054,15055,437],{},"As part of our mission to ensure a smooth transition from Dashboard 1.0 to Dashboard 2.0, we have published a first draft of a ",[256,15056,3730],{"href":15057,"rel":15058},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fmigration.html",[402],[15,15060,15061,15062,15065],{},"As a starting point, we have comprehesively covered the Dashboard 1.0 widgets and their associated properties. We've then detailed which properties are already supported, which have partial support, and where appropriate, we do not support and ",[333,15063,15064],{},"why"," (most of the time, it's just because we haven't got round to it yet!)",[15,15067,15068],{},[239,15069],{"alt":15070,"src":15071},"Migration Guide Snippet","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fmigration-guide-snippet.png",[15,15073,15074],{},"We fully appreciate that the migration path is not yet complete, and we that we are missing some features and properties, but please know that we are working hard to ensure that as many of the features from Dashboard 1.0 are available in Dashboard 2.0. We will be updating this guide as we progress.",[15,15076,15077],{},"We will also be adding \"event\" and \"dynamic properties\" sections to the guide, to detail how you can update and control elements via runtime messages (e.g. dynamically change the label of a button), and how this differs (if at all) from Dashboard 1.0.",[15,15079,15080],{},"Whilst we aren't quite there yet, this guide offers a comprehensive breakdown on our progress in backporting all of the properties from Dashboard 1.0",[82,15082,15084],{"id":15083},"automated-script","Automated Script",[15,15086,15087,15088,15093],{},"An ambitious plan that we have is to also provide a ",[256,15089,15092],{"href":15090,"rel":15091},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F261",[402],"Migration Script",". Any feedback, ideas or concerns are most welcome as comments on the issue.",[15,15095,15096],{},"Whilst this will never provide 100% perfect migration, we hope to be able to provide a script that can be run against your flows to automatically convert as much as possible from Dashboard 1.0 to 2.0. In most cases, as you can see in the Migration guide, we match most properties 1:1, so this should do a lot of the heavy lifting for you.",[19,15098,15100],{"id":15099},"updates-to-ui-chart","Updates to UI Chart",[82,15102,15104],{"id":15103},"key-mapping","Key Mapping",[15,15106,15107],{},"One of the core purposes of Node-RED Dashboard has always been to provide low-code access to charting your data. With the 0.7.x releases we've made some big improvements to the UI Chart node to make it easier to use and more powerful.",[15,15109,15110,15111,15114,15115,15118,15119,15122],{},"In Dashboard 1.0, it was common place to have to regularly re-format your own data into ",[442,15112,15113],{},"{x, y}"," structure to be chart-friendly. In ",[442,15116,15117],{},"0.7.0"," we've introduced the concept of ",[33,15120,15121],{},"key mapping",", where you can specify which keys in your data object should be used for the x and y axes. This means you can now pass in data in the format you want to use, and the chart will do the rest.",[15,15124,15125],{},"For example, when rendering a chart of our weekly npm downloads, we have a data structure:",[981,15127,15129],{"className":3156,"code":15128,"language":3158,"meta":265,"style":265},"[{\n    \"day\": \"YYYY-MM-DD\",\n    \"downloads\": 128\n}, {\n    \"day\": \"YYYY-MM-DD\",\n    \"downloads\": 256\n}, {\n    \"day\": \"YYYY-MM-DD\",\n    \"downloads\": 512\n}]\n",[442,15130,15131,15135,15155,15169,15175,15193,15206,15212,15230,15243],{"__ignoreMap":265},[989,15132,15133],{"class":991,"line":992},[989,15134,3165],{"class":995},[989,15136,15137,15139,15142,15144,15146,15148,15151,15153],{"class":991,"line":269},[989,15138,3170],{"class":995},[989,15140,15141],{"class":1020},"day",[989,15143,1027],{"class":995},[989,15145,1180],{"class":995},[989,15147,4414],{"class":995},[989,15149,15150],{"class":1030},"YYYY-MM-DD",[989,15152,1027],{"class":995},[989,15154,3187],{"class":995},[989,15156,15157,15159,15162,15164,15166],{"class":991,"line":274},[989,15158,3170],{"class":995},[989,15160,15161],{"class":1020},"downloads",[989,15163,1027],{"class":995},[989,15165,1180],{"class":995},[989,15167,15168],{"class":1777}," 128\n",[989,15170,15171,15173],{"class":991,"line":266},[989,15172,3337],{"class":995},[989,15174,1152],{"class":995},[989,15176,15177,15179,15181,15183,15185,15187,15189,15191],{"class":991,"line":1071},[989,15178,3170],{"class":995},[989,15180,15141],{"class":1020},[989,15182,1027],{"class":995},[989,15184,1180],{"class":995},[989,15186,4414],{"class":995},[989,15188,15150],{"class":1030},[989,15190,1027],{"class":995},[989,15192,3187],{"class":995},[989,15194,15195,15197,15199,15201,15203],{"class":991,"line":1089},[989,15196,3170],{"class":995},[989,15198,15161],{"class":1020},[989,15200,1027],{"class":995},[989,15202,1180],{"class":995},[989,15204,15205],{"class":1777}," 256\n",[989,15207,15208,15210],{"class":991,"line":1107},[989,15209,3337],{"class":995},[989,15211,1152],{"class":995},[989,15213,15214,15216,15218,15220,15222,15224,15226,15228],{"class":991,"line":1117},[989,15215,3170],{"class":995},[989,15217,15141],{"class":1020},[989,15219,1027],{"class":995},[989,15221,1180],{"class":995},[989,15223,4414],{"class":995},[989,15225,15150],{"class":1030},[989,15227,1027],{"class":995},[989,15229,3187],{"class":995},[989,15231,15232,15234,15236,15238,15240],{"class":991,"line":1126},[989,15233,3170],{"class":995},[989,15235,15161],{"class":1020},[989,15237,1027],{"class":995},[989,15239,1180],{"class":995},[989,15241,15242],{"class":1777}," 512\n",[989,15244,15245],{"class":991,"line":1132},[989,15246,3348],{"class":995},[15,15248,15249,15250,15252,15253,15256,15257,15259],{},"Rather than having to pipe this into a ",[442,15251,4307],{}," node and re-map the properties to ",[442,15254,15255],{},"{ x, y }",", we can now use the ",[442,15258,4930],{},"'s key mapping properties:",[15,15261,15262],{},[239,15263],{"alt":15264,"src":15265},"ui-chart-key-mapping","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fui-chart-keymap-properties.png",[15,15267,15268],{},"Resulting in the following chart:",[15,15270,15271],{},[239,15272],{"alt":15264,"src":15273},"\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fui-chart-mapping.png",[82,15275,15277],{"id":15276},"multiple-lines","Multiple Lines",[15,15279,15280,15281,15284,15285,15287,15288,15291],{},"Note above, another new option has been added to define ",[333,15282,15283],{},"\"Series\"",". In Dashboard 1.0 this was fixed as ",[442,15286,3449],{}," at all times, and defined which line\u002Fseries data points rendered too. Now, this is configurable, and can even be set as a ",[442,15289,15290],{},"key:"," type too, whereby each data point being treated individually, and grouped based on a given key\u002Fproperty.",[15,15293,15294,15295,15298,15299,15302],{},"Another great new feature here is the type ",[442,15296,15297],{},"JSON"," for this property. We can provide a ",[333,15300,15301],{},"list"," of series labels, and the chart will render each value from a single data point as separate lines.",[15,15304,15305],{},"For example, if we consider the data:",[981,15307,15309],{"className":3156,"code":15308,"language":3158,"meta":265,"style":265},"[{\n    \"day\": \"2023-10-23\",\n    \"temperature\": 28,\n    \"humidity\": 16\n}, {\n    \"day\": \"2023-10-24\",\n    \"temperature\": 26,\n    \"humidity\": 19\n}, {\n    \"day\": \"2023-10-25\",\n    \"temperature\": 27,\n    \"humidity\": 24\n}]\n",[442,15310,15311,15315,15334,15350,15364,15370,15389,15404,15417,15423,15442,15457,15470],{"__ignoreMap":265},[989,15312,15313],{"class":991,"line":992},[989,15314,3165],{"class":995},[989,15316,15317,15319,15321,15323,15325,15327,15330,15332],{"class":991,"line":269},[989,15318,3170],{"class":995},[989,15320,15141],{"class":1020},[989,15322,1027],{"class":995},[989,15324,1180],{"class":995},[989,15326,4414],{"class":995},[989,15328,15329],{"class":1030},"2023-10-23",[989,15331,1027],{"class":995},[989,15333,3187],{"class":995},[989,15335,15336,15338,15341,15343,15345,15348],{"class":991,"line":274},[989,15337,3170],{"class":995},[989,15339,15340],{"class":1020},"temperature",[989,15342,1027],{"class":995},[989,15344,1180],{"class":995},[989,15346,15347],{"class":1777}," 28",[989,15349,3187],{"class":995},[989,15351,15352,15354,15357,15359,15361],{"class":991,"line":266},[989,15353,3170],{"class":995},[989,15355,15356],{"class":1020},"humidity",[989,15358,1027],{"class":995},[989,15360,1180],{"class":995},[989,15362,15363],{"class":1777}," 16\n",[989,15365,15366,15368],{"class":991,"line":1071},[989,15367,3337],{"class":995},[989,15369,1152],{"class":995},[989,15371,15372,15374,15376,15378,15380,15382,15385,15387],{"class":991,"line":1089},[989,15373,3170],{"class":995},[989,15375,15141],{"class":1020},[989,15377,1027],{"class":995},[989,15379,1180],{"class":995},[989,15381,4414],{"class":995},[989,15383,15384],{"class":1030},"2023-10-24",[989,15386,1027],{"class":995},[989,15388,3187],{"class":995},[989,15390,15391,15393,15395,15397,15399,15402],{"class":991,"line":1107},[989,15392,3170],{"class":995},[989,15394,15340],{"class":1020},[989,15396,1027],{"class":995},[989,15398,1180],{"class":995},[989,15400,15401],{"class":1777}," 26",[989,15403,3187],{"class":995},[989,15405,15406,15408,15410,15412,15414],{"class":991,"line":1117},[989,15407,3170],{"class":995},[989,15409,15356],{"class":1020},[989,15411,1027],{"class":995},[989,15413,1180],{"class":995},[989,15415,15416],{"class":1777}," 19\n",[989,15418,15419,15421],{"class":991,"line":1126},[989,15420,3337],{"class":995},[989,15422,1152],{"class":995},[989,15424,15425,15427,15429,15431,15433,15435,15438,15440],{"class":991,"line":1132},[989,15426,3170],{"class":995},[989,15428,15141],{"class":1020},[989,15430,1027],{"class":995},[989,15432,1180],{"class":995},[989,15434,4414],{"class":995},[989,15436,15437],{"class":1030},"2023-10-25",[989,15439,1027],{"class":995},[989,15441,3187],{"class":995},[989,15443,15444,15446,15448,15450,15452,15455],{"class":991,"line":1142},[989,15445,3170],{"class":995},[989,15447,15340],{"class":1020},[989,15449,1027],{"class":995},[989,15451,1180],{"class":995},[989,15453,15454],{"class":1777}," 27",[989,15456,3187],{"class":995},[989,15458,15459,15461,15463,15465,15467],{"class":991,"line":1155},[989,15460,3170],{"class":995},[989,15462,15356],{"class":1020},[989,15464,1027],{"class":995},[989,15466,1180],{"class":995},[989,15468,15469],{"class":1777}," 24\n",[989,15471,15472],{"class":991,"line":1166},[989,15473,3348],{"class":995},[15,15475,15476,15477,15480],{},"We can provide a series: ",[442,15478,15479],{},"[\"temperature\", \"humidity\"]"," like so:",[15,15482,15483],{},[239,15484],{"alt":15264,"src":15485},"\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fui-chart-series-property.png",[15,15487,15488],{},"Which would result in the following plot:",[15,15490,15491],{},[239,15492],{"alt":15264,"src":15493},"\u002Fblog\u002F2023\u002F11\u002Fimages\u002Fui-chart-multipoint.png",[15,15495,15496],{},"We appreciate this offers a new way of working with data in Dashboard, but hopefully, once you've tried it, you'll find it much easier to work with, and see the value it brings when working with your own data sets.",[19,15498,15500],{"id":15499},"what-else-is-new-in-07x","What else is new in 0.7.x?",[15,15502,15503],{},"Whilst we focussed this article on the migration paths and new UI Chart features, we did also squeeze quite a lot more into the 0.7.x releases too with plenty other fixes and improvements:",[27,15505,15506,15513,15520,15527,15534],{},[30,15507,15508],{},[256,15509,15512],{"href":15510,"rel":15511},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F279",[402],"Re-architecture of Server-side State Management",[30,15514,15515],{},[256,15516,15519],{"href":15517,"rel":15518},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F327",[402],"Y Axis Min\u002FMax Options",[30,15521,15522],{},[256,15523,15526],{"href":15524,"rel":15525},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F320",[402],"\"Focus\" button for widgets added to Sidebar",[30,15528,15529],{},[256,15530,15533],{"href":15531,"rel":15532},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F310",[402],"No more \"blue screen\" and improved error reporting",[30,15535,15536],{},[256,15537,15540],{"href":15538,"rel":15539},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fpull\u002F301",[402],"Better route handling",[15,15542,15543],{},"You can also read the more comprehensive release notes for each release here:",[27,15545,15546,15553,15560],{},[30,15547,15548],{},[256,15549,15552],{"href":15550,"rel":15551},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.7.0",[402],"0.7.0 Release Notes",[30,15554,15555],{},[256,15556,15559],{"href":15557,"rel":15558},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.7.1",[402],"0.7.1 Release Notes",[30,15561,15562],{},[256,15563,15566],{"href":15564,"rel":15565},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.7.2",[402],"0.7.2 Release Notes",[19,15568,8036],{"id":8035},[15,15570,14729,15571,437],{},[256,15572,8068],{"href":8066,"rel":15573},[402],[27,15575,15576,15581],{},[30,15577,15578],{},[256,15579,8047],{"href":448,"rel":15580},[402],[30,15582,15583],{},[256,15584,8053],{"href":2553,"rel":15585},[402],[1720,15587,15588],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":265,"searchDepth":266,"depth":266,"links":15590},[15591,15597,15600,15604,15605],{"id":14941,"depth":269,"text":14942,"children":15592},[15593],{"id":14965,"depth":274,"text":14966,"children":15594},[15595,15596],{"id":14988,"depth":266,"text":14989},{"id":15030,"depth":266,"text":15031},{"id":15050,"depth":269,"text":15051,"children":15598},[15599],{"id":15083,"depth":274,"text":15084},{"id":15099,"depth":269,"text":15100,"children":15601},[15602,15603],{"id":15103,"depth":274,"text":15104},{"id":15276,"depth":274,"text":15277},{"id":15499,"depth":269,"text":15500},{"id":8035,"depth":269,"text":8036},"2023-11-09","Discover significant chart enhancements and migration guidance in Dashboard 2.0's 0.7.x releases. Stay informed on project updates.","\u002Fblog\u002F2023\u002F11\u002Fimages\u002Ftile-blog-dashboard-migration.png",{"excerpt":15610},{"type":12,"value":15611},[15612],[15,15613,14938],{},"\u002Fblog\u002F2023\u002F11\u002Fdashboard-0-7",{"title":14932,"description":15607},{"loc":15614},"blog\u002F2023\u002F11\u002Fdashboard-0-7","With the 0.7.x Releases of Dashboard 2.0, we've made big improvements to Charts, generated a migration guide, and much more...",[487,8099,8100,8101,303],"T4o8ZOuxQftTMkhLO8Cxf8btELrymkTWhQQHIfhxRiM",{"id":15622,"title":15623,"authors":15624,"body":15625,"cta":3,"date":15790,"description":15791,"extension":287,"image":15792,"lastUpdated":3,"meta":15793,"navigation":295,"path":15798,"seo":15799,"sitemap":15800,"stem":15801,"subtitle":15802,"tags":15803,"tldr":3,"video":3,"__hash__":15804},"blog\u002Fblog\u002F2023\u002F10\u002Fdashboard-integrations.md","Integrate your own widgets with Dashboard 2.0",[309],{"type":12,"value":15626,"toc":15784},[15627,15630,15640,15643,15649,15655,15667,15670,15720,15726,15730,15733,15754,15758,15767,15772],[15,15628,15629],{},"With a new release, comes new features for Dashboard 2.0, and the focus of this release has been on improving the developer experience for those building third-party widgets for Dashboard 2.0.",[15,15631,15632,15633,3553,15636,15639],{},"Dashboard 1.0 had a hugely popular ecosystem of third party widgets (e.g. ",[442,15634,15635],{},"ui-worldmap",[442,15637,15638],{},"ui-svg",") and something we've been keen to support is a platform where these widgets (and more) can be built and used within Dashboard 2.0 too.",[15,15641,15642],{},"Whilst we can't support the existing Dashboard 1.0 extensions directly (given that we're now VueJS-based, rather than AngularJS), we hope that the framework, documentation and this article, will help springboard the community to build new (and transfer over old) widgets for Dashboard 2.0.",[19,15644,15646,15647],{"id":15645},"building-from-ui-template","Building from ",[442,15648,869],{},[15,15650,15651,15652,15654],{},"As with Dashboard 1.0, we've utilised the flexibility of our ",[442,15653,869],{}," node here to enable third-party integrations.",[15,15656,15657,15658,15660,15661,15663,15664,15666],{},"If you're used the new ",[442,15659,869],{}," in Dashboard 2.0 already, you'll know that you can provide raw Vue (HTML) content and it'll render that into your Dashboard. In 0.6.0, we've added ",[333,15662,13062],{}," of new functionality to the guts of ",[442,15665,869],{},", which we can then extend with our third-party widgets.",[15,15668,15669],{},"This new functionality includes:",[27,15671,15672,15681,15690,15699,15705,15714],{},[30,15673,15674,15677,15678,437],{},[33,15675,15676],{},"Custom Dependencies"," - Injection of external widget dependencies (e.g. other JavaScript libraries) via ",[442,15679,15680],{},"\u003Chead>",[30,15682,15683,13315,15686,15689],{},[33,15684,15685],{},"On Input",[442,15687,15688],{},"onInput"," defines behaviour of the widget in Dashboard when it receives a message in Node-RED.",[30,15691,15692,13315,15695,15698],{},[33,15693,15694],{},"On Load",[442,15696,15697],{},"onMounted"," defines functionality when a widget first loads in Dashboard.",[30,15700,15701,15704],{},[33,15702,15703],{},"Custom Functions"," - Define general functions that can be called from within your widget at any point of your choosing",[30,15706,15707,15710,15711,15713],{},[33,15708,15709],{},"Extend Built-In Events"," - Our built in ",[442,15712,6833],{}," function can be called within your widget's template, and will send a message back to Node-RED, with any content of your choosing.",[30,15715,15716,15719],{},[33,15717,15718],{},"Custom SocketIO Event Handlers"," - If you want to extend the communication between Dashboard and Node-RED, you can emit your own SocketIO events from Dashboard, and have respective handlers for those events in Node-RED.",[15,15721,15722,15723,15725],{},"We also have plans to expose more of this new functionality to the ",[442,15724,869],{}," interface itself within Node-RED, but for now it's mostly available when developing third-party widgets.",[19,15727,15729],{"id":15728},"useful-resources","Useful Resources",[15,15731,15732],{},"If you're interested in building integrations, then we've also built a couple of resources to help you get started:",[27,15734,15735,15742],{},[30,15736,15737,15741],{},[256,15738,15740],{"href":11728,"rel":15739},[402],"Widget Development Guide"," - A guide for how to structure your own widgets, and",[30,15743,15744,15749,15750,15753],{},[256,15745,15748],{"href":15746,"rel":15747},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard-example-node",[402],"Example Integration (Repo)"," - We've open sourced a very simple ",[442,15751,15752],{},"ui-example"," node that demonstrates how you can build your own widget for Dashboard 2.0, that utilises all of the features highlighted above.",[19,15755,15757],{"id":15756},"what-else-is-new-in-060","What else is new in 0.6.0?",[15,15759,15760,15761,15766],{},"Whilst we focussed this article on the third-party integrations, we did also squeeze quite a lot more into the 0.6.0 release too with plenty ",[256,15762,15765],{"href":15763,"rel":15764},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.6.0",[402],"other fixes and improvements",", including the separation of the Dash oard 2.0 nodes into a new \"Dashboard 2\" category in the Node-RED palette.",[15,15768,14729,15769,437],{},[256,15770,8068],{"href":8066,"rel":15771},[402],[27,15773,15774,15779],{},[30,15775,15776],{},[256,15777,8047],{"href":448,"rel":15778},[402],[30,15780,15781],{},[256,15782,8053],{"href":2553,"rel":15783},[402],{"title":265,"searchDepth":266,"depth":266,"links":15785},[15786,15788,15789],{"id":15645,"depth":269,"text":15787},"Building from ui-template",{"id":15728,"depth":269,"text":15729},{"id":15756,"depth":269,"text":15757},"2023-10-06","Explore Dashboard 2.0's 0.6.0 Release with third-party widget support. Learn more, build your widgets, and join our community on GitHub.","\u002Fblog\u002F2023\u002F10\u002Fimages\u002Ftile-db-integration.png",{"excerpt":15794},{"type":12,"value":15795},[15796],[15,15797,15629],{},"\u002Fblog\u002F2023\u002F10\u002Fdashboard-integrations",{"title":15623,"description":15791},{"loc":15798},"blog\u002F2023\u002F10\u002Fdashboard-integrations","With the 0.6.0 Release of Dashboard 2.0, we now support third-party widget integration. Read more in this deep dive.",[487,8099,8100,8101,303],"o2c00-QjwDorb5KemQ3SEepc9GVlbWLyUmeev7Rc_Yc",{"id":15806,"title":12969,"authors":15807,"body":15809,"cta":3,"date":16080,"description":16081,"extension":287,"image":16082,"lastUpdated":3,"meta":16083,"navigation":295,"path":16090,"seo":16091,"sitemap":16092,"stem":16093,"subtitle":16081,"tags":16094,"tldr":3,"video":3,"__hash__":16095},"blog\u002Fblog\u002F2023\u002F10\u002Fcustom-vuetify-components-dashboard.md",[15808],"zeger-jan-van-de-weg",{"type":12,"value":15810,"toc":16072},[15811,15817,15825,15829,15842,15845,15895,15899,15912,15919,15923,15932,15942,15945,15992,16002,16017,16024,16028,16031,16045,16048,16070],[15,15812,15813,15814,15816],{},"Vuetify is a library of UI components using Vue. This saves the developers of\nDashboard 2.0 a lot of time, but it can also help you, the end-user. As Vuetify\nis now included, it can be used to include ",[333,15815,3867],{}," of their components. So in this\npost we're going to use a few of these to teach you how to use any of them.",[15,15818,15819,15820,15824],{},"Let's install the ",[256,15821,15823],{"href":3691,"rel":15822},[402],"Dashboard 2.0 package"," if you want to follow along. When that's done, let's figure\nout how to build custom components on dashboards.",[19,15826,15828],{"id":15827},"custom-components","Custom components",[15,15830,15831,15832,15835,15836,15841],{},"While going through the list of components on ",[256,15833,3591],{"href":8639,"rel":15834},[402],"\nthere's several examples that aren't natively implemented in Dashboard 2.0.\nOne example we'll use in a dashboard in this post is the\n",[256,15837,15840],{"href":15838,"rel":15839},"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fcomponents\u002Fprogress-circular\u002F",[402],"Progress circular"," to\nbuild a count down timer.",[15,15843,15844],{},"The documentation explains which elements one can change, in this case the size and\nwidth. Having set those to the values you'd want in your dashboard, the HTML is\ngenerated for you, in my case it's:",[981,15846,15848],{"className":983,"code":15847,"language":985,"meta":265,"style":265},"\u003Cv-progress-circular model-value=\"20\" :size=\"128\" :width=\"12\">\u003C\u002Fv-progress-circular>\n",[442,15849,15850],{"__ignoreMap":265},[989,15851,15852,15854,15856,15859,15861,15863,15865,15867,15869,15871,15873,15876,15878,15880,15882,15884,15887,15889,15891,15893],{"class":991,"line":992},[989,15853,996],{"class":995},[989,15855,12688],{"class":999},[989,15857,15858],{"class":1020}," model-value",[989,15860,1024],{"class":995},[989,15862,1027],{"class":995},[989,15864,12721],{"class":1030},[989,15866,1027],{"class":995},[989,15868,12703],{"class":1020},[989,15870,1024],{"class":995},[989,15872,1027],{"class":995},[989,15874,15875],{"class":1030},"128",[989,15877,1027],{"class":995},[989,15879,12726],{"class":1020},[989,15881,1024],{"class":995},[989,15883,1027],{"class":995},[989,15885,15886],{"class":1030},"12",[989,15888,1027],{"class":995},[989,15890,1340],{"class":995},[989,15892,12688],{"class":999},[989,15894,1003],{"class":995},[82,15896,15898],{"id":15897},"using-the-template-node","Using the template node",[15,15900,15901,15902,15906,15907,15911],{},"Like the ",[256,15903,15905],{"href":15904},"\u002Fnode-red\u002Fcore-nodes\u002Ftemplate","template core node",", the dashboard package\ncomes with ",[256,15908,15910],{"href":4980,"rel":15909},[402],"a template node of its own",".\nIf we take the HTML from the Vuetify docs pages and copy it in a template node\nthe spinner will show up on the dashboard.",[15,15913,15914],{},[239,15915],{"alt":15916,"src":15917,"title":15918},"\"Custom widget on Dashboard 2.0\"","\u002Fblog\u002F2023\u002F10\u002Fimages\u002Fcustom-element-dashboard.png","Custom widget on Dashboard 2.0",[19,15920,15922],{"id":15921},"dynamic-templates","Dynamic templates",[15,15924,15925,15926,15931],{},"While a custom element on a page is cool, and shows you can inject arbitrary HTML\non a Dashboard, it's even better if we could make the element dynamic. So let's\nstart with a first dynamic element. The quickest way to get that done is have\nan ",[256,15927,15929],{"href":15928},"\u002Fnode-red\u002Fcore-nodes\u002Finject",[442,15930,5584],{}," node output a random number every second.",[15,15933,15934,15935,15937,15938,15941],{},"So let's hook up an Inject, with ",[442,15936,1350],{},"'s output being a JSONata expression\n",[442,15939,15940],{},"$round($random() * 100)"," to generate a random number. And let's make sure it\nsends a message every second.",[15,15943,15944],{},"Then we need to update the template node to the following snippet:",[981,15946,15948],{"className":983,"code":15947,"language":985,"meta":265,"style":265},"\u003Cv-progress-circular v-model=\"msg.payload\" :size=\"128\" :width=\"12\">\u003C\u002Fv-progress-circular>\n",[442,15949,15950],{"__ignoreMap":265},[989,15951,15952,15954,15956,15958,15960,15962,15964,15966,15968,15970,15972,15974,15976,15978,15980,15982,15984,15986,15988,15990],{"class":991,"line":992},[989,15953,996],{"class":995},[989,15955,12688],{"class":999},[989,15957,6724],{"class":1020},[989,15959,1024],{"class":995},[989,15961,1027],{"class":995},[989,15963,1350],{"class":1030},[989,15965,1027],{"class":995},[989,15967,12703],{"class":1020},[989,15969,1024],{"class":995},[989,15971,1027],{"class":995},[989,15973,15875],{"class":1030},[989,15975,1027],{"class":995},[989,15977,12726],{"class":1020},[989,15979,1024],{"class":995},[989,15981,1027],{"class":995},[989,15983,15886],{"class":1030},[989,15985,1027],{"class":995},[989,15987,1340],{"class":995},[989,15989,12688],{"class":999},[989,15991,1003],{"class":995},[15,15993,15994,15995,15998,15999,16001],{},"The difference is subtle, but important. Instead of hard-coding the ",[442,15996,15997],{},"model-value","\nto 20, the tag has changed name and it's set to ",[442,16000,1350],{},". The latter makes\nthe value dynamic.",[15,16003,16004,16005,4750,16007,16010,16011,16016],{},"Changing ",[442,16006,15997],{},[442,16008,16009],{},"v-model"," is due to leaking implementation details of\nDashboard 2.0. It uses VueJS to provide, among other features, easy updating of\ncomponents. If components are dynamic, ",[333,16012,16013,16014],{},"always use ",[442,16015,16009],{},". This allows VueJS\nto pick up changes made dynamically.",[15,16018,16019],{},[239,16020],{"alt":16021,"src":16022,"title":16023},"\"Progress spinner, random values\"","\u002Fblog\u002F2023\u002F10\u002Fimages\u002Frandom-progress-element.gif","Progress spinner, random values",[82,16025,16027],{"id":16026},"finishing-the-count-down-timer","Finishing the count down timer",[15,16029,16030],{},"This is mostly a programmers job, but it's not hard, so let's get to it. A button\nwould be great to reset the timer, and for the sake of this post we can hardcode\nthe deadline to 1m from the button press.",[15,16032,16033,16034,16037,16038,16041,16042,16044],{},"When dragging in a button node, connect it to a ",[256,16035,4613],{"href":16036},"\u002Fnode-red\u002Fcore-nodes\u002Fchange","\nnode. In the change node set the flow variable ",[442,16039,16040],{},"flow.deadline"," to the timestamp. The\nInject node from earlier needs updating to inject the ",[442,16043,16040],{},". All that's\nleft is calculating how many seconds passed, and normalizing 60 seconds to the\nrange between 0-100.",[15,16046,16047],{},"The complete flow is:",[15,16049,5928,16050,5411],{},[989,16051,16052,16053,16055,16056,16058,16059,16061,16062,16065,16066,16069],{},"{\"id\":\"ce9bb8f74e3fc934\",\"type\":\"ui-template\",\"z\":\"24065a0aadb305e3\",\"group\":\"8fa772a709ae3316\",\"dashboard\":\"e5a3f4cdb11e5e3b\",\"page\":\"5bedf7f49d5a6037\",\"name\":\"Progress spinner\",\"order\":0,\"width\":0,\"height\":0,\"format\":\"\u003Cv-progress-circular v-model=\"msg.payload\" ",[6083,16054],{},"=\"128\" ",[12982,16057],{},"=\"12\">\\n\",\"storeOutMessages\":true,\"fwdInMessages\":true,\"resendOnRefresh\":true,\"templateScope\":\"local\",\"className\":\"\",\"x\":810,\"y\":80,\"wires\":[[]]},{\"id\":\"8f3e6631414aa096\",\"type\":\"inject\",\"z\":\"24065a0aadb305e3\",\"name\":\"Inject deadline\",\"props\":",[989,16060,5944],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":true,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"deadline\",\"payloadType\":\"flow\",\"x\":140,\"y\":80,\"wires\":[[\"293cd6f9d727fa02\"]]},{\"id\":\"bd9032719d24a53d\",\"type\":\"ui-button\",\"z\":\"24065a0aadb305e3\",\"group\":\"8fa772a709ae3316\",\"name\":\"\",\"label\":\"Reset\",\"order\":0,\"width\":0,\"height\":0,\"passthru\":false,\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"payload\":\"\",\"payloadType\":\"date\",\"topic\":\"deadline\",\"topicType\":\"msg\",\"x\":170,\"y\":140,\"wires\":[[\"61ef83d8b06ff626\"]]},{\"id\":\"61ef83d8b06ff626\",\"type\":\"change\",\"z\":\"24065a0aadb305e3\",\"name\":\"\",\"rules\":",[989,16063,16064],{},"{\"t\":\"set\",\"p\":\"deadline\",\"pt\":\"flow\",\"to\":\"\",\"tot\":\"date\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":350,\"y\":140,\"wires\":[[]]},{\"id\":\"293cd6f9d727fa02\",\"type\":\"change\",\"z\":\"24065a0aadb305e3\",\"name\":\"Secs since reset\",\"rules\":",[989,16067,16068],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"($millis() - msg.payload)\u002F1000\",\"tot\":\"jsonata\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":340,\"y\":80,\"wires\":[[\"9742da7e74fd3cd2\"]]},{\"id\":\"9742da7e74fd3cd2\",\"type\":\"range\",\"z\":\"24065a0aadb305e3\",\"minin\":\"0\",\"maxin\":\"60\",\"minout\":\"0\",\"maxout\":\"100\",\"action\":\"clamp\",\"round\":false,\"property\":\"payload\",\"name\":\"Seconds to percentages\",\"x\":570,\"y\":80,\"wires\":[[\"ce9bb8f74e3fc934\"]]},{\"id\":\"8fa772a709ae3316\",\"type\":\"ui-group\",\"name\":\"Group Name\",\"page\":\"5bedf7f49d5a6037\",\"width\":\"6\",\"height\":\"1\",\"order\":\"\",\"disp\":true},{\"id\":\"e5a3f4cdb11e5e3b\",\"type\":\"ui-base\",\"name\":\"UI Name\",\"path\":\"\u002Fdashboard\"},{\"id\":\"5bedf7f49d5a6037\",\"type\":\"ui-page\",\"name\":\"Page Name\",\"ui\":\"e5a3f4cdb11e5e3b\",\"path\":\"\u002F\",\"layout\":\"grid\",\"theme\":\"8240fbe7c09bc81c\"},{\"id\":\"8240fbe7c09bc81c\",\"type\":\"ui-theme\",\"name\":\"Theme Name\",\"colors\":{\"surface\":\"#ffffff\",\"primary\":\"#0094ce\",\"bgPage\":\"#eeeeee\",\"groupBg\":\"#ffffff\",\"groupOutline\":\"#cccccc\"}}",[1720,16071,13025],{},{"title":265,"searchDepth":266,"depth":266,"links":16073},[16074,16077],{"id":15827,"depth":269,"text":15828,"children":16075},[16076],{"id":15897,"depth":274,"text":15898},{"id":15921,"depth":269,"text":15922,"children":16078},[16079],{"id":16026,"depth":274,"text":16027},"2023-10-02","Expand your dashboard with the full collection of Vuetify components","blog\u002F2023\u002F10\u002Fimages\u002Ftile-blog-custom-vuetify-components-for-Dashboard.png",{"excerpt":16084},{"type":12,"value":16085},[16086],[15,16087,15813,16088,15816],{},[333,16089,3867],{},"\u002Fblog\u002F2023\u002F10\u002Fcustom-vuetify-components-dashboard",{"title":12969,"description":16081},{"loc":16090},"blog\u002F2023\u002F10\u002Fcustom-vuetify-components-dashboard",[487,2164,3010,303],"KO_LrX3IbVRXKJstHOLgJyEUJhvBN9uquLYkw9FdhGM",{"id":16097,"title":16098,"authors":16099,"body":16100,"cta":3,"date":16398,"description":16399,"extension":287,"image":16400,"lastUpdated":3,"meta":16401,"navigation":295,"path":16406,"seo":16407,"sitemap":16408,"stem":16409,"subtitle":16410,"tags":16411,"tldr":3,"video":3,"__hash__":16412},"blog\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout.md","Dynamic Markdown, Tables & Notebooks with Dashboard 2.0",[309],{"type":12,"value":16101,"toc":16392},[16102,16105,16108,16121,16139,16148,16152,16155,16181,16185,16191,16198,16201,16273,16293,16299,16302,16308,16310,16316,16325,16332,16338,16341,16346,16349,16354,16358,16372,16377,16389],[15,16103,16104],{},"Whilst we're still busy backporting through the existing Dashboard 1.0 features, we did want to highlight some new features we've built in Dashboard 2.0 released this week.",[15,16106,16107],{},"In our v0.4.0 release, we've introduced a new \"Notebook\" layout, alongside a new Table widget.",[15,16109,16110,16111,950,16116,15044],{},"The Notebook layout is designed to allow users to create Dashboards structured like a Notebook (most often seen with the likes of ",[256,16112,16115],{"href":16113,"rel":16114},"https:\u002F\u002Fjupyter.org\u002F",[402],"Jupyter Notebooks",[256,16117,16120],{"href":16118,"rel":16119},"https:\u002F\u002Fobservablehq.com\u002F",[402],"ObservableHQ",[15,16122,16123,16124,9801,16127,16131,16132,9801,16135,16138],{},"Here we will deepdive into the Notebook layout, and show how, alongside our new ",[33,16125,16126],{},"Markdown Node",[256,16128,6677],{"href":16129,"rel":16130},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-markdown.html",[402],"), ",[33,16133,16134],{},"Table Node",[256,16136,6677],{"href":3571,"rel":16137},[402],") and others, it's becoming easier to create dynamic and interactive Dashboards.",[15,16140,16141],{},[333,16142,16143,16144,437],{},"Note: If you're not familiar with Markdown, it's a simple markup language that allows you to format text. You can learn more about it ",[256,16145,436],{"href":16146,"rel":16147},"https:\u002F\u002Fwww.markdownguide.org\u002Fcheat-sheet\u002F",[402],[19,16149,16151],{"id":16150},"dashboard-hierarchy","Dashboard Hierarchy",[15,16153,16154],{},"As a quick introductory note ahead of our below guide, each Dashboard is structured accordingly:",[27,16156,16157,16163,16169,16175],{},[30,16158,16159,16162],{},[33,16160,16161],{},"Widget",": An individual functional block, e.g. button, chart, slider",[30,16164,16165,16168],{},[33,16166,16167],{},"Group",": A collection of widgets that render together",[30,16170,16171,16174],{},[33,16172,16173],{},"Page",": A single page\u002Ftab in your Dashboard. Each page can have it's own Layout, in this case we'll use \"Notebook\"",[30,16176,16177,16180],{},[33,16178,16179],{},"UI",": Contains a collection of pages, deployed from Node-RED, provides the basic side navigation to switch between Pages.",[19,16182,16184],{"id":16183},"building-a-notebook","Building a Notebook",[15,16186,16187],{},[239,16188],{"alt":16189,"src":16190},"Example Notebook created in Dashboard","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-example.png",[15,16192,16193,16194,16197],{},"To get started, drop your first widget (in this case, we'll add a ",[442,16195,16196],{},"ui-markdown",") onto the Node-RED canvas. This in turn will prompt us to create our first Group\u002FPage\u002FDashboard which we can name and configure accordingly.",[15,16199,16200],{},"Let's add the following Markdown to our first widget:",[981,16202,16205],{"className":16203,"code":16204,"language":287,"meta":265,"style":265},"language-md shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Markdown Content\n\nHere we can render dynamic Markdown content that is\neasily _styled_.\n\n{% raw %}\nWe can inject `msg.payload`. For example, here is a\ntimestamp updating every second: {{ msg.payload }}\n{% endraw %}\n",[442,16206,16207,16215,16219,16224,16241,16245,16250,16264,16269],{"__ignoreMap":265},[989,16208,16209,16212],{"class":991,"line":992},[989,16210,16211],{"class":995},"# ",[989,16213,16214],{"class":1736},"Markdown Content\n",[989,16216,16217],{"class":991,"line":269},[989,16218,1129],{"emptyLinePlaceholder":295},[989,16220,16221],{"class":991,"line":274},[989,16222,16223],{"class":1060},"Here we can render dynamic Markdown content that is\n",[989,16225,16226,16229,16232,16236,16238],{"class":991,"line":266},[989,16227,16228],{"class":1060},"easily ",[989,16230,16231],{"class":1145},"_",[989,16233,16235],{"class":16234},"s5tWE","styled",[989,16237,16231],{"class":1145},[989,16239,16240],{"class":1060},".\n",[989,16242,16243],{"class":991,"line":1071},[989,16244,1129],{"emptyLinePlaceholder":295},[989,16246,16247],{"class":991,"line":1089},[989,16248,16249],{"class":1060},"{% raw %}\n",[989,16251,16252,16255,16257,16259,16261],{"class":991,"line":1107},[989,16253,16254],{"class":1060},"We can inject ",[989,16256,14184],{"class":995},[989,16258,1350],{"class":1030},[989,16260,14184],{"class":995},[989,16262,16263],{"class":1060},". For example, here is a\n",[989,16265,16266],{"class":991,"line":1117},[989,16267,16268],{"class":1060},"timestamp updating every second: {{ msg.payload }}\n",[989,16270,16271],{"class":991,"line":1126},[989,16272,9049],{"class":1060},[15,16274,16275,16276,16278,16279,16282,16283,16285,16286,16289,16290,16292],{},"The joy of ",[442,16277,16196],{}," in Dashboard 2.0 is ",[333,16280,16281],{},"dynamic"," content, i.e. content that can be updated by passing messages to the ",[442,16284,16196],{}," node. We can wire an ",[442,16287,16288],{},"inject"," node, set it up to repeat every second, and connect it to ",[442,16291,16196],{},". Now, our Markdown content will automatically update show this value.",[15,16294,16295],{},[239,16296],{"alt":16297,"src":16298},"Screenshot to show how an inject node can drive content of a ui-markdown node","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-inject.png",[15,16300,16301],{},"Resulting in:",[15,16303,16304],{},[239,16305],{"alt":16306,"src":16307},"Dynamic markdown with an updating timestamp every 1 second","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fmd-timestamp.gif",[19,16309,9896],{"id":9895},[15,16311,16312,16313,16315],{},"Because the Notebook is ",[333,16314,13581],{}," a layout, we can still wire together any of the available widgets and existing nodes and display them accordingly.",[15,16317,16318,16319,16321,16322,16324],{},"Let's wire a ",[442,16320,9700],{},", HTTP Request, and ",[442,16323,4688],{}," node. When we click the button, it will perform the HTTP request, and then render the response in the table.",[15,16326,16327,16328,16331],{},"For this, we're going to use the Random Jokes API, and in particular, a call to ",[442,16329,16330],{},"https:\u002F\u002Fofficial-joke-api.appspot.com\u002Fjokes\u002Ften"," which will return 10 random jokes.",[15,16333,16334],{},[239,16335],{"alt":16336,"src":16337},"Screenshot showing a simple Button > HTTP Request > Table flow","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fgenerate-jokes-flow.png",[15,16339,16340],{},"We can also re-order the widgets on the page using the Dashboard 2.0 sidebar (as you could in Dashboard 1.0).",[15,16342,16343],{},[239,16344],{"alt":16297,"src":16345},"\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-order.png",[15,16347,16348],{},"The above effort results in the following output in our Notebook:",[15,16350,16351],{},[239,16352],{"alt":16297,"src":16353},"\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-jokes-table.png",[19,16355,16357],{"id":16356},"what-else-is-new-in-040","What else is new in 0.4.0?",[15,16359,16360,16361,16365,16366,16371],{},"The above demonstrates just a few of the new features in the 0.4.0 Release, but we've also added ",[256,16362,15765],{"href":16363,"rel":16364},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.4.0",[402],". In particular, I want to call out Steve's great work on implementing custom class injection, the first of our new ",[256,16367,16370],{"href":16368,"rel":16369},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fdynamic-properties.html",[402],"\"Dynamic Properties\"",", of which there will be more (e.g. visibility, disabled, etc.) to come.",[15,16373,14729,16374,437],{},[256,16375,8068],{"href":8066,"rel":16376},[402],[27,16378,16379,16384],{},[30,16380,16381],{},[256,16382,8047],{"href":448,"rel":16383},[402],[30,16385,16386],{},[256,16387,8053],{"href":2553,"rel":16388},[402],[1720,16390,16391],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s5tWE, html code.shiki .s5tWE{--shiki-light:#E53935;--shiki-light-font-style:italic;--shiki-default:#F07178;--shiki-default-font-style:italic;--shiki-dark:#F07178;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":265,"searchDepth":266,"depth":266,"links":16393},[16394,16395,16396,16397],{"id":16150,"depth":269,"text":16151},{"id":16183,"depth":269,"text":16184},{"id":9895,"depth":269,"text":9896},{"id":16356,"depth":269,"text":16357},"2023-09-06","Explore the latest features in Dashboard 2.0's v0.4.0 release, including \"Notebook\" layout, dynamic Markdown & Table widgets, and additional enhancements.","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-tile.png",{"excerpt":16402},{"type":12,"value":16403},[16404],[15,16405,16104],{},"\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout",{"title":16098,"description":16399},{"loc":16406},"blog\u002F2023\u002F09\u002Fdashboard-notebook-layout","A dive into the new features available in 0.4.0 - The \"Notebook\" Layout and new dynamic Markdown & Table widgets.",[487,8099,8100,8101,303],"6fU7RFKqryqT85Q9gudjfXS-bzzPLWcHsHsCgXVvfyo",{"id":16414,"title":16415,"authors":16416,"body":16417,"cta":3,"date":16616,"description":16617,"extension":287,"image":16618,"lastUpdated":3,"meta":16619,"navigation":295,"path":16624,"seo":16625,"sitemap":16626,"stem":16627,"subtitle":16617,"tags":16628,"tldr":3,"video":3,"__hash__":16629},"blog\u002Fblog\u002F2023\u002F08\u002Fdashboard-community-update.md","Dashboard 2.0 - Community Update",[309],{"type":12,"value":16418,"toc":16601},[16419,16422,16429,16435,16442,16446,16453,16463,16469,16472,16500,16507,16513,16516,16520,16524,16530,16534,16543,16551,16555,16562,16569,16571,16579,16585,16589,16592],[15,16420,16421],{},"Welcome to the latest Node-RED Dashboard 2.0 update. We've added lots of new widgets, cleaned up compatibility issues alongside Dashboard 1.0 and made strides to improve the events system linking the Node-RED editor with the Dashboard.",[15,16423,16424,16425,16428],{},"I firstly need to begin with a  ",[333,16426,16427],{},"\"Thank You\""," to the dozens of pre-alpha users we've had so far. Thanks for being patient whilst we're shipping fast and breaking things. We've had some great feedback, and we're working hard to implement is as best as possible.",[15,16430,16431,16432,437],{},"With all of the changes we've been making, we've also made the decision to jump to minor version numbers, and so, ",[33,16433,16434],{},"0.1.0 is available now",[15,16436,16437,16438,437],{},"Below you'll find a summary of the changes we've made since our ",[256,16439,16441],{"href":16440},"\u002Fblog\u002F2023\u002F07\u002Fdashboard-0-1-release","last community update",[19,16443,16445],{"id":16444},"new-widgets","New Widgets",[82,16447,16449,16450,3883],{"id":16448},"template-docs","Template (",[256,16451,6677],{"href":4980,"target":16452},"_blank",[15,16454,16455,16456,16458,16459,16462],{},"Steve has been doing some incredible work on the new ",[442,16457,869],{}," widget. This widget allows you to create your own custom components using raw HTML, but also works with any of the components in the ",[256,16460,3591],{"href":8639,"rel":16461},[402]," component library. It's a powerful tool that will enable users to be creative with their own widgets that are not currently available with the standard set of widgets.",[15,16464,16465],{},[239,16466],{"alt":16467,"src":16468},"Examples of ui-template","https:\u002F\u002Fdashboard.flowfuse.com\u002Fimages\u002Fnode-examples\u002Fui-template.png",[15,16470,16471],{},"The Template node also provides access to two built-in functions that can be used to send data back to Node-RED:",[27,16473,16474,16480],{},[30,16475,16476,16479],{},[33,16477,16478],{},"send(msg)",": Outputs a message (defined by the input to this function call) from this node in the Node-RED flow.",[30,16481,16482,16485,16486,16489,16490,16493,16494,16496,16497,16499],{},[33,16483,16484],{},"submit()",": Send a ",[442,16487,16488],{},"FormData"," object when attached to a ",[442,16491,16492],{},"\u003Cform>"," element. The created object will consist of the ",[442,16495,3173],{}," attributes for each form element, corresponding to their respective ",[442,16498,6731],{}," attributes.",[82,16501,16503,16504,3883],{"id":16502},"toggle-switch-docs","Toggle Switch (",[256,16505,6677],{"href":16506,"target":16452},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-switch.html",[15,16508,16509],{},[239,16510],{"alt":16511,"src":16512},"Examples of ui-switch","https:\u002F\u002Fdashboard.flowfuse.com\u002Fimages\u002Fnode-examples\u002Fui-switch.png",[15,16514,16515],{},"Adds a toggle switch to the user interface that can be rendered with a label, and traditional toggle switch, or, as in Dashboard 1.0, can be a square element with an icon & color provided.",[19,16517,16519],{"id":16518},"fixes-other-changes","Fixes & Other Changes",[82,16521,16523],{"id":16522},"sidebar","Sidebar",[15,16525,16526,16527,16529],{},"As requested on multiple occasions by the community when we released v0.0.4 of Dashboard 2.0, we've now added a side menu, as per Dashboard 1.0. Currently, this ",[333,16528,13581],{}," provides a link to the Dashboard UI, but gives us a canvas on which to expand functionality in the future.",[82,16531,16533],{"id":16532},"improved-events-system","Improved Events System",[15,16535,16536,16537,16539,16540,437],{},"We've re-structured the hierarchy of the events system to make it more streamlined. Now, the ",[442,16538,3770],{}," manages comms via single channels dedicated to each event type, and the widget's ID is then used as a topic. Previously, we had a separate channel for each ",[442,16541,16542],{},"action:id",[15,16544,16545,16546,16550],{},"If you're interested in learning more about our events architecture, you can read about it ",[256,16547,436],{"href":16548,"rel":16549},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fcontributing\u002Fguides\u002Fevents.html",[402]," in the docs.",[82,16552,16554],{"id":16553},"documentation-updates","Documentation Updates",[15,16556,16557,16558,3639],{},"It's not glamorous, but it's important. We've made sure that all documentation and help text inside Node-RED is fully up to date for the Dashboard 2.0 nodes. We've also include rendered examples for all widgets in our ",[256,16559,16561],{"href":3518,"rel":16560},[402],"online documentation",[15,16563,16564,16565,16568],{},"We've also made sure that any legacy options that had been transferred over from Dashboard 1.0 that haven't been fully implemented yet are temporarily hidden. This means, any options you're seeing, ",[333,16566,16567],{},"should"," be working. If they're not - it's a bug.",[19,16570,633],{"id":632},[15,16572,16573,16574,16578],{},"We have a lot of things to keep us busy, we are documenting them all in GitHub, and have made public our ",[256,16575,16577],{"href":448,"rel":16576},[402],"planning board",". You can see what we're working on, what's coming up next, and what we've got planned for the future.",[15,16580,16581,16582,437],{},"As always, we're open to ideas, feedback & contributions. If you'd like to get involved, please check out our GitHub Repository ",[256,16583,436],{"href":8066,"rel":16584},[402],[19,16586,16588],{"id":16587},"join-our-team","Join Our Team",[15,16590,16591],{},"If you'd like to be paid to directly contribute to Dashboard 2.0, we are hiring for a 2-3 month position to do just that:",[27,16593,16594],{},[30,16595,16596],{},[256,16597,16600],{"href":16598,"rel":16599},"https:\u002F\u002Fboards.greenhouse.io\u002Fflowfuse\u002Fjobs\u002F4911532004",[402],"Contract Front-End Engineer – Node-RED Dashboard",{"title":265,"searchDepth":266,"depth":266,"links":16602},[16603,16609,16614,16615],{"id":16444,"depth":269,"text":16445,"children":16604},[16605,16607],{"id":16448,"depth":274,"text":16606},"Template (docs)",{"id":16502,"depth":274,"text":16608},"Toggle Switch (docs)",{"id":16518,"depth":269,"text":16519,"children":16610},[16611,16612,16613],{"id":16522,"depth":274,"text":16523},{"id":16532,"depth":274,"text":16533},{"id":16553,"depth":274,"text":16554},{"id":632,"depth":269,"text":633},{"id":16587,"depth":269,"text":16588},"2023-08-10","Our latest Community Update for Dashboard 2.0, including the latest new widgets, fixes and updates on what's next.","\u002Fblog\u002F2023\u002F08\u002Fimages\u002FDashboard Community Update-Aug23.jpg",{"excerpt":16620},{"type":12,"value":16621},[16622],[15,16623,16421],{},"\u002Fblog\u002F2023\u002F08\u002Fdashboard-community-update",{"title":16415,"description":16617},{"loc":16624},"blog\u002F2023\u002F08\u002Fdashboard-community-update",[487,8099,8100,303],"H0v8D8RuvOesIOyZ38eIm01iP0HfQm0NNW0sMP3Rd78",{"id":16631,"title":16632,"authors":16633,"body":16635,"cta":3,"date":16782,"description":16783,"extension":287,"image":16784,"lastUpdated":3,"meta":16785,"navigation":295,"path":16440,"seo":16792,"sitemap":16793,"stem":16794,"subtitle":16795,"tags":16796,"tldr":3,"video":3,"__hash__":16797},"blog\u002Fblog\u002F2023\u002F07\u002Fdashboard-0-1-release.md","First Pre-Alpha Release of the new Node-RED Dashboard",[309,16634],"marian-demme",{"type":12,"value":16636,"toc":16778},[16637,16644,16648,16656,16659,16666,16669,16676,16680,16683,16717,16720,16730,16733,16772,16775],[15,16638,16639,16640,16643],{},"Just weeks ago, we at FlowFuse ",[256,16641,16642],{"href":11699},"announced our plan"," to develop a successor to the Node-RED Dashboard. Today, we're excited to reveal the pre-alpha release of this highly anticipated project, bringing us one step closer to a new era of data visualization in Node-RED.",[19,16645,16647],{"id":16646},"sneak-peek-into-the-new-node-red-dashboard","Sneak Peek into the New Node-RED Dashboard",[15,16649,16650,16651,16655],{},"The Node-RED Dashboard successor is now available for install as an npm package under the name ",[256,16652,14957],{"href":16653,"rel":16654},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@flowforge\u002Fnode-red-dashboard",[402]," in your Node-RED palette manager.",[15,16657,16658],{},"This pre-alpha version includes the first set of Vue.js-based elements familiar to Node-RED Dashboard users:",[15,16660,16661],{},[239,16662],{"alt":16663,"src":16664,"title":16665},"\"new Node-RED Dashboard Elements\"","\u002Fblog\u002F2023\u002F07\u002Fimages\u002Fnr-dashboard-screenshot.png","new Node-RED Dashboard Elements",[15,16667,16668],{},"This is but a hint of what's to come. The objective of these pre-alpha releases is to provide early access to the current status.",[15,16670,16671,16672,437],{},"The strength of the project comes from the community. Your insights, suggestions and contributions play a significant role in shaping the future of this dashboard. Keep them coming through our ",[256,16673,16675],{"href":8066,"rel":16674},[402],"Github page",[19,16677,16679],{"id":16678},"current-status-and-next-steps","Current Status and Next Steps",[15,16681,16682],{},"As of now, we've implemented the following Dashboard Widgets:",[27,16684,16685,16693,16701,16709],{},[30,16686,16687,16688,3883],{},"UI Text (",[256,16689,16692],{"href":16690,"rel":16691},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F38",[402],"ui-text Widget",[30,16694,16695,16696,3883],{},"Text Input (",[256,16697,16700],{"href":16698,"rel":16699},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F39",[402],"ui-text-input Widget",[30,16702,16703,16704,3883],{},"Range Slider (",[256,16705,16708],{"href":16706,"rel":16707},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F47",[402],"ui-slider Widget",[30,16710,16711,16712,3883],{},"Dropdown\u002FSelect (",[256,16713,16716],{"href":16714,"rel":16715},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F45",[402],"ui-dropdown Widget",[15,16718,16719],{},"We've also introduced a new widget:",[27,16721,16722],{},[30,16723,16724,16725,3883],{},"Markdown (",[256,16726,16729],{"href":16727,"rel":16728},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F62",[402],"ui-markdown Widget",[15,16731,16732],{},"Not yet part of the first Pre-Alpha Release:",[27,16734,16735,16742,16750,16756,16764],{},[30,16736,16503,16737,3883],{},[256,16738,16741],{"href":16739,"rel":16740},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F42",[402],"ui-switch Widget",[30,16743,16744,16745,3883],{},"Color Picker (",[256,16746,16749],{"href":16747,"rel":16748},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F46",[402],"ui-color-picker Widget",[30,16751,6672,16752,3883],{},[256,16753,16755],{"href":6692,"rel":16754},[402],"ui-numeric Widget",[30,16757,16758,16759,3883],{},"Form (",[256,16760,16763],{"href":16761,"rel":16762},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F49",[402],"ui-form Widget",[30,16765,16766,16767,3883],{},"Date selector (",[256,16768,16771],{"href":16769,"rel":16770},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Fissues\u002F32",[402],"ui-date-picker",[15,16773,16774],{},"Our immediate focus is to continue adding the missing elements from the original Node-RED Dashboard, releasing each as soon as they're fully developed. This will significantly increase the frequency of our releases in the upcoming weeks.",[15,16776,16777],{},"In addition to these releases, we plan to publish regular blog posts titled \"What's New in Node-RED Dashboard\". These posts will keep you informed of all the latest features, updates, and improvements.",{"title":265,"searchDepth":266,"depth":266,"links":16779},[16780,16781],{"id":16646,"depth":269,"text":16647},{"id":16678,"depth":269,"text":16679},"2023-07-27","The first release of the successor to the Node-RED Dashboard has arrived, marking the beginning of the pre-alpha phase.","\u002Fblog\u002F2023\u002F07\u002Fimages\u002Fnr-dashboard-tile.png",{"excerpt":16786},{"type":12,"value":16787},[16788],[15,16789,16639,16790,16643],{},[256,16791,16642],{"href":11699},{"title":16632,"description":16783},{"loc":16440},"blog\u002F2023\u002F07\u002Fdashboard-0-1-release","Introducing v0.0.1 – An Initial Glimpse at the Future of Dashboarding in Node-RED",[487,8099,303],"TRQka9nz4i5NfX96JGrliGWel82iCxbUM7EBwXh8oVs",{"id":16799,"title":16800,"authors":16801,"body":16803,"cta":17663,"date":17666,"description":17667,"extension":287,"image":17668,"lastUpdated":659,"meta":17669,"navigation":295,"path":17675,"seo":17676,"sitemap":17677,"stem":17678,"subtitle":17679,"tags":17680,"tldr":17681,"video":3,"__hash__":17682},"blog\u002Fblog\u002F2023\u002F07\u002Fimages-in-node-red-dashboards.md","How to add images to Node-RED dashboards when using FlowFuse (2026)",[16802],"rob-marcer",{"type":12,"value":16804,"toc":17640},[16805,16808,16811,16822,16826,16829,16857,16861,16869,16873,16877,16890,16894,16907,16911,16922,16926,16935,16939,16959,16963,16997,17001,17187,17191,17222,17259,17262,17266,17269,17272,17276,17279,17283,17286,17297,17300,17303,17307,17310,17352,17356,17364,17368,17371,17456,17459,17462,17468,17471,17613,17616,17622,17625,17629,17632,17634,17637],[15,16806,16807],{},"Using images in your Node-RED dashboards can significantly improve your users' experience. The most common method to add images to dashboards is to store them within the filesystem of an Node-RED instance but sometimes that's not an option. How can you easily use images when working in a containerized environment such as Docker, or Kubernetes? We will also explore latest feature from FlowFuse that makes this step super easy.",[15,16809,16810],{},"When designing a dashboard, images allow you to significantly enrich your content. Some examples include:",[27,16812,16813,16816,16819],{},[30,16814,16815],{},"displaying maps to guide engineers to a problem which needs resolving.",[30,16817,16818],{},"displaying pictures of specific hardware on a factory-floor which needs to be checked.",[30,16820,16821],{},"displaying physical tools which should be used to resolve a problem.",[82,16823,16825],{"id":16824},"prerequisites","Prerequisites",[15,16827,16828],{},"Before we begin, ensure you have the following custom nodes installed:",[27,16830,16831,16841,16849],{},[30,16832,16833,16837,16838,437],{},[256,16834,3669],{"href":16835,"rel":16836},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002F@flowfuse\u002Fnode-red-dashboard",[402]," - A set of dashboard nodes for Node-RED. We will use this dashboard to demonstrate how to quickly display images using static assets. If you're a beginner and want to dive deeper, refer to ",[256,16839,16840],{"href":4196},"Getting started with FlowFuse Dashboarad",[30,16842,16843,16848],{},[256,16844,16847],{"href":16845,"rel":16846},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-string",[402],"node-red-contrib-string"," - A string manipulation node based on the lightweight stringjs library.",[30,16850,16851,16856],{},[256,16852,16855],{"href":16853,"rel":16854},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-node-base64",[402],"node-red-node-base64"," - A Node-RED node to encode and decode data to and from base64.",[19,16858,16860],{"id":16859},"easily-add-images-to-node-red-dashboards-with-flowfuses-static-asset-service","Easily Add Images to Node-RED Dashboards with FlowFuse’s Static Asset Service",[15,16862,16863,16868],{},[256,16864,16867],{"href":16865,"rel":16866},"https:\u002F\u002Fflowforge.com\u002Fdocs\u002Fuser\u002Fstatic-asset-service\u002F",[402],"FlowFuse's static assets"," service provides a simple way to manage images and other assets in Node-RED. Follow these steps to quickly add images to your Node-RED dashboard.",[82,16870,16872],{"id":16871},"steps-to-add-images-using-the-static-asset-service","Steps to Add Images Using the Static Asset Service:",[11920,16874,16876],{"id":16875},"_1-access-the-static-assets-service","1. Access the Static Assets Service",[27,16878,16879],{},[30,16880,16881,16882,16885,16886,16889],{},"Log into your FlowFuse account, navigate to your ",[33,16883,16884],{},"Node-RED instance",", and click on the ",[33,16887,16888],{},"Static Assets Service"," tab.",[11920,16891,16893],{"id":16892},"_2-create-a-new-folder-optional","2. Create a New Folder (Optional)",[27,16895,16896],{},[30,16897,16898,16899,16902,16903,16906],{},"Click the ",[33,16900,16901],{},"New Folder"," button to create a folder that will help you organize your assets. Provide a folder name and ",[33,16904,16905],{},"confirm"," the creation.",[11920,16908,16910],{"id":16909},"_3-upload-your-image","3. Upload Your Image",[27,16912,16913],{},[30,16914,16915,16916,16919,16920,437],{},"Enter the folder (or skip this step if not using folders), click ",[33,16917,16918],{},"Upload",", select your image file, and ",[33,16921,16905],{},[11920,16923,16925],{"id":16924},"_4-copy-the-image-path","4. Copy the Image Path",[27,16927,16928],{},[30,16929,16930,16931,16934],{},"Once uploaded, click the ",[33,16932,16933],{},"copy icon"," next to the image to get the path for use in Node-RED.",[11920,16936,16938],{"id":16937},"_5-set-up-the-image-flow-in-node-red","5. Set Up the Image Flow in Node-RED",[27,16940,16941,16944,16949],{},[30,16942,16943],{},"Open the Node-RED editor for the relevant instance.",[30,16945,4584,16946,16948],{},[442,16947,16288],{}," node onto the canvas and set it to trigger immediately when the flow is deployed.",[30,16950,940,16951,16954,16955,16958],{},[442,16952,16953],{},"read file"," node, paste the copied file path in the ",[33,16956,16957],{},"Filename"," field, and set the output to Single buffer object.",[11920,16960,16962],{"id":16961},"_6-prepare-the-image-for-display","6. Prepare the Image for Display",[27,16964,16965,16986],{},[30,16966,16967,16968,16971,16972,16975,16976,16979,16980,4750,16983,437],{},"Add a ",[442,16969,16970],{},"string"," node to convert the buffer to a base64 string. Set ",[33,16973,16974],{},"From"," as ",[442,16977,16978],{},"msg.filename"," and adjust the ",[33,16981,16982],{},"Method",[442,16984,16985],{},"getmost",[30,16987,16967,16988,16990,16991,16993],{},[442,16989,4613],{}," node and configure it to add the elements shown in the following image:",[2278,16992],{},[239,16994],{"alt":16995,"src":16996,"title":16995},"The change node showing added elements","\u002Fblog\u002F2023\u002F07\u002Fimages\u002Fchange-node.png",[11920,16998,17000],{"id":16999},"_7-display-the-image-in-the-dashboard","7. Display the Image in the Dashboard",[27,17002,17003,17007],{},[30,17004,940,17005,1287],{},[442,17006,869],{},[30,17008,17009,17010,1276,17012,17015,17016,17019,17020,17022,17023],{},"Add the code in ",[442,17011,869],{},[442,17013,17014],{},"\u003Cimg>"," tag, configuring the ",[442,17017,17018],{},"src"," attribute with ",[442,17021,1350],{},", as shown in the following code. Alternatively, you can use the following code directly if you want to display the image in the top-left corner of your dashboard header:",[981,17024,17026],{"className":4318,"code":17025,"language":4320,"meta":265,"style":265},"\u003Ctemplate>\n    \u003CTeleport v-if=\"mounted\" to=\"#app-bar-title\">\n        \u003Cimg :src=\"msg.payload\" style=\"height: 32px;\" \u002F>\n    \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n    export default {\n        data() {\n            return {\n                mounted: false\n            }\n        },\n        mounted() {\n            this.mounted = true;\n        }\n    }\n\u003C\u002Fscript>\n",[442,17027,17028,17036,17064,17086,17094,17102,17106,17114,17121,17129,17136,17144,17148,17152,17160,17171,17175,17179],{"__ignoreMap":265},[989,17029,17030,17032,17034],{"class":991,"line":992},[989,17031,996],{"class":995},[989,17033,1000],{"class":999},[989,17035,1003],{"class":995},[989,17037,17038,17040,17042,17044,17046,17048,17050,17052,17054,17056,17058,17060,17062],{"class":991,"line":269},[989,17039,1014],{"class":995},[989,17041,1017],{"class":1736},[989,17043,1021],{"class":1020},[989,17045,1024],{"class":995},[989,17047,1027],{"class":995},[989,17049,1031],{"class":1030},[989,17051,1027],{"class":995},[989,17053,1036],{"class":1020},[989,17055,1024],{"class":995},[989,17057,1027],{"class":995},[989,17059,880],{"class":1030},[989,17061,1027],{"class":995},[989,17063,1003],{"class":995},[989,17065,17066,17068,17070,17073,17075,17077,17079,17082,17084],{"class":991,"line":274},[989,17067,1051],{"class":995},[989,17069,239],{"class":999},[989,17071,17072],{"class":995}," :src=\"msg.payload\" ",[989,17074,1720],{"class":1020},[989,17076,1024],{"class":995},[989,17078,1027],{"class":995},[989,17080,17081],{"class":1030},"height: 32px;",[989,17083,1027],{"class":995},[989,17085,1528],{"class":995},[989,17087,17088,17090,17092],{"class":991,"line":266},[989,17089,1110],{"class":995},[989,17091,1017],{"class":1736},[989,17093,1003],{"class":995},[989,17095,17096,17098,17100],{"class":991,"line":1071},[989,17097,1064],{"class":995},[989,17099,1000],{"class":999},[989,17101,1003],{"class":995},[989,17103,17104],{"class":991,"line":1089},[989,17105,1129],{"emptyLinePlaceholder":295},[989,17107,17108,17110,17112],{"class":991,"line":1107},[989,17109,996],{"class":995},[989,17111,1137],{"class":999},[989,17113,1003],{"class":995},[989,17115,17116,17119],{"class":991,"line":1117},[989,17117,17118],{"class":1060},"    export default ",[989,17120,4390],{"class":995},[989,17122,17123,17125,17127],{"class":991,"line":1126},[989,17124,1158],{"class":4345},[989,17126,11341],{"class":1060},[989,17128,4390],{"class":995},[989,17130,17131,17134],{"class":991,"line":1132},[989,17132,17133],{"class":1060},"            return ",[989,17135,4390],{"class":995},[989,17137,17138,17140,17142],{"class":991,"line":1142},[989,17139,1177],{"class":1736},[989,17141,1180],{"class":995},[989,17143,1184],{"class":1183},[989,17145,17146],{"class":991,"line":1155},[989,17147,1190],{"class":995},[989,17149,17150],{"class":991,"line":1166},[989,17151,1196],{"class":995},[989,17153,17154,17156,17158],{"class":991,"line":1174},[989,17155,1202],{"class":4345},[989,17157,11341],{"class":1060},[989,17159,4390],{"class":995},[989,17161,17162,17165,17167,17169],{"class":991,"line":1187},[989,17163,17164],{"class":1060},"            this.mounted ",[989,17166,1024],{"class":995},[989,17168,1681],{"class":1183},[989,17170,1753],{"class":1060},[989,17172,17173],{"class":991,"line":1193},[989,17174,1232],{"class":995},[989,17176,17177],{"class":991,"line":1199},[989,17178,1238],{"class":995},[989,17180,17181,17183,17185],{"class":991,"line":1209},[989,17182,1064],{"class":995},[989,17184,1137],{"class":999},[989,17186,1003],{"class":995},[11920,17188,17190],{"id":17189},"_8-connect-the-nodes","8. Connect the Nodes",[27,17192,17193],{},[30,17194,17195,17196,17199,17200,4903,17202,17199,17205,17207,17208,17211,17212,17214,17215,574,17217,17219],{},"Finally connect the nodes in the following order:\nthe ",[33,17197,17198],{},"output"," of the ",[442,17201,16288],{},[33,17203,17204],{},"input",[442,17206,16953],{}," node, then link to the ",[442,17209,17210],{},"string node",", followed by the ",[442,17213,4613],{}," node, and finally to the ",[442,17216,869],{},[2278,17218],{},[442,17220,17221],{},"inject → read file → string → change → ui-template",[15,17223,5928,17224,5411],{},[989,17225,17226,17227,17230,17231,5329,17237,17240,17241,17243,17244,17247,17248,17254,17255,17258],{},"{\"id\":\"e50f7c57189d62f8\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"style\":{\"stroke\":\"#b2b3bd\",\"stroke-opacity\":\"1\",\"fill\":\"#f2f3fb\",\"fill-opacity\":\"0.5\",\"label\":true,\"label-position\":\"nw\",\"color\":\"#32333b\"},\"nodes\":",[989,17228,17229],{},"\"3bf4c71150bd0524\",\"4d3ca1b96c181645\",\"315948cc6a2cc9e8\",\"fcf061d4cc732e2e\",\"6563d8715af4cb06\",\"d40caa36040de881\"",",\"x\":514,\"y\":699,\"w\":1752,\"h\":82},{\"id\":\"3bf4c71150bd0524\",\"type\":\"ui-template\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"group\":\"\",\"page\":\"\",\"ui\":\"25f447d87d1ce5c9\",\"name\":\"Display image\",\"order\":0,\"width\":0,\"height\":0,\"head\":\"\",\"format\":\"",[1000,17232,5320,17233,17234,17236],{},"\\n    \u003CTeleport v-if=\"mounted\" to=\"#app-bar-title\">\\n        \u003Cimg ",[17018,17235],{},"=\"msg.payload\" style=\"height: 32px;\" \u002F>\\n    \\n",[1137,17238,17239],{},"\\n    export default {\\n        data() {\\n            return {\\n                mounted: false\\n            }\\n        },\\n        mounted() {\\n            \u002F\u002F Set mounted to true when the component is mounted\\n            this.mounted = true\\n        }\\n    }\\n","\",\"storeOutMessages\":true,\"passthru\":true,\"resendOnRefresh\":true,\"templateScope\":\"widget:ui\",\"className\":\"\",\"x\":2160,\"y\":740,\"wires\":[[]]},{\"id\":\"4d3ca1b96c181645\",\"type\":\"inject\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"name\":\"\",\"props\":",[989,17242,5944],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":true,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"\",\"payloadType\":\"date\",\"x\":630,\"y\":740,\"wires\":[[\"315948cc6a2cc9e8\"]]},{\"id\":\"315948cc6a2cc9e8\",\"type\":\"file in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"name\":\"\",\"filename\":\"Images\u002Fff-logo--wordmark--light.png\",\"filenameType\":\"str\",\"format\":\"\",\"chunk\":false,\"sendError\":false,\"encoding\":\"none\",\"allProps\":false,\"x\":880,\"y\":740,\"wires\":[[\"d40caa36040de881\"]]},{\"id\":\"fcf061d4cc732e2e\",\"type\":\"change\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"name\":\"Add the file type to the mimetype, add to image content\",\"rules\":",[989,17245,17246],{},"{\"t\":\"set\",\"p\":\"mimetype\",\"pt\":\"msg\",\"to\":\"\"data:image\u002F\"&msg.filetype&\";base64,\"\",\"tot\":\"jsonata\"},{\"t\":\"set\",\"p\":\"output\",\"pt\":\"msg\",\"to\":\"msg.mimetype&msg.payload\",\"tot\":\"jsonata\"},{\"t\":\"move\",\"p\":\"output\",\"pt\":\"msg\",\"to\":\"payload\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":1820,\"y\":740,\"wires\":[[\"3bf4c71150bd0524\"]]},{\"id\":\"6563d8715af4cb06\",\"type\":\"string\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"name\":\"Get file type from file name\",\"methods\":",[989,17249,17250,17251,4425],{},"{\"name\":\"getRightMost\",\"params\":",[989,17252,17253],{},"{\"type\":\"str\",\"value\":\".\"}",",\"prop\":\"filename\",\"propout\":\"filetype\",\"object\":\"msg\",\"objectout\":\"msg\",\"x\":1480,\"y\":740,\"wires\":[[\"fcf061d4cc732e2e\"]]},{\"id\":\"d40caa36040de881\",\"type\":\"base64\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"e50f7c57189d62f8\",\"name\":\"Convert Buffer to Base 64 String\",\"action\":\"\",\"property\":\"payload\",\"x\":1210,\"y\":740,\"wires\":[[\"6563d8715af4cb06\"]]},{\"id\":\"25f447d87d1ce5c9\",\"type\":\"ui-base\",\"name\":\"Dashboard\",\"path\":\"\u002Fdashboard\",\"includeClientData\":true,\"acceptsClientConfig\":",[989,17256,17257],{},"\"ui-control\",\"ui-notification\"",",\"showPathInSidebar\":false,\"showPageTitle\":false,\"titleBarStyle\":\"default\"}",[15,17260,17261],{},"Using the FlowFuse Static Assets service is highly beneficial when you want to display images in Node-RED dashboards, as it saves time compared to alternative solutions. However, it’s important to note that moving Node-RED instances through a DevOps pipeline currently does not support handling static assets. This feature is expected in future updates. If you want to manage images effectively within your Node-RED dashboards, consider the alternative solutions discussed in this blog, ensuring that the movement of instances does not affect the usage of these assets.",[19,17263,17265],{"id":17264},"why-not-just-store-them-in-node-reds-host-operating-system","Why not just store them in Node-RED's host operating system?",[15,17267,17268],{},"Storing images locally can work well when you can access and edit the images on an operating system, but that approach doesn't scale if you are moving instances through a DevOps pipeline. It can also not work well when deploying to environments where you don't have easy access to the host operating system.",[15,17270,17271],{},"How can we include images in dashboards, and be confident that a given build of an application will show the correct images, no matter where your Node-RED instances are hosted?",[19,17273,17275],{"id":17274},"inspiration","Inspiration",[15,17277,17278],{},"There are various solutions to this problem, I wanted to share one I came across when working with a FlowFuse customer recently. I've modified the flows to make them more general in design, but the underlying principal is the same. I asked if I was OK to credit the customer but they said there was no need. Thanks for the inspiration, kind customer!",[19,17280,17282],{"id":17281},"solution-explanation","Solution explanation",[15,17284,17285],{},"There are three key sections to this solution:",[903,17287,17288,17291,17294],{},[30,17289,17290],{},"Pull the images we need from URLs",[30,17292,17293],{},"Store those images in the temporary filesystem of Node-RED",[30,17295,17296],{},"Serve up those images as needed in the dashboard",[15,17298,17299],{},"It is possible for us to skip step 2, but I wanted to have the images stored locally, in the Node-RED instance. storing the images locally will improve the loading times of the dashboard. This is especially beneficial when your dashboard is dynamically displaying relevant images, e.g. to show an image of a specific machine which needs to be attended to.",[15,17301,17302],{},"The key benefit of pulling the images from URLs this way is, no matter where you are running Node-RED, the correct images will be shown in your dashboard.",[19,17304,17306],{"id":17305},"prequsite","Prequsite",[15,17308,17309],{},"Before moving forward, ensure you have the following nodes installed, as the flows shared later will require them:",[27,17311,17312,17320,17328,17336,17341,17347],{},[30,17313,17314,17319],{},[256,17315,17318],{"href":17316,"rel":17317},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-calc",[402],"node-red-contrib-calc"," - A Node-RED node to perform basic mathematical calculations.",[30,17321,17322,17327],{},[256,17323,17326],{"href":17324,"rel":17325},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-image-output",[402],"node-red-contrib-image-output"," - A simple way to preview and examine images in your flows.",[30,17329,17330,17335],{},[256,17331,17334],{"href":17332,"rel":17333},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-os",[402],"node-red-contrib-os"," - Nodes for obtaining system information like CPU usage.",[30,17337,17338,16848],{},[256,17339,16847],{"href":16845,"rel":17340},[402],[30,17342,17343,17346],{},[256,17344,3669],{"href":16835,"rel":17345},[402]," - A set of dashboard nodes for Node-RED.",[30,17348,17349,16856],{},[256,17350,16855],{"href":16853,"rel":17351},[402],[19,17353,17355],{"id":17354},"file-and-file-in-nodes","File and file-in nodes",[15,17357,17358,17359,17363],{},"I've included the flows as json below so you can try them out yourself. Please note, I'm using FlowFuse's own ",[256,17360,17362],{"href":17361},"\u002Fdocs\u002Fuser\u002Ffilenodes\u002F","file and file-in nodes"," in these examples. If you want to use these flows on hosting other than FlowFuse, you will need to replace the nodes with the standard Node-RED file and file-in nodes.",[19,17365,17367],{"id":17366},"the-flows","The flows",[15,17369,17370],{},"The first flow takes image URLs in an array, each image is downloaded, processed, then saved to the local file storage. Let's take a look at the flow:",[15,17372,5928,17373,5411],{},[989,17374,17375,17376,17379,17380,17383,17384,17386,17387,17394,17395,17398,17399,17401,17402,17405,17406,17408,17409,17412,17413,17416,17417,17419,17420,17423,17424,17427,17428,17433,17434,17437,17438,17441,17442,17444,17445,17448,17449,17451,17452,17455],{},"{\"id\":\"6b8059f703d0f574\",\"type\":\"group\",\"z\":\"c6f2a894be05d857\",\"name\":\"Write the images to disk from the URLs\",\"style\":{\"label\":true},\"nodes\":",[989,17377,17378],{},"\"04fb6911559797a0\",\"8a3c077f0f85a905\",\"22c5026dd58e418b\",\"6fcca5cfee2bcb89\"",",\"x\":38,\"y\":53,\"w\":1004,\"h\":434},{\"id\":\"04fb6911559797a0\",\"type\":\"group\",\"z\":\"c6f2a894be05d857\",\"g\":\"6b8059f703d0f574\",\"name\":\"Inject the image URLs to download\",\"style\":{\"label\":true},\"nodes\":",[989,17381,17382],{},"\"e635ceb0577a86d5\",\"29fe40a054be5b2b\",\"1e81a35c27aae6ad\"",",\"x\":74,\"y\":79,\"w\":502,\"h\":82},{\"id\":\"e635ceb0577a86d5\",\"type\":\"inject\",\"z\":\"c6f2a894be05d857\",\"g\":\"04fb6911559797a0\",\"name\":\"Send in image URLs as an array\",\"props\":",[989,17385,5944],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"",[989,17388,1027,17389,1027],{},[256,17390,17393],{"href":17391,"rel":17392},"https:\u002F\u002Fopenjsf.org\u002Fwp-content\u002Fuploads\u002Fsites\u002F84\u002F2023\u002F02\u002Fff-logo-wordmark-light_4x.png%5C%22,%5C%22https:\u002F\u002Fnodered.org\u002Fimages\u002Fnr-image-1.png%5C%22,%5C%22\u002Fimg\u002Fscreen-pseudo-overview-2QvTVle3Mr-384.avif%5C",[402],"https:\u002F\u002Fopenjsf.org\u002Fwp-content\u002Fuploads\u002Fsites\u002F84\u002F2023\u002F02\u002Fff-logo-wordmark-light_4x.png\\\",\\\"https:\u002F\u002Fnodered.org\u002Fimages\u002Fnr-image-1.png\\\",\\\"\u002Fimg\u002Fscreen-pseudo-overview-2QvTVle3Mr-384.avif\\","\",\"payloadType\":\"json\",\"x\":250,\"y\":120,\"wires\":[[\"29fe40a054be5b2b\"]]},{\"id\":\"29fe40a054be5b2b\",\"type\":\"split\",\"z\":\"c6f2a894be05d857\",\"g\":\"04fb6911559797a0\",\"name\":\"\",\"splt\":\"\\n\",\"spltType\":\"str\",\"arraySplt\":1,\"arraySpltType\":\"len\",\"stream\":false,\"addname\":\"\",\"x\":450,\"y\":120,\"wires\":[[\"1e81a35c27aae6ad\"]]},{\"id\":\"1e81a35c27aae6ad\",\"type\":\"link out\",\"z\":\"c6f2a894be05d857\",\"g\":\"04fb6911559797a0\",\"name\":\"link out 3\",\"mode\":\"link\",\"links\":",[989,17396,17397],{},"\"f582702ec222069c\"",",\"x\":535,\"y\":120,\"wires\":",[989,17400],{},"},{\"id\":\"8a3c077f0f85a905\",\"type\":\"group\",\"z\":\"c6f2a894be05d857\",\"g\":\"6b8059f703d0f574\",\"name\":\"Download the images\",\"style\":{\"label\":true},\"nodes\":",[989,17403,17404],{},"\"453f3b9d7d312bd2\",\"ecbd7b1a410ecd9d\",\"4d650baa2118036e\",\"f582702ec222069c\"",",\"x\":84,\"y\":179,\"w\":532,\"h\":82},{\"id\":\"453f3b9d7d312bd2\",\"type\":\"http request\",\"z\":\"c6f2a894be05d857\",\"g\":\"8a3c077f0f85a905\",\"name\":\"Get the image\",\"method\":\"GET\",\"ret\":\"bin\",\"paytoqs\":\"ignore\",\"url\":\"\",\"tls\":\"\",\"persist\":false,\"proxy\":\"\",\"insecureHTTPParser\":false,\"authType\":\"\",\"senderr\":false,\"headers\":",[989,17407],{},",\"x\":460,\"y\":220,\"wires\":[[\"4d650baa2118036e\"]]},{\"id\":\"ecbd7b1a410ecd9d\",\"type\":\"change\",\"z\":\"c6f2a894be05d857\",\"g\":\"8a3c077f0f85a905\",\"name\":\"Set URL to download\",\"rules\":",[989,17410,17411],{},"{\"t\":\"move\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"url\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":260,\"y\":220,\"wires\":[[\"453f3b9d7d312bd2\"]]},{\"id\":\"4d650baa2118036e\",\"type\":\"link out\",\"z\":\"c6f2a894be05d857\",\"g\":\"8a3c077f0f85a905\",\"name\":\"link out 1\",\"mode\":\"link\",\"links\":",[989,17414,17415],{},"\"8bc38803dec97185\"",",\"x\":575,\"y\":220,\"wires\":",[989,17418],{},"},{\"id\":\"f582702ec222069c\",\"type\":\"link in\",\"z\":\"c6f2a894be05d857\",\"g\":\"8a3c077f0f85a905\",\"name\":\"link in 3\",\"links\":",[989,17421,17422],{},"\"1e81a35c27aae6ad\"",",\"x\":125,\"y\":220,\"wires\":[[\"ecbd7b1a410ecd9d\"]]},{\"id\":\"22c5026dd58e418b\",\"type\":\"group\",\"z\":\"c6f2a894be05d857\",\"g\":\"6b8059f703d0f574\",\"name\":\"Save the images to the local storage\",\"style\":{\"label\":true},\"nodes\":",[989,17425,17426],{},"\"95c819560d22f394\",\"0fe7f013b6356c5d\",\"7edc6cb2b0d243db\",\"829bfc8e6e293ada\",\"8bc38803dec97185\",\"98980d88013c6e12\"",",\"x\":84,\"y\":279,\"w\":932,\"h\":82},{\"id\":\"95c819560d22f394\",\"type\":\"base64\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"convert to base64\",\"action\":\"str\",\"property\":\"payload\",\"x\":250,\"y\":320,\"wires\":[[\"829bfc8e6e293ada\"]]},{\"id\":\"0fe7f013b6356c5d\",\"type\":\"file\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"Write file to storage\",\"filename\":\"filename\",\"filenameType\":\"msg\",\"appendNewline\":true,\"createDir\":false,\"overwriteFile\":\"true\",\"encoding\":\"none\",\"x\":850,\"y\":320,\"wires\":[[\"98980d88013c6e12\"]]},{\"id\":\"7edc6cb2b0d243db\",\"type\":\"string\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"Get filename from the URL\",\"methods\":",[989,17429,17250,17430,4425],{},[989,17431,17432],{},"{\"type\":\"str\",\"value\":\"\u002F\"}",",\"prop\":\"responseUrl\",\"propout\":\"filename\",\"object\":\"msg\",\"objectout\":\"msg\",\"x\":620,\"y\":320,\"wires\":[[\"0fe7f013b6356c5d\"]]},{\"id\":\"829bfc8e6e293ada\",\"type\":\"image\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"preview\",\"width\":\"150\",\"data\":\"payload\",\"dataType\":\"msg\",\"thumbnail\":false,\"active\":true,\"pass\":true,\"outputs\":1,\"x\":420,\"y\":320,\"wires\":[[\"7edc6cb2b0d243db\"]]},{\"id\":\"8bc38803dec97185\",\"type\":\"link in\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"link in 1\",\"links\":",[989,17435,17436],{},"\"4d650baa2118036e\"",",\"x\":125,\"y\":320,\"wires\":[[\"95c819560d22f394\"]]},{\"id\":\"98980d88013c6e12\",\"type\":\"link out\",\"z\":\"c6f2a894be05d857\",\"g\":\"22c5026dd58e418b\",\"name\":\"link out 2\",\"mode\":\"link\",\"links\":",[989,17439,17440],{},"\"1e94b5bab542830a\"",",\"x\":975,\"y\":320,\"wires\":",[989,17443],{},"},{\"id\":\"6fcca5cfee2bcb89\",\"type\":\"group\",\"z\":\"c6f2a894be05d857\",\"g\":\"6b8059f703d0f574\",\"name\":\"Output a debug once all images have been processed\",\"style\":{\"label\":true},\"nodes\":",[989,17446,17447],{},"\"d1a6feea3ac829c6\",\"119f8008752bc4fb\",\"1e94b5bab542830a\"",",\"x\":64,\"y\":379,\"w\":382,\"h\":82},{\"id\":\"d1a6feea3ac829c6\",\"type\":\"debug\",\"z\":\"c6f2a894be05d857\",\"g\":\"6fcca5cfee2bcb89\",\"name\":\"debug 140\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"true\",\"targetType\":\"full\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":330,\"y\":420,\"wires\":",[989,17450],{},"},{\"id\":\"119f8008752bc4fb\",\"type\":\"join\",\"z\":\"c6f2a894be05d857\",\"g\":\"6fcca5cfee2bcb89\",\"name\":\"\",\"mode\":\"auto\",\"build\":\"object\",\"property\":\"payload\",\"propertyType\":\"msg\",\"key\":\"topic\",\"joiner\":\"\\n\",\"joinerType\":\"str\",\"accumulate\":\"false\",\"timeout\":\"\",\"count\":\"\",\"reduceRight\":false,\"x\":190,\"y\":420,\"wires\":[[\"d1a6feea3ac829c6\"]]},{\"id\":\"1e94b5bab542830a\",\"type\":\"link in\",\"z\":\"c6f2a894be05d857\",\"g\":\"6fcca5cfee2bcb89\",\"name\":\"link in 2\",\"links\":",[989,17453,17454],{},"\"98980d88013c6e12\"",",\"x\":105,\"y\":420,\"wires\":[[\"119f8008752bc4fb\"]]}",[15,17457,17458],{},"We've now downloaded the images we need, and saved them to our local storage, to make them load more quickly when a user views them in the dashboard.",[15,17460,17461],{},"Onto the second flow, which will get the images from the local storage and then load them into the dashboard. Let's take a look at it:",[15,17463,17464],{},[239,17465],{"alt":17466,"src":17467,"title":17466},"Get the images from the local storage and place them in a dashboard","\u002Fblog\u002F2023\u002F07\u002Fimages\u002Fload-images-from-disk-and-show-in-dashboard.png",[15,17469,17470],{},"You can import this flow into Node-RED using the code below:",[15,17472,5928,17473,5411],{},[989,17474,17475,17476,17479,17480,17483,17484,17487,17488,17491,17492,17494,17495,17498,17499,17501,17502,17506,17507,17510,17511,17514,17515,17517,17518,17521,17522,17525,17526,4459,17529,17532,17533,17536,17537,17540,17541,17543,17544,17555,17556,17564,17565,17573,17574,17577,17578,17580,17581,17584,17585,17588,17589,17591,17592,17595,17596,17598,17599,17602,17603,17605,17606,17612],{},"{\"id\":\"596006fe79275d55\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"name\":\"Get the images from the filestore and display in the Dashboard\",\"style\":{\"label\":true},\"nodes\":",[989,17477,17478],{},"\"be421f8265c4c090\",\"d2dc98b4f3d6b968\",\"b9029adc6097bd14\",\"1e54acecec6bd411\",\"99aaee673fc70bc2\"",",\"x\":1228,\"y\":3733,\"w\":974,\"h\":654},{\"id\":\"be421f8265c4c090\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"596006fe79275d55\",\"name\":\"Get the images from the local storage\",\"style\":{\"label\":true},\"nodes\":",[989,17481,17482],{},"\"c698b2945583e126\",\"ab22b978a2f5d80f\",\"2836914f9b643e34\",\"8e32aba67d9ac9d4\"",",\"x\":1264,\"y\":3899,\"w\":492,\"h\":82},{\"id\":\"c698b2945583e126\",\"type\":\"image\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"be421f8265c4c090\",\"name\":\"preview\",\"width\":\"150\",\"data\":\"payload\",\"dataType\":\"msg\",\"thumbnail\":false,\"active\":true,\"pass\":true,\"outputs\":1,\"x\":1620,\"y\":3940,\"wires\":[[\"8e32aba67d9ac9d4\"]]},{\"id\":\"ab22b978a2f5d80f\",\"type\":\"file in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"be421f8265c4c090\",\"name\":\"Read file from storage\",\"filename\":\"payload\",\"filenameType\":\"msg\",\"format\":\"utf8\",\"chunk\":false,\"sendError\":false,\"encoding\":\"none\",\"allProps\":false,\"x\":1440,\"y\":3940,\"wires\":[[\"c698b2945583e126\"]]},{\"id\":\"2836914f9b643e34\",\"type\":\"link in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"be421f8265c4c090\",\"name\":\"link in 4\",\"links\":",[989,17485,17486],{},"\"a9958e1e4b07191a\"",",\"x\":1305,\"y\":3940,\"wires\":[[\"ab22b978a2f5d80f\"]]},{\"id\":\"8e32aba67d9ac9d4\",\"type\":\"link out\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"be421f8265c4c090\",\"name\":\"link out 5\",\"mode\":\"link\",\"links\":",[989,17489,17490],{},"\"bbdd3a2e737e1074\"",",\"x\":1715,\"y\":3940,\"wires\":",[989,17493],{},"},{\"id\":\"d2dc98b4f3d6b968\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"596006fe79275d55\",\"name\":\"Prepare each image to be shown in the dashboard\",\"style\":{\"label\":true},\"nodes\":",[989,17496,17497],{},"\"54f0e7fddf447d10\",\"d856077cc6d37093\",\"bbdd3a2e737e1074\",\"2d29c953bcdab787\"",",\"x\":1264,\"y\":3999,\"w\":832,\"h\":82},{\"id\":\"54f0e7fddf447d10\",\"type\":\"change\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"d2dc98b4f3d6b968\",\"name\":\"Add the file type to the mimetype, add to image content\",\"rules\":",[989,17500,17246],{},",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":1810,\"y\":4040,\"wires\":[[\"2d29c953bcdab787\"]]},{\"id\":\"d856077cc6d37093\",\"type\":\"string\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"d2dc98b4f3d6b968\",\"name\":\"Get file type from file name\",\"methods\":",[989,17503,17250,17504,4425],{},[989,17505,17253],{},",\"prop\":\"filename\",\"propout\":\"filetype\",\"object\":\"msg\",\"objectout\":\"msg\",\"x\":1460,\"y\":4040,\"wires\":[[\"54f0e7fddf447d10\"]]},{\"id\":\"bbdd3a2e737e1074\",\"type\":\"link in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"d2dc98b4f3d6b968\",\"name\":\"link in 5\",\"links\":",[989,17508,17509],{},"\"8e32aba67d9ac9d4\"",",\"x\":1305,\"y\":4040,\"wires\":[[\"d856077cc6d37093\"]]},{\"id\":\"2d29c953bcdab787\",\"type\":\"link out\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"d2dc98b4f3d6b968\",\"name\":\"link out 6\",\"mode\":\"link\",\"links\":",[989,17512,17513],{},"\"c5e4febe48363987\"",",\"x\":2055,\"y\":4040,\"wires\":",[989,17516],{},"},{\"id\":\"b9029adc6097bd14\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"596006fe79275d55\",\"name\":\"Send the images to the correct section of the dashboard\",\"style\":{\"label\":true},\"nodes\":",[989,17519,17520],{},"\"fa873d7bccd2b6be\",\"c5e4febe48363987\",\"d80e5a54a7c5b2f8\",\"fb0c76a6934b0a7f\",\"4e4105a9774c7b5c\",\"917c842a1b46ad4c\"",",\"x\":1264,\"y\":4099,\"w\":912,\"h\":162},{\"id\":\"fa873d7bccd2b6be\",\"type\":\"switch\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"name\":\"Send the image to the correct section of the dashboard\",\"property\":\"filename\",\"propertyType\":\"msg\",\"rules\":",[989,17523,17524],{},"{\"t\":\"eq\",\"v\":\"ff-logo-wordmark-light_4x.png\",\"vt\":\"str\"},{\"t\":\"eq\",\"v\":\"screen-pseudo-overview-2QvTVle3Mr-384.avif\",\"vt\":\"str\"},{\"t\":\"eq\",\"v\":\"nr-image-1.png\",\"vt\":\"str\"}",",\"checkall\":\"true\",\"repair\":false,\"outputs\":3,\"x\":1550,\"y\":4180,\"wires\":[[\"917c842a1b46ad4c\"],",[989,17527,17528],{},"\"4e4105a9774c7b5c\"",[989,17530,17531],{},"\"fb0c76a6934b0a7f\"","]},{\"id\":\"c5e4febe48363987\",\"type\":\"link in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"name\":\"link in 6\",\"links\":",[989,17534,17535],{},"\"2d29c953bcdab787\"",",\"x\":1305,\"y\":4180,\"wires\":[[\"fa873d7bccd2b6be\"]]},{\"id\":\"d80e5a54a7c5b2f8\",\"type\":\"link out\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"name\":\"link out 7\",\"mode\":\"link\",\"links\":",[989,17538,17539],{},"\"c9de7384c9ca672f\"",",\"x\":2135,\"y\":4180,\"wires\":",[989,17542],{},"},{\"id\":\"fb0c76a6934b0a7f\",\"type\":\"ui-template\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"group\":\"ec62d482d77f7908\",\"page\":\"\",\"ui\":\"\",\"name\":\"Display the image on the Dashboard\",\"order\":6,\"width\":\"3\",\"height\":\"1\",\"head\":\"\",\"format\":\"",[1000,17545,5320,17546,17554],{},[228,17547,17548,17549,17551,17552,5320],{},"\\n        \u003Cimg ",[17018,17550],{},"= \"msg.paylaod\" alt=\"Image loaded from the filestore\" style=\"width:100%\">",[2278,17553],{},"\\n","\",\"storeOutMessages\":true,\"passthru\":true,\"resendOnRefresh\":true,\"templateScope\":\"local\",\"className\":\"\",\"x\":1930,\"y\":4220,\"wires\":[[\"d80e5a54a7c5b2f8\"]]},{\"id\":\"4e4105a9774c7b5c\",\"type\":\"ui-template\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"group\":\"ec62d482d77f7908\",\"page\":\"\",\"ui\":\"\",\"name\":\"Display the image on the Dashboard\",\"order\":5,\"width\":\"3\",\"height\":\"1\",\"head\":\"\",\"format\":\"",[1000,17557,5320,17558,17554],{},[228,17559,17548,17560,17551,17562,5320],{},[17018,17561],{},[2278,17563],{},"\",\"storeOutMessages\":true,\"passthru\":true,\"resendOnRefresh\":true,\"templateScope\":\"local\",\"className\":\"\",\"x\":1930,\"y\":4180,\"wires\":[[\"d80e5a54a7c5b2f8\"]]},{\"id\":\"917c842a1b46ad4c\",\"type\":\"ui-template\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"b9029adc6097bd14\",\"group\":\"ec62d482d77f7908\",\"page\":\"\",\"ui\":\"\",\"name\":\"Display the image on the Dashboard\",\"order\":2,\"width\":0,\"height\":0,\"head\":\"\",\"format\":\"",[1000,17566,5320,17567,17554],{},[228,17568,17548,17569,17551,17571,5320],{},[17018,17570],{},[2278,17572],{},"\",\"storeOutMessages\":true,\"passthru\":true,\"resendOnRefresh\":true,\"templateScope\":\"local\",\"className\":\"\",\"x\":1930,\"y\":4140,\"wires\":[[\"d80e5a54a7c5b2f8\"]]},{\"id\":\"ec62d482d77f7908\",\"type\":\"ui-group\",\"name\":\"Default\",\"page\":\"550c9ac3b2ed01c9\",\"width\":\"6\",\"height\":\"1\",\"order\":1,\"showTitle\":false,\"className\":\"\",\"visible\":\"true\",\"disabled\":\"false\"},{\"id\":\"550c9ac3b2ed01c9\",\"type\":\"ui-page\",\"name\":\"Home\",\"ui\":\"25f447d87d1ce5c9\",\"path\":\"\u002F\",\"icon\":\"home\",\"layout\":\"grid\",\"theme\":\"c68088445147719b\",\"breakpoints\":",[989,17575,17576],{},"{\"name\":\"Default\",\"px\":0,\"cols\":3},{\"name\":\"Tablet\",\"px\":576,\"cols\":6},{\"name\":\"Small Desktop\",\"px\":768,\"cols\":9},{\"name\":\"Desktop\",\"px\":1024,\"cols\":12}",",\"order\":1,\"className\":\"\",\"visible\":true,\"disabled\":false},{\"id\":\"25f447d87d1ce5c9\",\"type\":\"ui-base\",\"name\":\"Dashboard\",\"path\":\"\u002Fdashboard\",\"includeClientData\":true,\"acceptsClientConfig\":",[989,17579,17257],{},",\"showPathInSidebar\":false,\"showPageTitle\":false,\"titleBarStyle\":\"default\"},{\"id\":\"c68088445147719b\",\"type\":\"ui-theme\",\"name\":\"Theme Name\",\"colors\":{\"surface\":\"#ffffff\",\"primary\":\"#0094ce\",\"bgPage\":\"#eeeeee\",\"groupBg\":\"#ffffff\",\"groupOutline\":\"#cccccc\"}},{\"id\":\"1e54acecec6bd411\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"596006fe79275d55\",\"name\":\"Output a debug once all images have been processed\",\"style\":{\"label\":true},\"nodes\":",[989,17582,17583],{},"\"c9de7384c9ca672f\",\"b073cd4970e6ddf2\",\"c1b52f44fd4260b3\"",",\"x\":1254,\"y\":4279,\"w\":392,\"h\":82},{\"id\":\"c9de7384c9ca672f\",\"type\":\"link in\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"1e54acecec6bd411\",\"name\":\"link in 7\",\"links\":",[989,17586,17587],{},"\"d80e5a54a7c5b2f8\"",",\"x\":1295,\"y\":4320,\"wires\":[[\"b073cd4970e6ddf2\"]]},{\"id\":\"b073cd4970e6ddf2\",\"type\":\"join\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"1e54acecec6bd411\",\"name\":\"\",\"mode\":\"auto\",\"build\":\"object\",\"property\":\"payload\",\"propertyType\":\"msg\",\"key\":\"topic\",\"joiner\":\"\\n\",\"joinerType\":\"str\",\"accumulate\":\"false\",\"timeout\":\"\",\"count\":\"\",\"reduceRight\":false,\"x\":1380,\"y\":4320,\"wires\":[[\"c1b52f44fd4260b3\"]]},{\"id\":\"c1b52f44fd4260b3\",\"type\":\"debug\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"1e54acecec6bd411\",\"name\":\"debug 141\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":1530,\"y\":4320,\"wires\":",[989,17590],{},"},{\"id\":\"99aaee673fc70bc2\",\"type\":\"group\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"596006fe79275d55\",\"name\":\"Inject the image files' names\",\"style\":{\"label\":true},\"nodes\":",[989,17593,17594],{},"\"11787d1ab6c8a9ec\",\"49b8f3cce48dd5a9\",\"a9958e1e4b07191a\",\"c452f250e1303c69\",\"08b30802899573a6\"",",\"x\":1254,\"y\":3759,\"w\":782,\"h\":122},{\"id\":\"11787d1ab6c8a9ec\",\"type\":\"inject\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"99aaee673fc70bc2\",\"name\":\"Inject\",\"props\":",[989,17597],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":true,\"onceDelay\":\"1\",\"topic\":\"\",\"x\":1350,\"y\":3800,\"wires\":[[\"c452f250e1303c69\"]]},{\"id\":\"49b8f3cce48dd5a9\",\"type\":\"split\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"99aaee673fc70bc2\",\"name\":\"\",\"splt\":\"\\n\",\"spltType\":\"str\",\"arraySplt\":1,\"arraySpltType\":\"len\",\"stream\":false,\"addname\":\"\",\"property\":\"payload\",\"x\":1910,\"y\":3800,\"wires\":[[\"a9958e1e4b07191a\"]]},{\"id\":\"a9958e1e4b07191a\",\"type\":\"link out\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"99aaee673fc70bc2\",\"name\":\"link out 4\",\"mode\":\"link\",\"links\":",[989,17600,17601],{},"\"2836914f9b643e34\"",",\"x\":1995,\"y\":3800,\"wires\":",[989,17604],{},"},{\"id\":\"c452f250e1303c69\",\"type\":\"change\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"99aaee673fc70bc2\",\"name\":\"Image file names as an array\",\"rules\":",[989,17607,5377,17608,17611],{},[989,17609,17610],{},"\"ff-logo-wordmark-light_4x.png\",\"screen-pseudo-overview-2QvTVle3Mr-384.avif\",\"nr-image-1.png\"","\",\"tot\":\"json\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":1720,\"y\":3800,\"wires\":[[\"49b8f3cce48dd5a9\"]]},{\"id\":\"08b30802899573a6\",\"type\":\"ui-event\",\"z\":\"d4aa6dd5b63a56de\",\"g\":\"99aaee673fc70bc2\",\"ui\":\"25f447d87d1ce5c9\",\"name\":\"Update images on dashboard open\",\"x\":1420,\"y\":3840,\"wires\":[[\"c452f250e1303c69\"]]}",[15,17614,17615],{},"I have also included some simple dashboard elements you can view alongside the images. Let's take a look at the dashboard:",[15,17617,17618],{},[239,17619],{"alt":17620,"src":17621,"title":17620},"The dashboard showing our images alongside other standard elements","\u002Fblog\u002F2023\u002F07\u002Fimages\u002Fthe-dashboard.gif",[15,17623,17624],{},"If you import these flows into Node-RED, you should see the images automatically loaded into the dashboard when you view it. You can also replace the URLs and file paths to try using some different images if you'd like to.",[19,17626,17628],{"id":17627},"more-things-to-try","More things to try",[15,17630,17631],{},"In this example, the images are static but it's simple to load images depending on the state of the flow. As mentioned in this article's introduction, you could display context aware images guiding the user of the dashboard to a specific location on a map, to complete a maintenance task. If you're interested in seeing examples of dynamic image loading please comment below.",[19,17633,2115],{"id":2114},[15,17635,17636],{},"Images can significantly enhance dashboards, but ensuring their proper display in different Node-RED hosting environments, especially within DevOps pipelines, can be challenging. The techniques discussed here enable effective use of images in dashboards, even within containerized setups. Additionally, if you are using FlowFuse, the new features simplify adding and managing static assets.\nI'd love to hear your comments and suggestions on this article. please tell us what you think about this article, and how you might use these techniques in the comments section below.",[1720,17638,17639],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":265,"searchDepth":266,"depth":266,"links":17641},[17642,17643,17655,17656,17657,17658,17659,17660,17661,17662],{"id":16824,"depth":274,"text":16825},{"id":16859,"depth":269,"text":16860,"children":17644},[17645],{"id":16871,"depth":274,"text":16872,"children":17646},[17647,17648,17649,17650,17651,17652,17653,17654],{"id":16875,"depth":1071,"text":16876},{"id":16892,"depth":1071,"text":16893},{"id":16909,"depth":1071,"text":16910},{"id":16924,"depth":1071,"text":16925},{"id":16937,"depth":1071,"text":16938},{"id":16961,"depth":1071,"text":16962},{"id":16999,"depth":1071,"text":17000},{"id":17189,"depth":1071,"text":17190},{"id":17264,"depth":269,"text":17265},{"id":17274,"depth":269,"text":17275},{"id":17281,"depth":269,"text":17282},{"id":17305,"depth":269,"text":17306},{"id":17354,"depth":269,"text":17355},{"id":17366,"depth":269,"text":17367},{"id":17627,"depth":269,"text":17628},{"id":2114,"depth":269,"text":2115},{"type":653,"title":17664,"description":17665},"Start Building Better Node-RED Dashboards","Sign up for FlowFuse and use the Static Asset Service to easily add and manage images in your Node-RED dashboards, no filesystem access required.","2023-07-21","Learn to enhance Node-RED dashboards with images using FlowFuse. Pull images from URLs, store locally, and serve them in your dashboards.","blog\u002F2023\u002F07\u002Fimages\u002Fadd-images-in-node-red-header.png",{"keywords":17670,"excerpt":17671},"node-red dashboard images, node-red static assets, flowfuse static asset service, base64 image node-red, node-red image display, dashboard image upload, node-red docker images",{"type":12,"value":17672},[17673],[15,17674,16807],{},"\u002Fblog\u002F2023\u002F07\u002Fimages-in-node-red-dashboards",{"title":16800,"description":17667},{"loc":17675},"blog\u002F2023\u002F07\u002Fimages-in-node-red-dashboards","Import your images into your Node-RED dashboards, wherever you are running your instances",[487,302,3010,303,2164],"This guide covers multiple methods for displaying images in Node-RED dashboards, including pulling from URLs, encoding files as base64, and serving them via FlowFuse's Static Asset Service. The Static Asset Service approach is the simplest option for containerized environments like Docker or Kubernetes where writing to the local filesystem is not practical.","NUoZ4VyBD5HJgjU5f1aRVQsgRJCDloMl8-mRvrvKhjo",{"id":17684,"title":17685,"authors":17686,"body":17687,"cta":3,"date":17752,"description":17753,"extension":287,"image":17754,"lastUpdated":3,"meta":17755,"navigation":295,"path":17760,"seo":17761,"sitemap":17762,"stem":17763,"subtitle":17764,"tags":17765,"tldr":3,"video":3,"__hash__":17768},"blog\u002Fblog\u002F2023\u002F06\u002Fdashboard-announcement.md","The Next Step in Data Visualization - Announcing the Successor to the Node-RED Dashboard",[309,16634],{"type":12,"value":17688,"toc":17745},[17689,17692,17695,17699,17702,17706,17709,17713,17721,17724,17728,17735,17739,17742],[15,17690,17691],{},"For the past several years, the Node-RED Dashboard has been an indispensable tool for many Node-RED users. It has offered a seamless way to create live dashboards, enabling the quick and intuitive creation of user interfaces for Node-RED flows. However, as the saying goes, \"all good things must come to an end.\"",[15,17693,17694],{},"We at FlowFuse have identified a significant need for a modern, interactive data visualization and dashboard solution. Having evaluated a wide range of options, we've decided to embark on an exciting journey: the creation of what we hope becomes the official successor to the Node-RED Dashboard.",[19,17696,17698],{"id":17697},"the-problem-at-hand","The Problem at Hand",[15,17700,17701],{},"The original Node-RED Dashboard is based on Angular v1, which is no longer maintained. Although small patches have been and will continue to be applied on a \"best can do\" basis, there will be no major feature upgrades. The lack of ongoing maintenance and updates has the potential to lead to underlying security breakages, a risk we are not comfortable taking. We have recognized the need to innovate and adapt, which is why we are creating a completely new project to replace the existing Node-RED Dashboard.",[19,17703,17705],{"id":17704},"the-solution","The Solution",[15,17707,17708],{},"The successor to the Node-RED Dashboard will be a completely new project, published as a separate package. This new project will take the reins from the old dashboard and guide us into the future with the support and blessing of the existing dashboard maintainers. The Node-RED community can rest assured that the project will stay under the Apache 2.0 licence and keep intact the core principles of open-source and community-driven development.",[19,17710,17712],{"id":17711},"community-involvement-and-open-source-contribution","Community Involvement and Open Source Contribution",[15,17714,17715,17716,17720],{},"We believe in the power of the community, and we want your feedback. If there are features you'd like to see or improvements you think can be made, we invite you to open a ",[256,17717,17719],{"href":3656,"rel":17718},[402],"Github issue",". Your insights and suggestions will be invaluable in shaping the future of this project. Contributions from the community are not just welcome, but highly encouraged. We believe that the strength of a project is proportional to the strength of its community.",[15,17722,17723],{},"In our commitment to transparency and collaboration, we will be documenting all major decision-making processes and sharing the details here in our blog as they become available. By working closely with additional Node-RED key figures like Dave Conway-Jones, and by making our development process as open and collaborative as possible, we aim to ensure that the successor to the Node-RED Dashboard lives up to the high standards set by the original, while also introducing innovative features and enhancements.",[19,17725,17727],{"id":17726},"join-the-team","Join the Team",[15,17729,17730,17731],{},"Are you a developer looking for a new challenge? We are searching for a freelancer to help us with the development of the first version of the new dashboard. This is a 2-3 month project that provides an exciting opportunity to contribute to the future of data visualization and Node-RED. If you're interested, ",[256,17732,17734],{"href":16598,"rel":17733},[402],"we'd love to hear from you.",[19,17736,17738],{"id":17737},"charting-the-course","Charting the Course",[15,17740,17741],{},"As we embark on this new journey, we are excited about the potential of the successor to the Node-RED Dashboard. The road ahead will be filled with challenges, but we are confident that with the help of the community, and a dedicated team, we will create a tool that surpasses its predecessor in every way.",[15,17743,17744],{},"Join us on this exciting journey as we innovate, create, and redefine the future of data visualization with the successor to the Node-RED Dashboard.",{"title":265,"searchDepth":266,"depth":266,"links":17746},[17747,17748,17749,17750,17751],{"id":17697,"depth":269,"text":17698},{"id":17704,"depth":269,"text":17705},{"id":17711,"depth":269,"text":17712},{"id":17726,"depth":269,"text":17727},{"id":17737,"depth":269,"text":17738},"2023-06-21","This article unveils FlowFuse's plans to build the successor to the Node-RED Dashboard.","\u002Fblog\u002F2023\u002F06\u002Fimages\u002Fnode-red-dashboard.png",{"excerpt":17756},{"type":12,"value":17757},[17758],[15,17759,17691],{},"\u002Fblog\u002F2023\u002F06\u002Fdashboard-announcement",{"title":17685,"description":17753},{"loc":17760},"blog\u002F2023\u002F06\u002Fdashboard-announcement","FlowFuse's Journey Towards a New Node-RED Dashboard",[487,303,17766,17767],"nodered dashboard announcement","nodered dashboard depreciated","9vu5D-fiqqOLGmESyZtx5YpWyL_qXfuTq3OjLzgiZDE",{"id":17770,"title":17771,"authors":17772,"body":17773,"cta":3,"date":18019,"description":18020,"extension":287,"image":18021,"lastUpdated":3,"meta":18022,"navigation":295,"path":18027,"seo":18028,"sitemap":18029,"stem":18030,"subtitle":18031,"tags":18032,"tldr":3,"video":3,"__hash__":18034},"blog\u002Fblog\u002F2023\u002F06\u002F3-quick-node-red-tips-7.md","Node-RED Tips - Dashboard Edition",[16802],{"type":12,"value":17774,"toc":18014},[17775,17778,17785,17789,17792,17795,17798,17801,17807,17810,17879,17883,17886,17892,17895,17898,17922,17926,17929,17932,17938,17941,17944,17970,17978],[15,17776,17777],{},"There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.",[15,17779,17780,17781,17784],{},"In this Node-RED Tips article, we are going to focus on ",[256,17782,2228],{"href":2226,"rel":17783},[402],". Dashboard is a great tool for creating HMI (Human Machine Interfaces), it's also the most popular custom node for Node-RED with thousands of downloads per week.",[82,17786,17788],{"id":17787},"_1-responsive-layouts-almost","1. Responsive layouts (almost)",[15,17790,17791],{},"Responsive design is the ability for a webpage to change its content to best fit the features of a device used to view the page. For example, when viewing a graph on a mobile phone or a laptop the available screen space differs significantly in size as well as aspect-ratio.",[15,17793,17794],{},"Dashboard doesn't offer the feature to change graph sizes based on the screen of a viewing device. That being said, there is one trick you can use to make your dashboards a lot more useful on small and large screens alike.",[15,17796,17797],{},"Place your content into Dashboard 'groups', those groups can make use of wider screens by sitting side by side where the screen is big enough while stacking vertically on smaller devices.",[15,17799,17800],{},"The image below shows what happens when you change the screen size for this dashboard.",[15,17802,17803],{},[239,17804],{"alt":17805,"src":17806,"title":17805},"Changing the aspect ratio of the screen","\u002Fblog\u002F2023\u002F06\u002Fimages\u002Fresponsive.gif",[15,17808,17809],{},"If you'd like to try this out on your own Node-RED, you can import the flow below.",[15,17811,17812,17813,5411],{},"{% renderFlow 500 %}\n",[989,17814,17815,17816,17818,17819,17822,17823,17826,17827,17829,17830,17833,17834,17836,17837,17822,17839,17841,17842,17844,17845,17847,17848,17850,17851,17822,17853,17855,17856,17858,17859,17861,17862,17864,17865,17822,17867,17869,17870,17872,17873,17875,17876,17878],{},"{\"id\":\"e351b1251dfbc2f7\",\"type\":\"tab\",\"label\":\"Flow 1\",\"disabled\":false,\"info\":\"\",\"env\":",[989,17817],{},"},{\"id\":\"d388b48fcbed93a1\",\"type\":\"ui_gauge\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"ba1ff527abfa5261\",\"order\":2,\"width\":0,\"height\":0,\"gtype\":\"gage\",\"title\":\"gauge\",\"label\":\"units\",\"format\":\"",[17820,17821],"binding",{"value":6731},"\",\"min\":0,\"max\":\"100\",\"colors\":",[989,17824,17825],{},"\"#00b500\",\"#e6e600\",\"#ca3838\"",",\"seg1\":\"\",\"seg2\":\"\",\"diff\":false,\"className\":\"\",\"x\":350,\"y\":80,\"wires\":",[989,17828],{},"},{\"id\":\"80780894450cfb6d\",\"type\":\"ui_button\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"ba1ff527abfa5261\",\"order\":1,\"width\":0,\"height\":0,\"passthru\":false,\"label\":\"Update\",\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"x\":80,\"y\":80,\"wires\":[[\"49e78ff51c3a1ea3\"]]},{\"id\":\"07b44990e5d5b5f6\",\"type\":\"ui_chart\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"ba1ff527abfa5261\",\"order\":3,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"60\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,17831,17832],{},"\"#1f77b4\",\"#aec7e8\",\"#ff7f0e\",\"#2ca02c\",\"#98df8a\",\"#d62728\",\"#ff9896\",\"#9467bd\",\"#c5b0d5\"",",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":350,\"y\":120,\"wires\":[[]]},{\"id\":\"1482bcf69325aa92\",\"type\":\"inject\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"props\":",[989,17835],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":90,\"y\":120,\"wires\":[[\"49e78ff51c3a1ea3\"]]},{\"id\":\"49e78ff51c3a1ea3\",\"type\":\"random\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"low\":\"0\",\"high\":\"100\",\"inte\":\"true\",\"property\":\"payload\",\"x\":220,\"y\":100,\"wires\":[[\"d388b48fcbed93a1\",\"07b44990e5d5b5f6\"]]},{\"id\":\"38996d8eb9f6535d\",\"type\":\"ui_gauge\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"f6052a3dccc77ea3\",\"order\":2,\"width\":0,\"height\":0,\"gtype\":\"gage\",\"title\":\"gauge\",\"label\":\"units\",\"format\":\"",[17820,17838],{"value":6731},[989,17840,17825],{},",\"seg1\":\"\",\"seg2\":\"\",\"diff\":false,\"className\":\"\",\"x\":350,\"y\":240,\"wires\":",[989,17843],{},"},{\"id\":\"cf5599fbda28e614\",\"type\":\"ui_button\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"f6052a3dccc77ea3\",\"order\":1,\"width\":0,\"height\":0,\"passthru\":false,\"label\":\"Update\",\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"x\":80,\"y\":240,\"wires\":[[\"f093c63e17a620ba\"]]},{\"id\":\"936438ebf9eef986\",\"type\":\"ui_chart\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"f6052a3dccc77ea3\",\"order\":3,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"60\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,17846,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":350,\"y\":280,\"wires\":[[]]},{\"id\":\"60a40faa335f943e\",\"type\":\"inject\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"props\":",[989,17849],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":90,\"y\":280,\"wires\":[[\"f093c63e17a620ba\"]]},{\"id\":\"f093c63e17a620ba\",\"type\":\"random\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"low\":\"0\",\"high\":\"100\",\"inte\":\"true\",\"property\":\"payload\",\"x\":220,\"y\":260,\"wires\":[[\"38996d8eb9f6535d\",\"936438ebf9eef986\"]]},{\"id\":\"e284b90164e648e6\",\"type\":\"ui_gauge\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"1e4a72d62ed7564c\",\"order\":2,\"width\":0,\"height\":0,\"gtype\":\"gage\",\"title\":\"gauge\",\"label\":\"units\",\"format\":\"",[17820,17852],{"value":6731},[989,17854,17825],{},",\"seg1\":\"\",\"seg2\":\"\",\"diff\":false,\"className\":\"\",\"x\":350,\"y\":380,\"wires\":",[989,17857],{},"},{\"id\":\"cabe7a8150dbfaf6\",\"type\":\"ui_button\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"1e4a72d62ed7564c\",\"order\":1,\"width\":0,\"height\":0,\"passthru\":false,\"label\":\"Update\",\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"x\":80,\"y\":380,\"wires\":[[\"7b9862186954c4b3\"]]},{\"id\":\"ac116116c56e6c3c\",\"type\":\"ui_chart\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"1e4a72d62ed7564c\",\"order\":3,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"60\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,17860,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":350,\"y\":420,\"wires\":[[]]},{\"id\":\"bb27ef41380ec1d2\",\"type\":\"inject\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"props\":",[989,17863],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":90,\"y\":420,\"wires\":[[\"7b9862186954c4b3\"]]},{\"id\":\"7b9862186954c4b3\",\"type\":\"random\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"low\":\"0\",\"high\":\"100\",\"inte\":\"true\",\"property\":\"payload\",\"x\":220,\"y\":400,\"wires\":[[\"e284b90164e648e6\",\"ac116116c56e6c3c\"]]},{\"id\":\"e891f555bad51f01\",\"type\":\"ui_gauge\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"fcc4481a9e329266\",\"order\":2,\"width\":0,\"height\":0,\"gtype\":\"gage\",\"title\":\"gauge\",\"label\":\"units\",\"format\":\"",[17820,17866],{"value":6731},[989,17868,17825],{},",\"seg1\":\"\",\"seg2\":\"\",\"diff\":false,\"className\":\"\",\"x\":350,\"y\":500,\"wires\":",[989,17871],{},"},{\"id\":\"fa090cd1a0e97885\",\"type\":\"ui_button\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"fcc4481a9e329266\",\"order\":1,\"width\":0,\"height\":0,\"passthru\":false,\"label\":\"Update\",\"tooltip\":\"\",\"color\":\"\",\"bgcolor\":\"\",\"className\":\"\",\"icon\":\"\",\"payload\":\"\",\"payloadType\":\"str\",\"topic\":\"topic\",\"topicType\":\"msg\",\"x\":80,\"y\":500,\"wires\":[[\"bb4e945a2a8e681c\"]]},{\"id\":\"1c3a8aa84dfc85fe\",\"type\":\"ui_chart\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"group\":\"fcc4481a9e329266\",\"order\":3,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"60\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,17874,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":350,\"y\":540,\"wires\":[[]]},{\"id\":\"796f79538c15dd66\",\"type\":\"inject\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"props\":",[989,17877],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":90,\"y\":540,\"wires\":[[\"bb4e945a2a8e681c\"]]},{\"id\":\"bb4e945a2a8e681c\",\"type\":\"random\",\"z\":\"e351b1251dfbc2f7\",\"name\":\"\",\"low\":\"0\",\"high\":\"100\",\"inte\":\"true\",\"property\":\"payload\",\"x\":220,\"y\":520,\"wires\":[[\"e891f555bad51f01\",\"1c3a8aa84dfc85fe\"]]},{\"id\":\"ba1ff527abfa5261\",\"type\":\"ui_group\",\"name\":\"Machine 1\",\"tab\":\"39383a7a648193dd\",\"order\":1,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"f6052a3dccc77ea3\",\"type\":\"ui_group\",\"name\":\"Machine 2\",\"tab\":\"39383a7a648193dd\",\"order\":2,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"1e4a72d62ed7564c\",\"type\":\"ui_group\",\"name\":\"Machine 3\",\"tab\":\"39383a7a648193dd\",\"order\":3,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"fcc4481a9e329266\",\"type\":\"ui_group\",\"name\":\"Machine 4\",\"tab\":\"39383a7a648193dd\",\"order\":4,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"39383a7a648193dd\",\"type\":\"ui_tab\",\"name\":\"Node-RED Tips\",\"icon\":\"dashboard\",\"disabled\":false,\"hidden\":false}",[82,17880,17882],{"id":17881},"_2-add-more-than-one-series-of-data-to-a-line-chart","2. Add more than one series of data to a line chart",[15,17884,17885],{},"Being able to add more than one series of data to a single chart can make the data far more useful. One great way to use this is to compare the same data from different sensors. In this example I'm going to show the external and internal temperature at a location on the same chart.",[15,17887,17888],{},[239,17889],{"alt":17890,"src":17891,"title":17890},"Graphing two series on the same line chart","\u002Fblog\u002F2023\u002F06\u002Fimages\u002Ftemp-graph.png",[15,17893,17894],{},"To do this you need to give a different msg.topic to each series, you can add that using a change node before passing the data to the chart.",[15,17896,17897],{},"If you'd like to view this chart on your own Node-RED, you can import the flow below.",[15,17899,5928,17900,5411],{},[989,17901,17902,17903,17905,17906,17386,17908,17921],{},"{\"id\":\"3eb08d4843164efc\",\"type\":\"ui_chart\",\"z\":\"58569b35dacd54f3\",\"name\":\"\",\"group\":\"41e847ff22249c0e\",\"order\":3,\"width\":\"12\",\"height\":\"5\",\"label\":\"Celsius\",\"chartType\":\"line\",\"legend\":\"true\",\"xformat\":\"dd HH:mm\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"604800\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,17904,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":280,\"y\":180,\"wires\":[[]]},{\"id\":\"c4a13220356f76d3\",\"type\":\"inject\",\"z\":\"58569b35dacd54f3\",\"name\":\"\",\"props\":",[989,17907,5944],{},[989,17909,17910,17911,17914,17915,17918,17919,4425],{},"{\"series\":",[989,17912,17913],{},"\"inside\",\"outside\"",",\"data\":[[{\"x\":1685015544647,\"y\":20.8},{\"x\":1685015844687,\"y\":20.8},{\"x\":1685016144791,\"y\":20.8},{\"x\":1685016444933,\"y\":20.8},{\"x\":1685016745032,\"y\":20.8},{\"x\":1685017045123,\"y\":20.8},{\"x\":1685017345223,\"y\":20.8},{\"x\":1685017645339,\"y\":20.8},{\"x\":1685017945424,\"y\":20.8},{\"x\":1685018245500,\"y\":20.8},{\"x\":1685018545670,\"y\":20.8},{\"x\":1685018860580,\"y\":20.8},{\"x\":1685019160814,\"y\":20.8},{\"x\":1685019460832,\"y\":20.8},{\"x\":1685019760943,\"y\":20.8},{\"x\":1685020061037,\"y\":20.8},{\"x\":1685020361249,\"y\":20.8},{\"x\":1685020661264,\"y\":20.8},{\"x\":1685020961381,\"y\":20.8},{\"x\":1685021261473,\"y\":20.8},{\"x\":1685021561721,\"y\":20.8},{\"x\":1685021876580,\"y\":20.6},{\"x\":1685022176696,\"y\":20.7},{\"x\":1685022476852,\"y\":20.8},{\"x\":1685022776957,\"y\":20.8},{\"x\":1685023077032,\"y\":20.8},{\"x\":1685023377120,\"y\":20.8},{\"x\":1685023677234,\"y\":20.8},{\"x\":1685023977339,\"y\":20.8},{\"x\":1685024277455,\"y\":20.8},{\"x\":1685024577576,\"y\":20.8},{\"x\":1685024892578,\"y\":20.8},{\"x\":1685025192616,\"y\":20.8},{\"x\":1685025492757,\"y\":20.8},{\"x\":1685025792847,\"y\":20.7},{\"x\":1685026092949,\"y\":20.8},{\"x\":1685026393052,\"y\":20.8},{\"x\":1685026693174,\"y\":20.8},{\"x\":1685026993234,\"y\":20.8},{\"x\":1685027293387,\"y\":20.8},{\"x\":1685027593514,\"y\":20.8},{\"x\":1685027908550,\"y\":20.8},{\"x\":1685028208624,\"y\":20.8},{\"x\":1685028508708,\"y\":20.8},{\"x\":1685028808828,\"y\":20.8},{\"x\":1685029108909,\"y\":20.8},{\"x\":1685029409026,\"y\":20.8},{\"x\":1685029709096,\"y\":20.8},{\"x\":1685030009262,\"y\":20.8},{\"x\":1685030309361,\"y\":20.8},{\"x\":1685030609541,\"y\":20.8},{\"x\":1685030924565,\"y\":20.8},{\"x\":1685031239588,\"y\":20.8},{\"x\":1685031539702,\"y\":20.8},{\"x\":1685031839784,\"y\":20.8},{\"x\":1685032139922,\"y\":20.8},{\"x\":1685032440027,\"y\":20.8},{\"x\":1685032740134,\"y\":20.6},{\"x\":1685033040252,\"y\":20.7},{\"x\":1685033340317,\"y\":20.5},{\"x\":1685033640450,\"y\":20.5},{\"x\":1685033940507,\"y\":20.6},{\"x\":1685034240592,\"y\":20.5},{\"x\":1685034540633,\"y\":20.4},{\"x\":1685034840784,\"y\":20.4},{\"x\":1685035140888,\"y\":20.5},{\"x\":1685035441026,\"y\":20.4},{\"x\":1685035741107,\"y\":20.5},{\"x\":1685036041205,\"y\":20.5},{\"x\":1685036341328,\"y\":20.5},{\"x\":1685036641457,\"y\":20.5},{\"x\":1685036941583,\"y\":20.4},{\"x\":1685037256578,\"y\":20.5},{\"x\":1685037556715,\"y\":20.5},{\"x\":1685037856773,\"y\":20.5},{\"x\":1685038156902,\"y\":20.5},{\"x\":1685038457023,\"y\":20.5},{\"x\":1685038757090,\"y\":20.5},{\"x\":1685039057219,\"y\":20.5},{\"x\":1685039357278,\"y\":20.5},{\"x\":1685039657449,\"y\":20.5},{\"x\":1685039957553,\"y\":20.5},{\"x\":1685040257570,\"y\":20.5},{\"x\":1685040557615,\"y\":20.5},{\"x\":1685040857735,\"y\":20.4},{\"x\":1685041157843,\"y\":20.4},{\"x\":1685041457971,\"y\":20.5},{\"x\":1685041758072,\"y\":20.5},{\"x\":1685042058154,\"y\":20.5},{\"x\":1685042358273,\"y\":20.5},{\"x\":1685042658392,\"y\":20.5},{\"x\":1685042958486,\"y\":20.6},{\"x\":1685043258518,\"y\":20.6},{\"x\":1685043558568,\"y\":20.6},{\"x\":1685043858688,\"y\":20.5},{\"x\":1685044158769,\"y\":20.5},{\"x\":1685044458908,\"y\":20.5},{\"x\":1685044758984,\"y\":20.5},{\"x\":1685045059095,\"y\":20.5},{\"x\":1685045359169,\"y\":20.5},{\"x\":1685045659320,\"y\":20.5},{\"x\":1685045959367,\"y\":20.5},{\"x\":1685046259469,\"y\":20.7},{\"x\":1685046559497,\"y\":20.6},{\"x\":1685046859589,\"y\":20.5},{\"x\":1685047159647,\"y\":20.6},{\"x\":1685047459714,\"y\":20.6},{\"x\":1685047759793,\"y\":20.7},{\"x\":1685048059921,\"y\":20.7},{\"x\":1685048359994,\"y\":20.6},{\"x\":1685048659997,\"y\":20.7},{\"x\":1685048960056,\"y\":20.7},{\"x\":1685049260070,\"y\":20.8},{\"x\":1685049560116,\"y\":20.8},{\"x\":1685049860167,\"y\":20.8},{\"x\":1685050160212,\"y\":20.8},{\"x\":1685050460281,\"y\":20.8},{\"x\":1685050760368,\"y\":20.8},{\"x\":1685051060400,\"y\":20.7},{\"x\":1685051360435,\"y\":20.8},{\"x\":1685051660553,\"y\":20.8},{\"x\":1685051960585,\"y\":20.8},{\"x\":1685052260665,\"y\":20.8},{\"x\":1685052560675,\"y\":20.8},{\"x\":1685052860700,\"y\":20.7},{\"x\":1685053160749,\"y\":20.8},{\"x\":1685053460790,\"y\":20.8},{\"x\":1685053760855,\"y\":20.7},{\"x\":1685054060931,\"y\":20.7},{\"x\":1685054361019,\"y\":20.7},{\"x\":1685054661030,\"y\":20.7},{\"x\":1685054961121,\"y\":20.7},{\"x\":1685055261227,\"y\":20.7},{\"x\":1685055576250,\"y\":20.7},{\"x\":1685055891289,\"y\":20.5},{\"x\":1685056191290,\"y\":20.6},{\"x\":1685056491397,\"y\":20.7},{\"x\":1685056791444,\"y\":20.7},{\"x\":1685057091489,\"y\":20.7},{\"x\":1685057391516,\"y\":20.7},{\"x\":1685057691607,\"y\":20.7},{\"x\":1685057991660,\"y\":20.7},{\"x\":1685058291741,\"y\":20.6},{\"x\":1685058606760,\"y\":20.5},{\"x\":1685058906775,\"y\":20.5},{\"x\":1685059206866,\"y\":20.5},{\"x\":1685059506900,\"y\":20.5},{\"x\":1685059806979,\"y\":20.4},{\"x\":1685060107035,\"y\":20.5},{\"x\":1685060407099,\"y\":20.5},{\"x\":1685060707132,\"y\":20.4},{\"x\":1685061007199,\"y\":20.5},{\"x\":1685061307220,\"y\":20.4},{\"x\":1685061607228,\"y\":20.5},{\"x\":1685061907286,\"y\":20.6},{\"x\":1685062207289,\"y\":20.7},{\"x\":1685062507315,\"y\":20.6},{\"x\":1685062807355,\"y\":20.7},{\"x\":1685063107395,\"y\":20.7},{\"x\":1685063407413,\"y\":20.7},{\"x\":1685063707465,\"y\":20.7},{\"x\":1685064007492,\"y\":20.7},{\"x\":1685064307565,\"y\":20.7},{\"x\":1685064607587,\"y\":20.7},{\"x\":1685064907609,\"y\":20.7},{\"x\":1685065207618,\"y\":20.5},{\"x\":1685065507642,\"y\":20.4},{\"x\":1685065807670,\"y\":20.4},{\"x\":1685066107679,\"y\":20.4},{\"x\":1685066407758,\"y\":20.5},{\"x\":1685066707760,\"y\":20.3},{\"x\":1685067007798,\"y\":20.4},{\"x\":1685067307865,\"y\":20.4},{\"x\":1685067622903,\"y\":20.4},{\"x\":1685067937922,\"y\":20.4},{\"x\":1685068237945,\"y\":20.4},{\"x\":1685068537971,\"y\":20.3},{\"x\":1685068838009,\"y\":20.3},{\"x\":1685069138060,\"y\":20.2},{\"x\":1685069453065,\"y\":20.3},{\"x\":1685069753104,\"y\":20.3},{\"x\":1685070053108,\"y\":20.2},{\"x\":1685070353140,\"y\":20.3},{\"x\":1685070653170,\"y\":20.2},{\"x\":1685070953219,\"y\":20.2},{\"x\":1685071253232,\"y\":20.2},{\"x\":1685071553258,\"y\":20},{\"x\":1685071853260,\"y\":20},{\"x\":1685072153324,\"y\":20.2},{\"x\":1685072453329,\"y\":20.2},{\"x\":1685072753343,\"y\":19.9},{\"x\":1685073053359,\"y\":20},{\"x\":1685073353402,\"y\":19.9},{\"x\":1685073653411,\"y\":19.9},{\"x\":1685073953453,\"y\":20},{\"x\":1685074253462,\"y\":20},{\"x\":1685074553509,\"y\":20},{\"x\":1685074853529,\"y\":20},{\"x\":1685075153554,\"y\":20},{\"x\":1685075453556,\"y\":20},{\"x\":1685075753590,\"y\":20},{\"x\":1685076053642,\"y\":20.2},{\"x\":1685076368644,\"y\":20},{\"x\":1685076668676,\"y\":20.2},{\"x\":1685076968685,\"y\":20.3},{\"x\":1685077268752,\"y\":20.3},{\"x\":1685077583729,\"y\":20.3},{\"x\":1685077883800,\"y\":20.2},{\"x\":1685078198760,\"y\":20.2},{\"x\":1685078498762,\"y\":20.4},{\"x\":1685078798782,\"y\":20.4},{\"x\":1685079098837,\"y\":20.5},{\"x\":1685079398903,\"y\":20.5},{\"x\":1685079698965,\"y\":20.6},{\"x\":1685079999013,\"y\":20.7},{\"x\":1685080299091,\"y\":20.8},{\"x\":1685080599234,\"y\":20.8},{\"x\":1685080899276,\"y\":20.8},{\"x\":1685081199340,\"y\":20.8},{\"x\":1685081499403,\"y\":20.8},{\"x\":1685081799441,\"y\":20.8},{\"x\":1685082099467,\"y\":20.9},{\"x\":1685082399584,\"y\":20.8},{\"x\":1685082699624,\"y\":21},{\"x\":1685082999670,\"y\":21},{\"x\":1685083299724,\"y\":21.2},{\"x\":1685083599810,\"y\":21.2},{\"x\":1685083899884,\"y\":21.2},{\"x\":1685084199935,\"y\":21.2},{\"x\":1685084500001,\"y\":21.3},{\"x\":1685084800063,\"y\":21.4},{\"x\":1685085115072,\"y\":21.5},{\"x\":1685085415170,\"y\":21.5},{\"x\":1685085715226,\"y\":21.5},{\"x\":1685086015289,\"y\":21.5},{\"x\":1685086315365,\"y\":21.5},{\"x\":1685086615447,\"y\":21.5},{\"x\":1685086915501,\"y\":21.7},{\"x\":1685087215603,\"y\":21.7},{\"x\":1685087515642,\"y\":21.6},{\"x\":1685087815732,\"y\":21.6},{\"x\":1685088115759,\"y\":21.7},{\"x\":1685088415793,\"y\":21.9},{\"x\":1685088715840,\"y\":21.9},{\"x\":1685089015891,\"y\":21.9},{\"x\":1685089315950,\"y\":21.9},{\"x\":1685089616045,\"y\":21.9},{\"x\":1685089916094,\"y\":21.9},{\"x\":1685090216153,\"y\":21.9},{\"x\":1685090516202,\"y\":21.9},{\"x\":1685090816299,\"y\":21.9},{\"x\":1685091116304,\"y\":22},{\"x\":1685091416326,\"y\":22},{\"x\":1685091716409,\"y\":22},{\"x\":1685092016500,\"y\":22},{\"x\":1685092316555,\"y\":21.9},{\"x\":1685092616597,\"y\":21.9},{\"x\":1685092916687,\"y\":21.9},{\"x\":1685093216749,\"y\":21.9},{\"x\":1685093516770,\"y\":21.9},{\"x\":1685093816833,\"y\":21.8},{\"x\":1685094116862,\"y\":21.8},{\"x\":1685094416941,\"y\":21.9},{\"x\":1685094717014,\"y\":21.8},{\"x\":1685095017079,\"y\":21.8},{\"x\":1685095317146,\"y\":21.9},{\"x\":1685095617198,\"y\":21.9},{\"x\":1685095917267,\"y\":22},{\"x\":1685096217380,\"y\":22},{\"x\":1685096517436,\"y\":22.2},{\"x\":1685096817481,\"y\":22.1},{\"x\":1685097117519,\"y\":21.9},{\"x\":1685097417582,\"y\":21.9},{\"x\":1685097717607,\"y\":21.9},{\"x\":1685098017734,\"y\":21.9},{\"x\":1685098317791,\"y\":21.9},{\"x\":1685098617850,\"y\":21.9},{\"x\":1685098917939,\"y\":21.9},{\"x\":1685099218020,\"y\":21.9},{\"x\":1685099518088,\"y\":21.9},{\"x\":1685099818190,\"y\":21.9},{\"x\":1685100118269,\"y\":21.9},{\"x\":1685100418304,\"y\":21.9},{\"x\":1685100718355,\"y\":21.9},{\"x\":1685101018437,\"y\":22},{\"x\":1685101318544,\"y\":22.1},{\"x\":1685101618646,\"y\":22},{\"x\":1685101918720,\"y\":22},{\"x\":1685102218803,\"y\":22},{\"x\":1685102518914,\"y\":21.9},{\"x\":1685102818997,\"y\":21.9},{\"x\":1685103119093,\"y\":21.9},{\"x\":1685103419119,\"y\":21.9},{\"x\":1685103719183,\"y\":21.9},{\"x\":1685104019263,\"y\":21.9},{\"x\":1685104319361,\"y\":21.9},{\"x\":1685104619467,\"y\":21.9},{\"x\":1685104919565,\"y\":21.9},{\"x\":1685105219692,\"y\":21.9},{\"x\":1685105261657,\"y\":21.9},{\"x\":1685105275726,\"y\":21.9},{\"x\":1685105316848,\"y\":21.9},{\"x\":1685105388676,\"y\":21.9},{\"x\":1685105475001,\"y\":21.9},{\"x\":1685105501466,\"y\":21.9},{\"x\":1685105576628,\"y\":21.9},{\"x\":1685105627162,\"y\":21.9},{\"x\":1685105653330,\"y\":21.9},{\"x\":1685105684112,\"y\":21.9},{\"x\":1685105722222,\"y\":21.9},{\"x\":1685105769629,\"y\":21.9},{\"x\":1685105825666,\"y\":21.9},{\"x\":1685105889137,\"y\":21.9},{\"x\":1685105910507,\"y\":21.9},{\"x\":1685105970749,\"y\":21.9},{\"x\":1685106270828,\"y\":21.9},{\"x\":1685106570844,\"y\":21.9},{\"x\":1685106870845,\"y\":21.9},{\"x\":1685107170872,\"y\":21.9},{\"x\":1685107485846,\"y\":21.9},{\"x\":1685107785884,\"y\":21.9},{\"x\":1685108100859,\"y\":21.9},{\"x\":1685108400859,\"y\":21.9},{\"x\":1685108700881,\"y\":21.9},{\"x\":1685109000885,\"y\":21.9},{\"x\":1685109300898,\"y\":21.9},{\"x\":1685109615915,\"y\":21.8},{\"x\":1685109930873,\"y\":21.9},{\"x\":1685110230928,\"y\":21.9},{\"x\":1685110545931,\"y\":21.7},{\"x\":1685110845948,\"y\":21.7},{\"x\":1685111145989,\"y\":21.7},{\"x\":1685111460988,\"y\":21.7},{\"x\":1685111761062,\"y\":21.8},{\"x\":1685112061067,\"y\":21.6},{\"x\":1685112361107,\"y\":21.7},{\"x\":1685112661141,\"y\":21.7},{\"x\":1685112961145,\"y\":21.8},{\"x\":1685113261191,\"y\":21.8},{\"x\":1685113561195,\"y\":21.8},{\"x\":1685113861234,\"y\":21.8},{\"x\":1685114161272,\"y\":21.8},{\"x\":1685114461288,\"y\":21.7},{\"x\":1685114761326,\"y\":21.7},{\"x\":1685115061359,\"y\":21.7},{\"x\":1685115361389,\"y\":21.7},{\"x\":1685115661413,\"y\":21.6},{\"x\":1685115961522,\"y\":21.7},{\"x\":1685116276440,\"y\":21.7},{\"x\":1685116576471,\"y\":21.5},{\"x\":1685116876500,\"y\":21.5},{\"x\":1685117176511,\"y\":21.5},{\"x\":1685117476538,\"y\":21.6},{\"x\":1685117776599,\"y\":21.6},{\"x\":1685118091580,\"y\":21.8},{\"x\":1685118391620,\"y\":21.6},{\"x\":1685118691646,\"y\":21.7},{\"x\":1685118991656,\"y\":21.7},{\"x\":1685119291661,\"y\":21.5},{\"x\":1685119591684,\"y\":21.5},{\"x\":1685119891711,\"y\":21.5},{\"x\":1685120191732,\"y\":21.5},{\"x\":1685120491763,\"y\":21.5},{\"x\":1685120791797,\"y\":21.4},{\"x\":1685121091832,\"y\":21.2},{\"x\":1685121406802,\"y\":21.2},{\"x\":1685121706853,\"y\":21.1},{\"x\":1685122021885,\"y\":21.1},{\"x\":1685122336872,\"y\":21.2},{\"x\":1685122636878,\"y\":21.2},{\"x\":1685122936903,\"y\":21.1},{\"x\":1685123236933,\"y\":21},{\"x\":1685123536988,\"y\":21},{\"x\":1685123837007,\"y\":21.1},{\"x\":1685124137007,\"y\":21},{\"x\":1685124437098,\"y\":21},{\"x\":1685124737193,\"y\":21},{\"x\":1685125037270,\"y\":21},{\"x\":1685125337370,\"y\":20.9},{\"x\":1685125637493,\"y\":20.9},{\"x\":1685125937530,\"y\":21},{\"x\":1685126237627,\"y\":20.9},{\"x\":1685126537712,\"y\":20.8},{\"x\":1685126837733,\"y\":20.8},{\"x\":1685127137746,\"y\":20.8},{\"x\":1685127437870,\"y\":20.8},{\"x\":1685127737940,\"y\":20.8},{\"x\":1685128038026,\"y\":20.8},{\"x\":1685128338109,\"y\":20.8},{\"x\":1685128638215,\"y\":20.8},{\"x\":1685128938321,\"y\":20.8},{\"x\":1685129238409,\"y\":20.8},{\"x\":1685129538484,\"y\":20.8},{\"x\":1685129838514,\"y\":20.8},{\"x\":1685130138614,\"y\":20.8},{\"x\":1685130438644,\"y\":20.8},{\"x\":1685130738716,\"y\":20.8},{\"x\":1685131038856,\"y\":20.8},{\"x\":1685131338912,\"y\":20.8},{\"x\":1685131639028,\"y\":20.8},{\"x\":1685131939140,\"y\":20.8},{\"x\":1685132239222,\"y\":20.8},{\"x\":1685132539344,\"y\":20.8},{\"x\":1685132839390,\"y\":20.8},{\"x\":1685133154381,\"y\":20.8},{\"x\":1685133454402,\"y\":20.8},{\"x\":1685133754494,\"y\":20.8},{\"x\":1685134054557,\"y\":20.8},{\"x\":1685134354644,\"y\":20.8},{\"x\":1685134654753,\"y\":20.8},{\"x\":1685134954810,\"y\":20.8},{\"x\":1685135254894,\"y\":20.7},{\"x\":1685135554961,\"y\":20.8},{\"x\":1685135854990,\"y\":20.8},{\"x\":1685136155013,\"y\":20.8},{\"x\":1685136455070,\"y\":20.8},{\"x\":1685136755172,\"y\":20.8},{\"x\":1685137055242,\"y\":20.8},{\"x\":1685137355339,\"y\":20.8},{\"x\":1685137655440,\"y\":20.7},{\"x\":1685137955504,\"y\":20.7},{\"x\":1685138255592,\"y\":20.6},{\"x\":1685138555675,\"y\":20.6},{\"x\":1685138855742,\"y\":20.6},{\"x\":1685139155750,\"y\":20.6},{\"x\":1685139455841,\"y\":20.5},{\"x\":1685139755904,\"y\":20.6},{\"x\":1685140055961,\"y\":20.5},{\"x\":1685140356100,\"y\":20.6},{\"x\":1685140656187,\"y\":20.5},{\"x\":1685140956268,\"y\":20.4},{\"x\":1685141256384,\"y\":20.4},{\"x\":1685141556467,\"y\":20.4},{\"x\":1685141856547,\"y\":20.4},{\"x\":1685142156630,\"y\":20.3},{\"x\":1685142456678,\"y\":20.2},{\"x\":1685142756713,\"y\":20.3},{\"x\":1685143056833,\"y\":20.3},{\"x\":1685143356922,\"y\":20.3},{\"x\":1685143657019,\"y\":20.3},{\"x\":1685143957116,\"y\":20.2},{\"x\":1685144257203,\"y\":20.2},{\"x\":1685144557262,\"y\":20.1},{\"x\":1685144857393,\"y\":20.2},{\"x\":1685145157511,\"y\":20.2},{\"x\":1685145457515,\"y\":20.2},{\"x\":1685145757583,\"y\":20},{\"x\":1685146057687,\"y\":20},{\"x\":1685146357780,\"y\":20.1},{\"x\":1685146657878,\"y\":19.9},{\"x\":1685146957969,\"y\":19.9},{\"x\":1685147258066,\"y\":20},{\"x\":1685147558163,\"y\":20},{\"x\":1685147858255,\"y\":19.9},{\"x\":1685148158303,\"y\":19.9},{\"x\":1685148458377,\"y\":19.9},{\"x\":1685148758392,\"y\":19.9},{\"x\":1685149058441,\"y\":19.9},{\"x\":1685149358550,\"y\":19.9},{\"x\":1685149658652,\"y\":19.5},{\"x\":1685149958735,\"y\":19.5},{\"x\":1685150258816,\"y\":19.5},{\"x\":1685150558892,\"y\":19.5},{\"x\":1685150858996,\"y\":19.5},{\"x\":1685151159109,\"y\":19.5},{\"x\":1685151459166,\"y\":19.5},{\"x\":1685151759230,\"y\":19.5},{\"x\":1685152059291,\"y\":19.5},{\"x\":1685152359350,\"y\":19.5},{\"x\":1685152659430,\"y\":19.5},{\"x\":1685152959526,\"y\":19.5},{\"x\":1685153259622,\"y\":19.5},{\"x\":1685153559728,\"y\":19.5},{\"x\":1685153859883,\"y\":19.5},{\"x\":1685154159899,\"y\":19.5},{\"x\":1685154459974,\"y\":19.5},{\"x\":1685154760016,\"y\":19.5},{\"x\":1685155060096,\"y\":19.5},{\"x\":1685155360142,\"y\":19.5},{\"x\":1685155660284,\"y\":19.5},{\"x\":1685155960372,\"y\":19.5},{\"x\":1685156260469,\"y\":19.5},{\"x\":1685156560559,\"y\":19.5},{\"x\":1685156860664,\"y\":19.5},{\"x\":1685157160732,\"y\":19.5},{\"x\":1685157460827,\"y\":19.5},{\"x\":1685157760925,\"y\":19.5},{\"x\":1685158061041,\"y\":19.4},{\"x\":1685158361093,\"y\":19.4},{\"x\":1685158661174,\"y\":19.4},{\"x\":1685158961238,\"y\":19.4},{\"x\":1685159261356,\"y\":19.4},{\"x\":1685159561460,\"y\":19.4},{\"x\":1685159861591,\"y\":19.4},{\"x\":1685160161622,\"y\":19.5},{\"x\":1685160461727,\"y\":19.4},{\"x\":1685160761798,\"y\":19.3},{\"x\":1685161061899,\"y\":19.3},{\"x\":1685161361960,\"y\":19.3},{\"x\":1685161662030,\"y\":19.3},{\"x\":1685161962083,\"y\":19.2},{\"x\":1685162262205,\"y\":19.2},{\"x\":1685162562329,\"y\":19.2},{\"x\":1685162862420,\"y\":19.2},{\"x\":1685163162514,\"y\":19.3},{\"x\":1685163462630,\"y\":19.4},{\"x\":1685163762689,\"y\":19.5},{\"x\":1685164062785,\"y\":19.5},{\"x\":1685164362862,\"y\":19.5},{\"x\":1685164662929,\"y\":19.5},{\"x\":1685164962989,\"y\":19.5},{\"x\":1685165263080,\"y\":19.5},{\"x\":1685165563213,\"y\":19.5},{\"x\":1685165863284,\"y\":19.5},{\"x\":1685166163398,\"y\":19.7},{\"x\":1685166463432,\"y\":20},{\"x\":1685166763562,\"y\":20},{\"x\":1685167063657,\"y\":20.3},{\"x\":1685167363752,\"y\":20.3},{\"x\":1685167663818,\"y\":20.2},{\"x\":1685167963868,\"y\":20.4},{\"x\":1685168263959,\"y\":20.5},{\"x\":1685168564052,\"y\":20.7},{\"x\":1685168864152,\"y\":20.8},{\"x\":1685169164297,\"y\":20.8},{\"x\":1685169464371,\"y\":20.8},{\"x\":1685169764428,\"y\":20.9},{\"x\":1685170064553,\"y\":21},{\"x\":1685170364630,\"y\":20.8},{\"x\":1685170664689,\"y\":20.8},{\"x\":1685170964744,\"y\":20.9},{\"x\":1685171264839,\"y\":21},{\"x\":1685171564944,\"y\":21},{\"x\":1685171865046,\"y\":21.1},{\"x\":1685172165136,\"y\":21.1},{\"x\":1685172465216,\"y\":21.2},{\"x\":1685172765270,\"y\":21.5},{\"x\":1685173065378,\"y\":21.5},{\"x\":1685173365491,\"y\":21.5},{\"x\":1685173665574,\"y\":21.5},{\"x\":1685173965634,\"y\":21.5},{\"x\":1685174265651,\"y\":21.5},{\"x\":1685174565770,\"y\":21.5},{\"x\":1685174865842,\"y\":21.5},{\"x\":1685175165962,\"y\":21.5},{\"x\":1685175466056,\"y\":21.5},{\"x\":1685175766151,\"y\":21.6},{\"x\":1685176066247,\"y\":21.7},{\"x\":1685176366347,\"y\":21.6},{\"x\":1685176666421,\"y\":21.6},{\"x\":1685176966481,\"y\":21.7},{\"x\":1685177266535,\"y\":21.7},{\"x\":1685177566618,\"y\":21.7},{\"x\":1685177866715,\"y\":21.8},{\"x\":1685178166786,\"y\":21.7},{\"x\":1685178466868,\"y\":21.7},{\"x\":1685178766964,\"y\":21.8},{\"x\":1685179067013,\"y\":21.9},{\"x\":1685179367161,\"y\":21.9},{\"x\":1685179667226,\"y\":21.9},{\"x\":1685179967298,\"y\":21.9},{\"x\":1685180267304,\"y\":21.9},{\"x\":1685180567400,\"y\":21.9},{\"x\":1685180867474,\"y\":21.9},{\"x\":1685181167605,\"y\":21.9},{\"x\":1685181467661,\"y\":21.9},{\"x\":1685181767781,\"y\":21.9},{\"x\":1685182067847,\"y\":21.9},{\"x\":1685182367916,\"y\":21.9},{\"x\":1685182668010,\"y\":21.9},{\"x\":1685182968067,\"y\":21.9},{\"x\":1685183268142,\"y\":21.9},{\"x\":1685183568218,\"y\":21.9},{\"x\":1685183868264,\"y\":21.9},{\"x\":1685184168356,\"y\":22},{\"x\":1685184468449,\"y\":22},{\"x\":1685184768557,\"y\":22},{\"x\":1685185068624,\"y\":22.2},{\"x\":1685185368711,\"y\":22.1},{\"x\":1685185668784,\"y\":22.1},{\"x\":1685185968847,\"y\":22},{\"x\":1685186268953,\"y\":21.9},{\"x\":1685186568982,\"y\":21.9},{\"x\":1685186868996,\"y\":21.9},{\"x\":1685187169094,\"y\":21.9},{\"x\":1685187469146,\"y\":21.9},{\"x\":1685187769224,\"y\":21.9},{\"x\":1685188069250,\"y\":21.9},{\"x\":1685188369327,\"y\":21.9},{\"x\":1685188669411,\"y\":21.7},{\"x\":1685188969475,\"y\":21.7},{\"x\":1685189269500,\"y\":21.5},{\"x\":1685189569548,\"y\":21.5},{\"x\":1685189869583,\"y\":21.6},{\"x\":1685190169645,\"y\":21.7},{\"x\":1685190469717,\"y\":21.7},{\"x\":1685190769801,\"y\":21.7},{\"x\":1685191069848,\"y\":21.7},{\"x\":1685191369885,\"y\":21.7},{\"x\":1685191669980,\"y\":21.7},{\"x\":1685191970014,\"y\":21.7},{\"x\":1685192270055,\"y\":21.6},{\"x\":1685192570106,\"y\":21.7},{\"x\":1685192870150,\"y\":21.7},{\"x\":1685193170235,\"y\":21.6},{\"x\":1685193470249,\"y\":21.5},{\"x\":1685193770302,\"y\":21.5},{\"x\":1685194070311,\"y\":21.6},{\"x\":1685194370328,\"y\":21.7},{\"x\":1685194670393,\"y\":21.7},{\"x\":1685194985377,\"y\":21.7},{\"x\":1685195285440,\"y\":21.7},{\"x\":1685195585471,\"y\":21.7},{\"x\":1685195885473,\"y\":21.7},{\"x\":1685196185514,\"y\":21.6},{\"x\":1685196485562,\"y\":21.7},{\"x\":1685196800615,\"y\":21.7},{\"x\":1685197115572,\"y\":21.7},{\"x\":1685197415601,\"y\":21.7},{\"x\":1685197715640,\"y\":21.7},{\"x\":1685198015652,\"y\":21.7},{\"x\":1685198315706,\"y\":21.7},{\"x\":1685198615725,\"y\":21.7},{\"x\":1685198915775,\"y\":21.8},{\"x\":1685199215786,\"y\":21.8},{\"x\":1685199515831,\"y\":21.9},{\"x\":1685199815856,\"y\":21.8},{\"x\":1685200115858,\"y\":21.9},{\"x\":1685200415875,\"y\":21.8},{\"x\":1685200715913,\"y\":21.8},{\"x\":1685201015918,\"y\":21.8},{\"x\":1685201315964,\"y\":21.9},{\"x\":1685201616032,\"y\":21.9},{\"x\":1685201916044,\"y\":21.9},{\"x\":1685202231051,\"y\":21.9},{\"x\":1685202531062,\"y\":21.9},{\"x\":1685202831089,\"y\":21.8},{\"x\":1685203131095,\"y\":21.8},{\"x\":1685203431195,\"y\":21.8},{\"x\":1685203746138,\"y\":21.8},{\"x\":1685204046168,\"y\":21.8},{\"x\":1685204346182,\"y\":21.7},{\"x\":1685204646203,\"y\":21.8},{\"x\":1685204946241,\"y\":21.9},{\"x\":1685205246243,\"y\":21.9},{\"x\":1685205546262,\"y\":21.9},{\"x\":1685205846296,\"y\":21.9},{\"x\":1685206146312,\"y\":21.9},{\"x\":1685206446335,\"y\":21.9},{\"x\":1685206746375,\"y\":21.9},{\"x\":1685207046395,\"y\":21.9},{\"x\":1685207346549,\"y\":21.9},{\"x\":1685207661544,\"y\":21.9},{\"x\":1685207961647,\"y\":21.9},{\"x\":1685208261700,\"y\":21.9},{\"x\":1685208561766,\"y\":21.9},{\"x\":1685208861855,\"y\":21.9},{\"x\":1685209161943,\"y\":21.9},{\"x\":1685209462007,\"y\":21.9},{\"x\":1685209762097,\"y\":21.9},{\"x\":1685210077101,\"y\":21.9},{\"x\":1685210377152,\"y\":21.9},{\"x\":1685210677231,\"y\":21.9},{\"x\":1685210977296,\"y\":21.9},{\"x\":1685211277406,\"y\":21.9},{\"x\":1685211577537,\"y\":21.9},{\"x\":1685211877620,\"y\":21.9},{\"x\":1685212177660,\"y\":21.9},{\"x\":1685212477797,\"y\":21.9},{\"x\":1685212777837,\"y\":21.9},{\"x\":1685213077881,\"y\":21.9},{\"x\":1685213377932,\"y\":21.9},{\"x\":1685213677997,\"y\":21.9},{\"x\":1685213978205,\"y\":21.9},{\"x\":1685214293200,\"y\":21.9},{\"x\":1685214593270,\"y\":21.9},{\"x\":1685214893375,\"y\":21.9},{\"x\":1685215193482,\"y\":21.9},{\"x\":1685215493529,\"y\":21.8},{\"x\":1685215793531,\"y\":21.9},{\"x\":1685216093643,\"y\":21.9},{\"x\":1685216393738,\"y\":22},{\"x\":1685216693784,\"y\":21.9},{\"x\":1685216993880,\"y\":21.9},{\"x\":1685217293962,\"y\":21.7},{\"x\":1685217594100,\"y\":21.7},{\"x\":1685217894151,\"y\":21.7},{\"x\":1685218194256,\"y\":21.6},{\"x\":1685218494376,\"y\":21.5},{\"x\":1685218794467,\"y\":21.5},{\"x\":1685219094477,\"y\":21.5},{\"x\":1685219394675,\"y\":21.5},{\"x\":1685219709688,\"y\":21.5},{\"x\":1685220009789,\"y\":21.5},{\"x\":1685220309889,\"y\":21.5},{\"x\":1685220609986,\"y\":21.4},{\"x\":1685220910080,\"y\":21.5},{\"x\":1685221210236,\"y\":21.5},{\"x\":1685221510267,\"y\":21.5},{\"x\":1685221810331,\"y\":21.5},{\"x\":1685222110381,\"y\":21.4},{\"x\":1685222410481,\"y\":21.4},{\"x\":1685222710598,\"y\":21.3},{\"x\":1685223010661,\"y\":21.5},{\"x\":1685223310759,\"y\":21.5},{\"x\":1685223610881,\"y\":21.5},{\"x\":1685223911009,\"y\":21.5},{\"x\":1685224211106,\"y\":21.5},{\"x\":1685224511191,\"y\":21.5},{\"x\":1685224811272,\"y\":21.4},{\"x\":1685225111309,\"y\":21.4},{\"x\":1685225411398,\"y\":21.3},{\"x\":1685225711438,\"y\":21.2},{\"x\":1685226011552,\"y\":21.2},{\"x\":1685226311659,\"y\":21.2},{\"x\":1685226611773,\"y\":21.2},{\"x\":1685226911876,\"y\":21.2},{\"x\":1685227211995,\"y\":21.2},{\"x\":1685227512070,\"y\":21.2},{\"x\":1685227812175,\"y\":21.2},{\"x\":1685228112250,\"y\":21.2},{\"x\":1685228412314,\"y\":21},{\"x\":1685228712352,\"y\":21},{\"x\":1685229012470,\"y\":21},{\"x\":1685229312587,\"y\":21},{\"x\":1685229612662,\"y\":21.1},{\"x\":1685229912736,\"y\":21},{\"x\":1685230212847,\"y\":20.9},{\"x\":1685230512904,\"y\":21},{\"x\":1685230813034,\"y\":21},{\"x\":1685231113081,\"y\":21},{\"x\":1685231413122,\"y\":20.8},{\"x\":1685231713183,\"y\":20.8},{\"x\":1685232013342,\"y\":20.8},{\"x\":1685232328321,\"y\":20.8},{\"x\":1685232628419,\"y\":20.8},{\"x\":1685232928528,\"y\":20.8},{\"x\":1685233228604,\"y\":20.8},{\"x\":1685233528687,\"y\":20.8},{\"x\":1685233828743,\"y\":20.8},{\"x\":1685234128809,\"y\":20.8},{\"x\":1685234428883,\"y\":20.8},{\"x\":1685234728963,\"y\":20.8},{\"x\":1685235028977,\"y\":20.8},{\"x\":1685235329064,\"y\":20.8},{\"x\":1685235629163,\"y\":20.8},{\"x\":1685235929251,\"y\":20.8},{\"x\":1685236229341,\"y\":20.8},{\"x\":1685236529423,\"y\":20.7},{\"x\":1685236829513,\"y\":20.7},{\"x\":1685237129612,\"y\":20.8},{\"x\":1685237429697,\"y\":20.7},{\"x\":1685237729771,\"y\":20.7},{\"x\":1685238029832,\"y\":20.5},{\"x\":1685238329902,\"y\":20.5},{\"x\":1685238629974,\"y\":20.5},{\"x\":1685238930096,\"y\":20.5},{\"x\":1685239230144,\"y\":20.6},{\"x\":1685239530225,\"y\":20.6},{\"x\":1685239830331,\"y\":20.6},{\"x\":1685240130366,\"y\":20.6},{\"x\":1685240430509,\"y\":20.5},{\"x\":1685240730597,\"y\":20.5},{\"x\":1685241030697,\"y\":20.4},{\"x\":1685241330716,\"y\":20.4},{\"x\":1685241630792,\"y\":20.4},{\"x\":1685241930839,\"y\":20.4},{\"x\":1685242230957,\"y\":20.4},{\"x\":1685242531061,\"y\":20.4},{\"x\":1685242831116,\"y\":20.4},{\"x\":1685243131245,\"y\":20.4},{\"x\":1685243431358,\"y\":20.4},{\"x\":1685243731422,\"y\":20.3},{\"x\":1685244031484,\"y\":20.3},{\"x\":1685244331554,\"y\":20.2},{\"x\":1685244631614,\"y\":20.3},{\"x\":1685244931700,\"y\":20.3},{\"x\":1685245231790,\"y\":20.3},{\"x\":1685245531908,\"y\":20.3},{\"x\":1685245832059,\"y\":20.3},{\"x\":1685246132107,\"y\":20.3},{\"x\":1685246432206,\"y\":20.3},{\"x\":1685246732334,\"y\":20.3},{\"x\":1685247032445,\"y\":20.3},{\"x\":1685247332472,\"y\":20.2},{\"x\":1685247632538,\"y\":20.2},{\"x\":1685247932668,\"y\":20.2},{\"x\":1685248232731,\"y\":20.2},{\"x\":1685248532806,\"y\":20.2},{\"x\":1685248832930,\"y\":20.2},{\"x\":1685249133015,\"y\":20.2},{\"x\":1685249433093,\"y\":20.2},{\"x\":1685249733189,\"y\":20.2},{\"x\":1685250033291,\"y\":20.1},{\"x\":1685250333378,\"y\":20},{\"x\":1685250633446,\"y\":20},{\"x\":1685250933493,\"y\":20},{\"x\":1685251233569,\"y\":20},{\"x\":1685251533627,\"y\":20},{\"x\":1685251833774,\"y\":20.1},{\"x\":1685252133852,\"y\":20.2},{\"x\":1685252433955,\"y\":20.2},{\"x\":1685252734091,\"y\":20.2},{\"x\":1685253034179,\"y\":20},{\"x\":1685253334257,\"y\":19.9},{\"x\":1685253634325,\"y\":20},{\"x\":1685253934367,\"y\":20.2},{\"x\":1685254234489,\"y\":20.2},{\"x\":1685254534587,\"y\":20.2},{\"x\":1685254834680,\"y\":20.2},{\"x\":1685255134805,\"y\":20.3},{\"x\":1685255434885,\"y\":20.3},{\"x\":1685255735002,\"y\":20.3},{\"x\":1685256035085,\"y\":20.5},{\"x\":1685256335179,\"y\":20.5},{\"x\":1685256635254,\"y\":20.3},{\"x\":1685256935309,\"y\":20.3},{\"x\":1685257235338,\"y\":20.3},{\"x\":1685257535440,\"y\":20.3},{\"x\":1685257835520,\"y\":20.4},{\"x\":1685258135635,\"y\":20.5},{\"x\":1685258435709,\"y\":20.5},{\"x\":1685258735790,\"y\":20.5},{\"x\":1685259035904,\"y\":20.5},{\"x\":1685259335965,\"y\":20.4},{\"x\":1685259636005,\"y\":20.4},{\"x\":1685259936052,\"y\":20.4},{\"x\":1685260236148,\"y\":20.5},{\"x\":1685260536249,\"y\":20.4},{\"x\":1685260836320,\"y\":20.5},{\"x\":1685261136489,\"y\":20.5},{\"x\":1685261436489,\"y\":20.6},{\"x\":1685261736607,\"y\":20.5},{\"x\":1685262036710,\"y\":20.5},{\"x\":1685262336806,\"y\":20.4},{\"x\":1685262636943,\"y\":20.4},{\"x\":1685262936991,\"y\":20.3},{\"x\":1685263237019,\"y\":20.3},{\"x\":1685263537113,\"y\":20.3},{\"x\":1685263837223,\"y\":20.3},{\"x\":1685264137303,\"y\":20.3},{\"x\":1685264437449,\"y\":20.4},{\"x\":1685264737520,\"y\":20.3},{\"x\":1685265037596,\"y\":20.4},{\"x\":1685265337653,\"y\":20.3},{\"x\":1685265637725,\"y\":20.3},{\"x\":1685265937773,\"y\":20.3},{\"x\":1685266237884,\"y\":20.3},{\"x\":1685266537917,\"y\":20.3},{\"x\":1685266837940,\"y\":20.3},{\"x\":1685267138006,\"y\":20.3},{\"x\":1685267438089,\"y\":20.3},{\"x\":1685267738177,\"y\":20.3},{\"x\":1685268038239,\"y\":20.4},{\"x\":1685268338288,\"y\":20.3},{\"x\":1685268638340,\"y\":20.4},{\"x\":1685268938413,\"y\":20.3},{\"x\":1685269238479,\"y\":20.4},{\"x\":1685269538567,\"y\":20.4},{\"x\":1685269838641,\"y\":20.4},{\"x\":1685270138681,\"y\":20.3},{\"x\":1685270438761,\"y\":20.3},{\"x\":1685270738813,\"y\":20.3},{\"x\":1685271038911,\"y\":20.3},{\"x\":1685271338993,\"y\":20},{\"x\":1685271638994,\"y\":20},{\"x\":1685271939107,\"y\":20.2},{\"x\":1685272239155,\"y\":20.3},{\"x\":1685272539230,\"y\":20.3},{\"x\":1685272839299,\"y\":20.3},{\"x\":1685273139339,\"y\":20.3},{\"x\":1685273439382,\"y\":20.2},{\"x\":1685273739450,\"y\":19.9},{\"x\":1685274039516,\"y\":19.9},{\"x\":1685274339570,\"y\":20.2},{\"x\":1685274639651,\"y\":20.3},{\"x\":1685274939715,\"y\":20.5},{\"x\":1685275239718,\"y\":20.5},{\"x\":1685275539821,\"y\":20.6},{\"x\":1685275839883,\"y\":20.5},{\"x\":1685276139936,\"y\":20.3},{\"x\":1685276439971,\"y\":20.3},{\"x\":1685276740019,\"y\":20.3},{\"x\":1685277040061,\"y\":20.2},{\"x\":1685277340154,\"y\":20},{\"x\":1685277640177,\"y\":19.9},{\"x\":1685277940231,\"y\":20},{\"x\":1685278240249,\"y\":20},{\"x\":1685278540299,\"y\":19.9},{\"x\":1685278840376,\"y\":19.9},{\"x\":1685279140399,\"y\":19.5},{\"x\":1685279440422,\"y\":19.7},{\"x\":1685279740489,\"y\":19.8},{\"x\":1685280040542,\"y\":19.8},{\"x\":1685280340547,\"y\":19.5},{\"x\":1685280640612,\"y\":19.5},{\"x\":1685280940692,\"y\":19.5},{\"x\":1685280995978,\"y\":19.5},{\"x\":1685281186232,\"y\":19.5},{\"x\":1685281372604,\"y\":19.5},{\"x\":1685281687601,\"y\":19.5},{\"x\":1685281710226,\"y\":19.5},{\"x\":1685281749591,\"y\":19.5},{\"x\":1685281762017,\"y\":19.5},{\"x\":1685281799605,\"y\":19.5},{\"x\":1685282023556,\"y\":19.5},{\"x\":1685282044430,\"y\":19.5},{\"x\":1685282166915,\"y\":19.5},{\"x\":1685282208131,\"y\":19.5},{\"x\":1685282217923,\"y\":19.5},{\"x\":1685282260379,\"y\":19.5},{\"x\":1685282339652,\"y\":19.5},{\"x\":1685282364558,\"y\":19.5},{\"x\":1685282412077,\"y\":19.5},{\"x\":1685282588188,\"y\":19.5},{\"x\":1685282614967,\"y\":19.5},{\"x\":1685282852605,\"y\":19.5},{\"x\":1685282960718,\"y\":19.5},{\"x\":1685282980565,\"y\":19.5},{\"x\":1685283037810,\"y\":19.5},{\"x\":1685283067001,\"y\":19.5},{\"x\":1685283122144,\"y\":19.5},{\"x\":1685283272482,\"y\":19.5},{\"x\":1685283343031,\"y\":19.5},{\"x\":1685283445211,\"y\":19.5},{\"x\":1685283473050,\"y\":19.5},{\"x\":1685283503945,\"y\":19.4},{\"x\":1685283559122,\"y\":19.5},{\"x\":1685283661335,\"y\":19.5},{\"x\":1685283679196,\"y\":19.5},{\"x\":1685283753141,\"y\":19.5},{\"x\":1685283789923,\"y\":19.4},{\"x\":1685283796674,\"y\":19.4},{\"x\":1685284111596,\"y\":19.5},{\"x\":1685284411624,\"y\":19.5},{\"x\":1685284726634,\"y\":20},{\"x\":1685285041633,\"y\":19.9},{\"x\":1685285341650,\"y\":19.6},{\"x\":1685285641691,\"y\":19.8},{\"x\":1685285941711,\"y\":20},{\"x\":1685286241759,\"y\":20},{\"x\":1685286541841,\"y\":19.7},{\"x\":1685286856821,\"y\":20},{\"x\":1685287156833,\"y\":20.3},{\"x\":1685287456865,\"y\":20.4},{\"x\":1685287756902,\"y\":20.3},{\"x\":1685288056933,\"y\":20.3},{\"x\":1685288357007,\"y\":20.3},{\"x\":1685288671988,\"y\":20.1},{\"x\":1685288972004,\"y\":20.2},{\"x\":1685289272052,\"y\":20},{\"x\":1685289572077,\"y\":20},{\"x\":1685289872089,\"y\":20},{\"x\":1685290172161,\"y\":19.9},{\"x\":1685290487147,\"y\":20},{\"x\":1685290787163,\"y\":20},{\"x\":1685291087218,\"y\":19.9},{\"x\":1685291387247,\"y\":19.9},{\"x\":1685291687274,\"y\":20},{\"x\":1685291987283,\"y\":20.2},{\"x\":1685292287334,\"y\":20},{\"x\":1685292587380,\"y\":19.9},{\"x\":1685292887389,\"y\":19.9},{\"x\":1685293187427,\"y\":19.8},{\"x\":1685293502456,\"y\":19.7},{\"x\":1685293817480,\"y\":19.5},{\"x\":1685294117492,\"y\":19.6},{\"x\":1685294417507,\"y\":19.9},{\"x\":1685294717548,\"y\":20},{\"x\":1685295017585,\"y\":19.9},{\"x\":1685295317622,\"y\":19.6},{\"x\":1685295617633,\"y\":20},{\"x\":1685295917642,\"y\":19.7},{\"x\":1685296217701,\"y\":19.9},{\"x\":1685296532704,\"y\":19.5},{\"x\":1685296832750,\"y\":19.5},{\"x\":1685297132754,\"y\":19.5},{\"x\":1685297432771,\"y\":19.5},{\"x\":1685297732796,\"y\":19.5},{\"x\":1685298032828,\"y\":19.5},{\"x\":1685298332882,\"y\":19.5},{\"x\":1685298647889,\"y\":19.5},{\"x\":1685298947921,\"y\":19.5},{\"x\":1685299247969,\"y\":19.5},{\"x\":1685299547997,\"y\":19.5},{\"x\":1685299848026,\"y\":19.5},{\"x\":1685300163050,\"y\":19.5},{\"x\":1685300463065,\"y\":19.5},{\"x\":1685300763075,\"y\":19.5},{\"x\":1685301063109,\"y\":19.5},{\"x\":1685301363164,\"y\":19.5},{\"x\":1685301678208,\"y\":19.5},{\"x\":1685301993216,\"y\":19.5},{\"x\":1685302293269,\"y\":19.5},{\"x\":1685302593314,\"y\":19.5},{\"x\":1685302908310,\"y\":19.5},{\"x\":1685303208329,\"y\":19.5},{\"x\":1685303508359,\"y\":19.5},{\"x\":1685303808369,\"y\":19.5},{\"x\":1685304108395,\"y\":19.5},{\"x\":1685304408424,\"y\":19.3},{\"x\":1685304708455,\"y\":19.4},{\"x\":1685305008461,\"y\":19.4},{\"x\":1685305308490,\"y\":19.4},{\"x\":1685305608530,\"y\":19.5},{\"x\":1685305908539,\"y\":19.5},{\"x\":1685306208562,\"y\":19.4},{\"x\":1685306508616,\"y\":19.5},{\"x\":1685306823616,\"y\":19.5},{\"x\":1685307123649,\"y\":19.5},{\"x\":1685307423661,\"y\":19.5},{\"x\":1685307723699,\"y\":19.5},{\"x\":1685308023733,\"y\":19.5},{\"x\":1685308323779,\"y\":19.5},{\"x\":1685308638772,\"y\":19.5},{\"x\":1685308938793,\"y\":19.5},{\"x\":1685309238818,\"y\":19.5},{\"x\":1685309538833,\"y\":19.5},{\"x\":1685309838872,\"y\":19.5},{\"x\":1685310138910,\"y\":19.5},{\"x\":1685310453907,\"y\":19.5},{\"x\":1685310768906,\"y\":19.5},{\"x\":1685311068915,\"y\":19.5},{\"x\":1685311368965,\"y\":19.5},{\"x\":1685311668966,\"y\":19.5},{\"x\":1685311968998,\"y\":19.5},{\"x\":1685312269016,\"y\":19.5},{\"x\":1685312569034,\"y\":19.5},{\"x\":1685312869061,\"y\":19.5},{\"x\":1685313169072,\"y\":19.5},{\"x\":1685313484093,\"y\":19.5},{\"x\":1685313784097,\"y\":19.6},{\"x\":1685314084113,\"y\":19.5},{\"x\":1685314384134,\"y\":19.7},{\"x\":1685314684165,\"y\":19.9},{\"x\":1685314984191,\"y\":19.9},{\"x\":1685315299157,\"y\":19.9},{\"x\":1685315599168,\"y\":20},{\"x\":1685315899192,\"y\":19.9},{\"x\":1685316199221,\"y\":20.1},{\"x\":1685316514243,\"y\":20},{\"x\":1685316814264,\"y\":20.2},{\"x\":1685317129218,\"y\":20.2},{\"x\":1685317444217,\"y\":20.2},{\"x\":1685317744298,\"y\":20.3},{\"x\":1685318059259,\"y\":20.3},{\"x\":1685318359275,\"y\":20.3},{\"x\":1685318659355,\"y\":20.3},{\"x\":1685318959404,\"y\":20.3},{\"x\":1685319259419,\"y\":20.2},{\"x\":1685319559443,\"y\":20.3},{\"x\":1685319859535,\"y\":20.3},{\"x\":1685320159597,\"y\":20.3},{\"x\":1685320459678,\"y\":20.3},{\"x\":1685320759851,\"y\":20.3},{\"x\":1685321074857,\"y\":20.2},{\"x\":1685321374890,\"y\":20.3},{\"x\":1685321674930,\"y\":20.3},{\"x\":1685321974980,\"y\":20.3},{\"x\":1685322274993,\"y\":20.3},{\"x\":1685322575024,\"y\":20.3},{\"x\":1685322875122,\"y\":20.3},{\"x\":1685323175196,\"y\":20.3},{\"x\":1685323475244,\"y\":20.3},{\"x\":1685323775309,\"y\":20.4},{\"x\":1685324075375,\"y\":20.3},{\"x\":1685324375402,\"y\":20.4},{\"x\":1685324675425,\"y\":20.5},{\"x\":1685324975485,\"y\":20.5},{\"x\":1685325275523,\"y\":20.5},{\"x\":1685325575582,\"y\":20.5},{\"x\":1685325875647,\"y\":20.5},{\"x\":1685326175713,\"y\":20.5},{\"x\":1685326475768,\"y\":20.4},{\"x\":1685326775825,\"y\":20.4},{\"x\":1685327075908,\"y\":20.4},{\"x\":1685327376002,\"y\":20.4},{\"x\":1685327676015,\"y\":20.4},{\"x\":1685327976059,\"y\":20.4},{\"x\":1685328276184,\"y\":20.4},{\"x\":1685328591156,\"y\":20.4},{\"x\":1685328891332,\"y\":20.4},{\"x\":1685329206306,\"y\":20.4},{\"x\":1685329506397,\"y\":20.4},{\"x\":1685329806440,\"y\":20.3},{\"x\":1685330106549,\"y\":20.3},{\"x\":1685330406587,\"y\":20.3},{\"x\":1685330706687,\"y\":20.2},{\"x\":1685331006741,\"y\":20.3},{\"x\":1685331306759,\"y\":20.3},{\"x\":1685331606822,\"y\":20.2},{\"x\":1685331906872,\"y\":20.2},{\"x\":1685332206974,\"y\":20.2},{\"x\":1685332507043,\"y\":20.3},{\"x\":1685332807216,\"y\":20.2},{\"x\":1685333122210,\"y\":20.2},{\"x\":1685333422298,\"y\":20.2},{\"x\":1685333722396,\"y\":20.2},{\"x\":1685334022464,\"y\":20.2},{\"x\":1685334322536,\"y\":20.2},{\"x\":1685334622591,\"y\":20.2},{\"x\":1685334922644,\"y\":20.2},{\"x\":1685335222714,\"y\":20.1},{\"x\":1685335522841,\"y\":20},{\"x\":1685335822919,\"y\":20},{\"x\":1685336122954,\"y\":20},{\"x\":1685336423087,\"y\":19.9},{\"x\":1685336723138,\"y\":20},{\"x\":1685337023185,\"y\":19.9},{\"x\":1685337323274,\"y\":19.9},{\"x\":1685337623330,\"y\":19.9},{\"x\":1685337923414,\"y\":20},{\"x\":1685338223520,\"y\":19.9},{\"x\":1685338523616,\"y\":20},{\"x\":1685338823724,\"y\":19.9},{\"x\":1685339123797,\"y\":20},{\"x\":1685339423870,\"y\":19.9},{\"x\":1685339723950,\"y\":19.9},{\"x\":1685340024030,\"y\":19.9},{\"x\":1685340324090,\"y\":20},{\"x\":1685340624115,\"y\":20},{\"x\":1685340924164,\"y\":20},{\"x\":1685341224265,\"y\":20},{\"x\":1685341524353,\"y\":20},{\"x\":1685341824453,\"y\":20},{\"x\":1685342124531,\"y\":20.2},{\"x\":1685342424622,\"y\":19.9},{\"x\":1685342724753,\"y\":20},{\"x\":1685343024799,\"y\":20.2},{\"x\":1685343324830,\"y\":20},{\"x\":1685343624890,\"y\":19.9},{\"x\":1685343924971,\"y\":20.2},{\"x\":1685344225070,\"y\":20.2},{\"x\":1685344525149,\"y\":20.3},{\"x\":1685344825216,\"y\":20.2},{\"x\":1685345125344,\"y\":20.2},{\"x\":1685345425362,\"y\":20.3},{\"x\":1685345725441,\"y\":20.3},{\"x\":1685346025536,\"y\":20.3},{\"x\":1685346325591,\"y\":20},{\"x\":1685346625679,\"y\":20.2},{\"x\":1685346925731,\"y\":20.2},{\"x\":1685347225748,\"y\":20.3},{\"x\":1685347525839,\"y\":20.3},{\"x\":1685347825931,\"y\":20.3},{\"x\":1685348126031,\"y\":20.3},{\"x\":1685348426089,\"y\":20.3},{\"x\":1685348726163,\"y\":20.3},{\"x\":1685349026225,\"y\":20.3},{\"x\":1685349326308,\"y\":20.3},{\"x\":1685349626392,\"y\":20},{\"x\":1685349926466,\"y\":20},{\"x\":1685350226553,\"y\":20.2},{\"x\":1685350526651,\"y\":19.9},{\"x\":1685350826811,\"y\":20},{\"x\":1685351141763,\"y\":19.9},{\"x\":1685351441827,\"y\":20.2},{\"x\":1685351741927,\"y\":20.2},{\"x\":1685352042064,\"y\":20.1},{\"x\":1685352342100,\"y\":20.3},{\"x\":1685352642170,\"y\":20},{\"x\":1685352942245,\"y\":19.9},{\"x\":1685353242314,\"y\":19.9},{\"x\":1685353542387,\"y\":20},{\"x\":1685353842461,\"y\":20},{\"x\":1685354142491,\"y\":20},{\"x\":1685354442557,\"y\":19.9},{\"x\":1685354742628,\"y\":20},{\"x\":1685355042729,\"y\":20.3},{\"x\":1685355342838,\"y\":20.2},{\"x\":1685355642921,\"y\":20.3},{\"x\":1685355942977,\"y\":20},{\"x\":1685356243149,\"y\":19.9},{\"x\":1685356558148,\"y\":19.5},{\"x\":1685356858211,\"y\":19.9},{\"x\":1685357158249,\"y\":20},{\"x\":1685357458282,\"y\":19.6},{\"x\":1685357758424,\"y\":20},{\"x\":1685358058471,\"y\":19.5},{\"x\":1685358358569,\"y\":19.5},{\"x\":1685358658635,\"y\":20},{\"x\":1685358958716,\"y\":20.1},{\"x\":1685359258767,\"y\":20},{\"x\":1685359558873,\"y\":19.9},{\"x\":1685359858954,\"y\":20.2},{\"x\":1685360159014,\"y\":20.2},{\"x\":1685360459077,\"y\":20},{\"x\":1685360759117,\"y\":19.9},{\"x\":1685361059194,\"y\":19.8},{\"x\":1685361359285,\"y\":20},{\"x\":1685361659377,\"y\":20},{\"x\":1685361959454,\"y\":20.1},{\"x\":1685362259508,\"y\":20.2},{\"x\":1685362559586,\"y\":19.9},{\"x\":1685362859674,\"y\":20},{\"x\":1685363159756,\"y\":20},{\"x\":1685363459810,\"y\":19.5},{\"x\":1685363759869,\"y\":19.6},{\"x\":1685364059953,\"y\":19.5},{\"x\":1685364360040,\"y\":19.9},{\"x\":1685364660157,\"y\":19.9},{\"x\":1685364960261,\"y\":19.9},{\"x\":1685365260272,\"y\":19.9},{\"x\":1685365560367,\"y\":20},{\"x\":1685365860483,\"y\":19.9},{\"x\":1685366160569,\"y\":19.9},{\"x\":1685366460633,\"y\":19.5},{\"x\":1685366760670,\"y\":19.5},{\"x\":1685367060781,\"y\":19.5},{\"x\":1685367360928,\"y\":19.5},{\"x\":1685367660996,\"y\":19.5},{\"x\":1685367961125,\"y\":19.5},{\"x\":1685368261267,\"y\":19.5},{\"x\":1685368561326,\"y\":19.5},{\"x\":1685368861443,\"y\":19.5},{\"x\":1685369161528,\"y\":19.5},{\"x\":1685369461571,\"y\":19.5},{\"x\":1685369761618,\"y\":19.5},{\"x\":1685370061811,\"y\":19.5},{\"x\":1685370361876,\"y\":19.5},{\"x\":1685370661975,\"y\":19.5},{\"x\":1685370962096,\"y\":19.5},{\"x\":1685371262161,\"y\":19.5},{\"x\":1685371562287,\"y\":19.5},{\"x\":1685371862386,\"y\":19.5},{\"x\":1685372162471,\"y\":19.5},{\"x\":1685372462563,\"y\":19.4},{\"x\":1685372762583,\"y\":19.2},{\"x\":1685373062692,\"y\":19.2},{\"x\":1685373362813,\"y\":19.1},{\"x\":1685373662925,\"y\":19.3},{\"x\":1685373963012,\"y\":19.2},{\"x\":1685374263073,\"y\":19.2},{\"x\":1685374563193,\"y\":19},{\"x\":1685374863306,\"y\":19.2},{\"x\":1685375163412,\"y\":19.3},{\"x\":1685375463446,\"y\":19.4},{\"x\":1685375763533,\"y\":19.4},{\"x\":1685376063611,\"y\":19.2},{\"x\":1685376363690,\"y\":19.1},{\"x\":1685376663795,\"y\":19},{\"x\":1685376963909,\"y\":19.2},{\"x\":1685377263998,\"y\":19.3},{\"x\":1685377564112,\"y\":19.1},{\"x\":1685377864184,\"y\":19.2},{\"x\":1685378164260,\"y\":19.1},{\"x\":1685378464309,\"y\":19},{\"x\":1685378764426,\"y\":19},{\"x\":1685379064528,\"y\":19},{\"x\":1685379364568,\"y\":19.2},{\"x\":1685379664627,\"y\":19.1},{\"x\":1685379964711,\"y\":19},{\"x\":1685380264778,\"y\":19.1},{\"x\":1685380564838,\"y\":19.2},{\"x\":1685380864899,\"y\":19},{\"x\":1685381164922,\"y\":19},{\"x\":1685381464995,\"y\":18.9},{\"x\":1685381765085,\"y\":18.9},{\"x\":1685382065145,\"y\":18.9},{\"x\":1685382365238,\"y\":18.9},{\"x\":1685382665304,\"y\":18.9},{\"x\":1685382965394,\"y\":19},{\"x\":1685383265458,\"y\":19},{\"x\":1685383565523,\"y\":18.9},{\"x\":1685383865573,\"y\":18.9},{\"x\":1685384165635,\"y\":18.7},{\"x\":1685384465670,\"y\":18.7},{\"x\":1685384765740,\"y\":18.7},{\"x\":1685385065812,\"y\":18.9},{\"x\":1685385365909,\"y\":18.8},{\"x\":1685385665940,\"y\":18.7},{\"x\":1685385966015,\"y\":18.9},{\"x\":1685386266095,\"y\":18.9},{\"x\":1685386566159,\"y\":18.8},{\"x\":1685386866204,\"y\":18.5},{\"x\":1685387166270,\"y\":18.5},{\"x\":1685387466325,\"y\":18.7},{\"x\":1685387766371,\"y\":18.5},{\"x\":1685388066417,\"y\":18.7},{\"x\":1685388366441,\"y\":18.7},{\"x\":1685388666495,\"y\":18.7},{\"x\":1685388966561,\"y\":18.4},{\"x\":1685389266600,\"y\":18.4},{\"x\":1685389566607,\"y\":18.4},{\"x\":1685389866660,\"y\":18.4},{\"x\":1685390166677,\"y\":18.5},{\"x\":1685390466746,\"y\":18.5},{\"x\":1685390781720,\"y\":18.6},{\"x\":1685391081770,\"y\":18.6},{\"x\":1685391381808,\"y\":18.4},{\"x\":1685391681836,\"y\":18.4},{\"x\":1685391981922,\"y\":18.4},{\"x\":1685392281964,\"y\":18.4},{\"x\":1685392582032,\"y\":18.4},{\"x\":1685392897029,\"y\":18.4},{\"x\":1685393197037,\"y\":18.4},{\"x\":1685393497068,\"y\":18.4},{\"x\":1685393797107,\"y\":18.4},{\"x\":1685394097146,\"y\":18.4},{\"x\":1685394397195,\"y\":18.4},{\"x\":1685394697240,\"y\":18.4},{\"x\":1685394997269,\"y\":18.4},{\"x\":1685395297315,\"y\":18.4},{\"x\":1685395597344,\"y\":18.4},{\"x\":1685395897378,\"y\":18.4},{\"x\":1685396197391,\"y\":18.4},{\"x\":1685396497411,\"y\":18.4},{\"x\":1685396797418,\"y\":18.3},{\"x\":1685397097514,\"y\":18.4},{\"x\":1685397397526,\"y\":18.2},{\"x\":1685397697553,\"y\":18.1},{\"x\":1685397997603,\"y\":18.1},{\"x\":1685398297622,\"y\":18.1},{\"x\":1685398597700,\"y\":18.1},{\"x\":1685398897737,\"y\":18.2},{\"x\":1685399212765,\"y\":18.2},{\"x\":1685399527768,\"y\":18},{\"x\":1685399827776,\"y\":18.1},{\"x\":1685400127841,\"y\":17.9},{\"x\":1685400442841,\"y\":18},{\"x\":1685400742935,\"y\":17.9},{\"x\":1685401057950,\"y\":18},{\"x\":1685401357960,\"y\":18},{\"x\":1685401657984,\"y\":18.1},{\"x\":1685401957995,\"y\":18},{\"x\":1685402258067,\"y\":18.1},{\"x\":1685402573081,\"y\":18},{\"x\":1685402873096,\"y\":17.9},{\"x\":1685403173117,\"y\":17.9},{\"x\":1685403473129,\"y\":17.9},{\"x\":1685403773148,\"y\":17.9},{\"x\":1685404073175,\"y\":18},{\"x\":1685404373229,\"y\":17.9},{\"x\":1685404688249,\"y\":17.9},{\"x\":1685404988317,\"y\":17.9},{\"x\":1685405288409,\"y\":17.9},{\"x\":1685405588488,\"y\":17.9},{\"x\":1685405888522,\"y\":17.9},{\"x\":1685406188569,\"y\":17.9},{\"x\":1685406488623,\"y\":17.9},{\"x\":1685406788688,\"y\":17.9},{\"x\":1685407088721,\"y\":17.9},{\"x\":1685407388765,\"y\":17.9},{\"x\":1685407688838,\"y\":17.9},{\"x\":1685407988885,\"y\":17.9},{\"x\":1685408288915,\"y\":17.9},{\"x\":1685408588993,\"y\":17.9},{\"x\":1685408889074,\"y\":17.9},{\"x\":1685409189147,\"y\":17.9},{\"x\":1685409489206,\"y\":17.9},{\"x\":1685409789249,\"y\":17.9},{\"x\":1685410089310,\"y\":17.9},{\"x\":1685410389345,\"y\":17.9},{\"x\":1685410704354,\"y\":17.9},{\"x\":1685411004452,\"y\":17.9},{\"x\":1685411304516,\"y\":17.9},{\"x\":1685411604552,\"y\":17.9},{\"x\":1685411904625,\"y\":17.8},{\"x\":1685412204887,\"y\":17.8},{\"x\":1685412519762,\"y\":17.7},{\"x\":1685412819867,\"y\":17.7},{\"x\":1685413119886,\"y\":17.8},{\"x\":1685413419976,\"y\":17.7},{\"x\":1685413719986,\"y\":17.7},{\"x\":1685414020028,\"y\":17.7},{\"x\":1685414320085,\"y\":17.7},{\"x\":1685414620140,\"y\":17.7},{\"x\":1685414920229,\"y\":17.7},{\"x\":1685415220270,\"y\":17.7},{\"x\":1685415520407,\"y\":17.7},{\"x\":1685415820425,\"y\":17.7},{\"x\":1685416120509,\"y\":17.7},{\"x\":1685416420519,\"y\":17.7},{\"x\":1685416720605,\"y\":17.7},{\"x\":1685417020626,\"y\":17.7},{\"x\":1685417320672,\"y\":17.7},{\"x\":1685417620774,\"y\":17.7},{\"x\":1685417920843,\"y\":17.7},{\"x\":1685418220900,\"y\":17.8},{\"x\":1685418520971,\"y\":17.7},{\"x\":1685418821022,\"y\":17.7},{\"x\":1685419121073,\"y\":17.8},{\"x\":1685419421171,\"y\":17.9},{\"x\":1685419721181,\"y\":17.7},{\"x\":1685420021225,\"y\":17.7},{\"x\":1685420321304,\"y\":17.6},{\"x\":1685420621355,\"y\":17.7},{\"x\":1685420921447,\"y\":17.7},{\"x\":1685421221522,\"y\":17.7},{\"x\":1685421521582,\"y\":17.7},{\"x\":1685421821663,\"y\":17.7},{\"x\":1685422121736,\"y\":17.6},{\"x\":1685422421818,\"y\":17.7},{\"x\":1685422721865,\"y\":17.7},{\"x\":1685423021869,\"y\":17.6},{\"x\":1685423321956,\"y\":17.4},{\"x\":1685423622015,\"y\":17.5},{\"x\":1685423922080,\"y\":17.4},{\"x\":1685424222162,\"y\":17.5},{\"x\":1685424522203,\"y\":17.5},{\"x\":1685424822288,\"y\":17.5},{\"x\":1685425122362,\"y\":17.4},{\"x\":1685425422438,\"y\":17.4},{\"x\":1685425722513,\"y\":17.4},{\"x\":1685426022547,\"y\":17.4},{\"x\":1685426322620,\"y\":17.5},{\"x\":1685426622723,\"y\":17.5},{\"x\":1685426922744,\"y\":17.4},{\"x\":1685427222854,\"y\":17.4},{\"x\":1685427522913,\"y\":17.4},{\"x\":1685427823002,\"y\":17.4},{\"x\":1685428123104,\"y\":17.5},{\"x\":1685428423173,\"y\":17.5},{\"x\":1685428723329,\"y\":17.4},{\"x\":1685429038338,\"y\":17.4},{\"x\":1685429338390,\"y\":17.4},{\"x\":1685429638534,\"y\":17.4},{\"x\":1685429938550,\"y\":17.4},{\"x\":1685430238655,\"y\":17.4},{\"x\":1685430538750,\"y\":17.4},{\"x\":1685430838822,\"y\":17.3},{\"x\":1685431139008,\"y\":17.5},{\"x\":1685431439050,\"y\":17.5},{\"x\":1685431739109,\"y\":17.4},{\"x\":1685432039156,\"y\":17.5},{\"x\":1685432339204,\"y\":17.7},{\"x\":1685432639299,\"y\":17.3},{\"x\":1685432939394,\"y\":17.2},{\"x\":1685433239499,\"y\":17.2},{\"x\":1685433539575,\"y\":17.2},{\"x\":1685433839700,\"y\":17.2},{\"x\":1685434139771,\"y\":16.9},{\"x\":1685434439873,\"y\":16.7},{\"x\":1685434739965,\"y\":16.5},{\"x\":1685435040038,\"y\":16.5},{\"x\":1685435340054,\"y\":16.5},{\"x\":1685435640133,\"y\":16.5},{\"x\":1685435940205,\"y\":16.5},{\"x\":1685436240311,\"y\":16.8},{\"x\":1685436540423,\"y\":16.9},{\"x\":1685436840548,\"y\":17.1},{\"x\":1685437140665,\"y\":17},{\"x\":1685437440701,\"y\":16.8},{\"x\":1685437740799,\"y\":16.5},{\"x\":1685438040887,\"y\":16.5},{\"x\":1685438340964,\"y\":16.5},{\"x\":1685438641030,\"y\":17.2},{\"x\":1685438941063,\"y\":17.2},{\"x\":1685439241150,\"y\":17.2},{\"x\":1685439541265,\"y\":17},{\"x\":1685439841366,\"y\":17.2},{\"x\":1685440141451,\"y\":16.5},{\"x\":1685440441506,\"y\":16.5},{\"x\":1685440741607,\"y\":16.5},{\"x\":1685441041684,\"y\":16.5},{\"x\":1685441341786,\"y\":16.5},{\"x\":1685441641830,\"y\":16.5},{\"x\":1685441941863,\"y\":16.5},{\"x\":1685442241939,\"y\":17},{\"x\":1685442542010,\"y\":17.3},{\"x\":1685442842108,\"y\":17.2},{\"x\":1685443142199,\"y\":16.6},{\"x\":1685443442319,\"y\":17.2},{\"x\":1685443742376,\"y\":16.5},{\"x\":1685444042480,\"y\":16.8},{\"x\":1685444342574,\"y\":16.8},{\"x\":1685444642649,\"y\":16.5},{\"x\":1685444942748,\"y\":17.2},{\"x\":1685445242792,\"y\":17.1},{\"x\":1685445542799,\"y\":17.2},{\"x\":1685445842907,\"y\":17.3},{\"x\":1685446143003,\"y\":17.4},{\"x\":1685446443122,\"y\":17.4},{\"x\":1685446743194,\"y\":17.3},{\"x\":1685447043298,\"y\":17.2},{\"x\":1685447343341,\"y\":17.4},{\"x\":1685447643442,\"y\":17.2},{\"x\":1685447943557,\"y\":17.2},{\"x\":1685448243632,\"y\":17.3},{\"x\":1685448543708,\"y\":17.2},{\"x\":1685448843747,\"y\":17.1},{\"x\":1685449143768,\"y\":16.6},{\"x\":1685449443878,\"y\":16.5},{\"x\":1685449743965,\"y\":16.5},{\"x\":1685450044053,\"y\":16.5},{\"x\":1685450344178,\"y\":17.2},{\"x\":1685450644263,\"y\":17.3},{\"x\":1685450944279,\"y\":17.4},{\"x\":1685451244382,\"y\":17.2},{\"x\":1685451544448,\"y\":17.3},{\"x\":1685451844600,\"y\":17.3},{\"x\":1685452144626,\"y\":17.4},{\"x\":1685452444701,\"y\":17.4},{\"x\":1685452744749,\"y\":17.2},{\"x\":1685453044818,\"y\":17.4},{\"x\":1685453344909,\"y\":17.7},{\"x\":1685453645071,\"y\":17.6},{\"x\":1685453945113,\"y\":17.5},{\"x\":1685454245205,\"y\":17.6},{\"x\":1685454545276,\"y\":17.6},{\"x\":1685454845390,\"y\":17.7},{\"x\":1685455145455,\"y\":17.8},{\"x\":1685455445552,\"y\":17.7},{\"x\":1685455745631,\"y\":17.7},{\"x\":1685456045706,\"y\":17.7},{\"x\":1685456345813,\"y\":17.6},{\"x\":1685456645826,\"y\":17.7},{\"x\":1685456945928,\"y\":17.7},{\"x\":1685457246034,\"y\":17.4},{\"x\":1685457546104,\"y\":17.4},{\"x\":1685457846188,\"y\":17.6},{\"x\":1685458146263,\"y\":17.9},{\"x\":1685458446341,\"y\":17.9},{\"x\":1685458746470,\"y\":17.9},{\"x\":1685459046554,\"y\":17.8},{\"x\":1685459346643,\"y\":17.7},{\"x\":1685459646708,\"y\":17.9},{\"x\":1685459946734,\"y\":18},{\"x\":1685460246833,\"y\":17.9},{\"x\":1685460546913,\"y\":17.9},{\"x\":1685460847002,\"y\":17.9},{\"x\":1685461147079,\"y\":17.9},{\"x\":1685461447115,\"y\":17.9},{\"x\":1685461747181,\"y\":17.9},{\"x\":1685462047303,\"y\":17.9},{\"x\":1685462347360,\"y\":17.9},{\"x\":1685462647457,\"y\":17.9},{\"x\":1685462947533,\"y\":17.9},{\"x\":1685463247622,\"y\":17.9},{\"x\":1685463437946,\"y\":17.9},{\"x\":1685463752894,\"y\":17.9},{\"x\":1685464067891,\"y\":17.9},{\"x\":1685464367932,\"y\":17.9},{\"x\":1685464668016,\"y\":18.2},{\"x\":1685464968034,\"y\":18.2},{\"x\":1685465268109,\"y\":17.9},{\"x\":1685465568127,\"y\":17.9},{\"x\":1685465868179,\"y\":18},{\"x\":1685466168200,\"y\":18},{\"x\":1685466468292,\"y\":17.9},{\"x\":1685466783247,\"y\":17.9},{\"x\":1685467083281,\"y\":18},{\"x\":1685467383324,\"y\":18},{\"x\":1685467683356,\"y\":17.9},{\"x\":1685467983393,\"y\":17.9},{\"x\":1685468283508,\"y\":18},{\"x\":1685468598507,\"y\":17.9},{\"x\":1685468898532,\"y\":17.9},{\"x\":1685469198568,\"y\":17.9},{\"x\":1685469498602,\"y\":17.9},{\"x\":1685469798635,\"y\":17.9},{\"x\":1685470098653,\"y\":17.8},{\"x\":1685470398701,\"y\":17.8},{\"x\":1685470698741,\"y\":17.8},{\"x\":1685470998770,\"y\":17.7},{\"x\":1685471298800,\"y\":17.8},{\"x\":1685471598821,\"y\":17.9},{\"x\":1685471898877,\"y\":17.7},{\"x\":1685472198886,\"y\":17.7},{\"x\":1685472498957,\"y\":17.7},{\"x\":1685472798992,\"y\":17.7},{\"x\":1685473099049,\"y\":17.9},{\"x\":1685473414059,\"y\":17.9},{\"x\":1685473714086,\"y\":17.7},{\"x\":1685474014164,\"y\":17.6},{\"x\":1685474314238,\"y\":17.4},{\"x\":1685474629191,\"y\":17.5},{\"x\":1685474929212,\"y\":17.6},{\"x\":1685475229261,\"y\":17.7},{\"x\":1685475529275,\"y\":17.4},{\"x\":1685475829340,\"y\":17.4},{\"x\":1685476129417,\"y\":17.4},{\"x\":1685476429433,\"y\":17.4},{\"x\":1685476729449,\"y\":17.3},{\"x\":1685477029470,\"y\":17.2},{\"x\":1685477329512,\"y\":17.2},{\"x\":1685477629544,\"y\":17.3},{\"x\":1685477929562,\"y\":17.4},{\"x\":1685478229615,\"y\":17.3},{\"x\":1685478529641,\"y\":17},{\"x\":1685478829667,\"y\":16.5},{\"x\":1685479129749,\"y\":16.5},{\"x\":1685479429791,\"y\":16.5},{\"x\":1685479729807,\"y\":16.5},{\"x\":1685480029843,\"y\":16.5},{\"x\":1685480329850,\"y\":16.5},{\"x\":1685480629899,\"y\":16.7},{\"x\":1685480929954,\"y\":16.5},{\"x\":1685481244998,\"y\":16.5},{\"x\":1685481545012,\"y\":16.5},{\"x\":1685481845043,\"y\":16.5},{\"x\":1685482145093,\"y\":16.5},{\"x\":1685482445120,\"y\":16.5},{\"x\":1685482745153,\"y\":16.5},{\"x\":1685483045222,\"y\":16.5},{\"x\":1685483345235,\"y\":16.5},{\"x\":1685483645258,\"y\":16.5},{\"x\":1685483945299,\"y\":16.5},{\"x\":1685484245340,\"y\":16.5},{\"x\":1685484545382,\"y\":16.5},{\"x\":1685484845385,\"y\":16.5},{\"x\":1685485145425,\"y\":16.5},{\"x\":1685485445459,\"y\":16.5},{\"x\":1685485745479,\"y\":16.5},{\"x\":1685486045546,\"y\":16.5},{\"x\":1685486345575,\"y\":16.5},{\"x\":1685486645633,\"y\":16.5},{\"x\":1685486945725,\"y\":16.5},{\"x\":1685487260693,\"y\":16.5},{\"x\":1685487560707,\"y\":16.5},{\"x\":1685487860814,\"y\":16.5},{\"x\":1685488175808,\"y\":16.5},{\"x\":1685488475825,\"y\":16.5},{\"x\":1685488775853,\"y\":16.5},{\"x\":1685489075914,\"y\":16.5},{\"x\":1685489375930,\"y\":16.5},{\"x\":1685489675982,\"y\":16.5},{\"x\":1685489976039,\"y\":16.5},{\"x\":1685490276048,\"y\":16.5},{\"x\":1685490576126,\"y\":16.5},{\"x\":1685490876150,\"y\":16.5},{\"x\":1685491176154,\"y\":16.5},{\"x\":1685491476262,\"y\":16.5},{\"x\":1685491791218,\"y\":16.5},{\"x\":1685492091237,\"y\":16.5},{\"x\":1685492391276,\"y\":16.5},{\"x\":1685492691341,\"y\":16.5},{\"x\":1685492991352,\"y\":16.5},{\"x\":1685493291416,\"y\":16.5},{\"x\":1685493591464,\"y\":16.5},{\"x\":1685493891476,\"y\":16.2},{\"x\":1685494191553,\"y\":16.5},{\"x\":1685494491555,\"y\":16.5},{\"x\":1685494806655,\"y\":16.5},{\"x\":1685495121636,\"y\":16.5},{\"x\":1685495436647,\"y\":16.5},{\"x\":1685495736703,\"y\":16.5},{\"x\":1685496036726,\"y\":16.4},{\"x\":1685496336779,\"y\":16.5},{\"x\":1685496636854,\"y\":16.4},{\"x\":1685496951873,\"y\":16.4},{\"x\":1685497251911,\"y\":16.5},{\"x\":1685497566911,\"y\":16.5},{\"x\":1685497866915,\"y\":16.5},{\"x\":1685498166972,\"y\":16.2},{\"x\":1685498466989,\"y\":16.2},{\"x\":1685498767043,\"y\":16.4},{\"x\":1685499067095,\"y\":16.2},{\"x\":1685499367129,\"y\":16.5},{\"x\":1685499667180,\"y\":16.4},{\"x\":1685499967184,\"y\":16.5},{\"x\":1685500282215,\"y\":16.5},{\"x\":1685500582236,\"y\":16.5},{\"x\":1685500882309,\"y\":16.5},{\"x\":1685501197336,\"y\":16.4},{\"x\":1685501497371,\"y\":16.2},{\"x\":1685501797405,\"y\":16.3},{\"x\":1685502097446,\"y\":16.1},{\"x\":1685502397471,\"y\":16},{\"x\":1685502697518,\"y\":15.7},{\"x\":1685502997526,\"y\":16},{\"x\":1685503297549,\"y\":16},{\"x\":1685503597589,\"y\":16.2},{\"x\":1685503897624,\"y\":16.2},{\"x\":1685504197687,\"y\":16},{\"x\":1685504497728,\"y\":15.9},{\"x\":1685504797753,\"y\":16},{\"x\":1685505097809,\"y\":16},{\"x\":1685505397837,\"y\":16.2},{\"x\":1685505697885,\"y\":16.4},{\"x\":1685505997899,\"y\":16.3},{\"x\":1685506297916,\"y\":16.1},{\"x\":1685506597958,\"y\":16},{\"x\":1685506897987,\"y\":16},{\"x\":1685507198004,\"y\":15.8},{\"x\":1685507498078,\"y\":15.9},{\"x\":1685507798110,\"y\":16},{\"x\":1685508098131,\"y\":15.8},{\"x\":1685508398152,\"y\":16},{\"x\":1685508698194,\"y\":15.9},{\"x\":1685508998213,\"y\":15.8},{\"x\":1685509298220,\"y\":15.8},{\"x\":1685509598290,\"y\":15.9},{\"x\":1685509898323,\"y\":15.7},{\"x\":1685510198331,\"y\":15.7},{\"x\":1685510498370,\"y\":15.7},{\"x\":1685510798393,\"y\":15.5},{\"x\":1685511098454,\"y\":15.8},{\"x\":1685511398491,\"y\":15.7},{\"x\":1685511698520,\"y\":15.9},{\"x\":1685512013528,\"y\":15.9},{\"x\":1685512313605,\"y\":15.8},{\"x\":1685512628564,\"y\":15.7},{\"x\":1685512928630,\"y\":15.5},{\"x\":1685513228650,\"y\":15.5},{\"x\":1685513528663,\"y\":15.5},{\"x\":1685513828703,\"y\":15.6},{\"x\":1685514143711,\"y\":15.7},{\"x\":1685514443729,\"y\":15.7},{\"x\":1685514743749,\"y\":15.8},{\"x\":1685515043937,\"y\":15.7},{\"x\":1685515358896,\"y\":15.5},{\"x\":1685515658956,\"y\":15.6},{\"x\":1685515959007,\"y\":15.7},{\"x\":1685516259087,\"y\":15.6},{\"x\":1685516559112,\"y\":15.9},{\"x\":1685516859194,\"y\":16},{\"x\":1685517174175,\"y\":15.9},{\"x\":1685517474229,\"y\":15.8},{\"x\":1685517774323,\"y\":15.7},{\"x\":1685518074366,\"y\":15.7},{\"x\":1685518374438,\"y\":15.7},{\"x\":1685518674561,\"y\":15.9},{\"x\":1685518974586,\"y\":15.7},{\"x\":1685519274602,\"y\":16},{\"x\":1685519574700,\"y\":15.7},{\"x\":1685519889719,\"y\":15.8},{\"x\":1685520189753,\"y\":15.9},{\"x\":1685520489831,\"y\":15.8},{\"x\":1685520789861,\"y\":15.9},{\"x\":1685521089913,\"y\":16},{\"x\":1685521390016,\"y\":15.7},{\"x\":1685521690069,\"y\":15.5},{\"x\":1685521990135,\"y\":15.5},{\"x\":1685522290216,\"y\":15.5},{\"x\":1685522590301,\"y\":15.5},{\"x\":1685522905260,\"y\":15.7},{\"x\":1685523205311,\"y\":15.7},{\"x\":1685523505402,\"y\":15.7},{\"x\":1685523805456,\"y\":15.6},{\"x\":1685524105543,\"y\":15.9},{\"x\":1685524405592,\"y\":15.7},{\"x\":1685524705754,\"y\":15.5},{\"x\":1685525005757,\"y\":15.5},{\"x\":1685525305830,\"y\":15.7},{\"x\":1685525605894,\"y\":15.5},{\"x\":1685525905934,\"y\":15.7},{\"x\":1685526205944,\"y\":15.7},{\"x\":1685526505986,\"y\":15.5},{\"x\":1685526806078,\"y\":15.6},{\"x\":1685527106180,\"y\":15.8},{\"x\":1685527406287,\"y\":15.5},{\"x\":1685527706314,\"y\":15.6},{\"x\":1685528006417,\"y\":15.7},{\"x\":1685528306469,\"y\":15.8},{\"x\":1685528606541,\"y\":15.9},{\"x\":1685528906576,\"y\":15.7},{\"x\":1685529206598,\"y\":15.7},{\"x\":1685529506705,\"y\":15.7},{\"x\":1685529806799,\"y\":15.5},{\"x\":1685530106900,\"y\":15.7},{\"x\":1685530406997,\"y\":15.9},{\"x\":1685530707031,\"y\":15.9},{\"x\":1685531007135,\"y\":15.7},{\"x\":1685531307217,\"y\":15.9},{\"x\":1685531607277,\"y\":15.7},{\"x\":1685531907312,\"y\":15.9},{\"x\":1685532207333,\"y\":16},{\"x\":1685532507449,\"y\":15.9},{\"x\":1685532807538,\"y\":16},{\"x\":1685533107607,\"y\":15.9},{\"x\":1685533407716,\"y\":16.1},{\"x\":1685533707801,\"y\":16.4},{\"x\":1685534007891,\"y\":16.5},{\"x\":1685534307936,\"y\":17.9},{\"x\":1685534607976,\"y\":18.5},{\"x\":1685534908043,\"y\":19},{\"x\":1685535208090,\"y\":19.4},{\"x\":1685535508186,\"y\":19.5},{\"x\":1685535808331,\"y\":19.5},{\"x\":1685536108352,\"y\":19.5},{\"x\":1685536408438,\"y\":19.9},{\"x\":1685536708630,\"y\":20.2},{\"x\":1685537023666,\"y\":20.3},{\"x\":1685537323705,\"y\":20.5},{\"x\":1685537623753,\"y\":20.4},{\"x\":1685537923799,\"y\":20.4},{\"x\":1685538223965,\"y\":20.5},{\"x\":1685538538965,\"y\":20.4},{\"x\":1685538839060,\"y\":20.5},{\"x\":1685539139180,\"y\":20.5},{\"x\":1685539439233,\"y\":20.5},{\"x\":1685539739375,\"y\":20.4},{\"x\":1685540039424,\"y\":20.6},{\"x\":1685540339520,\"y\":20.4},{\"x\":1685540639601,\"y\":20.6},{\"x\":1685540939668,\"y\":20.5},{\"x\":1685541239749,\"y\":20.5},{\"x\":1685541539840,\"y\":20.8},{\"x\":1685541839913,\"y\":20.5},{\"x\":1685542139995,\"y\":20.4},{\"x\":1685542440177,\"y\":20.8},{\"x\":1685542740192,\"y\":20.4},{\"x\":1685543040283,\"y\":20.8},{\"x\":1685543340389,\"y\":20.5},{\"x\":1685543640471,\"y\":20.8},{\"x\":1685543940473,\"y\":20.5},{\"x\":1685544240621,\"y\":20.8},{\"x\":1685544540685,\"y\":20.5},{\"x\":1685544840799,\"y\":20.7},{\"x\":1685545140901,\"y\":20.5},{\"x\":1685545441001,\"y\":20.8},{\"x\":1685545741065,\"y\":20.6},{\"x\":1685546041186,\"y\":20.5},{\"x\":1685546341243,\"y\":20.7},{\"x\":1685546641292,\"y\":20.4},{\"x\":1685546941376,\"y\":20.8},{\"x\":1685547241438,\"y\":20.5},{\"x\":1685547541565,\"y\":20.8},{\"x\":1685547841634,\"y\":20.5},{\"x\":1685548141711,\"y\":20.8},{\"x\":1685548441854,\"y\":20.6},{\"x\":1685548741902,\"y\":20.5},{\"x\":1685549042002,\"y\":20.8},{\"x\":1685549342099,\"y\":20.5},{\"x\":1685549642156,\"y\":20.8},{\"x\":1685549942238,\"y\":20.7},{\"x\":1685550242287,\"y\":20.5},{\"x\":1685550542321,\"y\":20.8},{\"x\":1685550842435,\"y\":20.7},{\"x\":1685551142532,\"y\":20.5},{\"x\":1685551442679,\"y\":20.8},{\"x\":1685551742742,\"y\":20.8},{\"x\":1685552042824,\"y\":20.7},{\"x\":1685552342904,\"y\":20.6},{\"x\":1685552643024,\"y\":20.7},{\"x\":1685552943102,\"y\":20.7},{\"x\":1685553243197,\"y\":20.7},{\"x\":1685553543262,\"y\":20.7},{\"x\":1685553843353,\"y\":20.8},{\"x\":1685554143366,\"y\":20.8},{\"x\":1685554443531,\"y\":20.8},{\"x\":1685554743589,\"y\":20.8},{\"x\":1685555043690,\"y\":20.8},{\"x\":1685555343799,\"y\":20.8},{\"x\":1685555643872,\"y\":20.8},{\"x\":1685555943930,\"y\":20.8},{\"x\":1685556244056,\"y\":20.8},{\"x\":1685556544148,\"y\":20.8},{\"x\":1685556844209,\"y\":20.8},{\"x\":1685557144344,\"y\":20.7},{\"x\":1685557444363,\"y\":20.8},{\"x\":1685557744405,\"y\":20.7},{\"x\":1685558044539,\"y\":20.7},{\"x\":1685558344605,\"y\":20.7},{\"x\":1685558644713,\"y\":20.7},{\"x\":1685558944785,\"y\":20.7},{\"x\":1685559244901,\"y\":20.6},{\"x\":1685559544945,\"y\":20.6},{\"x\":1685559845042,\"y\":20.5},{\"x\":1685560145143,\"y\":20.5},{\"x\":1685560445241,\"y\":20.6},{\"x\":1685560745257,\"y\":20.5},{\"x\":1685561045328,\"y\":20.5},{\"x\":1685561345445,\"y\":20.5},{\"x\":1685561645525,\"y\":20.6},{\"x\":1685561945646,\"y\":20.8},{\"x\":1685562245696,\"y\":20.7},{\"x\":1685562545795,\"y\":20.6},{\"x\":1685562845871,\"y\":20.7},{\"x\":1685563145971,\"y\":20.8},{\"x\":1685563446094,\"y\":20.7},{\"x\":1685563746173,\"y\":20.5},{\"x\":1685564046283,\"y\":20.8},{\"x\":1685564346314,\"y\":20.8},{\"x\":1685564646386,\"y\":20.7},{\"x\":1685564946460,\"y\":20.6},{\"x\":1685565246561,\"y\":20.5},{\"x\":1685565546656,\"y\":20.7},{\"x\":1685565846745,\"y\":20.8},{\"x\":1685566146812,\"y\":20.6},{\"x\":1685566446933,\"y\":20.7},{\"x\":1685566746982,\"y\":20.7},{\"x\":1685567047084,\"y\":20.5},{\"x\":1685567347176,\"y\":20.8},{\"x\":1685567647243,\"y\":20.5},{\"x\":1685567947275,\"y\":20.8},{\"x\":1685568247414,\"y\":20.8},{\"x\":1685568547487,\"y\":20.8},{\"x\":1685568847582,\"y\":20.6},{\"x\":1685569147698,\"y\":20.6},{\"x\":1685569447750,\"y\":20.5},{\"x\":1685569747835,\"y\":20.8},{\"x\":1685570047948,\"y\":20.7},{\"x\":1685570348041,\"y\":20.5},{\"x\":1685570648135,\"y\":20.7},{\"x\":1685570948186,\"y\":20.7},{\"x\":1685571248285,\"y\":20.5},{\"x\":1685571548397,\"y\":20.7},{\"x\":1685571848461,\"y\":20.6},{\"x\":1685572148552,\"y\":20.7},{\"x\":1685572448646,\"y\":20.8},{\"x\":1685572748724,\"y\":20.7},{\"x\":1685573048812,\"y\":20.4},{\"x\":1685573348924,\"y\":20.8},{\"x\":1685573648998,\"y\":20.7},{\"x\":1685573949035,\"y\":20.5},{\"x\":1685574249162,\"y\":20.7},{\"x\":1685574564170,\"y\":20.5},{\"x\":1685574864211,\"y\":20.3},{\"x\":1685575164295,\"y\":20.3},{\"x\":1685575464392,\"y\":20.3},{\"x\":1685575764473,\"y\":20.2},{\"x\":1685576064520,\"y\":20},{\"x\":1685576364561,\"y\":19.9},{\"x\":1685576664649,\"y\":19.6},{\"x\":1685576964764,\"y\":19.5},{\"x\":1685577264783,\"y\":19.5},{\"x\":1685577564825,\"y\":19.5},{\"x\":1685577864898,\"y\":19.5},{\"x\":1685578165022,\"y\":19.5},{\"x\":1685578465041,\"y\":19.5},{\"x\":1685578765123,\"y\":19.5},{\"x\":1685579065190,\"y\":19.5},{\"x\":1685579365242,\"y\":19.5},{\"x\":1685579665270,\"y\":19.5},{\"x\":1685579965342,\"y\":19.5},{\"x\":1685580265419,\"y\":19.5},{\"x\":1685580565474,\"y\":19.5},{\"x\":1685580865528,\"y\":19.5},{\"x\":1685581165617,\"y\":19.5},{\"x\":1685581465707,\"y\":19.5},{\"x\":1685581765780,\"y\":19.5},{\"x\":1685582065871,\"y\":19.5},{\"x\":1685582365914,\"y\":19.5},{\"x\":1685582665994,\"y\":19.5},{\"x\":1685582966029,\"y\":19.5},{\"x\":1685583266054,\"y\":19.5},{\"x\":1685583566137,\"y\":19.5},{\"x\":1685583866167,\"y\":19.5},{\"x\":1685584166249,\"y\":19.5},{\"x\":1685584466332,\"y\":19.5},{\"x\":1685584766387,\"y\":19.5},{\"x\":1685585066444,\"y\":19.5},{\"x\":1685585366558,\"y\":19.5},{\"x\":1685585666591,\"y\":19.5},{\"x\":1685585966705,\"y\":19.5},{\"x\":1685586281700,\"y\":19.5},{\"x\":1685586581763,\"y\":19.5},{\"x\":1685586881831,\"y\":19.5},{\"x\":1685587181935,\"y\":19.5},{\"x\":1685587481999,\"y\":19.4},{\"x\":1685587782043,\"y\":19.4},{\"x\":1685588082116,\"y\":19.4},{\"x\":1685588382188,\"y\":19.4},{\"x\":1685588682255,\"y\":19.4},{\"x\":1685588982296,\"y\":19.4},{\"x\":1685589282341,\"y\":19.3},{\"x\":1685589582405,\"y\":19.4},{\"x\":1685589882472,\"y\":19.4},{\"x\":1685590182540,\"y\":19.3},{\"x\":1685590482618,\"y\":19.3},{\"x\":1685590782722,\"y\":19.3},{\"x\":1685591082771,\"y\":19.3},{\"x\":1685591382819,\"y\":19.2},{\"x\":1685591682931,\"y\":19.2},{\"x\":1685591982967,\"y\":19.2},{\"x\":1685592282986,\"y\":19.2},{\"x\":1685592583082,\"y\":19.2},{\"x\":1685592883165,\"y\":19.2},{\"x\":1685593183195,\"y\":19.2},{\"x\":1685593483277,\"y\":19.1},{\"x\":1685593783380,\"y\":19.2},{\"x\":1685594083450,\"y\":19.2},{\"x\":1685594383491,\"y\":19.2},{\"x\":1685594683592,\"y\":19.1},{\"x\":1685594983618,\"y\":19.1},{\"x\":1685595283711,\"y\":19.1},{\"x\":1685595583730,\"y\":19.1},{\"x\":1685595883817,\"y\":19},{\"x\":1685596183896,\"y\":19},{\"x\":1685596483953,\"y\":19},{\"x\":1685596784061,\"y\":19},{\"x\":1685597084124,\"y\":19},{\"x\":1685597384139,\"y\":19.1},{\"x\":1685597684213,\"y\":19},{\"x\":1685597984240,\"y\":19},{\"x\":1685598284312,\"y\":19},{\"x\":1685598584338,\"y\":19},{\"x\":1685598884381,\"y\":19},{\"x\":1685599184436,\"y\":19},{\"x\":1685599499407,\"y\":19},{\"x\":1685599799490,\"y\":18.9},{\"x\":1685600099528,\"y\":19},{\"x\":1685600399539,\"y\":19},{\"x\":1685600699637,\"y\":19},{\"x\":1685600999644,\"y\":19},{\"x\":1685601299689,\"y\":19},{\"x\":1685601599758,\"y\":19},{\"x\":1685601899826,\"y\":19},{\"x\":1685602199848,\"y\":18.9},{\"x\":1685602499869,\"y\":18.9},{\"x\":1685602799939,\"y\":19},{\"x\":1685603099979,\"y\":18.9},{\"x\":1685603414978,\"y\":18.9},{\"x\":1685603715053,\"y\":19},{\"x\":1685604030039,\"y\":19},{\"x\":1685604330117,\"y\":19},{\"x\":1685604630167,\"y\":19},{\"x\":1685604930199,\"y\":19},{\"x\":1685605230238,\"y\":18.9},{\"x\":1685605530260,\"y\":19},{\"x\":1685605830318,\"y\":19},{\"x\":1685606130319,\"y\":19},{\"x\":1685606430335,\"y\":19},{\"x\":1685606730393,\"y\":19},{\"x\":1685607030458,\"y\":19},{\"x\":1685607330485,\"y\":19.5},{\"x\":1685607630516,\"y\":20.3},{\"x\":1685607930568,\"y\":20.6},{\"x\":1685608230576,\"y\":20.4},{\"x\":1685608530643,\"y\":20.5},{\"x\":1685608830684,\"y\":20.5},{\"x\":1685609130723,\"y\":20.5},{\"x\":1685609430778,\"y\":20.5},{\"x\":1685609745753,\"y\":20.7},{\"x\":1685610045798,\"y\":20.4},{\"x\":1685610345834,\"y\":20.7},{\"x\":1685610645876,\"y\":20.4},{\"x\":1685610945921,\"y\":20.8},{\"x\":1685611245935,\"y\":20.5},{\"x\":1685611545963,\"y\":20.8},{\"x\":1685611845989,\"y\":20.6},{\"x\":1685612146117,\"y\":20.5},{\"x\":1685612446189,\"y\":20.8},{\"x\":1685612746312,\"y\":20.6},{\"x\":1685613046346,\"y\":20.5},{\"x\":1685613346425,\"y\":20.8},{\"x\":1685613646580,\"y\":20.6},{\"x\":1685613961556,\"y\":20.6},{\"x\":1685614261648,\"y\":20.7},{\"x\":1685614576669,\"y\":20.7},{\"x\":1685614876695,\"y\":20.5},{\"x\":1685615176733,\"y\":20.4},{\"x\":1685615476808,\"y\":20.7},{\"x\":1685615776863,\"y\":20.7},{\"x\":1685616076917,\"y\":20.5},{\"x\":1685616376987,\"y\":20.4},{\"x\":1685616677033,\"y\":20.3},{\"x\":1685616977113,\"y\":20.3},{\"x\":1685617277203,\"y\":20.3},{\"x\":1685617577236,\"y\":20.3},{\"x\":1685617877275,\"y\":20.2},{\"x\":1685618177324,\"y\":20.3},{\"x\":1685618477408,\"y\":20.2},{\"x\":1685618777447,\"y\":20.3},{\"x\":1685619077601,\"y\":20.2},{\"x\":1685619377646,\"y\":20.2},{\"x\":1685619677730,\"y\":20.1},{\"x\":1685619977761,\"y\":20.2},{\"x\":1685620017473,\"y\":20.1},{\"x\":1685620080667,\"y\":20.1}],",[989,17916,17917],{},"{\"x\":1685015251039,\"y\":19.18},{\"x\":1685015551015,\"y\":19.18},{\"x\":1685015851010,\"y\":19.18},{\"x\":1685016151028,\"y\":19.09},{\"x\":1685016451042,\"y\":18.75},{\"x\":1685016751019,\"y\":18.66},{\"x\":1685017051028,\"y\":18.75},{\"x\":1685017351047,\"y\":18.89},{\"x\":1685017651031,\"y\":18.8},{\"x\":1685017951098,\"y\":18.83},{\"x\":1685018251018,\"y\":18.3},{\"x\":1685018551020,\"y\":18.3},{\"x\":1685018851032,\"y\":18.36},{\"x\":1685019151038,\"y\":18.36},{\"x\":1685019451035,\"y\":19.14},{\"x\":1685019751031,\"y\":19.04},{\"x\":1685020051038,\"y\":19.64},{\"x\":1685020351040,\"y\":19.42},{\"x\":1685020651063,\"y\":19.88},{\"x\":1685020951079,\"y\":19.73},{\"x\":1685021251036,\"y\":19.73},{\"x\":1685021551137,\"y\":19.54},{\"x\":1685021851047,\"y\":19.21},{\"x\":1685022151057,\"y\":19.13},{\"x\":1685022451042,\"y\":19.21},{\"x\":1685022751080,\"y\":19.1},{\"x\":1685023051043,\"y\":18.46},{\"x\":1685023351058,\"y\":18.46},{\"x\":1685023651118,\"y\":18.47},{\"x\":1685023951188,\"y\":18.48},{\"x\":1685024251055,\"y\":18.48},{\"x\":1685024551051,\"y\":18.44},{\"x\":1685024851052,\"y\":18.44},{\"x\":1685025151135,\"y\":18.73},{\"x\":1685025451076,\"y\":18.73},{\"x\":1685025751061,\"y\":18.73},{\"x\":1685026051071,\"y\":19.02},{\"x\":1685026351158,\"y\":19.05},{\"x\":1685026651115,\"y\":19.03},{\"x\":1685026951071,\"y\":19.03},{\"x\":1685027251066,\"y\":19.03},{\"x\":1685027551148,\"y\":18.62},{\"x\":1685027851058,\"y\":18.62},{\"x\":1685028151059,\"y\":18.62},{\"x\":1685028451112,\"y\":19},{\"x\":1685028751146,\"y\":18.91},{\"x\":1685029051091,\"y\":18.1},{\"x\":1685029351104,\"y\":18.12},{\"x\":1685029651134,\"y\":18.51},{\"x\":1685029951350,\"y\":18.12},{\"x\":1685030251085,\"y\":18.51},{\"x\":1685030551087,\"y\":18.42},{\"x\":1685030851113,\"y\":18.46},{\"x\":1685031151160,\"y\":18.37},{\"x\":1685031451109,\"y\":18.33},{\"x\":1685031751080,\"y\":18.21},{\"x\":1685032051082,\"y\":18.3},{\"x\":1685032351518,\"y\":18.3},{\"x\":1685032651206,\"y\":17.89},{\"x\":1685032951081,\"y\":17.8},{\"x\":1685033251086,\"y\":17.8},{\"x\":1685033551096,\"y\":17.8},{\"x\":1685033851075,\"y\":17.8},{\"x\":1685034151086,\"y\":17.78},{\"x\":1685034451139,\"y\":17.63},{\"x\":1685034751066,\"y\":17.63},{\"x\":1685035051075,\"y\":17.63},{\"x\":1685035351084,\"y\":17.54},{\"x\":1685035651091,\"y\":17.54},{\"x\":1685035951102,\"y\":17.55},{\"x\":1685036251109,\"y\":17.28},{\"x\":1685036551080,\"y\":17.54},{\"x\":1685036851085,\"y\":17.25},{\"x\":1685037151113,\"y\":17.2},{\"x\":1685037451085,\"y\":16.99},{\"x\":1685037751124,\"y\":16.99},{\"x\":1685038051100,\"y\":16.99},{\"x\":1685038351547,\"y\":17.1},{\"x\":1685038651116,\"y\":17.02},{\"x\":1685038951187,\"y\":16.94},{\"x\":1685039251190,\"y\":16.88},{\"x\":1685039551190,\"y\":16.85},{\"x\":1685039851181,\"y\":16.85},{\"x\":1685040151138,\"y\":16.82},{\"x\":1685040451132,\"y\":16.79},{\"x\":1685040751183,\"y\":16.79},{\"x\":1685041051160,\"y\":16.79},{\"x\":1685041351171,\"y\":16.7},{\"x\":1685041651173,\"y\":16.44},{\"x\":1685041951215,\"y\":16.44},{\"x\":1685042251220,\"y\":16.48},{\"x\":1685042551262,\"y\":16.52},{\"x\":1685042851204,\"y\":16.48},{\"x\":1685043151252,\"y\":16.52},{\"x\":1685043451209,\"y\":16.4},{\"x\":1685043751246,\"y\":16.26},{\"x\":1685044051210,\"y\":16.26},{\"x\":1685044351522,\"y\":16.26},{\"x\":1685044651215,\"y\":16.17},{\"x\":1685044951218,\"y\":16.17},{\"x\":1685045251281,\"y\":15.98},{\"x\":1685045551345,\"y\":15.98},{\"x\":1685045851232,\"y\":16.01},{\"x\":1685046151240,\"y\":15.98},{\"x\":1685046451276,\"y\":15.75},{\"x\":1685046751262,\"y\":15.75},{\"x\":1685047051266,\"y\":15.75},{\"x\":1685047351285,\"y\":15.68},{\"x\":1685047651267,\"y\":15.68},{\"x\":1685047951728,\"y\":15.49},{\"x\":1685048251321,\"y\":15.5},{\"x\":1685048551265,\"y\":15.49},{\"x\":1685048851352,\"y\":15.35},{\"x\":1685049151302,\"y\":15.35},{\"x\":1685049451264,\"y\":14.98},{\"x\":1685049751268,\"y\":14.98},{\"x\":1685050051322,\"y\":14.97},{\"x\":1685050351309,\"y\":14.97},{\"x\":1685050651266,\"y\":14.75},{\"x\":1685050951264,\"y\":14.75},{\"x\":1685051251276,\"y\":14.82},{\"x\":1685051551291,\"y\":14.73},{\"x\":1685051851384,\"y\":14.57},{\"x\":1685052151274,\"y\":14.41},{\"x\":1685052451281,\"y\":14.41},{\"x\":1685052751280,\"y\":14.35},{\"x\":1685053051279,\"y\":14.49},{\"x\":1685053351326,\"y\":14.29},{\"x\":1685053651310,\"y\":14.3},{\"x\":1685053951323,\"y\":14.29},{\"x\":1685054251377,\"y\":13.95},{\"x\":1685054551303,\"y\":13.95},{\"x\":1685054851307,\"y\":13.95},{\"x\":1685055151655,\"y\":13.71},{\"x\":1685055451302,\"y\":13.71},{\"x\":1685055751335,\"y\":13.58},{\"x\":1685056051330,\"y\":13.55},{\"x\":1685056351435,\"y\":13.58},{\"x\":1685056651370,\"y\":13.33},{\"x\":1685056951348,\"y\":13.58},{\"x\":1685057251335,\"y\":13.23},{\"x\":1685057551642,\"y\":13.23},{\"x\":1685057851342,\"y\":13.23},{\"x\":1685058151360,\"y\":12.98},{\"x\":1685058451395,\"y\":13},{\"x\":1685058751511,\"y\":13.01},{\"x\":1685059051391,\"y\":13.01},{\"x\":1685059351339,\"y\":12.9},{\"x\":1685059651359,\"y\":12.9},{\"x\":1685059951438,\"y\":12.48},{\"x\":1685060251356,\"y\":12.48},{\"x\":1685060551372,\"y\":12.48},{\"x\":1685060851371,\"y\":12.32},{\"x\":1685061151374,\"y\":12.32},{\"x\":1685061451412,\"y\":11.72},{\"x\":1685061751394,\"y\":11.63},{\"x\":1685062051381,\"y\":11.72},{\"x\":1685062352047,\"y\":11.55},{\"x\":1685062651444,\"y\":11.36},{\"x\":1685062951373,\"y\":11.46},{\"x\":1685063251410,\"y\":11.36},{\"x\":1685063551479,\"y\":11.37},{\"x\":1685063851380,\"y\":11.36},{\"x\":1685064151391,\"y\":11.44},{\"x\":1685064451471,\"y\":11.34},{\"x\":1685064751589,\"y\":11.32},{\"x\":1685065051396,\"y\":11.26},{\"x\":1685065351399,\"y\":11.22},{\"x\":1685065651409,\"y\":11.39},{\"x\":1685065952272,\"y\":11.33},{\"x\":1685066251396,\"y\":11.21},{\"x\":1685066551403,\"y\":11.21},{\"x\":1685066851417,\"y\":11.34},{\"x\":1685067151442,\"y\":11.28},{\"x\":1685067451399,\"y\":11.27},{\"x\":1685067751460,\"y\":11.06},{\"x\":1685068051420,\"y\":11.27},{\"x\":1685068351485,\"y\":11.02},{\"x\":1685068651412,\"y\":11.02},{\"x\":1685068951402,\"y\":10.91},{\"x\":1685069251450,\"y\":11},{\"x\":1685069551482,\"y\":11},{\"x\":1685069851414,\"y\":10.88},{\"x\":1685070151414,\"y\":10.66},{\"x\":1685070451408,\"y\":10.66},{\"x\":1685070752331,\"y\":10.76},{\"x\":1685071051424,\"y\":10.76},{\"x\":1685071351428,\"y\":10.76},{\"x\":1685071651498,\"y\":10.55},{\"x\":1685071951451,\"y\":10.55},{\"x\":1685072251483,\"y\":10.55},{\"x\":1685072551428,\"y\":10.55},{\"x\":1685072851477,\"y\":10.34},{\"x\":1685073151490,\"y\":10.34},{\"x\":1685073451401,\"y\":10.34},{\"x\":1685073751433,\"y\":10.08},{\"x\":1685074051433,\"y\":10.08},{\"x\":1685074351659,\"y\":9.98},{\"x\":1685074651481,\"y\":9.98},{\"x\":1685074951442,\"y\":9.98},{\"x\":1685075251486,\"y\":9.76},{\"x\":1685075553145,\"y\":9.76},{\"x\":1685075851454,\"y\":9.76},{\"x\":1685076151559,\"y\":9.76},{\"x\":1685076451455,\"y\":9.76},{\"x\":1685076751637,\"y\":9.76},{\"x\":1685077051562,\"y\":10.23},{\"x\":1685077351466,\"y\":10.23},{\"x\":1685077651495,\"y\":10.23},{\"x\":1685077951596,\"y\":10.15},{\"x\":1685078251465,\"y\":10.36},{\"x\":1685078551490,\"y\":10.36},{\"x\":1685078851486,\"y\":10.82},{\"x\":1685079152413,\"y\":10.82},{\"x\":1685079451481,\"y\":11.06},{\"x\":1685079751484,\"y\":11.06},{\"x\":1685080051515,\"y\":11.26},{\"x\":1685080353153,\"y\":11.08},{\"x\":1685080651466,\"y\":11.37},{\"x\":1685080951559,\"y\":11.85},{\"x\":1685081251496,\"y\":12.07},{\"x\":1685081552662,\"y\":11.54},{\"x\":1685081851505,\"y\":11.54},{\"x\":1685082151498,\"y\":12.9},{\"x\":1685082451574,\"y\":11.98},{\"x\":1685082752768,\"y\":12.05},{\"x\":1685083051516,\"y\":12.05},{\"x\":1685083351518,\"y\":12.54},{\"x\":1685083651522,\"y\":12.54},{\"x\":1685083951825,\"y\":13.01},{\"x\":1685084251526,\"y\":13.01},{\"x\":1685084551531,\"y\":13.84},{\"x\":1685084851537,\"y\":14.15},{\"x\":1685085154315,\"y\":14.2},{\"x\":1685085451540,\"y\":14.2},{\"x\":1685085751599,\"y\":14.74},{\"x\":1685086051532,\"y\":14.65},{\"x\":1685086352440,\"y\":14.65},{\"x\":1685086651538,\"y\":15.31},{\"x\":1685086951544,\"y\":15.31},{\"x\":1685087251583,\"y\":15.43},{\"x\":1685087552469,\"y\":15.61},{\"x\":1685087851550,\"y\":15.43},{\"x\":1685088151549,\"y\":15.75},{\"x\":1685088451547,\"y\":15.75},{\"x\":1685088752994,\"y\":16.44},{\"x\":1685089051545,\"y\":16.44},{\"x\":1685089351589,\"y\":16.84},{\"x\":1685089651598,\"y\":16.44},{\"x\":1685089952825,\"y\":16.84},{\"x\":1685090251561,\"y\":17.35},{\"x\":1685090551636,\"y\":17.66},{\"x\":1685090851564,\"y\":17.56},{\"x\":1685091152016,\"y\":17.66},{\"x\":1685091451594,\"y\":17.93},{\"x\":1685091751567,\"y\":18.04},{\"x\":1685092051581,\"y\":17.93},{\"x\":1685092352469,\"y\":18.08},{\"x\":1685092651613,\"y\":18.17},{\"x\":1685092951598,\"y\":18.25},{\"x\":1685093251572,\"y\":18.23},{\"x\":1685093551684,\"y\":18.43},{\"x\":1685093851596,\"y\":18.5},{\"x\":1685094151578,\"y\":18.5},{\"x\":1685094451581,\"y\":18.85},{\"x\":1685094753849,\"y\":18.85},{\"x\":1685095051634,\"y\":19.17},{\"x\":1685095351592,\"y\":19.09},{\"x\":1685095651582,\"y\":19.37},{\"x\":1685095952262,\"y\":19.37},{\"x\":1685096251665,\"y\":19.46},{\"x\":1685096551653,\"y\":19.46},{\"x\":1685096851597,\"y\":19.46},{\"x\":1685097151894,\"y\":19.32},{\"x\":1685097451605,\"y\":19.59},{\"x\":1685097751603,\"y\":19.85},{\"x\":1685098051603,\"y\":19.75},{\"x\":1685098351825,\"y\":19.65},{\"x\":1685098651611,\"y\":19.82},{\"x\":1685098951612,\"y\":19.65},{\"x\":1685099251620,\"y\":19.57},{\"x\":1685099554557,\"y\":19.84},{\"x\":1685099851611,\"y\":19.98},{\"x\":1685100151610,\"y\":19.98},{\"x\":1685100451674,\"y\":19.9},{\"x\":1685100751631,\"y\":19.9},{\"x\":1685101051671,\"y\":20.45},{\"x\":1685101351650,\"y\":20.45},{\"x\":1685101651625,\"y\":20.45},{\"x\":1685101952592,\"y\":19.74},{\"x\":1685102251628,\"y\":19.74},{\"x\":1685102551620,\"y\":19.74},{\"x\":1685102851630,\"y\":19.84},{\"x\":1685103152663,\"y\":20.53},{\"x\":1685103451625,\"y\":20.53},{\"x\":1685103751638,\"y\":20.37},{\"x\":1685104051653,\"y\":20.37},{\"x\":1685104351690,\"y\":20.42},{\"x\":1685104651625,\"y\":20.92},{\"x\":1685104951669,\"y\":21.05},{\"x\":1685105251635,\"y\":20.92},{\"x\":1685106270209,\"y\":21.51},{\"x\":1685106570210,\"y\":21.28},{\"x\":1685106870262,\"y\":21.31},{\"x\":1685107170259,\"y\":20.87},{\"x\":1685107470202,\"y\":20.87},{\"x\":1685107770205,\"y\":20.87},{\"x\":1685108070201,\"y\":20.24},{\"x\":1685108370268,\"y\":20.24},{\"x\":1685108670211,\"y\":20.81},{\"x\":1685108970215,\"y\":20.61},{\"x\":1685109270264,\"y\":21.02},{\"x\":1685109570225,\"y\":21.02},{\"x\":1685109870210,\"y\":21.35},{\"x\":1685110170276,\"y\":21.42},{\"x\":1685110470215,\"y\":21.08},{\"x\":1685110770218,\"y\":21.08},{\"x\":1685111070267,\"y\":21.3},{\"x\":1685111370237,\"y\":21.32},{\"x\":1685111670242,\"y\":21.21},{\"x\":1685111970278,\"y\":21.56},{\"x\":1685112270243,\"y\":21.43},{\"x\":1685112570286,\"y\":20.62},{\"x\":1685112870312,\"y\":20.61},{\"x\":1685113170279,\"y\":20.61},{\"x\":1685113470259,\"y\":20.52},{\"x\":1685113770274,\"y\":21.03},{\"x\":1685114070330,\"y\":20.96},{\"x\":1685114370346,\"y\":20.62},{\"x\":1685114670290,\"y\":20.62},{\"x\":1685114970303,\"y\":20.62},{\"x\":1685115270293,\"y\":20.57},{\"x\":1685115570345,\"y\":20.81},{\"x\":1685115870301,\"y\":20.81},{\"x\":1685116170341,\"y\":20.85},{\"x\":1685116470425,\"y\":20.35},{\"x\":1685116770319,\"y\":20.73},{\"x\":1685117070306,\"y\":20.35},{\"x\":1685117370344,\"y\":20.75},{\"x\":1685117670330,\"y\":20.75},{\"x\":1685117970336,\"y\":20.75},{\"x\":1685118270330,\"y\":20.45},{\"x\":1685118570325,\"y\":20.45},{\"x\":1685118870362,\"y\":19.95},{\"x\":1685119170359,\"y\":19.95},{\"x\":1685119470369,\"y\":19.95},{\"x\":1685119770365,\"y\":19.92},{\"x\":1685120070363,\"y\":20.06},{\"x\":1685120370385,\"y\":20.17},{\"x\":1685120670359,\"y\":20.17},{\"x\":1685120970383,\"y\":20.08},{\"x\":1685121270373,\"y\":19.95},{\"x\":1685121570376,\"y\":19.85},{\"x\":1685121870394,\"y\":19.88},{\"x\":1685122170385,\"y\":19.88},{\"x\":1685122470467,\"y\":19},{\"x\":1685122770415,\"y\":19},{\"x\":1685123070412,\"y\":19},{\"x\":1685123370409,\"y\":18.86},{\"x\":1685123670402,\"y\":18.86},{\"x\":1685123970418,\"y\":18.86},{\"x\":1685124270399,\"y\":18.86},{\"x\":1685124570415,\"y\":18.79},{\"x\":1685124870446,\"y\":18.79},{\"x\":1685125170457,\"y\":18.85},{\"x\":1685125470494,\"y\":18.85},{\"x\":1685125770424,\"y\":18.85},{\"x\":1685126070436,\"y\":18.71},{\"x\":1685126370464,\"y\":18.71},{\"x\":1685126670446,\"y\":18.67},{\"x\":1685126970458,\"y\":18.67},{\"x\":1685127270730,\"y\":17.76},{\"x\":1685127570540,\"y\":17.84},{\"x\":1685127870479,\"y\":17.42},{\"x\":1685128170488,\"y\":17.42},{\"x\":1685128470446,\"y\":17.32},{\"x\":1685128770711,\"y\":17.38},{\"x\":1685129070493,\"y\":17.55},{\"x\":1685129370460,\"y\":17.46},{\"x\":1685129670456,\"y\":17.51},{\"x\":1685129970444,\"y\":16.98},{\"x\":1685130270452,\"y\":16.94},{\"x\":1685130570463,\"y\":16.94},{\"x\":1685130870454,\"y\":16.63},{\"x\":1685131170558,\"y\":16.63},{\"x\":1685131470459,\"y\":16.63},{\"x\":1685131770480,\"y\":15.83},{\"x\":1685132070539,\"y\":15.61},{\"x\":1685132370654,\"y\":15.61},{\"x\":1685132670510,\"y\":15.17},{\"x\":1685132970470,\"y\":15.17},{\"x\":1685133270483,\"y\":15.17},{\"x\":1685133570534,\"y\":15.33},{\"x\":1685133870537,\"y\":15.17},{\"x\":1685134170481,\"y\":15.33},{\"x\":1685134470522,\"y\":15.17},{\"x\":1685134770619,\"y\":15.17},{\"x\":1685135070468,\"y\":15.17},{\"x\":1685135370539,\"y\":14.12},{\"x\":1685135670470,\"y\":14.12},{\"x\":1685135970588,\"y\":14.12},{\"x\":1685136270506,\"y\":13.94},{\"x\":1685136570482,\"y\":13.94},{\"x\":1685136870483,\"y\":13.88},{\"x\":1685137170591,\"y\":13.53},{\"x\":1685137470482,\"y\":13.29},{\"x\":1685137770513,\"y\":13.29},{\"x\":1685138070565,\"y\":13.24},{\"x\":1685138370612,\"y\":13.3},{\"x\":1685138670513,\"y\":12.65},{\"x\":1685138970488,\"y\":13.03},{\"x\":1685139270567,\"y\":12.44},{\"x\":1685139570520,\"y\":12.44},{\"x\":1685139870495,\"y\":12.47},{\"x\":1685140170514,\"y\":12.41},{\"x\":1685140470469,\"y\":12.41},{\"x\":1685140770566,\"y\":12.32},{\"x\":1685141070532,\"y\":11.91},{\"x\":1685141370505,\"y\":11.91},{\"x\":1685141670535,\"y\":11.91},{\"x\":1685141970572,\"y\":11.87},{\"x\":1685142270528,\"y\":11.87},{\"x\":1685142570539,\"y\":11.49},{\"x\":1685142870540,\"y\":11.49},{\"x\":1685143170721,\"y\":11.69},{\"x\":1685143470532,\"y\":11.69},{\"x\":1685143770537,\"y\":11.69},{\"x\":1685144070587,\"y\":11.38},{\"x\":1685144370585,\"y\":11.29},{\"x\":1685144670544,\"y\":11.38},{\"x\":1685144970592,\"y\":11.66},{\"x\":1685145270578,\"y\":11.66},{\"x\":1685145570616,\"y\":11.66},{\"x\":1685145870578,\"y\":11.54},{\"x\":1685146170575,\"y\":11.3},{\"x\":1685146470586,\"y\":11.26},{\"x\":1685146770618,\"y\":10.97},{\"x\":1685147070575,\"y\":10.97},{\"x\":1685147370627,\"y\":11.06},{\"x\":1685147670593,\"y\":10.78},{\"x\":1685147970600,\"y\":11.06},{\"x\":1685148270605,\"y\":10.65},{\"x\":1685148570644,\"y\":10.63},{\"x\":1685148870584,\"y\":10.63},{\"x\":1685149170590,\"y\":10.63},{\"x\":1685149470587,\"y\":10.44},{\"x\":1685149770583,\"y\":10.44},{\"x\":1685150070580,\"y\":10.1},{\"x\":1685150370584,\"y\":10.1},{\"x\":1685150670582,\"y\":10.03},{\"x\":1685150970594,\"y\":10.03},{\"x\":1685151270632,\"y\":10.08},{\"x\":1685151570591,\"y\":10.08},{\"x\":1685151870605,\"y\":9.61},{\"x\":1685152170611,\"y\":9.61},{\"x\":1685152470611,\"y\":9.42},{\"x\":1685152770613,\"y\":9.42},{\"x\":1685153070628,\"y\":9.48},{\"x\":1685153370683,\"y\":9.39},{\"x\":1685153670664,\"y\":9.33},{\"x\":1685153970636,\"y\":9.33},{\"x\":1685154270611,\"y\":9.33},{\"x\":1685154570650,\"y\":9.14},{\"x\":1685154870623,\"y\":9.14},{\"x\":1685155170939,\"y\":9.05},{\"x\":1685155470674,\"y\":8.95},{\"x\":1685155770628,\"y\":8.95},{\"x\":1685156070642,\"y\":8.86},{\"x\":1685156370678,\"y\":8.95},{\"x\":1685156670691,\"y\":8.95},{\"x\":1685156970647,\"y\":8.95},{\"x\":1685157270649,\"y\":8.48},{\"x\":1685157570728,\"y\":8.51},{\"x\":1685157870653,\"y\":8.67},{\"x\":1685158170653,\"y\":8.67},{\"x\":1685158470652,\"y\":8.47},{\"x\":1685158770755,\"y\":8.29},{\"x\":1685159070671,\"y\":8.29},{\"x\":1685159370691,\"y\":8.19},{\"x\":1685159670661,\"y\":8.19},{\"x\":1685159971379,\"y\":8.08},{\"x\":1685160270711,\"y\":8.04},{\"x\":1685160570739,\"y\":8.22},{\"x\":1685160870655,\"y\":8.22},{\"x\":1685161170787,\"y\":8.04},{\"x\":1685161470703,\"y\":8.24},{\"x\":1685161770668,\"y\":8.04},{\"x\":1685162070717,\"y\":8.02},{\"x\":1685162371170,\"y\":7.93},{\"x\":1685162670708,\"y\":8.02},{\"x\":1685162970719,\"y\":8.55},{\"x\":1685163270676,\"y\":8.55},{\"x\":1685163571126,\"y\":8.55},{\"x\":1685163870678,\"y\":8.77},{\"x\":1685164170681,\"y\":8.69},{\"x\":1685164470773,\"y\":9.46},{\"x\":1685164771057,\"y\":9.68},{\"x\":1685165070675,\"y\":9.97},{\"x\":1685165370677,\"y\":9.83},{\"x\":1685165670713,\"y\":10.29},{\"x\":1685165970916,\"y\":10.29},{\"x\":1685166270681,\"y\":10.47},{\"x\":1685166570684,\"y\":10.47},{\"x\":1685166870680,\"y\":11},{\"x\":1685167171095,\"y\":10.85},{\"x\":1685167470678,\"y\":11.53},{\"x\":1685167770689,\"y\":12.14},{\"x\":1685168070683,\"y\":12.14},{\"x\":1685168370787,\"y\":11.68},{\"x\":1685168670739,\"y\":11.68},{\"x\":1685168970743,\"y\":11.98},{\"x\":1685169270696,\"y\":11.98},{\"x\":1685169570699,\"y\":11.98},{\"x\":1685169870784,\"y\":13.66},{\"x\":1685170170701,\"y\":13.66},{\"x\":1685170470695,\"y\":13.66},{\"x\":1685170770757,\"y\":13.66},{\"x\":1685171070684,\"y\":13.98},{\"x\":1685171370697,\"y\":13.98},{\"x\":1685171670698,\"y\":14.38},{\"x\":1685171971138,\"y\":14.38},{\"x\":1685172270759,\"y\":13.85},{\"x\":1685172570699,\"y\":13.85},{\"x\":1685172870711,\"y\":13.85},{\"x\":1685173170778,\"y\":15.4},{\"x\":1685173470740,\"y\":15.5},{\"x\":1685173770702,\"y\":15.18},{\"x\":1685174070719,\"y\":15.49},{\"x\":1685174371094,\"y\":15.8},{\"x\":1685174670695,\"y\":15.49},{\"x\":1685174970800,\"y\":16.03},{\"x\":1685175270722,\"y\":15.86},{\"x\":1685175570763,\"y\":15.86},{\"x\":1685175870697,\"y\":16.35},{\"x\":1685176170707,\"y\":16.48},{\"x\":1685176470754,\"y\":16.94},{\"x\":1685176770748,\"y\":16.94},{\"x\":1685177070739,\"y\":17.05},{\"x\":1685177370721,\"y\":17.05},{\"x\":1685177670735,\"y\":17.05},{\"x\":1685177971115,\"y\":17.66},{\"x\":1685178270740,\"y\":17.66},{\"x\":1685178570747,\"y\":17.64},{\"x\":1685178870774,\"y\":18.01},{\"x\":1685179171072,\"y\":17.92},{\"x\":1685179470822,\"y\":18.19},{\"x\":1685179770758,\"y\":18.1},{\"x\":1685180070762,\"y\":18.19},{\"x\":1685180370805,\"y\":18.1},{\"x\":1685180670780,\"y\":18.51},{\"x\":1685180970809,\"y\":18.65},{\"x\":1685181270793,\"y\":18.72},{\"x\":1685181570900,\"y\":19.19},{\"x\":1685181870801,\"y\":19.1},{\"x\":1685182170811,\"y\":19.19},{\"x\":1685182470860,\"y\":19.44},{\"x\":1685182771048,\"y\":19.67},{\"x\":1685183070826,\"y\":19.44},{\"x\":1685183370877,\"y\":19.67},{\"x\":1685183670882,\"y\":19.85},{\"x\":1685183970939,\"y\":19.85},{\"x\":1685184270841,\"y\":19.85},{\"x\":1685184570853,\"y\":19.96},{\"x\":1685184870900,\"y\":20.18},{\"x\":1685185170967,\"y\":20.47},{\"x\":1685185470866,\"y\":20.18},{\"x\":1685185770871,\"y\":20.65},{\"x\":1685186070870,\"y\":20.65},{\"x\":1685186370892,\"y\":20.6},{\"x\":1685186670893,\"y\":20.57},{\"x\":1685186970904,\"y\":20.71},{\"x\":1685187270868,\"y\":20.71},{\"x\":1685187572989,\"y\":20.99},{\"x\":1685187870872,\"y\":20.99},{\"x\":1685188170877,\"y\":20.99},{\"x\":1685188470913,\"y\":21.13},{\"x\":1685188771470,\"y\":21.2},{\"x\":1685189070899,\"y\":21.12},{\"x\":1685189370894,\"y\":21.2},{\"x\":1685189670921,\"y\":21.41},{\"x\":1685189971610,\"y\":21.41},{\"x\":1685190270898,\"y\":21.41},{\"x\":1685190570940,\"y\":21.32},{\"x\":1685190870918,\"y\":21.32},{\"x\":1685191171751,\"y\":21.78},{\"x\":1685191470923,\"y\":21.68},{\"x\":1685191770922,\"y\":21.68},{\"x\":1685192070981,\"y\":22.17},{\"x\":1685192371026,\"y\":22.17},{\"x\":1685192670934,\"y\":22.17},{\"x\":1685192970954,\"y\":22.46},{\"x\":1685193270953,\"y\":22.46},{\"x\":1685193571076,\"y\":21.99},{\"x\":1685193870942,\"y\":21.91},{\"x\":1685194171071,\"y\":21.99},{\"x\":1685194470972,\"y\":21.91},{\"x\":1685194770981,\"y\":21.91},{\"x\":1685195070960,\"y\":23.06},{\"x\":1685195370975,\"y\":22.73},{\"x\":1685195670969,\"y\":23.06},{\"x\":1685195971032,\"y\":22.82},{\"x\":1685196270973,\"y\":22.82},{\"x\":1685196570982,\"y\":22.82},{\"x\":1685196870986,\"y\":21.82},{\"x\":1685197171084,\"y\":21.93},{\"x\":1685197470984,\"y\":22.31},{\"x\":1685197770988,\"y\":22.31},{\"x\":1685198070990,\"y\":22.31},{\"x\":1685198371020,\"y\":22.31},{\"x\":1685198671053,\"y\":22.37},{\"x\":1685198970993,\"y\":22.23},{\"x\":1685199271011,\"y\":22.37},{\"x\":1685199571046,\"y\":22.48},{\"x\":1685199871115,\"y\":21.98},{\"x\":1685200171006,\"y\":21.98},{\"x\":1685200471008,\"y\":21.98},{\"x\":1685200771192,\"y\":22.9},{\"x\":1685201071014,\"y\":22.9},{\"x\":1685201371067,\"y\":22.11},{\"x\":1685201671018,\"y\":22.11},{\"x\":1685201971372,\"y\":22.11},{\"x\":1685202271010,\"y\":21.91},{\"x\":1685202571020,\"y\":21.91},{\"x\":1685202871094,\"y\":22.37},{\"x\":1685203171957,\"y\":22.04},{\"x\":1685203471024,\"y\":21.92},{\"x\":1685203771087,\"y\":22.72},{\"x\":1685204071079,\"y\":22.72},{\"x\":1685204372043,\"y\":22.63},{\"x\":1685204671023,\"y\":22.63},{\"x\":1685204971067,\"y\":22.65},{\"x\":1685205271028,\"y\":22.65},{\"x\":1685205571490,\"y\":22.29},{\"x\":1685205871024,\"y\":21.93},{\"x\":1685206171037,\"y\":21.93},{\"x\":1685206471023,\"y\":21.53},{\"x\":1685206771057,\"y\":21.53},{\"x\":1685207071049,\"y\":20.84},{\"x\":1685207371039,\"y\":20.84},{\"x\":1685207671107,\"y\":20.92},{\"x\":1685207971068,\"y\":20.84},{\"x\":1685208271098,\"y\":22.62},{\"x\":1685208571110,\"y\":22.62},{\"x\":1685208871086,\"y\":22.62},{\"x\":1685209171774,\"y\":20.91},{\"x\":1685209471092,\"y\":20.82},{\"x\":1685209771092,\"y\":19.71},{\"x\":1685210071129,\"y\":19.73},{\"x\":1685210371211,\"y\":19.73},{\"x\":1685210671121,\"y\":19.24},{\"x\":1685210971142,\"y\":21.59},{\"x\":1685211271109,\"y\":21.59},{\"x\":1685211573673,\"y\":21.59},{\"x\":1685211871103,\"y\":21.59},{\"x\":1685212171150,\"y\":21.56},{\"x\":1685212471136,\"y\":21.47},{\"x\":1685212771652,\"y\":20.46},{\"x\":1685213071195,\"y\":20.46},{\"x\":1685213371188,\"y\":19.23},{\"x\":1685213671169,\"y\":19.15},{\"x\":1685213971280,\"y\":19.23},{\"x\":1685214271228,\"y\":19.41},{\"x\":1685214571150,\"y\":19.41},{\"x\":1685214871151,\"y\":19.24},{\"x\":1685215171157,\"y\":19.21},{\"x\":1685215471219,\"y\":19.21},{\"x\":1685215771223,\"y\":18.87},{\"x\":1685216071239,\"y\":18.72},{\"x\":1685216371187,\"y\":18.87},{\"x\":1685216671220,\"y\":16.48},{\"x\":1685216971167,\"y\":16.48},{\"x\":1685217271190,\"y\":16.48},{\"x\":1685217571385,\"y\":16.48},{\"x\":1685217871202,\"y\":16.48},{\"x\":1685218171176,\"y\":16.48},{\"x\":1685218471193,\"y\":17.13},{\"x\":1685218772083,\"y\":17.04},{\"x\":1685219071242,\"y\":16.94},{\"x\":1685219371182,\"y\":16.94},{\"x\":1685219671182,\"y\":16.94},{\"x\":1685219971327,\"y\":17.29},{\"x\":1685220271195,\"y\":17.28},{\"x\":1685220571204,\"y\":17.28},{\"x\":1685220871265,\"y\":16.43},{\"x\":1685221171213,\"y\":16.43},{\"x\":1685221471206,\"y\":16.43},{\"x\":1685221771244,\"y\":16.32},{\"x\":1685222071214,\"y\":16.32},{\"x\":1685222371240,\"y\":16.22},{\"x\":1685222671231,\"y\":15.63},{\"x\":1685222971227,\"y\":15.63},{\"x\":1685223271215,\"y\":15.63},{\"x\":1685223571642,\"y\":15.63},{\"x\":1685223871216,\"y\":14.69},{\"x\":1685224171238,\"y\":14.69},{\"x\":1685224471255,\"y\":15.05},{\"x\":1685224771718,\"y\":15.05},{\"x\":1685225071254,\"y\":15},{\"x\":1685225371225,\"y\":14.91},{\"x\":1685225671230,\"y\":14.91},{\"x\":1685225971278,\"y\":15.03},{\"x\":1685226271229,\"y\":14.76},{\"x\":1685226571268,\"y\":14.62},{\"x\":1685226871228,\"y\":14.62},{\"x\":1685227171310,\"y\":14.58},{\"x\":1685227471236,\"y\":14.47},{\"x\":1685227771233,\"y\":14.47},{\"x\":1685228071264,\"y\":14.56},{\"x\":1685228371438,\"y\":14.56},{\"x\":1685228671307,\"y\":14.37},{\"x\":1685228971287,\"y\":14.26},{\"x\":1685229271247,\"y\":14.17},{\"x\":1685229571283,\"y\":14.26},{\"x\":1685229871252,\"y\":14.08},{\"x\":1685230171240,\"y\":14.08},{\"x\":1685230471249,\"y\":13.81},{\"x\":1685230771547,\"y\":13.9},{\"x\":1685231071282,\"y\":13.88},{\"x\":1685231371247,\"y\":13.88},{\"x\":1685231671245,\"y\":13.57},{\"x\":1685231971299,\"y\":13.8},{\"x\":1685232271267,\"y\":13.8},{\"x\":1685232571258,\"y\":13.67},{\"x\":1685232871256,\"y\":13.67},{\"x\":1685233172128,\"y\":13.34},{\"x\":1685233471266,\"y\":13.26},{\"x\":1685233771304,\"y\":13.55},{\"x\":1685234071280,\"y\":13.5},{\"x\":1685234371267,\"y\":13.55},{\"x\":1685234671308,\"y\":13.47},{\"x\":1685234971294,\"y\":13.47},{\"x\":1685235271259,\"y\":13.47},{\"x\":1685235573201,\"y\":13.47},{\"x\":1685235871295,\"y\":13.51},{\"x\":1685236171262,\"y\":13.65},{\"x\":1685236471308,\"y\":13.36},{\"x\":1685236772640,\"y\":13.36},{\"x\":1685237071263,\"y\":13.55},{\"x\":1685237371273,\"y\":13.46},{\"x\":1685237671265,\"y\":13.46},{\"x\":1685237972838,\"y\":13.08},{\"x\":1685238271265,\"y\":13.08},{\"x\":1685238571268,\"y\":13.08},{\"x\":1685238871275,\"y\":13.28},{\"x\":1685239172611,\"y\":13.41},{\"x\":1685239471288,\"y\":13.33},{\"x\":1685239771274,\"y\":13.31},{\"x\":1685240071325,\"y\":13.15},{\"x\":1685240372227,\"y\":13.07},{\"x\":1685240671318,\"y\":13.07},{\"x\":1685240971329,\"y\":13.07},{\"x\":1685241271288,\"y\":13.07},{\"x\":1685241571466,\"y\":13.07},{\"x\":1685241871279,\"y\":12.98},{\"x\":1685242171369,\"y\":13.28},{\"x\":1685242471346,\"y\":13.28},{\"x\":1685242771307,\"y\":13.28},{\"x\":1685243071278,\"y\":13.28},{\"x\":1685243371329,\"y\":13.28},{\"x\":1685243671340,\"y\":13.34},{\"x\":1685243971443,\"y\":13.34},{\"x\":1685244271334,\"y\":13.34},{\"x\":1685244571292,\"y\":13.34},{\"x\":1685244871333,\"y\":13.47},{\"x\":1685245171537,\"y\":13.69},{\"x\":1685245471361,\"y\":13.69},{\"x\":1685245771298,\"y\":13.69},{\"x\":1685246071304,\"y\":13.6},{\"x\":1685246371537,\"y\":13.65},{\"x\":1685246671321,\"y\":13.56},{\"x\":1685246971335,\"y\":13.65},{\"x\":1685247271382,\"y\":13.48},{\"x\":1685247571470,\"y\":13.48},{\"x\":1685247871384,\"y\":13.28},{\"x\":1685248171411,\"y\":13.28},{\"x\":1685248471353,\"y\":13.24},{\"x\":1685248771403,\"y\":13.24},{\"x\":1685249071402,\"y\":13.23},{\"x\":1685249371376,\"y\":13.23},{\"x\":1685249671393,\"y\":13.23},{\"x\":1685249971493,\"y\":13.17},{\"x\":1685250271426,\"y\":13.08},{\"x\":1685250571467,\"y\":13.11},{\"x\":1685250871415,\"y\":13.14},{\"x\":1685251171439,\"y\":13.14},{\"x\":1685251471413,\"y\":13.14},{\"x\":1685251771409,\"y\":13.14},{\"x\":1685252071420,\"y\":13.19},{\"x\":1685252371615,\"y\":13.25},{\"x\":1685252671425,\"y\":13.17},{\"x\":1685252971434,\"y\":13.18},{\"x\":1685253271482,\"y\":13.38},{\"x\":1685253571596,\"y\":13.3},{\"x\":1685253871453,\"y\":13.38},{\"x\":1685254171462,\"y\":13.45},{\"x\":1685254471470,\"y\":13.51},{\"x\":1685254771721,\"y\":13.58},{\"x\":1685255071473,\"y\":13.58},{\"x\":1685255371478,\"y\":13.58},{\"x\":1685255671578,\"y\":13.78},{\"x\":1685255971776,\"y\":13.54},{\"x\":1685256271512,\"y\":13.78},{\"x\":1685256571498,\"y\":13.76},{\"x\":1685256871502,\"y\":13.87},{\"x\":1685257171620,\"y\":13.87},{\"x\":1685257471509,\"y\":14.11},{\"x\":1685257771511,\"y\":14.36},{\"x\":1685258071508,\"y\":14.36},{\"x\":1685258371764,\"y\":14.39},{\"x\":1685258671517,\"y\":14.56},{\"x\":1685258971516,\"y\":14.56},{\"x\":1685259271515,\"y\":14.92},{\"x\":1685259571742,\"y\":14.92},{\"x\":1685259871562,\"y\":15.01},{\"x\":1685260171531,\"y\":15.01},{\"x\":1685260471534,\"y\":15.01},{\"x\":1685260771696,\"y\":14.85},{\"x\":1685261071539,\"y\":15.04},{\"x\":1685261371589,\"y\":15.04},{\"x\":1685261671538,\"y\":15.4},{\"x\":1685261971867,\"y\":15.59},{\"x\":1685262271550,\"y\":15.59},{\"x\":1685262571548,\"y\":15.59},{\"x\":1685262871567,\"y\":15.46},{\"x\":1685263171794,\"y\":15.73},{\"x\":1685263471562,\"y\":15.69},{\"x\":1685263771602,\"y\":15.85},{\"x\":1685264071565,\"y\":15.71},{\"x\":1685264371846,\"y\":15.71},{\"x\":1685264671596,\"y\":15.72},{\"x\":1685264971615,\"y\":15.73},{\"x\":1685265271570,\"y\":15.73},{\"x\":1685265571596,\"y\":15.65},{\"x\":1685265871585,\"y\":15.47},{\"x\":1685266171591,\"y\":15.47},{\"x\":1685266471584,\"y\":15.48},{\"x\":1685266771720,\"y\":15.72},{\"x\":1685267071581,\"y\":15.72},{\"x\":1685267371587,\"y\":15.9},{\"x\":1685267671638,\"y\":16.17},{\"x\":1685267971896,\"y\":16.17},{\"x\":1685268271589,\"y\":15.98},{\"x\":1685268571603,\"y\":16.37},{\"x\":1685268871604,\"y\":16.37},{\"x\":1685269171897,\"y\":16.65},{\"x\":1685269471607,\"y\":16.58},{\"x\":1685269771613,\"y\":16.58},{\"x\":1685270071662,\"y\":16.41},{\"x\":1685270371882,\"y\":16.41},{\"x\":1685270671617,\"y\":16.41},{\"x\":1685270971621,\"y\":16.28},{\"x\":1685271271686,\"y\":16.19},{\"x\":1685271571713,\"y\":16.22},{\"x\":1685271871621,\"y\":16.15},{\"x\":1685272171630,\"y\":16.22},{\"x\":1685272471630,\"y\":15.92},{\"x\":1685272771817,\"y\":15.96},{\"x\":1685273071635,\"y\":15.96},{\"x\":1685273371650,\"y\":16.12},{\"x\":1685273671673,\"y\":15.95},{\"x\":1685273971701,\"y\":16.31},{\"x\":1685274271656,\"y\":16.31},{\"x\":1685274571692,\"y\":16.32},{\"x\":1685274871686,\"y\":16.32},{\"x\":1685275171921,\"y\":16.73},{\"x\":1685275471665,\"y\":16.65},{\"x\":1685275771698,\"y\":16.73},{\"x\":1685276071659,\"y\":16.22},{\"x\":1685276371756,\"y\":16.22},{\"x\":1685276671662,\"y\":16.48},{\"x\":1685276971675,\"y\":15.89},{\"x\":1685277271661,\"y\":15.89},{\"x\":1685277571970,\"y\":15.63},{\"x\":1685277871714,\"y\":15.68},{\"x\":1685278171675,\"y\":15.63},{\"x\":1685278471667,\"y\":15.56},{\"x\":1685278771920,\"y\":15.65},{\"x\":1685279071689,\"y\":15.87},{\"x\":1685279371671,\"y\":15.87},{\"x\":1685279671675,\"y\":15.87},{\"x\":1685279972052,\"y\":15.71},{\"x\":1685280271668,\"y\":15.71},{\"x\":1685280571670,\"y\":16.04},{\"x\":1685280871676,\"y\":16.04},{\"x\":1685281671888,\"y\":15.97},{\"x\":1685284096032,\"y\":15.5},{\"x\":1685284395921,\"y\":15.5},{\"x\":1685284695933,\"y\":15.5},{\"x\":1685284995930,\"y\":15.47},{\"x\":1685285295935,\"y\":15.47},{\"x\":1685285595944,\"y\":15.8},{\"x\":1685285895939,\"y\":15.8},{\"x\":1685286195949,\"y\":15.51},{\"x\":1685286495951,\"y\":15.51},{\"x\":1685286796009,\"y\":15.36},{\"x\":1685287095965,\"y\":15.27},{\"x\":1685287395953,\"y\":15.27},{\"x\":1685287695970,\"y\":15.36},{\"x\":1685287995955,\"y\":15.36},{\"x\":1685288295961,\"y\":15.34},{\"x\":1685288595996,\"y\":14.97},{\"x\":1685288895968,\"y\":14.97},{\"x\":1685289196133,\"y\":14.79},{\"x\":1685289495999,\"y\":14.79},{\"x\":1685289795972,\"y\":14.69},{\"x\":1685290095973,\"y\":14.69},{\"x\":1685290395973,\"y\":14.69},{\"x\":1685290695981,\"y\":14.79},{\"x\":1685290996003,\"y\":14.79},{\"x\":1685291295989,\"y\":14.79},{\"x\":1685291595985,\"y\":14.77},{\"x\":1685291896008,\"y\":14.5},{\"x\":1685292196008,\"y\":14.5},{\"x\":1685292496041,\"y\":14.55},{\"x\":1685292796005,\"y\":14.47},{\"x\":1685293096013,\"y\":14.55},{\"x\":1685293396082,\"y\":14.49},{\"x\":1685293696011,\"y\":14.45},{\"x\":1685293996026,\"y\":14.65},{\"x\":1685294296016,\"y\":14.65},{\"x\":1685294596031,\"y\":14.43},{\"x\":1685294896026,\"y\":14.43},{\"x\":1685295196031,\"y\":14.42},{\"x\":1685295496032,\"y\":14.4},{\"x\":1685295796073,\"y\":14.53},{\"x\":1685296096031,\"y\":14.53},{\"x\":1685296396105,\"y\":14.32},{\"x\":1685296696030,\"y\":14.24},{\"x\":1685296996047,\"y\":14.24},{\"x\":1685297296080,\"y\":14.48},{\"x\":1685297596038,\"y\":14.4},{\"x\":1685297896041,\"y\":14.48},{\"x\":1685298196059,\"y\":14.08},{\"x\":1685298496041,\"y\":14.08},{\"x\":1685298796049,\"y\":14.33},{\"x\":1685299096058,\"y\":14},{\"x\":1685299396061,\"y\":13.59},{\"x\":1685299696048,\"y\":13.56},{\"x\":1685299996049,\"y\":13.56},{\"x\":1685300296111,\"y\":13.8},{\"x\":1685300596061,\"y\":13.71},{\"x\":1685300896068,\"y\":13.71},{\"x\":1685301196056,\"y\":13.49},{\"x\":1685301496064,\"y\":13.49},{\"x\":1685301796076,\"y\":13.49},{\"x\":1685302096103,\"y\":13.4},{\"x\":1685302396063,\"y\":13.46},{\"x\":1685302696077,\"y\":13.34},{\"x\":1685302996145,\"y\":13.04},{\"x\":1685303296067,\"y\":12.95},{\"x\":1685303596073,\"y\":13.04},{\"x\":1685303896072,\"y\":12.69},{\"x\":1685304196079,\"y\":12.67},{\"x\":1685304496103,\"y\":12.49},{\"x\":1685304796082,\"y\":12.49},{\"x\":1685305096071,\"y\":12.49},{\"x\":1685305396094,\"y\":12.49},{\"x\":1685305696124,\"y\":12.2},{\"x\":1685305996075,\"y\":12.14},{\"x\":1685306296121,\"y\":11.8},{\"x\":1685306596072,\"y\":11.8},{\"x\":1685306896081,\"y\":11.8},{\"x\":1685307196124,\"y\":11.34},{\"x\":1685307496091,\"y\":11.34},{\"x\":1685307797175,\"y\":11.28},{\"x\":1685308096131,\"y\":11.3},{\"x\":1685308396095,\"y\":11.28},{\"x\":1685308696095,\"y\":11.3},{\"x\":1685308996098,\"y\":11.22},{\"x\":1685309296119,\"y\":11},{\"x\":1685309596104,\"y\":11},{\"x\":1685309896135,\"y\":10.5},{\"x\":1685310196123,\"y\":10.5},{\"x\":1685310496134,\"y\":10.5},{\"x\":1685310796104,\"y\":10.45},{\"x\":1685311096115,\"y\":10.45},{\"x\":1685311396137,\"y\":10.24},{\"x\":1685311696121,\"y\":10.24},{\"x\":1685311996202,\"y\":10.21},{\"x\":1685312296125,\"y\":10.21},{\"x\":1685312596146,\"y\":10.21},{\"x\":1685312896148,\"y\":9.93},{\"x\":1685313196132,\"y\":10.07},{\"x\":1685313496203,\"y\":9.89},{\"x\":1685313796150,\"y\":9.83},{\"x\":1685314096147,\"y\":9.75},{\"x\":1685314396195,\"y\":9.81},{\"x\":1685314696202,\"y\":9.81},{\"x\":1685314996169,\"y\":9.68},{\"x\":1685315296183,\"y\":9.65},{\"x\":1685315596155,\"y\":9.37},{\"x\":1685315896207,\"y\":9.43},{\"x\":1685316196167,\"y\":9.43},{\"x\":1685316496181,\"y\":9.32},{\"x\":1685316796216,\"y\":9.22},{\"x\":1685317096164,\"y\":9.22},{\"x\":1685317396213,\"y\":8.84},{\"x\":1685317696170,\"y\":8.76},{\"x\":1685317996185,\"y\":8.81},{\"x\":1685318296172,\"y\":8.72},{\"x\":1685318596191,\"y\":8.81},{\"x\":1685318896205,\"y\":8.99},{\"x\":1685319196165,\"y\":8.99},{\"x\":1685319496187,\"y\":8.9},{\"x\":1685319796169,\"y\":8.9},{\"x\":1685320096204,\"y\":8.99},{\"x\":1685320396170,\"y\":8.7},{\"x\":1685320696174,\"y\":8.65},{\"x\":1685320996175,\"y\":8.65},{\"x\":1685321296205,\"y\":8.41},{\"x\":1685321596177,\"y\":8.41},{\"x\":1685321896203,\"y\":8.41},{\"x\":1685322196246,\"y\":8.09},{\"x\":1685322496225,\"y\":7.88},{\"x\":1685322796181,\"y\":7.88},{\"x\":1685323096176,\"y\":7.73},{\"x\":1685323396175,\"y\":7.73},{\"x\":1685323696184,\"y\":7.67},{\"x\":1685323996186,\"y\":7.67},{\"x\":1685324296221,\"y\":7.83},{\"x\":1685324596190,\"y\":7.74},{\"x\":1685324896222,\"y\":7.83},{\"x\":1685325196203,\"y\":7.74},{\"x\":1685325496188,\"y\":7.32},{\"x\":1685325796536,\"y\":7.32},{\"x\":1685326096185,\"y\":7.32},{\"x\":1685326396231,\"y\":7.41},{\"x\":1685326696191,\"y\":7.41},{\"x\":1685326996194,\"y\":7.41},{\"x\":1685327296195,\"y\":7.29},{\"x\":1685327596190,\"y\":7.3},{\"x\":1685327896227,\"y\":7.33},{\"x\":1685328196279,\"y\":7.33},{\"x\":1685328496276,\"y\":7.33},{\"x\":1685328796240,\"y\":7.2},{\"x\":1685329096191,\"y\":7.2},{\"x\":1685329396192,\"y\":7.11},{\"x\":1685329696248,\"y\":7.2},{\"x\":1685329996247,\"y\":7.2},{\"x\":1685330296206,\"y\":7.2},{\"x\":1685330596222,\"y\":7.11},{\"x\":1685330896241,\"y\":7.37},{\"x\":1685331196223,\"y\":7.37},{\"x\":1685331496227,\"y\":7.37},{\"x\":1685331796287,\"y\":7.54},{\"x\":1685332096241,\"y\":7.54},{\"x\":1685332396262,\"y\":7.25},{\"x\":1685332696288,\"y\":7.34},{\"x\":1685332996282,\"y\":7.25},{\"x\":1685333296250,\"y\":7.34},{\"x\":1685333596314,\"y\":7.3},{\"x\":1685333896248,\"y\":7.3},{\"x\":1685334196250,\"y\":7.22},{\"x\":1685334496287,\"y\":7.3},{\"x\":1685334796262,\"y\":7.3},{\"x\":1685335096310,\"y\":7.34},{\"x\":1685335396322,\"y\":7.34},{\"x\":1685335696328,\"y\":7.35},{\"x\":1685335996277,\"y\":7.35},{\"x\":1685336296341,\"y\":7.46},{\"x\":1685336596305,\"y\":7.46},{\"x\":1685336896288,\"y\":7.46},{\"x\":1685337196337,\"y\":7.77},{\"x\":1685337496307,\"y\":7.68},{\"x\":1685337796344,\"y\":7.77},{\"x\":1685338096310,\"y\":7.7},{\"x\":1685338396309,\"y\":7.7},{\"x\":1685338696313,\"y\":7.87},{\"x\":1685338996338,\"y\":7.91},{\"x\":1685339296305,\"y\":8.24},{\"x\":1685339596306,\"y\":8.24},{\"x\":1685339896363,\"y\":8.87},{\"x\":1685340196325,\"y\":8.81},{\"x\":1685340496328,\"y\":8.87},{\"x\":1685340796324,\"y\":8.93},{\"x\":1685341096323,\"y\":8.93},{\"x\":1685341396403,\"y\":9.54},{\"x\":1685341696331,\"y\":9.46},{\"x\":1685341996329,\"y\":9.48},{\"x\":1685342296334,\"y\":9.53},{\"x\":1685342596385,\"y\":9.94},{\"x\":1685342896330,\"y\":9.94},{\"x\":1685343196338,\"y\":10.15},{\"x\":1685343496342,\"y\":10.74},{\"x\":1685343796354,\"y\":10.74},{\"x\":1685344096339,\"y\":11.17},{\"x\":1685344396346,\"y\":11.17},{\"x\":1685344697407,\"y\":11.29},{\"x\":1685344996353,\"y\":11.26},{\"x\":1685345296424,\"y\":11.74},{\"x\":1685345596406,\"y\":11.65},{\"x\":1685345896351,\"y\":11.65},{\"x\":1685346196416,\"y\":12.07},{\"x\":1685346496410,\"y\":12.16},{\"x\":1685346796378,\"y\":12.07},{\"x\":1685347096406,\"y\":12.03},{\"x\":1685347396359,\"y\":12.03},{\"x\":1685347696378,\"y\":12.03},{\"x\":1685347996394,\"y\":12.1},{\"x\":1685348296366,\"y\":12.1},{\"x\":1685348596360,\"y\":12.02},{\"x\":1685348896369,\"y\":12.44},{\"x\":1685349196480,\"y\":12.49},{\"x\":1685349496365,\"y\":12.49},{\"x\":1685349796376,\"y\":12.49},{\"x\":1685350096394,\"y\":12.97},{\"x\":1685350396369,\"y\":12.97},{\"x\":1685350696451,\"y\":13.05},{\"x\":1685350996421,\"y\":13.19},{\"x\":1685351296370,\"y\":13.05},{\"x\":1685351596436,\"y\":13.25},{\"x\":1685351896375,\"y\":13.25},{\"x\":1685352196381,\"y\":13.25},{\"x\":1685352496379,\"y\":13.28},{\"x\":1685352796390,\"y\":13.28},{\"x\":1685353096503,\"y\":13.97},{\"x\":1685353396412,\"y\":13.97},{\"x\":1685353696392,\"y\":13.97},{\"x\":1685353996429,\"y\":14.15},{\"x\":1685354296437,\"y\":14.15},{\"x\":1685354596450,\"y\":14.15},{\"x\":1685354896393,\"y\":14.3},{\"x\":1685355196401,\"y\":14.3},{\"x\":1685355496440,\"y\":14.36},{\"x\":1685355796402,\"y\":14.36},{\"x\":1685356096449,\"y\":14.32},{\"x\":1685356396391,\"y\":14.24},{\"x\":1685356696401,\"y\":14.32},{\"x\":1685356996401,\"y\":14.61},{\"x\":1685357296408,\"y\":14.61},{\"x\":1685357596403,\"y\":15.01},{\"x\":1685357896429,\"y\":15.59},{\"x\":1685358196393,\"y\":15.59},{\"x\":1685358496468,\"y\":15.59},{\"x\":1685358796424,\"y\":16},{\"x\":1685359096400,\"y\":16},{\"x\":1685359396448,\"y\":16.11},{\"x\":1685359696410,\"y\":16.08},{\"x\":1685359996404,\"y\":16.08},{\"x\":1685360296411,\"y\":16.35},{\"x\":1685360596442,\"y\":16.35},{\"x\":1685360896460,\"y\":16.44},{\"x\":1685361196442,\"y\":16.44},{\"x\":1685361496409,\"y\":16.44},{\"x\":1685361796427,\"y\":16.52},{\"x\":1685362096416,\"y\":16.62},{\"x\":1685362396413,\"y\":16.67},{\"x\":1685362696411,\"y\":16.68},{\"x\":1685362996461,\"y\":16.79},{\"x\":1685363296411,\"y\":16.85},{\"x\":1685363596420,\"y\":16.79},{\"x\":1685363896467,\"y\":16.76},{\"x\":1685364196435,\"y\":16.76},{\"x\":1685364496434,\"y\":16.76},{\"x\":1685364796430,\"y\":16.68},{\"x\":1685365096423,\"y\":17.1},{\"x\":1685365396432,\"y\":17.1},{\"x\":1685365696497,\"y\":17.46},{\"x\":1685365996459,\"y\":17.44},{\"x\":1685366296423,\"y\":17.46},{\"x\":1685366596445,\"y\":17.44},{\"x\":1685366896437,\"y\":17.38},{\"x\":1685367196433,\"y\":17.38},{\"x\":1685367496432,\"y\":17.38},{\"x\":1685367796435,\"y\":17.27},{\"x\":1685368096426,\"y\":17.27},{\"x\":1685368396429,\"y\":17.26},{\"x\":1685368696436,\"y\":17.26},{\"x\":1685368996438,\"y\":17.44},{\"x\":1685369296428,\"y\":17.32},{\"x\":1685369596501,\"y\":17.5},{\"x\":1685369896441,\"y\":17.42},{\"x\":1685370196509,\"y\":17.5},{\"x\":1685370496485,\"y\":17.7},{\"x\":1685370796502,\"y\":17.7},{\"x\":1685371096455,\"y\":17.7},{\"x\":1685371396510,\"y\":17.39},{\"x\":1685371696485,\"y\":17.39},{\"x\":1685371996502,\"y\":17.64},{\"x\":1685372296476,\"y\":17.31},{\"x\":1685372596474,\"y\":17.78},{\"x\":1685372896482,\"y\":17.78},{\"x\":1685373196484,\"y\":17.78},{\"x\":1685373496572,\"y\":17.86},{\"x\":1685373796514,\"y\":17.78},{\"x\":1685374096510,\"y\":17.81},{\"x\":1685374396544,\"y\":17.86},{\"x\":1685374696519,\"y\":17.78},{\"x\":1685374996566,\"y\":17.78},{\"x\":1685375296542,\"y\":17.89},{\"x\":1685375596519,\"y\":17.89},{\"x\":1685375896531,\"y\":17.89},{\"x\":1685376196570,\"y\":17.89},{\"x\":1685376496581,\"y\":18.04},{\"x\":1685376796589,\"y\":18.04},{\"x\":1685377096547,\"y\":17.74},{\"x\":1685377396613,\"y\":17.74},{\"x\":1685377696596,\"y\":17.6},{\"x\":1685377996542,\"y\":17.51},{\"x\":1685378296565,\"y\":17.51},{\"x\":1685378596624,\"y\":17.51},{\"x\":1685378896627,\"y\":17.42},{\"x\":1685379196643,\"y\":17.2},{\"x\":1685379496586,\"y\":17.42},{\"x\":1685379796637,\"y\":17.09},{\"x\":1685380096596,\"y\":17.09},{\"x\":1685380396635,\"y\":17.11},{\"x\":1685380696607,\"y\":17.04},{\"x\":1685380996713,\"y\":17.08},{\"x\":1685381296598,\"y\":16.99},{\"x\":1685381596615,\"y\":17.08},{\"x\":1685381896608,\"y\":17.03},{\"x\":1685382196647,\"y\":17.03},{\"x\":1685382496621,\"y\":16.09},{\"x\":1685382796622,\"y\":16.25},{\"x\":1685383096636,\"y\":16.25},{\"x\":1685383396656,\"y\":16.25},{\"x\":1685383696677,\"y\":16.1},{\"x\":1685383996640,\"y\":16.09},{\"x\":1685384296634,\"y\":16.09},{\"x\":1685384596702,\"y\":16.09},{\"x\":1685384896755,\"y\":15.72},{\"x\":1685385196657,\"y\":15.7},{\"x\":1685385496648,\"y\":15.72},{\"x\":1685385796721,\"y\":14.94},{\"x\":1685386096661,\"y\":14.89},{\"x\":1685386396764,\"y\":14.48},{\"x\":1685386696644,\"y\":14.48},{\"x\":1685386996711,\"y\":14.39},{\"x\":1685387296665,\"y\":14.47},{\"x\":1685387596687,\"y\":14.47},{\"x\":1685387896719,\"y\":14.45},{\"x\":1685388196746,\"y\":14.37},{\"x\":1685388496677,\"y\":14.36},{\"x\":1685388796728,\"y\":14.16},{\"x\":1685389096728,\"y\":14.95},{\"x\":1685389396772,\"y\":15.89},{\"x\":1685389696700,\"y\":15.8},{\"x\":1685389996694,\"y\":15.8},{\"x\":1685390296741,\"y\":13.52},{\"x\":1685390596769,\"y\":13.52},{\"x\":1685390896706,\"y\":13.52},{\"x\":1685391196708,\"y\":12.38},{\"x\":1685391496778,\"y\":12.52},{\"x\":1685391796848,\"y\":12.52},{\"x\":1685392096805,\"y\":12.37},{\"x\":1685392396723,\"y\":12.01},{\"x\":1685392696723,\"y\":12.01},{\"x\":1685392996799,\"y\":11.33},{\"x\":1685393296731,\"y\":11.58},{\"x\":1685393596725,\"y\":11.33},{\"x\":1685393896759,\"y\":11.64},{\"x\":1685394196778,\"y\":11.64},{\"x\":1685394496727,\"y\":11.63},{\"x\":1685394796838,\"y\":11},{\"x\":1685395096733,\"y\":10.92},{\"x\":1685395396756,\"y\":10.84},{\"x\":1685395696744,\"y\":10.81},{\"x\":1685395996738,\"y\":10.81},{\"x\":1685396296745,\"y\":10.81},{\"x\":1685396596863,\"y\":9.92},{\"x\":1685396896748,\"y\":9.92},{\"x\":1685397196744,\"y\":9.92},{\"x\":1685397496752,\"y\":9.84},{\"x\":1685397797031,\"y\":9.29},{\"x\":1685398096745,\"y\":9.59},{\"x\":1685398396778,\"y\":9.29},{\"x\":1685398696753,\"y\":9.67},{\"x\":1685398996882,\"y\":9.8},{\"x\":1685399296749,\"y\":9.67},{\"x\":1685399596872,\"y\":9.64},{\"x\":1685399896856,\"y\":9.29},{\"x\":1685400196853,\"y\":9.29},{\"x\":1685400496758,\"y\":9.29},{\"x\":1685400796806,\"y\":8.88},{\"x\":1685401096749,\"y\":8.88},{\"x\":1685401396853,\"y\":8.88},{\"x\":1685401696823,\"y\":8.87},{\"x\":1685401996749,\"y\":8.93},{\"x\":1685402296834,\"y\":8.83},{\"x\":1685402596862,\"y\":8.83},{\"x\":1685402896766,\"y\":8.83},{\"x\":1685403196764,\"y\":8.69},{\"x\":1685403496778,\"y\":8.79},{\"x\":1685403796902,\"y\":8.76},{\"x\":1685404096775,\"y\":8.76},{\"x\":1685404396829,\"y\":8.45},{\"x\":1685404696790,\"y\":8.45},{\"x\":1685404996816,\"y\":8.36},{\"x\":1685405296883,\"y\":8.71},{\"x\":1685405596870,\"y\":8.7},{\"x\":1685405896793,\"y\":8.63},{\"x\":1685406196983,\"y\":8.7},{\"x\":1685406496794,\"y\":8.47},{\"x\":1685406796799,\"y\":8.47},{\"x\":1685407096806,\"y\":8.41},{\"x\":1685407396889,\"y\":8.27},{\"x\":1685407696814,\"y\":8.19},{\"x\":1685407996818,\"y\":8.27},{\"x\":1685408296823,\"y\":8.19},{\"x\":1685408596913,\"y\":8.19},{\"x\":1685408896867,\"y\":7.82},{\"x\":1685409196827,\"y\":7.82},{\"x\":1685409496885,\"y\":7.78},{\"x\":1685409796923,\"y\":7.69},{\"x\":1685410096833,\"y\":7.69},{\"x\":1685410396863,\"y\":7.68},{\"x\":1685410696853,\"y\":7.69},{\"x\":1685410996931,\"y\":7.59},{\"x\":1685411296850,\"y\":7.59},{\"x\":1685411596860,\"y\":7.59},{\"x\":1685411896863,\"y\":7.34},{\"x\":1685412197065,\"y\":7.41},{\"x\":1685412496865,\"y\":7.34},{\"x\":1685412796871,\"y\":7.34},{\"x\":1685413096914,\"y\":7.41},{\"x\":1685413396986,\"y\":7.41},{\"x\":1685413696881,\"y\":7.41},{\"x\":1685413996886,\"y\":7.35},{\"x\":1685414296923,\"y\":7.82},{\"x\":1685414597013,\"y\":7.95},{\"x\":1685414896976,\"y\":7.95},{\"x\":1685415196895,\"y\":7.95},{\"x\":1685415496889,\"y\":7.95},{\"x\":1685415796967,\"y\":8.17},{\"x\":1685416096899,\"y\":8.17},{\"x\":1685416396952,\"y\":8.17},{\"x\":1685416696900,\"y\":8.09},{\"x\":1685416997056,\"y\":8.23},{\"x\":1685417296914,\"y\":8.21},{\"x\":1685417596918,\"y\":8.23},{\"x\":1685417896941,\"y\":8.11},{\"x\":1685418197072,\"y\":8.11},{\"x\":1685418496972,\"y\":7.78},{\"x\":1685418796976,\"y\":7.78},{\"x\":1685419096917,\"y\":7.78},{\"x\":1685419397122,\"y\":7.76},{\"x\":1685419696925,\"y\":7.7},{\"x\":1685419996981,\"y\":7.76},{\"x\":1685420296927,\"y\":7.98},{\"x\":1685420597159,\"y\":7.68},{\"x\":1685420896981,\"y\":8.25},{\"x\":1685421196938,\"y\":8.25},{\"x\":1685421496968,\"y\":9.25},{\"x\":1685421797058,\"y\":8.95},{\"x\":1685422096935,\"y\":8.95},{\"x\":1685422397004,\"y\":9.27},{\"x\":1685422696956,\"y\":9.27},{\"x\":1685422997188,\"y\":9.29},{\"x\":1685423296955,\"y\":9.29},{\"x\":1685423597001,\"y\":9.11},{\"x\":1685423896956,\"y\":9.02},{\"x\":1685424197012,\"y\":9.02},{\"x\":1685424497000,\"y\":9.11},{\"x\":1685424796971,\"y\":9.02},{\"x\":1685425096964,\"y\":10.04},{\"x\":1685425397109,\"y\":10.04},{\"x\":1685425696964,\"y\":10.02},{\"x\":1685425996974,\"y\":9.99},{\"x\":1685426296965,\"y\":10.2},{\"x\":1685426597100,\"y\":10.28},{\"x\":1685426896989,\"y\":10.33},{\"x\":1685427196988,\"y\":10.33},{\"x\":1685427497031,\"y\":10.45},{\"x\":1685427797156,\"y\":10.38},{\"x\":1685428097083,\"y\":10.94},{\"x\":1685428396991,\"y\":10.94},{\"x\":1685428696996,\"y\":10.82},{\"x\":1685428997105,\"y\":11.01},{\"x\":1685429296992,\"y\":11.01},{\"x\":1685429597030,\"y\":11.01},{\"x\":1685429896994,\"y\":11.04},{\"x\":1685430197076,\"y\":11.04},{\"x\":1685430497010,\"y\":11.39},{\"x\":1685430796999,\"y\":11.6},{\"x\":1685431097007,\"y\":11.55},{\"x\":1685431397249,\"y\":11.81},{\"x\":1685431697002,\"y\":11.81},{\"x\":1685431997013,\"y\":11.81},{\"x\":1685432297009,\"y\":11.82},{\"x\":1685432597030,\"y\":11.82},{\"x\":1685432897132,\"y\":12.15},{\"x\":1685433197016,\"y\":12.07},{\"x\":1685433497009,\"y\":12.15},{\"x\":1685433797139,\"y\":12.16},{\"x\":1685434097016,\"y\":12.19},{\"x\":1685434397064,\"y\":12.22},{\"x\":1685434697027,\"y\":12.14},{\"x\":1685434997238,\"y\":12.14},{\"x\":1685435297077,\"y\":12.32},{\"x\":1685435597014,\"y\":12.33},{\"x\":1685435897071,\"y\":12.41},{\"x\":1685436197195,\"y\":12.35},{\"x\":1685436497013,\"y\":12.35},{\"x\":1685436797015,\"y\":12.32},{\"x\":1685437097050,\"y\":12.32},{\"x\":1685437397237,\"y\":12.33},{\"x\":1685437697030,\"y\":12.33},{\"x\":1685437997069,\"y\":12.27},{\"x\":1685438297034,\"y\":12.19},{\"x\":1685438597203,\"y\":12.17},{\"x\":1685438897033,\"y\":12.34},{\"x\":1685439197064,\"y\":12.31},{\"x\":1685439497033,\"y\":12.32},{\"x\":1685439797107,\"y\":12.31},{\"x\":1685440097051,\"y\":13.11},{\"x\":1685440397038,\"y\":13.21},{\"x\":1685440697073,\"y\":13.37},{\"x\":1685440997179,\"y\":13.19},{\"x\":1685441297048,\"y\":13.28},{\"x\":1685441597041,\"y\":13.19},{\"x\":1685441897039,\"y\":13.29},{\"x\":1685442197094,\"y\":13.29},{\"x\":1685442497030,\"y\":13.33},{\"x\":1685442797045,\"y\":13.33},{\"x\":1685443097030,\"y\":13.2},{\"x\":1685443397349,\"y\":13.31},{\"x\":1685443697027,\"y\":13.31},{\"x\":1685443997092,\"y\":13.23},{\"x\":1685444297033,\"y\":13.77},{\"x\":1685444597073,\"y\":13.68},{\"x\":1685444897078,\"y\":16.19},{\"x\":1685445197034,\"y\":16.19},{\"x\":1685445497068,\"y\":16.19},{\"x\":1685445797209,\"y\":16.19},{\"x\":1685446097058,\"y\":16.19},{\"x\":1685446397051,\"y\":17.22},{\"x\":1685446697059,\"y\":17.22},{\"x\":1685446997166,\"y\":18.41},{\"x\":1685447297115,\"y\":18.41},{\"x\":1685447597112,\"y\":18.41},{\"x\":1685447897089,\"y\":18.41},{\"x\":1685448197159,\"y\":12.74},{\"x\":1685448497098,\"y\":12.72},{\"x\":1685448797127,\"y\":12.89},{\"x\":1685449097105,\"y\":12.97},{\"x\":1685449397373,\"y\":13.15},{\"x\":1685449697109,\"y\":13.03},{\"x\":1685449997136,\"y\":13.06},{\"x\":1685450297128,\"y\":13.06},{\"x\":1685450597387,\"y\":13.06},{\"x\":1685450897183,\"y\":13.21},{\"x\":1685451197144,\"y\":13.21},{\"x\":1685451497142,\"y\":13.33},{\"x\":1685451797185,\"y\":13.33},{\"x\":1685452097148,\"y\":13.57},{\"x\":1685452397249,\"y\":13.64},{\"x\":1685452697161,\"y\":13.64},{\"x\":1685452997474,\"y\":13.64},{\"x\":1685453297206,\"y\":13.97},{\"x\":1685453597173,\"y\":13.69},{\"x\":1685453897183,\"y\":13.94},{\"x\":1685454197215,\"y\":13.94},{\"x\":1685454497192,\"y\":14.16},{\"x\":1685454797260,\"y\":14.48},{\"x\":1685455097202,\"y\":14.67},{\"x\":1685455397476,\"y\":14.67},{\"x\":1685455697209,\"y\":14.86},{\"x\":1685455997240,\"y\":15.03},{\"x\":1685456297262,\"y\":15.18},{\"x\":1685456597249,\"y\":15.18},{\"x\":1685456897228,\"y\":15.09},{\"x\":1685457197269,\"y\":15.55},{\"x\":1685457497236,\"y\":15.55},{\"x\":1685457797465,\"y\":15.55},{\"x\":1685458097286,\"y\":16.03},{\"x\":1685458397242,\"y\":16.03},{\"x\":1685458697267,\"y\":16.03},{\"x\":1685458997286,\"y\":15.84},{\"x\":1685459297248,\"y\":15.84},{\"x\":1685459597268,\"y\":16.22},{\"x\":1685459897263,\"y\":16.22},{\"x\":1685460197357,\"y\":16.94},{\"x\":1685460497301,\"y\":16.94},{\"x\":1685460797266,\"y\":16.94},{\"x\":1685461097305,\"y\":16.95},{\"x\":1685461397544,\"y\":17.05},{\"x\":1685461697280,\"y\":16.95},{\"x\":1685461997291,\"y\":16.97},{\"x\":1685462297287,\"y\":16.97},{\"x\":1685462597465,\"y\":17.35},{\"x\":1685462897303,\"y\":17.35},{\"x\":1685463197366,\"y\":17.2},{\"x\":1685463737229,\"y\":17.2},{\"x\":1685464037277,\"y\":17.14},{\"x\":1685464337245,\"y\":17.14},{\"x\":1685464637256,\"y\":17.03},{\"x\":1685464937262,\"y\":17.14},{\"x\":1685465237316,\"y\":17.08},{\"x\":1685465537294,\"y\":17.08},{\"x\":1685465837334,\"y\":17.31},{\"x\":1685466137337,\"y\":17.31},{\"x\":1685466437310,\"y\":17.03},{\"x\":1685466737354,\"y\":17.04},{\"x\":1685467037407,\"y\":16.96},{\"x\":1685467337326,\"y\":17.16},{\"x\":1685467637328,\"y\":17.13},{\"x\":1685467937333,\"y\":16.81},{\"x\":1685468237339,\"y\":16.48},{\"x\":1685468537360,\"y\":16.48},{\"x\":1685468837368,\"y\":16.47},{\"x\":1685469137413,\"y\":15.9},{\"x\":1685469437370,\"y\":16.04},{\"x\":1685469737372,\"y\":15.9},{\"x\":1685470037427,\"y\":15.82},{\"x\":1685470337392,\"y\":15.82},{\"x\":1685470637406,\"y\":15.82},{\"x\":1685470937407,\"y\":15.69},{\"x\":1685471237416,\"y\":15.83},{\"x\":1685471537421,\"y\":15.83},{\"x\":1685471837423,\"y\":15.95},{\"x\":1685472137555,\"y\":15.16},{\"x\":1685472437434,\"y\":15.08},{\"x\":1685472737439,\"y\":14.87},{\"x\":1685473037727,\"y\":14.79},{\"x\":1685473337523,\"y\":15.1},{\"x\":1685473637452,\"y\":14.79},{\"x\":1685473937500,\"y\":14.51},{\"x\":1685474237504,\"y\":14.29},{\"x\":1685474537449,\"y\":14.29},{\"x\":1685474837471,\"y\":14.21},{\"x\":1685475137479,\"y\":14.06},{\"x\":1685475437511,\"y\":13.27},{\"x\":1685475737497,\"y\":13.27},{\"x\":1685476037496,\"y\":13.19},{\"x\":1685476337572,\"y\":13.61},{\"x\":1685476637511,\"y\":13.49},{\"x\":1685476937513,\"y\":13.47},{\"x\":1685477237528,\"y\":13.42},{\"x\":1685477537526,\"y\":13.44},{\"x\":1685477837530,\"y\":13.44},{\"x\":1685478137582,\"y\":13.03},{\"x\":1685478437532,\"y\":13.14},{\"x\":1685478737565,\"y\":12.83},{\"x\":1685479037545,\"y\":12.91},{\"x\":1685479337555,\"y\":12.59},{\"x\":1685479637566,\"y\":12.56},{\"x\":1685479937595,\"y\":12.5},{\"x\":1685480237565,\"y\":12.61},{\"x\":1685480537635,\"y\":12.43},{\"x\":1685480837564,\"y\":12.43},{\"x\":1685481137578,\"y\":12.27},{\"x\":1685481437654,\"y\":12.32},{\"x\":1685481737583,\"y\":12.24},{\"x\":1685482037634,\"y\":12.13},{\"x\":1685482337596,\"y\":12.13},{\"x\":1685482637588,\"y\":12.04},{\"x\":1685482937605,\"y\":11.88},{\"x\":1685483237606,\"y\":11.88},{\"x\":1685483537617,\"y\":11.87},{\"x\":1685483837694,\"y\":11.87},{\"x\":1685484137652,\"y\":11.83},{\"x\":1685484437620,\"y\":11.55},{\"x\":1685484737629,\"y\":11.83},{\"x\":1685485037682,\"y\":11.43},{\"x\":1685485337673,\"y\":11.43},{\"x\":1685485637637,\"y\":11.43},{\"x\":1685485937698,\"y\":11.4},{\"x\":1685486237666,\"y\":11.4},{\"x\":1685486537695,\"y\":11.4},{\"x\":1685486837701,\"y\":11.34},{\"x\":1685487137670,\"y\":11.34},{\"x\":1685487437690,\"y\":11.34},{\"x\":1685487737711,\"y\":11.08},{\"x\":1685488037671,\"y\":11.08},{\"x\":1685488337728,\"y\":11.08},{\"x\":1685488637752,\"y\":11.06},{\"x\":1685488937679,\"y\":11.06},{\"x\":1685489237735,\"y\":11.04},{\"x\":1685489537691,\"y\":10.96},{\"x\":1685489837848,\"y\":11.05},{\"x\":1685490137701,\"y\":11.05},{\"x\":1685490437705,\"y\":10.95},{\"x\":1685490737730,\"y\":10.86},{\"x\":1685491037756,\"y\":10.8},{\"x\":1685491337708,\"y\":10.8},{\"x\":1685491637705,\"y\":10.8},{\"x\":1685491937711,\"y\":10.71},{\"x\":1685492237764,\"y\":10.8},{\"x\":1685492537769,\"y\":10.8},{\"x\":1685492837718,\"y\":10.8},{\"x\":1685493137753,\"y\":10.8},{\"x\":1685493437930,\"y\":10.87},{\"x\":1685493737724,\"y\":10.87},{\"x\":1685494037777,\"y\":10.61},{\"x\":1685494337747,\"y\":10.52},{\"x\":1685494637852,\"y\":10.61},{\"x\":1685494937737,\"y\":10.61},{\"x\":1685495237777,\"y\":10.63},{\"x\":1685495537775,\"y\":10.62},{\"x\":1685495837812,\"y\":10.51},{\"x\":1685496137755,\"y\":10.43},{\"x\":1685496437796,\"y\":10.49},{\"x\":1685496737809,\"y\":10.49},{\"x\":1685497037761,\"y\":10.49},{\"x\":1685497337761,\"y\":10.23},{\"x\":1685497637765,\"y\":10.23},{\"x\":1685497937814,\"y\":10.31},{\"x\":1685498237807,\"y\":10.31},{\"x\":1685498537788,\"y\":10.31},{\"x\":1685498837775,\"y\":10.23},{\"x\":1685499137789,\"y\":10.23},{\"x\":1685499437805,\"y\":10.23},{\"x\":1685499737817,\"y\":10.31},{\"x\":1685500037780,\"y\":10.31},{\"x\":1685500337844,\"y\":10.14},{\"x\":1685500637891,\"y\":10.14},{\"x\":1685500937793,\"y\":10.14},{\"x\":1685501237793,\"y\":10.14},{\"x\":1685501537807,\"y\":10.05},{\"x\":1685501837925,\"y\":10.05},{\"x\":1685502137801,\"y\":10.05},{\"x\":1685502437811,\"y\":9.97},{\"x\":1685502737895,\"y\":10.14},{\"x\":1685503037900,\"y\":10.16},{\"x\":1685503337808,\"y\":10.16},{\"x\":1685503637807,\"y\":10.08},{\"x\":1685503937812,\"y\":9.94},{\"x\":1685504237850,\"y\":9.94},{\"x\":1685504537822,\"y\":9.99},{\"x\":1685504837872,\"y\":9.96},{\"x\":1685505137866,\"y\":9.98},{\"x\":1685505438032,\"y\":9.98},{\"x\":1685505737834,\"y\":9.98},{\"x\":1685506037879,\"y\":9.81},{\"x\":1685506337861,\"y\":9.81},{\"x\":1685506637914,\"y\":9.81},{\"x\":1685506937872,\"y\":9.81},{\"x\":1685507237889,\"y\":9.81},{\"x\":1685507537838,\"y\":9.81},{\"x\":1685507837888,\"y\":9.81},{\"x\":1685508137887,\"y\":9.82},{\"x\":1685508437832,\"y\":9.73},{\"x\":1685508737867,\"y\":9.82},{\"x\":1685509037974,\"y\":9.62},{\"x\":1685509337857,\"y\":9.82},{\"x\":1685509637848,\"y\":9.62},{\"x\":1685509937889,\"y\":9.62},{\"x\":1685510237947,\"y\":9.62},{\"x\":1685510537889,\"y\":9.65},{\"x\":1685510837852,\"y\":9.65},{\"x\":1685511137855,\"y\":9.65},{\"x\":1685511437965,\"y\":9.57},{\"x\":1685511737859,\"y\":9.57},{\"x\":1685512037848,\"y\":9.54},{\"x\":1685512337852,\"y\":9.55},{\"x\":1685512638025,\"y\":9.58},{\"x\":1685512937857,\"y\":9.57},{\"x\":1685513237850,\"y\":9.58},{\"x\":1685513537848,\"y\":9.57},{\"x\":1685513837893,\"y\":9.57},{\"x\":1685514137857,\"y\":9.75},{\"x\":1685514437855,\"y\":9.75},{\"x\":1685514737977,\"y\":9.84},{\"x\":1685515037889,\"y\":9.84},{\"x\":1685515337874,\"y\":9.84},{\"x\":1685515637865,\"y\":9.84},{\"x\":1685515937961,\"y\":9.84},{\"x\":1685516238059,\"y\":9.84},{\"x\":1685516537872,\"y\":9.75},{\"x\":1685516837969,\"y\":10.01},{\"x\":1685517137902,\"y\":10.01},{\"x\":1685517437997,\"y\":10.01},{\"x\":1685517737887,\"y\":10.03},{\"x\":1685518037974,\"y\":10.03},{\"x\":1685518337895,\"y\":9.92},{\"x\":1685518637932,\"y\":9.92},{\"x\":1685518937904,\"y\":9.96},{\"x\":1685519238002,\"y\":10.1},{\"x\":1685519537959,\"y\":10.1},{\"x\":1685519837988,\"y\":10.1},{\"x\":1685520137912,\"y\":10.1},{\"x\":1685520437906,\"y\":10.37},{\"x\":1685520737913,\"y\":10.33},{\"x\":1685521038006,\"y\":10.33},{\"x\":1685521337908,\"y\":10.33},{\"x\":1685521637915,\"y\":10.33},{\"x\":1685521937963,\"y\":10.25},{\"x\":1685522238080,\"y\":10.54},{\"x\":1685522537924,\"y\":10.54},{\"x\":1685522837919,\"y\":10.54},{\"x\":1685523137944,\"y\":10.5},{\"x\":1685523438045,\"y\":10.6},{\"x\":1685523737930,\"y\":10.58},{\"x\":1685524037929,\"y\":10.52},{\"x\":1685524337974,\"y\":10.82},{\"x\":1685524638007,\"y\":10.82},{\"x\":1685524937934,\"y\":10.82},{\"x\":1685525237935,\"y\":10.95},{\"x\":1685525537943,\"y\":10.99},{\"x\":1685525838078,\"y\":11.08},{\"x\":1685526137951,\"y\":11.08},{\"x\":1685526437950,\"y\":10.99},{\"x\":1685526737944,\"y\":11.07},{\"x\":1685527038721,\"y\":11.07},{\"x\":1685527338012,\"y\":11.11},{\"x\":1685527637961,\"y\":11.11},{\"x\":1685527937952,\"y\":11.07},{\"x\":1685528238080,\"y\":11.16},{\"x\":1685528537978,\"y\":11.03},{\"x\":1685528837960,\"y\":11.12},{\"x\":1685529137967,\"y\":11.08},{\"x\":1685529438131,\"y\":11.61},{\"x\":1685529738016,\"y\":11.61},{\"x\":1685530037967,\"y\":11.61},{\"x\":1685530337963,\"y\":11.61},{\"x\":1685530638067,\"y\":11.61},{\"x\":1685530937995,\"y\":11.61},{\"x\":1685531237967,\"y\":11.61},{\"x\":1685531537979,\"y\":12.07},{\"x\":1685531838029,\"y\":11.73},{\"x\":1685532137972,\"y\":11.72},{\"x\":1685532437974,\"y\":11.73},{\"x\":1685532738070,\"y\":11.43},{\"x\":1685533038022,\"y\":11.92},{\"x\":1685533338038,\"y\":16.07},{\"x\":1685533637982,\"y\":16.07},{\"x\":1685533938045,\"y\":16.07},{\"x\":1685534238057,\"y\":16.07},{\"x\":1685534537980,\"y\":16.07},{\"x\":1685534838036,\"y\":12.17},{\"x\":1685535137993,\"y\":12.17},{\"x\":1685535438136,\"y\":12.17},{\"x\":1685535737984,\"y\":12.17},{\"x\":1685536037986,\"y\":12.17},{\"x\":1685536337985,\"y\":12.17},{\"x\":1685536638024,\"y\":11.9},{\"x\":1685536938025,\"y\":15.91},{\"x\":1685537237999,\"y\":15.91},{\"x\":1685537538002,\"y\":15.91},{\"x\":1685537838106,\"y\":15.91},{\"x\":1685538138007,\"y\":15.82},{\"x\":1685538438058,\"y\":13.28},{\"x\":1685538738048,\"y\":13.28},{\"x\":1685539038104,\"y\":13.28},{\"x\":1685539338007,\"y\":13.2},{\"x\":1685539638019,\"y\":13.2},{\"x\":1685539938003,\"y\":13.33},{\"x\":1685540238052,\"y\":13.2},{\"x\":1685540538039,\"y\":16.75},{\"x\":1685540838017,\"y\":16.67},{\"x\":1685541138064,\"y\":16.75},{\"x\":1685541438054,\"y\":16.67},{\"x\":1685541738229,\"y\":17.3},{\"x\":1685542038012,\"y\":17.22},{\"x\":1685542338042,\"y\":17.3},{\"x\":1685542638126,\"y\":18.38},{\"x\":1685542938012,\"y\":18.38},{\"x\":1685543238056,\"y\":18.97},{\"x\":1685543538110,\"y\":17.86},{\"x\":1685543838052,\"y\":17.86},{\"x\":1685544138125,\"y\":17.78},{\"x\":1685544438027,\"y\":17.78},{\"x\":1685544738110,\"y\":14.96},{\"x\":1685545038075,\"y\":14.94},{\"x\":1685545338027,\"y\":14.94},{\"x\":1685545638075,\"y\":15.63},{\"x\":1685545938022,\"y\":15.63},{\"x\":1685546238174,\"y\":16},{\"x\":1685546538079,\"y\":15.83},{\"x\":1685546838020,\"y\":15.81},{\"x\":1685547138129,\"y\":14.9},{\"x\":1685547438095,\"y\":14.83},{\"x\":1685547738125,\"y\":14.9},{\"x\":1685548038046,\"y\":14.83},{\"x\":1685548338056,\"y\":14.9},{\"x\":1685548638087,\"y\":14.85},{\"x\":1685548938038,\"y\":14.85},{\"x\":1685549238040,\"y\":14.85},{\"x\":1685549538033,\"y\":14.97},{\"x\":1685549838168,\"y\":14.97},{\"x\":1685550138087,\"y\":15.03},{\"x\":1685550438030,\"y\":14.97},{\"x\":1685550738120,\"y\":14.3},{\"x\":1685551038139,\"y\":14.3},{\"x\":1685551338037,\"y\":13.6},{\"x\":1685551638033,\"y\":13.49},{\"x\":1685551938041,\"y\":13.47},{\"x\":1685552238174,\"y\":13.61},{\"x\":1685552538043,\"y\":13.61},{\"x\":1685552838043,\"y\":13.52},{\"x\":1685553138067,\"y\":13.52},{\"x\":1685553438546,\"y\":13.6},{\"x\":1685553738055,\"y\":13.52},{\"x\":1685554038140,\"y\":13.59},{\"x\":1685554338045,\"y\":13.51},{\"x\":1685554638134,\"y\":13.16},{\"x\":1685554938070,\"y\":13.16},{\"x\":1685555238057,\"y\":13.18},{\"x\":1685555538064,\"y\":13.07},{\"x\":1685555838093,\"y\":13.07},{\"x\":1685556138085,\"y\":13.14},{\"x\":1685556438188,\"y\":13.11},{\"x\":1685556738092,\"y\":13.12},{\"x\":1685557038192,\"y\":13.01},{\"x\":1685557338095,\"y\":13.01},{\"x\":1685557638182,\"y\":12.89},{\"x\":1685557938150,\"y\":12.8},{\"x\":1685558238172,\"y\":12.61},{\"x\":1685558538110,\"y\":12.8},{\"x\":1685558838201,\"y\":12.58},{\"x\":1685559138123,\"y\":12.58},{\"x\":1685559438206,\"y\":12.59},{\"x\":1685559738189,\"y\":12.57},{\"x\":1685560038129,\"y\":12.57},{\"x\":1685560338155,\"y\":12.57},{\"x\":1685560638404,\"y\":12.29},{\"x\":1685560938173,\"y\":12.29},{\"x\":1685561238169,\"y\":12.29},{\"x\":1685561538183,\"y\":12.17},{\"x\":1685561838237,\"y\":12.17},{\"x\":1685562138233,\"y\":12.21},{\"x\":1685562438249,\"y\":12.18},{\"x\":1685562738211,\"y\":12.18},{\"x\":1685563038228,\"y\":12.09},{\"x\":1685563338214,\"y\":12.07},{\"x\":1685563638217,\"y\":12.07},{\"x\":1685563938231,\"y\":11.8},{\"x\":1685564238362,\"y\":11.86},{\"x\":1685564538381,\"y\":11.83},{\"x\":1685564838277,\"y\":11.83},{\"x\":1685565138242,\"y\":11.79},{\"x\":1685565438280,\"y\":11.7},{\"x\":1685565738251,\"y\":11.53},{\"x\":1685566038259,\"y\":11.53},{\"x\":1685566338265,\"y\":11.53},{\"x\":1685566638303,\"y\":11.43},{\"x\":1685566938268,\"y\":11.43},{\"x\":1685567238323,\"y\":11.33},{\"x\":1685567538343,\"y\":11.39},{\"x\":1685567838304,\"y\":11.31},{\"x\":1685568138281,\"y\":11.39},{\"x\":1685568438336,\"y\":11.31},{\"x\":1685568738284,\"y\":11.31},{\"x\":1685569038329,\"y\":11.31},{\"x\":1685569338310,\"y\":11.25},{\"x\":1685569638302,\"y\":11.25},{\"x\":1685569938300,\"y\":11.25},{\"x\":1685570238298,\"y\":10.97},{\"x\":1685570538297,\"y\":10.97},{\"x\":1685570838294,\"y\":10.97},{\"x\":1685571138323,\"y\":10.78},{\"x\":1685571438384,\"y\":10.78},{\"x\":1685571738313,\"y\":10.78},{\"x\":1685572038419,\"y\":10.8},{\"x\":1685572338315,\"y\":10.8},{\"x\":1685572638324,\"y\":10.8},{\"x\":1685572938327,\"y\":10.44},{\"x\":1685573238329,\"y\":10.44},{\"x\":1685573538333,\"y\":10.44},{\"x\":1685573838369,\"y\":10.44},{\"x\":1685574138332,\"y\":10.44},{\"x\":1685574438328,\"y\":10.43},{\"x\":1685574738335,\"y\":10.43},{\"x\":1685575038372,\"y\":10.42},{\"x\":1685575338334,\"y\":10.43},{\"x\":1685575638376,\"y\":10.44},{\"x\":1685575938389,\"y\":10.48},{\"x\":1685576238419,\"y\":10.39},{\"x\":1685576538344,\"y\":10.11},{\"x\":1685576838359,\"y\":10.2},{\"x\":1685577138380,\"y\":10.29},{\"x\":1685577438375,\"y\":10.29},{\"x\":1685577738413,\"y\":10.3},{\"x\":1685578038361,\"y\":10.29},{\"x\":1685578338371,\"y\":10.3},{\"x\":1685578638503,\"y\":10.18},{\"x\":1685578938376,\"y\":10.18},{\"x\":1685579238383,\"y\":10.09},{\"x\":1685579538380,\"y\":10.17},{\"x\":1685579838438,\"y\":10.13},{\"x\":1685580138376,\"y\":9.88},{\"x\":1685580438398,\"y\":9.88},{\"x\":1685580738405,\"y\":9.94},{\"x\":1685581038616,\"y\":9.94},{\"x\":1685581338395,\"y\":9.94},{\"x\":1685581638435,\"y\":9.94},{\"x\":1685581938409,\"y\":9.88},{\"x\":1685582238480,\"y\":9.86},{\"x\":1685582538402,\"y\":9.86},{\"x\":1685582838405,\"y\":9.86},{\"x\":1685583138415,\"y\":9.86},{\"x\":1685583438613,\"y\":9.86},{\"x\":1685583738415,\"y\":9.88},{\"x\":1685584038410,\"y\":9.88},{\"x\":1685584338448,\"y\":9.79},{\"x\":1685584638454,\"y\":9.88},{\"x\":1685584938414,\"y\":9.88},{\"x\":1685585238420,\"y\":9.98},{\"x\":1685585538423,\"y\":9.89},{\"x\":1685585838440,\"y\":9.89},{\"x\":1685586138428,\"y\":9.84},{\"x\":1685586438423,\"y\":9.84},{\"x\":1685586738424,\"y\":9.79},{\"x\":1685587038648,\"y\":9.93},{\"x\":1685587338431,\"y\":9.79},{\"x\":1685587638450,\"y\":9.79},{\"x\":1685587938475,\"y\":9.88},{\"x\":1685588238559,\"y\":9.88},{\"x\":1685588538441,\"y\":9.88},{\"x\":1685588838584,\"y\":9.67},{\"x\":1685589138428,\"y\":9.58},{\"x\":1685589438536,\"y\":9.67},{\"x\":1685589738473,\"y\":9.67},{\"x\":1685590038433,\"y\":9.67},{\"x\":1685590338478,\"y\":9.67},{\"x\":1685590638761,\"y\":9.42},{\"x\":1685590938425,\"y\":9.42},{\"x\":1685591238442,\"y\":9.42},{\"x\":1685591538439,\"y\":9.31},{\"x\":1685591838504,\"y\":9.31},{\"x\":1685592138436,\"y\":9.34},{\"x\":1685592438435,\"y\":9.34},{\"x\":1685592738487,\"y\":9.38},{\"x\":1685593038723,\"y\":9.38},{\"x\":1685593338444,\"y\":9.38},{\"x\":1685593638424,\"y\":9.34},{\"x\":1685593938457,\"y\":9.34},{\"x\":1685594238655,\"y\":9.86},{\"x\":1685594538452,\"y\":9.86},{\"x\":1685594838449,\"y\":9.86},{\"x\":1685595138489,\"y\":9.84},{\"x\":1685595438547,\"y\":9.84},{\"x\":1685595738460,\"y\":9.78},{\"x\":1685596038492,\"y\":9.85},{\"x\":1685596338571,\"y\":9.85},{\"x\":1685596638545,\"y\":9.85},{\"x\":1685596938457,\"y\":9.76},{\"x\":1685597238477,\"y\":9.85},{\"x\":1685597538472,\"y\":9.8},{\"x\":1685597838494,\"y\":9.83},{\"x\":1685598138501,\"y\":9.86},{\"x\":1685598438509,\"y\":10.14},{\"x\":1685598738535,\"y\":10.14},{\"x\":1685599038819,\"y\":10.14},{\"x\":1685599338484,\"y\":10.07},{\"x\":1685599638529,\"y\":10.07},{\"x\":1685599938480,\"y\":10.14},{\"x\":1685600238698,\"y\":10.23},{\"x\":1685600538482,\"y\":10.1},{\"x\":1685600838527,\"y\":10.43},{\"x\":1685601138487,\"y\":10.43},{\"x\":1685601438740,\"y\":10.43},{\"x\":1685601738547,\"y\":10.45},{\"x\":1685602038498,\"y\":10.36},{\"x\":1685602338488,\"y\":10.43},{\"x\":1685602638682,\"y\":10.46},{\"x\":1685602938581,\"y\":10.46},{\"x\":1685603238508,\"y\":10.47},{\"x\":1685603538503,\"y\":10.47},{\"x\":1685603838572,\"y\":10.47},{\"x\":1685604138511,\"y\":10.47},{\"x\":1685604438579,\"y\":10.6},{\"x\":1685604738515,\"y\":10.51},{\"x\":1685605038560,\"y\":10.55},{\"x\":1685605338556,\"y\":11.07},{\"x\":1685605638563,\"y\":11.07},{\"x\":1685605938519,\"y\":11.07},{\"x\":1685606238594,\"y\":11.05},{\"x\":1685606538513,\"y\":11.12},{\"x\":1685606838518,\"y\":11.15},{\"x\":1685607138518,\"y\":11.15},{\"x\":1685607438879,\"y\":11.19},{\"x\":1685607738543,\"y\":11.19},{\"x\":1685608038530,\"y\":11.42},{\"x\":1685608338527,\"y\":11.33},{\"x\":1685608638628,\"y\":11.33},{\"x\":1685608938572,\"y\":11.54},{\"x\":1685609238526,\"y\":11.54},{\"x\":1685609538568,\"y\":11.54},{\"x\":1685609838674,\"y\":11.73},{\"x\":1685610138530,\"y\":11.54},{\"x\":1685610438525,\"y\":11.73},{\"x\":1685610738604,\"y\":11.81},{\"x\":1685611038666,\"y\":11.81},{\"x\":1685611338564,\"y\":11.72},{\"x\":1685611638584,\"y\":12.09},{\"x\":1685611938537,\"y\":12.09},{\"x\":1685612238596,\"y\":12.09},{\"x\":1685612538547,\"y\":12.11},{\"x\":1685612838540,\"y\":12.11},{\"x\":1685613138539,\"y\":12.07},{\"x\":1685613438767,\"y\":12.53},{\"x\":1685613738611,\"y\":12.64},{\"x\":1685614038551,\"y\":12.51},{\"x\":1685614338551,\"y\":12.64},{\"x\":1685614638741,\"y\":12.64},{\"x\":1685614938559,\"y\":12.64},{\"x\":1685615238587,\"y\":13.05},{\"x\":1685615538593,\"y\":13.15},{\"x\":1685615838836,\"y\":13.07},{\"x\":1685616138551,\"y\":13.07},{\"x\":1685616438549,\"y\":13.17},{\"x\":1685616738558,\"y\":13.26},{\"x\":1685617038760,\"y\":13.26},{\"x\":1685617338558,\"y\":13.36},{\"x\":1685617638534,\"y\":13.36},{\"x\":1685617938635,\"y\":13.73},{\"x\":1685618238566,\"y\":13.71},{\"x\":1685618538558,\"y\":13.71},{\"x\":1685618838593,\"y\":13.75},{\"x\":1685619138565,\"y\":13.75},{\"x\":1685619438673,\"y\":13.93},{\"x\":1685619738585,\"y\":13.93}","],\"labels\":",[989,17920,11999],{},"\",\"payloadType\":\"json\",\"x\":150,\"y\":180,\"wires\":[[\"3eb08d4843164efc\"]]},{\"id\":\"41e847ff22249c0e\",\"type\":\"ui_group\",\"name\":\"Temperature\",\"tab\":\"1d985094b1a81b0c\",\"order\":5,\"disp\":true,\"width\":\"24\",\"collapse\":false,\"className\":\"\"},{\"id\":\"1d985094b1a81b0c\",\"type\":\"ui_tab\",\"name\":\"Wide View\",\"icon\":\"dashboard\",\"disabled\":false,\"hidden\":false}",[82,17923,17925],{"id":17924},"_3-using-sliders-and-persisting-the-current-value","3. Using sliders and persisting the current value",[15,17927,17928],{},"Sliders are a really useful user-interface element. Where you need to control the speed of a piece of machinery, having the ability to use a slider rather than manually typing in a value is a much better fit for shop-floor HMIs.",[15,17930,17931],{},"When using sliders in your dashboards, it's important to consider how you will persist the state of the slider. If you don't persist the state, you will find that a redeploy of your dashboard will set the slider back to the default value. That would also change the speed of your machine.",[15,17933,17934],{},[239,17935],{"alt":17936,"src":17937,"title":17936},"An example of a slider in a HMI","\u002Fblog\u002F2023\u002F06\u002Fimages\u002Fslider-ui.gif",[15,17939,17940],{},"To retain the current value of the slider we can use Node-RED's context. Each time the slider value is updated, we store the value in context. Each time we deploy the flow, we can now load the value back from context.",[15,17942,17943],{},"If you'd like to view this slider and the flow which makes it work on your own Node-RED, you can import the flow below.",[15,17945,17946,17947,5411],{},"{% renderFlow 300 %}\n",[989,17948,17949,17950,17952,17953,17955,17956,17959,17960,17963,17964,17966,17967,17969],{},"{\"id\":\"05340e7a133098a6\",\"type\":\"ui_slider\",\"z\":\"0e6be5088cecccc1\",\"name\":\"\",\"label\":\"",[17820,17951],{"value":1350},"\",\"tooltip\":\"\",\"group\":\"41e847ff22249c0e\",\"order\":1,\"width\":0,\"height\":0,\"passthru\":true,\"outs\":\"all\",\"topic\":\"topic\",\"topicType\":\"msg\",\"min\":0,\"max\":\"20\",\"step\":1,\"className\":\"\",\"x\":230,\"y\":300,\"wires\":[[\"945db61c94fc0704\",\"ad7819da2cfbcd4e\"]]},{\"id\":\"849d76d146ff8c12\",\"type\":\"inject\",\"z\":\"0e6be5088cecccc1\",\"name\":\"Inject on deploy\",\"props\":",[989,17954],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":true,\"onceDelay\":0.1,\"topic\":\"\",\"x\":160,\"y\":240,\"wires\":[[\"aeedb3c60965c1af\"]]},{\"id\":\"945db61c94fc0704\",\"type\":\"change\",\"z\":\"0e6be5088cecccc1\",\"name\":\"Set global-slider-value = msg.payload\",\"rules\":",[989,17957,17958],{},"{\"t\":\"set\",\"p\":\"slider-value\",\"pt\":\"global\",\"to\":\"payload\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":450,\"y\":300,\"wires\":[[]]},{\"id\":\"aeedb3c60965c1af\",\"type\":\"change\",\"z\":\"0e6be5088cecccc1\",\"name\":\"Set msg.payload = global.slider-value\",\"rules\":",[989,17961,17962],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"slider-value\",\"tot\":\"global\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":410,\"y\":240,\"wires\":[[\"05340e7a133098a6\"]]},{\"id\":\"ad7819da2cfbcd4e\",\"type\":\"ui_text\",\"z\":\"0e6be5088cecccc1\",\"group\":\"41e847ff22249c0e\",\"order\":2,\"width\":0,\"height\":0,\"name\":\"\",\"label\":\"\",\"format\":\"The current value is ",[17820,17965],{"value":1350}," meters per minute\",\"layout\":\"row-spread\",\"className\":\"\",\"style\":false,\"font\":\"\",\"fontSize\":16,\"color\":\"#000000\",\"x\":350,\"y\":340,\"wires\":",[989,17968],{},"},{\"id\":\"41e847ff22249c0e\",\"type\":\"ui_group\",\"name\":\"Meters per Minute\",\"tab\":\"466e33abb95e4dd4\",\"order\":5,\"disp\":true,\"width\":\"10\",\"collapse\":false,\"className\":\"\"},{\"id\":\"466e33abb95e4dd4\",\"type\":\"ui_tab\",\"name\":\"Sliders\",\"icon\":\"dashboard\",\"order\":3,\"disabled\":false,\"hidden\":false}",[15,17971,17972,17973,17977],{},"We hope you found these tips useful, if you'd like to suggest some of your own tips which you think we should share in our future blog posts please ",[256,17974,17976],{"href":17975},"mailto:contact@flowfuse.com","get in touch",". You can also read some of our previous Node-RED tips using the links below.",[15,17979,17980,17984,17986,17990,17992,17996,17998,18002,18004,18008,18010],{},[256,17981,17983],{"href":17982},"\u002Fblog\u002F2023\u002F04\u002F3-quick-node-red-tips-6\u002F","Node-RED Tips - Subflows, Link Nodes, and the Range Node",[2278,17985],{},[256,17987,17989],{"href":17988},"\u002Fblog\u002F2023\u002F03\u002F3-quick-node-red-tips-5\u002F","Node-RED Tips - Importing, Exporting, and Grouping Flows",[2278,17991],{},[256,17993,17995],{"href":17994},"\u002Fblog\u002F2023\u002F03\u002F3-quick-node-red-tips-4\u002F","Node-RED Tips - Smooth, Catch, and Maths",[2278,17997],{},[256,17999,18001],{"href":18000},"\u002Fblog\u002F2023\u002F03\u002F3-quick-node-red-tips-3\u002F","Node-RED Tips - Exec, Filter, and Debug",[2278,18003],{},[256,18005,18007],{"href":18006},"\u002Fblog\u002F2023\u002F02\u002F3-quick-node-red-tips-2\u002F","Node-RED Tips - Deploying, Debugging, and Delaying",[2278,18009],{},[256,18011,18013],{"href":18012},"\u002Fblog\u002F2023\u002F02\u002F3-quick-node-red-tips-1\u002F","Node-RED Tips - Wiring Shortcuts",{"title":265,"searchDepth":266,"depth":266,"links":18015},[18016,18017,18018],{"id":17787,"depth":274,"text":17788},{"id":17881,"depth":274,"text":17882},{"id":17924,"depth":274,"text":17925},"2023-06-01","Learn three practical tips for improving your Node-RED Dashboard workflow, such as creating responsive layouts, adding multiple data series to charts, and persisting slider values.","\u002Fimages\u002Fblog\u002Fnr-quicktips.jpg",{"excerpt":18023},{"type":12,"value":18024},[18025],[15,18026,17777],{},"\u002Fblog\u002F2023\u002F06\u002F3-quick-node-red-tips-7",{"title":17771,"description":18020},{"loc":18027},"blog\u002F2023\u002F06\u002F3-quick-node-red-tips-7","Save yourself time when working with Node-RED Dashboards with these three tips.",[487,2164,3010,303,18033],"node-red tips","h5GmOwlW7UuahwdTPwHCe-u7SZQDJw8zjkVdPQFXuZ4",{"id":18036,"title":18037,"authors":18038,"body":18039,"cta":3,"date":18343,"description":18344,"extension":287,"image":18345,"lastUpdated":3,"meta":18346,"navigation":295,"path":18354,"seo":18355,"sitemap":18356,"stem":18357,"subtitle":18358,"tags":18359,"tldr":3,"video":3,"__hash__":18360},"blog\u002Fblog\u002F2023\u002F05\u002Fpersisting-chart-data-in-node-red.md","Persisting chart data in Node-RED Dashboard 1",[16802],{"type":12,"value":18040,"toc":18333},[18041,18047,18050,18072,18076,18079,18082,18086,18089,18092,18107,18111,18114,18117,18121,18124,18127,18143,18146,18149,18167,18170,18176,18179,18183,18186,18189,18209,18212,18236,18239,18243,18246,18271,18274,18280,18287,18290,18296,18325,18328,18330],[15,18042,18043,18044,437],{},"Node-RED makes it easy to create HMI (Human Machine Interfaces) using ",[256,18045,2228],{"href":2226,"rel":18046},[402],[15,18048,18049],{},"One of the most useful features of Dashboard 1 is the ability to store historic data passed to a chart within the chart node itself. This makes your flows far simpler than would be the case if you needed to send the entire data set to the chart for each update.",[228,18051,18054,18055,18054,18065],{"className":18052},[18053],"blog-update-notes","\n    ",[15,18056,18057,18060,18061,437],{},[33,18058,18059],{},"UPDATE:"," Since this article was published, Node-RED Dashboard (1.0) has been ",[256,18062,18064],{"href":18063,"target":16452},"https:\u002F\u002Fdiscourse.nodered.org\u002Ft\u002Fannouncement-node-red-dashboard-v1-deprecation-notice\u002F89006","deprecated",[15,18066,18067,18068,18071],{},"Instead, it is recommended to use ",[256,18069,18070],{"href":3518},"FlowFuse Dashboard (Dashboard 2.0)"," which is a more modern and feature-rich dashboard solution for Node-RED.",[82,18073,18075],{"id":18074},"the-importance-of-persisting-chart-data","The Importance of Persisting Chart Data",[15,18077,18078],{},"Storing the data in the chart node is fine to show prototypes of HMIs, but where it's vital the correct data is always shown we are going to need a backup. Data can easily be lost when you move your flow to a new device, restart your instance, or simply when upgrading Node-RED.",[15,18080,18081],{},"How can we store our chart data so we can be confident it will be there each time a user views your HMI?",[82,18083,18085],{"id":18084},"example-dashboard","Example Dashboard",[15,18087,18088],{},"In this example, we are passing in a random number between one and 10 each second. With each new value received the chart updates and as mentioned about, the values are also stored in the chart node.",[15,18090,18091],{},"If you'd like to see and edit the flows I've created, you can copy and paste the JSON below into your Node-RED import feature.",[15,18093,5928,18094,18106],{},[989,18095,18096,18097,18099,18100,18102,18103,18105],{},"{\"id\":\"c6825b1001216b89\",\"type\":\"inject\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"props\":",[989,18098],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":110,\"y\":220,\"wires\":[[\"6b609d978540fb2a\"]]},{\"id\":\"6b609d978540fb2a\",\"type\":\"Number\",\"z\":\"668c56888fd0f960\",\"name\":\"Random Number\",\"minimum\":\"1\",\"maximum\":\"10\",\"roundTo\":\"0\",\"Floor\":true,\"x\":270,\"y\":220,\"wires\":[[\"794846db6dc8cef8\"]]},{\"id\":\"794846db6dc8cef8\",\"type\":\"ui_chart\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"group\":\"af1535b39b74f94a\",\"order\":0,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"3600\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,18101,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":430,\"y\":220,\"wires\":[[\"ad53848ee4b0d91e\"]]},{\"id\":\"ad53848ee4b0d91e\",\"type\":\"debug\",\"z\":\"668c56888fd0f960\",\"name\":\"debug\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":550,\"y\":220,\"wires\":",[989,18104],{},"},{\"id\":\"af1535b39b74f94a\",\"type\":\"ui_group\",\"name\":\"Example\",\"tab\":\"14f1442eb7525190\",\"order\":1,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"14f1442eb7525190\",\"type\":\"ui_tab\",\"name\":\"Home\",\"icon\":\"dashboard\",\"disabled\":false,\"hidden\":false}","\n{% endrenderFlow %}\nx",[82,18108,18110],{"id":18109},"how-can-we-store-and-recall-the-chart-data","How can we store and recall the chart data?",[15,18112,18113],{},"The chart node has a really useful feature which allows us to access all the data currently shown in the chart. Each time the chart receives new data, it's added to the existing values then the whole data set is sent out the outbound port of the chart node.",[15,18115,18116],{},"Now that we have a way to easily access the chart data in a single payload, we next need to store that data somewhere safer. I'm going to explain 3 potential solutions, which I use on a regular basis.",[892,18118,18120],{"id":18119},"_1-node-red-file-out-and-file-in-nodes","1. Node-RED file-out and file-in nodes",[15,18122,18123],{},"Node-RED can read and write data to a local filesystem. Being that we already have the chart data in a single payload, we just need to write that payload to a file for later use, which we can do using the file-out node.",[15,18125,18126],{},"This example flow shows how to use the file-out node to write the chart data to your local filesystem.",[15,18128,5928,18129,5411],{},[989,18130,18131,18132,18134,18135,18137,18138,18140,18141,18105],{},"{\"id\":\"ead9df683d29fb8a\",\"type\":\"inject\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"props\":",[989,18133],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":110,\"y\":560,\"wires\":[[\"ef5359b8bd3f78b3\"]]},{\"id\":\"ef5359b8bd3f78b3\",\"type\":\"Number\",\"z\":\"668c56888fd0f960\",\"name\":\"Random Number\",\"minimum\":\"1\",\"maximum\":\"10\",\"roundTo\":\"0\",\"Floor\":true,\"x\":270,\"y\":560,\"wires\":[[\"69ad440cd8d1ce30\"]]},{\"id\":\"69ad440cd8d1ce30\",\"type\":\"ui_chart\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"group\":\"af1535b39b74f94a\",\"order\":0,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"3600\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,18136,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":430,\"y\":560,\"wires\":[[\"e4e7758028477505\",\"d9d6a2e34767f568\"]]},{\"id\":\"e4e7758028477505\",\"type\":\"debug\",\"z\":\"668c56888fd0f960\",\"name\":\"debug\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":550,\"y\":560,\"wires\":",[989,18139],{},"},{\"id\":\"d9d6a2e34767f568\",\"type\":\"json\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"property\":\"payload\",\"action\":\"\",\"pretty\":false,\"x\":550,\"y\":600,\"wires\":[[\"b5b020fb17f615df\"]]},{\"id\":\"b5b020fb17f615df\",\"type\":\"file\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"filename\":\"example.json\",\"filenameType\":\"str\",\"appendNewline\":true,\"createDir\":false,\"overwriteFile\":\"true\",\"encoding\":\"none\",\"x\":690,\"y\":600,\"wires\":[[\"a6d9eab41d4dcf97\"]]},{\"id\":\"a6d9eab41d4dcf97\",\"type\":\"debug\",\"z\":\"668c56888fd0f960\",\"name\":\"debug 92\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":840,\"y\":600,\"wires\":",[989,18142],{},[15,18144,18145],{},"As the chart node sends the full data set each time new data is added, we overwrite the content of the file rather than append the new values.",[15,18147,18148],{},"The next step is to pull the data back from the filesystem to your Node-RED instance. Node-RED makes this very easy using the file-in node.",[15,18150,5928,18151,5411],{},[989,18152,18131,18153,18134,18155,18137,18157,18140,18159,18161,18162,18164,18165,18105],{},[989,18154],{},[989,18156,17832],{},[989,18158],{},[989,18160],{},"},{\"id\":\"e9cb9350f1aaeb38\",\"type\":\"inject\",\"z\":\"668c56888fd0f960\",\"name\":\"import data\",\"props\":",[989,18163],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":110,\"y\":660,\"wires\":[[\"600f014947f73d8f\"]]},{\"id\":\"600f014947f73d8f\",\"type\":\"file in\",\"z\":\"668c56888fd0f960\",\"name\":\"\",\"filename\":\"example.json\",\"filenameType\":\"str\",\"format\":\"utf8\",\"chunk\":false,\"sendError\":false,\"encoding\":\"none\",\"allProps\":false,\"x\":270,\"y\":660,\"wires\":[[\"972118c0e114f47b\",\"69ad440cd8d1ce30\"]]},{\"id\":\"972118c0e114f47b\",\"type\":\"debug\",\"z\":\"668c56888fd0f960\",\"name\":\"debug 93\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":420,\"y\":660,\"wires\":",[989,18166],{},[15,18168,18169],{},"When you press the 'import data' trigger node, the data is loaded in from the filesystem and shown in the chart. You may want to automate that task to run each you deploy your Node-RED instance.",[15,18171,18172],{},[239,18173],{"alt":18174,"src":18175,"title":18174},"Import data on deploy","\u002Fblog\u002F2023\u002F05\u002Fimages\u002Finject-on-deploy.png",[15,18177,18178],{},"Bear in mind that your data is stored in your filesystem, if your storage drive fails you will lose your data, you might want to consider taking backups and storing elsewhere for emergencies.",[892,18180,18182],{"id":18181},"_2-flowfuses-persistent-context","2. FlowFuse's persistent context",[15,18184,18185],{},"FlowFuse Cloud and premium self hosted version provides persistent context storage as part of its Node-RED instances. This allows you to create, read, update, and delete data as needed, even if you have restarted a Node-RED instance.",[15,18187,18188],{},"This flow shows chart data being sent to persistent context so we can access it later. The process is very similar to using the file-out and file-in nodes.",[15,18190,5928,18191,5411],{},[989,18192,18193,18194,18196,18197,18199,18200,18202,18203,18206,18207,18105],{},"{\"id\":\"c6825b1001216b89\",\"type\":\"inject\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"props\":",[989,18195],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":170,\"y\":100,\"wires\":[[\"6b609d978540fb2a\"]]},{\"id\":\"794846db6dc8cef8\",\"type\":\"ui_chart\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"group\":\"af1535b39b74f94a\",\"order\":0,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"3600\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,18198,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":490,\"y\":100,\"wires\":[[\"ad53848ee4b0d91e\",\"938c7d878545e623\"]]},{\"id\":\"ad53848ee4b0d91e\",\"type\":\"debug\",\"z\":\"4767c2f7095bee53\",\"name\":\"debug\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":610,\"y\":100,\"wires\":",[989,18201],{},"},{\"id\":\"6b609d978540fb2a\",\"type\":\"Number\",\"z\":\"4767c2f7095bee53\",\"name\":\"Random Number\",\"minimum\":\"1\",\"maximum\":\"10\",\"roundTo\":\"0\",\"Floor\":true,\"x\":330,\"y\":100,\"wires\":[[\"794846db6dc8cef8\"]]},{\"id\":\"938c7d878545e623\",\"type\":\"change\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"rules\":",[989,18204,18205],{},"{\"t\":\"set\",\"p\":\"#:(persistent)::chart-data\",\"pt\":\"global\",\"to\":\"payload\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":660,\"y\":140,\"wires\":[[\"3792cc96a748e75a\"]]},{\"id\":\"3792cc96a748e75a\",\"type\":\"debug\",\"z\":\"4767c2f7095bee53\",\"name\":\"debug 1\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":840,\"y\":140,\"wires\":",[989,18208],{},[15,18210,18211],{},"We now need to have a method to load the data back into our chart. We will again use a manual 'import data' trigger to load the full set of data from the persistent context, and then push it back into the chart.",[15,18213,5928,18214,5411],{},[989,18215,18193,18216,18196,18218,18199,18220,18202,18222,18206,18224,18226,18227,18229,18230,18233,18234,18105],{},[989,18217],{},[989,18219,17832],{},[989,18221],{},[989,18223,18205],{},[989,18225],{},"},{\"id\":\"3379276c77b4691c\",\"type\":\"inject\",\"z\":\"4767c2f7095bee53\",\"name\":\"import data\",\"props\":",[989,18228],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":true,\"onceDelay\":0.1,\"topic\":\"\",\"x\":150,\"y\":180,\"wires\":[[\"ddd1ef41321fb4a6\"]]},{\"id\":\"ddd1ef41321fb4a6\",\"type\":\"change\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"rules\":",[989,18231,18232],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"#:(persistent)::chart-data\",\"tot\":\"global\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":320,\"y\":180,\"wires\":[[\"794846db6dc8cef8\",\"fa65b958e34bc971\"]]},{\"id\":\"fa65b958e34bc971\",\"type\":\"debug\",\"z\":\"4767c2f7095bee53\",\"name\":\"debug 2\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"false\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":480,\"y\":180,\"wires\":",[989,18235],{},[15,18237,18238],{},"You may have noticed that when we are pushing duplicate data into the chart it automatically checks to see if the data is already stored. If the data points are already in the chart the new data is disregard. This saves us writing an extra section of the flow to delete the data before we load it in.",[892,18240,18242],{"id":18241},"_3-expose-the-data-via-an-api-then-manually-import-it","3. Expose the data via an API then manually import it",[15,18244,18245],{},"In some cases you may want to copy your chart data to somewhere outside of your Node-RED instances. You can do this by creating a simple API which allows an outside system to request the chart data. You can also manually go to the URL of the API in a web browser to get your data. This example flow allows a user or system to access the chart data via a URL.",[15,18247,5928,18248,5411],{},[989,18249,18250,18251,18253,18254,18256,18257,18259,18260,18263,18264,18266,18267,18270],{},"{\"id\":\"6523e86042252710\",\"type\":\"inject\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"props\":",[989,18252],{},",\"repeat\":\"1\",\"crontab\":\"\",\"once\":false,\"onceDelay\":0.1,\"topic\":\"\",\"x\":150,\"y\":540,\"wires\":[[\"d51aba5f9a808592\"]]},{\"id\":\"427c60f2c4f523b7\",\"type\":\"ui_chart\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"group\":\"af1535b39b74f94a\",\"order\":0,\"width\":0,\"height\":0,\"label\":\"chart\",\"chartType\":\"line\",\"legend\":\"false\",\"xformat\":\"HH:mm:ss\",\"interpolate\":\"linear\",\"nodata\":\"\",\"dot\":false,\"ymin\":\"\",\"ymax\":\"\",\"removeOlder\":1,\"removeOlderPoints\":\"\",\"removeOlderUnit\":\"3600\",\"cutout\":0,\"useOneColor\":false,\"useUTC\":false,\"colors\":",[989,18255,17832],{},",\"outputs\":1,\"useDifferentColor\":false,\"className\":\"\",\"x\":470,\"y\":540,\"wires\":[[\"ba84cd1820120139\",\"d9087436f4769691\"]]},{\"id\":\"ba84cd1820120139\",\"type\":\"debug\",\"z\":\"4767c2f7095bee53\",\"name\":\"debug\",\"active\":true,\"tosidebar\":true,\"console\":false,\"tostatus\":false,\"complete\":\"payload\",\"targetType\":\"msg\",\"statusVal\":\"\",\"statusType\":\"auto\",\"x\":590,\"y\":540,\"wires\":",[989,18258],{},"},{\"id\":\"d51aba5f9a808592\",\"type\":\"Number\",\"z\":\"4767c2f7095bee53\",\"name\":\"Random Number\",\"minimum\":\"1\",\"maximum\":\"10\",\"roundTo\":\"0\",\"Floor\":true,\"x\":310,\"y\":540,\"wires\":[[\"427c60f2c4f523b7\"]]},{\"id\":\"d9087436f4769691\",\"type\":\"change\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"rules\":",[989,18261,18262],{},"{\"t\":\"set\",\"p\":\"chart-data\",\"pt\":\"flow\",\"to\":\"payload\",\"tot\":\"msg\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":630,\"y\":580,\"wires\":[[]]},{\"id\":\"4dd97b29430ad2ba\",\"type\":\"http in\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"url\":\"\u002Fdata\",\"method\":\"get\",\"upload\":false,\"swaggerDoc\":\"\",\"x\":200,\"y\":640,\"wires\":[[\"b4f0eb085cc91834\"]]},{\"id\":\"7ca49e5465699355\",\"type\":\"http response\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"statusCode\":\"\",\"headers\":{},\"x\":670,\"y\":640,\"wires\":",[989,18265],{},"},{\"id\":\"b4f0eb085cc91834\",\"type\":\"change\",\"z\":\"4767c2f7095bee53\",\"name\":\"Get the chart data from flow.chart-data\",\"rules\":",[989,18268,18269],{},"{\"t\":\"set\",\"p\":\"payload\",\"pt\":\"msg\",\"to\":\"chart-data\",\"tot\":\"flow\"}",",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":440,\"y\":640,\"wires\":[[\"7ca49e5465699355\"]]},{\"id\":\"af1535b39b74f94a\",\"type\":\"ui_group\",\"name\":\"Example\",\"tab\":\"14f1442eb7525190\",\"order\":1,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"14f1442eb7525190\",\"type\":\"ui_tab\",\"name\":\"Home\",\"icon\":\"dashboard\",\"disabled\":false,\"hidden\":false}",[15,18272,18273],{},"We can now access the data by simply visiting the URL of the API.",[15,18275,18276],{},[239,18277],{"alt":18278,"src":18279,"title":18278},"The chart data accessed via the API in a web browser","\u002Fblog\u002F2023\u002F05\u002Fimages\u002Fdata-in-browser.png",[15,18281,18282,18283,437],{},"Bear in mind that you should secure the API as appropriate for the data. If you don't put security around the API, anyone on the same network as your Node-RED instance can access your chart data. Potentially that could give access to our data to the whole internet, so where needed take steps to keep your data safe. You can read more about securing Node-RED in our ",[256,18284,18286],{"href":18285},"\u002Fblog\u002F2023\u002F04\u002Fsecuring-node-red-in-production\u002F","blog post here",[15,18288,18289],{},"We now need to get that data back into a Node-RED instance. We can do that by editing a node and pasting in the data we got from the API. The flow below shows where you can paste in your data, you will then need to deploy and manually trigger 'import data'.",[15,18291,18292],{},[239,18293],{"alt":18294,"src":18295,"title":18294},"Inject the data in JSON format","\u002Fblog\u002F2023\u002F05\u002Fimages\u002Finject-the-json.png",[15,18297,5928,18298,5411],{},[989,18299,18250,18300,18253,18302,18256,18304,18259,18306,18308,18309,18266,18311,18313,18314,18316,18317,18324],{},[989,18301],{},[989,18303,17832],{},[989,18305],{},[989,18307,18262],{},",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":630,\"y\":580,\"wires\":[[]]},{\"id\":\"4dd97b29430ad2ba\",\"type\":\"http in\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"url\":\"\u002Fdata\",\"method\":\"get\",\"upload\":false,\"swaggerDoc\":\"\",\"x\":200,\"y\":660,\"wires\":[[\"b4f0eb085cc91834\"]]},{\"id\":\"7ca49e5465699355\",\"type\":\"http response\",\"z\":\"4767c2f7095bee53\",\"name\":\"\",\"statusCode\":\"\",\"headers\":{},\"x\":670,\"y\":660,\"wires\":",[989,18310],{},[989,18312,18269],{},",\"action\":\"\",\"property\":\"\",\"from\":\"\",\"to\":\"\",\"reg\":false,\"x\":440,\"y\":660,\"wires\":[[\"7ca49e5465699355\"]]},{\"id\":\"d13d16b33ec638b2\",\"type\":\"inject\",\"z\":\"4767c2f7095bee53\",\"name\":\"import data\",\"props\":",[989,18315,5944],{},",\"repeat\":\"\",\"crontab\":\"\",\"once\":true,\"onceDelay\":0.1,\"topic\":\"\",\"payload\":\"",[989,18318,17910,18319,18321,18322,4425],{},[989,18320,11999],{},",\"data\":[[{\"x\":1684841975036,\"y\":8},{\"x\":1684841976037,\"y\":6},{\"x\":1684841977038,\"y\":7},{\"x\":1684841978037,\"y\":7}]],\"labels\":",[989,18323,11999],{},"\",\"payloadType\":\"json\",\"x\":170,\"y\":600,\"wires\":[[\"427c60f2c4f523b7\"]]},{\"id\":\"af1535b39b74f94a\",\"type\":\"ui_group\",\"name\":\"Example\",\"tab\":\"14f1442eb7525190\",\"order\":1,\"disp\":true,\"width\":\"6\",\"collapse\":false,\"className\":\"\"},{\"id\":\"14f1442eb7525190\",\"type\":\"ui_tab\",\"name\":\"Home\",\"icon\":\"dashboard\",\"disabled\":false,\"hidden\":false}",[15,18326,18327],{},"Each of these solutions has strengths and weaknesses but there are many other ways to persist your chart data. You should consider which approach is the best fit for your needs. To be as confident as possible that you data is safe, you may decide to push your data to dedicate external storage such as a database or backup solution.",[82,18329,2115],{"id":2114},[15,18331,18332],{},"Node-RED Dashboard 1 allows you to easily make informative HMIs, but it's important to make sure the chart data you are showing is stored safely. The approaches we have discussed above should give you a good start in ensuring your charts are populated with the correct data, even if your Node-RED instance crashes or you need to move it to a new hosting location.",{"title":265,"searchDepth":266,"depth":266,"links":18334},[18335,18336,18337,18342],{"id":18074,"depth":274,"text":18075},{"id":18084,"depth":274,"text":18085},{"id":18109,"depth":274,"text":18110,"children":18338},[18339,18340,18341],{"id":18119,"depth":266,"text":18120},{"id":18181,"depth":266,"text":18182},{"id":18241,"depth":266,"text":18242},{"id":2114,"depth":274,"text":2115},"2023-05-25","Chart data in Node-RED can be stored directly in your flows but it's a good idea to also store data eleswhere. In this article we are looking at some easy ways to persist your historic chart data in Dashboard 1","\u002Fblog\u002F2023\u002F05\u002Fimages\u002Fpersisting-data-header.jpeg",{"excerpt":18347},{"type":12,"value":18348},[18349],[15,18350,18043,18351,437],{},[256,18352,2228],{"href":2226,"rel":18353},[402],"\u002Fblog\u002F2023\u002F05\u002Fpersisting-chart-data-in-node-red",{"title":18037,"description":18344},{"loc":18354},"blog\u002F2023\u002F05\u002Fpersisting-chart-data-in-node-red","Keep your historic chart data safe and available",[487,3010,2164,303],"XOV8jlfg8Ym1N-NeSNj2So7YX36lMt0P73DX8r4OFxA",{"id":18362,"title":18363,"authors":18364,"body":18365,"cta":3,"date":18838,"description":18839,"extension":287,"image":18840,"lastUpdated":2996,"meta":18841,"navigation":295,"path":18847,"seo":18848,"sitemap":18849,"stem":18850,"subtitle":18851,"tags":18852,"tldr":3,"video":3,"__hash__":18853},"blog\u002Fblog\u002F2023\u002F03\u002Fcomparing-node-red-dashboards.md","Comparing Node-RED Dashboards Solutions",[16802],{"type":12,"value":18366,"toc":18801},[18367,18370,18390,18394,18411,18414,18433,18437,18440,18462,18465,18468,18470,18474,18477,18481,18484,18488,18500,18503,18506,18515,18524,18527,18530,18534,18537,18541,18544,18548,18551,18554,18557,18560,18564,18567,18571,18574,18576,18580,18583,18586,18598,18603,18606,18610,18613,18617,18624,18627,18630,18633,18636,18642,18645,18648,18654,18657,18660,18666,18672,18675,18677,18681,18687,18692,18701,18707,18711,18717,18722,18725,18729,18744,18750,18758,18768,18782,18785,18789,18792,18795,18798],[15,18368,18369],{},"Dashboards are a great feature of Node-RED, allowing you to easily expose data visualisations and interactive elements of your flows to users via a web browser. I often see discussions in the community about which dashboard option is best for any given scenario, I wanted to compare the most popular options as they stand in early 2023.",[228,18371,18054,18373,18054,18378],{"className":18372},[18053],[15,18374,18375,18377],{},[33,18376,18059],{}," Since this article was published, it's worth noting a couple of important updates:",[27,18379,18380,18381,18380,18384,18054],{},"\n        ",[30,18382,18383],{},"FlexDash is no longer maintained and supported.",[30,18385,18386,18389],{},[256,18387,18388],{"href":10046},"Node-RED Dashboard 2.0"," has been released, which is a new, modern dashboard stack for Node-RED, and offers all of the benefits of the original \"Node-RED Dashboard\", plus more.",[19,18391,18393],{"id":18392},"which-dashboards-am-i-going-to-consider","Which dashboards am I going to consider?",[15,18395,18396,18397,3553,18401,4837,18406,437],{},"Based on their downloads per week and active development, I believe there are 3 main dashboards worth considering. In no particular order, they are ",[256,18398,18400],{"href":2226,"rel":18399},[402],"Dashboard",[256,18402,18405],{"href":18403,"rel":18404},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-uibuilder",[402],"uibuilder",[256,18407,18410],{"href":18408,"rel":18409},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002F@flexdash\u002Fnode-red-fd-corewidgets",[402],"FlexDash",[15,18412,18413],{},"It's not to say that there are not other options, I am focusing on the dashboards I believe are popular in the Node-RED community.",[15,18415,18416,18417,3553,18422,4837,18427,18432],{},"I'd like to take this opportunity to thank the project leads for each of the three dashboards for responding to me and providing their take on the current state and future development of each. Where possible I have quoted their words, either from their messages to me or from the projects' documentation. Thanks to ",[256,18418,18421],{"href":18419,"rel":18420},"https:\u002F\u002Fgithub.com\u002Fdceejay",[402],"Dave",[256,18423,18426],{"href":18424,"rel":18425},"https:\u002F\u002Fgithub.com\u002FTotallyInformation",[402],"Julian",[256,18428,18431],{"href":18429,"rel":18430},"https:\u002F\u002Fgithub.com\u002Ftve",[402],"Thorsten"," for their replies as well as all the work they've put into these great projects!",[19,18434,18436],{"id":18435},"methodology","Methodology",[15,18438,18439],{},"To compare these dashboards, I am going to consider each of them based on the following factors:",[27,18441,18442,18445,18448,18451,18454,18457,18460],{},[30,18443,18444],{},"How easy is it to install?",[30,18446,18447],{},"How easy is it to get your first demo dashboard running?",[30,18449,18450],{},"How extensive is the collection of UI elements?",[30,18452,18453],{},"How good is the support and documentation?",[30,18455,18456],{},"How 'cloud native' is the dashboard?",[30,18458,18459],{},"How active is each project's development?",[30,18461,2544],{},[15,18463,18464],{},"I am assuming the user is a low-code developer. They may have limited experience with coding and are most comfortable working in visual interfaces.",[15,18466,18467],{},"So, that's the methodology, let's get on with looking at the strengths of each project.",[19,18469,18444],{"id":2178},[82,18471,18473],{"id":18472},"uibuilder-1st-place","uibuilder - 1st place",[15,18475,18476],{},"A search on Google for uibuilder returns the correct custom node. When searching for the custom node in the palette manager there is only one result, this is great as users are very likely to install what they were searching for. Once you've found the correct custom node, the installation takes just a few moments using the palette manager.",[82,18478,18480],{"id":18479},"dashboard-2nd-place","Dashboard - 2nd place",[15,18482,18483],{},"As Dashboard is currently the most popular solution to build dashboards in Node-RED, it's very easy to find both in search engines and in the Node-RED interface. A Google search brings up the correct custom node. Finding this custom node in Node-RED's palette manager is not quite as easy, at the time of writing it's the third from top result for the search term 'dashboard'. Some users might not select the intended item from the palette manager on first attempt. However, once you have found the correct custom node, installation is easy and takes just a few moments.",[82,18485,18487],{"id":18486},"flexdash-3rd-place","FlexDash - 3rd place",[15,18489,18490,18491],{},"When searching for 'FlexDash node red' on Google, the top result is the Node-RED website for the custom node. The issue with this, and this is also a problem when searching in the palette manager, is the project 'FlexDash' is apparently not what we actually need to install. When reading the readme for the project on Github it says ",[333,18492,18493,18494,18499],{},"'You most likely do not want to explicitly install this package, you want to install the ",[256,18495,18498],{"href":18496,"rel":18497},"https:\u002F\u002Fgithub.com\u002Fflexdash\u002Fnode-red-fd-corewidgets",[402],"core widgets",", which will bring in this package and more and will provide a usable whole'.",[15,18501,18502],{},"Credit to the developers for adding in this helpful text but I suspect most users will start off by installing FlexDash then later discover that was not the correct way to proceed. It would be great if the custom node which needs to be installed was the one called 'FlexDash' in my opinion.",[15,18504,18505],{},"This problem is compounded by there being no help file at all for 'FlexDash' showing up on the Node-RED web site. That may well be a deliberate attempt to help users get the right custom node installed, but it was still a confusing start for me and I suspect other users will have a similar experience.",[15,18507,18508,18509,18514],{},"When setting up FlexDash, one thing that wasn't immediately obvious was that I needed to restart Node-RED before the custom node showed in the palette. This step is ",[256,18510,18513],{"href":18511,"rel":18512},"https:\u002F\u002Fflexdash.github.io\u002Fdocs\u002Fquick-start\u002F#installing-flexdash-in-node-red",[402],"covered in the docs"," but I suspect a lot of users will get stuck working out why the palette manager says the custom node is installed but nothing new has been added to the palette.",[15,18516,18517,18518,18523],{},"There is also an ",[256,18519,18522],{"href":18520,"rel":18521},"https:\u002F\u002Fgithub.com\u002Fnode-red\u002Fnode-red\u002Fissues\u002F569",[402],"ongoing discussion"," about a way to resolve issue by changing how Node-RED deals with dependencies which sounds promising.",[15,18525,18526],{},"I believe a few improvements to the install process could make FlexDash a much more popular custom node.",[19,18528,18447],{"id":18529},"how-easy-is-it-to-get-your-first-demo-dashboard-running",[82,18531,18533],{"id":18532},"flexdash-1st-place","FlexDash - 1st place",[15,18535,18536],{},"Getting an example dashboard up and running in FlexDash is very easy thanks to the example flows which are included in the package. Simply go to 'Import', 'Examples' then select 'Hello-world' from the example flows. Now deploy and add \u002Fflexdash to the end of the URL of your Node-RED editor and you should have your first dashboard running.",[82,18538,18540],{"id":18539},"uibuilder-2nd-place","uibuilder - 2nd place",[15,18542,18543],{},"It was quite simple to get an example dashboard up and running in uibuilder. As with FlexDash, there are examples you can import. Once we import an example we do start to see the significantly different approach to delivering dashboards with uibuilder to the other two solutions. The examples seem to demonstrate how you could build a dashboard rather than showing specific UI elements such as charts in use.",[82,18545,18547],{"id":18546},"dashboard-3rd-place","Dashboard - 3rd place",[15,18549,18550],{},"Getting your first dashboard running in Dashboard is quite easy, once installed you need to drag in a Dashboard UI element then assign that to a UI group and tab. The group and tab can be left as their default options (home) which I suspect most users will work out quickly.",[15,18552,18553],{},"You then need to deploy your flow and visit the dashboard using '\u002Fui' on the end of the URL of your Node-RED editor and you are up and running.",[15,18555,18556],{},"Dashboard would benefit from some example flows as we see with the other two custom nodes.",[19,18558,18450],{"id":18559},"how-extensive-is-the-collection-of-ui-elements",[82,18561,18563],{"id":18562},"flexdash-and-dashboard-joint-1st-place","FlexDash and Dashboard - joint 1st place",[15,18565,18566],{},"It's really hard to separate these two, when considering the UI elements they come with. They both have out of the box solutions for charts, gauges, buttons, drop downs, toggles, text etc. I think they both deserve 1st place in this category.",[82,18568,18570],{"id":18569},"uibuilder-3rd-place","uibuilder - 3rd place",[15,18572,18573],{},"This is possibly a little unfair on uibuilder. Arguably by design, uibuilder does not currently include many UI elements. To add most useful elements (charts, gauges etc) to your dashboard, you will need to set out your design in HTML or look at using one of the supported frontend frameworks. This makes uibuilder more versatile for users who are comfortable using code to set out dashboards but for the low-coders among us it's less ideal.",[19,18575,18453],{"id":2527},[82,18577,18579],{"id":18578},"all-three-joint-first-place","All three - joint first place",[15,18581,18582],{},"All three projects have an active community and good support documentation. Where as I may have a personal preference about how I like documentation to be set out, I don't think that makes any one project better than the rest.",[19,18584,18456],{"id":18585},"how-cloud-native-is-the-dashboard",[15,18587,18588,18589,7202,18594,18597],{},"In the words of the ",[256,18590,18593],{"href":18591,"rel":18592},"https:\u002F\u002Fwww.cncf.io\u002F",[402],"Cloud Native Computing Foundation",[333,18595,18596],{},"Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach","'.",[15,18599,4352,18600,18597],{},[333,18601,18602],{},"These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil",[15,18604,18605],{},"So, how well does each project conform to these ideals?",[82,18607,18609],{"id":18608},"dashboard-1st-place","Dashboard - 1st place",[15,18611,18612],{},"Dashboard stores all configuration data within the Node-RED instance. When deploying an existing Node-RED project to a new instance everything just works exactly as it did previously.",[82,18614,18616],{"id":18615},"flexdash-2nd-place","FlexDash - 2nd place",[15,18618,18619,18620,18623],{},"As with Dashboard, everything required to define each dashboard is stored within Node-RED. This makes redeployment trivial. Unfortunately, as the Node-RED instance currently needs to be restarted before FlexDash works, it just missed out on joint first place. It would be great to see that issue resolved in future versions. There is also an ",[256,18621,18522],{"href":18520,"rel":18622},[402]," about a way to resolve issue by changing how Node-RED deals with dependencies.",[82,18625,18570],{"id":18626},"uibuilder-3rd-place-1",[15,18628,18629],{},"uibuilder uses the filesystem of the host instance to store its configuration. In practice this means that if you migrate the Node-RED project files to a new location you probably will find your dashboard no longer works. This can be mitigated by also migrating the filesystem (for example using persistent storage in Docker) and re-deploying via a Docker registry but it would be great to see uibuilder move towards not being dependant on the filesystem as it will make DevOps tasks that much easier.",[19,18631,18459],{"id":18632},"how-active-is-each-projects-development",[82,18634,18473],{"id":18635},"uibuilder-1st-place-1",[15,18637,18638],{},[239,18639],{"alt":18640,"src":18641,"title":18640},"Image showing the uibuilder Github Commits","\u002Fblog\u002F2023\u002F03\u002Fimages\u002Fuibuilder-activity.png",[15,18643,18644],{},"uibuilder has has consistent commits to the project going back several years with even greater activity since the start of 2022.",[82,18646,18616],{"id":18647},"flexdash-2nd-place-1",[15,18649,18650],{},[239,18651],{"alt":18652,"src":18653,"title":18652},"Image showing the FlexDash Github Commits","\u002Fblog\u002F2023\u002F03\u002Fimages\u002Fflexdash-activity.png",[15,18655,18656],{},"The commits to FlexDash have been regular since mid 2022.",[82,18658,18547],{"id":18659},"dashboard-3rd-place-1",[15,18661,18662],{},[239,18663],{"alt":18664,"src":18665,"title":18664},"Image showing the Dashboard Github Commits","\u002Fblog\u002F2023\u002F03\u002Fimages\u002Fdashboard-activity.png",[15,18667,18668,18669,437],{},"Dashboard is now in a a maintenance only state. In the words of the project lead, ",[333,18670,18671],{},"'Angular 1 (the framework used to build Dashboard) is now unsupported and it's just a matter of time before there is a serious security hole raised against it, for which there will be no fix. Of course we don't use all the features of it so we may be lucky that an exploit doesn't necessarily expose us directly but it will compromise any audits people may wish to do'",[15,18673,18674],{},"In practice, this means that sooner or later using Dashboard might become a significant security risk.",[19,18676,2544],{"id":2543},[82,18678,18680],{"id":18679},"uibuilder-joint-firstplace","uibuilder - joint firstplace",[15,18682,18683,18684,437],{},"During the writing of this article, uibuilder released a new version with some significant new features. In the words of the project lead when talking about version 6.1.0, '",[333,18685,18686],{},"It feels like uibuilder really is growing up. No more apologising for not being a direct Node-RED Dashboard replacement, uibuilder has its own path",[15,18688,18689,18597],{},[333,18690,18691],{},"You can now create and update visible web page elements direct from Node-RED data without needing to understand all of the intricacies and inconsistencies of HTML. You can create your own utility tools either in Node-RED or in front-end code that leverages the low-code UI features of uibuilder",[15,18693,18694,18695,18700],{},"It's great to see projects under active development. My greatest difficulty when using uibuilder, is I found it hard to create the UI elements I needed based on low-code workflows. According to the ",[256,18696,18699],{"href":18697,"rel":18698},"https:\u002F\u002Ftotallyinformation.github.io\u002Fnode-red-contrib-uibuilder\u002F#\u002Froadmap",[402],"development roadmap for uibuilder"," the project should progress towards being easier and easier for low-coders to make use of.",[15,18702,18703,18704,18597],{},"To again quote the project lead, '",[333,18705,18706],{},"In general, the ongoing direction of travel is to enable more zero-code features that will work both in Node-RED flows and in front-end custom code. The low-code feature set is already quite mature now and is well documented enough that it can be used by other tools should anyone wish to do so. I will be making sure that both the zero-code and low-code features are as easy to use as possible both from Node-RED and front-end code for maximum flexibility",[82,18708,18710],{"id":18709},"flexdash-joint-firstplace","FlexDash - joint firstplace",[15,18712,18713,18714,18597],{},"The project Lead for FlexDash had the following to say about the future development of the project. '",[333,18715,18716],{},"FlexDash currently has a fairly rigid overall page structure: there's a tab bar and each tab's content is organized in grids of widgets. The plan is to open this up fully so the user can start from a blank page and place containers which contain widgets. This way almost any layout could be implemented in FlexDash",[15,18718,4352,18719,18597],{},[333,18720,18721],{},"I also would like to improve the multi-user capabilities of FlexDash by supporting authentication and making it easier for users to implement flows that present per-user data in the dashboard",[15,18723,18724],{},"After using FlexDash over the past couple of weeks and finding it to be already be a strong contender for all my Node-RED dashboard needs, it's great to see it continuing to be improved.",[82,18726,18728],{"id":18727},"dashboard-third-place","Dashboard - third place",[15,18730,18731,18736,18737],{},[333,18732,18733],{},[33,18734,18735],{},"Important Update: New Generation of Node-RED Dashboard Released:"," ",[333,18738,18739,18740,18743],{},"A new generation of the outdated and unmaintained Node-RED Dashboard has been released to replace it. Introducing ",[256,18741,18388],{"href":3518,"rel":18742},[402],", built on Vue.js, offering significantly more versatility than its predecessor. This new dashboard, managed by FlowFuse, is designed to allow full customization, addressing the limitations of the previous version.",[15,18745,18746,18747,437],{},"*Node-RED Dashboard 2.0 retains most of the widgets and concepts from the old version, so transitioning from Node-RED Dashboard 1.0 to 2.0 is easy. For a full feature comparison you can check out the ",[256,18748,3730],{"href":15057,"rel":18749},[402],[15,18751,18752,18753,18757],{},"Dashboard 2.0 includes various chart types such as line, scatter, bar, gauge, and more, and it's compatible with all the ",[256,18754,18756],{"href":3589,"rel":18755},[402],"Vuetify component library",", making it easier to build advanced dashboards.*",[15,18759,18760],{},[333,18761,18762,18763,5531],{},"Furthermore, the team is continuously working on adding more amazing features to enhance the user experience. For a smooth transition, FlowFuse provides easy-to-follow guides. Refer to ",[256,18764,18767],{"href":18765,"rel":18766},"https:\u002F\u002Fflowfuse.com\u002Fblog\u002Fdashboard\u002F",[402],"Node-RED Dashboard 2.0 Guides",[15,18769,18770,18771,18776,18777,437],{},"As mentioned above, Dashboard is no longer in active development. This is due to the framework upon which it was build ",[256,18772,18775],{"href":18773,"rel":18774},"https:\u002F\u002Fangularjs.org\u002F",[402],"(AngularJS)"," now being unsupported as of the end of 2021. You can read a lot more detail on why ongoing development of Dashboard is not practical in this ",[256,18778,18781],{"href":18779,"rel":18780},"https:\u002F\u002Fdiscourse.nodered.org\u002Ft\u002Fdiscussion-about-a-new-dashboard\u002F51119\u002F3",[402],"thread on the Node-RED forums",[15,18783,18784],{},"There could possibly be new effort put into porting Dashboard over to a new framework but that is a significant amount of work. I suspect it would take hundreds of hours development just to get the feature set back to the same state as the current version so I suspect it won't ever happen.",[19,18786,18788],{"id":18787},"conclusions","Conclusions",[15,18790,18791],{},"Personally, I was a little surprised by these results. I have used Dashboard for around 3 years and always found it to be a great tool for putting together quick and informative dashboards. That being said, when attempting to objectively compare it to uibuilder and FlexDash, the other two projects often are individually better in a given category. That coupled with the halt of development for Dashboard due to AngularJS being no longer supported, it's hard to recommend Dashboard for totally new Node-RED users in 2023, especially for commercial projects.",[15,18793,18794],{},"If you already use Dashboard, in a non-commercial setting you should probably continue to do so, you might find that its development slows down to a near stall due to the underlying framework now being abandoned but for at least as of right now it's a great solution to build your Node-RED dashboards in.",[15,18796,18797],{},"FlexDash is probably the best low-code solution for building dashboards in Node-RED. If you don't get blocked by the confusing install process I believe it's the one to pick up at the time of writing due to it's ongoing support and low-code interface.",[15,18799,18800],{},"uibuilder is currently not what I would consider a truly low-code option for creating dashboards but it is moving in that direction. It has some great features and is extremely flexible so it has a good chance of ending up as the most popular solution to build dashboards in Node-RED in the long term. That being said, as of time of writing unless you are a 'coder' you will may struggle to build a dashboard using it.",{"title":265,"searchDepth":266,"depth":266,"links":18802},[18803,18804,18805,18810,18815,18819,18822,18827,18832,18837],{"id":18392,"depth":269,"text":18393},{"id":18435,"depth":269,"text":18436},{"id":2178,"depth":269,"text":18444,"children":18806},[18807,18808,18809],{"id":18472,"depth":274,"text":18473},{"id":18479,"depth":274,"text":18480},{"id":18486,"depth":274,"text":18487},{"id":18529,"depth":269,"text":18447,"children":18811},[18812,18813,18814],{"id":18532,"depth":274,"text":18533},{"id":18539,"depth":274,"text":18540},{"id":18546,"depth":274,"text":18547},{"id":18559,"depth":269,"text":18450,"children":18816},[18817,18818],{"id":18562,"depth":274,"text":18563},{"id":18569,"depth":274,"text":18570},{"id":2527,"depth":269,"text":18453,"children":18820},[18821],{"id":18578,"depth":274,"text":18579},{"id":18585,"depth":269,"text":18456,"children":18823},[18824,18825,18826],{"id":18608,"depth":274,"text":18609},{"id":18615,"depth":274,"text":18616},{"id":18626,"depth":274,"text":18570},{"id":18632,"depth":269,"text":18459,"children":18828},[18829,18830,18831],{"id":18635,"depth":274,"text":18473},{"id":18647,"depth":274,"text":18616},{"id":18659,"depth":274,"text":18547},{"id":2543,"depth":269,"text":2544,"children":18833},[18834,18835,18836],{"id":18679,"depth":274,"text":18680},{"id":18709,"depth":274,"text":18710},{"id":18727,"depth":274,"text":18728},{"id":18787,"depth":269,"text":18788},"2023-03-13","Explore a thorough comparison of Node-RED dashboard solutions, covering installation, UI elements, support, and future development plans.","\u002Fimages\u002Fblog\u002Fdb-comparison.jpg",{"keywords":18842,"excerpt":18843},"node red dashboard, node-red dashboard, node red ui builder, ui builder node red, flexdash, node red dashboard alternative, node red alternative dashboard",{"type":12,"value":18844},[18845],[15,18846,18369],{},"\u002Fblog\u002F2023\u002F03\u002Fcomparing-node-red-dashboards",{"title":18363,"description":18839},{"loc":18847},"blog\u002F2023\u002F03\u002Fcomparing-node-red-dashboards","One of the most common features Node-RED users add to their flows is a dashboard, we compaure the 3 most popular options.",[3009,3010,303,3011],"WLaG1Z5dQtBGepVDycZbwzakm1DqWxvg4fKLicMACOk",1785528670865]