[{"data":1,"prerenderedAt":347},["ShallowReactive",2],{"blog-\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout":3},{"id":4,"title":5,"body":6,"description":12,"extension":130,"meta":338,"navigation":148,"path":343,"seo":344,"stem":345,"__hash__":346},"blog\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout.md","Dynamic Markdown, Tables & Notebooks with Dashboard 2.0",{"type":7,"value":8,"toc":332},"minimark",[9,13,16,33,55,67,72,75,103,107,114,122,125,199,219,225,228,234,238,245,256,263,269,272,277,280,285,289,304,312,328],[10,11,12],"p",{},"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.",[10,14,15],{},"In our v0.4.0 release, we've introduced a new \"Notebook\" layout, alongside a new Table widget.",[10,17,18,19,26,27,32],{},"The Notebook layout is designed to allow users to create Dashboards structured like a Notebook (most often seen with the likes of ",[20,21,25],"a",{"href":22,"rel":23},"https:\u002F\u002Fjupyter.org\u002F",[24],"nofollow","Jupyter Notebooks"," or ",[20,28,31],{"href":29,"rel":30},"https:\u002F\u002Fobservablehq.com\u002F",[24],"ObservableHQ",").",[10,34,35,36,40,41,46,47,40,50,54],{},"Here we will deepdive into the Notebook layout, and show how, alongside our new ",[37,38,39],"strong",{},"Markdown Node"," (",[20,42,45],{"href":43,"rel":44},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-markdown.html",[24],"docs","), ",[37,48,49],{},"Table Node",[20,51,45],{"href":52,"rel":53},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fnodes\u002Fwidgets\u002Fui-table.html",[24],") and others, it's becoming easier to create dynamic and interactive Dashboards.",[10,56,57],{},[58,59,60,61,66],"em",{},"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 ",[20,62,65],{"href":63,"rel":64},"https:\u002F\u002Fwww.markdownguide.org\u002Fcheat-sheet\u002F",[24],"here",".",[68,69,71],"h2",{"id":70},"dashboard-hierarchy","Dashboard Hierarchy",[10,73,74],{},"As a quick introductory note ahead of our below guide, each Dashboard is structured accordingly:",[76,77,78,85,91,97],"ul",{},[79,80,81,84],"li",{},[37,82,83],{},"Widget",": An individual functional block, e.g. button, chart, slider",[79,86,87,90],{},[37,88,89],{},"Group",": A collection of widgets that render together",[79,92,93,96],{},[37,94,95],{},"Page",": A single page\u002Ftab in your Dashboard. Each page can have it's own Layout, in this case we'll use \"Notebook\"",[79,98,99,102],{},[37,100,101],{},"UI",": Contains a collection of pages, deployed from Node-RED, provides the basic side navigation to switch between Pages.",[68,104,106],{"id":105},"building-a-notebook","Building a Notebook",[10,108,109],{},[110,111],"img",{"alt":112,"src":113},"Example Notebook created in Dashboard","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-example.png",[10,115,116,117,121],{},"To get started, drop your first widget (in this case, we'll add a ",[118,119,120],"code",{},"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.",[10,123,124],{},"Let's add the following Markdown to our first widget:",[126,127,132],"pre",{"className":128,"code":129,"language":130,"meta":131,"style":131},"language-md shiki shiki-themes github-light github-dark","# Markdown Content\n\nHere we can render dynamic Markdown content that is\neasily _styled_.\n\n\nWe can inject `msg.payload`. For example, here is a\ntimestamp updating every second: {{ msg.payload }}\n\n","md","",[118,133,134,143,150,157,170,175,180,193],{"__ignoreMap":131},[135,136,139],"span",{"class":137,"line":138},"line",1,[135,140,142],{"class":141},"sq-ep","# Markdown Content\n",[135,144,146],{"class":137,"line":145},2,[135,147,149],{"emptyLinePlaceholder":148},true,"\n",[135,151,153],{"class":137,"line":152},3,[135,154,156],{"class":155},"sVt8B","Here we can render dynamic Markdown content that is\n",[135,158,160,163,167],{"class":137,"line":159},4,[135,161,162],{"class":155},"easily ",[135,164,166],{"class":165},"s5osK","_styled_",[135,168,169],{"class":155},".\n",[135,171,173],{"class":137,"line":172},5,[135,174,149],{"emptyLinePlaceholder":148},[135,176,178],{"class":137,"line":177},6,[135,179,149],{"emptyLinePlaceholder":148},[135,181,183,186,190],{"class":137,"line":182},7,[135,184,185],{"class":155},"We can inject ",[135,187,189],{"class":188},"sj4cs","`msg.payload`",[135,191,192],{"class":155},". For example, here is a\n",[135,194,196],{"class":137,"line":195},8,[135,197,198],{"class":155},"timestamp updating every second: {{ msg.payload }}\n",[10,200,201,202,204,205,208,209,211,212,215,216,218],{},"The joy of ",[118,203,120],{}," in Dashboard 2.0 is ",[58,206,207],{},"dynamic"," content, i.e. content that can be updated by passing messages to the ",[118,210,120],{}," node. We can wire an ",[118,213,214],{},"inject"," node, set it up to repeat every second, and connect it to ",[118,217,120],{},". Now, our Markdown content will automatically update show this value.",[10,220,221],{},[110,222],{"alt":223,"src":224},"Screenshot to show how an inject node can drive content of a ui-markdown node","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-inject.png",[10,226,227],{},"Resulting in:",[10,229,230],{},[110,231],{"alt":232,"src":233},"Dynamic markdown with an updating timestamp every 1 second","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fmd-timestamp.gif",[68,235,237],{"id":236},"adding-more-widgets","Adding More Widgets",[10,239,240,241,244],{},"Because the Notebook is ",[58,242,243],{},"just"," a layout, we can still wire together any of the available widgets and existing nodes and display them accordingly.",[10,246,247,248,251,252,255],{},"Let's wire a ",[118,249,250],{},"ui-button",", HTTP Request, and ",[118,253,254],{},"ui-table"," node. When we click the button, it will perform the HTTP request, and then render the response in the table.",[10,257,258,259,262],{},"For this, we're going to use the Random Jokes API, and in particular, a call to ",[118,260,261],{},"https:\u002F\u002Fofficial-joke-api.appspot.com\u002Fjokes\u002Ften"," which will return 10 random jokes.",[10,264,265],{},[110,266],{"alt":267,"src":268},"Screenshot showing a simple Button > HTTP Request > Table flow","\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fgenerate-jokes-flow.png",[10,270,271],{},"We can also re-order the widgets on the page using the Dashboard 2.0 sidebar (as you could in Dashboard 1.0).",[10,273,274],{},[110,275],{"alt":223,"src":276},"\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-order.png",[10,278,279],{},"The above effort results in the following output in our Notebook:",[10,281,282],{},[110,283],{"alt":223,"src":284},"\u002Fblog\u002F2023\u002F09\u002Fimages\u002Fdb-notebook-jokes-table.png",[68,286,288],{"id":287},"what-else-is-new-in-040","What else is new in 0.4.0?",[10,290,291,292,297,298,303],{},"The above demonstrates just a few of the new features in the 0.4.0 Release, but we've also added ",[20,293,296],{"href":294,"rel":295},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard\u002Freleases\u002Ftag\u002Fv0.4.0",[24],"other fixes and improvements",". In particular, I want to call out Steve's great work on implementing custom class injection, the first of our new ",[20,299,302],{"href":300,"rel":301},"https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fdynamic-properties.html",[24],"\"Dynamic Properties\"",", of which there will be more (e.g. visibility, disabled, etc.) to come.",[10,305,306,307,66],{},"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 ",[20,308,311],{"href":309,"rel":310},"https:\u002F\u002Fgithub.com\u002FFlowFuse\u002Fnode-red-dashboard",[24],"GitHub repository",[76,313,314,321],{},[79,315,316],{},[20,317,320],{"href":318,"rel":319},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F1",[24],"Dashboard 2.0 Activity Tracker",[79,322,323],{},[20,324,327],{"href":325,"rel":326},"https:\u002F\u002Fgithub.com\u002Forgs\u002FFlowFuse\u002Fprojects\u002F15\u002Fviews\u002F4",[24],"Dashboard 2.0 Planning Board",[329,330,331],"style",{},"html pre.shiki code .sq-ep, html code.shiki .sq-ep{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s5osK, html code.shiki .s5osK{--shiki-default:#24292E;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:italic}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":131,"searchDepth":145,"depth":145,"links":333},[334,335,336,337],{"id":70,"depth":145,"text":71},{"id":105,"depth":145,"text":106},{"id":236,"depth":145,"text":237},{"id":287,"depth":145,"text":288},{"navTitle":5,"excerpt":339},{"type":7,"value":340},[341],[10,342,12],{},"\u002Fblog\u002F2023\u002F09\u002Fdashboard-notebook-layout",{"title":5,"description":12},"blog\u002F2023\u002F09\u002Fdashboard-notebook-layout","Dc3-jyvKETUru4Hrk-lj3bXAooKKdUoN0OIQsFzh8qk",1780070550915]